xref: /freebsd/sys/netinet/ip_input.c (revision bbb4330b6156ef2827cc03ff4aab7a0fe307683c)
1df8bae1dSRodney W. Grimes /*
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  * 3. All advertising materials mentioning features or use of this software
14df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
15df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
16df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
17df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  *
33df8bae1dSRodney W. Grimes  *	@(#)ip_input.c	8.2 (Berkeley) 1/4/94
34c3aac50fSPeter Wemm  * $FreeBSD$
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
37e4f4247aSEivind Eklund #include "opt_bootp.h"
3874a9466cSGary Palmer #include "opt_ipfw.h"
39b715f178SLuigi Rizzo #include "opt_ipdn.h"
40fbd1372aSJoerg Wunsch #include "opt_ipdivert.h"
411ee25934SPeter Wemm #include "opt_ipfilter.h"
4227108a15SDag-Erling Smørgrav #include "opt_ipstealth.h"
436a800098SYoshinobu Inoue #include "opt_ipsec.h"
4436b0360bSRobert Watson #include "opt_mac.h"
45c4ac87eaSDarren Reed #include "opt_pfil_hooks.h"
4664dddc18SKris Kennaway #include "opt_random_ip_id.h"
4774a9466cSGary Palmer 
48df8bae1dSRodney W. Grimes #include <sys/param.h>
49df8bae1dSRodney W. Grimes #include <sys/systm.h>
5036b0360bSRobert Watson #include <sys/mac.h>
51df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
52b715f178SLuigi Rizzo #include <sys/malloc.h>
53df8bae1dSRodney W. Grimes #include <sys/domain.h>
54df8bae1dSRodney W. Grimes #include <sys/protosw.h>
55df8bae1dSRodney W. Grimes #include <sys/socket.h>
56df8bae1dSRodney W. Grimes #include <sys/time.h>
57df8bae1dSRodney W. Grimes #include <sys/kernel.h>
581025071fSGarrett Wollman #include <sys/syslog.h>
59b5e8ce9fSBruce Evans #include <sys/sysctl.h>
60df8bae1dSRodney W. Grimes 
61c85540ddSAndrey A. Chernov #include <net/pfil.h>
62df8bae1dSRodney W. Grimes #include <net/if.h>
639494d596SBrooks Davis #include <net/if_types.h>
64d314ad7bSJulian Elischer #include <net/if_var.h>
6582c23ebaSBill Fenner #include <net/if_dl.h>
66df8bae1dSRodney W. Grimes #include <net/route.h>
67748e0b0aSGarrett Wollman #include <net/netisr.h>
68367d34f8SBrian Somers #include <net/intrq.h>
69df8bae1dSRodney W. Grimes 
70df8bae1dSRodney W. Grimes #include <netinet/in.h>
71df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
72b5e8ce9fSBruce Evans #include <netinet/in_var.h>
73df8bae1dSRodney W. Grimes #include <netinet/ip.h>
74df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h>
75df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
76df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h>
7758938916SGarrett Wollman #include <machine/in_cksum.h>
78df8bae1dSRodney W. Grimes 
79f0068c4aSGarrett Wollman #include <sys/socketvar.h>
806ddbf1e2SGary Palmer 
816ddbf1e2SGary Palmer #include <netinet/ip_fw.h>
82db69a05dSPaul Saab #include <netinet/ip_dummynet.h>
83db69a05dSPaul Saab 
846a800098SYoshinobu Inoue #ifdef IPSEC
856a800098SYoshinobu Inoue #include <netinet6/ipsec.h>
866a800098SYoshinobu Inoue #include <netkey/key.h>
876a800098SYoshinobu Inoue #endif
886a800098SYoshinobu Inoue 
89b9234fafSSam Leffler #ifdef FAST_IPSEC
90b9234fafSSam Leffler #include <netipsec/ipsec.h>
91b9234fafSSam Leffler #include <netipsec/key.h>
92b9234fafSSam Leffler #endif
93b9234fafSSam Leffler 
941c5de19aSGarrett Wollman int rsvp_on = 0;
95f0068c4aSGarrett Wollman 
961f91d8c5SDavid Greenman int	ipforwarding = 0;
970312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW,
983d177f46SBill Fumerola     &ipforwarding, 0, "Enable IP forwarding between interfaces");
990312fbe9SPoul-Henning Kamp 
100d4fb926cSGarrett Wollman static int	ipsendredirects = 1; /* XXX */
1010312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW,
1023d177f46SBill Fumerola     &ipsendredirects, 0, "Enable sending IP redirects");
1030312fbe9SPoul-Henning Kamp 
104df8bae1dSRodney W. Grimes int	ip_defttl = IPDEFTTL;
1050312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW,
1063d177f46SBill Fumerola     &ip_defttl, 0, "Maximum TTL on IP packets");
1070312fbe9SPoul-Henning Kamp 
1080312fbe9SPoul-Henning Kamp static int	ip_dosourceroute = 0;
1090312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
1103d177f46SBill Fumerola     &ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
1114fce5804SGuido van Rooij 
1124fce5804SGuido van Rooij static int	ip_acceptsourceroute = 0;
1134fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute,
1143d177f46SBill Fumerola     CTLFLAG_RW, &ip_acceptsourceroute, 0,
1153d177f46SBill Fumerola     "Enable accepting source routed IP packets");
1166a800098SYoshinobu Inoue 
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 
122690a6055SJesper Skriver static int	ip_nfragpackets = 0;
12396c2b042SJesper Skriver static int	ip_maxfragpackets;	/* initialized in ip_init() */
124690a6055SJesper Skriver SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW,
125690a6055SJesper Skriver 	&ip_maxfragpackets, 0,
126690a6055SJesper Skriver 	"Maximum number of IPv4 fragment reassembly queue entries");
127690a6055SJesper Skriver 
128823db0e9SDon Lewis /*
129823db0e9SDon Lewis  * XXX - Setting ip_checkinterface mostly implements the receive side of
130823db0e9SDon Lewis  * the Strong ES model described in RFC 1122, but since the routing table
131a8f12100SDon Lewis  * and transmit implementation do not implement the Strong ES model,
132823db0e9SDon Lewis  * setting this to 1 results in an odd hybrid.
1333f67c834SDon Lewis  *
134a8f12100SDon Lewis  * XXX - ip_checkinterface currently must be disabled if you use ipnat
135a8f12100SDon Lewis  * to translate the destination address to another local interface.
1363f67c834SDon Lewis  *
1373f67c834SDon Lewis  * XXX - ip_checkinterface must be disabled if you add IP aliases
1383f67c834SDon Lewis  * to the loopback interface instead of the interface where the
1393f67c834SDon Lewis  * packets for those addresses are received.
140823db0e9SDon Lewis  */
141b3e95d4eSJonathan Lemon static int	ip_checkinterface = 1;
142b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW,
143b3e95d4eSJonathan Lemon     &ip_checkinterface, 0, "Verify packet arrives on correct interface");
144b3e95d4eSJonathan Lemon 
145df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1460312fbe9SPoul-Henning Kamp static int	ipprintfs = 0;
147df8bae1dSRodney W. Grimes #endif
148df8bae1dSRodney W. Grimes 
149ca925d9cSJonathan Lemon static int	ipqmaxlen = IFQ_MAXLEN;
150ca925d9cSJonathan Lemon 
151df8bae1dSRodney W. Grimes extern	struct domain inetdomain;
152f0ffb944SJulian Elischer extern	struct protosw inetsw[];
153df8bae1dSRodney W. Grimes u_char	ip_protox[IPPROTO_MAX];
15459562606SGarrett Wollman struct	in_ifaddrhead in_ifaddrhead; 		/* first inet address */
155ca925d9cSJonathan Lemon struct	in_ifaddrhashhead *in_ifaddrhashtbl;	/* inet addr hash table  */
156ca925d9cSJonathan Lemon u_long 	in_ifaddrhmask;				/* mask for hash table */
157ca925d9cSJonathan Lemon 
158afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW,
1593d177f46SBill Fumerola     &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue");
1600312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
1613d177f46SBill Fumerola     &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue");
162df8bae1dSRodney W. Grimes 
163f23b4c91SGarrett Wollman struct ipstat ipstat;
164c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW,
1653d177f46SBill Fumerola     &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)");
166194a213eSAndrey A. Chernov 
167194a213eSAndrey A. Chernov /* Packet reassembly stuff */
168194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2      6
169194a213eSAndrey A. Chernov #define IPREASS_NHASH           (1 << IPREASS_NHASH_LOG2)
170194a213eSAndrey A. Chernov #define IPREASS_HMASK           (IPREASS_NHASH - 1)
171194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \
172831a80b0SMatthew Dillon 	(((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
173194a213eSAndrey A. Chernov 
174462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH];
175194a213eSAndrey A. Chernov static int    nipq = 0;         /* total # of reass queues */
176194a213eSAndrey A. Chernov static int    maxnipq;
177f23b4c91SGarrett Wollman 
1780312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU
1790312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
1803d177f46SBill Fumerola     &ip_mtu, 0, "Default MTU");
1810312fbe9SPoul-Henning Kamp #endif
1820312fbe9SPoul-Henning Kamp 
1831b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
1841b968362SDag-Erling Smørgrav static int	ipstealth = 0;
1851b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW,
1861b968362SDag-Erling Smørgrav     &ipstealth, 0, "");
1871b968362SDag-Erling Smørgrav #endif
1881b968362SDag-Erling Smørgrav 
189cfe8b629SGarrett Wollman 
19023bf9953SPoul-Henning Kamp /* Firewall hooks */
19123bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr;
1929fcc0795SLuigi Rizzo int fw_enable = 1 ;
193e7319babSPoul-Henning Kamp 
194db69a05dSPaul Saab /* Dummynet hooks */
195db69a05dSPaul Saab ip_dn_io_t *ip_dn_io_ptr;
196b715f178SLuigi Rizzo 
197afed1b49SDarren Reed 
198e7319babSPoul-Henning Kamp /*
1994d2e3692SLuigi Rizzo  * XXX this is ugly -- the following two global variables are
2004d2e3692SLuigi Rizzo  * used to store packet state while it travels through the stack.
2014d2e3692SLuigi Rizzo  * Note that the code even makes assumptions on the size and
2024d2e3692SLuigi Rizzo  * alignment of fields inside struct ip_srcrt so e.g. adding some
2034d2e3692SLuigi Rizzo  * fields will break the code. This needs to be fixed.
2044d2e3692SLuigi Rizzo  *
205df8bae1dSRodney W. Grimes  * We need to save the IP options in case a protocol wants to respond
206df8bae1dSRodney W. Grimes  * to an incoming packet over the same route if the packet got here
207df8bae1dSRodney W. Grimes  * using IP source routing.  This allows connection establishment and
208df8bae1dSRodney W. Grimes  * maintenance when the remote end is on a network that is not known
209df8bae1dSRodney W. Grimes  * to us.
210df8bae1dSRodney W. Grimes  */
2110312fbe9SPoul-Henning Kamp static int	ip_nhops = 0;
212df8bae1dSRodney W. Grimes static	struct ip_srcrt {
213df8bae1dSRodney W. Grimes 	struct	in_addr dst;			/* final destination */
214df8bae1dSRodney W. Grimes 	char	nop;				/* one NOP to align */
215df8bae1dSRodney W. Grimes 	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
216df8bae1dSRodney W. Grimes 	struct	in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
217df8bae1dSRodney W. Grimes } ip_srcrt;
218df8bae1dSRodney W. Grimes 
2194d77a549SAlfred Perlstein static void	save_rte(u_char *, struct in_addr);
2202b25acc1SLuigi Rizzo static int	ip_dooptions(struct mbuf *m, int,
2212b25acc1SLuigi Rizzo 			struct sockaddr_in *next_hop);
2222b25acc1SLuigi Rizzo static void	ip_forward(struct mbuf *m, int srcrt,
2232b25acc1SLuigi Rizzo 			struct sockaddr_in *next_hop);
2244d77a549SAlfred Perlstein static void	ip_freef(struct ipqhead *, struct ipq *);
2252b25acc1SLuigi Rizzo static struct	mbuf *ip_reass(struct mbuf *, struct ipqhead *,
2262b25acc1SLuigi Rizzo 		struct ipq *, u_int32_t *, u_int16_t *);
2274d77a549SAlfred Perlstein static void	ipintr(void);
2288948e4baSArchie Cobbs 
229df8bae1dSRodney W. Grimes /*
230df8bae1dSRodney W. Grimes  * IP initialization: fill in IP protocol switch table.
231df8bae1dSRodney W. Grimes  * All protocols not implemented in kernel go to raw IP protocol handler.
232df8bae1dSRodney W. Grimes  */
233df8bae1dSRodney W. Grimes void
234df8bae1dSRodney W. Grimes ip_init()
235df8bae1dSRodney W. Grimes {
236f0ffb944SJulian Elischer 	register struct protosw *pr;
237df8bae1dSRodney W. Grimes 	register int i;
238df8bae1dSRodney W. Grimes 
23959562606SGarrett Wollman 	TAILQ_INIT(&in_ifaddrhead);
240ca925d9cSJonathan Lemon 	in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask);
241f0ffb944SJulian Elischer 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
242df8bae1dSRodney W. Grimes 	if (pr == 0)
243df8bae1dSRodney W. Grimes 		panic("ip_init");
244df8bae1dSRodney W. Grimes 	for (i = 0; i < IPPROTO_MAX; i++)
245df8bae1dSRodney W. Grimes 		ip_protox[i] = pr - inetsw;
246f0ffb944SJulian Elischer 	for (pr = inetdomain.dom_protosw;
247f0ffb944SJulian Elischer 	    pr < inetdomain.dom_protoswNPROTOSW; pr++)
248df8bae1dSRodney W. Grimes 		if (pr->pr_domain->dom_family == PF_INET &&
249df8bae1dSRodney W. Grimes 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
250df8bae1dSRodney W. Grimes 			ip_protox[pr->pr_protocol] = pr - inetsw;
251194a213eSAndrey A. Chernov 
252194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++)
253462b86feSPoul-Henning Kamp 	    TAILQ_INIT(&ipq[i]);
254194a213eSAndrey A. Chernov 
255194a213eSAndrey A. Chernov 	maxnipq = nmbclusters / 4;
25696c2b042SJesper Skriver 	ip_maxfragpackets = nmbclusters / 4;
257194a213eSAndrey A. Chernov 
25864dddc18SKris Kennaway #ifndef RANDOM_IP_ID
259227ee8a1SPoul-Henning Kamp 	ip_id = time_second & 0xffff;
26064dddc18SKris Kennaway #endif
261df8bae1dSRodney W. Grimes 	ipintrq.ifq_maxlen = ipqmaxlen;
2626008862bSJohn Baldwin 	mtx_init(&ipintrq.ifq_mtx, "ip_inq", NULL, MTX_DEF);
263bedbd47eSMike Smith 	ipintrq_present = 1;
264242c5536SPeter Wemm 
265242c5536SPeter Wemm 	register_netisr(NETISR_IP, ipintr);
266df8bae1dSRodney W. Grimes }
267df8bae1dSRodney W. Grimes 
2684d2e3692SLuigi Rizzo /*
2694d2e3692SLuigi Rizzo  * XXX watch out this one. It is perhaps used as a cache for
2704d2e3692SLuigi Rizzo  * the most recently used route ? it is cleared in in_addroute()
2714d2e3692SLuigi Rizzo  * when a new route is successfully created.
2724d2e3692SLuigi Rizzo  */
2731e3d5af0SRuslan Ermilov struct	route ipforward_rt;
274df8bae1dSRodney W. Grimes 
275df8bae1dSRodney W. Grimes /*
276df8bae1dSRodney W. Grimes  * Ip input routine.  Checksum and byte swap header.  If fragmented
277df8bae1dSRodney W. Grimes  * try to reassemble.  Process options.  Pass to next level.
278df8bae1dSRodney W. Grimes  */
279c67b1d17SGarrett Wollman void
280c67b1d17SGarrett Wollman ip_input(struct mbuf *m)
281df8bae1dSRodney W. Grimes {
28223bf9953SPoul-Henning Kamp 	struct ip *ip;
28323bf9953SPoul-Henning Kamp 	struct ipq *fp;
2845da9f8faSJosef Karthauser 	struct in_ifaddr *ia = NULL;
285ca925d9cSJonathan Lemon 	struct ifaddr *ifa;
286823db0e9SDon Lewis 	int    i, hlen, checkif;
28747c861ecSBrian Somers 	u_short sum;
2887538a9a0SJonathan Lemon 	struct in_addr pkt_dst;
2898948e4baSArchie Cobbs 	u_int32_t divert_info = 0;		/* packet divert/tee info */
2902b25acc1SLuigi Rizzo 	struct ip_fw_args args;
291c4ac87eaSDarren Reed #ifdef PFIL_HOOKS
292c4ac87eaSDarren Reed 	struct packet_filter_hook *pfh;
293c4ac87eaSDarren Reed 	struct mbuf *m0;
294c4ac87eaSDarren Reed 	int rv;
295c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */
296b9234fafSSam Leffler #ifdef FAST_IPSEC
297b9234fafSSam Leffler 	struct m_tag *mtag;
298b9234fafSSam Leffler 	struct tdb_ident *tdbi;
299b9234fafSSam Leffler 	struct secpolicy *sp;
300b9234fafSSam Leffler 	int s, error;
301b9234fafSSam Leffler #endif /* FAST_IPSEC */
302b715f178SLuigi Rizzo 
3032b25acc1SLuigi Rizzo 	args.eh = NULL;
3042b25acc1SLuigi Rizzo 	args.oif = NULL;
3052b25acc1SLuigi Rizzo 	args.rule = NULL;
3062b25acc1SLuigi Rizzo 	args.divert_rule = 0;			/* divert cookie */
3072b25acc1SLuigi Rizzo 	args.next_hop = NULL;
3088948e4baSArchie Cobbs 
3092b25acc1SLuigi Rizzo 	/* Grab info from MT_TAG mbufs prepended to the chain.	*/
3102b25acc1SLuigi Rizzo 	for (; m && m->m_type == MT_TAG; m = m->m_next) {
3115d846453SSam Leffler 		switch(m->_m_tag_id) {
3122b25acc1SLuigi Rizzo 		default:
3132b25acc1SLuigi Rizzo 			printf("ip_input: unrecognised MT_TAG tag %d\n",
3145d846453SSam Leffler 			    m->_m_tag_id);
3152b25acc1SLuigi Rizzo 			break;
3162b25acc1SLuigi Rizzo 
3172b25acc1SLuigi Rizzo 		case PACKET_TAG_DUMMYNET:
3182b25acc1SLuigi Rizzo 			args.rule = ((struct dn_pkt *)m)->rule;
3192b25acc1SLuigi Rizzo 			break;
3202b25acc1SLuigi Rizzo 
3212b25acc1SLuigi Rizzo 		case PACKET_TAG_DIVERT:
3227627c6cbSMaxime Henrion 			args.divert_rule = (intptr_t)m->m_hdr.mh_data & 0xffff;
3232b25acc1SLuigi Rizzo 			break;
3242b25acc1SLuigi Rizzo 
3252b25acc1SLuigi Rizzo 		case PACKET_TAG_IPFORWARD:
3262b25acc1SLuigi Rizzo 			args.next_hop = (struct sockaddr_in *)m->m_hdr.mh_data;
3272b25acc1SLuigi Rizzo 			break;
3282b25acc1SLuigi Rizzo 		}
3292b25acc1SLuigi Rizzo 	}
330df8bae1dSRodney W. Grimes 
331db40007dSAndrew R. Reiter 	KASSERT(m != NULL && (m->m_flags & M_PKTHDR) != 0,
332db40007dSAndrew R. Reiter 	    ("ip_input: no HDR"));
333db40007dSAndrew R. Reiter 
3342b25acc1SLuigi Rizzo 	if (args.rule) {	/* dummynet already filtered us */
3352b25acc1SLuigi Rizzo 		ip = mtod(m, struct ip *);
33653be11f6SPoul-Henning Kamp 		hlen = ip->ip_hl << 2;
3372b25acc1SLuigi Rizzo 		goto iphack ;
3382b25acc1SLuigi Rizzo 	}
3392b25acc1SLuigi Rizzo 
340df8bae1dSRodney W. Grimes 	ipstat.ips_total++;
34158938916SGarrett Wollman 
34258938916SGarrett Wollman 	if (m->m_pkthdr.len < sizeof(struct ip))
34358938916SGarrett Wollman 		goto tooshort;
34458938916SGarrett Wollman 
345df8bae1dSRodney W. Grimes 	if (m->m_len < sizeof (struct ip) &&
346df8bae1dSRodney W. Grimes 	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
347df8bae1dSRodney W. Grimes 		ipstat.ips_toosmall++;
348c67b1d17SGarrett Wollman 		return;
349df8bae1dSRodney W. Grimes 	}
350df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
35158938916SGarrett Wollman 
35253be11f6SPoul-Henning Kamp 	if (ip->ip_v != IPVERSION) {
353df8bae1dSRodney W. Grimes 		ipstat.ips_badvers++;
354df8bae1dSRodney W. Grimes 		goto bad;
355df8bae1dSRodney W. Grimes 	}
35658938916SGarrett Wollman 
35753be11f6SPoul-Henning Kamp 	hlen = ip->ip_hl << 2;
358df8bae1dSRodney W. Grimes 	if (hlen < sizeof(struct ip)) {	/* minimum header length */
359df8bae1dSRodney W. Grimes 		ipstat.ips_badhlen++;
360df8bae1dSRodney W. Grimes 		goto bad;
361df8bae1dSRodney W. Grimes 	}
362df8bae1dSRodney W. Grimes 	if (hlen > m->m_len) {
363df8bae1dSRodney W. Grimes 		if ((m = m_pullup(m, hlen)) == 0) {
364df8bae1dSRodney W. Grimes 			ipstat.ips_badhlen++;
365c67b1d17SGarrett Wollman 			return;
366df8bae1dSRodney W. Grimes 		}
367df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
368df8bae1dSRodney W. Grimes 	}
36933841545SHajimu UMEMOTO 
37033841545SHajimu UMEMOTO 	/* 127/8 must not appear on wire - RFC1122 */
37133841545SHajimu UMEMOTO 	if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
37233841545SHajimu UMEMOTO 	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
37333841545SHajimu UMEMOTO 		if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
37433841545SHajimu UMEMOTO 			ipstat.ips_badaddr++;
37533841545SHajimu UMEMOTO 			goto bad;
37633841545SHajimu UMEMOTO 		}
37733841545SHajimu UMEMOTO 	}
37833841545SHajimu UMEMOTO 
379db4f9cc7SJonathan Lemon 	if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
380db4f9cc7SJonathan Lemon 		sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
381db4f9cc7SJonathan Lemon 	} else {
38258938916SGarrett Wollman 		if (hlen == sizeof(struct ip)) {
38347c861ecSBrian Somers 			sum = in_cksum_hdr(ip);
38458938916SGarrett Wollman 		} else {
38547c861ecSBrian Somers 			sum = in_cksum(m, hlen);
38658938916SGarrett Wollman 		}
387db4f9cc7SJonathan Lemon 	}
38847c861ecSBrian Somers 	if (sum) {
389df8bae1dSRodney W. Grimes 		ipstat.ips_badsum++;
390df8bae1dSRodney W. Grimes 		goto bad;
391df8bae1dSRodney W. Grimes 	}
392df8bae1dSRodney W. Grimes 
393df8bae1dSRodney W. Grimes 	/*
394df8bae1dSRodney W. Grimes 	 * Convert fields to host representation.
395df8bae1dSRodney W. Grimes 	 */
396fd8e4ebcSMike Barcroft 	ip->ip_len = ntohs(ip->ip_len);
397df8bae1dSRodney W. Grimes 	if (ip->ip_len < hlen) {
398df8bae1dSRodney W. Grimes 		ipstat.ips_badlen++;
399df8bae1dSRodney W. Grimes 		goto bad;
400df8bae1dSRodney W. Grimes 	}
401fd8e4ebcSMike Barcroft 	ip->ip_off = ntohs(ip->ip_off);
402df8bae1dSRodney W. Grimes 
403df8bae1dSRodney W. Grimes 	/*
404df8bae1dSRodney W. Grimes 	 * Check that the amount of data in the buffers
405df8bae1dSRodney W. Grimes 	 * is as at least much as the IP header would have us expect.
406df8bae1dSRodney W. Grimes 	 * Trim mbufs if longer than we expect.
407df8bae1dSRodney W. Grimes 	 * Drop packet if shorter than we expect.
408df8bae1dSRodney W. Grimes 	 */
409df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len < ip->ip_len) {
41058938916SGarrett Wollman tooshort:
411df8bae1dSRodney W. Grimes 		ipstat.ips_tooshort++;
412df8bae1dSRodney W. Grimes 		goto bad;
413df8bae1dSRodney W. Grimes 	}
414df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len > ip->ip_len) {
415df8bae1dSRodney W. Grimes 		if (m->m_len == m->m_pkthdr.len) {
416df8bae1dSRodney W. Grimes 			m->m_len = ip->ip_len;
417df8bae1dSRodney W. Grimes 			m->m_pkthdr.len = ip->ip_len;
418df8bae1dSRodney W. Grimes 		} else
419df8bae1dSRodney W. Grimes 			m_adj(m, ip->ip_len - m->m_pkthdr.len);
420df8bae1dSRodney W. Grimes 	}
4213f67c834SDon Lewis 
4224dd1662bSUgen J.S. Antsilevich 	/*
4234dd1662bSUgen J.S. Antsilevich 	 * IpHack's section.
4244dd1662bSUgen J.S. Antsilevich 	 * Right now when no processing on packet has done
4254dd1662bSUgen J.S. Antsilevich 	 * and it is still fresh out of network we do our black
4264dd1662bSUgen J.S. Antsilevich 	 * deals with it.
42793e0e116SJulian Elischer 	 * - Firewall: deny/allow/divert
428fed1c7e9SSøren Schmidt 	 * - Xlate: translate packet's addr/port (NAT).
429b715f178SLuigi Rizzo 	 * - Pipe: pass pkt through dummynet.
4304dd1662bSUgen J.S. Antsilevich 	 * - Wrap: fake packet's addr/port <unimpl.>
4314dd1662bSUgen J.S. Antsilevich 	 * - Encapsulate: put it in another IP and send out. <unimp.>
4324dd1662bSUgen J.S. Antsilevich  	 */
433b715f178SLuigi Rizzo 
434b715f178SLuigi Rizzo iphack:
435df8bae1dSRodney W. Grimes 
436c4ac87eaSDarren Reed #ifdef PFIL_HOOKS
437c4ac87eaSDarren Reed 	/*
438c4ac87eaSDarren Reed 	 * Run through list of hooks for input packets.  If there are any
439c4ac87eaSDarren Reed 	 * filters which require that additional packets in the flow are
440c4ac87eaSDarren Reed 	 * not fast-forwarded, they must clear the M_CANFASTFWD flag.
441c4ac87eaSDarren Reed 	 * Note that filters must _never_ set this flag, as another filter
442c4ac87eaSDarren Reed 	 * in the list may have previously cleared it.
443c4ac87eaSDarren Reed 	 */
444c4ac87eaSDarren Reed 	m0 = m;
445c4ac87eaSDarren Reed 	pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
446fc2ffbe6SPoul-Henning Kamp 	for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link))
447c4ac87eaSDarren Reed 		if (pfh->pfil_func) {
448c4ac87eaSDarren Reed 			rv = pfh->pfil_func(ip, hlen,
449c4ac87eaSDarren Reed 					    m->m_pkthdr.rcvif, 0, &m0);
450c4ac87eaSDarren Reed 			if (rv)
451beec8214SDarren Reed 				return;
452c4ac87eaSDarren Reed 			m = m0;
453c4ac87eaSDarren Reed 			if (m == NULL)
454c4ac87eaSDarren Reed 				return;
455c4ac87eaSDarren Reed 			ip = mtod(m, struct ip *);
456beec8214SDarren Reed 		}
457c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */
458c4ac87eaSDarren Reed 
4597b109fa4SLuigi Rizzo 	if (fw_enable && IPFW_LOADED) {
460f9e354dfSJulian Elischer 		/*
461f9e354dfSJulian Elischer 		 * If we've been forwarded from the output side, then
462f9e354dfSJulian Elischer 		 * skip the firewall a second time
463f9e354dfSJulian Elischer 		 */
4642b25acc1SLuigi Rizzo 		if (args.next_hop)
465f9e354dfSJulian Elischer 			goto ours;
4662b25acc1SLuigi Rizzo 
4672b25acc1SLuigi Rizzo 		args.m = m;
4682b25acc1SLuigi Rizzo 		i = ip_fw_chk_ptr(&args);
4692b25acc1SLuigi Rizzo 		m = args.m;
4702b25acc1SLuigi Rizzo 
471d60315beSLuigi Rizzo 		if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
472507b4b54SLuigi Rizzo 			if (m)
473507b4b54SLuigi Rizzo 				m_freem(m);
474b715f178SLuigi Rizzo 			return;
475507b4b54SLuigi Rizzo 		}
476d60315beSLuigi Rizzo 		ip = mtod(m, struct ip *); /* just in case m changed */
4772b25acc1SLuigi Rizzo 		if (i == 0 && args.next_hop == NULL)	/* common case */
478b715f178SLuigi Rizzo 			goto pass;
4797b109fa4SLuigi Rizzo                 if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {
4808948e4baSArchie Cobbs 			/* Send packet to the appropriate pipe */
4812b25acc1SLuigi Rizzo 			ip_dn_io_ptr(m, i&0xffff, DN_TO_IP_IN, &args);
482e4676ba6SJulian Elischer 			return;
48393e0e116SJulian Elischer 		}
484b715f178SLuigi Rizzo #ifdef IPDIVERT
4858948e4baSArchie Cobbs 		if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
4868948e4baSArchie Cobbs 			/* Divert or tee packet */
4878948e4baSArchie Cobbs 			divert_info = i;
488b715f178SLuigi Rizzo 			goto ours;
489b715f178SLuigi Rizzo 		}
490b715f178SLuigi Rizzo #endif
4912b25acc1SLuigi Rizzo 		if (i == 0 && args.next_hop != NULL)
492b715f178SLuigi Rizzo 			goto pass;
493b715f178SLuigi Rizzo 		/*
494b715f178SLuigi Rizzo 		 * if we get here, the packet must be dropped
495b715f178SLuigi Rizzo 		 */
496b715f178SLuigi Rizzo 		m_freem(m);
497b715f178SLuigi Rizzo 		return;
498b715f178SLuigi Rizzo 	}
499b715f178SLuigi Rizzo pass:
500100ba1a6SJordan K. Hubbard 
501df8bae1dSRodney W. Grimes 	/*
502df8bae1dSRodney W. Grimes 	 * Process options and, if not destined for us,
503df8bae1dSRodney W. Grimes 	 * ship it on.  ip_dooptions returns 1 when an
504df8bae1dSRodney W. Grimes 	 * error was detected (causing an icmp message
505df8bae1dSRodney W. Grimes 	 * to be sent and the original packet to be freed).
506df8bae1dSRodney W. Grimes 	 */
507df8bae1dSRodney W. Grimes 	ip_nhops = 0;		/* for source routed packets */
5082b25acc1SLuigi Rizzo 	if (hlen > sizeof (struct ip) && ip_dooptions(m, 0, args.next_hop))
509c67b1d17SGarrett Wollman 		return;
510df8bae1dSRodney W. Grimes 
511f0068c4aSGarrett Wollman         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
512f0068c4aSGarrett Wollman          * matter if it is destined to another node, or whether it is
513f0068c4aSGarrett Wollman          * a multicast one, RSVP wants it! and prevents it from being forwarded
514f0068c4aSGarrett Wollman          * anywhere else. Also checks if the rsvp daemon is running before
515f0068c4aSGarrett Wollman 	 * grabbing the packet.
516f0068c4aSGarrett Wollman          */
5171c5de19aSGarrett Wollman 	if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
518f0068c4aSGarrett Wollman 		goto ours;
519f0068c4aSGarrett Wollman 
520df8bae1dSRodney W. Grimes 	/*
521df8bae1dSRodney W. Grimes 	 * Check our list of addresses, to see if the packet is for us.
522cc766e04SGarrett Wollman 	 * If we don't have any addresses, assume any unicast packet
523cc766e04SGarrett Wollman 	 * we receive might be for us (and let the upper layers deal
524cc766e04SGarrett Wollman 	 * with it).
525df8bae1dSRodney W. Grimes 	 */
526cc766e04SGarrett Wollman 	if (TAILQ_EMPTY(&in_ifaddrhead) &&
527cc766e04SGarrett Wollman 	    (m->m_flags & (M_MCAST|M_BCAST)) == 0)
528cc766e04SGarrett Wollman 		goto ours;
529cc766e04SGarrett Wollman 
5307538a9a0SJonathan Lemon 	/*
5317538a9a0SJonathan Lemon 	 * Cache the destination address of the packet; this may be
5327538a9a0SJonathan Lemon 	 * changed by use of 'ipfw fwd'.
5337538a9a0SJonathan Lemon 	 */
5342b25acc1SLuigi Rizzo 	pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
5357538a9a0SJonathan Lemon 
536823db0e9SDon Lewis 	/*
537823db0e9SDon Lewis 	 * Enable a consistency check between the destination address
538823db0e9SDon Lewis 	 * and the arrival interface for a unicast packet (the RFC 1122
539823db0e9SDon Lewis 	 * strong ES model) if IP forwarding is disabled and the packet
540e15ae1b2SDon Lewis 	 * is not locally generated and the packet is not subject to
541e15ae1b2SDon Lewis 	 * 'ipfw fwd'.
5423f67c834SDon Lewis 	 *
5433f67c834SDon Lewis 	 * XXX - Checking also should be disabled if the destination
5443f67c834SDon Lewis 	 * address is ipnat'ed to a different interface.
5453f67c834SDon Lewis 	 *
546a8f12100SDon Lewis 	 * XXX - Checking is incompatible with IP aliases added
5473f67c834SDon Lewis 	 * to the loopback interface instead of the interface where
5483f67c834SDon Lewis 	 * the packets are received.
549823db0e9SDon Lewis 	 */
550823db0e9SDon Lewis 	checkif = ip_checkinterface && (ipforwarding == 0) &&
5519494d596SBrooks Davis 	    m->m_pkthdr.rcvif != NULL &&
552e15ae1b2SDon Lewis 	    ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
5532b25acc1SLuigi Rizzo 	    (args.next_hop == NULL);
554823db0e9SDon Lewis 
555ca925d9cSJonathan Lemon 	/*
556ca925d9cSJonathan Lemon 	 * Check for exact addresses in the hash bucket.
557ca925d9cSJonathan Lemon 	 */
558ca925d9cSJonathan Lemon 	LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
559f9e354dfSJulian Elischer 		/*
560823db0e9SDon Lewis 		 * If the address matches, verify that the packet
561823db0e9SDon Lewis 		 * arrived via the correct interface if checking is
562823db0e9SDon Lewis 		 * enabled.
563f9e354dfSJulian Elischer 		 */
564823db0e9SDon Lewis 		if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr &&
565823db0e9SDon Lewis 		    (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif))
566ed1ff184SJulian Elischer 			goto ours;
567ca925d9cSJonathan Lemon 	}
568823db0e9SDon Lewis 	/*
569ca925d9cSJonathan Lemon 	 * Check for broadcast addresses.
570ca925d9cSJonathan Lemon 	 *
571ca925d9cSJonathan Lemon 	 * Only accept broadcast packets that arrive via the matching
572ca925d9cSJonathan Lemon 	 * interface.  Reception of forwarded directed broadcasts would
573ca925d9cSJonathan Lemon 	 * be handled via ip_forward() and ether_output() with the loopback
574ca925d9cSJonathan Lemon 	 * into the stack for SIMPLEX interfaces handled by ether_output().
575823db0e9SDon Lewis 	 */
576ca925d9cSJonathan Lemon 	if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
577ca925d9cSJonathan Lemon 	        TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
578ca925d9cSJonathan Lemon 			if (ifa->ifa_addr->sa_family != AF_INET)
579ca925d9cSJonathan Lemon 				continue;
580ca925d9cSJonathan Lemon 			ia = ifatoia(ifa);
581df8bae1dSRodney W. Grimes 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
5827538a9a0SJonathan Lemon 			    pkt_dst.s_addr)
583df8bae1dSRodney W. Grimes 				goto ours;
5847538a9a0SJonathan Lemon 			if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr)
585df8bae1dSRodney W. Grimes 				goto ours;
586ca925d9cSJonathan Lemon #ifdef BOOTP_COMPAT
587ca925d9cSJonathan Lemon 			if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
588ca925d9cSJonathan Lemon 				goto ours;
589ca925d9cSJonathan Lemon #endif
590df8bae1dSRodney W. Grimes 		}
591df8bae1dSRodney W. Grimes 	}
592df8bae1dSRodney W. Grimes 	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
593df8bae1dSRodney W. Grimes 		struct in_multi *inm;
594df8bae1dSRodney W. Grimes 		if (ip_mrouter) {
595df8bae1dSRodney W. Grimes 			/*
596df8bae1dSRodney W. Grimes 			 * If we are acting as a multicast router, all
597df8bae1dSRodney W. Grimes 			 * incoming multicast packets are passed to the
598df8bae1dSRodney W. Grimes 			 * kernel-level multicast forwarding function.
599df8bae1dSRodney W. Grimes 			 * The packet is returned (relatively) intact; if
600df8bae1dSRodney W. Grimes 			 * ip_mforward() returns a non-zero value, the packet
601df8bae1dSRodney W. Grimes 			 * must be discarded, else it may be accepted below.
602df8bae1dSRodney W. Grimes 			 */
603bbb4330bSLuigi Rizzo 			if (ip_mforward &&
604bbb4330bSLuigi Rizzo 			    ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) {
605df8bae1dSRodney W. Grimes 				ipstat.ips_cantforward++;
606df8bae1dSRodney W. Grimes 				m_freem(m);
607c67b1d17SGarrett Wollman 				return;
608df8bae1dSRodney W. Grimes 			}
609df8bae1dSRodney W. Grimes 
610df8bae1dSRodney W. Grimes 			/*
61111612afaSDima Dorfman 			 * The process-level routing daemon needs to receive
612df8bae1dSRodney W. Grimes 			 * all multicast IGMP packets, whether or not this
613df8bae1dSRodney W. Grimes 			 * host belongs to their destination groups.
614df8bae1dSRodney W. Grimes 			 */
615df8bae1dSRodney W. Grimes 			if (ip->ip_p == IPPROTO_IGMP)
616df8bae1dSRodney W. Grimes 				goto ours;
617df8bae1dSRodney W. Grimes 			ipstat.ips_forward++;
618df8bae1dSRodney W. Grimes 		}
619df8bae1dSRodney W. Grimes 		/*
620df8bae1dSRodney W. Grimes 		 * See if we belong to the destination multicast group on the
621df8bae1dSRodney W. Grimes 		 * arrival interface.
622df8bae1dSRodney W. Grimes 		 */
623df8bae1dSRodney W. Grimes 		IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
624df8bae1dSRodney W. Grimes 		if (inm == NULL) {
62582c39223SGarrett Wollman 			ipstat.ips_notmember++;
626df8bae1dSRodney W. Grimes 			m_freem(m);
627c67b1d17SGarrett Wollman 			return;
628df8bae1dSRodney W. Grimes 		}
629df8bae1dSRodney W. Grimes 		goto ours;
630df8bae1dSRodney W. Grimes 	}
631df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
632df8bae1dSRodney W. Grimes 		goto ours;
633df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == INADDR_ANY)
634df8bae1dSRodney W. Grimes 		goto ours;
635df8bae1dSRodney W. Grimes 
6366a800098SYoshinobu Inoue 	/*
6376a800098SYoshinobu Inoue 	 * FAITH(Firewall Aided Internet Translator)
6386a800098SYoshinobu Inoue 	 */
6396a800098SYoshinobu Inoue 	if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
6406a800098SYoshinobu Inoue 		if (ip_keepfaith) {
6416a800098SYoshinobu Inoue 			if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP)
6426a800098SYoshinobu Inoue 				goto ours;
6436a800098SYoshinobu Inoue 		}
6446a800098SYoshinobu Inoue 		m_freem(m);
6456a800098SYoshinobu Inoue 		return;
6466a800098SYoshinobu Inoue 	}
6479494d596SBrooks Davis 
648df8bae1dSRodney W. Grimes 	/*
649df8bae1dSRodney W. Grimes 	 * Not for us; forward if possible and desirable.
650df8bae1dSRodney W. Grimes 	 */
651df8bae1dSRodney W. Grimes 	if (ipforwarding == 0) {
652df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
653df8bae1dSRodney W. Grimes 		m_freem(m);
654546f251bSChris D. Faulhaber 	} else {
655546f251bSChris D. Faulhaber #ifdef IPSEC
656546f251bSChris D. Faulhaber 		/*
657546f251bSChris D. Faulhaber 		 * Enforce inbound IPsec SPD.
658546f251bSChris D. Faulhaber 		 */
659546f251bSChris D. Faulhaber 		if (ipsec4_in_reject(m, NULL)) {
660546f251bSChris D. Faulhaber 			ipsecstat.in_polvio++;
661546f251bSChris D. Faulhaber 			goto bad;
662546f251bSChris D. Faulhaber 		}
663546f251bSChris D. Faulhaber #endif /* IPSEC */
664b9234fafSSam Leffler #ifdef FAST_IPSEC
665b9234fafSSam Leffler 		mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
666b9234fafSSam Leffler 		s = splnet();
667b9234fafSSam Leffler 		if (mtag != NULL) {
668b9234fafSSam Leffler 			tdbi = (struct tdb_ident *)(mtag + 1);
669b9234fafSSam Leffler 			sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
670b9234fafSSam Leffler 		} else {
671b9234fafSSam Leffler 			sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
672b9234fafSSam Leffler 						   IP_FORWARDING, &error);
673b9234fafSSam Leffler 		}
674b9234fafSSam Leffler 		if (sp == NULL) {	/* NB: can happen if error */
675b9234fafSSam Leffler 			splx(s);
676b9234fafSSam Leffler 			/*XXX error stat???*/
677b9234fafSSam Leffler 			DPRINTF(("ip_input: no SP for forwarding\n"));	/*XXX*/
678b9234fafSSam Leffler 			goto bad;
679b9234fafSSam Leffler 		}
680b9234fafSSam Leffler 
681b9234fafSSam Leffler 		/*
682b9234fafSSam Leffler 		 * Check security policy against packet attributes.
683b9234fafSSam Leffler 		 */
684b9234fafSSam Leffler 		error = ipsec_in_reject(sp, m);
685b9234fafSSam Leffler 		KEY_FREESP(&sp);
686b9234fafSSam Leffler 		splx(s);
687b9234fafSSam Leffler 		if (error) {
688b9234fafSSam Leffler 			ipstat.ips_cantforward++;
689b9234fafSSam Leffler 			goto bad;
690b9234fafSSam Leffler 		}
691b9234fafSSam Leffler #endif /* FAST_IPSEC */
6922b25acc1SLuigi Rizzo 		ip_forward(m, 0, args.next_hop);
693546f251bSChris D. Faulhaber 	}
694c67b1d17SGarrett Wollman 	return;
695df8bae1dSRodney W. Grimes 
696df8bae1dSRodney W. Grimes ours:
697d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
698d0ebc0d2SYaroslav Tykhiy 	/*
699d0ebc0d2SYaroslav Tykhiy 	 * IPSTEALTH: Process non-routing options only
700d0ebc0d2SYaroslav Tykhiy 	 * if the packet is destined for us.
701d0ebc0d2SYaroslav Tykhiy 	 */
7022b25acc1SLuigi Rizzo 	if (ipstealth && hlen > sizeof (struct ip) &&
7032b25acc1SLuigi Rizzo 	    ip_dooptions(m, 1, args.next_hop))
704d0ebc0d2SYaroslav Tykhiy 		return;
705d0ebc0d2SYaroslav Tykhiy #endif /* IPSTEALTH */
706d0ebc0d2SYaroslav Tykhiy 
7075da9f8faSJosef Karthauser 	/* Count the packet in the ip address stats */
7085da9f8faSJosef Karthauser 	if (ia != NULL) {
7095da9f8faSJosef Karthauser 		ia->ia_ifa.if_ipackets++;
7105da9f8faSJosef Karthauser 		ia->ia_ifa.if_ibytes += m->m_pkthdr.len;
7115da9f8faSJosef Karthauser 	}
712100ba1a6SJordan K. Hubbard 
71363f8d699SJordan K. Hubbard 	/*
714df8bae1dSRodney W. Grimes 	 * If offset or IP_MF are set, must reassemble.
715df8bae1dSRodney W. Grimes 	 * Otherwise, nothing need be done.
716df8bae1dSRodney W. Grimes 	 * (We could look in the reassembly queue to see
717df8bae1dSRodney W. Grimes 	 * if the packet was previously fragmented,
718df8bae1dSRodney W. Grimes 	 * but it's not worth the time; just let them time out.)
719df8bae1dSRodney W. Grimes 	 */
720b6ea1aa5SRuslan Ermilov 	if (ip->ip_off & (IP_MF | IP_OFFMASK)) {
7216a800098SYoshinobu Inoue 
722194a213eSAndrey A. Chernov 		sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
723df8bae1dSRodney W. Grimes 		/*
724df8bae1dSRodney W. Grimes 		 * Look for queue of fragments
725df8bae1dSRodney W. Grimes 		 * of this datagram.
726df8bae1dSRodney W. Grimes 		 */
727462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(fp, &ipq[sum], ipq_list)
728df8bae1dSRodney W. Grimes 			if (ip->ip_id == fp->ipq_id &&
729df8bae1dSRodney W. Grimes 			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
730df8bae1dSRodney W. Grimes 			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
73136b0360bSRobert Watson #ifdef MAC
73236b0360bSRobert Watson 			    mac_fragment_match(m, fp) &&
73336b0360bSRobert Watson #endif
734df8bae1dSRodney W. Grimes 			    ip->ip_p == fp->ipq_p)
735df8bae1dSRodney W. Grimes 				goto found;
736df8bae1dSRodney W. Grimes 
737194a213eSAndrey A. Chernov 		fp = 0;
738194a213eSAndrey A. Chernov 
739194a213eSAndrey A. Chernov 		/* check if there's a place for the new queue */
740194a213eSAndrey A. Chernov 		if (nipq > maxnipq) {
741194a213eSAndrey A. Chernov 		    /*
742194a213eSAndrey A. Chernov 		     * drop something from the tail of the current queue
743194a213eSAndrey A. Chernov 		     * before proceeding further
744194a213eSAndrey A. Chernov 		     */
745462b86feSPoul-Henning Kamp 		    struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead);
746462b86feSPoul-Henning Kamp 		    if (q == NULL) {   /* gak */
747194a213eSAndrey A. Chernov 			for (i = 0; i < IPREASS_NHASH; i++) {
748462b86feSPoul-Henning Kamp 			    struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead);
749462b86feSPoul-Henning Kamp 			    if (r) {
750462b86feSPoul-Henning Kamp 				ip_freef(&ipq[i], r);
751194a213eSAndrey A. Chernov 				break;
752194a213eSAndrey A. Chernov 			    }
753194a213eSAndrey A. Chernov 			}
754194a213eSAndrey A. Chernov 		    } else
755462b86feSPoul-Henning Kamp 			ip_freef(&ipq[sum], q);
756194a213eSAndrey A. Chernov 		}
757194a213eSAndrey A. Chernov found:
758df8bae1dSRodney W. Grimes 		/*
759df8bae1dSRodney W. Grimes 		 * Adjust ip_len to not reflect header,
760df8bae1dSRodney W. Grimes 		 * convert offset of this to bytes.
761df8bae1dSRodney W. Grimes 		 */
762df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
763b6ea1aa5SRuslan Ermilov 		if (ip->ip_off & IP_MF) {
7646effc713SDoug Rabson 		        /*
7656effc713SDoug Rabson 		         * Make sure that fragments have a data length
7666effc713SDoug Rabson 			 * that's a non-zero multiple of 8 bytes.
7676effc713SDoug Rabson 		         */
7686effc713SDoug Rabson 			if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
7696effc713SDoug Rabson 				ipstat.ips_toosmall++; /* XXX */
7706effc713SDoug Rabson 				goto bad;
7716effc713SDoug Rabson 			}
7726effc713SDoug Rabson 			m->m_flags |= M_FRAG;
7731cf43499SMaxim Konovalov 		} else
7741cf43499SMaxim Konovalov 			m->m_flags &= ~M_FRAG;
775df8bae1dSRodney W. Grimes 		ip->ip_off <<= 3;
776df8bae1dSRodney W. Grimes 
777df8bae1dSRodney W. Grimes 		/*
778b6ea1aa5SRuslan Ermilov 		 * Attempt reassembly; if it succeeds, proceed.
7792b25acc1SLuigi Rizzo 		 * ip_reass() will return a different mbuf, and update
7802b25acc1SLuigi Rizzo 		 * the divert info in divert_info and args.divert_rule.
781df8bae1dSRodney W. Grimes 		 */
782df8bae1dSRodney W. Grimes 		ipstat.ips_fragments++;
783487bdb38SRuslan Ermilov 		m->m_pkthdr.header = ip;
7846a800098SYoshinobu Inoue 		m = ip_reass(m,
7852b25acc1SLuigi Rizzo 		    &ipq[sum], fp, &divert_info, &args.divert_rule);
7862b25acc1SLuigi Rizzo 		if (m == 0)
787c67b1d17SGarrett Wollman 			return;
788df8bae1dSRodney W. Grimes 		ipstat.ips_reassembled++;
7896a800098SYoshinobu Inoue 		ip = mtod(m, struct ip *);
7907e2df452SRuslan Ermilov 		/* Get the header length of the reassembled packet */
79153be11f6SPoul-Henning Kamp 		hlen = ip->ip_hl << 2;
792af782f1cSBrian Somers #ifdef IPDIVERT
7938948e4baSArchie Cobbs 		/* Restore original checksum before diverting packet */
7948948e4baSArchie Cobbs 		if (divert_info != 0) {
795af782f1cSBrian Somers 			ip->ip_len += hlen;
796fd8e4ebcSMike Barcroft 			ip->ip_len = htons(ip->ip_len);
797fd8e4ebcSMike Barcroft 			ip->ip_off = htons(ip->ip_off);
798af782f1cSBrian Somers 			ip->ip_sum = 0;
79960123168SRuslan Ermilov 			if (hlen == sizeof(struct ip))
800af782f1cSBrian Somers 				ip->ip_sum = in_cksum_hdr(ip);
80160123168SRuslan Ermilov 			else
80260123168SRuslan Ermilov 				ip->ip_sum = in_cksum(m, hlen);
803fd8e4ebcSMike Barcroft 			ip->ip_off = ntohs(ip->ip_off);
804fd8e4ebcSMike Barcroft 			ip->ip_len = ntohs(ip->ip_len);
805af782f1cSBrian Somers 			ip->ip_len -= hlen;
806af782f1cSBrian Somers 		}
807af782f1cSBrian Somers #endif
808df8bae1dSRodney W. Grimes 	} else
809df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
810df8bae1dSRodney W. Grimes 
81193e0e116SJulian Elischer #ifdef IPDIVERT
81293e0e116SJulian Elischer 	/*
8138948e4baSArchie Cobbs 	 * Divert or tee packet to the divert protocol if required.
81493e0e116SJulian Elischer 	 */
8158948e4baSArchie Cobbs 	if (divert_info != 0) {
8168948e4baSArchie Cobbs 		struct mbuf *clone = NULL;
8178948e4baSArchie Cobbs 
8188948e4baSArchie Cobbs 		/* Clone packet if we're doing a 'tee' */
8198948e4baSArchie Cobbs 		if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
8208948e4baSArchie Cobbs 			clone = m_dup(m, M_DONTWAIT);
8218948e4baSArchie Cobbs 
8228948e4baSArchie Cobbs 		/* Restore packet header fields to original values */
8238948e4baSArchie Cobbs 		ip->ip_len += hlen;
824fd8e4ebcSMike Barcroft 		ip->ip_len = htons(ip->ip_len);
825fd8e4ebcSMike Barcroft 		ip->ip_off = htons(ip->ip_off);
8268948e4baSArchie Cobbs 
8278948e4baSArchie Cobbs 		/* Deliver packet to divert input routine */
8282b25acc1SLuigi Rizzo 		divert_packet(m, 1, divert_info & 0xffff, args.divert_rule);
829e4676ba6SJulian Elischer 		ipstat.ips_delivered++;
8308948e4baSArchie Cobbs 
8318948e4baSArchie Cobbs 		/* If 'tee', continue with original packet */
8328948e4baSArchie Cobbs 		if (clone == NULL)
83393e0e116SJulian Elischer 			return;
8348948e4baSArchie Cobbs 		m = clone;
8358948e4baSArchie Cobbs 		ip = mtod(m, struct ip *);
83656962689SCrist J. Clark 		ip->ip_len += hlen;
8372b25acc1SLuigi Rizzo 		/*
8382b25acc1SLuigi Rizzo 		 * Jump backwards to complete processing of the
8392b25acc1SLuigi Rizzo 		 * packet. But first clear divert_info to avoid
8402b25acc1SLuigi Rizzo 		 * entering this block again.
8412b25acc1SLuigi Rizzo 		 * We do not need to clear args.divert_rule
8422b25acc1SLuigi Rizzo 		 * or args.next_hop as they will not be used.
8432b25acc1SLuigi Rizzo 		 */
84456962689SCrist J. Clark 		divert_info = 0;
84556962689SCrist J. Clark 		goto pass;
84693e0e116SJulian Elischer 	}
84793e0e116SJulian Elischer #endif
84893e0e116SJulian Elischer 
84933841545SHajimu UMEMOTO #ifdef IPSEC
85033841545SHajimu UMEMOTO 	/*
85133841545SHajimu UMEMOTO 	 * enforce IPsec policy checking if we are seeing last header.
85233841545SHajimu UMEMOTO 	 * note that we do not visit this with protocols with pcb layer
85333841545SHajimu UMEMOTO 	 * code - like udp/tcp/raw ip.
85433841545SHajimu UMEMOTO 	 */
85533841545SHajimu UMEMOTO 	if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 &&
85633841545SHajimu UMEMOTO 	    ipsec4_in_reject(m, NULL)) {
85733841545SHajimu UMEMOTO 		ipsecstat.in_polvio++;
85833841545SHajimu UMEMOTO 		goto bad;
85933841545SHajimu UMEMOTO 	}
86033841545SHajimu UMEMOTO #endif
861b9234fafSSam Leffler #if FAST_IPSEC
862b9234fafSSam Leffler 	/*
863b9234fafSSam Leffler 	 * enforce IPsec policy checking if we are seeing last header.
864b9234fafSSam Leffler 	 * note that we do not visit this with protocols with pcb layer
865b9234fafSSam Leffler 	 * code - like udp/tcp/raw ip.
866b9234fafSSam Leffler 	 */
867b9234fafSSam Leffler 	if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0) {
868b9234fafSSam Leffler 		/*
869b9234fafSSam Leffler 		 * Check if the packet has already had IPsec processing
870b9234fafSSam Leffler 		 * done.  If so, then just pass it along.  This tag gets
871b9234fafSSam Leffler 		 * set during AH, ESP, etc. input handling, before the
872b9234fafSSam Leffler 		 * packet is returned to the ip input queue for delivery.
873b9234fafSSam Leffler 		 */
874b9234fafSSam Leffler 		mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
875b9234fafSSam Leffler 		s = splnet();
876b9234fafSSam Leffler 		if (mtag != NULL) {
877b9234fafSSam Leffler 			tdbi = (struct tdb_ident *)(mtag + 1);
878b9234fafSSam Leffler 			sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
879b9234fafSSam Leffler 		} else {
880b9234fafSSam Leffler 			sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
881b9234fafSSam Leffler 						   IP_FORWARDING, &error);
882b9234fafSSam Leffler 		}
883b9234fafSSam Leffler 		if (sp != NULL) {
884b9234fafSSam Leffler 			/*
885b9234fafSSam Leffler 			 * Check security policy against packet attributes.
886b9234fafSSam Leffler 			 */
887b9234fafSSam Leffler 			error = ipsec_in_reject(sp, m);
888b9234fafSSam Leffler 			KEY_FREESP(&sp);
889b9234fafSSam Leffler 		} else {
890b9234fafSSam Leffler 			/* XXX error stat??? */
891b9234fafSSam Leffler 			error = EINVAL;
892b9234fafSSam Leffler DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/
893b9234fafSSam Leffler 			goto bad;
894b9234fafSSam Leffler 		}
895b9234fafSSam Leffler 		splx(s);
896b9234fafSSam Leffler 		if (error)
897b9234fafSSam Leffler 			goto bad;
898b9234fafSSam Leffler 	}
899b9234fafSSam Leffler #endif /* FAST_IPSEC */
90033841545SHajimu UMEMOTO 
901df8bae1dSRodney W. Grimes 	/*
902df8bae1dSRodney W. Grimes 	 * Switch out to protocol's input routine.
903df8bae1dSRodney W. Grimes 	 */
904df8bae1dSRodney W. Grimes 	ipstat.ips_delivered++;
9052b25acc1SLuigi Rizzo 	if (args.next_hop && ip->ip_p == IPPROTO_TCP) {
9062b25acc1SLuigi Rizzo 		/* TCP needs IPFORWARD info if available */
9072b25acc1SLuigi Rizzo 		struct m_hdr tag;
9086a800098SYoshinobu Inoue 
9092b25acc1SLuigi Rizzo 		tag.mh_type = MT_TAG;
9102b25acc1SLuigi Rizzo 		tag.mh_flags = PACKET_TAG_IPFORWARD;
9112b25acc1SLuigi Rizzo 		tag.mh_data = (caddr_t)args.next_hop;
9122b25acc1SLuigi Rizzo 		tag.mh_next = m;
9132b25acc1SLuigi Rizzo 
9142b25acc1SLuigi Rizzo 		(*inetsw[ip_protox[ip->ip_p]].pr_input)(
9152b25acc1SLuigi Rizzo 			(struct mbuf *)&tag, hlen);
9162b25acc1SLuigi Rizzo 	} else
9172b25acc1SLuigi Rizzo 		(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
918c67b1d17SGarrett Wollman 	return;
919df8bae1dSRodney W. Grimes bad:
920df8bae1dSRodney W. Grimes 	m_freem(m);
921c67b1d17SGarrett Wollman }
922c67b1d17SGarrett Wollman 
923c67b1d17SGarrett Wollman /*
924c67b1d17SGarrett Wollman  * IP software interrupt routine - to go away sometime soon
925c67b1d17SGarrett Wollman  */
926c67b1d17SGarrett Wollman static void
927c67b1d17SGarrett Wollman ipintr(void)
928c67b1d17SGarrett Wollman {
929c67b1d17SGarrett Wollman 	struct mbuf *m;
930c67b1d17SGarrett Wollman 
931c67b1d17SGarrett Wollman 	while (1) {
932c67b1d17SGarrett Wollman 		IF_DEQUEUE(&ipintrq, m);
933c67b1d17SGarrett Wollman 		if (m == 0)
934c67b1d17SGarrett Wollman 			return;
935c67b1d17SGarrett Wollman 		ip_input(m);
936c67b1d17SGarrett Wollman 	}
937df8bae1dSRodney W. Grimes }
938df8bae1dSRodney W. Grimes 
939df8bae1dSRodney W. Grimes /*
9408948e4baSArchie Cobbs  * Take incoming datagram fragment and try to reassemble it into
9418948e4baSArchie Cobbs  * whole datagram.  If a chain for reassembly of this datagram already
9428948e4baSArchie Cobbs  * exists, then it is given as fp; otherwise have to make a chain.
9438948e4baSArchie Cobbs  *
9448948e4baSArchie Cobbs  * When IPDIVERT enabled, keep additional state with each packet that
9458948e4baSArchie Cobbs  * tells us if we need to divert or tee the packet we're building.
9462b25acc1SLuigi Rizzo  * In particular, *divinfo includes the port and TEE flag,
9472b25acc1SLuigi Rizzo  * *divert_rule is the number of the matching rule.
948df8bae1dSRodney W. Grimes  */
9498948e4baSArchie Cobbs 
9506a800098SYoshinobu Inoue static struct mbuf *
9512b25acc1SLuigi Rizzo ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp,
9522b25acc1SLuigi Rizzo 	u_int32_t *divinfo, u_int16_t *divert_rule)
953df8bae1dSRodney W. Grimes {
9546effc713SDoug Rabson 	struct ip *ip = mtod(m, struct ip *);
955b6ea1aa5SRuslan Ermilov 	register struct mbuf *p, *q, *nq;
956df8bae1dSRodney W. Grimes 	struct mbuf *t;
95753be11f6SPoul-Henning Kamp 	int hlen = ip->ip_hl << 2;
958df8bae1dSRodney W. Grimes 	int i, next;
959df8bae1dSRodney W. Grimes 
960df8bae1dSRodney W. Grimes 	/*
961df8bae1dSRodney W. Grimes 	 * Presence of header sizes in mbufs
962df8bae1dSRodney W. Grimes 	 * would confuse code below.
963df8bae1dSRodney W. Grimes 	 */
964df8bae1dSRodney W. Grimes 	m->m_data += hlen;
965df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
966df8bae1dSRodney W. Grimes 
967df8bae1dSRodney W. Grimes 	/*
968df8bae1dSRodney W. Grimes 	 * If first fragment to arrive, create a reassembly queue.
969df8bae1dSRodney W. Grimes 	 */
970df8bae1dSRodney W. Grimes 	if (fp == 0) {
971690a6055SJesper Skriver 		/*
972690a6055SJesper Skriver 		 * Enforce upper bound on number of fragmented packets
973690a6055SJesper Skriver 		 * for which we attempt reassembly;
974690a6055SJesper Skriver 		 * If maxfrag is 0, never accept fragments.
975690a6055SJesper Skriver 		 * If maxfrag is -1, accept all fragments without limitation.
976690a6055SJesper Skriver 		 */
977690a6055SJesper Skriver 		if ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets))
978690a6055SJesper Skriver 			goto dropfrag;
979690a6055SJesper Skriver 		ip_nfragpackets++;
980df8bae1dSRodney W. Grimes 		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
981df8bae1dSRodney W. Grimes 			goto dropfrag;
982df8bae1dSRodney W. Grimes 		fp = mtod(t, struct ipq *);
98336b0360bSRobert Watson #ifdef MAC
98436b0360bSRobert Watson 		mac_init_ipq(fp);
98536b0360bSRobert Watson 		mac_create_ipq(m, fp);
98636b0360bSRobert Watson #endif
987462b86feSPoul-Henning Kamp 		TAILQ_INSERT_HEAD(head, fp, ipq_list);
988194a213eSAndrey A. Chernov 		nipq++;
989df8bae1dSRodney W. Grimes 		fp->ipq_ttl = IPFRAGTTL;
990df8bae1dSRodney W. Grimes 		fp->ipq_p = ip->ip_p;
991df8bae1dSRodney W. Grimes 		fp->ipq_id = ip->ip_id;
9926effc713SDoug Rabson 		fp->ipq_src = ip->ip_src;
9936effc713SDoug Rabson 		fp->ipq_dst = ip->ip_dst;
994af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
995af38c68cSLuigi Rizzo 		m->m_nextpkt = NULL;
99693e0e116SJulian Elischer #ifdef IPDIVERT
9978948e4baSArchie Cobbs 		fp->ipq_div_info = 0;
998bb60f459SJulian Elischer 		fp->ipq_div_cookie = 0;
99993e0e116SJulian Elischer #endif
1000af38c68cSLuigi Rizzo 		goto inserted;
100136b0360bSRobert Watson 	} else {
100236b0360bSRobert Watson #ifdef MAC
100336b0360bSRobert Watson 		mac_update_ipq(m, fp);
100436b0360bSRobert Watson #endif
1005df8bae1dSRodney W. Grimes 	}
1006df8bae1dSRodney W. Grimes 
10076effc713SDoug Rabson #define GETIP(m)	((struct ip*)((m)->m_pkthdr.header))
10086effc713SDoug Rabson 
1009df8bae1dSRodney W. Grimes 	/*
1010df8bae1dSRodney W. Grimes 	 * Find a segment which begins after this one does.
1011df8bae1dSRodney W. Grimes 	 */
10126effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
10136effc713SDoug Rabson 		if (GETIP(q)->ip_off > ip->ip_off)
1014df8bae1dSRodney W. Grimes 			break;
1015df8bae1dSRodney W. Grimes 
1016df8bae1dSRodney W. Grimes 	/*
1017df8bae1dSRodney W. Grimes 	 * If there is a preceding segment, it may provide some of
1018df8bae1dSRodney W. Grimes 	 * our data already.  If so, drop the data from the incoming
1019af38c68cSLuigi Rizzo 	 * segment.  If it provides all of our data, drop us, otherwise
1020af38c68cSLuigi Rizzo 	 * stick new segment in the proper place.
1021db4f9cc7SJonathan Lemon 	 *
1022db4f9cc7SJonathan Lemon 	 * If some of the data is dropped from the the preceding
1023db4f9cc7SJonathan Lemon 	 * segment, then it's checksum is invalidated.
1024df8bae1dSRodney W. Grimes 	 */
10256effc713SDoug Rabson 	if (p) {
10266effc713SDoug Rabson 		i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
1027df8bae1dSRodney W. Grimes 		if (i > 0) {
1028df8bae1dSRodney W. Grimes 			if (i >= ip->ip_len)
1029df8bae1dSRodney W. Grimes 				goto dropfrag;
10306a800098SYoshinobu Inoue 			m_adj(m, i);
1031db4f9cc7SJonathan Lemon 			m->m_pkthdr.csum_flags = 0;
1032df8bae1dSRodney W. Grimes 			ip->ip_off += i;
1033df8bae1dSRodney W. Grimes 			ip->ip_len -= i;
1034df8bae1dSRodney W. Grimes 		}
1035af38c68cSLuigi Rizzo 		m->m_nextpkt = p->m_nextpkt;
1036af38c68cSLuigi Rizzo 		p->m_nextpkt = m;
1037af38c68cSLuigi Rizzo 	} else {
1038af38c68cSLuigi Rizzo 		m->m_nextpkt = fp->ipq_frags;
1039af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
1040df8bae1dSRodney W. Grimes 	}
1041df8bae1dSRodney W. Grimes 
1042df8bae1dSRodney W. Grimes 	/*
1043df8bae1dSRodney W. Grimes 	 * While we overlap succeeding segments trim them or,
1044df8bae1dSRodney W. Grimes 	 * if they are completely covered, dequeue them.
1045df8bae1dSRodney W. Grimes 	 */
10466effc713SDoug Rabson 	for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
1047af38c68cSLuigi Rizzo 	     q = nq) {
10486effc713SDoug Rabson 		i = (ip->ip_off + ip->ip_len) -
10496effc713SDoug Rabson 		    GETIP(q)->ip_off;
10506effc713SDoug Rabson 		if (i < GETIP(q)->ip_len) {
10516effc713SDoug Rabson 			GETIP(q)->ip_len -= i;
10526effc713SDoug Rabson 			GETIP(q)->ip_off += i;
10536effc713SDoug Rabson 			m_adj(q, i);
1054db4f9cc7SJonathan Lemon 			q->m_pkthdr.csum_flags = 0;
1055df8bae1dSRodney W. Grimes 			break;
1056df8bae1dSRodney W. Grimes 		}
10576effc713SDoug Rabson 		nq = q->m_nextpkt;
1058af38c68cSLuigi Rizzo 		m->m_nextpkt = nq;
10596effc713SDoug Rabson 		m_freem(q);
1060df8bae1dSRodney W. Grimes 	}
1061df8bae1dSRodney W. Grimes 
1062af38c68cSLuigi Rizzo inserted:
106393e0e116SJulian Elischer 
106493e0e116SJulian Elischer #ifdef IPDIVERT
106593e0e116SJulian Elischer 	/*
10668948e4baSArchie Cobbs 	 * Transfer firewall instructions to the fragment structure.
10672b25acc1SLuigi Rizzo 	 * Only trust info in the fragment at offset 0.
106893e0e116SJulian Elischer 	 */
10692b25acc1SLuigi Rizzo 	if (ip->ip_off == 0) {
10708948e4baSArchie Cobbs 		fp->ipq_div_info = *divinfo;
10712b25acc1SLuigi Rizzo 		fp->ipq_div_cookie = *divert_rule;
10722b25acc1SLuigi Rizzo 	}
10738948e4baSArchie Cobbs 	*divinfo = 0;
10742b25acc1SLuigi Rizzo 	*divert_rule = 0;
107593e0e116SJulian Elischer #endif
107693e0e116SJulian Elischer 
1077df8bae1dSRodney W. Grimes 	/*
1078af38c68cSLuigi Rizzo 	 * Check for complete reassembly.
1079df8bae1dSRodney W. Grimes 	 */
10806effc713SDoug Rabson 	next = 0;
10816effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
10826effc713SDoug Rabson 		if (GETIP(q)->ip_off != next)
10836effc713SDoug Rabson 			return (0);
10846effc713SDoug Rabson 		next += GETIP(q)->ip_len;
10856effc713SDoug Rabson 	}
10866effc713SDoug Rabson 	/* Make sure the last packet didn't have the IP_MF flag */
10876effc713SDoug Rabson 	if (p->m_flags & M_FRAG)
1088df8bae1dSRodney W. Grimes 		return (0);
1089df8bae1dSRodney W. Grimes 
1090df8bae1dSRodney W. Grimes 	/*
1091430d30d8SBill Fenner 	 * Reassembly is complete.  Make sure the packet is a sane size.
1092430d30d8SBill Fenner 	 */
10936effc713SDoug Rabson 	q = fp->ipq_frags;
10946effc713SDoug Rabson 	ip = GETIP(q);
109553be11f6SPoul-Henning Kamp 	if (next + (ip->ip_hl << 2) > IP_MAXPACKET) {
1096430d30d8SBill Fenner 		ipstat.ips_toolong++;
1097462b86feSPoul-Henning Kamp 		ip_freef(head, fp);
1098430d30d8SBill Fenner 		return (0);
1099430d30d8SBill Fenner 	}
1100430d30d8SBill Fenner 
1101430d30d8SBill Fenner 	/*
1102430d30d8SBill Fenner 	 * Concatenate fragments.
1103df8bae1dSRodney W. Grimes 	 */
11046effc713SDoug Rabson 	m = q;
1105df8bae1dSRodney W. Grimes 	t = m->m_next;
1106df8bae1dSRodney W. Grimes 	m->m_next = 0;
1107df8bae1dSRodney W. Grimes 	m_cat(m, t);
11086effc713SDoug Rabson 	nq = q->m_nextpkt;
1109945aa40dSDoug Rabson 	q->m_nextpkt = 0;
11106effc713SDoug Rabson 	for (q = nq; q != NULL; q = nq) {
11116effc713SDoug Rabson 		nq = q->m_nextpkt;
1112945aa40dSDoug Rabson 		q->m_nextpkt = NULL;
1113db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags;
1114db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_data += q->m_pkthdr.csum_data;
1115a8db1d93SJonathan Lemon 		m_cat(m, q);
1116df8bae1dSRodney W. Grimes 	}
111736b0360bSRobert Watson #ifdef MAC
111836b0360bSRobert Watson 	mac_create_datagram_from_ipq(fp, m);
111936b0360bSRobert Watson 	mac_destroy_ipq(fp);
112036b0360bSRobert Watson #endif
1121df8bae1dSRodney W. Grimes 
112293e0e116SJulian Elischer #ifdef IPDIVERT
112393e0e116SJulian Elischer 	/*
11248948e4baSArchie Cobbs 	 * Extract firewall instructions from the fragment structure.
112593e0e116SJulian Elischer 	 */
11268948e4baSArchie Cobbs 	*divinfo = fp->ipq_div_info;
11272b25acc1SLuigi Rizzo 	*divert_rule = fp->ipq_div_cookie;
112893e0e116SJulian Elischer #endif
112993e0e116SJulian Elischer 
1130df8bae1dSRodney W. Grimes 	/*
1131df8bae1dSRodney W. Grimes 	 * Create header for new ip packet by
1132df8bae1dSRodney W. Grimes 	 * modifying header of first packet;
1133df8bae1dSRodney W. Grimes 	 * dequeue and discard fragment reassembly header.
1134df8bae1dSRodney W. Grimes 	 * Make header visible.
1135df8bae1dSRodney W. Grimes 	 */
1136df8bae1dSRodney W. Grimes 	ip->ip_len = next;
11376effc713SDoug Rabson 	ip->ip_src = fp->ipq_src;
11386effc713SDoug Rabson 	ip->ip_dst = fp->ipq_dst;
1139462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(head, fp, ipq_list);
1140194a213eSAndrey A. Chernov 	nipq--;
1141df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1142690a6055SJesper Skriver 	ip_nfragpackets--;
114353be11f6SPoul-Henning Kamp 	m->m_len += (ip->ip_hl << 2);
114453be11f6SPoul-Henning Kamp 	m->m_data -= (ip->ip_hl << 2);
1145df8bae1dSRodney W. Grimes 	/* some debugging cruft by sklower, below, will go away soon */
1146a5554bf0SPoul-Henning Kamp 	if (m->m_flags & M_PKTHDR)	/* XXX this should be done elsewhere */
1147a5554bf0SPoul-Henning Kamp 		m_fixhdr(m);
11486a800098SYoshinobu Inoue 	return (m);
1149df8bae1dSRodney W. Grimes 
1150df8bae1dSRodney W. Grimes dropfrag:
1151efe39c6aSJulian Elischer #ifdef IPDIVERT
11528948e4baSArchie Cobbs 	*divinfo = 0;
11532b25acc1SLuigi Rizzo 	*divert_rule = 0;
1154efe39c6aSJulian Elischer #endif
1155df8bae1dSRodney W. Grimes 	ipstat.ips_fragdropped++;
1156df8bae1dSRodney W. Grimes 	m_freem(m);
1157df8bae1dSRodney W. Grimes 	return (0);
11586effc713SDoug Rabson 
11596effc713SDoug Rabson #undef GETIP
1160df8bae1dSRodney W. Grimes }
1161df8bae1dSRodney W. Grimes 
1162df8bae1dSRodney W. Grimes /*
1163df8bae1dSRodney W. Grimes  * Free a fragment reassembly header and all
1164df8bae1dSRodney W. Grimes  * associated datagrams.
1165df8bae1dSRodney W. Grimes  */
11660312fbe9SPoul-Henning Kamp static void
1167462b86feSPoul-Henning Kamp ip_freef(fhp, fp)
1168462b86feSPoul-Henning Kamp 	struct ipqhead *fhp;
1169df8bae1dSRodney W. Grimes 	struct ipq *fp;
1170df8bae1dSRodney W. Grimes {
11716effc713SDoug Rabson 	register struct mbuf *q;
1172df8bae1dSRodney W. Grimes 
11736effc713SDoug Rabson 	while (fp->ipq_frags) {
11746effc713SDoug Rabson 		q = fp->ipq_frags;
11756effc713SDoug Rabson 		fp->ipq_frags = q->m_nextpkt;
11766effc713SDoug Rabson 		m_freem(q);
1177df8bae1dSRodney W. Grimes 	}
1178462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(fhp, fp, ipq_list);
1179df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1180690a6055SJesper Skriver 	ip_nfragpackets--;
1181194a213eSAndrey A. Chernov 	nipq--;
1182df8bae1dSRodney W. Grimes }
1183df8bae1dSRodney W. Grimes 
1184df8bae1dSRodney W. Grimes /*
1185df8bae1dSRodney W. Grimes  * IP timer processing;
1186df8bae1dSRodney W. Grimes  * if a timer expires on a reassembly
1187df8bae1dSRodney W. Grimes  * queue, discard it.
1188df8bae1dSRodney W. Grimes  */
1189df8bae1dSRodney W. Grimes void
1190df8bae1dSRodney W. Grimes ip_slowtimo()
1191df8bae1dSRodney W. Grimes {
1192df8bae1dSRodney W. Grimes 	register struct ipq *fp;
1193df8bae1dSRodney W. Grimes 	int s = splnet();
1194194a213eSAndrey A. Chernov 	int i;
1195df8bae1dSRodney W. Grimes 
1196194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1197462b86feSPoul-Henning Kamp 		for(fp = TAILQ_FIRST(&ipq[i]); fp;) {
1198462b86feSPoul-Henning Kamp 			struct ipq *fpp;
1199462b86feSPoul-Henning Kamp 
1200462b86feSPoul-Henning Kamp 			fpp = fp;
1201462b86feSPoul-Henning Kamp 			fp = TAILQ_NEXT(fp, ipq_list);
1202462b86feSPoul-Henning Kamp 			if(--fpp->ipq_ttl == 0) {
1203df8bae1dSRodney W. Grimes 				ipstat.ips_fragtimeout++;
1204462b86feSPoul-Henning Kamp 				ip_freef(&ipq[i], fpp);
1205df8bae1dSRodney W. Grimes 			}
1206df8bae1dSRodney W. Grimes 		}
1207194a213eSAndrey A. Chernov 	}
1208690a6055SJesper Skriver 	/*
1209690a6055SJesper Skriver 	 * If we are over the maximum number of fragments
1210690a6055SJesper Skriver 	 * (due to the limit being lowered), drain off
1211690a6055SJesper Skriver 	 * enough to get down to the new limit.
1212690a6055SJesper Skriver 	 */
1213690a6055SJesper Skriver 	for (i = 0; i < IPREASS_NHASH; i++) {
1214690a6055SJesper Skriver 		if (ip_maxfragpackets >= 0) {
1215690a6055SJesper Skriver 			while (ip_nfragpackets > ip_maxfragpackets &&
1216690a6055SJesper Skriver 				!TAILQ_EMPTY(&ipq[i])) {
1217690a6055SJesper Skriver 				ipstat.ips_fragdropped++;
1218690a6055SJesper Skriver 				ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1219690a6055SJesper Skriver 			}
1220690a6055SJesper Skriver 		}
1221690a6055SJesper Skriver 	}
12221f91d8c5SDavid Greenman 	ipflow_slowtimo();
1223df8bae1dSRodney W. Grimes 	splx(s);
1224df8bae1dSRodney W. Grimes }
1225df8bae1dSRodney W. Grimes 
1226df8bae1dSRodney W. Grimes /*
1227df8bae1dSRodney W. Grimes  * Drain off all datagram fragments.
1228df8bae1dSRodney W. Grimes  */
1229df8bae1dSRodney W. Grimes void
1230df8bae1dSRodney W. Grimes ip_drain()
1231df8bae1dSRodney W. Grimes {
1232194a213eSAndrey A. Chernov 	int     i;
1233ce29ab3aSGarrett Wollman 
1234194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1235462b86feSPoul-Henning Kamp 		while(!TAILQ_EMPTY(&ipq[i])) {
1236194a213eSAndrey A. Chernov 			ipstat.ips_fragdropped++;
1237462b86feSPoul-Henning Kamp 			ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1238194a213eSAndrey A. Chernov 		}
1239194a213eSAndrey A. Chernov 	}
1240ce29ab3aSGarrett Wollman 	in_rtqdrain();
1241df8bae1dSRodney W. Grimes }
1242df8bae1dSRodney W. Grimes 
1243df8bae1dSRodney W. Grimes /*
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
12562b25acc1SLuigi Rizzo ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
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 
1266df8bae1dSRodney W. Grimes 	dst = ip->ip_dst;
1267df8bae1dSRodney W. Grimes 	cp = (u_char *)(ip + 1);
126853be11f6SPoul-Henning Kamp 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
1269df8bae1dSRodney W. Grimes 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
1270df8bae1dSRodney W. Grimes 		opt = cp[IPOPT_OPTVAL];
1271df8bae1dSRodney W. Grimes 		if (opt == IPOPT_EOL)
1272df8bae1dSRodney W. Grimes 			break;
1273df8bae1dSRodney W. Grimes 		if (opt == IPOPT_NOP)
1274df8bae1dSRodney W. Grimes 			optlen = 1;
1275df8bae1dSRodney W. Grimes 		else {
1276fdcb8debSJun-ichiro itojun Hagino 			if (cnt < IPOPT_OLEN + sizeof(*cp)) {
1277fdcb8debSJun-ichiro itojun Hagino 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1278fdcb8debSJun-ichiro itojun Hagino 				goto bad;
1279fdcb8debSJun-ichiro itojun Hagino 			}
1280df8bae1dSRodney W. Grimes 			optlen = cp[IPOPT_OLEN];
1281707d00a3SJonathan Lemon 			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
1282df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1283df8bae1dSRodney W. Grimes 				goto bad;
1284df8bae1dSRodney W. Grimes 			}
1285df8bae1dSRodney W. Grimes 		}
1286df8bae1dSRodney W. Grimes 		switch (opt) {
1287df8bae1dSRodney W. Grimes 
1288df8bae1dSRodney W. Grimes 		default:
1289df8bae1dSRodney W. Grimes 			break;
1290df8bae1dSRodney W. Grimes 
1291df8bae1dSRodney W. Grimes 		/*
1292df8bae1dSRodney W. Grimes 		 * Source routing with record.
1293df8bae1dSRodney W. Grimes 		 * Find interface with current destination address.
1294df8bae1dSRodney W. Grimes 		 * If none on this machine then drop if strictly routed,
1295df8bae1dSRodney W. Grimes 		 * or do nothing if loosely routed.
1296df8bae1dSRodney W. Grimes 		 * Record interface address and bring up next address
1297df8bae1dSRodney W. Grimes 		 * component.  If strictly routed make sure next
1298df8bae1dSRodney W. Grimes 		 * address is on directly accessible net.
1299df8bae1dSRodney W. Grimes 		 */
1300df8bae1dSRodney W. Grimes 		case IPOPT_LSRR:
1301df8bae1dSRodney W. Grimes 		case IPOPT_SSRR:
1302d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1303d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass > 0)
1304d0ebc0d2SYaroslav Tykhiy 				break;
1305d0ebc0d2SYaroslav Tykhiy #endif
130633841545SHajimu UMEMOTO 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
130733841545SHajimu UMEMOTO 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
130833841545SHajimu UMEMOTO 				goto bad;
130933841545SHajimu UMEMOTO 			}
1310df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1311df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1312df8bae1dSRodney W. Grimes 				goto bad;
1313df8bae1dSRodney W. Grimes 			}
1314df8bae1dSRodney W. Grimes 			ipaddr.sin_addr = ip->ip_dst;
1315df8bae1dSRodney W. Grimes 			ia = (struct in_ifaddr *)
1316df8bae1dSRodney W. Grimes 				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
1317df8bae1dSRodney W. Grimes 			if (ia == 0) {
1318df8bae1dSRodney W. Grimes 				if (opt == IPOPT_SSRR) {
1319df8bae1dSRodney W. Grimes 					type = ICMP_UNREACH;
1320df8bae1dSRodney W. Grimes 					code = ICMP_UNREACH_SRCFAIL;
1321df8bae1dSRodney W. Grimes 					goto bad;
1322df8bae1dSRodney W. Grimes 				}
1323bc189bf8SGuido van Rooij 				if (!ip_dosourceroute)
1324bc189bf8SGuido van Rooij 					goto nosourcerouting;
1325df8bae1dSRodney W. Grimes 				/*
1326df8bae1dSRodney W. Grimes 				 * Loose routing, and not at next destination
1327df8bae1dSRodney W. Grimes 				 * yet; nothing to do except forward.
1328df8bae1dSRodney W. Grimes 				 */
1329df8bae1dSRodney W. Grimes 				break;
1330df8bae1dSRodney W. Grimes 			}
1331df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
13325d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr)) {
1333df8bae1dSRodney W. Grimes 				/*
1334df8bae1dSRodney W. Grimes 				 * End of source route.  Should be for us.
1335df8bae1dSRodney W. Grimes 				 */
13364fce5804SGuido van Rooij 				if (!ip_acceptsourceroute)
13374fce5804SGuido van Rooij 					goto nosourcerouting;
1338df8bae1dSRodney W. Grimes 				save_rte(cp, ip->ip_src);
1339df8bae1dSRodney W. Grimes 				break;
1340df8bae1dSRodney W. Grimes 			}
1341d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1342d0ebc0d2SYaroslav Tykhiy 			if (ipstealth)
1343d0ebc0d2SYaroslav Tykhiy 				goto dropit;
1344d0ebc0d2SYaroslav Tykhiy #endif
13451025071fSGarrett Wollman 			if (!ip_dosourceroute) {
13460af8d3ecSDavid Greenman 				if (ipforwarding) {
13470af8d3ecSDavid Greenman 					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
13480af8d3ecSDavid Greenman 					/*
13490af8d3ecSDavid Greenman 					 * Acting as a router, so generate ICMP
13500af8d3ecSDavid Greenman 					 */
1351efa48587SGuido van Rooij nosourcerouting:
1352bc189bf8SGuido van Rooij 					strcpy(buf, inet_ntoa(ip->ip_dst));
13531025071fSGarrett Wollman 					log(LOG_WARNING,
13541025071fSGarrett Wollman 					    "attempted source route from %s to %s\n",
13551025071fSGarrett Wollman 					    inet_ntoa(ip->ip_src), buf);
13561025071fSGarrett Wollman 					type = ICMP_UNREACH;
13571025071fSGarrett Wollman 					code = ICMP_UNREACH_SRCFAIL;
13581025071fSGarrett Wollman 					goto bad;
13590af8d3ecSDavid Greenman 				} else {
13600af8d3ecSDavid Greenman 					/*
13610af8d3ecSDavid Greenman 					 * Not acting as a router, so silently drop.
13620af8d3ecSDavid Greenman 					 */
1363d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1364d0ebc0d2SYaroslav Tykhiy dropit:
1365d0ebc0d2SYaroslav Tykhiy #endif
13660af8d3ecSDavid Greenman 					ipstat.ips_cantforward++;
13670af8d3ecSDavid Greenman 					m_freem(m);
13680af8d3ecSDavid Greenman 					return (1);
13690af8d3ecSDavid Greenman 				}
13701025071fSGarrett Wollman 			}
13711025071fSGarrett Wollman 
1372df8bae1dSRodney W. Grimes 			/*
1373df8bae1dSRodney W. Grimes 			 * locate outgoing interface
1374df8bae1dSRodney W. Grimes 			 */
137594a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, cp + off,
1376df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
13771025071fSGarrett Wollman 
1378df8bae1dSRodney W. Grimes 			if (opt == IPOPT_SSRR) {
1379df8bae1dSRodney W. Grimes #define	INA	struct in_ifaddr *
1380df8bae1dSRodney W. Grimes #define	SA	struct sockaddr *
1381df8bae1dSRodney W. Grimes 			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
1382df8bae1dSRodney W. Grimes 				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
1383df8bae1dSRodney W. Grimes 			} else
1384bd714208SRuslan Ermilov 				ia = ip_rtaddr(ipaddr.sin_addr, &ipforward_rt);
1385df8bae1dSRodney W. Grimes 			if (ia == 0) {
1386df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1387df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_SRCFAIL;
1388df8bae1dSRodney W. Grimes 				goto bad;
1389df8bae1dSRodney W. Grimes 			}
1390df8bae1dSRodney W. Grimes 			ip->ip_dst = ipaddr.sin_addr;
139194a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
139294a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1393df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1394df8bae1dSRodney W. Grimes 			/*
1395df8bae1dSRodney W. Grimes 			 * Let ip_intr's mcast routing check handle mcast pkts
1396df8bae1dSRodney W. Grimes 			 */
1397df8bae1dSRodney W. Grimes 			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
1398df8bae1dSRodney W. Grimes 			break;
1399df8bae1dSRodney W. Grimes 
1400df8bae1dSRodney W. Grimes 		case IPOPT_RR:
1401d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1402d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass == 0)
1403d0ebc0d2SYaroslav Tykhiy 				break;
1404d0ebc0d2SYaroslav Tykhiy #endif
1405707d00a3SJonathan Lemon 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
1406707d00a3SJonathan Lemon 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1407707d00a3SJonathan Lemon 				goto bad;
1408707d00a3SJonathan Lemon 			}
1409df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1410df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1411df8bae1dSRodney W. Grimes 				goto bad;
1412df8bae1dSRodney W. Grimes 			}
1413df8bae1dSRodney W. Grimes 			/*
1414df8bae1dSRodney W. Grimes 			 * If no space remains, ignore.
1415df8bae1dSRodney W. Grimes 			 */
1416df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
14175d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr))
1418df8bae1dSRodney W. Grimes 				break;
141994a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
1420df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
1421df8bae1dSRodney W. Grimes 			/*
1422df8bae1dSRodney W. Grimes 			 * locate outgoing interface; if we're the destination,
1423df8bae1dSRodney W. Grimes 			 * use the incoming interface (should be same).
1424df8bae1dSRodney W. Grimes 			 */
1425df8bae1dSRodney W. Grimes 			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
1426bd714208SRuslan Ermilov 			    (ia = ip_rtaddr(ipaddr.sin_addr,
1427bd714208SRuslan Ermilov 			    &ipforward_rt)) == 0) {
1428df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1429df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_HOST;
1430df8bae1dSRodney W. Grimes 				goto bad;
1431df8bae1dSRodney W. Grimes 			}
143294a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
143394a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1434df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1435df8bae1dSRodney W. Grimes 			break;
1436df8bae1dSRodney W. Grimes 
1437df8bae1dSRodney W. Grimes 		case IPOPT_TS:
1438d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1439d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass == 0)
1440d0ebc0d2SYaroslav Tykhiy 				break;
1441d0ebc0d2SYaroslav Tykhiy #endif
1442df8bae1dSRodney W. Grimes 			code = cp - (u_char *)ip;
144307514071SJonathan Lemon 			if (optlen < 4 || optlen > 40) {
144407514071SJonathan Lemon 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1445df8bae1dSRodney W. Grimes 				goto bad;
144633841545SHajimu UMEMOTO 			}
144707514071SJonathan Lemon 			if ((off = cp[IPOPT_OFFSET]) < 5) {
144807514071SJonathan Lemon 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
144933841545SHajimu UMEMOTO 				goto bad;
145033841545SHajimu UMEMOTO 			}
145107514071SJonathan Lemon 			if (off > optlen - (int)sizeof(int32_t)) {
145207514071SJonathan Lemon 				cp[IPOPT_OFFSET + 1] += (1 << 4);
145307514071SJonathan Lemon 				if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) {
145407514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1455df8bae1dSRodney W. Grimes 					goto bad;
145633841545SHajimu UMEMOTO 				}
1457df8bae1dSRodney W. Grimes 				break;
1458df8bae1dSRodney W. Grimes 			}
145907514071SJonathan Lemon 			off--;				/* 0 origin */
146007514071SJonathan Lemon 			sin = (struct in_addr *)(cp + off);
146107514071SJonathan Lemon 			switch (cp[IPOPT_OFFSET + 1] & 0x0f) {
1462df8bae1dSRodney W. Grimes 
1463df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSONLY:
1464df8bae1dSRodney W. Grimes 				break;
1465df8bae1dSRodney W. Grimes 
1466df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSANDADDR:
146707514071SJonathan Lemon 				if (off + sizeof(n_time) +
146807514071SJonathan Lemon 				    sizeof(struct in_addr) > optlen) {
146907514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1470df8bae1dSRodney W. Grimes 					goto bad;
147133841545SHajimu UMEMOTO 				}
1472df8bae1dSRodney W. Grimes 				ipaddr.sin_addr = dst;
1473df8bae1dSRodney W. Grimes 				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
1474df8bae1dSRodney W. Grimes 							    m->m_pkthdr.rcvif);
1475df8bae1dSRodney W. Grimes 				if (ia == 0)
1476df8bae1dSRodney W. Grimes 					continue;
147794a5d9b6SDavid Greenman 				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
147894a5d9b6SDavid Greenman 				    sizeof(struct in_addr));
147907514071SJonathan Lemon 				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1480a5428e3aSMaxim Konovalov 				off += sizeof(struct in_addr);
1481df8bae1dSRodney W. Grimes 				break;
1482df8bae1dSRodney W. Grimes 
1483df8bae1dSRodney W. Grimes 			case IPOPT_TS_PRESPEC:
148407514071SJonathan Lemon 				if (off + sizeof(n_time) +
148507514071SJonathan Lemon 				    sizeof(struct in_addr) > optlen) {
148607514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1487df8bae1dSRodney W. Grimes 					goto bad;
148833841545SHajimu UMEMOTO 				}
148994a5d9b6SDavid Greenman 				(void)memcpy(&ipaddr.sin_addr, sin,
1490df8bae1dSRodney W. Grimes 				    sizeof(struct in_addr));
1491df8bae1dSRodney W. Grimes 				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
1492df8bae1dSRodney W. Grimes 					continue;
149307514071SJonathan Lemon 				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1494a5428e3aSMaxim Konovalov 				off += sizeof(struct in_addr);
1495df8bae1dSRodney W. Grimes 				break;
1496df8bae1dSRodney W. Grimes 
1497df8bae1dSRodney W. Grimes 			default:
149807514071SJonathan Lemon 				code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip;
1499df8bae1dSRodney W. Grimes 				goto bad;
1500df8bae1dSRodney W. Grimes 			}
1501df8bae1dSRodney W. Grimes 			ntime = iptime();
150207514071SJonathan Lemon 			(void)memcpy(cp + off, &ntime, sizeof(n_time));
150307514071SJonathan Lemon 			cp[IPOPT_OFFSET] += sizeof(n_time);
1504df8bae1dSRodney W. Grimes 		}
1505df8bae1dSRodney W. Grimes 	}
150647174b49SAndrey A. Chernov 	if (forward && ipforwarding) {
15072b25acc1SLuigi Rizzo 		ip_forward(m, 1, next_hop);
1508df8bae1dSRodney W. Grimes 		return (1);
1509df8bae1dSRodney W. Grimes 	}
1510df8bae1dSRodney W. Grimes 	return (0);
1511df8bae1dSRodney W. Grimes bad:
1512df8bae1dSRodney W. Grimes 	icmp_error(m, type, code, 0, 0);
1513df8bae1dSRodney W. Grimes 	ipstat.ips_badoptions++;
1514df8bae1dSRodney W. Grimes 	return (1);
1515df8bae1dSRodney W. Grimes }
1516df8bae1dSRodney W. Grimes 
1517df8bae1dSRodney W. Grimes /*
1518df8bae1dSRodney W. Grimes  * Given address of next destination (final or next hop),
1519df8bae1dSRodney W. Grimes  * return internet address info of interface to be used to get there.
1520df8bae1dSRodney W. Grimes  */
1521bd714208SRuslan Ermilov struct in_ifaddr *
1522bd714208SRuslan Ermilov ip_rtaddr(dst, rt)
1523df8bae1dSRodney W. Grimes 	struct in_addr dst;
1524bd714208SRuslan Ermilov 	struct route *rt;
1525df8bae1dSRodney W. Grimes {
1526df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
1527df8bae1dSRodney W. Grimes 
1528bd714208SRuslan Ermilov 	sin = (struct sockaddr_in *)&rt->ro_dst;
1529df8bae1dSRodney W. Grimes 
1530bd714208SRuslan Ermilov 	if (rt->ro_rt == 0 ||
1531bd714208SRuslan Ermilov 	    !(rt->ro_rt->rt_flags & RTF_UP) ||
15324078ffb1SRuslan Ermilov 	    dst.s_addr != sin->sin_addr.s_addr) {
1533bd714208SRuslan Ermilov 		if (rt->ro_rt) {
1534bd714208SRuslan Ermilov 			RTFREE(rt->ro_rt);
1535bd714208SRuslan Ermilov 			rt->ro_rt = 0;
1536df8bae1dSRodney W. Grimes 		}
1537df8bae1dSRodney W. Grimes 		sin->sin_family = AF_INET;
1538df8bae1dSRodney W. Grimes 		sin->sin_len = sizeof(*sin);
1539df8bae1dSRodney W. Grimes 		sin->sin_addr = dst;
1540df8bae1dSRodney W. Grimes 
1541bd714208SRuslan Ermilov 		rtalloc_ign(rt, RTF_PRCLONING);
1542df8bae1dSRodney W. Grimes 	}
1543bd714208SRuslan Ermilov 	if (rt->ro_rt == 0)
1544df8bae1dSRodney W. Grimes 		return ((struct in_ifaddr *)0);
1545bd714208SRuslan Ermilov 	return (ifatoia(rt->ro_rt->rt_ifa));
1546df8bae1dSRodney W. Grimes }
1547df8bae1dSRodney W. Grimes 
1548df8bae1dSRodney W. Grimes /*
1549df8bae1dSRodney W. Grimes  * Save incoming source route for use in replies,
1550df8bae1dSRodney W. Grimes  * to be picked up later by ip_srcroute if the receiver is interested.
1551df8bae1dSRodney W. Grimes  */
155237c84183SPoul-Henning Kamp static void
1553df8bae1dSRodney W. Grimes save_rte(option, dst)
1554df8bae1dSRodney W. Grimes 	u_char *option;
1555df8bae1dSRodney W. Grimes 	struct in_addr dst;
1556df8bae1dSRodney W. Grimes {
1557df8bae1dSRodney W. Grimes 	unsigned olen;
1558df8bae1dSRodney W. Grimes 
1559df8bae1dSRodney W. Grimes 	olen = option[IPOPT_OLEN];
1560df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1561df8bae1dSRodney W. Grimes 	if (ipprintfs)
1562df8bae1dSRodney W. Grimes 		printf("save_rte: olen %d\n", olen);
1563df8bae1dSRodney W. Grimes #endif
1564df8bae1dSRodney W. Grimes 	if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
1565df8bae1dSRodney W. Grimes 		return;
15660453d3cbSBruce Evans 	bcopy(option, ip_srcrt.srcopt, olen);
1567df8bae1dSRodney W. Grimes 	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
1568df8bae1dSRodney W. Grimes 	ip_srcrt.dst = dst;
1569df8bae1dSRodney W. Grimes }
1570df8bae1dSRodney W. Grimes 
1571df8bae1dSRodney W. Grimes /*
1572df8bae1dSRodney W. Grimes  * Retrieve incoming source route for use in replies,
1573df8bae1dSRodney W. Grimes  * in the same form used by setsockopt.
1574df8bae1dSRodney W. Grimes  * The first hop is placed before the options, will be removed later.
1575df8bae1dSRodney W. Grimes  */
1576df8bae1dSRodney W. Grimes struct mbuf *
1577df8bae1dSRodney W. Grimes ip_srcroute()
1578df8bae1dSRodney W. Grimes {
1579df8bae1dSRodney W. Grimes 	register struct in_addr *p, *q;
1580df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1581df8bae1dSRodney W. Grimes 
1582df8bae1dSRodney W. Grimes 	if (ip_nhops == 0)
1583df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1584cfe8b629SGarrett Wollman 	m = m_get(M_DONTWAIT, MT_HEADER);
1585df8bae1dSRodney W. Grimes 	if (m == 0)
1586df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1587df8bae1dSRodney W. Grimes 
1588df8bae1dSRodney W. Grimes #define OPTSIZ	(sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
1589df8bae1dSRodney W. Grimes 
1590df8bae1dSRodney W. Grimes 	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
1591df8bae1dSRodney W. Grimes 	m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
1592df8bae1dSRodney W. Grimes 	    OPTSIZ;
1593df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1594df8bae1dSRodney W. Grimes 	if (ipprintfs)
1595df8bae1dSRodney W. Grimes 		printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
1596df8bae1dSRodney W. Grimes #endif
1597df8bae1dSRodney W. Grimes 
1598df8bae1dSRodney W. Grimes 	/*
1599df8bae1dSRodney W. Grimes 	 * First save first hop for return route
1600df8bae1dSRodney W. Grimes 	 */
1601df8bae1dSRodney W. Grimes 	p = &ip_srcrt.route[ip_nhops - 1];
1602df8bae1dSRodney W. Grimes 	*(mtod(m, struct in_addr *)) = *p--;
1603df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1604df8bae1dSRodney W. Grimes 	if (ipprintfs)
1605af38c68cSLuigi Rizzo 		printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
1606df8bae1dSRodney W. Grimes #endif
1607df8bae1dSRodney W. Grimes 
1608df8bae1dSRodney W. Grimes 	/*
1609df8bae1dSRodney W. Grimes 	 * Copy option fields and padding (nop) to mbuf.
1610df8bae1dSRodney W. Grimes 	 */
1611df8bae1dSRodney W. Grimes 	ip_srcrt.nop = IPOPT_NOP;
1612df8bae1dSRodney W. Grimes 	ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
161394a5d9b6SDavid Greenman 	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
161494a5d9b6SDavid Greenman 	    &ip_srcrt.nop, OPTSIZ);
1615df8bae1dSRodney W. Grimes 	q = (struct in_addr *)(mtod(m, caddr_t) +
1616df8bae1dSRodney W. Grimes 	    sizeof(struct in_addr) + OPTSIZ);
1617df8bae1dSRodney W. Grimes #undef OPTSIZ
1618df8bae1dSRodney W. Grimes 	/*
1619df8bae1dSRodney W. Grimes 	 * Record return path as an IP source route,
1620df8bae1dSRodney W. Grimes 	 * reversing the path (pointers are now aligned).
1621df8bae1dSRodney W. Grimes 	 */
1622df8bae1dSRodney W. Grimes 	while (p >= ip_srcrt.route) {
1623df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1624df8bae1dSRodney W. Grimes 		if (ipprintfs)
1625af38c68cSLuigi Rizzo 			printf(" %lx", (u_long)ntohl(q->s_addr));
1626df8bae1dSRodney W. Grimes #endif
1627df8bae1dSRodney W. Grimes 		*q++ = *p--;
1628df8bae1dSRodney W. Grimes 	}
1629df8bae1dSRodney W. Grimes 	/*
1630df8bae1dSRodney W. Grimes 	 * Last hop goes to final destination.
1631df8bae1dSRodney W. Grimes 	 */
1632df8bae1dSRodney W. Grimes 	*q = ip_srcrt.dst;
1633df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1634df8bae1dSRodney W. Grimes 	if (ipprintfs)
1635af38c68cSLuigi Rizzo 		printf(" %lx\n", (u_long)ntohl(q->s_addr));
1636df8bae1dSRodney W. Grimes #endif
1637df8bae1dSRodney W. Grimes 	return (m);
1638df8bae1dSRodney W. Grimes }
1639df8bae1dSRodney W. Grimes 
1640df8bae1dSRodney W. Grimes /*
1641df8bae1dSRodney W. Grimes  * Strip out IP options, at higher
1642df8bae1dSRodney W. Grimes  * level protocol in the kernel.
1643df8bae1dSRodney W. Grimes  * Second argument is buffer to which options
1644df8bae1dSRodney W. Grimes  * will be moved, and return value is their length.
1645df8bae1dSRodney W. Grimes  * XXX should be deleted; last arg currently ignored.
1646df8bae1dSRodney W. Grimes  */
1647df8bae1dSRodney W. Grimes void
1648df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt)
1649df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1650df8bae1dSRodney W. Grimes 	struct mbuf *mopt;
1651df8bae1dSRodney W. Grimes {
1652df8bae1dSRodney W. Grimes 	register int i;
1653df8bae1dSRodney W. Grimes 	struct ip *ip = mtod(m, struct ip *);
1654df8bae1dSRodney W. Grimes 	register caddr_t opts;
1655df8bae1dSRodney W. Grimes 	int olen;
1656df8bae1dSRodney W. Grimes 
165753be11f6SPoul-Henning Kamp 	olen = (ip->ip_hl << 2) - sizeof (struct ip);
1658df8bae1dSRodney W. Grimes 	opts = (caddr_t)(ip + 1);
1659df8bae1dSRodney W. Grimes 	i = m->m_len - (sizeof (struct ip) + olen);
1660df8bae1dSRodney W. Grimes 	bcopy(opts + olen, opts, (unsigned)i);
1661df8bae1dSRodney W. Grimes 	m->m_len -= olen;
1662df8bae1dSRodney W. Grimes 	if (m->m_flags & M_PKTHDR)
1663df8bae1dSRodney W. Grimes 		m->m_pkthdr.len -= olen;
166453be11f6SPoul-Henning Kamp 	ip->ip_v = IPVERSION;
166553be11f6SPoul-Henning Kamp 	ip->ip_hl = sizeof(struct ip) >> 2;
1666df8bae1dSRodney W. Grimes }
1667df8bae1dSRodney W. Grimes 
1668df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = {
1669df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
1670df8bae1dSRodney W. Grimes 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
1671df8bae1dSRodney W. Grimes 	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
1672df8bae1dSRodney W. Grimes 	EMSGSIZE,	EHOSTUNREACH,	0,		0,
1673df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
16743b8123b7SJesper Skriver 	ENOPROTOOPT,	ECONNREFUSED
1675df8bae1dSRodney W. Grimes };
1676df8bae1dSRodney W. Grimes 
1677df8bae1dSRodney W. Grimes /*
1678df8bae1dSRodney W. Grimes  * Forward a packet.  If some error occurs return the sender
1679df8bae1dSRodney W. Grimes  * an icmp packet.  Note we can't always generate a meaningful
1680df8bae1dSRodney W. Grimes  * icmp message because icmp doesn't have a large enough repertoire
1681df8bae1dSRodney W. Grimes  * of codes and types.
1682df8bae1dSRodney W. Grimes  *
1683df8bae1dSRodney W. Grimes  * If not forwarding, just drop the packet.  This could be confusing
1684df8bae1dSRodney W. Grimes  * if ipforwarding was zero but some routing protocol was advancing
1685df8bae1dSRodney W. Grimes  * us as a gateway to somewhere.  However, we must let the routing
1686df8bae1dSRodney W. Grimes  * protocol deal with that.
1687df8bae1dSRodney W. Grimes  *
1688df8bae1dSRodney W. Grimes  * The srcrt parameter indicates whether the packet is being forwarded
1689df8bae1dSRodney W. Grimes  * via a source route.
1690df8bae1dSRodney W. Grimes  */
16910312fbe9SPoul-Henning Kamp static void
16922b25acc1SLuigi Rizzo ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
1693df8bae1dSRodney W. Grimes {
16942b25acc1SLuigi Rizzo 	struct ip *ip = mtod(m, struct ip *);
16952b25acc1SLuigi Rizzo 	struct rtentry *rt;
169626f9a767SRodney W. Grimes 	int error, type = 0, code = 0;
1697df8bae1dSRodney W. Grimes 	struct mbuf *mcopy;
1698df8bae1dSRodney W. Grimes 	n_long dest;
16993efc3014SJulian Elischer 	struct in_addr pkt_dst;
1700df8bae1dSRodney W. Grimes 	struct ifnet *destifp;
1701b9234fafSSam Leffler #if defined(IPSEC) || defined(FAST_IPSEC)
17026a800098SYoshinobu Inoue 	struct ifnet dummyifp;
17036a800098SYoshinobu Inoue #endif
1704df8bae1dSRodney W. Grimes 
1705df8bae1dSRodney W. Grimes 	dest = 0;
17063efc3014SJulian Elischer 	/*
17073efc3014SJulian Elischer 	 * Cache the destination address of the packet; this may be
17083efc3014SJulian Elischer 	 * changed by use of 'ipfw fwd'.
17093efc3014SJulian Elischer 	 */
17102b25acc1SLuigi Rizzo 	pkt_dst = next_hop ? next_hop->sin_addr : ip->ip_dst;
17113efc3014SJulian Elischer 
1712df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1713df8bae1dSRodney W. Grimes 	if (ipprintfs)
171461ce519bSPoul-Henning Kamp 		printf("forward: src %lx dst %lx ttl %x\n",
17153efc3014SJulian Elischer 		    (u_long)ip->ip_src.s_addr, (u_long)pkt_dst.s_addr,
1716162886e2SBruce Evans 		    ip->ip_ttl);
1717df8bae1dSRodney W. Grimes #endif
1718100ba1a6SJordan K. Hubbard 
1719100ba1a6SJordan K. Hubbard 
17203efc3014SJulian Elischer 	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(pkt_dst) == 0) {
1721df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1722df8bae1dSRodney W. Grimes 		m_freem(m);
1723df8bae1dSRodney W. Grimes 		return;
1724df8bae1dSRodney W. Grimes 	}
17251b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
17261b968362SDag-Erling Smørgrav 	if (!ipstealth) {
17271b968362SDag-Erling Smørgrav #endif
1728df8bae1dSRodney W. Grimes 		if (ip->ip_ttl <= IPTTLDEC) {
17291b968362SDag-Erling Smørgrav 			icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
17301b968362SDag-Erling Smørgrav 			    dest, 0);
1731df8bae1dSRodney W. Grimes 			return;
1732df8bae1dSRodney W. Grimes 		}
17331b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
17341b968362SDag-Erling Smørgrav 	}
17351b968362SDag-Erling Smørgrav #endif
1736df8bae1dSRodney W. Grimes 
17373efc3014SJulian Elischer 	if (ip_rtaddr(pkt_dst, &ipforward_rt) == 0) {
1738df8bae1dSRodney W. Grimes 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
1739df8bae1dSRodney W. Grimes 		return;
17404078ffb1SRuslan Ermilov 	} else
1741df8bae1dSRodney W. Grimes 		rt = ipforward_rt.ro_rt;
1742df8bae1dSRodney W. Grimes 
1743df8bae1dSRodney W. Grimes 	/*
1744bfef7ed4SIan Dowse 	 * Save the IP header and at most 8 bytes of the payload,
1745bfef7ed4SIan Dowse 	 * in case we need to generate an ICMP message to the src.
1746bfef7ed4SIan Dowse 	 *
17474d2e3692SLuigi Rizzo 	 * XXX this can be optimized a lot by saving the data in a local
17484d2e3692SLuigi Rizzo 	 * buffer on the stack (72 bytes at most), and only allocating the
17494d2e3692SLuigi Rizzo 	 * mbuf if really necessary. The vast majority of the packets
17504d2e3692SLuigi Rizzo 	 * are forwarded without having to send an ICMP back (either
17514d2e3692SLuigi Rizzo 	 * because unnecessary, or because rate limited), so we are
17524d2e3692SLuigi Rizzo 	 * really we are wasting a lot of work here.
17534d2e3692SLuigi Rizzo 	 *
1754bfef7ed4SIan Dowse 	 * We don't use m_copy() because it might return a reference
1755bfef7ed4SIan Dowse 	 * to a shared cluster. Both this function and ip_output()
1756bfef7ed4SIan Dowse 	 * assume exclusive access to the IP header in `m', so any
1757bfef7ed4SIan Dowse 	 * data in a cluster may change before we reach icmp_error().
1758df8bae1dSRodney W. Grimes 	 */
1759bfef7ed4SIan Dowse 	MGET(mcopy, M_DONTWAIT, m->m_type);
1760bfef7ed4SIan Dowse 	if (mcopy != NULL) {
1761bfef7ed4SIan Dowse 		M_COPY_PKTHDR(mcopy, m);
176253be11f6SPoul-Henning Kamp 		mcopy->m_len = imin((ip->ip_hl << 2) + 8,
1763bfef7ed4SIan Dowse 		    (int)ip->ip_len);
1764bfef7ed4SIan Dowse 		m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
1765e316463aSRobert Watson #ifdef MAC
1766e316463aSRobert Watson 		/*
1767e316463aSRobert Watson 		 * XXXMAC: This will eventually become an explicit
1768e316463aSRobert Watson 		 * labeling point.
1769e316463aSRobert Watson 		 */
1770e316463aSRobert Watson 		mac_create_mbuf_from_mbuf(m, mcopy);
1771e316463aSRobert Watson #endif
1772bfef7ed4SIan Dowse 	}
177304287599SRuslan Ermilov 
177404287599SRuslan Ermilov #ifdef IPSTEALTH
177504287599SRuslan Ermilov 	if (!ipstealth) {
177604287599SRuslan Ermilov #endif
177704287599SRuslan Ermilov 		ip->ip_ttl -= IPTTLDEC;
177804287599SRuslan Ermilov #ifdef IPSTEALTH
177904287599SRuslan Ermilov 	}
178004287599SRuslan Ermilov #endif
1781df8bae1dSRodney W. Grimes 
1782df8bae1dSRodney W. Grimes 	/*
1783df8bae1dSRodney W. Grimes 	 * If forwarding packet using same interface that it came in on,
1784df8bae1dSRodney W. Grimes 	 * perhaps should send a redirect to sender to shortcut a hop.
1785df8bae1dSRodney W. Grimes 	 * Only send redirect if source is sending directly to us,
1786df8bae1dSRodney W. Grimes 	 * and if packet was not source routed (or has any options).
1787df8bae1dSRodney W. Grimes 	 * Also, don't send redirect if forwarding using a default route
1788df8bae1dSRodney W. Grimes 	 * or a route modified by a redirect.
1789df8bae1dSRodney W. Grimes 	 */
1790df8bae1dSRodney W. Grimes 	if (rt->rt_ifp == m->m_pkthdr.rcvif &&
1791df8bae1dSRodney W. Grimes 	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
1792df8bae1dSRodney W. Grimes 	    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
17932b25acc1SLuigi Rizzo 	    ipsendredirects && !srcrt && !next_hop) {
1794df8bae1dSRodney W. Grimes #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
1795df8bae1dSRodney W. Grimes 		u_long src = ntohl(ip->ip_src.s_addr);
1796df8bae1dSRodney W. Grimes 
1797df8bae1dSRodney W. Grimes 		if (RTA(rt) &&
1798df8bae1dSRodney W. Grimes 		    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1799df8bae1dSRodney W. Grimes 		    if (rt->rt_flags & RTF_GATEWAY)
1800df8bae1dSRodney W. Grimes 			dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
1801df8bae1dSRodney W. Grimes 		    else
18023efc3014SJulian Elischer 			dest = pkt_dst.s_addr;
1803df8bae1dSRodney W. Grimes 		    /* Router requirements says to only send host redirects */
1804df8bae1dSRodney W. Grimes 		    type = ICMP_REDIRECT;
1805df8bae1dSRodney W. Grimes 		    code = ICMP_REDIRECT_HOST;
1806df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1807df8bae1dSRodney W. Grimes 		    if (ipprintfs)
1808df8bae1dSRodney W. Grimes 		        printf("redirect (%d) to %lx\n", code, (u_long)dest);
1809df8bae1dSRodney W. Grimes #endif
1810df8bae1dSRodney W. Grimes 		}
1811df8bae1dSRodney W. Grimes 	}
1812df8bae1dSRodney W. Grimes 
1813ea779ff3SLuigi Rizzo     {
1814ea779ff3SLuigi Rizzo 	struct m_hdr tag;
1815ea779ff3SLuigi Rizzo 
1816ea779ff3SLuigi Rizzo 	if (next_hop) {
1817ea779ff3SLuigi Rizzo 		/* Pass IPFORWARD info if available */
1818ea779ff3SLuigi Rizzo 
1819ea779ff3SLuigi Rizzo 		tag.mh_type = MT_TAG;
1820ea779ff3SLuigi Rizzo 		tag.mh_flags = PACKET_TAG_IPFORWARD;
1821ea779ff3SLuigi Rizzo 		tag.mh_data = (caddr_t)next_hop;
1822ea779ff3SLuigi Rizzo 		tag.mh_next = m;
1823ea779ff3SLuigi Rizzo 		m = (struct mbuf *)&tag;
1824ea779ff3SLuigi Rizzo 	}
1825b97d15cbSGarrett Wollman 	error = ip_output(m, (struct mbuf *)0, &ipforward_rt,
18265d846453SSam Leffler 			  IP_FORWARDING, 0, NULL);
1827ea779ff3SLuigi Rizzo     }
1828df8bae1dSRodney W. Grimes 	if (error)
1829df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1830df8bae1dSRodney W. Grimes 	else {
1831df8bae1dSRodney W. Grimes 		ipstat.ips_forward++;
1832df8bae1dSRodney W. Grimes 		if (type)
1833df8bae1dSRodney W. Grimes 			ipstat.ips_redirectsent++;
1834df8bae1dSRodney W. Grimes 		else {
18351f91d8c5SDavid Greenman 			if (mcopy) {
18361f91d8c5SDavid Greenman 				ipflow_create(&ipforward_rt, mcopy);
1837df8bae1dSRodney W. Grimes 				m_freem(mcopy);
18381f91d8c5SDavid Greenman 			}
1839df8bae1dSRodney W. Grimes 			return;
1840df8bae1dSRodney W. Grimes 		}
1841df8bae1dSRodney W. Grimes 	}
1842df8bae1dSRodney W. Grimes 	if (mcopy == NULL)
1843df8bae1dSRodney W. Grimes 		return;
1844df8bae1dSRodney W. Grimes 	destifp = NULL;
1845df8bae1dSRodney W. Grimes 
1846df8bae1dSRodney W. Grimes 	switch (error) {
1847df8bae1dSRodney W. Grimes 
1848df8bae1dSRodney W. Grimes 	case 0:				/* forwarded, but need redirect */
1849df8bae1dSRodney W. Grimes 		/* type, code set above */
1850df8bae1dSRodney W. Grimes 		break;
1851df8bae1dSRodney W. Grimes 
1852df8bae1dSRodney W. Grimes 	case ENETUNREACH:		/* shouldn't happen, checked above */
1853df8bae1dSRodney W. Grimes 	case EHOSTUNREACH:
1854df8bae1dSRodney W. Grimes 	case ENETDOWN:
1855df8bae1dSRodney W. Grimes 	case EHOSTDOWN:
1856df8bae1dSRodney W. Grimes 	default:
1857df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1858df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_HOST;
1859df8bae1dSRodney W. Grimes 		break;
1860df8bae1dSRodney W. Grimes 
1861df8bae1dSRodney W. Grimes 	case EMSGSIZE:
1862df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1863df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_NEEDFRAG;
18645d846453SSam Leffler #ifdef IPSEC
18656a800098SYoshinobu Inoue 		/*
18666a800098SYoshinobu Inoue 		 * If the packet is routed over IPsec tunnel, tell the
18676a800098SYoshinobu Inoue 		 * originator the tunnel MTU.
18686a800098SYoshinobu Inoue 		 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
18696a800098SYoshinobu Inoue 		 * XXX quickhack!!!
18706a800098SYoshinobu Inoue 		 */
18716a800098SYoshinobu Inoue 		if (ipforward_rt.ro_rt) {
18726a800098SYoshinobu Inoue 			struct secpolicy *sp = NULL;
18736a800098SYoshinobu Inoue 			int ipsecerror;
18746a800098SYoshinobu Inoue 			int ipsechdr;
18756a800098SYoshinobu Inoue 			struct route *ro;
18766a800098SYoshinobu Inoue 
18776a800098SYoshinobu Inoue 			sp = ipsec4_getpolicybyaddr(mcopy,
18786a800098SYoshinobu Inoue 						    IPSEC_DIR_OUTBOUND,
18796a800098SYoshinobu Inoue 			                            IP_FORWARDING,
18806a800098SYoshinobu Inoue 			                            &ipsecerror);
18816a800098SYoshinobu Inoue 
18826a800098SYoshinobu Inoue 			if (sp == NULL)
18836a800098SYoshinobu Inoue 				destifp = ipforward_rt.ro_rt->rt_ifp;
18846a800098SYoshinobu Inoue 			else {
18856a800098SYoshinobu Inoue 				/* count IPsec header size */
18866a800098SYoshinobu Inoue 				ipsechdr = ipsec4_hdrsiz(mcopy,
18876a800098SYoshinobu Inoue 							 IPSEC_DIR_OUTBOUND,
18886a800098SYoshinobu Inoue 							 NULL);
18896a800098SYoshinobu Inoue 
18906a800098SYoshinobu Inoue 				/*
18916a800098SYoshinobu Inoue 				 * find the correct route for outer IPv4
18926a800098SYoshinobu Inoue 				 * header, compute tunnel MTU.
18936a800098SYoshinobu Inoue 				 *
18946a800098SYoshinobu Inoue 				 * XXX BUG ALERT
18956a800098SYoshinobu Inoue 				 * The "dummyifp" code relies upon the fact
18966a800098SYoshinobu Inoue 				 * that icmp_error() touches only ifp->if_mtu.
18976a800098SYoshinobu Inoue 				 */
18986a800098SYoshinobu Inoue 				/*XXX*/
18996a800098SYoshinobu Inoue 				destifp = NULL;
19006a800098SYoshinobu Inoue 				if (sp->req != NULL
19016a800098SYoshinobu Inoue 				 && sp->req->sav != NULL
19026a800098SYoshinobu Inoue 				 && sp->req->sav->sah != NULL) {
19036a800098SYoshinobu Inoue 					ro = &sp->req->sav->sah->sa_route;
19046a800098SYoshinobu Inoue 					if (ro->ro_rt && ro->ro_rt->rt_ifp) {
19056a800098SYoshinobu Inoue 						dummyifp.if_mtu =
19066a800098SYoshinobu Inoue 						    ro->ro_rt->rt_ifp->if_mtu;
19076a800098SYoshinobu Inoue 						dummyifp.if_mtu -= ipsechdr;
19086a800098SYoshinobu Inoue 						destifp = &dummyifp;
19096a800098SYoshinobu Inoue 					}
19106a800098SYoshinobu Inoue 				}
19116a800098SYoshinobu Inoue 
19126a800098SYoshinobu Inoue 				key_freesp(sp);
19136a800098SYoshinobu Inoue 			}
19146a800098SYoshinobu Inoue 		}
1915b9234fafSSam Leffler #elif FAST_IPSEC
1916b9234fafSSam Leffler 		/*
1917b9234fafSSam Leffler 		 * If the packet is routed over IPsec tunnel, tell the
1918b9234fafSSam Leffler 		 * originator the tunnel MTU.
1919b9234fafSSam Leffler 		 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
1920b9234fafSSam Leffler 		 * XXX quickhack!!!
1921b9234fafSSam Leffler 		 */
1922b9234fafSSam Leffler 		if (ipforward_rt.ro_rt) {
1923b9234fafSSam Leffler 			struct secpolicy *sp = NULL;
1924b9234fafSSam Leffler 			int ipsecerror;
1925b9234fafSSam Leffler 			int ipsechdr;
1926b9234fafSSam Leffler 			struct route *ro;
1927b9234fafSSam Leffler 
1928b9234fafSSam Leffler 			sp = ipsec_getpolicybyaddr(mcopy,
1929b9234fafSSam Leffler 						   IPSEC_DIR_OUTBOUND,
1930b9234fafSSam Leffler 			                           IP_FORWARDING,
1931b9234fafSSam Leffler 			                           &ipsecerror);
1932b9234fafSSam Leffler 
1933b9234fafSSam Leffler 			if (sp == NULL)
1934b9234fafSSam Leffler 				destifp = ipforward_rt.ro_rt->rt_ifp;
1935b9234fafSSam Leffler 			else {
1936b9234fafSSam Leffler 				/* count IPsec header size */
1937b9234fafSSam Leffler 				ipsechdr = ipsec4_hdrsiz(mcopy,
1938b9234fafSSam Leffler 							 IPSEC_DIR_OUTBOUND,
1939b9234fafSSam Leffler 							 NULL);
1940b9234fafSSam Leffler 
1941b9234fafSSam Leffler 				/*
1942b9234fafSSam Leffler 				 * find the correct route for outer IPv4
1943b9234fafSSam Leffler 				 * header, compute tunnel MTU.
1944b9234fafSSam Leffler 				 *
1945b9234fafSSam Leffler 				 * XXX BUG ALERT
1946b9234fafSSam Leffler 				 * The "dummyifp" code relies upon the fact
1947b9234fafSSam Leffler 				 * that icmp_error() touches only ifp->if_mtu.
1948b9234fafSSam Leffler 				 */
1949b9234fafSSam Leffler 				/*XXX*/
1950b9234fafSSam Leffler 				destifp = NULL;
1951b9234fafSSam Leffler 				if (sp->req != NULL
1952b9234fafSSam Leffler 				 && sp->req->sav != NULL
1953b9234fafSSam Leffler 				 && sp->req->sav->sah != NULL) {
1954b9234fafSSam Leffler 					ro = &sp->req->sav->sah->sa_route;
1955b9234fafSSam Leffler 					if (ro->ro_rt && ro->ro_rt->rt_ifp) {
1956b9234fafSSam Leffler 						dummyifp.if_mtu =
1957b9234fafSSam Leffler 						    ro->ro_rt->rt_ifp->if_mtu;
1958b9234fafSSam Leffler 						dummyifp.if_mtu -= ipsechdr;
1959b9234fafSSam Leffler 						destifp = &dummyifp;
1960b9234fafSSam Leffler 					}
1961b9234fafSSam Leffler 				}
1962b9234fafSSam Leffler 
1963b9234fafSSam Leffler 				KEY_FREESP(&sp);
1964b9234fafSSam Leffler 			}
1965b9234fafSSam Leffler 		}
1966b9234fafSSam Leffler #else /* !IPSEC && !FAST_IPSEC */
19675d846453SSam Leffler 		if (ipforward_rt.ro_rt)
19685d846453SSam Leffler 			destifp = ipforward_rt.ro_rt->rt_ifp;
19696a800098SYoshinobu Inoue #endif /*IPSEC*/
1970df8bae1dSRodney W. Grimes 		ipstat.ips_cantfrag++;
1971df8bae1dSRodney W. Grimes 		break;
1972df8bae1dSRodney W. Grimes 
1973df8bae1dSRodney W. Grimes 	case ENOBUFS:
1974df8bae1dSRodney W. Grimes 		type = ICMP_SOURCEQUENCH;
1975df8bae1dSRodney W. Grimes 		code = 0;
1976df8bae1dSRodney W. Grimes 		break;
19773a06e3e0SRuslan Ermilov 
19783a06e3e0SRuslan Ermilov 	case EACCES:			/* ipfw denied packet */
19793a06e3e0SRuslan Ermilov 		m_freem(mcopy);
19803a06e3e0SRuslan Ermilov 		return;
1981df8bae1dSRodney W. Grimes 	}
1982df8bae1dSRodney W. Grimes 	icmp_error(mcopy, type, code, dest, destifp);
1983df8bae1dSRodney W. Grimes }
1984df8bae1dSRodney W. Grimes 
198582c23ebaSBill Fenner void
198682c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m)
198782c23ebaSBill Fenner 	register struct inpcb *inp;
198882c23ebaSBill Fenner 	register struct mbuf **mp;
198982c23ebaSBill Fenner 	register struct ip *ip;
199082c23ebaSBill Fenner 	register struct mbuf *m;
199182c23ebaSBill Fenner {
199282c23ebaSBill Fenner 	if (inp->inp_socket->so_options & SO_TIMESTAMP) {
199382c23ebaSBill Fenner 		struct timeval tv;
199482c23ebaSBill Fenner 
199582c23ebaSBill Fenner 		microtime(&tv);
199682c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
199782c23ebaSBill Fenner 			SCM_TIMESTAMP, SOL_SOCKET);
199882c23ebaSBill Fenner 		if (*mp)
199982c23ebaSBill Fenner 			mp = &(*mp)->m_next;
20004cc20ab1SSeigo Tanimura 	}
200182c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVDSTADDR) {
200282c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
200382c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
200482c23ebaSBill Fenner 		if (*mp)
200582c23ebaSBill Fenner 			mp = &(*mp)->m_next;
200682c23ebaSBill Fenner 	}
200782c23ebaSBill Fenner #ifdef notyet
200882c23ebaSBill Fenner 	/* XXX
200982c23ebaSBill Fenner 	 * Moving these out of udp_input() made them even more broken
201082c23ebaSBill Fenner 	 * than they already were.
201182c23ebaSBill Fenner 	 */
201282c23ebaSBill Fenner 	/* options were tossed already */
201382c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVOPTS) {
201482c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) opts_deleted_above,
201582c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
201682c23ebaSBill Fenner 		if (*mp)
201782c23ebaSBill Fenner 			mp = &(*mp)->m_next;
201882c23ebaSBill Fenner 	}
201982c23ebaSBill Fenner 	/* ip_srcroute doesn't do what we want here, need to fix */
202082c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVRETOPTS) {
202182c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) ip_srcroute(),
202282c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
202382c23ebaSBill Fenner 		if (*mp)
202482c23ebaSBill Fenner 			mp = &(*mp)->m_next;
202582c23ebaSBill Fenner 	}
202682c23ebaSBill Fenner #endif
202782c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVIF) {
2028d314ad7bSJulian Elischer 		struct ifnet *ifp;
2029d314ad7bSJulian Elischer 		struct sdlbuf {
203082c23ebaSBill Fenner 			struct sockaddr_dl sdl;
2031d314ad7bSJulian Elischer 			u_char	pad[32];
2032d314ad7bSJulian Elischer 		} sdlbuf;
2033d314ad7bSJulian Elischer 		struct sockaddr_dl *sdp;
2034d314ad7bSJulian Elischer 		struct sockaddr_dl *sdl2 = &sdlbuf.sdl;
203582c23ebaSBill Fenner 
2036d314ad7bSJulian Elischer 		if (((ifp = m->m_pkthdr.rcvif))
2037d314ad7bSJulian Elischer 		&& ( ifp->if_index && (ifp->if_index <= if_index))) {
2038f9132cebSJonathan Lemon 			sdp = (struct sockaddr_dl *)
2039f9132cebSJonathan Lemon 			    (ifaddr_byindex(ifp->if_index)->ifa_addr);
2040d314ad7bSJulian Elischer 			/*
2041d314ad7bSJulian Elischer 			 * Change our mind and don't try copy.
2042d314ad7bSJulian Elischer 			 */
2043d314ad7bSJulian Elischer 			if ((sdp->sdl_family != AF_LINK)
2044d314ad7bSJulian Elischer 			|| (sdp->sdl_len > sizeof(sdlbuf))) {
2045d314ad7bSJulian Elischer 				goto makedummy;
2046d314ad7bSJulian Elischer 			}
2047d314ad7bSJulian Elischer 			bcopy(sdp, sdl2, sdp->sdl_len);
2048d314ad7bSJulian Elischer 		} else {
2049d314ad7bSJulian Elischer makedummy:
2050d314ad7bSJulian Elischer 			sdl2->sdl_len
2051d314ad7bSJulian Elischer 				= offsetof(struct sockaddr_dl, sdl_data[0]);
2052d314ad7bSJulian Elischer 			sdl2->sdl_family = AF_LINK;
2053d314ad7bSJulian Elischer 			sdl2->sdl_index = 0;
2054d314ad7bSJulian Elischer 			sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;
2055d314ad7bSJulian Elischer 		}
2056d314ad7bSJulian Elischer 		*mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,
205782c23ebaSBill Fenner 			IP_RECVIF, IPPROTO_IP);
205882c23ebaSBill Fenner 		if (*mp)
205982c23ebaSBill Fenner 			mp = &(*mp)->m_next;
206082c23ebaSBill Fenner 	}
206182c23ebaSBill Fenner }
206282c23ebaSBill Fenner 
20634d2e3692SLuigi Rizzo /*
20644d2e3692SLuigi Rizzo  * XXX these routines are called from the upper part of the kernel.
20654d2e3692SLuigi Rizzo  * They need to be locked when we remove Giant.
20664d2e3692SLuigi Rizzo  *
20674d2e3692SLuigi Rizzo  * They could also be moved to ip_mroute.c, since all the RSVP
20684d2e3692SLuigi Rizzo  *  handling is done there already.
20694d2e3692SLuigi Rizzo  */
20704d2e3692SLuigi Rizzo static int ip_rsvp_on;
20714d2e3692SLuigi Rizzo struct socket *ip_rsvpd;
2072df8bae1dSRodney W. Grimes int
2073f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so)
2074f0068c4aSGarrett Wollman {
2075f0068c4aSGarrett Wollman 	if (so->so_type != SOCK_RAW ||
2076f0068c4aSGarrett Wollman 	    so->so_proto->pr_protocol != IPPROTO_RSVP)
2077f0068c4aSGarrett Wollman 		return EOPNOTSUPP;
2078f0068c4aSGarrett Wollman 
2079f0068c4aSGarrett Wollman 	if (ip_rsvpd != NULL)
2080f0068c4aSGarrett Wollman 		return EADDRINUSE;
2081f0068c4aSGarrett Wollman 
2082f0068c4aSGarrett Wollman 	ip_rsvpd = so;
20831c5de19aSGarrett Wollman 	/*
20841c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-increment
20851c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
20861c5de19aSGarrett Wollman 	 */
20871c5de19aSGarrett Wollman 	if (!ip_rsvp_on) {
20881c5de19aSGarrett Wollman 		ip_rsvp_on = 1;
20891c5de19aSGarrett Wollman 		rsvp_on++;
20901c5de19aSGarrett Wollman 	}
2091f0068c4aSGarrett Wollman 
2092f0068c4aSGarrett Wollman 	return 0;
2093f0068c4aSGarrett Wollman }
2094f0068c4aSGarrett Wollman 
2095f0068c4aSGarrett Wollman int
2096f0068c4aSGarrett Wollman ip_rsvp_done(void)
2097f0068c4aSGarrett Wollman {
2098f0068c4aSGarrett Wollman 	ip_rsvpd = NULL;
20991c5de19aSGarrett Wollman 	/*
21001c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-decrement
21011c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
21021c5de19aSGarrett Wollman 	 */
21031c5de19aSGarrett Wollman 	if (ip_rsvp_on) {
21041c5de19aSGarrett Wollman 		ip_rsvp_on = 0;
21051c5de19aSGarrett Wollman 		rsvp_on--;
21061c5de19aSGarrett Wollman 	}
2107f0068c4aSGarrett Wollman 	return 0;
2108f0068c4aSGarrett Wollman }
2109bbb4330bSLuigi Rizzo 
2110bbb4330bSLuigi Rizzo void
2111bbb4330bSLuigi Rizzo rsvp_input(struct mbuf *m, int off)	/* XXX must fixup manually */
2112bbb4330bSLuigi Rizzo {
2113bbb4330bSLuigi Rizzo 	if (rsvp_input_p) { /* call the real one if loaded */
2114bbb4330bSLuigi Rizzo 		rsvp_input_p(m, off);
2115bbb4330bSLuigi Rizzo 		return;
2116bbb4330bSLuigi Rizzo 	}
2117bbb4330bSLuigi Rizzo 
2118bbb4330bSLuigi Rizzo 	/* Can still get packets with rsvp_on = 0 if there is a local member
2119bbb4330bSLuigi Rizzo 	 * of the group to which the RSVP packet is addressed.  But in this
2120bbb4330bSLuigi Rizzo 	 * case we want to throw the packet away.
2121bbb4330bSLuigi Rizzo 	 */
2122bbb4330bSLuigi Rizzo 
2123bbb4330bSLuigi Rizzo 	if (!rsvp_on) {
2124bbb4330bSLuigi Rizzo 		m_freem(m);
2125bbb4330bSLuigi Rizzo 		return;
2126bbb4330bSLuigi Rizzo 	}
2127bbb4330bSLuigi Rizzo 
2128bbb4330bSLuigi Rizzo 	if (ip_rsvpd != NULL) {
2129bbb4330bSLuigi Rizzo 		rip_input(m, off);
2130bbb4330bSLuigi Rizzo 		return;
2131bbb4330bSLuigi Rizzo 	}
2132bbb4330bSLuigi Rizzo 	/* Drop the packet */
2133bbb4330bSLuigi Rizzo 	m_freem(m);
2134bbb4330bSLuigi Rizzo }
2135