xref: /freebsd/sys/netinet/ip_input.c (revision c773494edd9d7aea4c5e7246345c570ded196c5c)
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
30c3aac50fSPeter Wemm  * $FreeBSD$
31df8bae1dSRodney W. Grimes  */
32df8bae1dSRodney W. Grimes 
330ac40133SBrian Somers #include "opt_bootp.h"
3474a9466cSGary Palmer #include "opt_ipfw.h"
3527108a15SDag-Erling Smørgrav #include "opt_ipstealth.h"
366a800098SYoshinobu Inoue #include "opt_ipsec.h"
3736b0360bSRobert Watson #include "opt_mac.h"
38a9771948SGleb Smirnoff #include "opt_carp.h"
3974a9466cSGary Palmer 
40df8bae1dSRodney W. Grimes #include <sys/param.h>
41df8bae1dSRodney W. Grimes #include <sys/systm.h>
425f311da2SMike Silbersack #include <sys/callout.h>
4336b0360bSRobert Watson #include <sys/mac.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>
511025071fSGarrett Wollman #include <sys/syslog.h>
52b5e8ce9fSBruce Evans #include <sys/sysctl.h>
53df8bae1dSRodney W. Grimes 
54c85540ddSAndrey A. Chernov #include <net/pfil.h>
55df8bae1dSRodney W. Grimes #include <net/if.h>
569494d596SBrooks Davis #include <net/if_types.h>
57d314ad7bSJulian Elischer #include <net/if_var.h>
5882c23ebaSBill Fenner #include <net/if_dl.h>
59df8bae1dSRodney W. Grimes #include <net/route.h>
60748e0b0aSGarrett Wollman #include <net/netisr.h>
61df8bae1dSRodney W. Grimes 
62df8bae1dSRodney W. Grimes #include <netinet/in.h>
63df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
64b5e8ce9fSBruce Evans #include <netinet/in_var.h>
65df8bae1dSRodney W. Grimes #include <netinet/ip.h>
66df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h>
67df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
68df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h>
6958938916SGarrett Wollman #include <machine/in_cksum.h>
70a9771948SGleb Smirnoff #ifdef DEV_CARP
71a9771948SGleb Smirnoff #include <netinet/ip_carp.h>
72a9771948SGleb Smirnoff #endif
73df8bae1dSRodney W. Grimes 
74f0068c4aSGarrett Wollman #include <sys/socketvar.h>
756ddbf1e2SGary Palmer 
769b932e9eSAndre Oppermann /* XXX: Temporary until ipfw_ether and ipfw_bridge are converted. */
776ddbf1e2SGary Palmer #include <netinet/ip_fw.h>
78db69a05dSPaul Saab #include <netinet/ip_dummynet.h>
79db69a05dSPaul Saab 
806a800098SYoshinobu Inoue #ifdef IPSEC
816a800098SYoshinobu Inoue #include <netinet6/ipsec.h>
826a800098SYoshinobu Inoue #include <netkey/key.h>
836a800098SYoshinobu Inoue #endif
846a800098SYoshinobu Inoue 
85b9234fafSSam Leffler #ifdef FAST_IPSEC
86b9234fafSSam Leffler #include <netipsec/ipsec.h>
87b9234fafSSam Leffler #include <netipsec/key.h>
88b9234fafSSam Leffler #endif
89b9234fafSSam Leffler 
901c5de19aSGarrett Wollman int rsvp_on = 0;
91f0068c4aSGarrett Wollman 
921f91d8c5SDavid Greenman int	ipforwarding = 0;
930312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW,
943d177f46SBill Fumerola     &ipforwarding, 0, "Enable IP forwarding between interfaces");
950312fbe9SPoul-Henning Kamp 
96d4fb926cSGarrett Wollman static int	ipsendredirects = 1; /* XXX */
970312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW,
983d177f46SBill Fumerola     &ipsendredirects, 0, "Enable sending IP redirects");
990312fbe9SPoul-Henning Kamp 
100df8bae1dSRodney W. Grimes int	ip_defttl = IPDEFTTL;
1010312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW,
1023d177f46SBill Fumerola     &ip_defttl, 0, "Maximum TTL on IP packets");
1030312fbe9SPoul-Henning Kamp 
1040312fbe9SPoul-Henning Kamp static int	ip_dosourceroute = 0;
1050312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
1063d177f46SBill Fumerola     &ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
1074fce5804SGuido van Rooij 
1084fce5804SGuido van Rooij static int	ip_acceptsourceroute = 0;
1094fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute,
1103d177f46SBill Fumerola     CTLFLAG_RW, &ip_acceptsourceroute, 0,
1113d177f46SBill Fumerola     "Enable accepting source routed IP packets");
1126a800098SYoshinobu Inoue 
1132bde81acSAndre Oppermann int		ip_doopts = 1;	/* 0 = ignore, 1 = process, 2 = reject */
1142bde81acSAndre Oppermann SYSCTL_INT(_net_inet_ip, OID_AUTO, process_options, CTLFLAG_RW,
1152bde81acSAndre Oppermann     &ip_doopts, 0, "Enable IP options processing ([LS]SRR, RR, TS)");
1162bde81acSAndre Oppermann 
1176a800098SYoshinobu Inoue static int	ip_keepfaith = 0;
1186a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
1196a800098SYoshinobu Inoue 	&ip_keepfaith,	0,
1206a800098SYoshinobu Inoue 	"Enable packet capture for FAITH IPv4->IPv6 translater daemon");
1216a800098SYoshinobu Inoue 
122402062e8SMike Silbersack static int    nipq = 0;         /* total # of reass queues */
123402062e8SMike Silbersack static int    maxnipq;
124690a6055SJesper Skriver SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW,
125402062e8SMike Silbersack 	&maxnipq, 0,
126690a6055SJesper Skriver 	"Maximum number of IPv4 fragment reassembly queue entries");
127690a6055SJesper Skriver 
128375386e2SMike Silbersack static int    maxfragsperpacket;
129375386e2SMike Silbersack SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragsperpacket, CTLFLAG_RW,
130375386e2SMike Silbersack 	&maxfragsperpacket, 0,
131375386e2SMike Silbersack 	"Maximum number of IPv4 fragments allowed per packet");
132375386e2SMike Silbersack 
133df285b3dSMike Silbersack static int	ip_sendsourcequench = 0;
134df285b3dSMike Silbersack SYSCTL_INT(_net_inet_ip, OID_AUTO, sendsourcequench, CTLFLAG_RW,
135df285b3dSMike Silbersack 	&ip_sendsourcequench, 0,
136df285b3dSMike Silbersack 	"Enable the transmission of source quench packets");
137df285b3dSMike Silbersack 
1381f44b0a1SDavid Malone int	ip_do_randomid = 0;
1391f44b0a1SDavid Malone SYSCTL_INT(_net_inet_ip, OID_AUTO, random_id, CTLFLAG_RW,
1401f44b0a1SDavid Malone 	&ip_do_randomid, 0,
1411f44b0a1SDavid Malone 	"Assign random ip_id values");
1421f44b0a1SDavid Malone 
143823db0e9SDon Lewis /*
144823db0e9SDon Lewis  * XXX - Setting ip_checkinterface mostly implements the receive side of
145823db0e9SDon Lewis  * the Strong ES model described in RFC 1122, but since the routing table
146a8f12100SDon Lewis  * and transmit implementation do not implement the Strong ES model,
147823db0e9SDon Lewis  * setting this to 1 results in an odd hybrid.
1483f67c834SDon Lewis  *
149a8f12100SDon Lewis  * XXX - ip_checkinterface currently must be disabled if you use ipnat
150a8f12100SDon Lewis  * to translate the destination address to another local interface.
1513f67c834SDon Lewis  *
1523f67c834SDon Lewis  * XXX - ip_checkinterface must be disabled if you add IP aliases
1533f67c834SDon Lewis  * to the loopback interface instead of the interface where the
1543f67c834SDon Lewis  * packets for those addresses are received.
155823db0e9SDon Lewis  */
1564bc37f98SMaxim Konovalov static int	ip_checkinterface = 0;
157b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW,
158b3e95d4eSJonathan Lemon     &ip_checkinterface, 0, "Verify packet arrives on correct interface");
159b3e95d4eSJonathan Lemon 
160df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1610312fbe9SPoul-Henning Kamp static int	ipprintfs = 0;
162df8bae1dSRodney W. Grimes #endif
163c21fd232SAndre Oppermann 
164c21fd232SAndre Oppermann struct pfil_head inet_pfil_hook;	/* Packet filter hooks */
165df8bae1dSRodney W. Grimes 
1661cafed39SJonathan Lemon static struct	ifqueue ipintrq;
167ca925d9cSJonathan Lemon static int	ipqmaxlen = IFQ_MAXLEN;
168ca925d9cSJonathan Lemon 
169df8bae1dSRodney W. Grimes extern	struct domain inetdomain;
170f0ffb944SJulian Elischer extern	struct protosw inetsw[];
171df8bae1dSRodney W. Grimes u_char	ip_protox[IPPROTO_MAX];
17259562606SGarrett Wollman struct	in_ifaddrhead in_ifaddrhead; 		/* first inet address */
173ca925d9cSJonathan Lemon struct	in_ifaddrhashhead *in_ifaddrhashtbl;	/* inet addr hash table  */
174ca925d9cSJonathan Lemon u_long 	in_ifaddrhmask;				/* mask for hash table */
175ca925d9cSJonathan Lemon 
176afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW,
1773d177f46SBill Fumerola     &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue");
1780312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
1793d177f46SBill Fumerola     &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue");
180df8bae1dSRodney W. Grimes 
181f23b4c91SGarrett Wollman struct ipstat ipstat;
182c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW,
1833d177f46SBill Fumerola     &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)");
184194a213eSAndrey A. Chernov 
185194a213eSAndrey A. Chernov /* Packet reassembly stuff */
186194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2      6
187194a213eSAndrey A. Chernov #define IPREASS_NHASH           (1 << IPREASS_NHASH_LOG2)
188194a213eSAndrey A. Chernov #define IPREASS_HMASK           (IPREASS_NHASH - 1)
189194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \
190831a80b0SMatthew Dillon 	(((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
191194a213eSAndrey A. Chernov 
192462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH];
1932fad1e93SSam Leffler struct mtx ipqlock;
1945f311da2SMike Silbersack struct callout ipport_tick_callout;
1952fad1e93SSam Leffler 
1962fad1e93SSam Leffler #define	IPQ_LOCK()	mtx_lock(&ipqlock)
1972fad1e93SSam Leffler #define	IPQ_UNLOCK()	mtx_unlock(&ipqlock)
198888c2a3cSSam Leffler #define	IPQ_LOCK_INIT()	mtx_init(&ipqlock, "ipqlock", NULL, MTX_DEF)
199888c2a3cSSam Leffler #define	IPQ_LOCK_ASSERT()	mtx_assert(&ipqlock, MA_OWNED)
200f23b4c91SGarrett Wollman 
2010312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU
2020312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
2033d177f46SBill Fumerola     &ip_mtu, 0, "Default MTU");
2040312fbe9SPoul-Henning Kamp #endif
2050312fbe9SPoul-Henning Kamp 
2061b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
207c76ff708SAndre Oppermann int	ipstealth = 0;
2081b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW,
2091b968362SDag-Erling Smørgrav     &ipstealth, 0, "");
2101b968362SDag-Erling Smørgrav #endif
2111b968362SDag-Erling Smørgrav 
2129b932e9eSAndre Oppermann /*
2139b932e9eSAndre Oppermann  * ipfw_ether and ipfw_bridge hooks.
2149b932e9eSAndre Oppermann  * XXX: Temporary until those are converted to pfil_hooks as well.
2159b932e9eSAndre Oppermann  */
2169b932e9eSAndre Oppermann ip_fw_chk_t *ip_fw_chk_ptr = NULL;
2179b932e9eSAndre Oppermann ip_dn_io_t *ip_dn_io_ptr = NULL;
218e4c97effSAndre Oppermann int fw_enable = 1;
21997850a5dSLuigi Rizzo int fw_one_pass = 1;
220e7319babSPoul-Henning Kamp 
221929b31ddSSam Leffler /*
222e0982661SAndre Oppermann  * XXX this is ugly.  IP options source routing magic.
223df8bae1dSRodney W. Grimes  */
224e0982661SAndre Oppermann struct ipoptrt {
225df8bae1dSRodney W. Grimes 	struct	in_addr dst;			/* final destination */
226df8bae1dSRodney W. Grimes 	char	nop;				/* one NOP to align */
227df8bae1dSRodney W. Grimes 	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
228df8bae1dSRodney W. Grimes 	struct	in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
229e0982661SAndre Oppermann };
230df8bae1dSRodney W. Grimes 
231e0982661SAndre Oppermann struct ipopt_tag {
232e0982661SAndre Oppermann 	struct	m_tag tag;
233e0982661SAndre Oppermann 	int	ip_nhops;
234e0982661SAndre Oppermann 	struct	ipoptrt ip_srcrt;
235e0982661SAndre Oppermann };
236e0982661SAndre Oppermann 
237e0982661SAndre Oppermann static void	save_rte(struct mbuf *, u_char *, struct in_addr);
2389b932e9eSAndre Oppermann static int	ip_dooptions(struct mbuf *m, int);
2399b932e9eSAndre Oppermann static void	ip_forward(struct mbuf *m, int srcrt);
2404d77a549SAlfred Perlstein static void	ip_freef(struct ipqhead *, struct ipq *);
2418948e4baSArchie Cobbs 
242df8bae1dSRodney W. Grimes /*
243df8bae1dSRodney W. Grimes  * IP initialization: fill in IP protocol switch table.
244df8bae1dSRodney W. Grimes  * All protocols not implemented in kernel go to raw IP protocol handler.
245df8bae1dSRodney W. Grimes  */
246df8bae1dSRodney W. Grimes void
247df8bae1dSRodney W. Grimes ip_init()
248df8bae1dSRodney W. Grimes {
249f0ffb944SJulian Elischer 	register struct protosw *pr;
250df8bae1dSRodney W. Grimes 	register int i;
251df8bae1dSRodney W. Grimes 
25259562606SGarrett Wollman 	TAILQ_INIT(&in_ifaddrhead);
253ca925d9cSJonathan Lemon 	in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask);
254f0ffb944SJulian Elischer 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
25502410549SRobert Watson 	if (pr == NULL)
256db09bef3SAndre Oppermann 		panic("ip_init: PF_INET not found");
257db09bef3SAndre Oppermann 
258db09bef3SAndre Oppermann 	/* Initialize the entire ip_protox[] array to IPPROTO_RAW. */
259df8bae1dSRodney W. Grimes 	for (i = 0; i < IPPROTO_MAX; i++)
260df8bae1dSRodney W. Grimes 		ip_protox[i] = pr - inetsw;
261db09bef3SAndre Oppermann 	/*
262db09bef3SAndre Oppermann 	 * Cycle through IP protocols and put them into the appropriate place
263db09bef3SAndre Oppermann 	 * in ip_protox[].
264db09bef3SAndre Oppermann 	 */
265f0ffb944SJulian Elischer 	for (pr = inetdomain.dom_protosw;
266f0ffb944SJulian Elischer 	    pr < inetdomain.dom_protoswNPROTOSW; pr++)
267df8bae1dSRodney W. Grimes 		if (pr->pr_domain->dom_family == PF_INET &&
268db09bef3SAndre Oppermann 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) {
269db09bef3SAndre Oppermann 			/* Be careful to only index valid IP protocols. */
270db77984cSSam Leffler 			if (pr->pr_protocol < IPPROTO_MAX)
271df8bae1dSRodney W. Grimes 				ip_protox[pr->pr_protocol] = pr - inetsw;
272db09bef3SAndre Oppermann 		}
273194a213eSAndrey A. Chernov 
274c21fd232SAndre Oppermann 	/* Initialize packet filter hooks. */
275134ea224SSam Leffler 	inet_pfil_hook.ph_type = PFIL_TYPE_AF;
276134ea224SSam Leffler 	inet_pfil_hook.ph_af = AF_INET;
277134ea224SSam Leffler 	if ((i = pfil_head_register(&inet_pfil_hook)) != 0)
278134ea224SSam Leffler 		printf("%s: WARNING: unable to register pfil hook, "
279134ea224SSam Leffler 			"error %d\n", __func__, i);
280134ea224SSam Leffler 
281db09bef3SAndre Oppermann 	/* Initialize IP reassembly queue. */
2822fad1e93SSam Leffler 	IPQ_LOCK_INIT();
283194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++)
284462b86feSPoul-Henning Kamp 	    TAILQ_INIT(&ipq[i]);
285375386e2SMike Silbersack 	maxnipq = nmbclusters / 32;
286375386e2SMike Silbersack 	maxfragsperpacket = 16;
287194a213eSAndrey A. Chernov 
2885f311da2SMike Silbersack 	/* Start ipport_tick. */
2895f311da2SMike Silbersack 	callout_init(&ipport_tick_callout, CALLOUT_MPSAFE);
2905f311da2SMike Silbersack 	ipport_tick(NULL);
2915f311da2SMike Silbersack 	EVENTHANDLER_REGISTER(shutdown_pre_sync, ip_fini, NULL,
2925f311da2SMike Silbersack 		SHUTDOWN_PRI_DEFAULT);
2935f311da2SMike Silbersack 
294db09bef3SAndre Oppermann 	/* Initialize various other remaining things. */
295227ee8a1SPoul-Henning Kamp 	ip_id = time_second & 0xffff;
296df8bae1dSRodney W. Grimes 	ipintrq.ifq_maxlen = ipqmaxlen;
2976008862bSJohn Baldwin 	mtx_init(&ipintrq.ifq_mtx, "ip_inq", NULL, MTX_DEF);
2987902224cSSam Leffler 	netisr_register(NETISR_IP, ip_input, &ipintrq, NETISR_MPSAFE);
299df8bae1dSRodney W. Grimes }
300df8bae1dSRodney W. Grimes 
3015f311da2SMike Silbersack void ip_fini(xtp)
3025f311da2SMike Silbersack 	void *xtp;
3035f311da2SMike Silbersack {
3045f311da2SMike Silbersack 	callout_stop(&ipport_tick_callout);
3055f311da2SMike Silbersack }
3065f311da2SMike Silbersack 
3074d2e3692SLuigi Rizzo /*
308df8bae1dSRodney W. Grimes  * Ip input routine.  Checksum and byte swap header.  If fragmented
309df8bae1dSRodney W. Grimes  * try to reassemble.  Process options.  Pass to next level.
310df8bae1dSRodney W. Grimes  */
311c67b1d17SGarrett Wollman void
312c67b1d17SGarrett Wollman ip_input(struct mbuf *m)
313df8bae1dSRodney W. Grimes {
3149188b4a1SAndre Oppermann 	struct ip *ip = NULL;
3155da9f8faSJosef Karthauser 	struct in_ifaddr *ia = NULL;
316ca925d9cSJonathan Lemon 	struct ifaddr *ifa;
3179b932e9eSAndre Oppermann 	int    checkif, hlen = 0;
31847c861ecSBrian Somers 	u_short sum;
31902c1c707SAndre Oppermann 	int dchg = 0;				/* dest changed after fw */
320f51f805fSSam Leffler 	struct in_addr odst;			/* original dst address */
321b9234fafSSam Leffler #ifdef FAST_IPSEC
32236e8826fSMax Laier 	struct m_tag *mtag;
323b9234fafSSam Leffler 	struct tdb_ident *tdbi;
324b9234fafSSam Leffler 	struct secpolicy *sp;
325b9234fafSSam Leffler 	int s, error;
326b9234fafSSam Leffler #endif /* FAST_IPSEC */
327b715f178SLuigi Rizzo 
328fe584538SDag-Erling Smørgrav   	M_ASSERTPKTHDR(m);
329db40007dSAndrew R. Reiter 
330ac9d7e26SMax Laier 	if (m->m_flags & M_FASTFWD_OURS) {
3319b932e9eSAndre Oppermann 		/*
33276ff6dcfSAndre Oppermann 		 * Firewall or NAT changed destination to local.
33376ff6dcfSAndre Oppermann 		 * We expect ip_len and ip_off to be in host byte order.
3349b932e9eSAndre Oppermann 		 */
33576ff6dcfSAndre Oppermann 		m->m_flags &= ~M_FASTFWD_OURS;
33676ff6dcfSAndre Oppermann 		/* Set up some basics that will be used later. */
3372b25acc1SLuigi Rizzo 		ip = mtod(m, struct ip *);
33853be11f6SPoul-Henning Kamp 		hlen = ip->ip_hl << 2;
3399b932e9eSAndre Oppermann   		goto ours;
3402b25acc1SLuigi Rizzo   	}
3412b25acc1SLuigi Rizzo 
342df8bae1dSRodney W. Grimes 	ipstat.ips_total++;
34358938916SGarrett Wollman 
34458938916SGarrett Wollman 	if (m->m_pkthdr.len < sizeof(struct ip))
34558938916SGarrett Wollman 		goto tooshort;
34658938916SGarrett Wollman 
347df8bae1dSRodney W. Grimes 	if (m->m_len < sizeof (struct ip) &&
3480b17fba7SAndre Oppermann 	    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
349df8bae1dSRodney W. Grimes 		ipstat.ips_toosmall++;
350c67b1d17SGarrett Wollman 		return;
351df8bae1dSRodney W. Grimes 	}
352df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
35358938916SGarrett Wollman 
35453be11f6SPoul-Henning Kamp 	if (ip->ip_v != IPVERSION) {
355df8bae1dSRodney W. Grimes 		ipstat.ips_badvers++;
356df8bae1dSRodney W. Grimes 		goto bad;
357df8bae1dSRodney W. Grimes 	}
35858938916SGarrett Wollman 
35953be11f6SPoul-Henning Kamp 	hlen = ip->ip_hl << 2;
360df8bae1dSRodney W. Grimes 	if (hlen < sizeof(struct ip)) {	/* minimum header length */
361df8bae1dSRodney W. Grimes 		ipstat.ips_badhlen++;
362df8bae1dSRodney W. Grimes 		goto bad;
363df8bae1dSRodney W. Grimes 	}
364df8bae1dSRodney W. Grimes 	if (hlen > m->m_len) {
3650b17fba7SAndre Oppermann 		if ((m = m_pullup(m, hlen)) == NULL) {
366df8bae1dSRodney W. Grimes 			ipstat.ips_badhlen++;
367c67b1d17SGarrett Wollman 			return;
368df8bae1dSRodney W. Grimes 		}
369df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
370df8bae1dSRodney W. Grimes 	}
37133841545SHajimu UMEMOTO 
37233841545SHajimu UMEMOTO 	/* 127/8 must not appear on wire - RFC1122 */
37333841545SHajimu UMEMOTO 	if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
37433841545SHajimu UMEMOTO 	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
37533841545SHajimu UMEMOTO 		if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
37633841545SHajimu UMEMOTO 			ipstat.ips_badaddr++;
37733841545SHajimu UMEMOTO 			goto bad;
37833841545SHajimu UMEMOTO 		}
37933841545SHajimu UMEMOTO 	}
38033841545SHajimu UMEMOTO 
381db4f9cc7SJonathan Lemon 	if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
382db4f9cc7SJonathan Lemon 		sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
383db4f9cc7SJonathan Lemon 	} else {
38458938916SGarrett Wollman 		if (hlen == sizeof(struct ip)) {
38547c861ecSBrian Somers 			sum = in_cksum_hdr(ip);
38658938916SGarrett Wollman 		} else {
38747c861ecSBrian Somers 			sum = in_cksum(m, hlen);
38858938916SGarrett Wollman 		}
389db4f9cc7SJonathan Lemon 	}
39047c861ecSBrian Somers 	if (sum) {
391df8bae1dSRodney W. Grimes 		ipstat.ips_badsum++;
392df8bae1dSRodney W. Grimes 		goto bad;
393df8bae1dSRodney W. Grimes 	}
394df8bae1dSRodney W. Grimes 
39502b199f1SMax Laier #ifdef ALTQ
39602b199f1SMax Laier 	if (altq_input != NULL && (*altq_input)(m, AF_INET) == 0)
39702b199f1SMax Laier 		/* packet is dropped by traffic conditioner */
39802b199f1SMax Laier 		return;
39902b199f1SMax Laier #endif
40002b199f1SMax Laier 
401df8bae1dSRodney W. Grimes 	/*
402df8bae1dSRodney W. Grimes 	 * Convert fields to host representation.
403df8bae1dSRodney W. Grimes 	 */
404fd8e4ebcSMike Barcroft 	ip->ip_len = ntohs(ip->ip_len);
405df8bae1dSRodney W. Grimes 	if (ip->ip_len < hlen) {
406df8bae1dSRodney W. Grimes 		ipstat.ips_badlen++;
407df8bae1dSRodney W. Grimes 		goto bad;
408df8bae1dSRodney W. Grimes 	}
409fd8e4ebcSMike Barcroft 	ip->ip_off = ntohs(ip->ip_off);
410df8bae1dSRodney W. Grimes 
411df8bae1dSRodney W. Grimes 	/*
412df8bae1dSRodney W. Grimes 	 * Check that the amount of data in the buffers
413df8bae1dSRodney W. Grimes 	 * is as at least much as the IP header would have us expect.
414df8bae1dSRodney W. Grimes 	 * Trim mbufs if longer than we expect.
415df8bae1dSRodney W. Grimes 	 * Drop packet if shorter than we expect.
416df8bae1dSRodney W. Grimes 	 */
417df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len < ip->ip_len) {
41858938916SGarrett Wollman tooshort:
419df8bae1dSRodney W. Grimes 		ipstat.ips_tooshort++;
420df8bae1dSRodney W. Grimes 		goto bad;
421df8bae1dSRodney W. Grimes 	}
422df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len > ip->ip_len) {
423df8bae1dSRodney W. Grimes 		if (m->m_len == m->m_pkthdr.len) {
424df8bae1dSRodney W. Grimes 			m->m_len = ip->ip_len;
425df8bae1dSRodney W. Grimes 			m->m_pkthdr.len = ip->ip_len;
426df8bae1dSRodney W. Grimes 		} else
427df8bae1dSRodney W. Grimes 			m_adj(m, ip->ip_len - m->m_pkthdr.len);
428df8bae1dSRodney W. Grimes 	}
42914dd6717SSam Leffler #if defined(IPSEC) && !defined(IPSEC_FILTERGIF)
43014dd6717SSam Leffler 	/*
43114dd6717SSam Leffler 	 * Bypass packet filtering for packets from a tunnel (gif).
43214dd6717SSam Leffler 	 */
4330f9ade71SHajimu UMEMOTO 	if (ipsec_getnhist(m))
434c21fd232SAndre Oppermann 		goto passin;
43514dd6717SSam Leffler #endif
4361f76a5e2SSam Leffler #if defined(FAST_IPSEC) && !defined(IPSEC_FILTERGIF)
4371f76a5e2SSam Leffler 	/*
4381f76a5e2SSam Leffler 	 * Bypass packet filtering for packets from a tunnel (gif).
4391f76a5e2SSam Leffler 	 */
4401f76a5e2SSam Leffler 	if (m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL)
441c21fd232SAndre Oppermann 		goto passin;
4421f76a5e2SSam Leffler #endif
4433f67c834SDon Lewis 
444c4ac87eaSDarren Reed 	/*
445134ea224SSam Leffler 	 * Run through list of hooks for input packets.
446f51f805fSSam Leffler 	 *
447f51f805fSSam Leffler 	 * NB: Beware of the destination address changing (e.g.
448f51f805fSSam Leffler 	 *     by NAT rewriting).  When this happens, tell
449f51f805fSSam Leffler 	 *     ip_forward to do the right thing.
450c4ac87eaSDarren Reed 	 */
451c21fd232SAndre Oppermann 
452c21fd232SAndre Oppermann 	/* Jump over all PFIL processing if hooks are not active. */
453c21fd232SAndre Oppermann 	if (inet_pfil_hook.ph_busy_count == -1)
454c21fd232SAndre Oppermann 		goto passin;
455c21fd232SAndre Oppermann 
456f51f805fSSam Leffler 	odst = ip->ip_dst;
457134ea224SSam Leffler 	if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif,
458d6a8d588SMax Laier 	    PFIL_IN, NULL) != 0)
459beec8214SDarren Reed 		return;
460134ea224SSam Leffler 	if (m == NULL)			/* consumed by filter */
461c4ac87eaSDarren Reed 		return;
4629b932e9eSAndre Oppermann 
463c4ac87eaSDarren Reed 	ip = mtod(m, struct ip *);
46402c1c707SAndre Oppermann 	dchg = (odst.s_addr != ip->ip_dst.s_addr);
4659b932e9eSAndre Oppermann 
4669b932e9eSAndre Oppermann #ifdef IPFIREWALL_FORWARD
4679b932e9eSAndre Oppermann 	if (m->m_flags & M_FASTFWD_OURS) {
4689b932e9eSAndre Oppermann 		m->m_flags &= ~M_FASTFWD_OURS;
4699b932e9eSAndre Oppermann 		goto ours;
4709b932e9eSAndre Oppermann 	}
471099dd043SAndre Oppermann #ifndef IPFIREWALL_FORWARD_EXTENDED
4729b932e9eSAndre Oppermann 	dchg = (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL);
473099dd043SAndre Oppermann #else
474099dd043SAndre Oppermann 	if ((dchg = (m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL)) != 0) {
475099dd043SAndre Oppermann 		/*
476099dd043SAndre Oppermann 		 * Directly ship on the packet.  This allows to forward packets
477099dd043SAndre Oppermann 		 * that were destined for us to some other directly connected
478099dd043SAndre Oppermann 		 * host.
479099dd043SAndre Oppermann 		 */
480099dd043SAndre Oppermann 		ip_forward(m, dchg);
481099dd043SAndre Oppermann 		return;
482099dd043SAndre Oppermann 	}
483099dd043SAndre Oppermann #endif /* IPFIREWALL_FORWARD_EXTENDED */
4849b932e9eSAndre Oppermann #endif /* IPFIREWALL_FORWARD */
4859b932e9eSAndre Oppermann 
486c21fd232SAndre Oppermann passin:
487df8bae1dSRodney W. Grimes 	/*
488df8bae1dSRodney W. Grimes 	 * Process options and, if not destined for us,
489df8bae1dSRodney W. Grimes 	 * ship it on.  ip_dooptions returns 1 when an
490df8bae1dSRodney W. Grimes 	 * error was detected (causing an icmp message
491df8bae1dSRodney W. Grimes 	 * to be sent and the original packet to be freed).
492df8bae1dSRodney W. Grimes 	 */
4939b932e9eSAndre Oppermann 	if (hlen > sizeof (struct ip) && ip_dooptions(m, 0))
494c67b1d17SGarrett Wollman 		return;
495df8bae1dSRodney W. Grimes 
496f0068c4aSGarrett Wollman         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
497f0068c4aSGarrett Wollman          * matter if it is destined to another node, or whether it is
498f0068c4aSGarrett Wollman          * a multicast one, RSVP wants it! and prevents it from being forwarded
499f0068c4aSGarrett Wollman          * anywhere else. Also checks if the rsvp daemon is running before
500f0068c4aSGarrett Wollman 	 * grabbing the packet.
501f0068c4aSGarrett Wollman          */
5021c5de19aSGarrett Wollman 	if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
503f0068c4aSGarrett Wollman 		goto ours;
504f0068c4aSGarrett Wollman 
505df8bae1dSRodney W. Grimes 	/*
506df8bae1dSRodney W. Grimes 	 * Check our list of addresses, to see if the packet is for us.
507cc766e04SGarrett Wollman 	 * If we don't have any addresses, assume any unicast packet
508cc766e04SGarrett Wollman 	 * we receive might be for us (and let the upper layers deal
509cc766e04SGarrett Wollman 	 * with it).
510df8bae1dSRodney W. Grimes 	 */
511cc766e04SGarrett Wollman 	if (TAILQ_EMPTY(&in_ifaddrhead) &&
512cc766e04SGarrett Wollman 	    (m->m_flags & (M_MCAST|M_BCAST)) == 0)
513cc766e04SGarrett Wollman 		goto ours;
514cc766e04SGarrett Wollman 
5157538a9a0SJonathan Lemon 	/*
516823db0e9SDon Lewis 	 * Enable a consistency check between the destination address
517823db0e9SDon Lewis 	 * and the arrival interface for a unicast packet (the RFC 1122
518823db0e9SDon Lewis 	 * strong ES model) if IP forwarding is disabled and the packet
519e15ae1b2SDon Lewis 	 * is not locally generated and the packet is not subject to
520e15ae1b2SDon Lewis 	 * 'ipfw fwd'.
5213f67c834SDon Lewis 	 *
5223f67c834SDon Lewis 	 * XXX - Checking also should be disabled if the destination
5233f67c834SDon Lewis 	 * address is ipnat'ed to a different interface.
5243f67c834SDon Lewis 	 *
525a8f12100SDon Lewis 	 * XXX - Checking is incompatible with IP aliases added
5263f67c834SDon Lewis 	 * to the loopback interface instead of the interface where
5273f67c834SDon Lewis 	 * the packets are received.
528a9771948SGleb Smirnoff 	 *
529a9771948SGleb Smirnoff 	 * XXX - This is the case for carp vhost IPs as well so we
530a9771948SGleb Smirnoff 	 * insert a workaround. If the packet got here, we already
531a9771948SGleb Smirnoff 	 * checked with carp_iamatch() and carp_forus().
532823db0e9SDon Lewis 	 */
533823db0e9SDon Lewis 	checkif = ip_checkinterface && (ipforwarding == 0) &&
5349494d596SBrooks Davis 	    m->m_pkthdr.rcvif != NULL &&
535e15ae1b2SDon Lewis 	    ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
536a9771948SGleb Smirnoff #ifdef DEV_CARP
537a9771948SGleb Smirnoff 	    !m->m_pkthdr.rcvif->if_carp &&
538a9771948SGleb Smirnoff #endif
5399b932e9eSAndre Oppermann 	    (dchg == 0);
540823db0e9SDon Lewis 
541ca925d9cSJonathan Lemon 	/*
542ca925d9cSJonathan Lemon 	 * Check for exact addresses in the hash bucket.
543ca925d9cSJonathan Lemon 	 */
5449b932e9eSAndre Oppermann 	LIST_FOREACH(ia, INADDR_HASH(ip->ip_dst.s_addr), ia_hash) {
545f9e354dfSJulian Elischer 		/*
546823db0e9SDon Lewis 		 * If the address matches, verify that the packet
547823db0e9SDon Lewis 		 * arrived via the correct interface if checking is
548823db0e9SDon Lewis 		 * enabled.
549f9e354dfSJulian Elischer 		 */
5509b932e9eSAndre Oppermann 		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr &&
551823db0e9SDon Lewis 		    (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif))
552ed1ff184SJulian Elischer 			goto ours;
553ca925d9cSJonathan Lemon 	}
554823db0e9SDon Lewis 	/*
555ca925d9cSJonathan Lemon 	 * Check for broadcast addresses.
556ca925d9cSJonathan Lemon 	 *
557ca925d9cSJonathan Lemon 	 * Only accept broadcast packets that arrive via the matching
558ca925d9cSJonathan Lemon 	 * interface.  Reception of forwarded directed broadcasts would
559ca925d9cSJonathan Lemon 	 * be handled via ip_forward() and ether_output() with the loopback
560ca925d9cSJonathan Lemon 	 * into the stack for SIMPLEX interfaces handled by ether_output().
561823db0e9SDon Lewis 	 */
5624f450ff9SBruce M Simpson 	if (m->m_pkthdr.rcvif != NULL &&
5634f450ff9SBruce M Simpson 	    m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
564ca925d9cSJonathan Lemon 	        TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
565ca925d9cSJonathan Lemon 			if (ifa->ifa_addr->sa_family != AF_INET)
566ca925d9cSJonathan Lemon 				continue;
567ca925d9cSJonathan Lemon 			ia = ifatoia(ifa);
568df8bae1dSRodney W. Grimes 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
5699b932e9eSAndre Oppermann 			    ip->ip_dst.s_addr)
570df8bae1dSRodney W. Grimes 				goto ours;
5719b932e9eSAndre Oppermann 			if (ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr)
572df8bae1dSRodney W. Grimes 				goto ours;
5730ac40133SBrian Somers #ifdef BOOTP_COMPAT
574ca925d9cSJonathan Lemon 			if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
575ca925d9cSJonathan Lemon 				goto ours;
5760ac40133SBrian Somers #endif
577df8bae1dSRodney W. Grimes 		}
578df8bae1dSRodney W. Grimes 	}
579df8bae1dSRodney W. Grimes 	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
580df8bae1dSRodney W. Grimes 		struct in_multi *inm;
581df8bae1dSRodney W. Grimes 		if (ip_mrouter) {
582df8bae1dSRodney W. Grimes 			/*
583df8bae1dSRodney W. Grimes 			 * If we are acting as a multicast router, all
584df8bae1dSRodney W. Grimes 			 * incoming multicast packets are passed to the
585df8bae1dSRodney W. Grimes 			 * kernel-level multicast forwarding function.
586df8bae1dSRodney W. Grimes 			 * The packet is returned (relatively) intact; if
587df8bae1dSRodney W. Grimes 			 * ip_mforward() returns a non-zero value, the packet
588df8bae1dSRodney W. Grimes 			 * must be discarded, else it may be accepted below.
589df8bae1dSRodney W. Grimes 			 */
590bbb4330bSLuigi Rizzo 			if (ip_mforward &&
591bbb4330bSLuigi Rizzo 			    ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) {
592df8bae1dSRodney W. Grimes 				ipstat.ips_cantforward++;
593df8bae1dSRodney W. Grimes 				m_freem(m);
594c67b1d17SGarrett Wollman 				return;
595df8bae1dSRodney W. Grimes 			}
596df8bae1dSRodney W. Grimes 
597df8bae1dSRodney W. Grimes 			/*
59811612afaSDima Dorfman 			 * The process-level routing daemon needs to receive
599df8bae1dSRodney W. Grimes 			 * all multicast IGMP packets, whether or not this
600df8bae1dSRodney W. Grimes 			 * host belongs to their destination groups.
601df8bae1dSRodney W. Grimes 			 */
602df8bae1dSRodney W. Grimes 			if (ip->ip_p == IPPROTO_IGMP)
603df8bae1dSRodney W. Grimes 				goto ours;
604df8bae1dSRodney W. Grimes 			ipstat.ips_forward++;
605df8bae1dSRodney W. Grimes 		}
606df8bae1dSRodney W. Grimes 		/*
607df8bae1dSRodney W. Grimes 		 * See if we belong to the destination multicast group on the
608df8bae1dSRodney W. Grimes 		 * arrival interface.
609df8bae1dSRodney W. Grimes 		 */
610df8bae1dSRodney W. Grimes 		IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
611df8bae1dSRodney W. Grimes 		if (inm == NULL) {
61282c39223SGarrett Wollman 			ipstat.ips_notmember++;
613df8bae1dSRodney W. Grimes 			m_freem(m);
614c67b1d17SGarrett Wollman 			return;
615df8bae1dSRodney W. Grimes 		}
616df8bae1dSRodney W. Grimes 		goto ours;
617df8bae1dSRodney W. Grimes 	}
618df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
619df8bae1dSRodney W. Grimes 		goto ours;
620df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == INADDR_ANY)
621df8bae1dSRodney W. Grimes 		goto ours;
622df8bae1dSRodney W. Grimes 
6236a800098SYoshinobu Inoue 	/*
6246a800098SYoshinobu Inoue 	 * FAITH(Firewall Aided Internet Translator)
6256a800098SYoshinobu Inoue 	 */
6266a800098SYoshinobu Inoue 	if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
6276a800098SYoshinobu Inoue 		if (ip_keepfaith) {
6286a800098SYoshinobu Inoue 			if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP)
6296a800098SYoshinobu Inoue 				goto ours;
6306a800098SYoshinobu Inoue 		}
6316a800098SYoshinobu Inoue 		m_freem(m);
6326a800098SYoshinobu Inoue 		return;
6336a800098SYoshinobu Inoue 	}
6349494d596SBrooks Davis 
635df8bae1dSRodney W. Grimes 	/*
636df8bae1dSRodney W. Grimes 	 * Not for us; forward if possible and desirable.
637df8bae1dSRodney W. Grimes 	 */
638df8bae1dSRodney W. Grimes 	if (ipforwarding == 0) {
639df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
640df8bae1dSRodney W. Grimes 		m_freem(m);
641546f251bSChris D. Faulhaber 	} else {
642546f251bSChris D. Faulhaber #ifdef IPSEC
643546f251bSChris D. Faulhaber 		/*
644546f251bSChris D. Faulhaber 		 * Enforce inbound IPsec SPD.
645546f251bSChris D. Faulhaber 		 */
646546f251bSChris D. Faulhaber 		if (ipsec4_in_reject(m, NULL)) {
647546f251bSChris D. Faulhaber 			ipsecstat.in_polvio++;
648546f251bSChris D. Faulhaber 			goto bad;
649546f251bSChris D. Faulhaber 		}
650546f251bSChris D. Faulhaber #endif /* IPSEC */
651b9234fafSSam Leffler #ifdef FAST_IPSEC
652b9234fafSSam Leffler 		mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
653b9234fafSSam Leffler 		s = splnet();
654b9234fafSSam Leffler 		if (mtag != NULL) {
655b9234fafSSam Leffler 			tdbi = (struct tdb_ident *)(mtag + 1);
656b9234fafSSam Leffler 			sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
657b9234fafSSam Leffler 		} else {
658b9234fafSSam Leffler 			sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
659b9234fafSSam Leffler 						   IP_FORWARDING, &error);
660b9234fafSSam Leffler 		}
661b9234fafSSam Leffler 		if (sp == NULL) {	/* NB: can happen if error */
662b9234fafSSam Leffler 			splx(s);
663b9234fafSSam Leffler 			/*XXX error stat???*/
664b9234fafSSam Leffler 			DPRINTF(("ip_input: no SP for forwarding\n"));	/*XXX*/
665b9234fafSSam Leffler 			goto bad;
666b9234fafSSam Leffler 		}
667b9234fafSSam Leffler 
668b9234fafSSam Leffler 		/*
669b9234fafSSam Leffler 		 * Check security policy against packet attributes.
670b9234fafSSam Leffler 		 */
671b9234fafSSam Leffler 		error = ipsec_in_reject(sp, m);
672b9234fafSSam Leffler 		KEY_FREESP(&sp);
673b9234fafSSam Leffler 		splx(s);
674b9234fafSSam Leffler 		if (error) {
675b9234fafSSam Leffler 			ipstat.ips_cantforward++;
676b9234fafSSam Leffler 			goto bad;
677b9234fafSSam Leffler 		}
678b9234fafSSam Leffler #endif /* FAST_IPSEC */
6799b932e9eSAndre Oppermann 		ip_forward(m, dchg);
680546f251bSChris D. Faulhaber 	}
681c67b1d17SGarrett Wollman 	return;
682df8bae1dSRodney W. Grimes 
683df8bae1dSRodney W. Grimes ours:
684d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
685d0ebc0d2SYaroslav Tykhiy 	/*
686d0ebc0d2SYaroslav Tykhiy 	 * IPSTEALTH: Process non-routing options only
687d0ebc0d2SYaroslav Tykhiy 	 * if the packet is destined for us.
688d0ebc0d2SYaroslav Tykhiy 	 */
6892b25acc1SLuigi Rizzo 	if (ipstealth && hlen > sizeof (struct ip) &&
6909b932e9eSAndre Oppermann 	    ip_dooptions(m, 1))
691d0ebc0d2SYaroslav Tykhiy 		return;
692d0ebc0d2SYaroslav Tykhiy #endif /* IPSTEALTH */
693d0ebc0d2SYaroslav Tykhiy 
6945da9f8faSJosef Karthauser 	/* Count the packet in the ip address stats */
6955da9f8faSJosef Karthauser 	if (ia != NULL) {
6965da9f8faSJosef Karthauser 		ia->ia_ifa.if_ipackets++;
6975da9f8faSJosef Karthauser 		ia->ia_ifa.if_ibytes += m->m_pkthdr.len;
6985da9f8faSJosef Karthauser 	}
699100ba1a6SJordan K. Hubbard 
70063f8d699SJordan K. Hubbard 	/*
701b6ea1aa5SRuslan Ermilov 	 * Attempt reassembly; if it succeeds, proceed.
702ac9d7e26SMax Laier 	 * ip_reass() will return a different mbuf.
703df8bae1dSRodney W. Grimes 	 */
704f0cada84SAndre Oppermann 	if (ip->ip_off & (IP_MF | IP_OFFMASK)) {
705f0cada84SAndre Oppermann 		m = ip_reass(m);
706f0cada84SAndre Oppermann 		if (m == NULL)
707c67b1d17SGarrett Wollman 			return;
7086a800098SYoshinobu Inoue 		ip = mtod(m, struct ip *);
7097e2df452SRuslan Ermilov 		/* Get the header length of the reassembled packet */
71053be11f6SPoul-Henning Kamp 		hlen = ip->ip_hl << 2;
711f0cada84SAndre Oppermann 	}
712f0cada84SAndre Oppermann 
713f0cada84SAndre Oppermann 	/*
714f0cada84SAndre Oppermann 	 * Further protocols expect the packet length to be w/o the
715f0cada84SAndre Oppermann 	 * IP header.
716f0cada84SAndre Oppermann 	 */
717df8bae1dSRodney W. Grimes 	ip->ip_len -= hlen;
718df8bae1dSRodney W. Grimes 
71933841545SHajimu UMEMOTO #ifdef IPSEC
72033841545SHajimu UMEMOTO 	/*
72133841545SHajimu UMEMOTO 	 * enforce IPsec policy checking if we are seeing last header.
72233841545SHajimu UMEMOTO 	 * note that we do not visit this with protocols with pcb layer
72333841545SHajimu UMEMOTO 	 * code - like udp/tcp/raw ip.
72433841545SHajimu UMEMOTO 	 */
72533841545SHajimu UMEMOTO 	if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 &&
72633841545SHajimu UMEMOTO 	    ipsec4_in_reject(m, NULL)) {
72733841545SHajimu UMEMOTO 		ipsecstat.in_polvio++;
72833841545SHajimu UMEMOTO 		goto bad;
72933841545SHajimu UMEMOTO 	}
73033841545SHajimu UMEMOTO #endif
731b9234fafSSam Leffler #if FAST_IPSEC
732b9234fafSSam Leffler 	/*
733b9234fafSSam Leffler 	 * enforce IPsec policy checking if we are seeing last header.
734b9234fafSSam Leffler 	 * note that we do not visit this with protocols with pcb layer
735b9234fafSSam Leffler 	 * code - like udp/tcp/raw ip.
736b9234fafSSam Leffler 	 */
737b9234fafSSam Leffler 	if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0) {
738b9234fafSSam Leffler 		/*
739b9234fafSSam Leffler 		 * Check if the packet has already had IPsec processing
740b9234fafSSam Leffler 		 * done.  If so, then just pass it along.  This tag gets
741b9234fafSSam Leffler 		 * set during AH, ESP, etc. input handling, before the
742b9234fafSSam Leffler 		 * packet is returned to the ip input queue for delivery.
743b9234fafSSam Leffler 		 */
744b9234fafSSam Leffler 		mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
745b9234fafSSam Leffler 		s = splnet();
746b9234fafSSam Leffler 		if (mtag != NULL) {
747b9234fafSSam Leffler 			tdbi = (struct tdb_ident *)(mtag + 1);
748b9234fafSSam Leffler 			sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
749b9234fafSSam Leffler 		} else {
750b9234fafSSam Leffler 			sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
751b9234fafSSam Leffler 						   IP_FORWARDING, &error);
752b9234fafSSam Leffler 		}
753b9234fafSSam Leffler 		if (sp != NULL) {
754b9234fafSSam Leffler 			/*
755b9234fafSSam Leffler 			 * Check security policy against packet attributes.
756b9234fafSSam Leffler 			 */
757b9234fafSSam Leffler 			error = ipsec_in_reject(sp, m);
758b9234fafSSam Leffler 			KEY_FREESP(&sp);
759b9234fafSSam Leffler 		} else {
760b9234fafSSam Leffler 			/* XXX error stat??? */
761b9234fafSSam Leffler 			error = EINVAL;
762b9234fafSSam Leffler DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/
763b9234fafSSam Leffler 			goto bad;
764b9234fafSSam Leffler 		}
765b9234fafSSam Leffler 		splx(s);
766b9234fafSSam Leffler 		if (error)
767b9234fafSSam Leffler 			goto bad;
768b9234fafSSam Leffler 	}
769b9234fafSSam Leffler #endif /* FAST_IPSEC */
77033841545SHajimu UMEMOTO 
771df8bae1dSRodney W. Grimes 	/*
772df8bae1dSRodney W. Grimes 	 * Switch out to protocol's input routine.
773df8bae1dSRodney W. Grimes 	 */
774df8bae1dSRodney W. Grimes 	ipstat.ips_delivered++;
7759b932e9eSAndre Oppermann 
7762b25acc1SLuigi Rizzo 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
777c67b1d17SGarrett Wollman 	return;
778df8bae1dSRodney W. Grimes bad:
779df8bae1dSRodney W. Grimes 	m_freem(m);
780c67b1d17SGarrett Wollman }
781c67b1d17SGarrett Wollman 
782c67b1d17SGarrett Wollman /*
7838948e4baSArchie Cobbs  * Take incoming datagram fragment and try to reassemble it into
784f0cada84SAndre Oppermann  * whole datagram.  If the argument is the first fragment or one
785f0cada84SAndre Oppermann  * in between the function will return NULL and store the mbuf
786f0cada84SAndre Oppermann  * in the fragment chain.  If the argument is the last fragment
787f0cada84SAndre Oppermann  * the packet will be reassembled and the pointer to the new
788f0cada84SAndre Oppermann  * mbuf returned for further processing.  Only m_tags attached
789f0cada84SAndre Oppermann  * to the first packet/fragment are preserved.
790f0cada84SAndre Oppermann  * The IP header is *NOT* adjusted out of iplen.
791df8bae1dSRodney W. Grimes  */
7928948e4baSArchie Cobbs 
793f0cada84SAndre Oppermann struct mbuf *
794f0cada84SAndre Oppermann ip_reass(struct mbuf *m)
795df8bae1dSRodney W. Grimes {
796f0cada84SAndre Oppermann 	struct ip *ip;
797f0cada84SAndre Oppermann 	struct mbuf *p, *q, *nq, *t;
798f0cada84SAndre Oppermann 	struct ipq *fp = NULL;
799f0cada84SAndre Oppermann 	struct ipqhead *head;
800f0cada84SAndre Oppermann 	int i, hlen, next;
80159dfcba4SHajimu UMEMOTO 	u_int8_t ecn, ecn0;
802f0cada84SAndre Oppermann 	u_short hash;
803df8bae1dSRodney W. Grimes 
804800af1fbSMaxim Konovalov 	/* If maxnipq or maxfragsperpacket are 0, never accept fragments. */
805800af1fbSMaxim Konovalov 	if (maxnipq == 0 || maxfragsperpacket == 0) {
806f0cada84SAndre Oppermann 		ipstat.ips_fragments++;
807f0cada84SAndre Oppermann 		ipstat.ips_fragdropped++;
8089d804f81SAndre Oppermann 		m_freem(m);
8099d804f81SAndre Oppermann 		return (NULL);
810f0cada84SAndre Oppermann 	}
8112fad1e93SSam Leffler 
812f0cada84SAndre Oppermann 	ip = mtod(m, struct ip *);
813f0cada84SAndre Oppermann 	hlen = ip->ip_hl << 2;
814f0cada84SAndre Oppermann 
815f0cada84SAndre Oppermann 	hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
816f0cada84SAndre Oppermann 	head = &ipq[hash];
817f0cada84SAndre Oppermann 	IPQ_LOCK();
818f0cada84SAndre Oppermann 
819f0cada84SAndre Oppermann 	/*
820f0cada84SAndre Oppermann 	 * Look for queue of fragments
821f0cada84SAndre Oppermann 	 * of this datagram.
822f0cada84SAndre Oppermann 	 */
823f0cada84SAndre Oppermann 	TAILQ_FOREACH(fp, head, ipq_list)
824f0cada84SAndre Oppermann 		if (ip->ip_id == fp->ipq_id &&
825f0cada84SAndre Oppermann 		    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
826f0cada84SAndre Oppermann 		    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
827f0cada84SAndre Oppermann #ifdef MAC
828f0cada84SAndre Oppermann 		    mac_fragment_match(m, fp) &&
829f0cada84SAndre Oppermann #endif
830f0cada84SAndre Oppermann 		    ip->ip_p == fp->ipq_p)
831f0cada84SAndre Oppermann 			goto found;
832f0cada84SAndre Oppermann 
833f0cada84SAndre Oppermann 	fp = NULL;
834f0cada84SAndre Oppermann 
835f0cada84SAndre Oppermann 	/*
836f0cada84SAndre Oppermann 	 * Enforce upper bound on number of fragmented packets
837f0cada84SAndre Oppermann 	 * for which we attempt reassembly;
838f0cada84SAndre Oppermann 	 * If maxnipq is -1, accept all fragments without limitation.
839f0cada84SAndre Oppermann 	 */
840f0cada84SAndre Oppermann 	if ((nipq > maxnipq) && (maxnipq > 0)) {
841f0cada84SAndre Oppermann 		/*
842f0cada84SAndre Oppermann 		 * drop something from the tail of the current queue
843f0cada84SAndre Oppermann 		 * before proceeding further
844f0cada84SAndre Oppermann 		 */
845f0cada84SAndre Oppermann 		struct ipq *q = TAILQ_LAST(head, ipqhead);
846f0cada84SAndre Oppermann 		if (q == NULL) {   /* gak */
847f0cada84SAndre Oppermann 			for (i = 0; i < IPREASS_NHASH; i++) {
848f0cada84SAndre Oppermann 				struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead);
849f0cada84SAndre Oppermann 				if (r) {
850f0cada84SAndre Oppermann 					ipstat.ips_fragtimeout += r->ipq_nfrags;
851f0cada84SAndre Oppermann 					ip_freef(&ipq[i], r);
852f0cada84SAndre Oppermann 					break;
853f0cada84SAndre Oppermann 				}
854f0cada84SAndre Oppermann 			}
855f0cada84SAndre Oppermann 		} else {
856f0cada84SAndre Oppermann 			ipstat.ips_fragtimeout += q->ipq_nfrags;
857f0cada84SAndre Oppermann 			ip_freef(head, q);
858f0cada84SAndre Oppermann 		}
859f0cada84SAndre Oppermann 	}
860f0cada84SAndre Oppermann 
861f0cada84SAndre Oppermann found:
862f0cada84SAndre Oppermann 	/*
863f0cada84SAndre Oppermann 	 * Adjust ip_len to not reflect header,
864f0cada84SAndre Oppermann 	 * convert offset of this to bytes.
865f0cada84SAndre Oppermann 	 */
866f0cada84SAndre Oppermann 	ip->ip_len -= hlen;
867f0cada84SAndre Oppermann 	if (ip->ip_off & IP_MF) {
868f0cada84SAndre Oppermann 		/*
869f0cada84SAndre Oppermann 		 * Make sure that fragments have a data length
870f0cada84SAndre Oppermann 		 * that's a non-zero multiple of 8 bytes.
871f0cada84SAndre Oppermann 		 */
872f0cada84SAndre Oppermann 		if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
873f0cada84SAndre Oppermann 			ipstat.ips_toosmall++; /* XXX */
874f0cada84SAndre Oppermann 			goto dropfrag;
875f0cada84SAndre Oppermann 		}
876f0cada84SAndre Oppermann 		m->m_flags |= M_FRAG;
877f0cada84SAndre Oppermann 	} else
878f0cada84SAndre Oppermann 		m->m_flags &= ~M_FRAG;
879f0cada84SAndre Oppermann 	ip->ip_off <<= 3;
880f0cada84SAndre Oppermann 
881f0cada84SAndre Oppermann 
882f0cada84SAndre Oppermann 	/*
883f0cada84SAndre Oppermann 	 * Attempt reassembly; if it succeeds, proceed.
884f0cada84SAndre Oppermann 	 * ip_reass() will return a different mbuf.
885f0cada84SAndre Oppermann 	 */
886f0cada84SAndre Oppermann 	ipstat.ips_fragments++;
887f0cada84SAndre Oppermann 	m->m_pkthdr.header = ip;
888f0cada84SAndre Oppermann 
889f0cada84SAndre Oppermann 	/* Previous ip_reass() started here. */
890df8bae1dSRodney W. Grimes 	/*
891df8bae1dSRodney W. Grimes 	 * Presence of header sizes in mbufs
892df8bae1dSRodney W. Grimes 	 * would confuse code below.
893df8bae1dSRodney W. Grimes 	 */
894df8bae1dSRodney W. Grimes 	m->m_data += hlen;
895df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
896df8bae1dSRodney W. Grimes 
897df8bae1dSRodney W. Grimes 	/*
898df8bae1dSRodney W. Grimes 	 * If first fragment to arrive, create a reassembly queue.
899df8bae1dSRodney W. Grimes 	 */
900042bbfa3SRobert Watson 	if (fp == NULL) {
901a163d034SWarner Losh 		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
902df8bae1dSRodney W. Grimes 			goto dropfrag;
903df8bae1dSRodney W. Grimes 		fp = mtod(t, struct ipq *);
90436b0360bSRobert Watson #ifdef MAC
9055e7ce478SRobert Watson 		if (mac_init_ipq(fp, M_NOWAIT) != 0) {
9065e7ce478SRobert Watson 			m_free(t);
9075e7ce478SRobert Watson 			goto dropfrag;
9085e7ce478SRobert Watson 		}
90936b0360bSRobert Watson 		mac_create_ipq(m, fp);
91036b0360bSRobert Watson #endif
911462b86feSPoul-Henning Kamp 		TAILQ_INSERT_HEAD(head, fp, ipq_list);
912194a213eSAndrey A. Chernov 		nipq++;
913375386e2SMike Silbersack 		fp->ipq_nfrags = 1;
914df8bae1dSRodney W. Grimes 		fp->ipq_ttl = IPFRAGTTL;
915df8bae1dSRodney W. Grimes 		fp->ipq_p = ip->ip_p;
916df8bae1dSRodney W. Grimes 		fp->ipq_id = ip->ip_id;
9176effc713SDoug Rabson 		fp->ipq_src = ip->ip_src;
9186effc713SDoug Rabson 		fp->ipq_dst = ip->ip_dst;
919af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
920af38c68cSLuigi Rizzo 		m->m_nextpkt = NULL;
921800af1fbSMaxim Konovalov 		goto done;
92236b0360bSRobert Watson 	} else {
923375386e2SMike Silbersack 		fp->ipq_nfrags++;
92436b0360bSRobert Watson #ifdef MAC
92536b0360bSRobert Watson 		mac_update_ipq(m, fp);
92636b0360bSRobert Watson #endif
927df8bae1dSRodney W. Grimes 	}
928df8bae1dSRodney W. Grimes 
9296effc713SDoug Rabson #define GETIP(m)	((struct ip*)((m)->m_pkthdr.header))
9306effc713SDoug Rabson 
931df8bae1dSRodney W. Grimes 	/*
93259dfcba4SHajimu UMEMOTO 	 * Handle ECN by comparing this segment with the first one;
93359dfcba4SHajimu UMEMOTO 	 * if CE is set, do not lose CE.
93459dfcba4SHajimu UMEMOTO 	 * drop if CE and not-ECT are mixed for the same packet.
93559dfcba4SHajimu UMEMOTO 	 */
93659dfcba4SHajimu UMEMOTO 	ecn = ip->ip_tos & IPTOS_ECN_MASK;
93759dfcba4SHajimu UMEMOTO 	ecn0 = GETIP(fp->ipq_frags)->ip_tos & IPTOS_ECN_MASK;
93859dfcba4SHajimu UMEMOTO 	if (ecn == IPTOS_ECN_CE) {
93959dfcba4SHajimu UMEMOTO 		if (ecn0 == IPTOS_ECN_NOTECT)
94059dfcba4SHajimu UMEMOTO 			goto dropfrag;
94159dfcba4SHajimu UMEMOTO 		if (ecn0 != IPTOS_ECN_CE)
94259dfcba4SHajimu UMEMOTO 			GETIP(fp->ipq_frags)->ip_tos |= IPTOS_ECN_CE;
94359dfcba4SHajimu UMEMOTO 	}
94459dfcba4SHajimu UMEMOTO 	if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT)
94559dfcba4SHajimu UMEMOTO 		goto dropfrag;
94659dfcba4SHajimu UMEMOTO 
94759dfcba4SHajimu UMEMOTO 	/*
948df8bae1dSRodney W. Grimes 	 * Find a segment which begins after this one does.
949df8bae1dSRodney W. Grimes 	 */
9506effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
9516effc713SDoug Rabson 		if (GETIP(q)->ip_off > ip->ip_off)
952df8bae1dSRodney W. Grimes 			break;
953df8bae1dSRodney W. Grimes 
954df8bae1dSRodney W. Grimes 	/*
955df8bae1dSRodney W. Grimes 	 * If there is a preceding segment, it may provide some of
956df8bae1dSRodney W. Grimes 	 * our data already.  If so, drop the data from the incoming
957af38c68cSLuigi Rizzo 	 * segment.  If it provides all of our data, drop us, otherwise
958af38c68cSLuigi Rizzo 	 * stick new segment in the proper place.
959db4f9cc7SJonathan Lemon 	 *
960db4f9cc7SJonathan Lemon 	 * If some of the data is dropped from the the preceding
961db4f9cc7SJonathan Lemon 	 * segment, then it's checksum is invalidated.
962df8bae1dSRodney W. Grimes 	 */
9636effc713SDoug Rabson 	if (p) {
9646effc713SDoug Rabson 		i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
965df8bae1dSRodney W. Grimes 		if (i > 0) {
966df8bae1dSRodney W. Grimes 			if (i >= ip->ip_len)
967df8bae1dSRodney W. Grimes 				goto dropfrag;
9686a800098SYoshinobu Inoue 			m_adj(m, i);
969db4f9cc7SJonathan Lemon 			m->m_pkthdr.csum_flags = 0;
970df8bae1dSRodney W. Grimes 			ip->ip_off += i;
971df8bae1dSRodney W. Grimes 			ip->ip_len -= i;
972df8bae1dSRodney W. Grimes 		}
973af38c68cSLuigi Rizzo 		m->m_nextpkt = p->m_nextpkt;
974af38c68cSLuigi Rizzo 		p->m_nextpkt = m;
975af38c68cSLuigi Rizzo 	} else {
976af38c68cSLuigi Rizzo 		m->m_nextpkt = fp->ipq_frags;
977af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
978df8bae1dSRodney W. Grimes 	}
979df8bae1dSRodney W. Grimes 
980df8bae1dSRodney W. Grimes 	/*
981df8bae1dSRodney W. Grimes 	 * While we overlap succeeding segments trim them or,
982df8bae1dSRodney W. Grimes 	 * if they are completely covered, dequeue them.
983df8bae1dSRodney W. Grimes 	 */
9846effc713SDoug Rabson 	for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
985af38c68cSLuigi Rizzo 	     q = nq) {
986b36f5b37SMaxim Konovalov 		i = (ip->ip_off + ip->ip_len) - GETIP(q)->ip_off;
9876effc713SDoug Rabson 		if (i < GETIP(q)->ip_len) {
9886effc713SDoug Rabson 			GETIP(q)->ip_len -= i;
9896effc713SDoug Rabson 			GETIP(q)->ip_off += i;
9906effc713SDoug Rabson 			m_adj(q, i);
991db4f9cc7SJonathan Lemon 			q->m_pkthdr.csum_flags = 0;
992df8bae1dSRodney W. Grimes 			break;
993df8bae1dSRodney W. Grimes 		}
9946effc713SDoug Rabson 		nq = q->m_nextpkt;
995af38c68cSLuigi Rizzo 		m->m_nextpkt = nq;
99699e8617dSMaxim Konovalov 		ipstat.ips_fragdropped++;
997375386e2SMike Silbersack 		fp->ipq_nfrags--;
9986effc713SDoug Rabson 		m_freem(q);
999df8bae1dSRodney W. Grimes 	}
1000df8bae1dSRodney W. Grimes 
1001df8bae1dSRodney W. Grimes 	/*
1002375386e2SMike Silbersack 	 * Check for complete reassembly and perform frag per packet
1003375386e2SMike Silbersack 	 * limiting.
1004375386e2SMike Silbersack 	 *
1005375386e2SMike Silbersack 	 * Frag limiting is performed here so that the nth frag has
1006375386e2SMike Silbersack 	 * a chance to complete the packet before we drop the packet.
1007375386e2SMike Silbersack 	 * As a result, n+1 frags are actually allowed per packet, but
1008375386e2SMike Silbersack 	 * only n will ever be stored. (n = maxfragsperpacket.)
1009375386e2SMike Silbersack 	 *
1010df8bae1dSRodney W. Grimes 	 */
10116effc713SDoug Rabson 	next = 0;
10126effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
1013375386e2SMike Silbersack 		if (GETIP(q)->ip_off != next) {
101499e8617dSMaxim Konovalov 			if (fp->ipq_nfrags > maxfragsperpacket) {
101599e8617dSMaxim Konovalov 				ipstat.ips_fragdropped += fp->ipq_nfrags;
1016375386e2SMike Silbersack 				ip_freef(head, fp);
101799e8617dSMaxim Konovalov 			}
1018f0cada84SAndre Oppermann 			goto done;
1019375386e2SMike Silbersack 		}
10206effc713SDoug Rabson 		next += GETIP(q)->ip_len;
10216effc713SDoug Rabson 	}
10226effc713SDoug Rabson 	/* Make sure the last packet didn't have the IP_MF flag */
1023375386e2SMike Silbersack 	if (p->m_flags & M_FRAG) {
102499e8617dSMaxim Konovalov 		if (fp->ipq_nfrags > maxfragsperpacket) {
102599e8617dSMaxim Konovalov 			ipstat.ips_fragdropped += fp->ipq_nfrags;
1026375386e2SMike Silbersack 			ip_freef(head, fp);
102799e8617dSMaxim Konovalov 		}
1028f0cada84SAndre Oppermann 		goto done;
1029375386e2SMike Silbersack 	}
1030df8bae1dSRodney W. Grimes 
1031df8bae1dSRodney W. Grimes 	/*
1032430d30d8SBill Fenner 	 * Reassembly is complete.  Make sure the packet is a sane size.
1033430d30d8SBill Fenner 	 */
10346effc713SDoug Rabson 	q = fp->ipq_frags;
10356effc713SDoug Rabson 	ip = GETIP(q);
103653be11f6SPoul-Henning Kamp 	if (next + (ip->ip_hl << 2) > IP_MAXPACKET) {
1037430d30d8SBill Fenner 		ipstat.ips_toolong++;
103899e8617dSMaxim Konovalov 		ipstat.ips_fragdropped += fp->ipq_nfrags;
1039462b86feSPoul-Henning Kamp 		ip_freef(head, fp);
1040f0cada84SAndre Oppermann 		goto done;
1041430d30d8SBill Fenner 	}
1042430d30d8SBill Fenner 
1043430d30d8SBill Fenner 	/*
1044430d30d8SBill Fenner 	 * Concatenate fragments.
1045df8bae1dSRodney W. Grimes 	 */
10466effc713SDoug Rabson 	m = q;
1047df8bae1dSRodney W. Grimes 	t = m->m_next;
104802410549SRobert Watson 	m->m_next = NULL;
1049df8bae1dSRodney W. Grimes 	m_cat(m, t);
10506effc713SDoug Rabson 	nq = q->m_nextpkt;
105102410549SRobert Watson 	q->m_nextpkt = NULL;
10526effc713SDoug Rabson 	for (q = nq; q != NULL; q = nq) {
10536effc713SDoug Rabson 		nq = q->m_nextpkt;
1054945aa40dSDoug Rabson 		q->m_nextpkt = NULL;
1055db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags;
1056db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_data += q->m_pkthdr.csum_data;
1057a8db1d93SJonathan Lemon 		m_cat(m, q);
1058df8bae1dSRodney W. Grimes 	}
105936b0360bSRobert Watson #ifdef MAC
106036b0360bSRobert Watson 	mac_create_datagram_from_ipq(fp, m);
106136b0360bSRobert Watson 	mac_destroy_ipq(fp);
106236b0360bSRobert Watson #endif
1063df8bae1dSRodney W. Grimes 
1064df8bae1dSRodney W. Grimes 	/*
1065f0cada84SAndre Oppermann 	 * Create header for new ip packet by modifying header of first
1066f0cada84SAndre Oppermann 	 * packet;  dequeue and discard fragment reassembly header.
1067df8bae1dSRodney W. Grimes 	 * Make header visible.
1068df8bae1dSRodney W. Grimes 	 */
1069f0cada84SAndre Oppermann 	ip->ip_len = (ip->ip_hl << 2) + next;
10706effc713SDoug Rabson 	ip->ip_src = fp->ipq_src;
10716effc713SDoug Rabson 	ip->ip_dst = fp->ipq_dst;
1072462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(head, fp, ipq_list);
1073194a213eSAndrey A. Chernov 	nipq--;
1074df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
107553be11f6SPoul-Henning Kamp 	m->m_len += (ip->ip_hl << 2);
107653be11f6SPoul-Henning Kamp 	m->m_data -= (ip->ip_hl << 2);
1077df8bae1dSRodney W. Grimes 	/* some debugging cruft by sklower, below, will go away soon */
1078a5554bf0SPoul-Henning Kamp 	if (m->m_flags & M_PKTHDR)	/* XXX this should be done elsewhere */
1079a5554bf0SPoul-Henning Kamp 		m_fixhdr(m);
1080f0cada84SAndre Oppermann 	ipstat.ips_reassembled++;
1081f0cada84SAndre Oppermann 	IPQ_UNLOCK();
10826a800098SYoshinobu Inoue 	return (m);
1083df8bae1dSRodney W. Grimes 
1084df8bae1dSRodney W. Grimes dropfrag:
1085df8bae1dSRodney W. Grimes 	ipstat.ips_fragdropped++;
1086042bbfa3SRobert Watson 	if (fp != NULL)
1087375386e2SMike Silbersack 		fp->ipq_nfrags--;
1088df8bae1dSRodney W. Grimes 	m_freem(m);
1089f0cada84SAndre Oppermann done:
1090f0cada84SAndre Oppermann 	IPQ_UNLOCK();
1091f0cada84SAndre Oppermann 	return (NULL);
10926effc713SDoug Rabson 
10936effc713SDoug Rabson #undef GETIP
1094df8bae1dSRodney W. Grimes }
1095df8bae1dSRodney W. Grimes 
1096df8bae1dSRodney W. Grimes /*
1097df8bae1dSRodney W. Grimes  * Free a fragment reassembly header and all
1098df8bae1dSRodney W. Grimes  * associated datagrams.
1099df8bae1dSRodney W. Grimes  */
11000312fbe9SPoul-Henning Kamp static void
1101462b86feSPoul-Henning Kamp ip_freef(fhp, fp)
1102462b86feSPoul-Henning Kamp 	struct ipqhead *fhp;
1103df8bae1dSRodney W. Grimes 	struct ipq *fp;
1104df8bae1dSRodney W. Grimes {
11056effc713SDoug Rabson 	register struct mbuf *q;
1106df8bae1dSRodney W. Grimes 
11072fad1e93SSam Leffler 	IPQ_LOCK_ASSERT();
11082fad1e93SSam Leffler 
11096effc713SDoug Rabson 	while (fp->ipq_frags) {
11106effc713SDoug Rabson 		q = fp->ipq_frags;
11116effc713SDoug Rabson 		fp->ipq_frags = q->m_nextpkt;
11126effc713SDoug Rabson 		m_freem(q);
1113df8bae1dSRodney W. Grimes 	}
1114462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(fhp, fp, ipq_list);
1115df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1116194a213eSAndrey A. Chernov 	nipq--;
1117df8bae1dSRodney W. Grimes }
1118df8bae1dSRodney W. Grimes 
1119df8bae1dSRodney W. Grimes /*
1120df8bae1dSRodney W. Grimes  * IP timer processing;
1121df8bae1dSRodney W. Grimes  * if a timer expires on a reassembly
1122df8bae1dSRodney W. Grimes  * queue, discard it.
1123df8bae1dSRodney W. Grimes  */
1124df8bae1dSRodney W. Grimes void
1125df8bae1dSRodney W. Grimes ip_slowtimo()
1126df8bae1dSRodney W. Grimes {
1127df8bae1dSRodney W. Grimes 	register struct ipq *fp;
1128df8bae1dSRodney W. Grimes 	int s = splnet();
1129194a213eSAndrey A. Chernov 	int i;
1130df8bae1dSRodney W. Grimes 
11312fad1e93SSam Leffler 	IPQ_LOCK();
1132194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1133462b86feSPoul-Henning Kamp 		for(fp = TAILQ_FIRST(&ipq[i]); fp;) {
1134462b86feSPoul-Henning Kamp 			struct ipq *fpp;
1135462b86feSPoul-Henning Kamp 
1136462b86feSPoul-Henning Kamp 			fpp = fp;
1137462b86feSPoul-Henning Kamp 			fp = TAILQ_NEXT(fp, ipq_list);
1138462b86feSPoul-Henning Kamp 			if(--fpp->ipq_ttl == 0) {
113999e8617dSMaxim Konovalov 				ipstat.ips_fragtimeout += fpp->ipq_nfrags;
1140462b86feSPoul-Henning Kamp 				ip_freef(&ipq[i], fpp);
1141df8bae1dSRodney W. Grimes 			}
1142df8bae1dSRodney W. Grimes 		}
1143194a213eSAndrey A. Chernov 	}
1144690a6055SJesper Skriver 	/*
1145690a6055SJesper Skriver 	 * If we are over the maximum number of fragments
1146690a6055SJesper Skriver 	 * (due to the limit being lowered), drain off
1147690a6055SJesper Skriver 	 * enough to get down to the new limit.
1148690a6055SJesper Skriver 	 */
1149a75a485dSMike Silbersack 	if (maxnipq >= 0 && nipq > maxnipq) {
1150690a6055SJesper Skriver 		for (i = 0; i < IPREASS_NHASH; i++) {
1151b36f5b37SMaxim Konovalov 			while (nipq > maxnipq && !TAILQ_EMPTY(&ipq[i])) {
115299e8617dSMaxim Konovalov 				ipstat.ips_fragdropped +=
115399e8617dSMaxim Konovalov 				    TAILQ_FIRST(&ipq[i])->ipq_nfrags;
1154690a6055SJesper Skriver 				ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1155690a6055SJesper Skriver 			}
1156690a6055SJesper Skriver 		}
1157690a6055SJesper Skriver 	}
11582fad1e93SSam Leffler 	IPQ_UNLOCK();
1159df8bae1dSRodney W. Grimes 	splx(s);
1160df8bae1dSRodney W. Grimes }
1161df8bae1dSRodney W. Grimes 
1162df8bae1dSRodney W. Grimes /*
1163df8bae1dSRodney W. Grimes  * Drain off all datagram fragments.
1164df8bae1dSRodney W. Grimes  */
1165df8bae1dSRodney W. Grimes void
1166df8bae1dSRodney W. Grimes ip_drain()
1167df8bae1dSRodney W. Grimes {
1168194a213eSAndrey A. Chernov 	int     i;
1169ce29ab3aSGarrett Wollman 
11702fad1e93SSam Leffler 	IPQ_LOCK();
1171194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1172462b86feSPoul-Henning Kamp 		while(!TAILQ_EMPTY(&ipq[i])) {
117399e8617dSMaxim Konovalov 			ipstat.ips_fragdropped +=
117499e8617dSMaxim Konovalov 			    TAILQ_FIRST(&ipq[i])->ipq_nfrags;
1175462b86feSPoul-Henning Kamp 			ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1176194a213eSAndrey A. Chernov 		}
1177194a213eSAndrey A. Chernov 	}
11782fad1e93SSam Leffler 	IPQ_UNLOCK();
1179ce29ab3aSGarrett Wollman 	in_rtqdrain();
1180df8bae1dSRodney W. Grimes }
1181df8bae1dSRodney W. Grimes 
1182df8bae1dSRodney W. Grimes /*
1183de38924dSAndre Oppermann  * The protocol to be inserted into ip_protox[] must be already registered
1184de38924dSAndre Oppermann  * in inetsw[], either statically or through pf_proto_register().
1185de38924dSAndre Oppermann  */
1186de38924dSAndre Oppermann int
1187de38924dSAndre Oppermann ipproto_register(u_char ipproto)
1188de38924dSAndre Oppermann {
1189de38924dSAndre Oppermann 	struct protosw *pr;
1190de38924dSAndre Oppermann 
1191de38924dSAndre Oppermann 	/* Sanity checks. */
1192de38924dSAndre Oppermann 	if (ipproto == 0)
1193de38924dSAndre Oppermann 		return (EPROTONOSUPPORT);
1194de38924dSAndre Oppermann 
1195de38924dSAndre Oppermann 	/*
1196de38924dSAndre Oppermann 	 * The protocol slot must not be occupied by another protocol
1197de38924dSAndre Oppermann 	 * already.  An index pointing to IPPROTO_RAW is unused.
1198de38924dSAndre Oppermann 	 */
1199de38924dSAndre Oppermann 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
1200de38924dSAndre Oppermann 	if (pr == NULL)
1201de38924dSAndre Oppermann 		return (EPFNOSUPPORT);
1202de38924dSAndre Oppermann 	if (ip_protox[ipproto] != pr - inetsw)	/* IPPROTO_RAW */
1203de38924dSAndre Oppermann 		return (EEXIST);
1204de38924dSAndre Oppermann 
1205de38924dSAndre Oppermann 	/* Find the protocol position in inetsw[] and set the index. */
1206de38924dSAndre Oppermann 	for (pr = inetdomain.dom_protosw;
1207de38924dSAndre Oppermann 	     pr < inetdomain.dom_protoswNPROTOSW; pr++) {
1208de38924dSAndre Oppermann 		if (pr->pr_domain->dom_family == PF_INET &&
1209de38924dSAndre Oppermann 		    pr->pr_protocol && pr->pr_protocol == ipproto) {
1210de38924dSAndre Oppermann 			/* Be careful to only index valid IP protocols. */
1211db77984cSSam Leffler 			if (pr->pr_protocol < IPPROTO_MAX) {
1212de38924dSAndre Oppermann 				ip_protox[pr->pr_protocol] = pr - inetsw;
1213de38924dSAndre Oppermann 				return (0);
1214de38924dSAndre Oppermann 			} else
1215de38924dSAndre Oppermann 				return (EINVAL);
1216de38924dSAndre Oppermann 		}
1217de38924dSAndre Oppermann 	}
1218de38924dSAndre Oppermann 	return (EPROTONOSUPPORT);
1219de38924dSAndre Oppermann }
1220de38924dSAndre Oppermann 
1221de38924dSAndre Oppermann int
1222de38924dSAndre Oppermann ipproto_unregister(u_char ipproto)
1223de38924dSAndre Oppermann {
1224de38924dSAndre Oppermann 	struct protosw *pr;
1225de38924dSAndre Oppermann 
1226de38924dSAndre Oppermann 	/* Sanity checks. */
1227de38924dSAndre Oppermann 	if (ipproto == 0)
1228de38924dSAndre Oppermann 		return (EPROTONOSUPPORT);
1229de38924dSAndre Oppermann 
1230de38924dSAndre Oppermann 	/* Check if the protocol was indeed registered. */
1231de38924dSAndre Oppermann 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
1232de38924dSAndre Oppermann 	if (pr == NULL)
1233de38924dSAndre Oppermann 		return (EPFNOSUPPORT);
1234de38924dSAndre Oppermann 	if (ip_protox[ipproto] == pr - inetsw)  /* IPPROTO_RAW */
1235de38924dSAndre Oppermann 		return (ENOENT);
1236de38924dSAndre Oppermann 
1237de38924dSAndre Oppermann 	/* Reset the protocol slot to IPPROTO_RAW. */
1238de38924dSAndre Oppermann 	ip_protox[ipproto] = pr - inetsw;
1239de38924dSAndre Oppermann 	return (0);
1240de38924dSAndre Oppermann }
1241de38924dSAndre Oppermann 
1242de38924dSAndre Oppermann 
1243de38924dSAndre Oppermann /*
1244df8bae1dSRodney W. Grimes  * Do option processing on a datagram,
1245df8bae1dSRodney W. Grimes  * possibly discarding it if bad options are encountered,
1246df8bae1dSRodney W. Grimes  * or forwarding it if source-routed.
1247d0ebc0d2SYaroslav Tykhiy  * The pass argument is used when operating in the IPSTEALTH
1248d0ebc0d2SYaroslav Tykhiy  * mode to tell what options to process:
1249d0ebc0d2SYaroslav Tykhiy  * [LS]SRR (pass 0) or the others (pass 1).
1250d0ebc0d2SYaroslav Tykhiy  * The reason for as many as two passes is that when doing IPSTEALTH,
1251d0ebc0d2SYaroslav Tykhiy  * non-routing options should be processed only if the packet is for us.
1252df8bae1dSRodney W. Grimes  * Returns 1 if packet has been forwarded/freed,
1253df8bae1dSRodney W. Grimes  * 0 if the packet should be processed further.
1254df8bae1dSRodney W. Grimes  */
12550312fbe9SPoul-Henning Kamp static int
12569b932e9eSAndre Oppermann ip_dooptions(struct mbuf *m, int pass)
1257df8bae1dSRodney W. Grimes {
12582b25acc1SLuigi Rizzo 	struct ip *ip = mtod(m, struct ip *);
12592b25acc1SLuigi Rizzo 	u_char *cp;
12602b25acc1SLuigi Rizzo 	struct in_ifaddr *ia;
1261df8bae1dSRodney W. Grimes 	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
1262df8bae1dSRodney W. Grimes 	struct in_addr *sin, dst;
1263df8bae1dSRodney W. Grimes 	n_time ntime;
12644d2e3692SLuigi Rizzo 	struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
1265df8bae1dSRodney W. Grimes 
12662bde81acSAndre Oppermann 	/* ignore or reject packets with IP options */
12672bde81acSAndre Oppermann 	if (ip_doopts == 0)
12682bde81acSAndre Oppermann 		return 0;
12692bde81acSAndre Oppermann 	else if (ip_doopts == 2) {
12702bde81acSAndre Oppermann 		type = ICMP_UNREACH;
12712bde81acSAndre Oppermann 		code = ICMP_UNREACH_FILTER_PROHIB;
12722bde81acSAndre Oppermann 		goto bad;
12732bde81acSAndre Oppermann 	}
12742bde81acSAndre Oppermann 
1275df8bae1dSRodney W. Grimes 	dst = ip->ip_dst;
1276df8bae1dSRodney W. Grimes 	cp = (u_char *)(ip + 1);
127753be11f6SPoul-Henning Kamp 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
1278df8bae1dSRodney W. Grimes 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
1279df8bae1dSRodney W. Grimes 		opt = cp[IPOPT_OPTVAL];
1280df8bae1dSRodney W. Grimes 		if (opt == IPOPT_EOL)
1281df8bae1dSRodney W. Grimes 			break;
1282df8bae1dSRodney W. Grimes 		if (opt == IPOPT_NOP)
1283df8bae1dSRodney W. Grimes 			optlen = 1;
1284df8bae1dSRodney W. Grimes 		else {
1285fdcb8debSJun-ichiro itojun Hagino 			if (cnt < IPOPT_OLEN + sizeof(*cp)) {
1286fdcb8debSJun-ichiro itojun Hagino 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1287fdcb8debSJun-ichiro itojun Hagino 				goto bad;
1288fdcb8debSJun-ichiro itojun Hagino 			}
1289df8bae1dSRodney W. Grimes 			optlen = cp[IPOPT_OLEN];
1290707d00a3SJonathan Lemon 			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
1291df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1292df8bae1dSRodney W. Grimes 				goto bad;
1293df8bae1dSRodney W. Grimes 			}
1294df8bae1dSRodney W. Grimes 		}
1295df8bae1dSRodney W. Grimes 		switch (opt) {
1296df8bae1dSRodney W. Grimes 
1297df8bae1dSRodney W. Grimes 		default:
1298df8bae1dSRodney W. Grimes 			break;
1299df8bae1dSRodney W. Grimes 
1300df8bae1dSRodney W. Grimes 		/*
1301df8bae1dSRodney W. Grimes 		 * Source routing with record.
1302df8bae1dSRodney W. Grimes 		 * Find interface with current destination address.
1303df8bae1dSRodney W. Grimes 		 * If none on this machine then drop if strictly routed,
1304df8bae1dSRodney W. Grimes 		 * or do nothing if loosely routed.
1305df8bae1dSRodney W. Grimes 		 * Record interface address and bring up next address
1306df8bae1dSRodney W. Grimes 		 * component.  If strictly routed make sure next
1307df8bae1dSRodney W. Grimes 		 * address is on directly accessible net.
1308df8bae1dSRodney W. Grimes 		 */
1309df8bae1dSRodney W. Grimes 		case IPOPT_LSRR:
1310df8bae1dSRodney W. Grimes 		case IPOPT_SSRR:
1311d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1312d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass > 0)
1313d0ebc0d2SYaroslav Tykhiy 				break;
1314d0ebc0d2SYaroslav Tykhiy #endif
131533841545SHajimu UMEMOTO 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
131633841545SHajimu UMEMOTO 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
131733841545SHajimu UMEMOTO 				goto bad;
131833841545SHajimu UMEMOTO 			}
1319df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1320df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1321df8bae1dSRodney W. Grimes 				goto bad;
1322df8bae1dSRodney W. Grimes 			}
1323df8bae1dSRodney W. Grimes 			ipaddr.sin_addr = ip->ip_dst;
1324df8bae1dSRodney W. Grimes 			ia = (struct in_ifaddr *)
1325df8bae1dSRodney W. Grimes 				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
13260b17fba7SAndre Oppermann 			if (ia == NULL) {
1327df8bae1dSRodney W. Grimes 				if (opt == IPOPT_SSRR) {
1328df8bae1dSRodney W. Grimes 					type = ICMP_UNREACH;
1329df8bae1dSRodney W. Grimes 					code = ICMP_UNREACH_SRCFAIL;
1330df8bae1dSRodney W. Grimes 					goto bad;
1331df8bae1dSRodney W. Grimes 				}
1332bc189bf8SGuido van Rooij 				if (!ip_dosourceroute)
1333bc189bf8SGuido van Rooij 					goto nosourcerouting;
1334df8bae1dSRodney W. Grimes 				/*
1335df8bae1dSRodney W. Grimes 				 * Loose routing, and not at next destination
1336df8bae1dSRodney W. Grimes 				 * yet; nothing to do except forward.
1337df8bae1dSRodney W. Grimes 				 */
1338df8bae1dSRodney W. Grimes 				break;
1339df8bae1dSRodney W. Grimes 			}
1340df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
13415d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr)) {
1342df8bae1dSRodney W. Grimes 				/*
1343df8bae1dSRodney W. Grimes 				 * End of source route.  Should be for us.
1344df8bae1dSRodney W. Grimes 				 */
13454fce5804SGuido van Rooij 				if (!ip_acceptsourceroute)
13464fce5804SGuido van Rooij 					goto nosourcerouting;
1347e0982661SAndre Oppermann 				save_rte(m, cp, ip->ip_src);
1348df8bae1dSRodney W. Grimes 				break;
1349df8bae1dSRodney W. Grimes 			}
1350d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1351d0ebc0d2SYaroslav Tykhiy 			if (ipstealth)
1352d0ebc0d2SYaroslav Tykhiy 				goto dropit;
1353d0ebc0d2SYaroslav Tykhiy #endif
13541025071fSGarrett Wollman 			if (!ip_dosourceroute) {
13550af8d3ecSDavid Greenman 				if (ipforwarding) {
13560af8d3ecSDavid Greenman 					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
13570af8d3ecSDavid Greenman 					/*
13580af8d3ecSDavid Greenman 					 * Acting as a router, so generate ICMP
13590af8d3ecSDavid Greenman 					 */
1360efa48587SGuido van Rooij nosourcerouting:
1361bc189bf8SGuido van Rooij 					strcpy(buf, inet_ntoa(ip->ip_dst));
13621025071fSGarrett Wollman 					log(LOG_WARNING,
13631025071fSGarrett Wollman 					    "attempted source route from %s to %s\n",
13641025071fSGarrett Wollman 					    inet_ntoa(ip->ip_src), buf);
13651025071fSGarrett Wollman 					type = ICMP_UNREACH;
13661025071fSGarrett Wollman 					code = ICMP_UNREACH_SRCFAIL;
13671025071fSGarrett Wollman 					goto bad;
13680af8d3ecSDavid Greenman 				} else {
13690af8d3ecSDavid Greenman 					/*
13700af8d3ecSDavid Greenman 					 * Not acting as a router, so silently drop.
13710af8d3ecSDavid Greenman 					 */
1372d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1373d0ebc0d2SYaroslav Tykhiy dropit:
1374d0ebc0d2SYaroslav Tykhiy #endif
13750af8d3ecSDavid Greenman 					ipstat.ips_cantforward++;
13760af8d3ecSDavid Greenman 					m_freem(m);
13770af8d3ecSDavid Greenman 					return (1);
13780af8d3ecSDavid Greenman 				}
13791025071fSGarrett Wollman 			}
13801025071fSGarrett Wollman 
1381df8bae1dSRodney W. Grimes 			/*
1382df8bae1dSRodney W. Grimes 			 * locate outgoing interface
1383df8bae1dSRodney W. Grimes 			 */
138494a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, cp + off,
1385df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
13861025071fSGarrett Wollman 
1387df8bae1dSRodney W. Grimes 			if (opt == IPOPT_SSRR) {
1388df8bae1dSRodney W. Grimes #define	INA	struct in_ifaddr *
1389df8bae1dSRodney W. Grimes #define	SA	struct sockaddr *
13900b17fba7SAndre Oppermann 			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == NULL)
1391df8bae1dSRodney W. Grimes 				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
1392df8bae1dSRodney W. Grimes 			} else
139302c1c707SAndre Oppermann 				ia = ip_rtaddr(ipaddr.sin_addr);
13940b17fba7SAndre Oppermann 			if (ia == NULL) {
1395df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1396df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_SRCFAIL;
1397df8bae1dSRodney W. Grimes 				goto bad;
1398df8bae1dSRodney W. Grimes 			}
1399df8bae1dSRodney W. Grimes 			ip->ip_dst = ipaddr.sin_addr;
140094a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
140194a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1402df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1403df8bae1dSRodney W. Grimes 			/*
1404df8bae1dSRodney W. Grimes 			 * Let ip_intr's mcast routing check handle mcast pkts
1405df8bae1dSRodney W. Grimes 			 */
1406df8bae1dSRodney W. Grimes 			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
1407df8bae1dSRodney W. Grimes 			break;
1408df8bae1dSRodney W. Grimes 
1409df8bae1dSRodney W. Grimes 		case IPOPT_RR:
1410d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1411d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass == 0)
1412d0ebc0d2SYaroslav Tykhiy 				break;
1413d0ebc0d2SYaroslav Tykhiy #endif
1414707d00a3SJonathan Lemon 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
1415707d00a3SJonathan Lemon 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1416707d00a3SJonathan Lemon 				goto bad;
1417707d00a3SJonathan Lemon 			}
1418df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1419df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1420df8bae1dSRodney W. Grimes 				goto bad;
1421df8bae1dSRodney W. Grimes 			}
1422df8bae1dSRodney W. Grimes 			/*
1423df8bae1dSRodney W. Grimes 			 * If no space remains, ignore.
1424df8bae1dSRodney W. Grimes 			 */
1425df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
14265d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr))
1427df8bae1dSRodney W. Grimes 				break;
142894a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
1429df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
1430df8bae1dSRodney W. Grimes 			/*
1431df8bae1dSRodney W. Grimes 			 * locate outgoing interface; if we're the destination,
1432df8bae1dSRodney W. Grimes 			 * use the incoming interface (should be same).
1433df8bae1dSRodney W. Grimes 			 */
14340b17fba7SAndre Oppermann 			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == NULL &&
14350b17fba7SAndre Oppermann 			    (ia = ip_rtaddr(ipaddr.sin_addr)) == NULL) {
1436df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1437df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_HOST;
1438df8bae1dSRodney W. Grimes 				goto bad;
1439df8bae1dSRodney W. Grimes 			}
144094a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
144194a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1442df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1443df8bae1dSRodney W. Grimes 			break;
1444df8bae1dSRodney W. Grimes 
1445df8bae1dSRodney W. Grimes 		case IPOPT_TS:
1446d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1447d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass == 0)
1448d0ebc0d2SYaroslav Tykhiy 				break;
1449d0ebc0d2SYaroslav Tykhiy #endif
1450df8bae1dSRodney W. Grimes 			code = cp - (u_char *)ip;
145107514071SJonathan Lemon 			if (optlen < 4 || optlen > 40) {
145207514071SJonathan Lemon 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1453df8bae1dSRodney W. Grimes 				goto bad;
145433841545SHajimu UMEMOTO 			}
145507514071SJonathan Lemon 			if ((off = cp[IPOPT_OFFSET]) < 5) {
145607514071SJonathan Lemon 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
145733841545SHajimu UMEMOTO 				goto bad;
145833841545SHajimu UMEMOTO 			}
145907514071SJonathan Lemon 			if (off > optlen - (int)sizeof(int32_t)) {
146007514071SJonathan Lemon 				cp[IPOPT_OFFSET + 1] += (1 << 4);
146107514071SJonathan Lemon 				if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) {
146207514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1463df8bae1dSRodney W. Grimes 					goto bad;
146433841545SHajimu UMEMOTO 				}
1465df8bae1dSRodney W. Grimes 				break;
1466df8bae1dSRodney W. Grimes 			}
146707514071SJonathan Lemon 			off--;				/* 0 origin */
146807514071SJonathan Lemon 			sin = (struct in_addr *)(cp + off);
146907514071SJonathan Lemon 			switch (cp[IPOPT_OFFSET + 1] & 0x0f) {
1470df8bae1dSRodney W. Grimes 
1471df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSONLY:
1472df8bae1dSRodney W. Grimes 				break;
1473df8bae1dSRodney W. Grimes 
1474df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSANDADDR:
147507514071SJonathan Lemon 				if (off + sizeof(n_time) +
147607514071SJonathan Lemon 				    sizeof(struct in_addr) > optlen) {
147707514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1478df8bae1dSRodney W. Grimes 					goto bad;
147933841545SHajimu UMEMOTO 				}
1480df8bae1dSRodney W. Grimes 				ipaddr.sin_addr = dst;
1481df8bae1dSRodney W. Grimes 				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
1482df8bae1dSRodney W. Grimes 							    m->m_pkthdr.rcvif);
14830b17fba7SAndre Oppermann 				if (ia == NULL)
1484df8bae1dSRodney W. Grimes 					continue;
148594a5d9b6SDavid Greenman 				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
148694a5d9b6SDavid Greenman 				    sizeof(struct in_addr));
148707514071SJonathan Lemon 				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1488a5428e3aSMaxim Konovalov 				off += sizeof(struct in_addr);
1489df8bae1dSRodney W. Grimes 				break;
1490df8bae1dSRodney W. Grimes 
1491df8bae1dSRodney W. Grimes 			case IPOPT_TS_PRESPEC:
149207514071SJonathan Lemon 				if (off + sizeof(n_time) +
149307514071SJonathan Lemon 				    sizeof(struct in_addr) > optlen) {
149407514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1495df8bae1dSRodney W. Grimes 					goto bad;
149633841545SHajimu UMEMOTO 				}
149794a5d9b6SDavid Greenman 				(void)memcpy(&ipaddr.sin_addr, sin,
1498df8bae1dSRodney W. Grimes 				    sizeof(struct in_addr));
14990b17fba7SAndre Oppermann 				if (ifa_ifwithaddr((SA)&ipaddr) == NULL)
1500df8bae1dSRodney W. Grimes 					continue;
150107514071SJonathan Lemon 				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1502a5428e3aSMaxim Konovalov 				off += sizeof(struct in_addr);
1503df8bae1dSRodney W. Grimes 				break;
1504df8bae1dSRodney W. Grimes 
1505df8bae1dSRodney W. Grimes 			default:
150607514071SJonathan Lemon 				code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip;
1507df8bae1dSRodney W. Grimes 				goto bad;
1508df8bae1dSRodney W. Grimes 			}
1509df8bae1dSRodney W. Grimes 			ntime = iptime();
151007514071SJonathan Lemon 			(void)memcpy(cp + off, &ntime, sizeof(n_time));
151107514071SJonathan Lemon 			cp[IPOPT_OFFSET] += sizeof(n_time);
1512df8bae1dSRodney W. Grimes 		}
1513df8bae1dSRodney W. Grimes 	}
151447174b49SAndrey A. Chernov 	if (forward && ipforwarding) {
15159b932e9eSAndre Oppermann 		ip_forward(m, 1);
1516df8bae1dSRodney W. Grimes 		return (1);
1517df8bae1dSRodney W. Grimes 	}
1518df8bae1dSRodney W. Grimes 	return (0);
1519df8bae1dSRodney W. Grimes bad:
1520df8bae1dSRodney W. Grimes 	icmp_error(m, type, code, 0, 0);
1521df8bae1dSRodney W. Grimes 	ipstat.ips_badoptions++;
1522df8bae1dSRodney W. Grimes 	return (1);
1523df8bae1dSRodney W. Grimes }
1524df8bae1dSRodney W. Grimes 
1525df8bae1dSRodney W. Grimes /*
1526df8bae1dSRodney W. Grimes  * Given address of next destination (final or next hop),
1527df8bae1dSRodney W. Grimes  * return internet address info of interface to be used to get there.
1528df8bae1dSRodney W. Grimes  */
1529bd714208SRuslan Ermilov struct in_ifaddr *
153002c1c707SAndre Oppermann ip_rtaddr(dst)
1531df8bae1dSRodney W. Grimes 	struct in_addr dst;
1532df8bae1dSRodney W. Grimes {
153397d8d152SAndre Oppermann 	struct route sro;
153402c1c707SAndre Oppermann 	struct sockaddr_in *sin;
153502c1c707SAndre Oppermann 	struct in_ifaddr *ifa;
1536df8bae1dSRodney W. Grimes 
15370cfbbe3bSAndre Oppermann 	bzero(&sro, sizeof(sro));
153897d8d152SAndre Oppermann 	sin = (struct sockaddr_in *)&sro.ro_dst;
1539df8bae1dSRodney W. Grimes 	sin->sin_family = AF_INET;
1540df8bae1dSRodney W. Grimes 	sin->sin_len = sizeof(*sin);
1541df8bae1dSRodney W. Grimes 	sin->sin_addr = dst;
154297d8d152SAndre Oppermann 	rtalloc_ign(&sro, RTF_CLONING);
1543df8bae1dSRodney W. Grimes 
154497d8d152SAndre Oppermann 	if (sro.ro_rt == NULL)
154502410549SRobert Watson 		return (NULL);
154602c1c707SAndre Oppermann 
154797d8d152SAndre Oppermann 	ifa = ifatoia(sro.ro_rt->rt_ifa);
154897d8d152SAndre Oppermann 	RTFREE(sro.ro_rt);
154902410549SRobert Watson 	return (ifa);
1550df8bae1dSRodney W. Grimes }
1551df8bae1dSRodney W. Grimes 
1552df8bae1dSRodney W. Grimes /*
1553df8bae1dSRodney W. Grimes  * Save incoming source route for use in replies,
1554df8bae1dSRodney W. Grimes  * to be picked up later by ip_srcroute if the receiver is interested.
1555df8bae1dSRodney W. Grimes  */
155637c84183SPoul-Henning Kamp static void
1557e0982661SAndre Oppermann save_rte(m, option, dst)
1558e0982661SAndre Oppermann 	struct mbuf *m;
1559df8bae1dSRodney W. Grimes 	u_char *option;
1560df8bae1dSRodney W. Grimes 	struct in_addr dst;
1561df8bae1dSRodney W. Grimes {
1562df8bae1dSRodney W. Grimes 	unsigned olen;
1563e0982661SAndre Oppermann 	struct ipopt_tag *opts;
1564e0982661SAndre Oppermann 
1565e0982661SAndre Oppermann 	opts = (struct ipopt_tag *)m_tag_get(PACKET_TAG_IPOPTIONS,
1566e0982661SAndre Oppermann 					sizeof(struct ipopt_tag), M_NOWAIT);
1567e0982661SAndre Oppermann 	if (opts == NULL)
1568e0982661SAndre Oppermann 		return;
1569df8bae1dSRodney W. Grimes 
1570df8bae1dSRodney W. Grimes 	olen = option[IPOPT_OLEN];
1571df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1572df8bae1dSRodney W. Grimes 	if (ipprintfs)
1573df8bae1dSRodney W. Grimes 		printf("save_rte: olen %d\n", olen);
1574df8bae1dSRodney W. Grimes #endif
15756a9909b5SSam Leffler 	if (olen > sizeof(opts->ip_srcrt) - (1 + sizeof(dst))) {
15766a9909b5SSam Leffler 		m_tag_free((struct m_tag *)opts);
1577df8bae1dSRodney W. Grimes 		return;
15786a9909b5SSam Leffler 	}
1579e0982661SAndre Oppermann 	bcopy(option, opts->ip_srcrt.srcopt, olen);
1580e0982661SAndre Oppermann 	opts->ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
1581e0982661SAndre Oppermann 	opts->ip_srcrt.dst = dst;
1582e0982661SAndre Oppermann 	m_tag_prepend(m, (struct m_tag *)opts);
1583df8bae1dSRodney W. Grimes }
1584df8bae1dSRodney W. Grimes 
1585df8bae1dSRodney W. Grimes /*
1586df8bae1dSRodney W. Grimes  * Retrieve incoming source route for use in replies,
1587df8bae1dSRodney W. Grimes  * in the same form used by setsockopt.
1588df8bae1dSRodney W. Grimes  * The first hop is placed before the options, will be removed later.
1589df8bae1dSRodney W. Grimes  */
1590df8bae1dSRodney W. Grimes struct mbuf *
1591e0982661SAndre Oppermann ip_srcroute(m0)
1592e0982661SAndre Oppermann 	struct mbuf *m0;
1593df8bae1dSRodney W. Grimes {
1594df8bae1dSRodney W. Grimes 	register struct in_addr *p, *q;
1595df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1596e0982661SAndre Oppermann 	struct ipopt_tag *opts;
1597df8bae1dSRodney W. Grimes 
1598e0982661SAndre Oppermann 	opts = (struct ipopt_tag *)m_tag_find(m0, PACKET_TAG_IPOPTIONS, NULL);
1599e0982661SAndre Oppermann 	if (opts == NULL)
160002410549SRobert Watson 		return (NULL);
1601e0982661SAndre Oppermann 
1602e0982661SAndre Oppermann 	if (opts->ip_nhops == 0)
160302410549SRobert Watson 		return (NULL);
1604a163d034SWarner Losh 	m = m_get(M_DONTWAIT, MT_HEADER);
16050b17fba7SAndre Oppermann 	if (m == NULL)
160602410549SRobert Watson 		return (NULL);
1607df8bae1dSRodney W. Grimes 
1608e0982661SAndre Oppermann #define OPTSIZ	(sizeof(opts->ip_srcrt.nop) + sizeof(opts->ip_srcrt.srcopt))
1609df8bae1dSRodney W. Grimes 
1610df8bae1dSRodney W. Grimes 	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
1611e0982661SAndre Oppermann 	m->m_len = opts->ip_nhops * sizeof(struct in_addr) +
1612e0982661SAndre Oppermann 	    sizeof(struct in_addr) + OPTSIZ;
1613df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1614df8bae1dSRodney W. Grimes 	if (ipprintfs)
1615e0982661SAndre Oppermann 		printf("ip_srcroute: nhops %d mlen %d", opts->ip_nhops, m->m_len);
1616df8bae1dSRodney W. Grimes #endif
1617df8bae1dSRodney W. Grimes 
1618df8bae1dSRodney W. Grimes 	/*
1619df8bae1dSRodney W. Grimes 	 * First save first hop for return route
1620df8bae1dSRodney W. Grimes 	 */
1621e0982661SAndre Oppermann 	p = &(opts->ip_srcrt.route[opts->ip_nhops - 1]);
1622df8bae1dSRodney W. Grimes 	*(mtod(m, struct in_addr *)) = *p--;
1623df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1624df8bae1dSRodney W. Grimes 	if (ipprintfs)
1625af38c68cSLuigi Rizzo 		printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
1626df8bae1dSRodney W. Grimes #endif
1627df8bae1dSRodney W. Grimes 
1628df8bae1dSRodney W. Grimes 	/*
1629df8bae1dSRodney W. Grimes 	 * Copy option fields and padding (nop) to mbuf.
1630df8bae1dSRodney W. Grimes 	 */
1631e0982661SAndre Oppermann 	opts->ip_srcrt.nop = IPOPT_NOP;
1632e0982661SAndre Oppermann 	opts->ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
163394a5d9b6SDavid Greenman 	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
1634e0982661SAndre Oppermann 	    &(opts->ip_srcrt.nop), OPTSIZ);
1635df8bae1dSRodney W. Grimes 	q = (struct in_addr *)(mtod(m, caddr_t) +
1636df8bae1dSRodney W. Grimes 	    sizeof(struct in_addr) + OPTSIZ);
1637df8bae1dSRodney W. Grimes #undef OPTSIZ
1638df8bae1dSRodney W. Grimes 	/*
1639df8bae1dSRodney W. Grimes 	 * Record return path as an IP source route,
1640df8bae1dSRodney W. Grimes 	 * reversing the path (pointers are now aligned).
1641df8bae1dSRodney W. Grimes 	 */
1642e0982661SAndre Oppermann 	while (p >= opts->ip_srcrt.route) {
1643df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1644df8bae1dSRodney W. Grimes 		if (ipprintfs)
1645af38c68cSLuigi Rizzo 			printf(" %lx", (u_long)ntohl(q->s_addr));
1646df8bae1dSRodney W. Grimes #endif
1647df8bae1dSRodney W. Grimes 		*q++ = *p--;
1648df8bae1dSRodney W. Grimes 	}
1649df8bae1dSRodney W. Grimes 	/*
1650df8bae1dSRodney W. Grimes 	 * Last hop goes to final destination.
1651df8bae1dSRodney W. Grimes 	 */
1652e0982661SAndre Oppermann 	*q = opts->ip_srcrt.dst;
1653df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1654df8bae1dSRodney W. Grimes 	if (ipprintfs)
1655af38c68cSLuigi Rizzo 		printf(" %lx\n", (u_long)ntohl(q->s_addr));
1656df8bae1dSRodney W. Grimes #endif
1657e0982661SAndre Oppermann 	m_tag_delete(m0, (struct m_tag *)opts);
1658df8bae1dSRodney W. Grimes 	return (m);
1659df8bae1dSRodney W. Grimes }
1660df8bae1dSRodney W. Grimes 
1661df8bae1dSRodney W. Grimes /*
1662df8bae1dSRodney W. Grimes  * Strip out IP options, at higher
1663df8bae1dSRodney W. Grimes  * level protocol in the kernel.
1664df8bae1dSRodney W. Grimes  * Second argument is buffer to which options
1665df8bae1dSRodney W. Grimes  * will be moved, and return value is their length.
1666df8bae1dSRodney W. Grimes  * XXX should be deleted; last arg currently ignored.
1667df8bae1dSRodney W. Grimes  */
1668df8bae1dSRodney W. Grimes void
1669df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt)
1670df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1671df8bae1dSRodney W. Grimes 	struct mbuf *mopt;
1672df8bae1dSRodney W. Grimes {
1673df8bae1dSRodney W. Grimes 	register int i;
1674df8bae1dSRodney W. Grimes 	struct ip *ip = mtod(m, struct ip *);
1675df8bae1dSRodney W. Grimes 	register caddr_t opts;
1676df8bae1dSRodney W. Grimes 	int olen;
1677df8bae1dSRodney W. Grimes 
167853be11f6SPoul-Henning Kamp 	olen = (ip->ip_hl << 2) - sizeof (struct ip);
1679df8bae1dSRodney W. Grimes 	opts = (caddr_t)(ip + 1);
1680df8bae1dSRodney W. Grimes 	i = m->m_len - (sizeof (struct ip) + olen);
1681df8bae1dSRodney W. Grimes 	bcopy(opts + olen, opts, (unsigned)i);
1682df8bae1dSRodney W. Grimes 	m->m_len -= olen;
1683df8bae1dSRodney W. Grimes 	if (m->m_flags & M_PKTHDR)
1684df8bae1dSRodney W. Grimes 		m->m_pkthdr.len -= olen;
168553be11f6SPoul-Henning Kamp 	ip->ip_v = IPVERSION;
168653be11f6SPoul-Henning Kamp 	ip->ip_hl = sizeof(struct ip) >> 2;
1687df8bae1dSRodney W. Grimes }
1688df8bae1dSRodney W. Grimes 
1689df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = {
1690df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
1691df8bae1dSRodney W. Grimes 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
1692df8bae1dSRodney W. Grimes 	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
1693df8bae1dSRodney W. Grimes 	EMSGSIZE,	EHOSTUNREACH,	0,		0,
1694fcaf9f91SMike Silbersack 	0,		0,		EHOSTUNREACH,	0,
16953b8123b7SJesper Skriver 	ENOPROTOOPT,	ECONNREFUSED
1696df8bae1dSRodney W. Grimes };
1697df8bae1dSRodney W. Grimes 
1698df8bae1dSRodney W. Grimes /*
1699df8bae1dSRodney W. Grimes  * Forward a packet.  If some error occurs return the sender
1700df8bae1dSRodney W. Grimes  * an icmp packet.  Note we can't always generate a meaningful
1701df8bae1dSRodney W. Grimes  * icmp message because icmp doesn't have a large enough repertoire
1702df8bae1dSRodney W. Grimes  * of codes and types.
1703df8bae1dSRodney W. Grimes  *
1704df8bae1dSRodney W. Grimes  * If not forwarding, just drop the packet.  This could be confusing
1705df8bae1dSRodney W. Grimes  * if ipforwarding was zero but some routing protocol was advancing
1706df8bae1dSRodney W. Grimes  * us as a gateway to somewhere.  However, we must let the routing
1707df8bae1dSRodney W. Grimes  * protocol deal with that.
1708df8bae1dSRodney W. Grimes  *
1709df8bae1dSRodney W. Grimes  * The srcrt parameter indicates whether the packet is being forwarded
1710df8bae1dSRodney W. Grimes  * via a source route.
1711df8bae1dSRodney W. Grimes  */
17129b932e9eSAndre Oppermann void
17139b932e9eSAndre Oppermann ip_forward(struct mbuf *m, int srcrt)
1714df8bae1dSRodney W. Grimes {
17152b25acc1SLuigi Rizzo 	struct ip *ip = mtod(m, struct ip *);
17169b932e9eSAndre Oppermann 	struct in_ifaddr *ia = NULL;
1717df8bae1dSRodney W. Grimes 	struct mbuf *mcopy;
17189b932e9eSAndre Oppermann 	struct in_addr dest;
1719c773494eSAndre Oppermann 	int error, type = 0, code = 0, mtu = 0;
17203efc3014SJulian Elischer 
1721df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1722df8bae1dSRodney W. Grimes 	if (ipprintfs)
172361ce519bSPoul-Henning Kamp 		printf("forward: src %lx dst %lx ttl %x\n",
17249b932e9eSAndre Oppermann 		    (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr,
1725162886e2SBruce Evans 		    ip->ip_ttl);
1726df8bae1dSRodney W. Grimes #endif
1727100ba1a6SJordan K. Hubbard 
1728100ba1a6SJordan K. Hubbard 
17299b932e9eSAndre Oppermann 	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
1730df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1731df8bae1dSRodney W. Grimes 		m_freem(m);
1732df8bae1dSRodney W. Grimes 		return;
1733df8bae1dSRodney W. Grimes 	}
17341b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
17351b968362SDag-Erling Smørgrav 	if (!ipstealth) {
17361b968362SDag-Erling Smørgrav #endif
1737df8bae1dSRodney W. Grimes 		if (ip->ip_ttl <= IPTTLDEC) {
17381b968362SDag-Erling Smørgrav 			icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
173902c1c707SAndre Oppermann 			    0, 0);
1740df8bae1dSRodney W. Grimes 			return;
1741df8bae1dSRodney W. Grimes 		}
17421b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
17431b968362SDag-Erling Smørgrav 	}
17441b968362SDag-Erling Smørgrav #endif
1745df8bae1dSRodney W. Grimes 
17469b932e9eSAndre Oppermann 	if (!srcrt && (ia = ip_rtaddr(ip->ip_dst)) == NULL) {
174702c1c707SAndre Oppermann 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
1748df8bae1dSRodney W. Grimes 		return;
174902c1c707SAndre Oppermann 	}
1750df8bae1dSRodney W. Grimes 
1751df8bae1dSRodney W. Grimes 	/*
1752bfef7ed4SIan Dowse 	 * Save the IP header and at most 8 bytes of the payload,
1753bfef7ed4SIan Dowse 	 * in case we need to generate an ICMP message to the src.
1754bfef7ed4SIan Dowse 	 *
17554d2e3692SLuigi Rizzo 	 * XXX this can be optimized a lot by saving the data in a local
17564d2e3692SLuigi Rizzo 	 * buffer on the stack (72 bytes at most), and only allocating the
17574d2e3692SLuigi Rizzo 	 * mbuf if really necessary. The vast majority of the packets
17584d2e3692SLuigi Rizzo 	 * are forwarded without having to send an ICMP back (either
17594d2e3692SLuigi Rizzo 	 * because unnecessary, or because rate limited), so we are
17604d2e3692SLuigi Rizzo 	 * really we are wasting a lot of work here.
17614d2e3692SLuigi Rizzo 	 *
1762bfef7ed4SIan Dowse 	 * We don't use m_copy() because it might return a reference
1763bfef7ed4SIan Dowse 	 * to a shared cluster. Both this function and ip_output()
1764bfef7ed4SIan Dowse 	 * assume exclusive access to the IP header in `m', so any
1765bfef7ed4SIan Dowse 	 * data in a cluster may change before we reach icmp_error().
1766df8bae1dSRodney W. Grimes 	 */
1767a163d034SWarner Losh 	MGET(mcopy, M_DONTWAIT, m->m_type);
1768a163d034SWarner Losh 	if (mcopy != NULL && !m_dup_pkthdr(mcopy, m, M_DONTWAIT)) {
17699967cafcSSam Leffler 		/*
17709967cafcSSam Leffler 		 * It's probably ok if the pkthdr dup fails (because
17719967cafcSSam Leffler 		 * the deep copy of the tag chain failed), but for now
17729967cafcSSam Leffler 		 * be conservative and just discard the copy since
17739967cafcSSam Leffler 		 * code below may some day want the tags.
17749967cafcSSam Leffler 		 */
17759967cafcSSam Leffler 		m_free(mcopy);
17769967cafcSSam Leffler 		mcopy = NULL;
17779967cafcSSam Leffler 	}
1778bfef7ed4SIan Dowse 	if (mcopy != NULL) {
177953be11f6SPoul-Henning Kamp 		mcopy->m_len = imin((ip->ip_hl << 2) + 8,
1780bfef7ed4SIan Dowse 		    (int)ip->ip_len);
1781e6b0a570SBruce M Simpson 		mcopy->m_pkthdr.len = mcopy->m_len;
1782bfef7ed4SIan Dowse 		m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
1783bfef7ed4SIan Dowse 	}
178404287599SRuslan Ermilov 
178504287599SRuslan Ermilov #ifdef IPSTEALTH
178604287599SRuslan Ermilov 	if (!ipstealth) {
178704287599SRuslan Ermilov #endif
178804287599SRuslan Ermilov 		ip->ip_ttl -= IPTTLDEC;
178904287599SRuslan Ermilov #ifdef IPSTEALTH
179004287599SRuslan Ermilov 	}
179104287599SRuslan Ermilov #endif
1792df8bae1dSRodney W. Grimes 
1793df8bae1dSRodney W. Grimes 	/*
1794df8bae1dSRodney W. Grimes 	 * If forwarding packet using same interface that it came in on,
1795df8bae1dSRodney W. Grimes 	 * perhaps should send a redirect to sender to shortcut a hop.
1796df8bae1dSRodney W. Grimes 	 * Only send redirect if source is sending directly to us,
1797df8bae1dSRodney W. Grimes 	 * and if packet was not source routed (or has any options).
1798df8bae1dSRodney W. Grimes 	 * Also, don't send redirect if forwarding using a default route
1799df8bae1dSRodney W. Grimes 	 * or a route modified by a redirect.
1800df8bae1dSRodney W. Grimes 	 */
18019b932e9eSAndre Oppermann 	dest.s_addr = 0;
18029b932e9eSAndre Oppermann 	if (!srcrt && ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) {
180302c1c707SAndre Oppermann 		struct sockaddr_in *sin;
180402c1c707SAndre Oppermann 		struct route ro;
180502c1c707SAndre Oppermann 		struct rtentry *rt;
180602c1c707SAndre Oppermann 
18070cfbbe3bSAndre Oppermann 		bzero(&ro, sizeof(ro));
180802c1c707SAndre Oppermann 		sin = (struct sockaddr_in *)&ro.ro_dst;
180902c1c707SAndre Oppermann 		sin->sin_family = AF_INET;
181002c1c707SAndre Oppermann 		sin->sin_len = sizeof(*sin);
18119b932e9eSAndre Oppermann 		sin->sin_addr = ip->ip_dst;
181226d02ca7SAndre Oppermann 		rtalloc_ign(&ro, RTF_CLONING);
181302c1c707SAndre Oppermann 
181402c1c707SAndre Oppermann 		rt = ro.ro_rt;
181502c1c707SAndre Oppermann 
181602c1c707SAndre Oppermann 		if (rt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
18179b932e9eSAndre Oppermann 		    satosin(rt_key(rt))->sin_addr.s_addr != 0) {
1818df8bae1dSRodney W. Grimes #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
1819df8bae1dSRodney W. Grimes 			u_long src = ntohl(ip->ip_src.s_addr);
1820df8bae1dSRodney W. Grimes 
1821df8bae1dSRodney W. Grimes 			if (RTA(rt) &&
1822df8bae1dSRodney W. Grimes 			    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1823df8bae1dSRodney W. Grimes 				if (rt->rt_flags & RTF_GATEWAY)
18249b932e9eSAndre Oppermann 					dest.s_addr = satosin(rt->rt_gateway)->sin_addr.s_addr;
1825df8bae1dSRodney W. Grimes 				else
18269b932e9eSAndre Oppermann 					dest.s_addr = ip->ip_dst.s_addr;
1827df8bae1dSRodney W. Grimes 				/* Router requirements says to only send host redirects */
1828df8bae1dSRodney W. Grimes 				type = ICMP_REDIRECT;
1829df8bae1dSRodney W. Grimes 				code = ICMP_REDIRECT_HOST;
1830df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1831df8bae1dSRodney W. Grimes 				if (ipprintfs)
18329b932e9eSAndre Oppermann 					printf("redirect (%d) to %lx\n", code, (u_long)dest.s_addr);
1833df8bae1dSRodney W. Grimes #endif
1834df8bae1dSRodney W. Grimes 			}
1835df8bae1dSRodney W. Grimes 		}
183602c1c707SAndre Oppermann 		if (rt)
183702c1c707SAndre Oppermann 			RTFREE(rt);
183802c1c707SAndre Oppermann 	}
1839df8bae1dSRodney W. Grimes 
184002410549SRobert Watson 	error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
1841df8bae1dSRodney W. Grimes 	if (error)
1842df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1843df8bae1dSRodney W. Grimes 	else {
1844df8bae1dSRodney W. Grimes 		ipstat.ips_forward++;
1845df8bae1dSRodney W. Grimes 		if (type)
1846df8bae1dSRodney W. Grimes 			ipstat.ips_redirectsent++;
1847df8bae1dSRodney W. Grimes 		else {
18489188b4a1SAndre Oppermann 			if (mcopy)
1849df8bae1dSRodney W. Grimes 				m_freem(mcopy);
1850df8bae1dSRodney W. Grimes 			return;
1851df8bae1dSRodney W. Grimes 		}
1852df8bae1dSRodney W. Grimes 	}
1853df8bae1dSRodney W. Grimes 	if (mcopy == NULL)
1854df8bae1dSRodney W. Grimes 		return;
1855df8bae1dSRodney W. Grimes 
1856df8bae1dSRodney W. Grimes 	switch (error) {
1857df8bae1dSRodney W. Grimes 
1858df8bae1dSRodney W. Grimes 	case 0:				/* forwarded, but need redirect */
1859df8bae1dSRodney W. Grimes 		/* type, code set above */
1860df8bae1dSRodney W. Grimes 		break;
1861df8bae1dSRodney W. Grimes 
1862df8bae1dSRodney W. Grimes 	case ENETUNREACH:		/* shouldn't happen, checked above */
1863df8bae1dSRodney W. Grimes 	case EHOSTUNREACH:
1864df8bae1dSRodney W. Grimes 	case ENETDOWN:
1865df8bae1dSRodney W. Grimes 	case EHOSTDOWN:
1866df8bae1dSRodney W. Grimes 	default:
1867df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1868df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_HOST;
1869df8bae1dSRodney W. Grimes 		break;
1870df8bae1dSRodney W. Grimes 
1871df8bae1dSRodney W. Grimes 	case EMSGSIZE:
1872df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1873df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_NEEDFRAG;
187402c1c707SAndre Oppermann #if defined(IPSEC) || defined(FAST_IPSEC)
18756a800098SYoshinobu Inoue 		/*
18766a800098SYoshinobu Inoue 		 * If the packet is routed over IPsec tunnel, tell the
18776a800098SYoshinobu Inoue 		 * originator the tunnel MTU.
18786a800098SYoshinobu Inoue 		 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
18796a800098SYoshinobu Inoue 		 * XXX quickhack!!!
18806a800098SYoshinobu Inoue 		 */
188102c1c707SAndre Oppermann 		{
18826a800098SYoshinobu Inoue 			struct secpolicy *sp = NULL;
18836a800098SYoshinobu Inoue 			int ipsecerror;
18846a800098SYoshinobu Inoue 			int ipsechdr;
188502c1c707SAndre Oppermann 			struct route *ro;
18866a800098SYoshinobu Inoue 
188702c1c707SAndre Oppermann #ifdef IPSEC
18886a800098SYoshinobu Inoue 			sp = ipsec4_getpolicybyaddr(mcopy,
18896a800098SYoshinobu Inoue 						    IPSEC_DIR_OUTBOUND,
18906a800098SYoshinobu Inoue 						    IP_FORWARDING,
18916a800098SYoshinobu Inoue 						    &ipsecerror);
189202c1c707SAndre Oppermann #else /* FAST_IPSEC */
1893b9234fafSSam Leffler 			sp = ipsec_getpolicybyaddr(mcopy,
1894b9234fafSSam Leffler 						   IPSEC_DIR_OUTBOUND,
1895b9234fafSSam Leffler 						   IP_FORWARDING,
1896b9234fafSSam Leffler 						   &ipsecerror);
189702c1c707SAndre Oppermann #endif
189802c1c707SAndre Oppermann 			if (sp != NULL) {
1899b9234fafSSam Leffler 				/* count IPsec header size */
1900b9234fafSSam Leffler 				ipsechdr = ipsec4_hdrsiz(mcopy,
1901b9234fafSSam Leffler 							 IPSEC_DIR_OUTBOUND,
1902b9234fafSSam Leffler 							 NULL);
1903b9234fafSSam Leffler 
1904b9234fafSSam Leffler 				/*
1905b9234fafSSam Leffler 				 * find the correct route for outer IPv4
1906b9234fafSSam Leffler 				 * header, compute tunnel MTU.
1907b9234fafSSam Leffler 				 */
1908b9234fafSSam Leffler 				if (sp->req != NULL
1909b9234fafSSam Leffler 				 && sp->req->sav != NULL
1910b9234fafSSam Leffler 				 && sp->req->sav->sah != NULL) {
191102c1c707SAndre Oppermann 					ro = &sp->req->sav->sah->sa_route;
191202c1c707SAndre Oppermann 					if (ro->ro_rt && ro->ro_rt->rt_ifp) {
1913c773494eSAndre Oppermann 						mtu =
191457ab3660SBruce M Simpson 						    ro->ro_rt->rt_rmx.rmx_mtu ?
191557ab3660SBruce M Simpson 						    ro->ro_rt->rt_rmx.rmx_mtu :
191602c1c707SAndre Oppermann 						    ro->ro_rt->rt_ifp->if_mtu;
1917c773494eSAndre Oppermann 						mtu -= ipsechdr;
1918b9234fafSSam Leffler 					}
1919b9234fafSSam Leffler 				}
1920b9234fafSSam Leffler 
192102c1c707SAndre Oppermann #ifdef IPSEC
192202c1c707SAndre Oppermann 				key_freesp(sp);
192302c1c707SAndre Oppermann #else /* FAST_IPSEC */
1924b9234fafSSam Leffler 				KEY_FREESP(&sp);
192502c1c707SAndre Oppermann #endif
192602c1c707SAndre Oppermann 				ipstat.ips_cantfrag++;
192702c1c707SAndre Oppermann 				break;
192802c1c707SAndre Oppermann 			} else
192902c1c707SAndre Oppermann #endif /*IPSEC || FAST_IPSEC*/
19309b932e9eSAndre Oppermann 		/*
19319b932e9eSAndre Oppermann 		 * When doing source routing 'ia' can be NULL.  Fall back
19329b932e9eSAndre Oppermann 		 * to the minimum guaranteed routeable packet size and use
19339b932e9eSAndre Oppermann 		 * the same hack as IPSEC to setup a dummyifp for icmp.
19349b932e9eSAndre Oppermann 		 */
1935c773494eSAndre Oppermann 		if (ia == NULL)
1936c773494eSAndre Oppermann 			mtu = IP_MSS;
1937c773494eSAndre Oppermann 		else
1938c773494eSAndre Oppermann 			mtu = ia->ia_ifp->if_mtu;
193902c1c707SAndre Oppermann #if defined(IPSEC) || defined(FAST_IPSEC)
1940b9234fafSSam Leffler 		}
194102c1c707SAndre Oppermann #endif /*IPSEC || FAST_IPSEC*/
1942df8bae1dSRodney W. Grimes 		ipstat.ips_cantfrag++;
1943df8bae1dSRodney W. Grimes 		break;
1944df8bae1dSRodney W. Grimes 
1945df8bae1dSRodney W. Grimes 	case ENOBUFS:
1946df285b3dSMike Silbersack 		/*
1947df285b3dSMike Silbersack 		 * A router should not generate ICMP_SOURCEQUENCH as
1948df285b3dSMike Silbersack 		 * required in RFC1812 Requirements for IP Version 4 Routers.
1949df285b3dSMike Silbersack 		 * Source quench could be a big problem under DoS attacks,
1950df285b3dSMike Silbersack 		 * or if the underlying interface is rate-limited.
1951df285b3dSMike Silbersack 		 * Those who need source quench packets may re-enable them
1952df285b3dSMike Silbersack 		 * via the net.inet.ip.sendsourcequench sysctl.
1953df285b3dSMike Silbersack 		 */
1954df285b3dSMike Silbersack 		if (ip_sendsourcequench == 0) {
1955df285b3dSMike Silbersack 			m_freem(mcopy);
1956df285b3dSMike Silbersack 			return;
1957df285b3dSMike Silbersack 		} else {
1958df8bae1dSRodney W. Grimes 			type = ICMP_SOURCEQUENCH;
1959df8bae1dSRodney W. Grimes 			code = 0;
1960df285b3dSMike Silbersack 		}
1961df8bae1dSRodney W. Grimes 		break;
19623a06e3e0SRuslan Ermilov 
19633a06e3e0SRuslan Ermilov 	case EACCES:			/* ipfw denied packet */
19643a06e3e0SRuslan Ermilov 		m_freem(mcopy);
19653a06e3e0SRuslan Ermilov 		return;
1966df8bae1dSRodney W. Grimes 	}
1967c773494eSAndre Oppermann 	icmp_error(mcopy, type, code, dest.s_addr, mtu);
1968df8bae1dSRodney W. Grimes }
1969df8bae1dSRodney W. Grimes 
197082c23ebaSBill Fenner void
197182c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m)
197282c23ebaSBill Fenner 	register struct inpcb *inp;
197382c23ebaSBill Fenner 	register struct mbuf **mp;
197482c23ebaSBill Fenner 	register struct ip *ip;
197582c23ebaSBill Fenner 	register struct mbuf *m;
197682c23ebaSBill Fenner {
1977be8a62e8SPoul-Henning Kamp 	if (inp->inp_socket->so_options & (SO_BINTIME | SO_TIMESTAMP)) {
1978be8a62e8SPoul-Henning Kamp 		struct bintime bt;
1979be8a62e8SPoul-Henning Kamp 
1980be8a62e8SPoul-Henning Kamp 		bintime(&bt);
1981be8a62e8SPoul-Henning Kamp 		if (inp->inp_socket->so_options & SO_BINTIME) {
1982be8a62e8SPoul-Henning Kamp 			*mp = sbcreatecontrol((caddr_t) &bt, sizeof(bt),
1983be8a62e8SPoul-Henning Kamp 			SCM_BINTIME, SOL_SOCKET);
1984be8a62e8SPoul-Henning Kamp 			if (*mp)
1985be8a62e8SPoul-Henning Kamp 				mp = &(*mp)->m_next;
1986be8a62e8SPoul-Henning Kamp 		}
198782c23ebaSBill Fenner 		if (inp->inp_socket->so_options & SO_TIMESTAMP) {
198882c23ebaSBill Fenner 			struct timeval tv;
198982c23ebaSBill Fenner 
1990be8a62e8SPoul-Henning Kamp 			bintime2timeval(&bt, &tv);
199182c23ebaSBill Fenner 			*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
199282c23ebaSBill Fenner 				SCM_TIMESTAMP, SOL_SOCKET);
199382c23ebaSBill Fenner 			if (*mp)
199482c23ebaSBill Fenner 				mp = &(*mp)->m_next;
19954cc20ab1SSeigo Tanimura 		}
1996be8a62e8SPoul-Henning Kamp 	}
199782c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVDSTADDR) {
199882c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
199982c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
200082c23ebaSBill Fenner 		if (*mp)
200182c23ebaSBill Fenner 			mp = &(*mp)->m_next;
200282c23ebaSBill Fenner 	}
20034957466bSMatthew N. Dodd 	if (inp->inp_flags & INP_RECVTTL) {
20044957466bSMatthew N. Dodd 		*mp = sbcreatecontrol((caddr_t) &ip->ip_ttl,
20054957466bSMatthew N. Dodd 		    sizeof(u_char), IP_RECVTTL, IPPROTO_IP);
20064957466bSMatthew N. Dodd 		if (*mp)
20074957466bSMatthew N. Dodd 			mp = &(*mp)->m_next;
20084957466bSMatthew N. Dodd 	}
200982c23ebaSBill Fenner #ifdef notyet
201082c23ebaSBill Fenner 	/* XXX
201182c23ebaSBill Fenner 	 * Moving these out of udp_input() made them even more broken
201282c23ebaSBill Fenner 	 * than they already were.
201382c23ebaSBill Fenner 	 */
201482c23ebaSBill Fenner 	/* options were tossed already */
201582c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVOPTS) {
201682c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) opts_deleted_above,
201782c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
201882c23ebaSBill Fenner 		if (*mp)
201982c23ebaSBill Fenner 			mp = &(*mp)->m_next;
202082c23ebaSBill Fenner 	}
202182c23ebaSBill Fenner 	/* ip_srcroute doesn't do what we want here, need to fix */
202282c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVRETOPTS) {
2023e0982661SAndre Oppermann 		*mp = sbcreatecontrol((caddr_t) ip_srcroute(m),
202482c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
202582c23ebaSBill Fenner 		if (*mp)
202682c23ebaSBill Fenner 			mp = &(*mp)->m_next;
202782c23ebaSBill Fenner 	}
202882c23ebaSBill Fenner #endif
202982c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVIF) {
2030d314ad7bSJulian Elischer 		struct ifnet *ifp;
2031d314ad7bSJulian Elischer 		struct sdlbuf {
203282c23ebaSBill Fenner 			struct sockaddr_dl sdl;
2033d314ad7bSJulian Elischer 			u_char	pad[32];
2034d314ad7bSJulian Elischer 		} sdlbuf;
2035d314ad7bSJulian Elischer 		struct sockaddr_dl *sdp;
2036d314ad7bSJulian Elischer 		struct sockaddr_dl *sdl2 = &sdlbuf.sdl;
203782c23ebaSBill Fenner 
2038d314ad7bSJulian Elischer 		if (((ifp = m->m_pkthdr.rcvif))
2039d314ad7bSJulian Elischer 		&& ( ifp->if_index && (ifp->if_index <= if_index))) {
2040f9132cebSJonathan Lemon 			sdp = (struct sockaddr_dl *)
2041f9132cebSJonathan Lemon 			    (ifaddr_byindex(ifp->if_index)->ifa_addr);
2042d314ad7bSJulian Elischer 			/*
2043d314ad7bSJulian Elischer 			 * Change our mind and don't try copy.
2044d314ad7bSJulian Elischer 			 */
2045d314ad7bSJulian Elischer 			if ((sdp->sdl_family != AF_LINK)
2046d314ad7bSJulian Elischer 			|| (sdp->sdl_len > sizeof(sdlbuf))) {
2047d314ad7bSJulian Elischer 				goto makedummy;
2048d314ad7bSJulian Elischer 			}
2049d314ad7bSJulian Elischer 			bcopy(sdp, sdl2, sdp->sdl_len);
2050d314ad7bSJulian Elischer 		} else {
2051d314ad7bSJulian Elischer makedummy:
2052d314ad7bSJulian Elischer 			sdl2->sdl_len
2053d314ad7bSJulian Elischer 				= offsetof(struct sockaddr_dl, sdl_data[0]);
2054d314ad7bSJulian Elischer 			sdl2->sdl_family = AF_LINK;
2055d314ad7bSJulian Elischer 			sdl2->sdl_index = 0;
2056d314ad7bSJulian Elischer 			sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;
2057d314ad7bSJulian Elischer 		}
2058d314ad7bSJulian Elischer 		*mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,
205982c23ebaSBill Fenner 			IP_RECVIF, IPPROTO_IP);
206082c23ebaSBill Fenner 		if (*mp)
206182c23ebaSBill Fenner 			mp = &(*mp)->m_next;
206282c23ebaSBill Fenner 	}
206382c23ebaSBill Fenner }
206482c23ebaSBill Fenner 
20654d2e3692SLuigi Rizzo /*
20664d2e3692SLuigi Rizzo  * XXX these routines are called from the upper part of the kernel.
20674d2e3692SLuigi Rizzo  * They need to be locked when we remove Giant.
20684d2e3692SLuigi Rizzo  *
20694d2e3692SLuigi Rizzo  * They could also be moved to ip_mroute.c, since all the RSVP
20704d2e3692SLuigi Rizzo  *  handling is done there already.
20714d2e3692SLuigi Rizzo  */
20724d2e3692SLuigi Rizzo static int ip_rsvp_on;
20734d2e3692SLuigi Rizzo struct socket *ip_rsvpd;
2074df8bae1dSRodney W. Grimes int
2075f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so)
2076f0068c4aSGarrett Wollman {
2077f0068c4aSGarrett Wollman 	if (so->so_type != SOCK_RAW ||
2078f0068c4aSGarrett Wollman 	    so->so_proto->pr_protocol != IPPROTO_RSVP)
2079f0068c4aSGarrett Wollman 		return EOPNOTSUPP;
2080f0068c4aSGarrett Wollman 
2081f0068c4aSGarrett Wollman 	if (ip_rsvpd != NULL)
2082f0068c4aSGarrett Wollman 		return EADDRINUSE;
2083f0068c4aSGarrett Wollman 
2084f0068c4aSGarrett Wollman 	ip_rsvpd = so;
20851c5de19aSGarrett Wollman 	/*
20861c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-increment
20871c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
20881c5de19aSGarrett Wollman 	 */
20891c5de19aSGarrett Wollman 	if (!ip_rsvp_on) {
20901c5de19aSGarrett Wollman 		ip_rsvp_on = 1;
20911c5de19aSGarrett Wollman 		rsvp_on++;
20921c5de19aSGarrett Wollman 	}
2093f0068c4aSGarrett Wollman 
2094f0068c4aSGarrett Wollman 	return 0;
2095f0068c4aSGarrett Wollman }
2096f0068c4aSGarrett Wollman 
2097f0068c4aSGarrett Wollman int
2098f0068c4aSGarrett Wollman ip_rsvp_done(void)
2099f0068c4aSGarrett Wollman {
2100f0068c4aSGarrett Wollman 	ip_rsvpd = NULL;
21011c5de19aSGarrett Wollman 	/*
21021c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-decrement
21031c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
21041c5de19aSGarrett Wollman 	 */
21051c5de19aSGarrett Wollman 	if (ip_rsvp_on) {
21061c5de19aSGarrett Wollman 		ip_rsvp_on = 0;
21071c5de19aSGarrett Wollman 		rsvp_on--;
21081c5de19aSGarrett Wollman 	}
2109f0068c4aSGarrett Wollman 	return 0;
2110f0068c4aSGarrett Wollman }
2111bbb4330bSLuigi Rizzo 
2112bbb4330bSLuigi Rizzo void
2113bbb4330bSLuigi Rizzo rsvp_input(struct mbuf *m, int off)	/* XXX must fixup manually */
2114bbb4330bSLuigi Rizzo {
2115bbb4330bSLuigi Rizzo 	if (rsvp_input_p) { /* call the real one if loaded */
2116bbb4330bSLuigi Rizzo 		rsvp_input_p(m, off);
2117bbb4330bSLuigi Rizzo 		return;
2118bbb4330bSLuigi Rizzo 	}
2119bbb4330bSLuigi Rizzo 
2120bbb4330bSLuigi Rizzo 	/* Can still get packets with rsvp_on = 0 if there is a local member
2121bbb4330bSLuigi Rizzo 	 * of the group to which the RSVP packet is addressed.  But in this
2122bbb4330bSLuigi Rizzo 	 * case we want to throw the packet away.
2123bbb4330bSLuigi Rizzo 	 */
2124bbb4330bSLuigi Rizzo 
2125bbb4330bSLuigi Rizzo 	if (!rsvp_on) {
2126bbb4330bSLuigi Rizzo 		m_freem(m);
2127bbb4330bSLuigi Rizzo 		return;
2128bbb4330bSLuigi Rizzo 	}
2129bbb4330bSLuigi Rizzo 
2130bbb4330bSLuigi Rizzo 	if (ip_rsvpd != NULL) {
2131bbb4330bSLuigi Rizzo 		rip_input(m, off);
2132bbb4330bSLuigi Rizzo 		return;
2133bbb4330bSLuigi Rizzo 	}
2134bbb4330bSLuigi Rizzo 	/* Drop the packet */
2135bbb4330bSLuigi Rizzo 	m_freem(m);
2136bbb4330bSLuigi Rizzo }
2137