xref: /freebsd/sys/netinet/ip_input.c (revision ad9f4d6ab6b12fbcfd41b4fbadef7020a17cad01)
1c398230bSWarner Losh /*-
2df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1988, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
14df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
15df8bae1dSRodney W. Grimes  *    without specific prior written permission.
16df8bae1dSRodney W. Grimes  *
17df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
28df8bae1dSRodney W. Grimes  *
29df8bae1dSRodney W. Grimes  *	@(#)ip_input.c	8.2 (Berkeley) 1/4/94
30df8bae1dSRodney W. Grimes  */
31df8bae1dSRodney W. Grimes 
324b421e2dSMike Silbersack #include <sys/cdefs.h>
334b421e2dSMike Silbersack __FBSDID("$FreeBSD$");
344b421e2dSMike Silbersack 
350ac40133SBrian Somers #include "opt_bootp.h"
3627108a15SDag-Erling Smørgrav #include "opt_ipstealth.h"
376a800098SYoshinobu Inoue #include "opt_ipsec.h"
3833553d6eSBjoern A. Zeeb #include "opt_route.h"
39b8bc95cdSAdrian Chadd #include "opt_rss.h"
4074a9466cSGary Palmer 
41df8bae1dSRodney W. Grimes #include <sys/param.h>
42df8bae1dSRodney W. Grimes #include <sys/systm.h>
43ef91a976SAndrey V. Elsukov #include <sys/hhook.h>
44df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
45b715f178SLuigi Rizzo #include <sys/malloc.h>
46df8bae1dSRodney W. Grimes #include <sys/domain.h>
47df8bae1dSRodney W. Grimes #include <sys/protosw.h>
48df8bae1dSRodney W. Grimes #include <sys/socket.h>
49df8bae1dSRodney W. Grimes #include <sys/time.h>
50df8bae1dSRodney W. Grimes #include <sys/kernel.h>
51385195c0SMarko Zec #include <sys/lock.h>
52cc0a3c8cSAndrey V. Elsukov #include <sys/rmlock.h>
53385195c0SMarko Zec #include <sys/rwlock.h>
5457f60867SMark Johnston #include <sys/sdt.h>
551025071fSGarrett Wollman #include <sys/syslog.h>
56b5e8ce9fSBruce Evans #include <sys/sysctl.h>
57df8bae1dSRodney W. Grimes 
58c85540ddSAndrey A. Chernov #include <net/pfil.h>
59df8bae1dSRodney W. Grimes #include <net/if.h>
609494d596SBrooks Davis #include <net/if_types.h>
61d314ad7bSJulian Elischer #include <net/if_var.h>
6282c23ebaSBill Fenner #include <net/if_dl.h>
63df8bae1dSRodney W. Grimes #include <net/route.h>
64748e0b0aSGarrett Wollman #include <net/netisr.h>
65b2bdc62aSAdrian Chadd #include <net/rss_config.h>
664b79449eSBjoern A. Zeeb #include <net/vnet.h>
67df8bae1dSRodney W. Grimes 
68df8bae1dSRodney W. Grimes #include <netinet/in.h>
6957f60867SMark Johnston #include <netinet/in_kdtrace.h>
70df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
71b5e8ce9fSBruce Evans #include <netinet/in_var.h>
72df8bae1dSRodney W. Grimes #include <netinet/ip.h>
73df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h>
74df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
75eddfbb76SRobert Watson #include <netinet/ip_fw.h>
76df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h>
77ef39adf0SAndre Oppermann #include <netinet/ip_options.h>
7858938916SGarrett Wollman #include <machine/in_cksum.h>
79a9771948SGleb Smirnoff #include <netinet/ip_carp.h>
80b2630c29SGeorge V. Neville-Neil #ifdef IPSEC
811dfcf0d2SAndre Oppermann #include <netinet/ip_ipsec.h>
8233872124SGeorge V. Neville-Neil #include <netipsec/ipsec.h>
8333872124SGeorge V. Neville-Neil #include <netipsec/key.h>
84b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */
85b8bc95cdSAdrian Chadd #include <netinet/in_rss.h>
86df8bae1dSRodney W. Grimes 
87f0068c4aSGarrett Wollman #include <sys/socketvar.h>
886ddbf1e2SGary Palmer 
89aed55708SRobert Watson #include <security/mac/mac_framework.h>
90aed55708SRobert Watson 
91d2035ffbSEd Maste #ifdef CTASSERT
92d2035ffbSEd Maste CTASSERT(sizeof(struct ip) == 20);
93d2035ffbSEd Maste #endif
94d2035ffbSEd Maste 
951dbefcc0SGleb Smirnoff /* IP reassembly functions are defined in ip_reass.c. */
96843b0e57SXin LI extern void ipreass_init(void);
97843b0e57SXin LI extern void ipreass_drain(void);
98843b0e57SXin LI extern void ipreass_slowtimo(void);
991dbefcc0SGleb Smirnoff #ifdef VIMAGE
100843b0e57SXin LI extern void ipreass_destroy(void);
1011dbefcc0SGleb Smirnoff #endif
1021dbefcc0SGleb Smirnoff 
103cc0a3c8cSAndrey V. Elsukov struct rmlock in_ifaddr_lock;
104cc0a3c8cSAndrey V. Elsukov RM_SYSINIT(in_ifaddr_lock, &in_ifaddr_lock, "in_ifaddr_lock");
105f0068c4aSGarrett Wollman 
10682cea7e6SBjoern A. Zeeb VNET_DEFINE(int, rsvp_on);
10782cea7e6SBjoern A. Zeeb 
10882cea7e6SBjoern A. Zeeb VNET_DEFINE(int, ipforwarding);
1096df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_VNET | CTLFLAG_RW,
110eddfbb76SRobert Watson     &VNET_NAME(ipforwarding), 0,
1118b615593SMarko Zec     "Enable IP forwarding between interfaces");
1120312fbe9SPoul-Henning Kamp 
1133e288e62SDimitry Andric static VNET_DEFINE(int, ipsendredirects) = 1;	/* XXX */
11482cea7e6SBjoern A. Zeeb #define	V_ipsendredirects	VNET(ipsendredirects)
1156df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_VNET | CTLFLAG_RW,
116eddfbb76SRobert Watson     &VNET_NAME(ipsendredirects), 0,
1178b615593SMarko Zec     "Enable sending IP redirects");
1180312fbe9SPoul-Henning Kamp 
119823db0e9SDon Lewis /*
120823db0e9SDon Lewis  * XXX - Setting ip_checkinterface mostly implements the receive side of
121823db0e9SDon Lewis  * the Strong ES model described in RFC 1122, but since the routing table
122a8f12100SDon Lewis  * and transmit implementation do not implement the Strong ES model,
123823db0e9SDon Lewis  * setting this to 1 results in an odd hybrid.
1243f67c834SDon Lewis  *
125a8f12100SDon Lewis  * XXX - ip_checkinterface currently must be disabled if you use ipnat
126a8f12100SDon Lewis  * to translate the destination address to another local interface.
1273f67c834SDon Lewis  *
1283f67c834SDon Lewis  * XXX - ip_checkinterface must be disabled if you add IP aliases
1293f67c834SDon Lewis  * to the loopback interface instead of the interface where the
1303f67c834SDon Lewis  * packets for those addresses are received.
131823db0e9SDon Lewis  */
1323e288e62SDimitry Andric static VNET_DEFINE(int, ip_checkinterface);
13382cea7e6SBjoern A. Zeeb #define	V_ip_checkinterface	VNET(ip_checkinterface)
1346df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_VNET | CTLFLAG_RW,
135eddfbb76SRobert Watson     &VNET_NAME(ip_checkinterface), 0,
1368b615593SMarko Zec     "Verify packet arrives on correct interface");
137b3e95d4eSJonathan Lemon 
1380b4b0b0fSJulian Elischer VNET_DEFINE(struct pfil_head, inet_pfil_hook);	/* Packet filter hooks */
139df8bae1dSRodney W. Grimes 
140d4b5cae4SRobert Watson static struct netisr_handler ip_nh = {
141d4b5cae4SRobert Watson 	.nh_name = "ip",
142d4b5cae4SRobert Watson 	.nh_handler = ip_input,
143d4b5cae4SRobert Watson 	.nh_proto = NETISR_IP,
144b8bc95cdSAdrian Chadd #ifdef	RSS
1452527ccadSAdrian Chadd 	.nh_m2cpuid = rss_soft_m2cpuid_v4,
146b8bc95cdSAdrian Chadd 	.nh_policy = NETISR_POLICY_CPU,
147b8bc95cdSAdrian Chadd 	.nh_dispatch = NETISR_DISPATCH_HYBRID,
148b8bc95cdSAdrian Chadd #else
149d4b5cae4SRobert Watson 	.nh_policy = NETISR_POLICY_FLOW,
150b8bc95cdSAdrian Chadd #endif
151d4b5cae4SRobert Watson };
152ca925d9cSJonathan Lemon 
153b8bc95cdSAdrian Chadd #ifdef	RSS
154b8bc95cdSAdrian Chadd /*
155b8bc95cdSAdrian Chadd  * Directly dispatched frames are currently assumed
156b8bc95cdSAdrian Chadd  * to have a flowid already calculated.
157b8bc95cdSAdrian Chadd  *
158b8bc95cdSAdrian Chadd  * It should likely have something that assert it
159b8bc95cdSAdrian Chadd  * actually has valid flow details.
160b8bc95cdSAdrian Chadd  */
161b8bc95cdSAdrian Chadd static struct netisr_handler ip_direct_nh = {
162b8bc95cdSAdrian Chadd 	.nh_name = "ip_direct",
163b8bc95cdSAdrian Chadd 	.nh_handler = ip_direct_input,
164b8bc95cdSAdrian Chadd 	.nh_proto = NETISR_IP_DIRECT,
165499baf0aSAdrian Chadd 	.nh_m2cpuid = rss_soft_m2cpuid_v4,
166b8bc95cdSAdrian Chadd 	.nh_policy = NETISR_POLICY_CPU,
167b8bc95cdSAdrian Chadd 	.nh_dispatch = NETISR_DISPATCH_HYBRID,
168b8bc95cdSAdrian Chadd };
169b8bc95cdSAdrian Chadd #endif
170b8bc95cdSAdrian Chadd 
171df8bae1dSRodney W. Grimes extern	struct domain inetdomain;
172f0ffb944SJulian Elischer extern	struct protosw inetsw[];
173df8bae1dSRodney W. Grimes u_char	ip_protox[IPPROTO_MAX];
17482cea7e6SBjoern A. Zeeb VNET_DEFINE(struct in_ifaddrhead, in_ifaddrhead);  /* first inet address */
17582cea7e6SBjoern A. Zeeb VNET_DEFINE(struct in_ifaddrhashhead *, in_ifaddrhashtbl); /* inet addr hash table  */
17682cea7e6SBjoern A. Zeeb VNET_DEFINE(u_long, in_ifaddrhmask);		/* mask for hash table */
177ca925d9cSJonathan Lemon 
1780312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU
1790312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
1803d177f46SBill Fumerola     &ip_mtu, 0, "Default MTU");
1810312fbe9SPoul-Henning Kamp #endif
1820312fbe9SPoul-Henning Kamp 
1831b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
18482cea7e6SBjoern A. Zeeb VNET_DEFINE(int, ipstealth);
1856df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_VNET | CTLFLAG_RW,
186eddfbb76SRobert Watson     &VNET_NAME(ipstealth), 0,
187eddfbb76SRobert Watson     "IP stealth mode, no TTL decrementation on forwarding");
1881b968362SDag-Erling Smørgrav #endif
189eddfbb76SRobert Watson 
190315e3e38SRobert Watson /*
1915da0521fSAndrey V. Elsukov  * IP statistics are stored in the "array" of counter(9)s.
1925923c293SGleb Smirnoff  */
1935da0521fSAndrey V. Elsukov VNET_PCPUSTAT_DEFINE(struct ipstat, ipstat);
1945da0521fSAndrey V. Elsukov VNET_PCPUSTAT_SYSINIT(ipstat);
1955da0521fSAndrey V. Elsukov SYSCTL_VNET_PCPUSTAT(_net_inet_ip, IPCTL_STATS, stats, struct ipstat, ipstat,
1965da0521fSAndrey V. Elsukov     "IP statistics (struct ipstat, netinet/ip_var.h)");
1975923c293SGleb Smirnoff 
1985923c293SGleb Smirnoff #ifdef VIMAGE
1995da0521fSAndrey V. Elsukov VNET_PCPUSTAT_SYSUNINIT(ipstat);
2005923c293SGleb Smirnoff #endif /* VIMAGE */
2015923c293SGleb Smirnoff 
2025923c293SGleb Smirnoff /*
203315e3e38SRobert Watson  * Kernel module interface for updating ipstat.  The argument is an index
2045923c293SGleb Smirnoff  * into ipstat treated as an array.
205315e3e38SRobert Watson  */
206315e3e38SRobert Watson void
207315e3e38SRobert Watson kmod_ipstat_inc(int statnum)
208315e3e38SRobert Watson {
209315e3e38SRobert Watson 
2105da0521fSAndrey V. Elsukov 	counter_u64_add(VNET(ipstat)[statnum], 1);
211315e3e38SRobert Watson }
212315e3e38SRobert Watson 
213315e3e38SRobert Watson void
214315e3e38SRobert Watson kmod_ipstat_dec(int statnum)
215315e3e38SRobert Watson {
216315e3e38SRobert Watson 
2175da0521fSAndrey V. Elsukov 	counter_u64_add(VNET(ipstat)[statnum], -1);
218315e3e38SRobert Watson }
219315e3e38SRobert Watson 
220d4b5cae4SRobert Watson static int
221d4b5cae4SRobert Watson sysctl_netinet_intr_queue_maxlen(SYSCTL_HANDLER_ARGS)
222d4b5cae4SRobert Watson {
223d4b5cae4SRobert Watson 	int error, qlimit;
224d4b5cae4SRobert Watson 
225d4b5cae4SRobert Watson 	netisr_getqlimit(&ip_nh, &qlimit);
226d4b5cae4SRobert Watson 	error = sysctl_handle_int(oidp, &qlimit, 0, req);
227d4b5cae4SRobert Watson 	if (error || !req->newptr)
228d4b5cae4SRobert Watson 		return (error);
229d4b5cae4SRobert Watson 	if (qlimit < 1)
230d4b5cae4SRobert Watson 		return (EINVAL);
231d4b5cae4SRobert Watson 	return (netisr_setqlimit(&ip_nh, qlimit));
232d4b5cae4SRobert Watson }
233d4b5cae4SRobert Watson SYSCTL_PROC(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen,
234d4b5cae4SRobert Watson     CTLTYPE_INT|CTLFLAG_RW, 0, 0, sysctl_netinet_intr_queue_maxlen, "I",
235d4b5cae4SRobert Watson     "Maximum size of the IP input queue");
236d4b5cae4SRobert Watson 
237d4b5cae4SRobert Watson static int
238d4b5cae4SRobert Watson sysctl_netinet_intr_queue_drops(SYSCTL_HANDLER_ARGS)
239d4b5cae4SRobert Watson {
240d4b5cae4SRobert Watson 	u_int64_t qdrops_long;
241d4b5cae4SRobert Watson 	int error, qdrops;
242d4b5cae4SRobert Watson 
243d4b5cae4SRobert Watson 	netisr_getqdrops(&ip_nh, &qdrops_long);
244d4b5cae4SRobert Watson 	qdrops = qdrops_long;
245d4b5cae4SRobert Watson 	error = sysctl_handle_int(oidp, &qdrops, 0, req);
246d4b5cae4SRobert Watson 	if (error || !req->newptr)
247d4b5cae4SRobert Watson 		return (error);
248d4b5cae4SRobert Watson 	if (qdrops != 0)
249d4b5cae4SRobert Watson 		return (EINVAL);
250d4b5cae4SRobert Watson 	netisr_clearqdrops(&ip_nh);
251d4b5cae4SRobert Watson 	return (0);
252d4b5cae4SRobert Watson }
253d4b5cae4SRobert Watson 
254d4b5cae4SRobert Watson SYSCTL_PROC(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops,
255d4b5cae4SRobert Watson     CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_netinet_intr_queue_drops, "I",
256d4b5cae4SRobert Watson     "Number of packets dropped from the IP input queue");
257d4b5cae4SRobert Watson 
258b8bc95cdSAdrian Chadd #ifdef	RSS
259b8bc95cdSAdrian Chadd static int
260b8bc95cdSAdrian Chadd sysctl_netinet_intr_direct_queue_maxlen(SYSCTL_HANDLER_ARGS)
261b8bc95cdSAdrian Chadd {
262b8bc95cdSAdrian Chadd 	int error, qlimit;
263b8bc95cdSAdrian Chadd 
264b8bc95cdSAdrian Chadd 	netisr_getqlimit(&ip_direct_nh, &qlimit);
265b8bc95cdSAdrian Chadd 	error = sysctl_handle_int(oidp, &qlimit, 0, req);
266b8bc95cdSAdrian Chadd 	if (error || !req->newptr)
267b8bc95cdSAdrian Chadd 		return (error);
268b8bc95cdSAdrian Chadd 	if (qlimit < 1)
269b8bc95cdSAdrian Chadd 		return (EINVAL);
270b8bc95cdSAdrian Chadd 	return (netisr_setqlimit(&ip_direct_nh, qlimit));
271b8bc95cdSAdrian Chadd }
272b8bc95cdSAdrian Chadd SYSCTL_PROC(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_direct_queue_maxlen,
273b8bc95cdSAdrian Chadd     CTLTYPE_INT|CTLFLAG_RW, 0, 0, sysctl_netinet_intr_direct_queue_maxlen, "I",
274b8bc95cdSAdrian Chadd     "Maximum size of the IP direct input queue");
275b8bc95cdSAdrian Chadd 
276b8bc95cdSAdrian Chadd static int
277b8bc95cdSAdrian Chadd sysctl_netinet_intr_direct_queue_drops(SYSCTL_HANDLER_ARGS)
278b8bc95cdSAdrian Chadd {
279b8bc95cdSAdrian Chadd 	u_int64_t qdrops_long;
280b8bc95cdSAdrian Chadd 	int error, qdrops;
281b8bc95cdSAdrian Chadd 
282b8bc95cdSAdrian Chadd 	netisr_getqdrops(&ip_direct_nh, &qdrops_long);
283b8bc95cdSAdrian Chadd 	qdrops = qdrops_long;
284b8bc95cdSAdrian Chadd 	error = sysctl_handle_int(oidp, &qdrops, 0, req);
285b8bc95cdSAdrian Chadd 	if (error || !req->newptr)
286b8bc95cdSAdrian Chadd 		return (error);
287b8bc95cdSAdrian Chadd 	if (qdrops != 0)
288b8bc95cdSAdrian Chadd 		return (EINVAL);
289b8bc95cdSAdrian Chadd 	netisr_clearqdrops(&ip_direct_nh);
290b8bc95cdSAdrian Chadd 	return (0);
291b8bc95cdSAdrian Chadd }
292b8bc95cdSAdrian Chadd 
293b8bc95cdSAdrian Chadd SYSCTL_PROC(_net_inet_ip, IPCTL_INTRQDROPS, intr_direct_queue_drops,
294b8bc95cdSAdrian Chadd     CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_netinet_intr_direct_queue_drops, "I",
295b8bc95cdSAdrian Chadd     "Number of packets dropped from the IP direct input queue");
296b8bc95cdSAdrian Chadd #endif	/* RSS */
297b8bc95cdSAdrian Chadd 
298df8bae1dSRodney W. Grimes /*
299df8bae1dSRodney W. Grimes  * IP initialization: fill in IP protocol switch table.
300df8bae1dSRodney W. Grimes  * All protocols not implemented in kernel go to raw IP protocol handler.
301df8bae1dSRodney W. Grimes  */
302df8bae1dSRodney W. Grimes void
303f2565d68SRobert Watson ip_init(void)
304df8bae1dSRodney W. Grimes {
305f2565d68SRobert Watson 	struct protosw *pr;
306f2565d68SRobert Watson 	int i;
307df8bae1dSRodney W. Grimes 
308603724d3SBjoern A. Zeeb 	TAILQ_INIT(&V_in_ifaddrhead);
309603724d3SBjoern A. Zeeb 	V_in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &V_in_ifaddrhmask);
3101ed81b73SMarko Zec 
3111ed81b73SMarko Zec 	/* Initialize IP reassembly queue. */
3121dbefcc0SGleb Smirnoff 	ipreass_init();
3131ed81b73SMarko Zec 
3140b4b0b0fSJulian Elischer 	/* Initialize packet filter hooks. */
3150b4b0b0fSJulian Elischer 	V_inet_pfil_hook.ph_type = PFIL_TYPE_AF;
3160b4b0b0fSJulian Elischer 	V_inet_pfil_hook.ph_af = AF_INET;
3170b4b0b0fSJulian Elischer 	if ((i = pfil_head_register(&V_inet_pfil_hook)) != 0)
3180b4b0b0fSJulian Elischer 		printf("%s: WARNING: unable to register pfil hook, "
3190b4b0b0fSJulian Elischer 			"error %d\n", __func__, i);
3200b4b0b0fSJulian Elischer 
321ef91a976SAndrey V. Elsukov 	if (hhook_head_register(HHOOK_TYPE_IPSEC_IN, AF_INET,
322ef91a976SAndrey V. Elsukov 	    &V_ipsec_hhh_in[HHOOK_IPSEC_INET],
323ef91a976SAndrey V. Elsukov 	    HHOOK_WAITOK | HHOOK_HEADISINVNET) != 0)
324ef91a976SAndrey V. Elsukov 		printf("%s: WARNING: unable to register input helper hook\n",
325ef91a976SAndrey V. Elsukov 		    __func__);
326ef91a976SAndrey V. Elsukov 	if (hhook_head_register(HHOOK_TYPE_IPSEC_OUT, AF_INET,
327ef91a976SAndrey V. Elsukov 	    &V_ipsec_hhh_out[HHOOK_IPSEC_INET],
328ef91a976SAndrey V. Elsukov 	    HHOOK_WAITOK | HHOOK_HEADISINVNET) != 0)
329ef91a976SAndrey V. Elsukov 		printf("%s: WARNING: unable to register output helper hook\n",
330ef91a976SAndrey V. Elsukov 		    __func__);
331ef91a976SAndrey V. Elsukov 
3321ed81b73SMarko Zec 	/* Skip initialization of globals for non-default instances. */
333484149deSBjoern A. Zeeb #ifdef VIMAGE
334484149deSBjoern A. Zeeb 	if (!IS_DEFAULT_VNET(curvnet)) {
335484149deSBjoern A. Zeeb 		netisr_register_vnet(&ip_nh);
336484149deSBjoern A. Zeeb #ifdef	RSS
337484149deSBjoern A. Zeeb 		netisr_register_vnet(&ip_direct_nh);
338484149deSBjoern A. Zeeb #endif
3391ed81b73SMarko Zec 		return;
340484149deSBjoern A. Zeeb 	}
341484149deSBjoern A. Zeeb #endif
3421ed81b73SMarko Zec 
343f0ffb944SJulian Elischer 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
34402410549SRobert Watson 	if (pr == NULL)
345db09bef3SAndre Oppermann 		panic("ip_init: PF_INET not found");
346db09bef3SAndre Oppermann 
347db09bef3SAndre Oppermann 	/* Initialize the entire ip_protox[] array to IPPROTO_RAW. */
348df8bae1dSRodney W. Grimes 	for (i = 0; i < IPPROTO_MAX; i++)
349df8bae1dSRodney W. Grimes 		ip_protox[i] = pr - inetsw;
350db09bef3SAndre Oppermann 	/*
351db09bef3SAndre Oppermann 	 * Cycle through IP protocols and put them into the appropriate place
352db09bef3SAndre Oppermann 	 * in ip_protox[].
353db09bef3SAndre Oppermann 	 */
354f0ffb944SJulian Elischer 	for (pr = inetdomain.dom_protosw;
355f0ffb944SJulian Elischer 	    pr < inetdomain.dom_protoswNPROTOSW; pr++)
356df8bae1dSRodney W. Grimes 		if (pr->pr_domain->dom_family == PF_INET &&
357db09bef3SAndre Oppermann 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) {
358db09bef3SAndre Oppermann 			/* Be careful to only index valid IP protocols. */
359db77984cSSam Leffler 			if (pr->pr_protocol < IPPROTO_MAX)
360df8bae1dSRodney W. Grimes 				ip_protox[pr->pr_protocol] = pr - inetsw;
361db09bef3SAndre Oppermann 		}
362194a213eSAndrey A. Chernov 
363d4b5cae4SRobert Watson 	netisr_register(&ip_nh);
364b8bc95cdSAdrian Chadd #ifdef	RSS
365b8bc95cdSAdrian Chadd 	netisr_register(&ip_direct_nh);
366b8bc95cdSAdrian Chadd #endif
367df8bae1dSRodney W. Grimes }
368df8bae1dSRodney W. Grimes 
3699802380eSBjoern A. Zeeb #ifdef VIMAGE
3703f58662dSBjoern A. Zeeb static void
3713f58662dSBjoern A. Zeeb ip_destroy(void *unused __unused)
3729802380eSBjoern A. Zeeb {
37389856f7eSBjoern A. Zeeb 	struct ifnet *ifp;
374ef91a976SAndrey V. Elsukov 	int error;
3754d3dfd45SMikolaj Golub 
376484149deSBjoern A. Zeeb #ifdef	RSS
377484149deSBjoern A. Zeeb 	netisr_unregister_vnet(&ip_direct_nh);
378484149deSBjoern A. Zeeb #endif
379484149deSBjoern A. Zeeb 	netisr_unregister_vnet(&ip_nh);
380484149deSBjoern A. Zeeb 
381ef91a976SAndrey V. Elsukov 	if ((error = pfil_head_unregister(&V_inet_pfil_hook)) != 0)
3824d3dfd45SMikolaj Golub 		printf("%s: WARNING: unable to unregister pfil hook, "
383ef91a976SAndrey V. Elsukov 		    "error %d\n", __func__, error);
3849802380eSBjoern A. Zeeb 
385ef91a976SAndrey V. Elsukov 	error = hhook_head_deregister(V_ipsec_hhh_in[HHOOK_IPSEC_INET]);
386ef91a976SAndrey V. Elsukov 	if (error != 0) {
387ef91a976SAndrey V. Elsukov 		printf("%s: WARNING: unable to deregister input helper hook "
388ef91a976SAndrey V. Elsukov 		    "type HHOOK_TYPE_IPSEC_IN, id HHOOK_IPSEC_INET: "
389ef91a976SAndrey V. Elsukov 		    "error %d returned\n", __func__, error);
390ef91a976SAndrey V. Elsukov 	}
391ef91a976SAndrey V. Elsukov 	error = hhook_head_deregister(V_ipsec_hhh_out[HHOOK_IPSEC_INET]);
392ef91a976SAndrey V. Elsukov 	if (error != 0) {
393ef91a976SAndrey V. Elsukov 		printf("%s: WARNING: unable to deregister output helper hook "
394ef91a976SAndrey V. Elsukov 		    "type HHOOK_TYPE_IPSEC_OUT, id HHOOK_IPSEC_INET: "
395ef91a976SAndrey V. Elsukov 		    "error %d returned\n", __func__, error);
396ef91a976SAndrey V. Elsukov 	}
39789856f7eSBjoern A. Zeeb 
39889856f7eSBjoern A. Zeeb 	/* Remove the IPv4 addresses from all interfaces. */
39989856f7eSBjoern A. Zeeb 	in_ifscrub_all();
40089856f7eSBjoern A. Zeeb 
40189856f7eSBjoern A. Zeeb 	/* Make sure the IPv4 routes are gone as well. */
40289856f7eSBjoern A. Zeeb 	IFNET_RLOCK();
40389856f7eSBjoern A. Zeeb 	TAILQ_FOREACH(ifp, &V_ifnet, if_link)
40489856f7eSBjoern A. Zeeb 		rt_flushifroutes_af(ifp, AF_INET);
40589856f7eSBjoern A. Zeeb 	IFNET_RUNLOCK();
4069802380eSBjoern A. Zeeb 
407e3c2c634SGleb Smirnoff 	/* Destroy IP reassembly queue. */
4081dbefcc0SGleb Smirnoff 	ipreass_destroy();
40989856f7eSBjoern A. Zeeb 
41089856f7eSBjoern A. Zeeb 	/* Cleanup in_ifaddr hash table; should be empty. */
41189856f7eSBjoern A. Zeeb 	hashdestroy(V_in_ifaddrhashtbl, M_IFADDR, V_in_ifaddrhmask);
4129802380eSBjoern A. Zeeb }
4133f58662dSBjoern A. Zeeb 
4143f58662dSBjoern A. Zeeb VNET_SYSUNINIT(ip, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip_destroy, NULL);
4159802380eSBjoern A. Zeeb #endif
4169802380eSBjoern A. Zeeb 
417b8bc95cdSAdrian Chadd #ifdef	RSS
418b8bc95cdSAdrian Chadd /*
419b8bc95cdSAdrian Chadd  * IP direct input routine.
420b8bc95cdSAdrian Chadd  *
421b8bc95cdSAdrian Chadd  * This is called when reinjecting completed fragments where
422b8bc95cdSAdrian Chadd  * all of the previous checking and book-keeping has been done.
423b8bc95cdSAdrian Chadd  */
424b8bc95cdSAdrian Chadd void
425b8bc95cdSAdrian Chadd ip_direct_input(struct mbuf *m)
426b8bc95cdSAdrian Chadd {
427b8bc95cdSAdrian Chadd 	struct ip *ip;
428b8bc95cdSAdrian Chadd 	int hlen;
429b8bc95cdSAdrian Chadd 
430b8bc95cdSAdrian Chadd 	ip = mtod(m, struct ip *);
431b8bc95cdSAdrian Chadd 	hlen = ip->ip_hl << 2;
432b8bc95cdSAdrian Chadd 
433b8bc95cdSAdrian Chadd 	IPSTAT_INC(ips_delivered);
434b8bc95cdSAdrian Chadd 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(&m, &hlen, ip->ip_p);
435b8bc95cdSAdrian Chadd 	return;
436b8bc95cdSAdrian Chadd }
437b8bc95cdSAdrian Chadd #endif
438b8bc95cdSAdrian Chadd 
4394d2e3692SLuigi Rizzo /*
440df8bae1dSRodney W. Grimes  * Ip input routine.  Checksum and byte swap header.  If fragmented
441df8bae1dSRodney W. Grimes  * try to reassemble.  Process options.  Pass to next level.
442df8bae1dSRodney W. Grimes  */
443c67b1d17SGarrett Wollman void
444c67b1d17SGarrett Wollman ip_input(struct mbuf *m)
445df8bae1dSRodney W. Grimes {
4469188b4a1SAndre Oppermann 	struct ip *ip = NULL;
4475da9f8faSJosef Karthauser 	struct in_ifaddr *ia = NULL;
448ca925d9cSJonathan Lemon 	struct ifaddr *ifa;
4490aade26eSRobert Watson 	struct ifnet *ifp;
4509b932e9eSAndre Oppermann 	int    checkif, hlen = 0;
45121d172a3SGleb Smirnoff 	uint16_t sum, ip_len;
45202c1c707SAndre Oppermann 	int dchg = 0;				/* dest changed after fw */
453f51f805fSSam Leffler 	struct in_addr odst;			/* original dst address */
454b715f178SLuigi Rizzo 
455fe584538SDag-Erling Smørgrav 	M_ASSERTPKTHDR(m);
456db40007dSAndrew R. Reiter 
457ac9d7e26SMax Laier 	if (m->m_flags & M_FASTFWD_OURS) {
45876ff6dcfSAndre Oppermann 		m->m_flags &= ~M_FASTFWD_OURS;
45976ff6dcfSAndre Oppermann 		/* Set up some basics that will be used later. */
4602b25acc1SLuigi Rizzo 		ip = mtod(m, struct ip *);
46153be11f6SPoul-Henning Kamp 		hlen = ip->ip_hl << 2;
4628f134647SGleb Smirnoff 		ip_len = ntohs(ip->ip_len);
4639b932e9eSAndre Oppermann 		goto ours;
4642b25acc1SLuigi Rizzo 	}
4652b25acc1SLuigi Rizzo 
46686425c62SRobert Watson 	IPSTAT_INC(ips_total);
46758938916SGarrett Wollman 
46858938916SGarrett Wollman 	if (m->m_pkthdr.len < sizeof(struct ip))
46958938916SGarrett Wollman 		goto tooshort;
47058938916SGarrett Wollman 
471df8bae1dSRodney W. Grimes 	if (m->m_len < sizeof (struct ip) &&
4720b17fba7SAndre Oppermann 	    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
47386425c62SRobert Watson 		IPSTAT_INC(ips_toosmall);
474c67b1d17SGarrett Wollman 		return;
475df8bae1dSRodney W. Grimes 	}
476df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
47758938916SGarrett Wollman 
47853be11f6SPoul-Henning Kamp 	if (ip->ip_v != IPVERSION) {
47986425c62SRobert Watson 		IPSTAT_INC(ips_badvers);
480df8bae1dSRodney W. Grimes 		goto bad;
481df8bae1dSRodney W. Grimes 	}
48258938916SGarrett Wollman 
48353be11f6SPoul-Henning Kamp 	hlen = ip->ip_hl << 2;
484df8bae1dSRodney W. Grimes 	if (hlen < sizeof(struct ip)) {	/* minimum header length */
48586425c62SRobert Watson 		IPSTAT_INC(ips_badhlen);
486df8bae1dSRodney W. Grimes 		goto bad;
487df8bae1dSRodney W. Grimes 	}
488df8bae1dSRodney W. Grimes 	if (hlen > m->m_len) {
4890b17fba7SAndre Oppermann 		if ((m = m_pullup(m, hlen)) == NULL) {
49086425c62SRobert Watson 			IPSTAT_INC(ips_badhlen);
491c67b1d17SGarrett Wollman 			return;
492df8bae1dSRodney W. Grimes 		}
493df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
494df8bae1dSRodney W. Grimes 	}
49533841545SHajimu UMEMOTO 
49657f60867SMark Johnston 	IP_PROBE(receive, NULL, NULL, ip, m->m_pkthdr.rcvif, ip, NULL);
49757f60867SMark Johnston 
49833841545SHajimu UMEMOTO 	/* 127/8 must not appear on wire - RFC1122 */
4990aade26eSRobert Watson 	ifp = m->m_pkthdr.rcvif;
50033841545SHajimu UMEMOTO 	if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
50133841545SHajimu UMEMOTO 	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
5020aade26eSRobert Watson 		if ((ifp->if_flags & IFF_LOOPBACK) == 0) {
50386425c62SRobert Watson 			IPSTAT_INC(ips_badaddr);
50433841545SHajimu UMEMOTO 			goto bad;
50533841545SHajimu UMEMOTO 		}
50633841545SHajimu UMEMOTO 	}
50733841545SHajimu UMEMOTO 
508db4f9cc7SJonathan Lemon 	if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
509db4f9cc7SJonathan Lemon 		sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
510db4f9cc7SJonathan Lemon 	} else {
51158938916SGarrett Wollman 		if (hlen == sizeof(struct ip)) {
51247c861ecSBrian Somers 			sum = in_cksum_hdr(ip);
51358938916SGarrett Wollman 		} else {
51447c861ecSBrian Somers 			sum = in_cksum(m, hlen);
51558938916SGarrett Wollman 		}
516db4f9cc7SJonathan Lemon 	}
51747c861ecSBrian Somers 	if (sum) {
51886425c62SRobert Watson 		IPSTAT_INC(ips_badsum);
519df8bae1dSRodney W. Grimes 		goto bad;
520df8bae1dSRodney W. Grimes 	}
521df8bae1dSRodney W. Grimes 
52202b199f1SMax Laier #ifdef ALTQ
52302b199f1SMax Laier 	if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0)
52402b199f1SMax Laier 		/* packet is dropped by traffic conditioner */
52502b199f1SMax Laier 		return;
52602b199f1SMax Laier #endif
52702b199f1SMax Laier 
52821d172a3SGleb Smirnoff 	ip_len = ntohs(ip->ip_len);
52921d172a3SGleb Smirnoff 	if (ip_len < hlen) {
53086425c62SRobert Watson 		IPSTAT_INC(ips_badlen);
531df8bae1dSRodney W. Grimes 		goto bad;
532df8bae1dSRodney W. Grimes 	}
533df8bae1dSRodney W. Grimes 
534df8bae1dSRodney W. Grimes 	/*
535df8bae1dSRodney W. Grimes 	 * Check that the amount of data in the buffers
536df8bae1dSRodney W. Grimes 	 * is as at least much as the IP header would have us expect.
537df8bae1dSRodney W. Grimes 	 * Trim mbufs if longer than we expect.
538df8bae1dSRodney W. Grimes 	 * Drop packet if shorter than we expect.
539df8bae1dSRodney W. Grimes 	 */
54021d172a3SGleb Smirnoff 	if (m->m_pkthdr.len < ip_len) {
54158938916SGarrett Wollman tooshort:
54286425c62SRobert Watson 		IPSTAT_INC(ips_tooshort);
543df8bae1dSRodney W. Grimes 		goto bad;
544df8bae1dSRodney W. Grimes 	}
54521d172a3SGleb Smirnoff 	if (m->m_pkthdr.len > ip_len) {
546df8bae1dSRodney W. Grimes 		if (m->m_len == m->m_pkthdr.len) {
54721d172a3SGleb Smirnoff 			m->m_len = ip_len;
54821d172a3SGleb Smirnoff 			m->m_pkthdr.len = ip_len;
549df8bae1dSRodney W. Grimes 		} else
55021d172a3SGleb Smirnoff 			m_adj(m, ip_len - m->m_pkthdr.len);
551df8bae1dSRodney W. Grimes 	}
552b8bc95cdSAdrian Chadd 
553*ad9f4d6aSAndrey V. Elsukov 	/*
554*ad9f4d6aSAndrey V. Elsukov 	 * Try to forward the packet, but if we fail continue.
555*ad9f4d6aSAndrey V. Elsukov 	 * ip_tryforward() does inbound and outbound packet firewall
556*ad9f4d6aSAndrey V. Elsukov 	 * processing. If firewall has decided that destination becomes
557*ad9f4d6aSAndrey V. Elsukov 	 * our local address, it sets M_FASTFWD_OURS flag. In this
558*ad9f4d6aSAndrey V. Elsukov 	 * case skip another inbound firewall processing and update
559*ad9f4d6aSAndrey V. Elsukov 	 * ip pointer.
560*ad9f4d6aSAndrey V. Elsukov 	 */
561*ad9f4d6aSAndrey V. Elsukov 	if (V_ipforwarding != 0
562b2630c29SGeorge V. Neville-Neil #ifdef IPSEC
563*ad9f4d6aSAndrey V. Elsukov 	    && !key_havesp(IPSEC_DIR_INBOUND)
564*ad9f4d6aSAndrey V. Elsukov 	    && !key_havesp(IPSEC_DIR_OUTBOUND)
565*ad9f4d6aSAndrey V. Elsukov #endif
566*ad9f4d6aSAndrey V. Elsukov 	   ) {
567*ad9f4d6aSAndrey V. Elsukov 		if ((m = ip_tryforward(m)) == NULL)
56833872124SGeorge V. Neville-Neil 			return;
569*ad9f4d6aSAndrey V. Elsukov 		if (m->m_flags & M_FASTFWD_OURS) {
570*ad9f4d6aSAndrey V. Elsukov 			m->m_flags &= ~M_FASTFWD_OURS;
571*ad9f4d6aSAndrey V. Elsukov 			ip = mtod(m, struct ip *);
572*ad9f4d6aSAndrey V. Elsukov 			goto ours;
573*ad9f4d6aSAndrey V. Elsukov 		}
574*ad9f4d6aSAndrey V. Elsukov 	}
575*ad9f4d6aSAndrey V. Elsukov #ifdef IPSEC
57614dd6717SSam Leffler 	/*
577ffe8cd7bSBjoern A. Zeeb 	 * Bypass packet filtering for packets previously handled by IPsec.
57814dd6717SSam Leffler 	 */
579cc977adcSBjoern A. Zeeb 	if (ip_ipsec_filtertunnel(m))
580c21fd232SAndre Oppermann 		goto passin;
581*ad9f4d6aSAndrey V. Elsukov #endif
582c4ac87eaSDarren Reed 	/*
583134ea224SSam Leffler 	 * Run through list of hooks for input packets.
584f51f805fSSam Leffler 	 *
585f51f805fSSam Leffler 	 * NB: Beware of the destination address changing (e.g.
586f51f805fSSam Leffler 	 *     by NAT rewriting).  When this happens, tell
587f51f805fSSam Leffler 	 *     ip_forward to do the right thing.
588c4ac87eaSDarren Reed 	 */
589c21fd232SAndre Oppermann 
590c21fd232SAndre Oppermann 	/* Jump over all PFIL processing if hooks are not active. */
5910b4b0b0fSJulian Elischer 	if (!PFIL_HOOKED(&V_inet_pfil_hook))
592c21fd232SAndre Oppermann 		goto passin;
593c21fd232SAndre Oppermann 
594f51f805fSSam Leffler 	odst = ip->ip_dst;
5950b4b0b0fSJulian Elischer 	if (pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_IN, NULL) != 0)
596beec8214SDarren Reed 		return;
597134ea224SSam Leffler 	if (m == NULL)			/* consumed by filter */
598c4ac87eaSDarren Reed 		return;
5999b932e9eSAndre Oppermann 
600c4ac87eaSDarren Reed 	ip = mtod(m, struct ip *);
60102c1c707SAndre Oppermann 	dchg = (odst.s_addr != ip->ip_dst.s_addr);
6020aade26eSRobert Watson 	ifp = m->m_pkthdr.rcvif;
6039b932e9eSAndre Oppermann 
6049b932e9eSAndre Oppermann 	if (m->m_flags & M_FASTFWD_OURS) {
6059b932e9eSAndre Oppermann 		m->m_flags &= ~M_FASTFWD_OURS;
6069b932e9eSAndre Oppermann 		goto ours;
6079b932e9eSAndre Oppermann 	}
608ffdbf9daSAndrey V. Elsukov 	if (m->m_flags & M_IP_NEXTHOP) {
609de89d74bSLuiz Otavio O Souza 		if (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) {
610099dd043SAndre Oppermann 			/*
611ffdbf9daSAndrey V. Elsukov 			 * Directly ship the packet on.  This allows
612ffdbf9daSAndrey V. Elsukov 			 * forwarding packets originally destined to us
613ffdbf9daSAndrey V. Elsukov 			 * to some other directly connected host.
614099dd043SAndre Oppermann 			 */
615ffdbf9daSAndrey V. Elsukov 			ip_forward(m, 1);
616099dd043SAndre Oppermann 			return;
617099dd043SAndre Oppermann 		}
618ffdbf9daSAndrey V. Elsukov 	}
619c21fd232SAndre Oppermann passin:
62021d172a3SGleb Smirnoff 
62121d172a3SGleb Smirnoff 	/*
622df8bae1dSRodney W. Grimes 	 * Process options and, if not destined for us,
623df8bae1dSRodney W. Grimes 	 * ship it on.  ip_dooptions returns 1 when an
624df8bae1dSRodney W. Grimes 	 * error was detected (causing an icmp message
625df8bae1dSRodney W. Grimes 	 * to be sent and the original packet to be freed).
626df8bae1dSRodney W. Grimes 	 */
6279b932e9eSAndre Oppermann 	if (hlen > sizeof (struct ip) && ip_dooptions(m, 0))
628c67b1d17SGarrett Wollman 		return;
629df8bae1dSRodney W. Grimes 
630f0068c4aSGarrett Wollman         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
631f0068c4aSGarrett Wollman          * matter if it is destined to another node, or whether it is
632f0068c4aSGarrett Wollman          * a multicast one, RSVP wants it! and prevents it from being forwarded
633f0068c4aSGarrett Wollman          * anywhere else. Also checks if the rsvp daemon is running before
634f0068c4aSGarrett Wollman 	 * grabbing the packet.
635f0068c4aSGarrett Wollman          */
636603724d3SBjoern A. Zeeb 	if (V_rsvp_on && ip->ip_p==IPPROTO_RSVP)
637f0068c4aSGarrett Wollman 		goto ours;
638f0068c4aSGarrett Wollman 
639df8bae1dSRodney W. Grimes 	/*
640df8bae1dSRodney W. Grimes 	 * Check our list of addresses, to see if the packet is for us.
641cc766e04SGarrett Wollman 	 * If we don't have any addresses, assume any unicast packet
642cc766e04SGarrett Wollman 	 * we receive might be for us (and let the upper layers deal
643cc766e04SGarrett Wollman 	 * with it).
644df8bae1dSRodney W. Grimes 	 */
645603724d3SBjoern A. Zeeb 	if (TAILQ_EMPTY(&V_in_ifaddrhead) &&
646cc766e04SGarrett Wollman 	    (m->m_flags & (M_MCAST|M_BCAST)) == 0)
647cc766e04SGarrett Wollman 		goto ours;
648cc766e04SGarrett Wollman 
6497538a9a0SJonathan Lemon 	/*
650823db0e9SDon Lewis 	 * Enable a consistency check between the destination address
651823db0e9SDon Lewis 	 * and the arrival interface for a unicast packet (the RFC 1122
652823db0e9SDon Lewis 	 * strong ES model) if IP forwarding is disabled and the packet
653e15ae1b2SDon Lewis 	 * is not locally generated and the packet is not subject to
654e15ae1b2SDon Lewis 	 * 'ipfw fwd'.
6553f67c834SDon Lewis 	 *
6563f67c834SDon Lewis 	 * XXX - Checking also should be disabled if the destination
6573f67c834SDon Lewis 	 * address is ipnat'ed to a different interface.
6583f67c834SDon Lewis 	 *
659a8f12100SDon Lewis 	 * XXX - Checking is incompatible with IP aliases added
6603f67c834SDon Lewis 	 * to the loopback interface instead of the interface where
6613f67c834SDon Lewis 	 * the packets are received.
662a9771948SGleb Smirnoff 	 *
663a9771948SGleb Smirnoff 	 * XXX - This is the case for carp vhost IPs as well so we
664a9771948SGleb Smirnoff 	 * insert a workaround. If the packet got here, we already
665a9771948SGleb Smirnoff 	 * checked with carp_iamatch() and carp_forus().
666823db0e9SDon Lewis 	 */
667603724d3SBjoern A. Zeeb 	checkif = V_ip_checkinterface && (V_ipforwarding == 0) &&
6680aade26eSRobert Watson 	    ifp != NULL && ((ifp->if_flags & IFF_LOOPBACK) == 0) &&
66954bfbd51SWill Andrews 	    ifp->if_carp == NULL && (dchg == 0);
670823db0e9SDon Lewis 
671ca925d9cSJonathan Lemon 	/*
672ca925d9cSJonathan Lemon 	 * Check for exact addresses in the hash bucket.
673ca925d9cSJonathan Lemon 	 */
6742d9cfabaSRobert Watson 	/* IN_IFADDR_RLOCK(); */
6759b932e9eSAndre Oppermann 	LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
676f9e354dfSJulian Elischer 		/*
677823db0e9SDon Lewis 		 * If the address matches, verify that the packet
678823db0e9SDon Lewis 		 * arrived via the correct interface if checking is
679823db0e9SDon Lewis 		 * enabled.
680f9e354dfSJulian Elischer 		 */
6819b932e9eSAndre Oppermann 		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr &&
6828c0fec80SRobert Watson 		    (!checkif || ia->ia_ifp == ifp)) {
6837caf4ab7SGleb Smirnoff 			counter_u64_add(ia->ia_ifa.ifa_ipackets, 1);
6847caf4ab7SGleb Smirnoff 			counter_u64_add(ia->ia_ifa.ifa_ibytes,
6857caf4ab7SGleb Smirnoff 			    m->m_pkthdr.len);
6862d9cfabaSRobert Watson 			/* IN_IFADDR_RUNLOCK(); */
687ed1ff184SJulian Elischer 			goto ours;
688ca925d9cSJonathan Lemon 		}
6898c0fec80SRobert Watson 	}
6902d9cfabaSRobert Watson 	/* IN_IFADDR_RUNLOCK(); */
6912d9cfabaSRobert Watson 
692823db0e9SDon Lewis 	/*
693ca925d9cSJonathan Lemon 	 * Check for broadcast addresses.
694ca925d9cSJonathan Lemon 	 *
695ca925d9cSJonathan Lemon 	 * Only accept broadcast packets that arrive via the matching
696ca925d9cSJonathan Lemon 	 * interface.  Reception of forwarded directed broadcasts would
697ca925d9cSJonathan Lemon 	 * be handled via ip_forward() and ether_output() with the loopback
698ca925d9cSJonathan Lemon 	 * into the stack for SIMPLEX interfaces handled by ether_output().
699823db0e9SDon Lewis 	 */
7000aade26eSRobert Watson 	if (ifp != NULL && ifp->if_flags & IFF_BROADCAST) {
701137f91e8SJohn Baldwin 		IF_ADDR_RLOCK(ifp);
7020aade26eSRobert Watson 	        TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
703ca925d9cSJonathan Lemon 			if (ifa->ifa_addr->sa_family != AF_INET)
704ca925d9cSJonathan Lemon 				continue;
705ca925d9cSJonathan Lemon 			ia = ifatoia(ifa);
706df8bae1dSRodney W. Grimes 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
7070aade26eSRobert Watson 			    ip->ip_dst.s_addr) {
7087caf4ab7SGleb Smirnoff 				counter_u64_add(ia->ia_ifa.ifa_ipackets, 1);
7097caf4ab7SGleb Smirnoff 				counter_u64_add(ia->ia_ifa.ifa_ibytes,
7107caf4ab7SGleb Smirnoff 				    m->m_pkthdr.len);
711137f91e8SJohn Baldwin 				IF_ADDR_RUNLOCK(ifp);
712df8bae1dSRodney W. Grimes 				goto ours;
7130aade26eSRobert Watson 			}
7140ac40133SBrian Somers #ifdef BOOTP_COMPAT
7150aade26eSRobert Watson 			if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) {
7167caf4ab7SGleb Smirnoff 				counter_u64_add(ia->ia_ifa.ifa_ipackets, 1);
7177caf4ab7SGleb Smirnoff 				counter_u64_add(ia->ia_ifa.ifa_ibytes,
7187caf4ab7SGleb Smirnoff 				    m->m_pkthdr.len);
719137f91e8SJohn Baldwin 				IF_ADDR_RUNLOCK(ifp);
720ca925d9cSJonathan Lemon 				goto ours;
7210aade26eSRobert Watson 			}
7220ac40133SBrian Somers #endif
723df8bae1dSRodney W. Grimes 		}
724137f91e8SJohn Baldwin 		IF_ADDR_RUNLOCK(ifp);
72519e5b0a7SRobert Watson 		ia = NULL;
726df8bae1dSRodney W. Grimes 	}
727f8429ca2SBruce M Simpson 	/* RFC 3927 2.7: Do not forward datagrams for 169.254.0.0/16. */
728f8429ca2SBruce M Simpson 	if (IN_LINKLOCAL(ntohl(ip->ip_dst.s_addr))) {
72986425c62SRobert Watson 		IPSTAT_INC(ips_cantforward);
730f8429ca2SBruce M Simpson 		m_freem(m);
731f8429ca2SBruce M Simpson 		return;
732f8429ca2SBruce M Simpson 	}
733df8bae1dSRodney W. Grimes 	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
734603724d3SBjoern A. Zeeb 		if (V_ip_mrouter) {
735df8bae1dSRodney W. Grimes 			/*
736df8bae1dSRodney W. Grimes 			 * If we are acting as a multicast router, all
737df8bae1dSRodney W. Grimes 			 * incoming multicast packets are passed to the
738df8bae1dSRodney W. Grimes 			 * kernel-level multicast forwarding function.
739df8bae1dSRodney W. Grimes 			 * The packet is returned (relatively) intact; if
740df8bae1dSRodney W. Grimes 			 * ip_mforward() returns a non-zero value, the packet
741df8bae1dSRodney W. Grimes 			 * must be discarded, else it may be accepted below.
742df8bae1dSRodney W. Grimes 			 */
7430aade26eSRobert Watson 			if (ip_mforward && ip_mforward(ip, ifp, m, 0) != 0) {
74486425c62SRobert Watson 				IPSTAT_INC(ips_cantforward);
745df8bae1dSRodney W. Grimes 				m_freem(m);
746c67b1d17SGarrett Wollman 				return;
747df8bae1dSRodney W. Grimes 			}
748df8bae1dSRodney W. Grimes 
749df8bae1dSRodney W. Grimes 			/*
75011612afaSDima Dorfman 			 * The process-level routing daemon needs to receive
751df8bae1dSRodney W. Grimes 			 * all multicast IGMP packets, whether or not this
752df8bae1dSRodney W. Grimes 			 * host belongs to their destination groups.
753df8bae1dSRodney W. Grimes 			 */
754df8bae1dSRodney W. Grimes 			if (ip->ip_p == IPPROTO_IGMP)
755df8bae1dSRodney W. Grimes 				goto ours;
75686425c62SRobert Watson 			IPSTAT_INC(ips_forward);
757df8bae1dSRodney W. Grimes 		}
758df8bae1dSRodney W. Grimes 		/*
759d10910e6SBruce M Simpson 		 * Assume the packet is for us, to avoid prematurely taking
760d10910e6SBruce M Simpson 		 * a lock on the in_multi hash. Protocols must perform
761d10910e6SBruce M Simpson 		 * their own filtering and update statistics accordingly.
762df8bae1dSRodney W. Grimes 		 */
763df8bae1dSRodney W. Grimes 		goto ours;
764df8bae1dSRodney W. Grimes 	}
765df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
766df8bae1dSRodney W. Grimes 		goto ours;
767df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == INADDR_ANY)
768df8bae1dSRodney W. Grimes 		goto ours;
769df8bae1dSRodney W. Grimes 
7706a800098SYoshinobu Inoue 	/*
771df8bae1dSRodney W. Grimes 	 * Not for us; forward if possible and desirable.
772df8bae1dSRodney W. Grimes 	 */
773603724d3SBjoern A. Zeeb 	if (V_ipforwarding == 0) {
77486425c62SRobert Watson 		IPSTAT_INC(ips_cantforward);
775df8bae1dSRodney W. Grimes 		m_freem(m);
776546f251bSChris D. Faulhaber 	} else {
7779b932e9eSAndre Oppermann 		ip_forward(m, dchg);
778546f251bSChris D. Faulhaber 	}
779c67b1d17SGarrett Wollman 	return;
780df8bae1dSRodney W. Grimes 
781df8bae1dSRodney W. Grimes ours:
782d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
783d0ebc0d2SYaroslav Tykhiy 	/*
784d0ebc0d2SYaroslav Tykhiy 	 * IPSTEALTH: Process non-routing options only
785d0ebc0d2SYaroslav Tykhiy 	 * if the packet is destined for us.
786d0ebc0d2SYaroslav Tykhiy 	 */
7877caf4ab7SGleb Smirnoff 	if (V_ipstealth && hlen > sizeof (struct ip) && ip_dooptions(m, 1))
788d0ebc0d2SYaroslav Tykhiy 		return;
789d0ebc0d2SYaroslav Tykhiy #endif /* IPSTEALTH */
790d0ebc0d2SYaroslav Tykhiy 
79163f8d699SJordan K. Hubbard 	/*
792b6ea1aa5SRuslan Ermilov 	 * Attempt reassembly; if it succeeds, proceed.
793ac9d7e26SMax Laier 	 * ip_reass() will return a different mbuf.
794df8bae1dSRodney W. Grimes 	 */
7958f134647SGleb Smirnoff 	if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) {
796aa69c612SGleb Smirnoff 		/* XXXGL: shouldn't we save & set m_flags? */
797f0cada84SAndre Oppermann 		m = ip_reass(m);
798f0cada84SAndre Oppermann 		if (m == NULL)
799c67b1d17SGarrett Wollman 			return;
8006a800098SYoshinobu Inoue 		ip = mtod(m, struct ip *);
8017e2df452SRuslan Ermilov 		/* Get the header length of the reassembled packet */
80253be11f6SPoul-Henning Kamp 		hlen = ip->ip_hl << 2;
803f0cada84SAndre Oppermann 	}
804f0cada84SAndre Oppermann 
805b2630c29SGeorge V. Neville-Neil #ifdef IPSEC
80633841545SHajimu UMEMOTO 	/*
80733841545SHajimu UMEMOTO 	 * enforce IPsec policy checking if we are seeing last header.
80833841545SHajimu UMEMOTO 	 * note that we do not visit this with protocols with pcb layer
80933841545SHajimu UMEMOTO 	 * code - like udp/tcp/raw ip.
81033841545SHajimu UMEMOTO 	 */
811e58320f1SAndrey V. Elsukov 	if (ip_ipsec_input(m, ip->ip_p) != 0)
81233841545SHajimu UMEMOTO 		goto bad;
813b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */
81433841545SHajimu UMEMOTO 
815df8bae1dSRodney W. Grimes 	/*
816df8bae1dSRodney W. Grimes 	 * Switch out to protocol's input routine.
817df8bae1dSRodney W. Grimes 	 */
81886425c62SRobert Watson 	IPSTAT_INC(ips_delivered);
8199b932e9eSAndre Oppermann 
8208f5a8818SKevin Lo 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(&m, &hlen, ip->ip_p);
821c67b1d17SGarrett Wollman 	return;
822df8bae1dSRodney W. Grimes bad:
823df8bae1dSRodney W. Grimes 	m_freem(m);
824c67b1d17SGarrett Wollman }
825c67b1d17SGarrett Wollman 
826c67b1d17SGarrett Wollman /*
827df8bae1dSRodney W. Grimes  * IP timer processing;
828df8bae1dSRodney W. Grimes  * if a timer expires on a reassembly
829df8bae1dSRodney W. Grimes  * queue, discard it.
830df8bae1dSRodney W. Grimes  */
831df8bae1dSRodney W. Grimes void
832f2565d68SRobert Watson ip_slowtimo(void)
833df8bae1dSRodney W. Grimes {
8348b615593SMarko Zec 	VNET_ITERATOR_DECL(vnet_iter);
835df8bae1dSRodney W. Grimes 
8365ee847d3SRobert Watson 	VNET_LIST_RLOCK_NOSLEEP();
8378b615593SMarko Zec 	VNET_FOREACH(vnet_iter) {
8388b615593SMarko Zec 		CURVNET_SET(vnet_iter);
8391dbefcc0SGleb Smirnoff 		ipreass_slowtimo();
8408b615593SMarko Zec 		CURVNET_RESTORE();
8418b615593SMarko Zec 	}
8425ee847d3SRobert Watson 	VNET_LIST_RUNLOCK_NOSLEEP();
843df8bae1dSRodney W. Grimes }
844df8bae1dSRodney W. Grimes 
8459802380eSBjoern A. Zeeb void
8469802380eSBjoern A. Zeeb ip_drain(void)
8479802380eSBjoern A. Zeeb {
8489802380eSBjoern A. Zeeb 	VNET_ITERATOR_DECL(vnet_iter);
8499802380eSBjoern A. Zeeb 
8509802380eSBjoern A. Zeeb 	VNET_LIST_RLOCK_NOSLEEP();
8519802380eSBjoern A. Zeeb 	VNET_FOREACH(vnet_iter) {
8529802380eSBjoern A. Zeeb 		CURVNET_SET(vnet_iter);
8531dbefcc0SGleb Smirnoff 		ipreass_drain();
8548b615593SMarko Zec 		CURVNET_RESTORE();
8558b615593SMarko Zec 	}
8565ee847d3SRobert Watson 	VNET_LIST_RUNLOCK_NOSLEEP();
857df8bae1dSRodney W. Grimes }
858df8bae1dSRodney W. Grimes 
859df8bae1dSRodney W. Grimes /*
860de38924dSAndre Oppermann  * The protocol to be inserted into ip_protox[] must be already registered
861de38924dSAndre Oppermann  * in inetsw[], either statically or through pf_proto_register().
862de38924dSAndre Oppermann  */
863de38924dSAndre Oppermann int
8641b48d245SBjoern A. Zeeb ipproto_register(short ipproto)
865de38924dSAndre Oppermann {
866de38924dSAndre Oppermann 	struct protosw *pr;
867de38924dSAndre Oppermann 
868de38924dSAndre Oppermann 	/* Sanity checks. */
8691b48d245SBjoern A. Zeeb 	if (ipproto <= 0 || ipproto >= IPPROTO_MAX)
870de38924dSAndre Oppermann 		return (EPROTONOSUPPORT);
871de38924dSAndre Oppermann 
872de38924dSAndre Oppermann 	/*
873de38924dSAndre Oppermann 	 * The protocol slot must not be occupied by another protocol
874de38924dSAndre Oppermann 	 * already.  An index pointing to IPPROTO_RAW is unused.
875de38924dSAndre Oppermann 	 */
876de38924dSAndre Oppermann 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
877de38924dSAndre Oppermann 	if (pr == NULL)
878de38924dSAndre Oppermann 		return (EPFNOSUPPORT);
879de38924dSAndre Oppermann 	if (ip_protox[ipproto] != pr - inetsw)	/* IPPROTO_RAW */
880de38924dSAndre Oppermann 		return (EEXIST);
881de38924dSAndre Oppermann 
882de38924dSAndre Oppermann 	/* Find the protocol position in inetsw[] and set the index. */
883de38924dSAndre Oppermann 	for (pr = inetdomain.dom_protosw;
884de38924dSAndre Oppermann 	     pr < inetdomain.dom_protoswNPROTOSW; pr++) {
885de38924dSAndre Oppermann 		if (pr->pr_domain->dom_family == PF_INET &&
886de38924dSAndre Oppermann 		    pr->pr_protocol && pr->pr_protocol == ipproto) {
887de38924dSAndre Oppermann 			ip_protox[pr->pr_protocol] = pr - inetsw;
888de38924dSAndre Oppermann 			return (0);
889de38924dSAndre Oppermann 		}
890de38924dSAndre Oppermann 	}
891de38924dSAndre Oppermann 	return (EPROTONOSUPPORT);
892de38924dSAndre Oppermann }
893de38924dSAndre Oppermann 
894de38924dSAndre Oppermann int
8951b48d245SBjoern A. Zeeb ipproto_unregister(short ipproto)
896de38924dSAndre Oppermann {
897de38924dSAndre Oppermann 	struct protosw *pr;
898de38924dSAndre Oppermann 
899de38924dSAndre Oppermann 	/* Sanity checks. */
9001b48d245SBjoern A. Zeeb 	if (ipproto <= 0 || ipproto >= IPPROTO_MAX)
901de38924dSAndre Oppermann 		return (EPROTONOSUPPORT);
902de38924dSAndre Oppermann 
903de38924dSAndre Oppermann 	/* Check if the protocol was indeed registered. */
904de38924dSAndre Oppermann 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
905de38924dSAndre Oppermann 	if (pr == NULL)
906de38924dSAndre Oppermann 		return (EPFNOSUPPORT);
907de38924dSAndre Oppermann 	if (ip_protox[ipproto] == pr - inetsw)  /* IPPROTO_RAW */
908de38924dSAndre Oppermann 		return (ENOENT);
909de38924dSAndre Oppermann 
910de38924dSAndre Oppermann 	/* Reset the protocol slot to IPPROTO_RAW. */
911de38924dSAndre Oppermann 	ip_protox[ipproto] = pr - inetsw;
912de38924dSAndre Oppermann 	return (0);
913de38924dSAndre Oppermann }
914de38924dSAndre Oppermann 
915df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = {
916df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
917df8bae1dSRodney W. Grimes 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
918df8bae1dSRodney W. Grimes 	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
919df8bae1dSRodney W. Grimes 	EMSGSIZE,	EHOSTUNREACH,	0,		0,
920fcaf9f91SMike Silbersack 	0,		0,		EHOSTUNREACH,	0,
9213b8123b7SJesper Skriver 	ENOPROTOOPT,	ECONNREFUSED
922df8bae1dSRodney W. Grimes };
923df8bae1dSRodney W. Grimes 
924df8bae1dSRodney W. Grimes /*
925df8bae1dSRodney W. Grimes  * Forward a packet.  If some error occurs return the sender
926df8bae1dSRodney W. Grimes  * an icmp packet.  Note we can't always generate a meaningful
927df8bae1dSRodney W. Grimes  * icmp message because icmp doesn't have a large enough repertoire
928df8bae1dSRodney W. Grimes  * of codes and types.
929df8bae1dSRodney W. Grimes  *
930df8bae1dSRodney W. Grimes  * If not forwarding, just drop the packet.  This could be confusing
931df8bae1dSRodney W. Grimes  * if ipforwarding was zero but some routing protocol was advancing
932df8bae1dSRodney W. Grimes  * us as a gateway to somewhere.  However, we must let the routing
933df8bae1dSRodney W. Grimes  * protocol deal with that.
934df8bae1dSRodney W. Grimes  *
935df8bae1dSRodney W. Grimes  * The srcrt parameter indicates whether the packet is being forwarded
936df8bae1dSRodney W. Grimes  * via a source route.
937df8bae1dSRodney W. Grimes  */
9389b932e9eSAndre Oppermann void
9399b932e9eSAndre Oppermann ip_forward(struct mbuf *m, int srcrt)
940df8bae1dSRodney W. Grimes {
9412b25acc1SLuigi Rizzo 	struct ip *ip = mtod(m, struct ip *);
942efbad259SEdward Tomasz Napierala 	struct in_ifaddr *ia;
943df8bae1dSRodney W. Grimes 	struct mbuf *mcopy;
944d14122b0SErmal Luçi 	struct sockaddr_in *sin;
9459b932e9eSAndre Oppermann 	struct in_addr dest;
946b835b6feSBjoern A. Zeeb 	struct route ro;
947c773494eSAndre Oppermann 	int error, type = 0, code = 0, mtu = 0;
9483efc3014SJulian Elischer 
9499b932e9eSAndre Oppermann 	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
95086425c62SRobert Watson 		IPSTAT_INC(ips_cantforward);
951df8bae1dSRodney W. Grimes 		m_freem(m);
952df8bae1dSRodney W. Grimes 		return;
953df8bae1dSRodney W. Grimes 	}
9548922ddbeSAndrey V. Elsukov #ifdef IPSEC
9558922ddbeSAndrey V. Elsukov 	if (ip_ipsec_fwd(m) != 0) {
9568922ddbeSAndrey V. Elsukov 		IPSTAT_INC(ips_cantforward);
9578922ddbeSAndrey V. Elsukov 		m_freem(m);
9588922ddbeSAndrey V. Elsukov 		return;
9598922ddbeSAndrey V. Elsukov 	}
9608922ddbeSAndrey V. Elsukov #endif /* IPSEC */
9611b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
962603724d3SBjoern A. Zeeb 	if (!V_ipstealth) {
9631b968362SDag-Erling Smørgrav #endif
964df8bae1dSRodney W. Grimes 		if (ip->ip_ttl <= IPTTLDEC) {
9651b968362SDag-Erling Smørgrav 			icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
96602c1c707SAndre Oppermann 			    0, 0);
967df8bae1dSRodney W. Grimes 			return;
968df8bae1dSRodney W. Grimes 		}
9691b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
9701b968362SDag-Erling Smørgrav 	}
9711b968362SDag-Erling Smørgrav #endif
972df8bae1dSRodney W. Grimes 
973d14122b0SErmal Luçi 	bzero(&ro, sizeof(ro));
974d14122b0SErmal Luçi 	sin = (struct sockaddr_in *)&ro.ro_dst;
975d14122b0SErmal Luçi 	sin->sin_family = AF_INET;
976d14122b0SErmal Luçi 	sin->sin_len = sizeof(*sin);
977d14122b0SErmal Luçi 	sin->sin_addr = ip->ip_dst;
978d14122b0SErmal Luçi #ifdef RADIX_MPATH
979d14122b0SErmal Luçi 	rtalloc_mpath_fib(&ro,
980d14122b0SErmal Luçi 	    ntohl(ip->ip_src.s_addr ^ ip->ip_dst.s_addr),
981d14122b0SErmal Luçi 	    M_GETFIB(m));
982d14122b0SErmal Luçi #else
983d14122b0SErmal Luçi 	in_rtalloc_ign(&ro, 0, M_GETFIB(m));
984d14122b0SErmal Luçi #endif
985d14122b0SErmal Luçi 	if (ro.ro_rt != NULL) {
986d14122b0SErmal Luçi 		ia = ifatoia(ro.ro_rt->rt_ifa);
987d14122b0SErmal Luçi 		ifa_ref(&ia->ia_ifa);
98856844a62SErmal Luçi 	} else
98956844a62SErmal Luçi 		ia = NULL;
990efbad259SEdward Tomasz Napierala #ifndef IPSEC
991efbad259SEdward Tomasz Napierala 	/*
992efbad259SEdward Tomasz Napierala 	 * 'ia' may be NULL if there is no route for this destination.
993efbad259SEdward Tomasz Napierala 	 * In case of IPsec, Don't discard it just yet, but pass it to
994efbad259SEdward Tomasz Napierala 	 * ip_output in case of outgoing IPsec policy.
995efbad259SEdward Tomasz Napierala 	 */
996d23d475fSGuido van Rooij 	if (!srcrt && ia == NULL) {
99702c1c707SAndre Oppermann 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
998d14122b0SErmal Luçi 		RO_RTFREE(&ro);
999df8bae1dSRodney W. Grimes 		return;
100002c1c707SAndre Oppermann 	}
1001efbad259SEdward Tomasz Napierala #endif
1002df8bae1dSRodney W. Grimes 
1003df8bae1dSRodney W. Grimes 	/*
1004bfef7ed4SIan Dowse 	 * Save the IP header and at most 8 bytes of the payload,
1005bfef7ed4SIan Dowse 	 * in case we need to generate an ICMP message to the src.
1006bfef7ed4SIan Dowse 	 *
10074d2e3692SLuigi Rizzo 	 * XXX this can be optimized a lot by saving the data in a local
10084d2e3692SLuigi Rizzo 	 * buffer on the stack (72 bytes at most), and only allocating the
10094d2e3692SLuigi Rizzo 	 * mbuf if really necessary. The vast majority of the packets
10104d2e3692SLuigi Rizzo 	 * are forwarded without having to send an ICMP back (either
10114d2e3692SLuigi Rizzo 	 * because unnecessary, or because rate limited), so we are
10124d2e3692SLuigi Rizzo 	 * really we are wasting a lot of work here.
10134d2e3692SLuigi Rizzo 	 *
1014c3bef61eSKevin Lo 	 * We don't use m_copym() because it might return a reference
1015bfef7ed4SIan Dowse 	 * to a shared cluster. Both this function and ip_output()
1016bfef7ed4SIan Dowse 	 * assume exclusive access to the IP header in `m', so any
1017bfef7ed4SIan Dowse 	 * data in a cluster may change before we reach icmp_error().
1018df8bae1dSRodney W. Grimes 	 */
1019dc4ad05eSGleb Smirnoff 	mcopy = m_gethdr(M_NOWAIT, m->m_type);
1020eb1b1807SGleb Smirnoff 	if (mcopy != NULL && !m_dup_pkthdr(mcopy, m, M_NOWAIT)) {
10219967cafcSSam Leffler 		/*
10229967cafcSSam Leffler 		 * It's probably ok if the pkthdr dup fails (because
10239967cafcSSam Leffler 		 * the deep copy of the tag chain failed), but for now
10249967cafcSSam Leffler 		 * be conservative and just discard the copy since
10259967cafcSSam Leffler 		 * code below may some day want the tags.
10269967cafcSSam Leffler 		 */
10279967cafcSSam Leffler 		m_free(mcopy);
10289967cafcSSam Leffler 		mcopy = NULL;
10299967cafcSSam Leffler 	}
1030bfef7ed4SIan Dowse 	if (mcopy != NULL) {
10318f134647SGleb Smirnoff 		mcopy->m_len = min(ntohs(ip->ip_len), M_TRAILINGSPACE(mcopy));
1032e6b0a570SBruce M Simpson 		mcopy->m_pkthdr.len = mcopy->m_len;
1033bfef7ed4SIan Dowse 		m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
1034bfef7ed4SIan Dowse 	}
103504287599SRuslan Ermilov 
103604287599SRuslan Ermilov #ifdef IPSTEALTH
1037603724d3SBjoern A. Zeeb 	if (!V_ipstealth) {
103804287599SRuslan Ermilov #endif
103904287599SRuslan Ermilov 		ip->ip_ttl -= IPTTLDEC;
104004287599SRuslan Ermilov #ifdef IPSTEALTH
104104287599SRuslan Ermilov 	}
104204287599SRuslan Ermilov #endif
1043df8bae1dSRodney W. Grimes 
1044df8bae1dSRodney W. Grimes 	/*
1045df8bae1dSRodney W. Grimes 	 * If forwarding packet using same interface that it came in on,
1046df8bae1dSRodney W. Grimes 	 * perhaps should send a redirect to sender to shortcut a hop.
1047df8bae1dSRodney W. Grimes 	 * Only send redirect if source is sending directly to us,
1048df8bae1dSRodney W. Grimes 	 * and if packet was not source routed (or has any options).
1049df8bae1dSRodney W. Grimes 	 * Also, don't send redirect if forwarding using a default route
1050df8bae1dSRodney W. Grimes 	 * or a route modified by a redirect.
1051df8bae1dSRodney W. Grimes 	 */
10529b932e9eSAndre Oppermann 	dest.s_addr = 0;
1053efbad259SEdward Tomasz Napierala 	if (!srcrt && V_ipsendredirects &&
1054efbad259SEdward Tomasz Napierala 	    ia != NULL && ia->ia_ifp == m->m_pkthdr.rcvif) {
105502c1c707SAndre Oppermann 		struct rtentry *rt;
105602c1c707SAndre Oppermann 
105702c1c707SAndre Oppermann 		rt = ro.ro_rt;
105802c1c707SAndre Oppermann 
105902c1c707SAndre Oppermann 		if (rt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
10609b932e9eSAndre Oppermann 		    satosin(rt_key(rt))->sin_addr.s_addr != 0) {
1061df8bae1dSRodney W. Grimes #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
1062df8bae1dSRodney W. Grimes 			u_long src = ntohl(ip->ip_src.s_addr);
1063df8bae1dSRodney W. Grimes 
1064df8bae1dSRodney W. Grimes 			if (RTA(rt) &&
1065df8bae1dSRodney W. Grimes 			    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1066df8bae1dSRodney W. Grimes 				if (rt->rt_flags & RTF_GATEWAY)
10679b932e9eSAndre Oppermann 					dest.s_addr = satosin(rt->rt_gateway)->sin_addr.s_addr;
1068df8bae1dSRodney W. Grimes 				else
10699b932e9eSAndre Oppermann 					dest.s_addr = ip->ip_dst.s_addr;
1070df8bae1dSRodney W. Grimes 				/* Router requirements says to only send host redirects */
1071df8bae1dSRodney W. Grimes 				type = ICMP_REDIRECT;
1072df8bae1dSRodney W. Grimes 				code = ICMP_REDIRECT_HOST;
1073df8bae1dSRodney W. Grimes 			}
1074df8bae1dSRodney W. Grimes 		}
107502c1c707SAndre Oppermann 	}
1076df8bae1dSRodney W. Grimes 
1077b835b6feSBjoern A. Zeeb 	error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL, NULL);
1078b835b6feSBjoern A. Zeeb 
1079b835b6feSBjoern A. Zeeb 	if (error == EMSGSIZE && ro.ro_rt)
1080e3a7aa6fSGleb Smirnoff 		mtu = ro.ro_rt->rt_mtu;
1081bf984051SGleb Smirnoff 	RO_RTFREE(&ro);
1082b835b6feSBjoern A. Zeeb 
1083df8bae1dSRodney W. Grimes 	if (error)
108486425c62SRobert Watson 		IPSTAT_INC(ips_cantforward);
1085df8bae1dSRodney W. Grimes 	else {
108686425c62SRobert Watson 		IPSTAT_INC(ips_forward);
1087df8bae1dSRodney W. Grimes 		if (type)
108886425c62SRobert Watson 			IPSTAT_INC(ips_redirectsent);
1089df8bae1dSRodney W. Grimes 		else {
10909188b4a1SAndre Oppermann 			if (mcopy)
1091df8bae1dSRodney W. Grimes 				m_freem(mcopy);
10928c0fec80SRobert Watson 			if (ia != NULL)
10938c0fec80SRobert Watson 				ifa_free(&ia->ia_ifa);
1094df8bae1dSRodney W. Grimes 			return;
1095df8bae1dSRodney W. Grimes 		}
1096df8bae1dSRodney W. Grimes 	}
10978c0fec80SRobert Watson 	if (mcopy == NULL) {
10988c0fec80SRobert Watson 		if (ia != NULL)
10998c0fec80SRobert Watson 			ifa_free(&ia->ia_ifa);
1100df8bae1dSRodney W. Grimes 		return;
11018c0fec80SRobert Watson 	}
1102df8bae1dSRodney W. Grimes 
1103df8bae1dSRodney W. Grimes 	switch (error) {
1104df8bae1dSRodney W. Grimes 
1105df8bae1dSRodney W. Grimes 	case 0:				/* forwarded, but need redirect */
1106df8bae1dSRodney W. Grimes 		/* type, code set above */
1107df8bae1dSRodney W. Grimes 		break;
1108df8bae1dSRodney W. Grimes 
1109efbad259SEdward Tomasz Napierala 	case ENETUNREACH:
1110df8bae1dSRodney W. Grimes 	case EHOSTUNREACH:
1111df8bae1dSRodney W. Grimes 	case ENETDOWN:
1112df8bae1dSRodney W. Grimes 	case EHOSTDOWN:
1113df8bae1dSRodney W. Grimes 	default:
1114df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1115df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_HOST;
1116df8bae1dSRodney W. Grimes 		break;
1117df8bae1dSRodney W. Grimes 
1118df8bae1dSRodney W. Grimes 	case EMSGSIZE:
1119df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1120df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_NEEDFRAG;
11211dfcf0d2SAndre Oppermann 
1122b2630c29SGeorge V. Neville-Neil #ifdef IPSEC
1123b835b6feSBjoern A. Zeeb 		/*
1124b835b6feSBjoern A. Zeeb 		 * If IPsec is configured for this path,
1125b835b6feSBjoern A. Zeeb 		 * override any possibly mtu value set by ip_output.
1126b835b6feSBjoern A. Zeeb 		 */
11271c044382SBjoern A. Zeeb 		mtu = ip_ipsec_mtu(mcopy, mtu);
1128b2630c29SGeorge V. Neville-Neil #endif /* IPSEC */
11299b932e9eSAndre Oppermann 		/*
1130b835b6feSBjoern A. Zeeb 		 * If the MTU was set before make sure we are below the
1131b835b6feSBjoern A. Zeeb 		 * interface MTU.
1132ab48768bSAndre Oppermann 		 * If the MTU wasn't set before use the interface mtu or
1133ab48768bSAndre Oppermann 		 * fall back to the next smaller mtu step compared to the
1134ab48768bSAndre Oppermann 		 * current packet size.
11359b932e9eSAndre Oppermann 		 */
1136b835b6feSBjoern A. Zeeb 		if (mtu != 0) {
1137b835b6feSBjoern A. Zeeb 			if (ia != NULL)
1138b835b6feSBjoern A. Zeeb 				mtu = min(mtu, ia->ia_ifp->if_mtu);
1139b835b6feSBjoern A. Zeeb 		} else {
1140ab48768bSAndre Oppermann 			if (ia != NULL)
1141c773494eSAndre Oppermann 				mtu = ia->ia_ifp->if_mtu;
1142ab48768bSAndre Oppermann 			else
11438f134647SGleb Smirnoff 				mtu = ip_next_mtu(ntohs(ip->ip_len), 0);
1144ab48768bSAndre Oppermann 		}
114586425c62SRobert Watson 		IPSTAT_INC(ips_cantfrag);
1146df8bae1dSRodney W. Grimes 		break;
1147df8bae1dSRodney W. Grimes 
1148df8bae1dSRodney W. Grimes 	case ENOBUFS:
11493a06e3e0SRuslan Ermilov 	case EACCES:			/* ipfw denied packet */
11503a06e3e0SRuslan Ermilov 		m_freem(mcopy);
11518c0fec80SRobert Watson 		if (ia != NULL)
11528c0fec80SRobert Watson 			ifa_free(&ia->ia_ifa);
11533a06e3e0SRuslan Ermilov 		return;
1154df8bae1dSRodney W. Grimes 	}
11558c0fec80SRobert Watson 	if (ia != NULL)
11568c0fec80SRobert Watson 		ifa_free(&ia->ia_ifa);
1157c773494eSAndre Oppermann 	icmp_error(mcopy, type, code, dest.s_addr, mtu);
1158df8bae1dSRodney W. Grimes }
1159df8bae1dSRodney W. Grimes 
116082c23ebaSBill Fenner void
1161f2565d68SRobert Watson ip_savecontrol(struct inpcb *inp, struct mbuf **mp, struct ip *ip,
1162f2565d68SRobert Watson     struct mbuf *m)
116382c23ebaSBill Fenner {
11648b615593SMarko Zec 
1165be8a62e8SPoul-Henning Kamp 	if (inp->inp_socket->so_options & (SO_BINTIME | SO_TIMESTAMP)) {
1166be8a62e8SPoul-Henning Kamp 		struct bintime bt;
1167be8a62e8SPoul-Henning Kamp 
1168be8a62e8SPoul-Henning Kamp 		bintime(&bt);
1169be8a62e8SPoul-Henning Kamp 		if (inp->inp_socket->so_options & SO_BINTIME) {
1170be8a62e8SPoul-Henning Kamp 			*mp = sbcreatecontrol((caddr_t)&bt, sizeof(bt),
1171be8a62e8SPoul-Henning Kamp 			    SCM_BINTIME, SOL_SOCKET);
1172be8a62e8SPoul-Henning Kamp 			if (*mp)
1173be8a62e8SPoul-Henning Kamp 				mp = &(*mp)->m_next;
1174be8a62e8SPoul-Henning Kamp 		}
117582c23ebaSBill Fenner 		if (inp->inp_socket->so_options & SO_TIMESTAMP) {
117682c23ebaSBill Fenner 			struct timeval tv;
117782c23ebaSBill Fenner 
1178be8a62e8SPoul-Henning Kamp 			bintime2timeval(&bt, &tv);
117982c23ebaSBill Fenner 			*mp = sbcreatecontrol((caddr_t)&tv, sizeof(tv),
118082c23ebaSBill Fenner 			    SCM_TIMESTAMP, SOL_SOCKET);
118182c23ebaSBill Fenner 			if (*mp)
118282c23ebaSBill Fenner 				mp = &(*mp)->m_next;
11834cc20ab1SSeigo Tanimura 		}
1184be8a62e8SPoul-Henning Kamp 	}
118582c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVDSTADDR) {
118682c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t)&ip->ip_dst,
118782c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
118882c23ebaSBill Fenner 		if (*mp)
118982c23ebaSBill Fenner 			mp = &(*mp)->m_next;
119082c23ebaSBill Fenner 	}
11914957466bSMatthew N. Dodd 	if (inp->inp_flags & INP_RECVTTL) {
11924957466bSMatthew N. Dodd 		*mp = sbcreatecontrol((caddr_t)&ip->ip_ttl,
11934957466bSMatthew N. Dodd 		    sizeof(u_char), IP_RECVTTL, IPPROTO_IP);
11944957466bSMatthew N. Dodd 		if (*mp)
11954957466bSMatthew N. Dodd 			mp = &(*mp)->m_next;
11964957466bSMatthew N. Dodd 	}
119782c23ebaSBill Fenner #ifdef notyet
119882c23ebaSBill Fenner 	/* XXX
119982c23ebaSBill Fenner 	 * Moving these out of udp_input() made them even more broken
120082c23ebaSBill Fenner 	 * than they already were.
120182c23ebaSBill Fenner 	 */
120282c23ebaSBill Fenner 	/* options were tossed already */
120382c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVOPTS) {
120482c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t)opts_deleted_above,
120582c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
120682c23ebaSBill Fenner 		if (*mp)
120782c23ebaSBill Fenner 			mp = &(*mp)->m_next;
120882c23ebaSBill Fenner 	}
120982c23ebaSBill Fenner 	/* ip_srcroute doesn't do what we want here, need to fix */
121082c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVRETOPTS) {
1211e0982661SAndre Oppermann 		*mp = sbcreatecontrol((caddr_t)ip_srcroute(m),
121282c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
121382c23ebaSBill Fenner 		if (*mp)
121482c23ebaSBill Fenner 			mp = &(*mp)->m_next;
121582c23ebaSBill Fenner 	}
121682c23ebaSBill Fenner #endif
121782c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVIF) {
1218d314ad7bSJulian Elischer 		struct ifnet *ifp;
1219d314ad7bSJulian Elischer 		struct sdlbuf {
122082c23ebaSBill Fenner 			struct sockaddr_dl sdl;
1221d314ad7bSJulian Elischer 			u_char	pad[32];
1222d314ad7bSJulian Elischer 		} sdlbuf;
1223d314ad7bSJulian Elischer 		struct sockaddr_dl *sdp;
1224d314ad7bSJulian Elischer 		struct sockaddr_dl *sdl2 = &sdlbuf.sdl;
122582c23ebaSBill Fenner 
122646f2df9cSSergey Kandaurov 		if ((ifp = m->m_pkthdr.rcvif) &&
122746f2df9cSSergey Kandaurov 		    ifp->if_index && ifp->if_index <= V_if_index) {
12284a0d6638SRuslan Ermilov 			sdp = (struct sockaddr_dl *)ifp->if_addr->ifa_addr;
1229d314ad7bSJulian Elischer 			/*
1230d314ad7bSJulian Elischer 			 * Change our mind and don't try copy.
1231d314ad7bSJulian Elischer 			 */
123246f2df9cSSergey Kandaurov 			if (sdp->sdl_family != AF_LINK ||
123346f2df9cSSergey Kandaurov 			    sdp->sdl_len > sizeof(sdlbuf)) {
1234d314ad7bSJulian Elischer 				goto makedummy;
1235d314ad7bSJulian Elischer 			}
1236d314ad7bSJulian Elischer 			bcopy(sdp, sdl2, sdp->sdl_len);
1237d314ad7bSJulian Elischer 		} else {
1238d314ad7bSJulian Elischer makedummy:
123946f2df9cSSergey Kandaurov 			sdl2->sdl_len =
124046f2df9cSSergey Kandaurov 			    offsetof(struct sockaddr_dl, sdl_data[0]);
1241d314ad7bSJulian Elischer 			sdl2->sdl_family = AF_LINK;
1242d314ad7bSJulian Elischer 			sdl2->sdl_index = 0;
1243d314ad7bSJulian Elischer 			sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;
1244d314ad7bSJulian Elischer 		}
1245d314ad7bSJulian Elischer 		*mp = sbcreatecontrol((caddr_t)sdl2, sdl2->sdl_len,
124682c23ebaSBill Fenner 		    IP_RECVIF, IPPROTO_IP);
124782c23ebaSBill Fenner 		if (*mp)
124882c23ebaSBill Fenner 			mp = &(*mp)->m_next;
124982c23ebaSBill Fenner 	}
12503cca425bSMichael Tuexen 	if (inp->inp_flags & INP_RECVTOS) {
12513cca425bSMichael Tuexen 		*mp = sbcreatecontrol((caddr_t)&ip->ip_tos,
12523cca425bSMichael Tuexen 		    sizeof(u_char), IP_RECVTOS, IPPROTO_IP);
12533cca425bSMichael Tuexen 		if (*mp)
12543cca425bSMichael Tuexen 			mp = &(*mp)->m_next;
12553cca425bSMichael Tuexen 	}
12569d3ddf43SAdrian Chadd 
12579d3ddf43SAdrian Chadd 	if (inp->inp_flags2 & INP_RECVFLOWID) {
12589d3ddf43SAdrian Chadd 		uint32_t flowid, flow_type;
12599d3ddf43SAdrian Chadd 
12609d3ddf43SAdrian Chadd 		flowid = m->m_pkthdr.flowid;
12619d3ddf43SAdrian Chadd 		flow_type = M_HASHTYPE_GET(m);
12629d3ddf43SAdrian Chadd 
12639d3ddf43SAdrian Chadd 		/*
12649d3ddf43SAdrian Chadd 		 * XXX should handle the failure of one or the
12659d3ddf43SAdrian Chadd 		 * other - don't populate both?
12669d3ddf43SAdrian Chadd 		 */
12679d3ddf43SAdrian Chadd 		*mp = sbcreatecontrol((caddr_t) &flowid,
12689d3ddf43SAdrian Chadd 		    sizeof(uint32_t), IP_FLOWID, IPPROTO_IP);
12699d3ddf43SAdrian Chadd 		if (*mp)
12709d3ddf43SAdrian Chadd 			mp = &(*mp)->m_next;
12719d3ddf43SAdrian Chadd 		*mp = sbcreatecontrol((caddr_t) &flow_type,
12729d3ddf43SAdrian Chadd 		    sizeof(uint32_t), IP_FLOWTYPE, IPPROTO_IP);
12739d3ddf43SAdrian Chadd 		if (*mp)
12749d3ddf43SAdrian Chadd 			mp = &(*mp)->m_next;
12759d3ddf43SAdrian Chadd 	}
12769d3ddf43SAdrian Chadd 
12779d3ddf43SAdrian Chadd #ifdef	RSS
12789d3ddf43SAdrian Chadd 	if (inp->inp_flags2 & INP_RECVRSSBUCKETID) {
12799d3ddf43SAdrian Chadd 		uint32_t flowid, flow_type;
12809d3ddf43SAdrian Chadd 		uint32_t rss_bucketid;
12819d3ddf43SAdrian Chadd 
12829d3ddf43SAdrian Chadd 		flowid = m->m_pkthdr.flowid;
12839d3ddf43SAdrian Chadd 		flow_type = M_HASHTYPE_GET(m);
12849d3ddf43SAdrian Chadd 
12859d3ddf43SAdrian Chadd 		if (rss_hash2bucket(flowid, flow_type, &rss_bucketid) == 0) {
12869d3ddf43SAdrian Chadd 			*mp = sbcreatecontrol((caddr_t) &rss_bucketid,
12879d3ddf43SAdrian Chadd 			   sizeof(uint32_t), IP_RSSBUCKETID, IPPROTO_IP);
12889d3ddf43SAdrian Chadd 			if (*mp)
12899d3ddf43SAdrian Chadd 				mp = &(*mp)->m_next;
12909d3ddf43SAdrian Chadd 		}
12919d3ddf43SAdrian Chadd 	}
12929d3ddf43SAdrian Chadd #endif
129382c23ebaSBill Fenner }
129482c23ebaSBill Fenner 
12954d2e3692SLuigi Rizzo /*
129630916a2dSRobert Watson  * XXXRW: Multicast routing code in ip_mroute.c is generally MPSAFE, but the
129730916a2dSRobert Watson  * ip_rsvp and ip_rsvp_on variables need to be interlocked with rsvp_on
129830916a2dSRobert Watson  * locking.  This code remains in ip_input.c as ip_mroute.c is optionally
129930916a2dSRobert Watson  * compiled.
13004d2e3692SLuigi Rizzo  */
13013e288e62SDimitry Andric static VNET_DEFINE(int, ip_rsvp_on);
130282cea7e6SBjoern A. Zeeb VNET_DEFINE(struct socket *, ip_rsvpd);
130382cea7e6SBjoern A. Zeeb 
130482cea7e6SBjoern A. Zeeb #define	V_ip_rsvp_on		VNET(ip_rsvp_on)
130582cea7e6SBjoern A. Zeeb 
1306df8bae1dSRodney W. Grimes int
1307f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so)
1308f0068c4aSGarrett Wollman {
13098b615593SMarko Zec 
1310f0068c4aSGarrett Wollman 	if (so->so_type != SOCK_RAW ||
1311f0068c4aSGarrett Wollman 	    so->so_proto->pr_protocol != IPPROTO_RSVP)
1312f0068c4aSGarrett Wollman 		return EOPNOTSUPP;
1313f0068c4aSGarrett Wollman 
1314603724d3SBjoern A. Zeeb 	if (V_ip_rsvpd != NULL)
1315f0068c4aSGarrett Wollman 		return EADDRINUSE;
1316f0068c4aSGarrett Wollman 
1317603724d3SBjoern A. Zeeb 	V_ip_rsvpd = so;
13181c5de19aSGarrett Wollman 	/*
13191c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-increment
13201c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
13211c5de19aSGarrett Wollman 	 */
1322603724d3SBjoern A. Zeeb 	if (!V_ip_rsvp_on) {
1323603724d3SBjoern A. Zeeb 		V_ip_rsvp_on = 1;
1324603724d3SBjoern A. Zeeb 		V_rsvp_on++;
13251c5de19aSGarrett Wollman 	}
1326f0068c4aSGarrett Wollman 
1327f0068c4aSGarrett Wollman 	return 0;
1328f0068c4aSGarrett Wollman }
1329f0068c4aSGarrett Wollman 
1330f0068c4aSGarrett Wollman int
1331f0068c4aSGarrett Wollman ip_rsvp_done(void)
1332f0068c4aSGarrett Wollman {
13338b615593SMarko Zec 
1334603724d3SBjoern A. Zeeb 	V_ip_rsvpd = NULL;
13351c5de19aSGarrett Wollman 	/*
13361c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-decrement
13371c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
13381c5de19aSGarrett Wollman 	 */
1339603724d3SBjoern A. Zeeb 	if (V_ip_rsvp_on) {
1340603724d3SBjoern A. Zeeb 		V_ip_rsvp_on = 0;
1341603724d3SBjoern A. Zeeb 		V_rsvp_on--;
13421c5de19aSGarrett Wollman 	}
1343f0068c4aSGarrett Wollman 	return 0;
1344f0068c4aSGarrett Wollman }
1345bbb4330bSLuigi Rizzo 
13468f5a8818SKevin Lo int
13478f5a8818SKevin Lo rsvp_input(struct mbuf **mp, int *offp, int proto)
1348bbb4330bSLuigi Rizzo {
13498f5a8818SKevin Lo 	struct mbuf *m;
13508f5a8818SKevin Lo 
13518f5a8818SKevin Lo 	m = *mp;
13528f5a8818SKevin Lo 	*mp = NULL;
13538b615593SMarko Zec 
1354bbb4330bSLuigi Rizzo 	if (rsvp_input_p) { /* call the real one if loaded */
13558f5a8818SKevin Lo 		*mp = m;
13568f5a8818SKevin Lo 		rsvp_input_p(mp, offp, proto);
13578f5a8818SKevin Lo 		return (IPPROTO_DONE);
1358bbb4330bSLuigi Rizzo 	}
1359bbb4330bSLuigi Rizzo 
1360bbb4330bSLuigi Rizzo 	/* Can still get packets with rsvp_on = 0 if there is a local member
1361bbb4330bSLuigi Rizzo 	 * of the group to which the RSVP packet is addressed.  But in this
1362bbb4330bSLuigi Rizzo 	 * case we want to throw the packet away.
1363bbb4330bSLuigi Rizzo 	 */
1364bbb4330bSLuigi Rizzo 
1365603724d3SBjoern A. Zeeb 	if (!V_rsvp_on) {
1366bbb4330bSLuigi Rizzo 		m_freem(m);
13678f5a8818SKevin Lo 		return (IPPROTO_DONE);
1368bbb4330bSLuigi Rizzo 	}
1369bbb4330bSLuigi Rizzo 
1370603724d3SBjoern A. Zeeb 	if (V_ip_rsvpd != NULL) {
13718f5a8818SKevin Lo 		*mp = m;
13728f5a8818SKevin Lo 		rip_input(mp, offp, proto);
13738f5a8818SKevin Lo 		return (IPPROTO_DONE);
1374bbb4330bSLuigi Rizzo 	}
1375bbb4330bSLuigi Rizzo 	/* Drop the packet */
1376bbb4330bSLuigi Rizzo 	m_freem(m);
13778f5a8818SKevin Lo 	return (IPPROTO_DONE);
1378bbb4330bSLuigi Rizzo }
1379