xref: /freebsd/sys/netinet/ip_input.c (revision 9967cafc49317bb9dc73646958d2f9ef9cadb227)
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 
128df285b3dSMike Silbersack static int	ip_sendsourcequench = 0;
129df285b3dSMike Silbersack SYSCTL_INT(_net_inet_ip, OID_AUTO, sendsourcequench, CTLFLAG_RW,
130df285b3dSMike Silbersack 	&ip_sendsourcequench, 0,
131df285b3dSMike Silbersack 	"Enable the transmission of source quench packets");
132df285b3dSMike Silbersack 
133823db0e9SDon Lewis /*
134823db0e9SDon Lewis  * XXX - Setting ip_checkinterface mostly implements the receive side of
135823db0e9SDon Lewis  * the Strong ES model described in RFC 1122, but since the routing table
136a8f12100SDon Lewis  * and transmit implementation do not implement the Strong ES model,
137823db0e9SDon Lewis  * setting this to 1 results in an odd hybrid.
1383f67c834SDon Lewis  *
139a8f12100SDon Lewis  * XXX - ip_checkinterface currently must be disabled if you use ipnat
140a8f12100SDon Lewis  * to translate the destination address to another local interface.
1413f67c834SDon Lewis  *
1423f67c834SDon Lewis  * XXX - ip_checkinterface must be disabled if you add IP aliases
1433f67c834SDon Lewis  * to the loopback interface instead of the interface where the
1443f67c834SDon Lewis  * packets for those addresses are received.
145823db0e9SDon Lewis  */
146b3e95d4eSJonathan Lemon static int	ip_checkinterface = 1;
147b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW,
148b3e95d4eSJonathan Lemon     &ip_checkinterface, 0, "Verify packet arrives on correct interface");
149b3e95d4eSJonathan Lemon 
150df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1510312fbe9SPoul-Henning Kamp static int	ipprintfs = 0;
152df8bae1dSRodney W. Grimes #endif
153df8bae1dSRodney W. Grimes 
154ca925d9cSJonathan Lemon static int	ipqmaxlen = IFQ_MAXLEN;
155ca925d9cSJonathan Lemon 
156df8bae1dSRodney W. Grimes extern	struct domain inetdomain;
157f0ffb944SJulian Elischer extern	struct protosw inetsw[];
158df8bae1dSRodney W. Grimes u_char	ip_protox[IPPROTO_MAX];
15959562606SGarrett Wollman struct	in_ifaddrhead in_ifaddrhead; 		/* first inet address */
160ca925d9cSJonathan Lemon struct	in_ifaddrhashhead *in_ifaddrhashtbl;	/* inet addr hash table  */
161ca925d9cSJonathan Lemon u_long 	in_ifaddrhmask;				/* mask for hash table */
162ca925d9cSJonathan Lemon 
163afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW,
1643d177f46SBill Fumerola     &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue");
1650312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
1663d177f46SBill Fumerola     &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue");
167df8bae1dSRodney W. Grimes 
168f23b4c91SGarrett Wollman struct ipstat ipstat;
169c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW,
1703d177f46SBill Fumerola     &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)");
171194a213eSAndrey A. Chernov 
172194a213eSAndrey A. Chernov /* Packet reassembly stuff */
173194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2      6
174194a213eSAndrey A. Chernov #define IPREASS_NHASH           (1 << IPREASS_NHASH_LOG2)
175194a213eSAndrey A. Chernov #define IPREASS_HMASK           (IPREASS_NHASH - 1)
176194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \
177831a80b0SMatthew Dillon 	(((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
178194a213eSAndrey A. Chernov 
179462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH];
180194a213eSAndrey A. Chernov static int    nipq = 0;         /* total # of reass queues */
181194a213eSAndrey A. Chernov static int    maxnipq;
182f23b4c91SGarrett Wollman 
1830312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU
1840312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
1853d177f46SBill Fumerola     &ip_mtu, 0, "Default MTU");
1860312fbe9SPoul-Henning Kamp #endif
1870312fbe9SPoul-Henning Kamp 
1881b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
1891b968362SDag-Erling Smørgrav static int	ipstealth = 0;
1901b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW,
1911b968362SDag-Erling Smørgrav     &ipstealth, 0, "");
1921b968362SDag-Erling Smørgrav #endif
1931b968362SDag-Erling Smørgrav 
194cfe8b629SGarrett Wollman 
19523bf9953SPoul-Henning Kamp /* Firewall hooks */
19623bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr;
1979fcc0795SLuigi Rizzo int fw_enable = 1 ;
19897850a5dSLuigi Rizzo int fw_one_pass = 1;
199e7319babSPoul-Henning Kamp 
200db69a05dSPaul Saab /* Dummynet hooks */
201db69a05dSPaul Saab ip_dn_io_t *ip_dn_io_ptr;
202b715f178SLuigi Rizzo 
203afed1b49SDarren Reed 
204e7319babSPoul-Henning Kamp /*
2054d2e3692SLuigi Rizzo  * XXX this is ugly -- the following two global variables are
2064d2e3692SLuigi Rizzo  * used to store packet state while it travels through the stack.
2074d2e3692SLuigi Rizzo  * Note that the code even makes assumptions on the size and
2084d2e3692SLuigi Rizzo  * alignment of fields inside struct ip_srcrt so e.g. adding some
2094d2e3692SLuigi Rizzo  * fields will break the code. This needs to be fixed.
2104d2e3692SLuigi Rizzo  *
211df8bae1dSRodney W. Grimes  * We need to save the IP options in case a protocol wants to respond
212df8bae1dSRodney W. Grimes  * to an incoming packet over the same route if the packet got here
213df8bae1dSRodney W. Grimes  * using IP source routing.  This allows connection establishment and
214df8bae1dSRodney W. Grimes  * maintenance when the remote end is on a network that is not known
215df8bae1dSRodney W. Grimes  * to us.
216df8bae1dSRodney W. Grimes  */
2170312fbe9SPoul-Henning Kamp static int	ip_nhops = 0;
218df8bae1dSRodney W. Grimes static	struct ip_srcrt {
219df8bae1dSRodney W. Grimes 	struct	in_addr dst;			/* final destination */
220df8bae1dSRodney W. Grimes 	char	nop;				/* one NOP to align */
221df8bae1dSRodney W. Grimes 	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
222df8bae1dSRodney W. Grimes 	struct	in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
223df8bae1dSRodney W. Grimes } ip_srcrt;
224df8bae1dSRodney W. Grimes 
2254d77a549SAlfred Perlstein static void	save_rte(u_char *, struct in_addr);
2262b25acc1SLuigi Rizzo static int	ip_dooptions(struct mbuf *m, int,
2272b25acc1SLuigi Rizzo 			struct sockaddr_in *next_hop);
2282b25acc1SLuigi Rizzo static void	ip_forward(struct mbuf *m, int srcrt,
2292b25acc1SLuigi Rizzo 			struct sockaddr_in *next_hop);
2304d77a549SAlfred Perlstein static void	ip_freef(struct ipqhead *, struct ipq *);
2312b25acc1SLuigi Rizzo static struct	mbuf *ip_reass(struct mbuf *, struct ipqhead *,
2322b25acc1SLuigi Rizzo 		struct ipq *, u_int32_t *, u_int16_t *);
2334d77a549SAlfred Perlstein static void	ipintr(void);
2348948e4baSArchie Cobbs 
235df8bae1dSRodney W. Grimes /*
236df8bae1dSRodney W. Grimes  * IP initialization: fill in IP protocol switch table.
237df8bae1dSRodney W. Grimes  * All protocols not implemented in kernel go to raw IP protocol handler.
238df8bae1dSRodney W. Grimes  */
239df8bae1dSRodney W. Grimes void
240df8bae1dSRodney W. Grimes ip_init()
241df8bae1dSRodney W. Grimes {
242f0ffb944SJulian Elischer 	register struct protosw *pr;
243df8bae1dSRodney W. Grimes 	register int i;
244df8bae1dSRodney W. Grimes 
24559562606SGarrett Wollman 	TAILQ_INIT(&in_ifaddrhead);
246ca925d9cSJonathan Lemon 	in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask);
247f0ffb944SJulian Elischer 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
248df8bae1dSRodney W. Grimes 	if (pr == 0)
249df8bae1dSRodney W. Grimes 		panic("ip_init");
250df8bae1dSRodney W. Grimes 	for (i = 0; i < IPPROTO_MAX; i++)
251df8bae1dSRodney W. Grimes 		ip_protox[i] = pr - inetsw;
252f0ffb944SJulian Elischer 	for (pr = inetdomain.dom_protosw;
253f0ffb944SJulian Elischer 	    pr < inetdomain.dom_protoswNPROTOSW; pr++)
254df8bae1dSRodney W. Grimes 		if (pr->pr_domain->dom_family == PF_INET &&
255df8bae1dSRodney W. Grimes 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
256df8bae1dSRodney W. Grimes 			ip_protox[pr->pr_protocol] = pr - inetsw;
257194a213eSAndrey A. Chernov 
258194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++)
259462b86feSPoul-Henning Kamp 	    TAILQ_INIT(&ipq[i]);
260194a213eSAndrey A. Chernov 
261194a213eSAndrey A. Chernov 	maxnipq = nmbclusters / 4;
26296c2b042SJesper Skriver 	ip_maxfragpackets = nmbclusters / 4;
263194a213eSAndrey A. Chernov 
26464dddc18SKris Kennaway #ifndef RANDOM_IP_ID
265227ee8a1SPoul-Henning Kamp 	ip_id = time_second & 0xffff;
26664dddc18SKris Kennaway #endif
267df8bae1dSRodney W. Grimes 	ipintrq.ifq_maxlen = ipqmaxlen;
2686008862bSJohn Baldwin 	mtx_init(&ipintrq.ifq_mtx, "ip_inq", NULL, MTX_DEF);
269bedbd47eSMike Smith 	ipintrq_present = 1;
270242c5536SPeter Wemm 
271242c5536SPeter Wemm 	register_netisr(NETISR_IP, ipintr);
272df8bae1dSRodney W. Grimes }
273df8bae1dSRodney W. Grimes 
2744d2e3692SLuigi Rizzo /*
2754d2e3692SLuigi Rizzo  * XXX watch out this one. It is perhaps used as a cache for
2764d2e3692SLuigi Rizzo  * the most recently used route ? it is cleared in in_addroute()
2774d2e3692SLuigi Rizzo  * when a new route is successfully created.
2784d2e3692SLuigi Rizzo  */
2791e3d5af0SRuslan Ermilov struct	route ipforward_rt;
280df8bae1dSRodney W. Grimes 
281df8bae1dSRodney W. Grimes /*
282df8bae1dSRodney W. Grimes  * Ip input routine.  Checksum and byte swap header.  If fragmented
283df8bae1dSRodney W. Grimes  * try to reassemble.  Process options.  Pass to next level.
284df8bae1dSRodney W. Grimes  */
285c67b1d17SGarrett Wollman void
286c67b1d17SGarrett Wollman ip_input(struct mbuf *m)
287df8bae1dSRodney W. Grimes {
28823bf9953SPoul-Henning Kamp 	struct ip *ip;
28923bf9953SPoul-Henning Kamp 	struct ipq *fp;
2905da9f8faSJosef Karthauser 	struct in_ifaddr *ia = NULL;
291ca925d9cSJonathan Lemon 	struct ifaddr *ifa;
292823db0e9SDon Lewis 	int    i, hlen, checkif;
29347c861ecSBrian Somers 	u_short sum;
2947538a9a0SJonathan Lemon 	struct in_addr pkt_dst;
2958948e4baSArchie Cobbs 	u_int32_t divert_info = 0;		/* packet divert/tee info */
2962b25acc1SLuigi Rizzo 	struct ip_fw_args args;
297c4ac87eaSDarren Reed #ifdef PFIL_HOOKS
298c4ac87eaSDarren Reed 	struct packet_filter_hook *pfh;
299c4ac87eaSDarren Reed 	struct mbuf *m0;
300c4ac87eaSDarren Reed 	int rv;
301c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */
302b9234fafSSam Leffler #ifdef FAST_IPSEC
303b9234fafSSam Leffler 	struct m_tag *mtag;
304b9234fafSSam Leffler 	struct tdb_ident *tdbi;
305b9234fafSSam Leffler 	struct secpolicy *sp;
306b9234fafSSam Leffler 	int s, error;
307b9234fafSSam Leffler #endif /* FAST_IPSEC */
308b715f178SLuigi Rizzo 
3092b25acc1SLuigi Rizzo 	args.eh = NULL;
3102b25acc1SLuigi Rizzo 	args.oif = NULL;
3112b25acc1SLuigi Rizzo 	args.rule = NULL;
3122b25acc1SLuigi Rizzo 	args.divert_rule = 0;			/* divert cookie */
3132b25acc1SLuigi Rizzo 	args.next_hop = NULL;
3148948e4baSArchie Cobbs 
3152b25acc1SLuigi Rizzo 	/* Grab info from MT_TAG mbufs prepended to the chain.	*/
3162b25acc1SLuigi Rizzo 	for (; m && m->m_type == MT_TAG; m = m->m_next) {
3175d846453SSam Leffler 		switch(m->_m_tag_id) {
3182b25acc1SLuigi Rizzo 		default:
3192b25acc1SLuigi Rizzo 			printf("ip_input: unrecognised MT_TAG tag %d\n",
3205d846453SSam Leffler 			    m->_m_tag_id);
3212b25acc1SLuigi Rizzo 			break;
3222b25acc1SLuigi Rizzo 
3232b25acc1SLuigi Rizzo 		case PACKET_TAG_DUMMYNET:
3242b25acc1SLuigi Rizzo 			args.rule = ((struct dn_pkt *)m)->rule;
3252b25acc1SLuigi Rizzo 			break;
3262b25acc1SLuigi Rizzo 
3272b25acc1SLuigi Rizzo 		case PACKET_TAG_DIVERT:
3287627c6cbSMaxime Henrion 			args.divert_rule = (intptr_t)m->m_hdr.mh_data & 0xffff;
3292b25acc1SLuigi Rizzo 			break;
3302b25acc1SLuigi Rizzo 
3312b25acc1SLuigi Rizzo 		case PACKET_TAG_IPFORWARD:
3322b25acc1SLuigi Rizzo 			args.next_hop = (struct sockaddr_in *)m->m_hdr.mh_data;
3332b25acc1SLuigi Rizzo 			break;
3342b25acc1SLuigi Rizzo 		}
3352b25acc1SLuigi Rizzo 	}
336df8bae1dSRodney W. Grimes 
337db40007dSAndrew R. Reiter 	KASSERT(m != NULL && (m->m_flags & M_PKTHDR) != 0,
338db40007dSAndrew R. Reiter 	    ("ip_input: no HDR"));
339db40007dSAndrew R. Reiter 
3402b25acc1SLuigi Rizzo 	if (args.rule) {	/* dummynet already filtered us */
3412b25acc1SLuigi Rizzo 		ip = mtod(m, struct ip *);
34253be11f6SPoul-Henning Kamp 		hlen = ip->ip_hl << 2;
3432b25acc1SLuigi Rizzo 		goto iphack ;
3442b25acc1SLuigi Rizzo 	}
3452b25acc1SLuigi Rizzo 
346df8bae1dSRodney W. Grimes 	ipstat.ips_total++;
34758938916SGarrett Wollman 
34858938916SGarrett Wollman 	if (m->m_pkthdr.len < sizeof(struct ip))
34958938916SGarrett Wollman 		goto tooshort;
35058938916SGarrett Wollman 
351df8bae1dSRodney W. Grimes 	if (m->m_len < sizeof (struct ip) &&
352df8bae1dSRodney W. Grimes 	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
353df8bae1dSRodney W. Grimes 		ipstat.ips_toosmall++;
354c67b1d17SGarrett Wollman 		return;
355df8bae1dSRodney W. Grimes 	}
356df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
35758938916SGarrett Wollman 
35853be11f6SPoul-Henning Kamp 	if (ip->ip_v != IPVERSION) {
359df8bae1dSRodney W. Grimes 		ipstat.ips_badvers++;
360df8bae1dSRodney W. Grimes 		goto bad;
361df8bae1dSRodney W. Grimes 	}
36258938916SGarrett Wollman 
36353be11f6SPoul-Henning Kamp 	hlen = ip->ip_hl << 2;
364df8bae1dSRodney W. Grimes 	if (hlen < sizeof(struct ip)) {	/* minimum header length */
365df8bae1dSRodney W. Grimes 		ipstat.ips_badhlen++;
366df8bae1dSRodney W. Grimes 		goto bad;
367df8bae1dSRodney W. Grimes 	}
368df8bae1dSRodney W. Grimes 	if (hlen > m->m_len) {
369df8bae1dSRodney W. Grimes 		if ((m = m_pullup(m, hlen)) == 0) {
370df8bae1dSRodney W. Grimes 			ipstat.ips_badhlen++;
371c67b1d17SGarrett Wollman 			return;
372df8bae1dSRodney W. Grimes 		}
373df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
374df8bae1dSRodney W. Grimes 	}
37533841545SHajimu UMEMOTO 
37633841545SHajimu UMEMOTO 	/* 127/8 must not appear on wire - RFC1122 */
37733841545SHajimu UMEMOTO 	if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
37833841545SHajimu UMEMOTO 	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
37933841545SHajimu UMEMOTO 		if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
38033841545SHajimu UMEMOTO 			ipstat.ips_badaddr++;
38133841545SHajimu UMEMOTO 			goto bad;
38233841545SHajimu UMEMOTO 		}
38333841545SHajimu UMEMOTO 	}
38433841545SHajimu UMEMOTO 
385db4f9cc7SJonathan Lemon 	if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
386db4f9cc7SJonathan Lemon 		sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
387db4f9cc7SJonathan Lemon 	} else {
38858938916SGarrett Wollman 		if (hlen == sizeof(struct ip)) {
38947c861ecSBrian Somers 			sum = in_cksum_hdr(ip);
39058938916SGarrett Wollman 		} else {
39147c861ecSBrian Somers 			sum = in_cksum(m, hlen);
39258938916SGarrett Wollman 		}
393db4f9cc7SJonathan Lemon 	}
39447c861ecSBrian Somers 	if (sum) {
395df8bae1dSRodney W. Grimes 		ipstat.ips_badsum++;
396df8bae1dSRodney W. Grimes 		goto bad;
397df8bae1dSRodney W. Grimes 	}
398df8bae1dSRodney W. Grimes 
399df8bae1dSRodney W. Grimes 	/*
400df8bae1dSRodney W. Grimes 	 * Convert fields to host representation.
401df8bae1dSRodney W. Grimes 	 */
402fd8e4ebcSMike Barcroft 	ip->ip_len = ntohs(ip->ip_len);
403df8bae1dSRodney W. Grimes 	if (ip->ip_len < hlen) {
404df8bae1dSRodney W. Grimes 		ipstat.ips_badlen++;
405df8bae1dSRodney W. Grimes 		goto bad;
406df8bae1dSRodney W. Grimes 	}
407fd8e4ebcSMike Barcroft 	ip->ip_off = ntohs(ip->ip_off);
408df8bae1dSRodney W. Grimes 
409df8bae1dSRodney W. Grimes 	/*
410df8bae1dSRodney W. Grimes 	 * Check that the amount of data in the buffers
411df8bae1dSRodney W. Grimes 	 * is as at least much as the IP header would have us expect.
412df8bae1dSRodney W. Grimes 	 * Trim mbufs if longer than we expect.
413df8bae1dSRodney W. Grimes 	 * Drop packet if shorter than we expect.
414df8bae1dSRodney W. Grimes 	 */
415df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len < ip->ip_len) {
41658938916SGarrett Wollman tooshort:
417df8bae1dSRodney W. Grimes 		ipstat.ips_tooshort++;
418df8bae1dSRodney W. Grimes 		goto bad;
419df8bae1dSRodney W. Grimes 	}
420df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len > ip->ip_len) {
421df8bae1dSRodney W. Grimes 		if (m->m_len == m->m_pkthdr.len) {
422df8bae1dSRodney W. Grimes 			m->m_len = ip->ip_len;
423df8bae1dSRodney W. Grimes 			m->m_pkthdr.len = ip->ip_len;
424df8bae1dSRodney W. Grimes 		} else
425df8bae1dSRodney W. Grimes 			m_adj(m, ip->ip_len - m->m_pkthdr.len);
426df8bae1dSRodney W. Grimes 	}
4273f67c834SDon Lewis 
4284dd1662bSUgen J.S. Antsilevich 	/*
4294dd1662bSUgen J.S. Antsilevich 	 * IpHack's section.
4304dd1662bSUgen J.S. Antsilevich 	 * Right now when no processing on packet has done
4314dd1662bSUgen J.S. Antsilevich 	 * and it is still fresh out of network we do our black
4324dd1662bSUgen J.S. Antsilevich 	 * deals with it.
43393e0e116SJulian Elischer 	 * - Firewall: deny/allow/divert
434fed1c7e9SSøren Schmidt 	 * - Xlate: translate packet's addr/port (NAT).
435b715f178SLuigi Rizzo 	 * - Pipe: pass pkt through dummynet.
4364dd1662bSUgen J.S. Antsilevich 	 * - Wrap: fake packet's addr/port <unimpl.>
4374dd1662bSUgen J.S. Antsilevich 	 * - Encapsulate: put it in another IP and send out. <unimp.>
4384dd1662bSUgen J.S. Antsilevich  	 */
439b715f178SLuigi Rizzo 
440b715f178SLuigi Rizzo iphack:
441df8bae1dSRodney W. Grimes 
442c4ac87eaSDarren Reed #ifdef PFIL_HOOKS
443c4ac87eaSDarren Reed 	/*
444c4ac87eaSDarren Reed 	 * Run through list of hooks for input packets.  If there are any
445c4ac87eaSDarren Reed 	 * filters which require that additional packets in the flow are
446c4ac87eaSDarren Reed 	 * not fast-forwarded, they must clear the M_CANFASTFWD flag.
447c4ac87eaSDarren Reed 	 * Note that filters must _never_ set this flag, as another filter
448c4ac87eaSDarren Reed 	 * in the list may have previously cleared it.
449c4ac87eaSDarren Reed 	 */
450c4ac87eaSDarren Reed 	m0 = m;
451c4ac87eaSDarren Reed 	pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
452fc2ffbe6SPoul-Henning Kamp 	for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link))
453c4ac87eaSDarren Reed 		if (pfh->pfil_func) {
454c4ac87eaSDarren Reed 			rv = pfh->pfil_func(ip, hlen,
455c4ac87eaSDarren Reed 					    m->m_pkthdr.rcvif, 0, &m0);
456c4ac87eaSDarren Reed 			if (rv)
457beec8214SDarren Reed 				return;
458c4ac87eaSDarren Reed 			m = m0;
459c4ac87eaSDarren Reed 			if (m == NULL)
460c4ac87eaSDarren Reed 				return;
461c4ac87eaSDarren Reed 			ip = mtod(m, struct ip *);
462beec8214SDarren Reed 		}
463c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */
464c4ac87eaSDarren Reed 
4657b109fa4SLuigi Rizzo 	if (fw_enable && IPFW_LOADED) {
466f9e354dfSJulian Elischer 		/*
467f9e354dfSJulian Elischer 		 * If we've been forwarded from the output side, then
468f9e354dfSJulian Elischer 		 * skip the firewall a second time
469f9e354dfSJulian Elischer 		 */
4702b25acc1SLuigi Rizzo 		if (args.next_hop)
471f9e354dfSJulian Elischer 			goto ours;
4722b25acc1SLuigi Rizzo 
4732b25acc1SLuigi Rizzo 		args.m = m;
4742b25acc1SLuigi Rizzo 		i = ip_fw_chk_ptr(&args);
4752b25acc1SLuigi Rizzo 		m = args.m;
4762b25acc1SLuigi Rizzo 
477d60315beSLuigi Rizzo 		if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
478507b4b54SLuigi Rizzo 			if (m)
479507b4b54SLuigi Rizzo 				m_freem(m);
480b715f178SLuigi Rizzo 			return;
481507b4b54SLuigi Rizzo 		}
482d60315beSLuigi Rizzo 		ip = mtod(m, struct ip *); /* just in case m changed */
4832b25acc1SLuigi Rizzo 		if (i == 0 && args.next_hop == NULL)	/* common case */
484b715f178SLuigi Rizzo 			goto pass;
4857b109fa4SLuigi Rizzo                 if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {
4868948e4baSArchie Cobbs 			/* Send packet to the appropriate pipe */
4872b25acc1SLuigi Rizzo 			ip_dn_io_ptr(m, i&0xffff, DN_TO_IP_IN, &args);
488e4676ba6SJulian Elischer 			return;
48993e0e116SJulian Elischer 		}
490b715f178SLuigi Rizzo #ifdef IPDIVERT
4918948e4baSArchie Cobbs 		if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
4928948e4baSArchie Cobbs 			/* Divert or tee packet */
4938948e4baSArchie Cobbs 			divert_info = i;
494b715f178SLuigi Rizzo 			goto ours;
495b715f178SLuigi Rizzo 		}
496b715f178SLuigi Rizzo #endif
4972b25acc1SLuigi Rizzo 		if (i == 0 && args.next_hop != NULL)
498b715f178SLuigi Rizzo 			goto pass;
499b715f178SLuigi Rizzo 		/*
500b715f178SLuigi Rizzo 		 * if we get here, the packet must be dropped
501b715f178SLuigi Rizzo 		 */
502b715f178SLuigi Rizzo 		m_freem(m);
503b715f178SLuigi Rizzo 		return;
504b715f178SLuigi Rizzo 	}
505b715f178SLuigi Rizzo pass:
506100ba1a6SJordan K. Hubbard 
507df8bae1dSRodney W. Grimes 	/*
508df8bae1dSRodney W. Grimes 	 * Process options and, if not destined for us,
509df8bae1dSRodney W. Grimes 	 * ship it on.  ip_dooptions returns 1 when an
510df8bae1dSRodney W. Grimes 	 * error was detected (causing an icmp message
511df8bae1dSRodney W. Grimes 	 * to be sent and the original packet to be freed).
512df8bae1dSRodney W. Grimes 	 */
513df8bae1dSRodney W. Grimes 	ip_nhops = 0;		/* for source routed packets */
5142b25acc1SLuigi Rizzo 	if (hlen > sizeof (struct ip) && ip_dooptions(m, 0, args.next_hop))
515c67b1d17SGarrett Wollman 		return;
516df8bae1dSRodney W. Grimes 
517f0068c4aSGarrett Wollman         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
518f0068c4aSGarrett Wollman          * matter if it is destined to another node, or whether it is
519f0068c4aSGarrett Wollman          * a multicast one, RSVP wants it! and prevents it from being forwarded
520f0068c4aSGarrett Wollman          * anywhere else. Also checks if the rsvp daemon is running before
521f0068c4aSGarrett Wollman 	 * grabbing the packet.
522f0068c4aSGarrett Wollman          */
5231c5de19aSGarrett Wollman 	if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
524f0068c4aSGarrett Wollman 		goto ours;
525f0068c4aSGarrett Wollman 
526df8bae1dSRodney W. Grimes 	/*
527df8bae1dSRodney W. Grimes 	 * Check our list of addresses, to see if the packet is for us.
528cc766e04SGarrett Wollman 	 * If we don't have any addresses, assume any unicast packet
529cc766e04SGarrett Wollman 	 * we receive might be for us (and let the upper layers deal
530cc766e04SGarrett Wollman 	 * with it).
531df8bae1dSRodney W. Grimes 	 */
532cc766e04SGarrett Wollman 	if (TAILQ_EMPTY(&in_ifaddrhead) &&
533cc766e04SGarrett Wollman 	    (m->m_flags & (M_MCAST|M_BCAST)) == 0)
534cc766e04SGarrett Wollman 		goto ours;
535cc766e04SGarrett Wollman 
5367538a9a0SJonathan Lemon 	/*
5377538a9a0SJonathan Lemon 	 * Cache the destination address of the packet; this may be
5387538a9a0SJonathan Lemon 	 * changed by use of 'ipfw fwd'.
5397538a9a0SJonathan Lemon 	 */
5402b25acc1SLuigi Rizzo 	pkt_dst = args.next_hop ? args.next_hop->sin_addr : ip->ip_dst;
5417538a9a0SJonathan Lemon 
542823db0e9SDon Lewis 	/*
543823db0e9SDon Lewis 	 * Enable a consistency check between the destination address
544823db0e9SDon Lewis 	 * and the arrival interface for a unicast packet (the RFC 1122
545823db0e9SDon Lewis 	 * strong ES model) if IP forwarding is disabled and the packet
546e15ae1b2SDon Lewis 	 * is not locally generated and the packet is not subject to
547e15ae1b2SDon Lewis 	 * 'ipfw fwd'.
5483f67c834SDon Lewis 	 *
5493f67c834SDon Lewis 	 * XXX - Checking also should be disabled if the destination
5503f67c834SDon Lewis 	 * address is ipnat'ed to a different interface.
5513f67c834SDon Lewis 	 *
552a8f12100SDon Lewis 	 * XXX - Checking is incompatible with IP aliases added
5533f67c834SDon Lewis 	 * to the loopback interface instead of the interface where
5543f67c834SDon Lewis 	 * the packets are received.
555823db0e9SDon Lewis 	 */
556823db0e9SDon Lewis 	checkif = ip_checkinterface && (ipforwarding == 0) &&
5579494d596SBrooks Davis 	    m->m_pkthdr.rcvif != NULL &&
558e15ae1b2SDon Lewis 	    ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
5592b25acc1SLuigi Rizzo 	    (args.next_hop == NULL);
560823db0e9SDon Lewis 
561ca925d9cSJonathan Lemon 	/*
562ca925d9cSJonathan Lemon 	 * Check for exact addresses in the hash bucket.
563ca925d9cSJonathan Lemon 	 */
564ca925d9cSJonathan Lemon 	LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
565f9e354dfSJulian Elischer 		/*
566823db0e9SDon Lewis 		 * If the address matches, verify that the packet
567823db0e9SDon Lewis 		 * arrived via the correct interface if checking is
568823db0e9SDon Lewis 		 * enabled.
569f9e354dfSJulian Elischer 		 */
570823db0e9SDon Lewis 		if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr &&
571823db0e9SDon Lewis 		    (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif))
572ed1ff184SJulian Elischer 			goto ours;
573ca925d9cSJonathan Lemon 	}
574823db0e9SDon Lewis 	/*
575ca925d9cSJonathan Lemon 	 * Check for broadcast addresses.
576ca925d9cSJonathan Lemon 	 *
577ca925d9cSJonathan Lemon 	 * Only accept broadcast packets that arrive via the matching
578ca925d9cSJonathan Lemon 	 * interface.  Reception of forwarded directed broadcasts would
579ca925d9cSJonathan Lemon 	 * be handled via ip_forward() and ether_output() with the loopback
580ca925d9cSJonathan Lemon 	 * into the stack for SIMPLEX interfaces handled by ether_output().
581823db0e9SDon Lewis 	 */
582ca925d9cSJonathan Lemon 	if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
583ca925d9cSJonathan Lemon 	        TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
584ca925d9cSJonathan Lemon 			if (ifa->ifa_addr->sa_family != AF_INET)
585ca925d9cSJonathan Lemon 				continue;
586ca925d9cSJonathan Lemon 			ia = ifatoia(ifa);
587df8bae1dSRodney W. Grimes 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
5887538a9a0SJonathan Lemon 			    pkt_dst.s_addr)
589df8bae1dSRodney W. Grimes 				goto ours;
5907538a9a0SJonathan Lemon 			if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr)
591df8bae1dSRodney W. Grimes 				goto ours;
592ca925d9cSJonathan Lemon #ifdef BOOTP_COMPAT
593ca925d9cSJonathan Lemon 			if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
594ca925d9cSJonathan Lemon 				goto ours;
595ca925d9cSJonathan Lemon #endif
596df8bae1dSRodney W. Grimes 		}
597df8bae1dSRodney W. Grimes 	}
598df8bae1dSRodney W. Grimes 	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
599df8bae1dSRodney W. Grimes 		struct in_multi *inm;
600df8bae1dSRodney W. Grimes 		if (ip_mrouter) {
601df8bae1dSRodney W. Grimes 			/*
602df8bae1dSRodney W. Grimes 			 * If we are acting as a multicast router, all
603df8bae1dSRodney W. Grimes 			 * incoming multicast packets are passed to the
604df8bae1dSRodney W. Grimes 			 * kernel-level multicast forwarding function.
605df8bae1dSRodney W. Grimes 			 * The packet is returned (relatively) intact; if
606df8bae1dSRodney W. Grimes 			 * ip_mforward() returns a non-zero value, the packet
607df8bae1dSRodney W. Grimes 			 * must be discarded, else it may be accepted below.
608df8bae1dSRodney W. Grimes 			 */
609bbb4330bSLuigi Rizzo 			if (ip_mforward &&
610bbb4330bSLuigi Rizzo 			    ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) {
611df8bae1dSRodney W. Grimes 				ipstat.ips_cantforward++;
612df8bae1dSRodney W. Grimes 				m_freem(m);
613c67b1d17SGarrett Wollman 				return;
614df8bae1dSRodney W. Grimes 			}
615df8bae1dSRodney W. Grimes 
616df8bae1dSRodney W. Grimes 			/*
61711612afaSDima Dorfman 			 * The process-level routing daemon needs to receive
618df8bae1dSRodney W. Grimes 			 * all multicast IGMP packets, whether or not this
619df8bae1dSRodney W. Grimes 			 * host belongs to their destination groups.
620df8bae1dSRodney W. Grimes 			 */
621df8bae1dSRodney W. Grimes 			if (ip->ip_p == IPPROTO_IGMP)
622df8bae1dSRodney W. Grimes 				goto ours;
623df8bae1dSRodney W. Grimes 			ipstat.ips_forward++;
624df8bae1dSRodney W. Grimes 		}
625df8bae1dSRodney W. Grimes 		/*
626df8bae1dSRodney W. Grimes 		 * See if we belong to the destination multicast group on the
627df8bae1dSRodney W. Grimes 		 * arrival interface.
628df8bae1dSRodney W. Grimes 		 */
629df8bae1dSRodney W. Grimes 		IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
630df8bae1dSRodney W. Grimes 		if (inm == NULL) {
63182c39223SGarrett Wollman 			ipstat.ips_notmember++;
632df8bae1dSRodney W. Grimes 			m_freem(m);
633c67b1d17SGarrett Wollman 			return;
634df8bae1dSRodney W. Grimes 		}
635df8bae1dSRodney W. Grimes 		goto ours;
636df8bae1dSRodney W. Grimes 	}
637df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
638df8bae1dSRodney W. Grimes 		goto ours;
639df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == INADDR_ANY)
640df8bae1dSRodney W. Grimes 		goto ours;
641df8bae1dSRodney W. Grimes 
6426a800098SYoshinobu Inoue 	/*
6436a800098SYoshinobu Inoue 	 * FAITH(Firewall Aided Internet Translator)
6446a800098SYoshinobu Inoue 	 */
6456a800098SYoshinobu Inoue 	if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
6466a800098SYoshinobu Inoue 		if (ip_keepfaith) {
6476a800098SYoshinobu Inoue 			if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP)
6486a800098SYoshinobu Inoue 				goto ours;
6496a800098SYoshinobu Inoue 		}
6506a800098SYoshinobu Inoue 		m_freem(m);
6516a800098SYoshinobu Inoue 		return;
6526a800098SYoshinobu Inoue 	}
6539494d596SBrooks Davis 
654df8bae1dSRodney W. Grimes 	/*
655df8bae1dSRodney W. Grimes 	 * Not for us; forward if possible and desirable.
656df8bae1dSRodney W. Grimes 	 */
657df8bae1dSRodney W. Grimes 	if (ipforwarding == 0) {
658df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
659df8bae1dSRodney W. Grimes 		m_freem(m);
660546f251bSChris D. Faulhaber 	} else {
661546f251bSChris D. Faulhaber #ifdef IPSEC
662546f251bSChris D. Faulhaber 		/*
663546f251bSChris D. Faulhaber 		 * Enforce inbound IPsec SPD.
664546f251bSChris D. Faulhaber 		 */
665546f251bSChris D. Faulhaber 		if (ipsec4_in_reject(m, NULL)) {
666546f251bSChris D. Faulhaber 			ipsecstat.in_polvio++;
667546f251bSChris D. Faulhaber 			goto bad;
668546f251bSChris D. Faulhaber 		}
669546f251bSChris D. Faulhaber #endif /* IPSEC */
670b9234fafSSam Leffler #ifdef FAST_IPSEC
671b9234fafSSam Leffler 		mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
672b9234fafSSam Leffler 		s = splnet();
673b9234fafSSam Leffler 		if (mtag != NULL) {
674b9234fafSSam Leffler 			tdbi = (struct tdb_ident *)(mtag + 1);
675b9234fafSSam Leffler 			sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
676b9234fafSSam Leffler 		} else {
677b9234fafSSam Leffler 			sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
678b9234fafSSam Leffler 						   IP_FORWARDING, &error);
679b9234fafSSam Leffler 		}
680b9234fafSSam Leffler 		if (sp == NULL) {	/* NB: can happen if error */
681b9234fafSSam Leffler 			splx(s);
682b9234fafSSam Leffler 			/*XXX error stat???*/
683b9234fafSSam Leffler 			DPRINTF(("ip_input: no SP for forwarding\n"));	/*XXX*/
684b9234fafSSam Leffler 			goto bad;
685b9234fafSSam Leffler 		}
686b9234fafSSam Leffler 
687b9234fafSSam Leffler 		/*
688b9234fafSSam Leffler 		 * Check security policy against packet attributes.
689b9234fafSSam Leffler 		 */
690b9234fafSSam Leffler 		error = ipsec_in_reject(sp, m);
691b9234fafSSam Leffler 		KEY_FREESP(&sp);
692b9234fafSSam Leffler 		splx(s);
693b9234fafSSam Leffler 		if (error) {
694b9234fafSSam Leffler 			ipstat.ips_cantforward++;
695b9234fafSSam Leffler 			goto bad;
696b9234fafSSam Leffler 		}
697b9234fafSSam Leffler #endif /* FAST_IPSEC */
6982b25acc1SLuigi Rizzo 		ip_forward(m, 0, args.next_hop);
699546f251bSChris D. Faulhaber 	}
700c67b1d17SGarrett Wollman 	return;
701df8bae1dSRodney W. Grimes 
702df8bae1dSRodney W. Grimes ours:
703d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
704d0ebc0d2SYaroslav Tykhiy 	/*
705d0ebc0d2SYaroslav Tykhiy 	 * IPSTEALTH: Process non-routing options only
706d0ebc0d2SYaroslav Tykhiy 	 * if the packet is destined for us.
707d0ebc0d2SYaroslav Tykhiy 	 */
7082b25acc1SLuigi Rizzo 	if (ipstealth && hlen > sizeof (struct ip) &&
7092b25acc1SLuigi Rizzo 	    ip_dooptions(m, 1, args.next_hop))
710d0ebc0d2SYaroslav Tykhiy 		return;
711d0ebc0d2SYaroslav Tykhiy #endif /* IPSTEALTH */
712d0ebc0d2SYaroslav Tykhiy 
7135da9f8faSJosef Karthauser 	/* Count the packet in the ip address stats */
7145da9f8faSJosef Karthauser 	if (ia != NULL) {
7155da9f8faSJosef Karthauser 		ia->ia_ifa.if_ipackets++;
7165da9f8faSJosef Karthauser 		ia->ia_ifa.if_ibytes += m->m_pkthdr.len;
7175da9f8faSJosef Karthauser 	}
718100ba1a6SJordan K. Hubbard 
71963f8d699SJordan K. Hubbard 	/*
720df8bae1dSRodney W. Grimes 	 * If offset or IP_MF are set, must reassemble.
721df8bae1dSRodney W. Grimes 	 * Otherwise, nothing need be done.
722df8bae1dSRodney W. Grimes 	 * (We could look in the reassembly queue to see
723df8bae1dSRodney W. Grimes 	 * if the packet was previously fragmented,
724df8bae1dSRodney W. Grimes 	 * but it's not worth the time; just let them time out.)
725df8bae1dSRodney W. Grimes 	 */
726b6ea1aa5SRuslan Ermilov 	if (ip->ip_off & (IP_MF | IP_OFFMASK)) {
7276a800098SYoshinobu Inoue 
728194a213eSAndrey A. Chernov 		sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
729df8bae1dSRodney W. Grimes 		/*
730df8bae1dSRodney W. Grimes 		 * Look for queue of fragments
731df8bae1dSRodney W. Grimes 		 * of this datagram.
732df8bae1dSRodney W. Grimes 		 */
733462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(fp, &ipq[sum], ipq_list)
734df8bae1dSRodney W. Grimes 			if (ip->ip_id == fp->ipq_id &&
735df8bae1dSRodney W. Grimes 			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
736df8bae1dSRodney W. Grimes 			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
73736b0360bSRobert Watson #ifdef MAC
73836b0360bSRobert Watson 			    mac_fragment_match(m, fp) &&
73936b0360bSRobert Watson #endif
740df8bae1dSRodney W. Grimes 			    ip->ip_p == fp->ipq_p)
741df8bae1dSRodney W. Grimes 				goto found;
742df8bae1dSRodney W. Grimes 
743194a213eSAndrey A. Chernov 		fp = 0;
744194a213eSAndrey A. Chernov 
745194a213eSAndrey A. Chernov 		/* check if there's a place for the new queue */
746194a213eSAndrey A. Chernov 		if (nipq > maxnipq) {
747194a213eSAndrey A. Chernov 		    /*
748194a213eSAndrey A. Chernov 		     * drop something from the tail of the current queue
749194a213eSAndrey A. Chernov 		     * before proceeding further
750194a213eSAndrey A. Chernov 		     */
751462b86feSPoul-Henning Kamp 		    struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead);
752462b86feSPoul-Henning Kamp 		    if (q == NULL) {   /* gak */
753194a213eSAndrey A. Chernov 			for (i = 0; i < IPREASS_NHASH; i++) {
754462b86feSPoul-Henning Kamp 			    struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead);
755462b86feSPoul-Henning Kamp 			    if (r) {
756462b86feSPoul-Henning Kamp 				ip_freef(&ipq[i], r);
757194a213eSAndrey A. Chernov 				break;
758194a213eSAndrey A. Chernov 			    }
759194a213eSAndrey A. Chernov 			}
760194a213eSAndrey A. Chernov 		    } else
761462b86feSPoul-Henning Kamp 			ip_freef(&ipq[sum], q);
762194a213eSAndrey A. Chernov 		}
763194a213eSAndrey A. Chernov found:
764df8bae1dSRodney W. Grimes 		/*
765df8bae1dSRodney W. Grimes 		 * Adjust ip_len to not reflect header,
766df8bae1dSRodney W. Grimes 		 * convert offset of this to bytes.
767df8bae1dSRodney W. Grimes 		 */
768df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
769b6ea1aa5SRuslan Ermilov 		if (ip->ip_off & IP_MF) {
7706effc713SDoug Rabson 		        /*
7716effc713SDoug Rabson 		         * Make sure that fragments have a data length
7726effc713SDoug Rabson 			 * that's a non-zero multiple of 8 bytes.
7736effc713SDoug Rabson 		         */
7746effc713SDoug Rabson 			if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
7756effc713SDoug Rabson 				ipstat.ips_toosmall++; /* XXX */
7766effc713SDoug Rabson 				goto bad;
7776effc713SDoug Rabson 			}
7786effc713SDoug Rabson 			m->m_flags |= M_FRAG;
7791cf43499SMaxim Konovalov 		} else
7801cf43499SMaxim Konovalov 			m->m_flags &= ~M_FRAG;
781df8bae1dSRodney W. Grimes 		ip->ip_off <<= 3;
782df8bae1dSRodney W. Grimes 
783df8bae1dSRodney W. Grimes 		/*
784b6ea1aa5SRuslan Ermilov 		 * Attempt reassembly; if it succeeds, proceed.
7852b25acc1SLuigi Rizzo 		 * ip_reass() will return a different mbuf, and update
7862b25acc1SLuigi Rizzo 		 * the divert info in divert_info and args.divert_rule.
787df8bae1dSRodney W. Grimes 		 */
788df8bae1dSRodney W. Grimes 		ipstat.ips_fragments++;
789487bdb38SRuslan Ermilov 		m->m_pkthdr.header = ip;
7906a800098SYoshinobu Inoue 		m = ip_reass(m,
7912b25acc1SLuigi Rizzo 		    &ipq[sum], fp, &divert_info, &args.divert_rule);
7922b25acc1SLuigi Rizzo 		if (m == 0)
793c67b1d17SGarrett Wollman 			return;
794df8bae1dSRodney W. Grimes 		ipstat.ips_reassembled++;
7956a800098SYoshinobu Inoue 		ip = mtod(m, struct ip *);
7967e2df452SRuslan Ermilov 		/* Get the header length of the reassembled packet */
79753be11f6SPoul-Henning Kamp 		hlen = ip->ip_hl << 2;
798af782f1cSBrian Somers #ifdef IPDIVERT
7998948e4baSArchie Cobbs 		/* Restore original checksum before diverting packet */
8008948e4baSArchie Cobbs 		if (divert_info != 0) {
801af782f1cSBrian Somers 			ip->ip_len += hlen;
802fd8e4ebcSMike Barcroft 			ip->ip_len = htons(ip->ip_len);
803fd8e4ebcSMike Barcroft 			ip->ip_off = htons(ip->ip_off);
804af782f1cSBrian Somers 			ip->ip_sum = 0;
80560123168SRuslan Ermilov 			if (hlen == sizeof(struct ip))
806af782f1cSBrian Somers 				ip->ip_sum = in_cksum_hdr(ip);
80760123168SRuslan Ermilov 			else
80860123168SRuslan Ermilov 				ip->ip_sum = in_cksum(m, hlen);
809fd8e4ebcSMike Barcroft 			ip->ip_off = ntohs(ip->ip_off);
810fd8e4ebcSMike Barcroft 			ip->ip_len = ntohs(ip->ip_len);
811af782f1cSBrian Somers 			ip->ip_len -= hlen;
812af782f1cSBrian Somers 		}
813af782f1cSBrian Somers #endif
814df8bae1dSRodney W. Grimes 	} else
815df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
816df8bae1dSRodney W. Grimes 
81793e0e116SJulian Elischer #ifdef IPDIVERT
81893e0e116SJulian Elischer 	/*
8198948e4baSArchie Cobbs 	 * Divert or tee packet to the divert protocol if required.
82093e0e116SJulian Elischer 	 */
8218948e4baSArchie Cobbs 	if (divert_info != 0) {
8228948e4baSArchie Cobbs 		struct mbuf *clone = NULL;
8238948e4baSArchie Cobbs 
8248948e4baSArchie Cobbs 		/* Clone packet if we're doing a 'tee' */
8258948e4baSArchie Cobbs 		if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
8268948e4baSArchie Cobbs 			clone = m_dup(m, M_DONTWAIT);
8278948e4baSArchie Cobbs 
8288948e4baSArchie Cobbs 		/* Restore packet header fields to original values */
8298948e4baSArchie Cobbs 		ip->ip_len += hlen;
830fd8e4ebcSMike Barcroft 		ip->ip_len = htons(ip->ip_len);
831fd8e4ebcSMike Barcroft 		ip->ip_off = htons(ip->ip_off);
8328948e4baSArchie Cobbs 
8338948e4baSArchie Cobbs 		/* Deliver packet to divert input routine */
8342b25acc1SLuigi Rizzo 		divert_packet(m, 1, divert_info & 0xffff, args.divert_rule);
835e4676ba6SJulian Elischer 		ipstat.ips_delivered++;
8368948e4baSArchie Cobbs 
8378948e4baSArchie Cobbs 		/* If 'tee', continue with original packet */
8388948e4baSArchie Cobbs 		if (clone == NULL)
83993e0e116SJulian Elischer 			return;
8408948e4baSArchie Cobbs 		m = clone;
8418948e4baSArchie Cobbs 		ip = mtod(m, struct ip *);
84256962689SCrist J. Clark 		ip->ip_len += hlen;
8432b25acc1SLuigi Rizzo 		/*
8442b25acc1SLuigi Rizzo 		 * Jump backwards to complete processing of the
8452b25acc1SLuigi Rizzo 		 * packet. But first clear divert_info to avoid
8462b25acc1SLuigi Rizzo 		 * entering this block again.
8472b25acc1SLuigi Rizzo 		 * We do not need to clear args.divert_rule
8482b25acc1SLuigi Rizzo 		 * or args.next_hop as they will not be used.
8492b25acc1SLuigi Rizzo 		 */
85056962689SCrist J. Clark 		divert_info = 0;
85156962689SCrist J. Clark 		goto pass;
85293e0e116SJulian Elischer 	}
85393e0e116SJulian Elischer #endif
85493e0e116SJulian Elischer 
85533841545SHajimu UMEMOTO #ifdef IPSEC
85633841545SHajimu UMEMOTO 	/*
85733841545SHajimu UMEMOTO 	 * enforce IPsec policy checking if we are seeing last header.
85833841545SHajimu UMEMOTO 	 * note that we do not visit this with protocols with pcb layer
85933841545SHajimu UMEMOTO 	 * code - like udp/tcp/raw ip.
86033841545SHajimu UMEMOTO 	 */
86133841545SHajimu UMEMOTO 	if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 &&
86233841545SHajimu UMEMOTO 	    ipsec4_in_reject(m, NULL)) {
86333841545SHajimu UMEMOTO 		ipsecstat.in_polvio++;
86433841545SHajimu UMEMOTO 		goto bad;
86533841545SHajimu UMEMOTO 	}
86633841545SHajimu UMEMOTO #endif
867b9234fafSSam Leffler #if FAST_IPSEC
868b9234fafSSam Leffler 	/*
869b9234fafSSam Leffler 	 * enforce IPsec policy checking if we are seeing last header.
870b9234fafSSam Leffler 	 * note that we do not visit this with protocols with pcb layer
871b9234fafSSam Leffler 	 * code - like udp/tcp/raw ip.
872b9234fafSSam Leffler 	 */
873b9234fafSSam Leffler 	if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0) {
874b9234fafSSam Leffler 		/*
875b9234fafSSam Leffler 		 * Check if the packet has already had IPsec processing
876b9234fafSSam Leffler 		 * done.  If so, then just pass it along.  This tag gets
877b9234fafSSam Leffler 		 * set during AH, ESP, etc. input handling, before the
878b9234fafSSam Leffler 		 * packet is returned to the ip input queue for delivery.
879b9234fafSSam Leffler 		 */
880b9234fafSSam Leffler 		mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
881b9234fafSSam Leffler 		s = splnet();
882b9234fafSSam Leffler 		if (mtag != NULL) {
883b9234fafSSam Leffler 			tdbi = (struct tdb_ident *)(mtag + 1);
884b9234fafSSam Leffler 			sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
885b9234fafSSam Leffler 		} else {
886b9234fafSSam Leffler 			sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
887b9234fafSSam Leffler 						   IP_FORWARDING, &error);
888b9234fafSSam Leffler 		}
889b9234fafSSam Leffler 		if (sp != NULL) {
890b9234fafSSam Leffler 			/*
891b9234fafSSam Leffler 			 * Check security policy against packet attributes.
892b9234fafSSam Leffler 			 */
893b9234fafSSam Leffler 			error = ipsec_in_reject(sp, m);
894b9234fafSSam Leffler 			KEY_FREESP(&sp);
895b9234fafSSam Leffler 		} else {
896b9234fafSSam Leffler 			/* XXX error stat??? */
897b9234fafSSam Leffler 			error = EINVAL;
898b9234fafSSam Leffler DPRINTF(("ip_input: no SP, packet discarded\n"));/*XXX*/
899b9234fafSSam Leffler 			goto bad;
900b9234fafSSam Leffler 		}
901b9234fafSSam Leffler 		splx(s);
902b9234fafSSam Leffler 		if (error)
903b9234fafSSam Leffler 			goto bad;
904b9234fafSSam Leffler 	}
905b9234fafSSam Leffler #endif /* FAST_IPSEC */
90633841545SHajimu UMEMOTO 
907df8bae1dSRodney W. Grimes 	/*
908df8bae1dSRodney W. Grimes 	 * Switch out to protocol's input routine.
909df8bae1dSRodney W. Grimes 	 */
910df8bae1dSRodney W. Grimes 	ipstat.ips_delivered++;
9112b25acc1SLuigi Rizzo 	if (args.next_hop && ip->ip_p == IPPROTO_TCP) {
9122b25acc1SLuigi Rizzo 		/* TCP needs IPFORWARD info if available */
9132b25acc1SLuigi Rizzo 		struct m_hdr tag;
9146a800098SYoshinobu Inoue 
9152b25acc1SLuigi Rizzo 		tag.mh_type = MT_TAG;
9162b25acc1SLuigi Rizzo 		tag.mh_flags = PACKET_TAG_IPFORWARD;
9172b25acc1SLuigi Rizzo 		tag.mh_data = (caddr_t)args.next_hop;
9182b25acc1SLuigi Rizzo 		tag.mh_next = m;
9192b25acc1SLuigi Rizzo 
9202b25acc1SLuigi Rizzo 		(*inetsw[ip_protox[ip->ip_p]].pr_input)(
9212b25acc1SLuigi Rizzo 			(struct mbuf *)&tag, hlen);
9222b25acc1SLuigi Rizzo 	} else
9232b25acc1SLuigi Rizzo 		(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
924c67b1d17SGarrett Wollman 	return;
925df8bae1dSRodney W. Grimes bad:
926df8bae1dSRodney W. Grimes 	m_freem(m);
927c67b1d17SGarrett Wollman }
928c67b1d17SGarrett Wollman 
929c67b1d17SGarrett Wollman /*
930c67b1d17SGarrett Wollman  * IP software interrupt routine - to go away sometime soon
931c67b1d17SGarrett Wollman  */
932c67b1d17SGarrett Wollman static void
933c67b1d17SGarrett Wollman ipintr(void)
934c67b1d17SGarrett Wollman {
935c67b1d17SGarrett Wollman 	struct mbuf *m;
936c67b1d17SGarrett Wollman 
937c67b1d17SGarrett Wollman 	while (1) {
938c67b1d17SGarrett Wollman 		IF_DEQUEUE(&ipintrq, m);
939c67b1d17SGarrett Wollman 		if (m == 0)
940c67b1d17SGarrett Wollman 			return;
941c67b1d17SGarrett Wollman 		ip_input(m);
942c67b1d17SGarrett Wollman 	}
943df8bae1dSRodney W. Grimes }
944df8bae1dSRodney W. Grimes 
945df8bae1dSRodney W. Grimes /*
9468948e4baSArchie Cobbs  * Take incoming datagram fragment and try to reassemble it into
9478948e4baSArchie Cobbs  * whole datagram.  If a chain for reassembly of this datagram already
9488948e4baSArchie Cobbs  * exists, then it is given as fp; otherwise have to make a chain.
9498948e4baSArchie Cobbs  *
9508948e4baSArchie Cobbs  * When IPDIVERT enabled, keep additional state with each packet that
9518948e4baSArchie Cobbs  * tells us if we need to divert or tee the packet we're building.
9522b25acc1SLuigi Rizzo  * In particular, *divinfo includes the port and TEE flag,
9532b25acc1SLuigi Rizzo  * *divert_rule is the number of the matching rule.
954df8bae1dSRodney W. Grimes  */
9558948e4baSArchie Cobbs 
9566a800098SYoshinobu Inoue static struct mbuf *
9572b25acc1SLuigi Rizzo ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp,
9582b25acc1SLuigi Rizzo 	u_int32_t *divinfo, u_int16_t *divert_rule)
959df8bae1dSRodney W. Grimes {
9606effc713SDoug Rabson 	struct ip *ip = mtod(m, struct ip *);
961b6ea1aa5SRuslan Ermilov 	register struct mbuf *p, *q, *nq;
962df8bae1dSRodney W. Grimes 	struct mbuf *t;
96353be11f6SPoul-Henning Kamp 	int hlen = ip->ip_hl << 2;
964df8bae1dSRodney W. Grimes 	int i, next;
965df8bae1dSRodney W. Grimes 
966df8bae1dSRodney W. Grimes 	/*
967df8bae1dSRodney W. Grimes 	 * Presence of header sizes in mbufs
968df8bae1dSRodney W. Grimes 	 * would confuse code below.
969df8bae1dSRodney W. Grimes 	 */
970df8bae1dSRodney W. Grimes 	m->m_data += hlen;
971df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
972df8bae1dSRodney W. Grimes 
973df8bae1dSRodney W. Grimes 	/*
974df8bae1dSRodney W. Grimes 	 * If first fragment to arrive, create a reassembly queue.
975df8bae1dSRodney W. Grimes 	 */
976df8bae1dSRodney W. Grimes 	if (fp == 0) {
977690a6055SJesper Skriver 		/*
978690a6055SJesper Skriver 		 * Enforce upper bound on number of fragmented packets
979690a6055SJesper Skriver 		 * for which we attempt reassembly;
980690a6055SJesper Skriver 		 * If maxfrag is 0, never accept fragments.
981690a6055SJesper Skriver 		 * If maxfrag is -1, accept all fragments without limitation.
982690a6055SJesper Skriver 		 */
983690a6055SJesper Skriver 		if ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets))
984690a6055SJesper Skriver 			goto dropfrag;
985690a6055SJesper Skriver 		ip_nfragpackets++;
986df8bae1dSRodney W. Grimes 		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
987df8bae1dSRodney W. Grimes 			goto dropfrag;
988df8bae1dSRodney W. Grimes 		fp = mtod(t, struct ipq *);
98936b0360bSRobert Watson #ifdef MAC
99036b0360bSRobert Watson 		mac_init_ipq(fp);
99136b0360bSRobert Watson 		mac_create_ipq(m, fp);
99236b0360bSRobert Watson #endif
993462b86feSPoul-Henning Kamp 		TAILQ_INSERT_HEAD(head, fp, ipq_list);
994194a213eSAndrey A. Chernov 		nipq++;
995df8bae1dSRodney W. Grimes 		fp->ipq_ttl = IPFRAGTTL;
996df8bae1dSRodney W. Grimes 		fp->ipq_p = ip->ip_p;
997df8bae1dSRodney W. Grimes 		fp->ipq_id = ip->ip_id;
9986effc713SDoug Rabson 		fp->ipq_src = ip->ip_src;
9996effc713SDoug Rabson 		fp->ipq_dst = ip->ip_dst;
1000af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
1001af38c68cSLuigi Rizzo 		m->m_nextpkt = NULL;
100293e0e116SJulian Elischer #ifdef IPDIVERT
10038948e4baSArchie Cobbs 		fp->ipq_div_info = 0;
1004bb60f459SJulian Elischer 		fp->ipq_div_cookie = 0;
100593e0e116SJulian Elischer #endif
1006af38c68cSLuigi Rizzo 		goto inserted;
100736b0360bSRobert Watson 	} else {
100836b0360bSRobert Watson #ifdef MAC
100936b0360bSRobert Watson 		mac_update_ipq(m, fp);
101036b0360bSRobert Watson #endif
1011df8bae1dSRodney W. Grimes 	}
1012df8bae1dSRodney W. Grimes 
10136effc713SDoug Rabson #define GETIP(m)	((struct ip*)((m)->m_pkthdr.header))
10146effc713SDoug Rabson 
1015df8bae1dSRodney W. Grimes 	/*
1016df8bae1dSRodney W. Grimes 	 * Find a segment which begins after this one does.
1017df8bae1dSRodney W. Grimes 	 */
10186effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
10196effc713SDoug Rabson 		if (GETIP(q)->ip_off > ip->ip_off)
1020df8bae1dSRodney W. Grimes 			break;
1021df8bae1dSRodney W. Grimes 
1022df8bae1dSRodney W. Grimes 	/*
1023df8bae1dSRodney W. Grimes 	 * If there is a preceding segment, it may provide some of
1024df8bae1dSRodney W. Grimes 	 * our data already.  If so, drop the data from the incoming
1025af38c68cSLuigi Rizzo 	 * segment.  If it provides all of our data, drop us, otherwise
1026af38c68cSLuigi Rizzo 	 * stick new segment in the proper place.
1027db4f9cc7SJonathan Lemon 	 *
1028db4f9cc7SJonathan Lemon 	 * If some of the data is dropped from the the preceding
1029db4f9cc7SJonathan Lemon 	 * segment, then it's checksum is invalidated.
1030df8bae1dSRodney W. Grimes 	 */
10316effc713SDoug Rabson 	if (p) {
10326effc713SDoug Rabson 		i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
1033df8bae1dSRodney W. Grimes 		if (i > 0) {
1034df8bae1dSRodney W. Grimes 			if (i >= ip->ip_len)
1035df8bae1dSRodney W. Grimes 				goto dropfrag;
10366a800098SYoshinobu Inoue 			m_adj(m, i);
1037db4f9cc7SJonathan Lemon 			m->m_pkthdr.csum_flags = 0;
1038df8bae1dSRodney W. Grimes 			ip->ip_off += i;
1039df8bae1dSRodney W. Grimes 			ip->ip_len -= i;
1040df8bae1dSRodney W. Grimes 		}
1041af38c68cSLuigi Rizzo 		m->m_nextpkt = p->m_nextpkt;
1042af38c68cSLuigi Rizzo 		p->m_nextpkt = m;
1043af38c68cSLuigi Rizzo 	} else {
1044af38c68cSLuigi Rizzo 		m->m_nextpkt = fp->ipq_frags;
1045af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
1046df8bae1dSRodney W. Grimes 	}
1047df8bae1dSRodney W. Grimes 
1048df8bae1dSRodney W. Grimes 	/*
1049df8bae1dSRodney W. Grimes 	 * While we overlap succeeding segments trim them or,
1050df8bae1dSRodney W. Grimes 	 * if they are completely covered, dequeue them.
1051df8bae1dSRodney W. Grimes 	 */
10526effc713SDoug Rabson 	for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
1053af38c68cSLuigi Rizzo 	     q = nq) {
10546effc713SDoug Rabson 		i = (ip->ip_off + ip->ip_len) -
10556effc713SDoug Rabson 		    GETIP(q)->ip_off;
10566effc713SDoug Rabson 		if (i < GETIP(q)->ip_len) {
10576effc713SDoug Rabson 			GETIP(q)->ip_len -= i;
10586effc713SDoug Rabson 			GETIP(q)->ip_off += i;
10596effc713SDoug Rabson 			m_adj(q, i);
1060db4f9cc7SJonathan Lemon 			q->m_pkthdr.csum_flags = 0;
1061df8bae1dSRodney W. Grimes 			break;
1062df8bae1dSRodney W. Grimes 		}
10636effc713SDoug Rabson 		nq = q->m_nextpkt;
1064af38c68cSLuigi Rizzo 		m->m_nextpkt = nq;
10656effc713SDoug Rabson 		m_freem(q);
1066df8bae1dSRodney W. Grimes 	}
1067df8bae1dSRodney W. Grimes 
1068af38c68cSLuigi Rizzo inserted:
106993e0e116SJulian Elischer 
107093e0e116SJulian Elischer #ifdef IPDIVERT
107193e0e116SJulian Elischer 	/*
10728948e4baSArchie Cobbs 	 * Transfer firewall instructions to the fragment structure.
10732b25acc1SLuigi Rizzo 	 * Only trust info in the fragment at offset 0.
107493e0e116SJulian Elischer 	 */
10752b25acc1SLuigi Rizzo 	if (ip->ip_off == 0) {
10768948e4baSArchie Cobbs 		fp->ipq_div_info = *divinfo;
10772b25acc1SLuigi Rizzo 		fp->ipq_div_cookie = *divert_rule;
10782b25acc1SLuigi Rizzo 	}
10798948e4baSArchie Cobbs 	*divinfo = 0;
10802b25acc1SLuigi Rizzo 	*divert_rule = 0;
108193e0e116SJulian Elischer #endif
108293e0e116SJulian Elischer 
1083df8bae1dSRodney W. Grimes 	/*
1084af38c68cSLuigi Rizzo 	 * Check for complete reassembly.
1085df8bae1dSRodney W. Grimes 	 */
10866effc713SDoug Rabson 	next = 0;
10876effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
10886effc713SDoug Rabson 		if (GETIP(q)->ip_off != next)
10896effc713SDoug Rabson 			return (0);
10906effc713SDoug Rabson 		next += GETIP(q)->ip_len;
10916effc713SDoug Rabson 	}
10926effc713SDoug Rabson 	/* Make sure the last packet didn't have the IP_MF flag */
10936effc713SDoug Rabson 	if (p->m_flags & M_FRAG)
1094df8bae1dSRodney W. Grimes 		return (0);
1095df8bae1dSRodney W. Grimes 
1096df8bae1dSRodney W. Grimes 	/*
1097430d30d8SBill Fenner 	 * Reassembly is complete.  Make sure the packet is a sane size.
1098430d30d8SBill Fenner 	 */
10996effc713SDoug Rabson 	q = fp->ipq_frags;
11006effc713SDoug Rabson 	ip = GETIP(q);
110153be11f6SPoul-Henning Kamp 	if (next + (ip->ip_hl << 2) > IP_MAXPACKET) {
1102430d30d8SBill Fenner 		ipstat.ips_toolong++;
1103462b86feSPoul-Henning Kamp 		ip_freef(head, fp);
1104430d30d8SBill Fenner 		return (0);
1105430d30d8SBill Fenner 	}
1106430d30d8SBill Fenner 
1107430d30d8SBill Fenner 	/*
1108430d30d8SBill Fenner 	 * Concatenate fragments.
1109df8bae1dSRodney W. Grimes 	 */
11106effc713SDoug Rabson 	m = q;
1111df8bae1dSRodney W. Grimes 	t = m->m_next;
1112df8bae1dSRodney W. Grimes 	m->m_next = 0;
1113df8bae1dSRodney W. Grimes 	m_cat(m, t);
11146effc713SDoug Rabson 	nq = q->m_nextpkt;
1115945aa40dSDoug Rabson 	q->m_nextpkt = 0;
11166effc713SDoug Rabson 	for (q = nq; q != NULL; q = nq) {
11176effc713SDoug Rabson 		nq = q->m_nextpkt;
1118945aa40dSDoug Rabson 		q->m_nextpkt = NULL;
1119db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags;
1120db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_data += q->m_pkthdr.csum_data;
1121a8db1d93SJonathan Lemon 		m_cat(m, q);
1122df8bae1dSRodney W. Grimes 	}
112336b0360bSRobert Watson #ifdef MAC
112436b0360bSRobert Watson 	mac_create_datagram_from_ipq(fp, m);
112536b0360bSRobert Watson 	mac_destroy_ipq(fp);
112636b0360bSRobert Watson #endif
1127df8bae1dSRodney W. Grimes 
112893e0e116SJulian Elischer #ifdef IPDIVERT
112993e0e116SJulian Elischer 	/*
11308948e4baSArchie Cobbs 	 * Extract firewall instructions from the fragment structure.
113193e0e116SJulian Elischer 	 */
11328948e4baSArchie Cobbs 	*divinfo = fp->ipq_div_info;
11332b25acc1SLuigi Rizzo 	*divert_rule = fp->ipq_div_cookie;
113493e0e116SJulian Elischer #endif
113593e0e116SJulian Elischer 
1136df8bae1dSRodney W. Grimes 	/*
1137df8bae1dSRodney W. Grimes 	 * Create header for new ip packet by
1138df8bae1dSRodney W. Grimes 	 * modifying header of first packet;
1139df8bae1dSRodney W. Grimes 	 * dequeue and discard fragment reassembly header.
1140df8bae1dSRodney W. Grimes 	 * Make header visible.
1141df8bae1dSRodney W. Grimes 	 */
1142df8bae1dSRodney W. Grimes 	ip->ip_len = next;
11436effc713SDoug Rabson 	ip->ip_src = fp->ipq_src;
11446effc713SDoug Rabson 	ip->ip_dst = fp->ipq_dst;
1145462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(head, fp, ipq_list);
1146194a213eSAndrey A. Chernov 	nipq--;
1147df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1148690a6055SJesper Skriver 	ip_nfragpackets--;
114953be11f6SPoul-Henning Kamp 	m->m_len += (ip->ip_hl << 2);
115053be11f6SPoul-Henning Kamp 	m->m_data -= (ip->ip_hl << 2);
1151df8bae1dSRodney W. Grimes 	/* some debugging cruft by sklower, below, will go away soon */
1152a5554bf0SPoul-Henning Kamp 	if (m->m_flags & M_PKTHDR)	/* XXX this should be done elsewhere */
1153a5554bf0SPoul-Henning Kamp 		m_fixhdr(m);
11546a800098SYoshinobu Inoue 	return (m);
1155df8bae1dSRodney W. Grimes 
1156df8bae1dSRodney W. Grimes dropfrag:
1157efe39c6aSJulian Elischer #ifdef IPDIVERT
11588948e4baSArchie Cobbs 	*divinfo = 0;
11592b25acc1SLuigi Rizzo 	*divert_rule = 0;
1160efe39c6aSJulian Elischer #endif
1161df8bae1dSRodney W. Grimes 	ipstat.ips_fragdropped++;
1162df8bae1dSRodney W. Grimes 	m_freem(m);
1163df8bae1dSRodney W. Grimes 	return (0);
11646effc713SDoug Rabson 
11656effc713SDoug Rabson #undef GETIP
1166df8bae1dSRodney W. Grimes }
1167df8bae1dSRodney W. Grimes 
1168df8bae1dSRodney W. Grimes /*
1169df8bae1dSRodney W. Grimes  * Free a fragment reassembly header and all
1170df8bae1dSRodney W. Grimes  * associated datagrams.
1171df8bae1dSRodney W. Grimes  */
11720312fbe9SPoul-Henning Kamp static void
1173462b86feSPoul-Henning Kamp ip_freef(fhp, fp)
1174462b86feSPoul-Henning Kamp 	struct ipqhead *fhp;
1175df8bae1dSRodney W. Grimes 	struct ipq *fp;
1176df8bae1dSRodney W. Grimes {
11776effc713SDoug Rabson 	register struct mbuf *q;
1178df8bae1dSRodney W. Grimes 
11796effc713SDoug Rabson 	while (fp->ipq_frags) {
11806effc713SDoug Rabson 		q = fp->ipq_frags;
11816effc713SDoug Rabson 		fp->ipq_frags = q->m_nextpkt;
11826effc713SDoug Rabson 		m_freem(q);
1183df8bae1dSRodney W. Grimes 	}
1184462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(fhp, fp, ipq_list);
1185df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1186690a6055SJesper Skriver 	ip_nfragpackets--;
1187194a213eSAndrey A. Chernov 	nipq--;
1188df8bae1dSRodney W. Grimes }
1189df8bae1dSRodney W. Grimes 
1190df8bae1dSRodney W. Grimes /*
1191df8bae1dSRodney W. Grimes  * IP timer processing;
1192df8bae1dSRodney W. Grimes  * if a timer expires on a reassembly
1193df8bae1dSRodney W. Grimes  * queue, discard it.
1194df8bae1dSRodney W. Grimes  */
1195df8bae1dSRodney W. Grimes void
1196df8bae1dSRodney W. Grimes ip_slowtimo()
1197df8bae1dSRodney W. Grimes {
1198df8bae1dSRodney W. Grimes 	register struct ipq *fp;
1199df8bae1dSRodney W. Grimes 	int s = splnet();
1200194a213eSAndrey A. Chernov 	int i;
1201df8bae1dSRodney W. Grimes 
1202194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1203462b86feSPoul-Henning Kamp 		for(fp = TAILQ_FIRST(&ipq[i]); fp;) {
1204462b86feSPoul-Henning Kamp 			struct ipq *fpp;
1205462b86feSPoul-Henning Kamp 
1206462b86feSPoul-Henning Kamp 			fpp = fp;
1207462b86feSPoul-Henning Kamp 			fp = TAILQ_NEXT(fp, ipq_list);
1208462b86feSPoul-Henning Kamp 			if(--fpp->ipq_ttl == 0) {
1209df8bae1dSRodney W. Grimes 				ipstat.ips_fragtimeout++;
1210462b86feSPoul-Henning Kamp 				ip_freef(&ipq[i], fpp);
1211df8bae1dSRodney W. Grimes 			}
1212df8bae1dSRodney W. Grimes 		}
1213194a213eSAndrey A. Chernov 	}
1214690a6055SJesper Skriver 	/*
1215690a6055SJesper Skriver 	 * If we are over the maximum number of fragments
1216690a6055SJesper Skriver 	 * (due to the limit being lowered), drain off
1217690a6055SJesper Skriver 	 * enough to get down to the new limit.
1218690a6055SJesper Skriver 	 */
1219690a6055SJesper Skriver 	for (i = 0; i < IPREASS_NHASH; i++) {
1220690a6055SJesper Skriver 		if (ip_maxfragpackets >= 0) {
1221690a6055SJesper Skriver 			while (ip_nfragpackets > ip_maxfragpackets &&
1222690a6055SJesper Skriver 				!TAILQ_EMPTY(&ipq[i])) {
1223690a6055SJesper Skriver 				ipstat.ips_fragdropped++;
1224690a6055SJesper Skriver 				ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1225690a6055SJesper Skriver 			}
1226690a6055SJesper Skriver 		}
1227690a6055SJesper Skriver 	}
12281f91d8c5SDavid Greenman 	ipflow_slowtimo();
1229df8bae1dSRodney W. Grimes 	splx(s);
1230df8bae1dSRodney W. Grimes }
1231df8bae1dSRodney W. Grimes 
1232df8bae1dSRodney W. Grimes /*
1233df8bae1dSRodney W. Grimes  * Drain off all datagram fragments.
1234df8bae1dSRodney W. Grimes  */
1235df8bae1dSRodney W. Grimes void
1236df8bae1dSRodney W. Grimes ip_drain()
1237df8bae1dSRodney W. Grimes {
1238194a213eSAndrey A. Chernov 	int     i;
1239ce29ab3aSGarrett Wollman 
1240194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1241462b86feSPoul-Henning Kamp 		while(!TAILQ_EMPTY(&ipq[i])) {
1242194a213eSAndrey A. Chernov 			ipstat.ips_fragdropped++;
1243462b86feSPoul-Henning Kamp 			ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1244194a213eSAndrey A. Chernov 		}
1245194a213eSAndrey A. Chernov 	}
1246ce29ab3aSGarrett Wollman 	in_rtqdrain();
1247df8bae1dSRodney W. Grimes }
1248df8bae1dSRodney W. Grimes 
1249df8bae1dSRodney W. Grimes /*
1250df8bae1dSRodney W. Grimes  * Do option processing on a datagram,
1251df8bae1dSRodney W. Grimes  * possibly discarding it if bad options are encountered,
1252df8bae1dSRodney W. Grimes  * or forwarding it if source-routed.
1253d0ebc0d2SYaroslav Tykhiy  * The pass argument is used when operating in the IPSTEALTH
1254d0ebc0d2SYaroslav Tykhiy  * mode to tell what options to process:
1255d0ebc0d2SYaroslav Tykhiy  * [LS]SRR (pass 0) or the others (pass 1).
1256d0ebc0d2SYaroslav Tykhiy  * The reason for as many as two passes is that when doing IPSTEALTH,
1257d0ebc0d2SYaroslav Tykhiy  * non-routing options should be processed only if the packet is for us.
1258df8bae1dSRodney W. Grimes  * Returns 1 if packet has been forwarded/freed,
1259df8bae1dSRodney W. Grimes  * 0 if the packet should be processed further.
1260df8bae1dSRodney W. Grimes  */
12610312fbe9SPoul-Henning Kamp static int
12622b25acc1SLuigi Rizzo ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
1263df8bae1dSRodney W. Grimes {
12642b25acc1SLuigi Rizzo 	struct ip *ip = mtod(m, struct ip *);
12652b25acc1SLuigi Rizzo 	u_char *cp;
12662b25acc1SLuigi Rizzo 	struct in_ifaddr *ia;
1267df8bae1dSRodney W. Grimes 	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
1268df8bae1dSRodney W. Grimes 	struct in_addr *sin, dst;
1269df8bae1dSRodney W. Grimes 	n_time ntime;
12704d2e3692SLuigi Rizzo 	struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
1271df8bae1dSRodney W. Grimes 
1272df8bae1dSRodney W. Grimes 	dst = ip->ip_dst;
1273df8bae1dSRodney W. Grimes 	cp = (u_char *)(ip + 1);
127453be11f6SPoul-Henning Kamp 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
1275df8bae1dSRodney W. Grimes 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
1276df8bae1dSRodney W. Grimes 		opt = cp[IPOPT_OPTVAL];
1277df8bae1dSRodney W. Grimes 		if (opt == IPOPT_EOL)
1278df8bae1dSRodney W. Grimes 			break;
1279df8bae1dSRodney W. Grimes 		if (opt == IPOPT_NOP)
1280df8bae1dSRodney W. Grimes 			optlen = 1;
1281df8bae1dSRodney W. Grimes 		else {
1282fdcb8debSJun-ichiro itojun Hagino 			if (cnt < IPOPT_OLEN + sizeof(*cp)) {
1283fdcb8debSJun-ichiro itojun Hagino 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1284fdcb8debSJun-ichiro itojun Hagino 				goto bad;
1285fdcb8debSJun-ichiro itojun Hagino 			}
1286df8bae1dSRodney W. Grimes 			optlen = cp[IPOPT_OLEN];
1287707d00a3SJonathan Lemon 			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
1288df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1289df8bae1dSRodney W. Grimes 				goto bad;
1290df8bae1dSRodney W. Grimes 			}
1291df8bae1dSRodney W. Grimes 		}
1292df8bae1dSRodney W. Grimes 		switch (opt) {
1293df8bae1dSRodney W. Grimes 
1294df8bae1dSRodney W. Grimes 		default:
1295df8bae1dSRodney W. Grimes 			break;
1296df8bae1dSRodney W. Grimes 
1297df8bae1dSRodney W. Grimes 		/*
1298df8bae1dSRodney W. Grimes 		 * Source routing with record.
1299df8bae1dSRodney W. Grimes 		 * Find interface with current destination address.
1300df8bae1dSRodney W. Grimes 		 * If none on this machine then drop if strictly routed,
1301df8bae1dSRodney W. Grimes 		 * or do nothing if loosely routed.
1302df8bae1dSRodney W. Grimes 		 * Record interface address and bring up next address
1303df8bae1dSRodney W. Grimes 		 * component.  If strictly routed make sure next
1304df8bae1dSRodney W. Grimes 		 * address is on directly accessible net.
1305df8bae1dSRodney W. Grimes 		 */
1306df8bae1dSRodney W. Grimes 		case IPOPT_LSRR:
1307df8bae1dSRodney W. Grimes 		case IPOPT_SSRR:
1308d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1309d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass > 0)
1310d0ebc0d2SYaroslav Tykhiy 				break;
1311d0ebc0d2SYaroslav Tykhiy #endif
131233841545SHajimu UMEMOTO 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
131333841545SHajimu UMEMOTO 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
131433841545SHajimu UMEMOTO 				goto bad;
131533841545SHajimu UMEMOTO 			}
1316df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1317df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1318df8bae1dSRodney W. Grimes 				goto bad;
1319df8bae1dSRodney W. Grimes 			}
1320df8bae1dSRodney W. Grimes 			ipaddr.sin_addr = ip->ip_dst;
1321df8bae1dSRodney W. Grimes 			ia = (struct in_ifaddr *)
1322df8bae1dSRodney W. Grimes 				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
1323df8bae1dSRodney W. Grimes 			if (ia == 0) {
1324df8bae1dSRodney W. Grimes 				if (opt == IPOPT_SSRR) {
1325df8bae1dSRodney W. Grimes 					type = ICMP_UNREACH;
1326df8bae1dSRodney W. Grimes 					code = ICMP_UNREACH_SRCFAIL;
1327df8bae1dSRodney W. Grimes 					goto bad;
1328df8bae1dSRodney W. Grimes 				}
1329bc189bf8SGuido van Rooij 				if (!ip_dosourceroute)
1330bc189bf8SGuido van Rooij 					goto nosourcerouting;
1331df8bae1dSRodney W. Grimes 				/*
1332df8bae1dSRodney W. Grimes 				 * Loose routing, and not at next destination
1333df8bae1dSRodney W. Grimes 				 * yet; nothing to do except forward.
1334df8bae1dSRodney W. Grimes 				 */
1335df8bae1dSRodney W. Grimes 				break;
1336df8bae1dSRodney W. Grimes 			}
1337df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
13385d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr)) {
1339df8bae1dSRodney W. Grimes 				/*
1340df8bae1dSRodney W. Grimes 				 * End of source route.  Should be for us.
1341df8bae1dSRodney W. Grimes 				 */
13424fce5804SGuido van Rooij 				if (!ip_acceptsourceroute)
13434fce5804SGuido van Rooij 					goto nosourcerouting;
1344df8bae1dSRodney W. Grimes 				save_rte(cp, ip->ip_src);
1345df8bae1dSRodney W. Grimes 				break;
1346df8bae1dSRodney W. Grimes 			}
1347d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1348d0ebc0d2SYaroslav Tykhiy 			if (ipstealth)
1349d0ebc0d2SYaroslav Tykhiy 				goto dropit;
1350d0ebc0d2SYaroslav Tykhiy #endif
13511025071fSGarrett Wollman 			if (!ip_dosourceroute) {
13520af8d3ecSDavid Greenman 				if (ipforwarding) {
13530af8d3ecSDavid Greenman 					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
13540af8d3ecSDavid Greenman 					/*
13550af8d3ecSDavid Greenman 					 * Acting as a router, so generate ICMP
13560af8d3ecSDavid Greenman 					 */
1357efa48587SGuido van Rooij nosourcerouting:
1358bc189bf8SGuido van Rooij 					strcpy(buf, inet_ntoa(ip->ip_dst));
13591025071fSGarrett Wollman 					log(LOG_WARNING,
13601025071fSGarrett Wollman 					    "attempted source route from %s to %s\n",
13611025071fSGarrett Wollman 					    inet_ntoa(ip->ip_src), buf);
13621025071fSGarrett Wollman 					type = ICMP_UNREACH;
13631025071fSGarrett Wollman 					code = ICMP_UNREACH_SRCFAIL;
13641025071fSGarrett Wollman 					goto bad;
13650af8d3ecSDavid Greenman 				} else {
13660af8d3ecSDavid Greenman 					/*
13670af8d3ecSDavid Greenman 					 * Not acting as a router, so silently drop.
13680af8d3ecSDavid Greenman 					 */
1369d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1370d0ebc0d2SYaroslav Tykhiy dropit:
1371d0ebc0d2SYaroslav Tykhiy #endif
13720af8d3ecSDavid Greenman 					ipstat.ips_cantforward++;
13730af8d3ecSDavid Greenman 					m_freem(m);
13740af8d3ecSDavid Greenman 					return (1);
13750af8d3ecSDavid Greenman 				}
13761025071fSGarrett Wollman 			}
13771025071fSGarrett Wollman 
1378df8bae1dSRodney W. Grimes 			/*
1379df8bae1dSRodney W. Grimes 			 * locate outgoing interface
1380df8bae1dSRodney W. Grimes 			 */
138194a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, cp + off,
1382df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
13831025071fSGarrett Wollman 
1384df8bae1dSRodney W. Grimes 			if (opt == IPOPT_SSRR) {
1385df8bae1dSRodney W. Grimes #define	INA	struct in_ifaddr *
1386df8bae1dSRodney W. Grimes #define	SA	struct sockaddr *
1387df8bae1dSRodney W. Grimes 			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
1388df8bae1dSRodney W. Grimes 				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
1389df8bae1dSRodney W. Grimes 			} else
1390bd714208SRuslan Ermilov 				ia = ip_rtaddr(ipaddr.sin_addr, &ipforward_rt);
1391df8bae1dSRodney W. Grimes 			if (ia == 0) {
1392df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1393df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_SRCFAIL;
1394df8bae1dSRodney W. Grimes 				goto bad;
1395df8bae1dSRodney W. Grimes 			}
1396df8bae1dSRodney W. Grimes 			ip->ip_dst = ipaddr.sin_addr;
139794a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
139894a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1399df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1400df8bae1dSRodney W. Grimes 			/*
1401df8bae1dSRodney W. Grimes 			 * Let ip_intr's mcast routing check handle mcast pkts
1402df8bae1dSRodney W. Grimes 			 */
1403df8bae1dSRodney W. Grimes 			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
1404df8bae1dSRodney W. Grimes 			break;
1405df8bae1dSRodney W. Grimes 
1406df8bae1dSRodney W. Grimes 		case IPOPT_RR:
1407d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1408d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass == 0)
1409d0ebc0d2SYaroslav Tykhiy 				break;
1410d0ebc0d2SYaroslav Tykhiy #endif
1411707d00a3SJonathan Lemon 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
1412707d00a3SJonathan Lemon 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1413707d00a3SJonathan Lemon 				goto bad;
1414707d00a3SJonathan Lemon 			}
1415df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1416df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1417df8bae1dSRodney W. Grimes 				goto bad;
1418df8bae1dSRodney W. Grimes 			}
1419df8bae1dSRodney W. Grimes 			/*
1420df8bae1dSRodney W. Grimes 			 * If no space remains, ignore.
1421df8bae1dSRodney W. Grimes 			 */
1422df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
14235d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr))
1424df8bae1dSRodney W. Grimes 				break;
142594a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
1426df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
1427df8bae1dSRodney W. Grimes 			/*
1428df8bae1dSRodney W. Grimes 			 * locate outgoing interface; if we're the destination,
1429df8bae1dSRodney W. Grimes 			 * use the incoming interface (should be same).
1430df8bae1dSRodney W. Grimes 			 */
1431df8bae1dSRodney W. Grimes 			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
1432bd714208SRuslan Ermilov 			    (ia = ip_rtaddr(ipaddr.sin_addr,
1433bd714208SRuslan Ermilov 			    &ipforward_rt)) == 0) {
1434df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1435df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_HOST;
1436df8bae1dSRodney W. Grimes 				goto bad;
1437df8bae1dSRodney W. Grimes 			}
143894a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
143994a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1440df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1441df8bae1dSRodney W. Grimes 			break;
1442df8bae1dSRodney W. Grimes 
1443df8bae1dSRodney W. Grimes 		case IPOPT_TS:
1444d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1445d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass == 0)
1446d0ebc0d2SYaroslav Tykhiy 				break;
1447d0ebc0d2SYaroslav Tykhiy #endif
1448df8bae1dSRodney W. Grimes 			code = cp - (u_char *)ip;
144907514071SJonathan Lemon 			if (optlen < 4 || optlen > 40) {
145007514071SJonathan Lemon 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1451df8bae1dSRodney W. Grimes 				goto bad;
145233841545SHajimu UMEMOTO 			}
145307514071SJonathan Lemon 			if ((off = cp[IPOPT_OFFSET]) < 5) {
145407514071SJonathan Lemon 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
145533841545SHajimu UMEMOTO 				goto bad;
145633841545SHajimu UMEMOTO 			}
145707514071SJonathan Lemon 			if (off > optlen - (int)sizeof(int32_t)) {
145807514071SJonathan Lemon 				cp[IPOPT_OFFSET + 1] += (1 << 4);
145907514071SJonathan Lemon 				if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) {
146007514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1461df8bae1dSRodney W. Grimes 					goto bad;
146233841545SHajimu UMEMOTO 				}
1463df8bae1dSRodney W. Grimes 				break;
1464df8bae1dSRodney W. Grimes 			}
146507514071SJonathan Lemon 			off--;				/* 0 origin */
146607514071SJonathan Lemon 			sin = (struct in_addr *)(cp + off);
146707514071SJonathan Lemon 			switch (cp[IPOPT_OFFSET + 1] & 0x0f) {
1468df8bae1dSRodney W. Grimes 
1469df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSONLY:
1470df8bae1dSRodney W. Grimes 				break;
1471df8bae1dSRodney W. Grimes 
1472df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSANDADDR:
147307514071SJonathan Lemon 				if (off + sizeof(n_time) +
147407514071SJonathan Lemon 				    sizeof(struct in_addr) > optlen) {
147507514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1476df8bae1dSRodney W. Grimes 					goto bad;
147733841545SHajimu UMEMOTO 				}
1478df8bae1dSRodney W. Grimes 				ipaddr.sin_addr = dst;
1479df8bae1dSRodney W. Grimes 				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
1480df8bae1dSRodney W. Grimes 							    m->m_pkthdr.rcvif);
1481df8bae1dSRodney W. Grimes 				if (ia == 0)
1482df8bae1dSRodney W. Grimes 					continue;
148394a5d9b6SDavid Greenman 				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
148494a5d9b6SDavid Greenman 				    sizeof(struct in_addr));
148507514071SJonathan Lemon 				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1486a5428e3aSMaxim Konovalov 				off += sizeof(struct in_addr);
1487df8bae1dSRodney W. Grimes 				break;
1488df8bae1dSRodney W. Grimes 
1489df8bae1dSRodney W. Grimes 			case IPOPT_TS_PRESPEC:
149007514071SJonathan Lemon 				if (off + sizeof(n_time) +
149107514071SJonathan Lemon 				    sizeof(struct in_addr) > optlen) {
149207514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1493df8bae1dSRodney W. Grimes 					goto bad;
149433841545SHajimu UMEMOTO 				}
149594a5d9b6SDavid Greenman 				(void)memcpy(&ipaddr.sin_addr, sin,
1496df8bae1dSRodney W. Grimes 				    sizeof(struct in_addr));
1497df8bae1dSRodney W. Grimes 				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
1498df8bae1dSRodney W. Grimes 					continue;
149907514071SJonathan Lemon 				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1500a5428e3aSMaxim Konovalov 				off += sizeof(struct in_addr);
1501df8bae1dSRodney W. Grimes 				break;
1502df8bae1dSRodney W. Grimes 
1503df8bae1dSRodney W. Grimes 			default:
150407514071SJonathan Lemon 				code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip;
1505df8bae1dSRodney W. Grimes 				goto bad;
1506df8bae1dSRodney W. Grimes 			}
1507df8bae1dSRodney W. Grimes 			ntime = iptime();
150807514071SJonathan Lemon 			(void)memcpy(cp + off, &ntime, sizeof(n_time));
150907514071SJonathan Lemon 			cp[IPOPT_OFFSET] += sizeof(n_time);
1510df8bae1dSRodney W. Grimes 		}
1511df8bae1dSRodney W. Grimes 	}
151247174b49SAndrey A. Chernov 	if (forward && ipforwarding) {
15132b25acc1SLuigi Rizzo 		ip_forward(m, 1, next_hop);
1514df8bae1dSRodney W. Grimes 		return (1);
1515df8bae1dSRodney W. Grimes 	}
1516df8bae1dSRodney W. Grimes 	return (0);
1517df8bae1dSRodney W. Grimes bad:
1518df8bae1dSRodney W. Grimes 	icmp_error(m, type, code, 0, 0);
1519df8bae1dSRodney W. Grimes 	ipstat.ips_badoptions++;
1520df8bae1dSRodney W. Grimes 	return (1);
1521df8bae1dSRodney W. Grimes }
1522df8bae1dSRodney W. Grimes 
1523df8bae1dSRodney W. Grimes /*
1524df8bae1dSRodney W. Grimes  * Given address of next destination (final or next hop),
1525df8bae1dSRodney W. Grimes  * return internet address info of interface to be used to get there.
1526df8bae1dSRodney W. Grimes  */
1527bd714208SRuslan Ermilov struct in_ifaddr *
1528bd714208SRuslan Ermilov ip_rtaddr(dst, rt)
1529df8bae1dSRodney W. Grimes 	struct in_addr dst;
1530bd714208SRuslan Ermilov 	struct route *rt;
1531df8bae1dSRodney W. Grimes {
1532df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
1533df8bae1dSRodney W. Grimes 
1534bd714208SRuslan Ermilov 	sin = (struct sockaddr_in *)&rt->ro_dst;
1535df8bae1dSRodney W. Grimes 
1536bd714208SRuslan Ermilov 	if (rt->ro_rt == 0 ||
1537bd714208SRuslan Ermilov 	    !(rt->ro_rt->rt_flags & RTF_UP) ||
15384078ffb1SRuslan Ermilov 	    dst.s_addr != sin->sin_addr.s_addr) {
1539bd714208SRuslan Ermilov 		if (rt->ro_rt) {
1540bd714208SRuslan Ermilov 			RTFREE(rt->ro_rt);
1541bd714208SRuslan Ermilov 			rt->ro_rt = 0;
1542df8bae1dSRodney W. Grimes 		}
1543df8bae1dSRodney W. Grimes 		sin->sin_family = AF_INET;
1544df8bae1dSRodney W. Grimes 		sin->sin_len = sizeof(*sin);
1545df8bae1dSRodney W. Grimes 		sin->sin_addr = dst;
1546df8bae1dSRodney W. Grimes 
1547bd714208SRuslan Ermilov 		rtalloc_ign(rt, RTF_PRCLONING);
1548df8bae1dSRodney W. Grimes 	}
1549bd714208SRuslan Ermilov 	if (rt->ro_rt == 0)
1550df8bae1dSRodney W. Grimes 		return ((struct in_ifaddr *)0);
1551bd714208SRuslan Ermilov 	return (ifatoia(rt->ro_rt->rt_ifa));
1552df8bae1dSRodney W. Grimes }
1553df8bae1dSRodney W. Grimes 
1554df8bae1dSRodney W. Grimes /*
1555df8bae1dSRodney W. Grimes  * Save incoming source route for use in replies,
1556df8bae1dSRodney W. Grimes  * to be picked up later by ip_srcroute if the receiver is interested.
1557df8bae1dSRodney W. Grimes  */
155837c84183SPoul-Henning Kamp static void
1559df8bae1dSRodney W. Grimes save_rte(option, dst)
1560df8bae1dSRodney W. Grimes 	u_char *option;
1561df8bae1dSRodney W. Grimes 	struct in_addr dst;
1562df8bae1dSRodney W. Grimes {
1563df8bae1dSRodney W. Grimes 	unsigned olen;
1564df8bae1dSRodney W. Grimes 
1565df8bae1dSRodney W. Grimes 	olen = option[IPOPT_OLEN];
1566df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1567df8bae1dSRodney W. Grimes 	if (ipprintfs)
1568df8bae1dSRodney W. Grimes 		printf("save_rte: olen %d\n", olen);
1569df8bae1dSRodney W. Grimes #endif
1570df8bae1dSRodney W. Grimes 	if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
1571df8bae1dSRodney W. Grimes 		return;
15720453d3cbSBruce Evans 	bcopy(option, ip_srcrt.srcopt, olen);
1573df8bae1dSRodney W. Grimes 	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
1574df8bae1dSRodney W. Grimes 	ip_srcrt.dst = dst;
1575df8bae1dSRodney W. Grimes }
1576df8bae1dSRodney W. Grimes 
1577df8bae1dSRodney W. Grimes /*
1578df8bae1dSRodney W. Grimes  * Retrieve incoming source route for use in replies,
1579df8bae1dSRodney W. Grimes  * in the same form used by setsockopt.
1580df8bae1dSRodney W. Grimes  * The first hop is placed before the options, will be removed later.
1581df8bae1dSRodney W. Grimes  */
1582df8bae1dSRodney W. Grimes struct mbuf *
1583df8bae1dSRodney W. Grimes ip_srcroute()
1584df8bae1dSRodney W. Grimes {
1585df8bae1dSRodney W. Grimes 	register struct in_addr *p, *q;
1586df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1587df8bae1dSRodney W. Grimes 
1588df8bae1dSRodney W. Grimes 	if (ip_nhops == 0)
1589df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1590cfe8b629SGarrett Wollman 	m = m_get(M_DONTWAIT, MT_HEADER);
1591df8bae1dSRodney W. Grimes 	if (m == 0)
1592df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1593df8bae1dSRodney W. Grimes 
1594df8bae1dSRodney W. Grimes #define OPTSIZ	(sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
1595df8bae1dSRodney W. Grimes 
1596df8bae1dSRodney W. Grimes 	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
1597df8bae1dSRodney W. Grimes 	m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
1598df8bae1dSRodney W. Grimes 	    OPTSIZ;
1599df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1600df8bae1dSRodney W. Grimes 	if (ipprintfs)
1601df8bae1dSRodney W. Grimes 		printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
1602df8bae1dSRodney W. Grimes #endif
1603df8bae1dSRodney W. Grimes 
1604df8bae1dSRodney W. Grimes 	/*
1605df8bae1dSRodney W. Grimes 	 * First save first hop for return route
1606df8bae1dSRodney W. Grimes 	 */
1607df8bae1dSRodney W. Grimes 	p = &ip_srcrt.route[ip_nhops - 1];
1608df8bae1dSRodney W. Grimes 	*(mtod(m, struct in_addr *)) = *p--;
1609df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1610df8bae1dSRodney W. Grimes 	if (ipprintfs)
1611af38c68cSLuigi Rizzo 		printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
1612df8bae1dSRodney W. Grimes #endif
1613df8bae1dSRodney W. Grimes 
1614df8bae1dSRodney W. Grimes 	/*
1615df8bae1dSRodney W. Grimes 	 * Copy option fields and padding (nop) to mbuf.
1616df8bae1dSRodney W. Grimes 	 */
1617df8bae1dSRodney W. Grimes 	ip_srcrt.nop = IPOPT_NOP;
1618df8bae1dSRodney W. Grimes 	ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
161994a5d9b6SDavid Greenman 	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
162094a5d9b6SDavid Greenman 	    &ip_srcrt.nop, OPTSIZ);
1621df8bae1dSRodney W. Grimes 	q = (struct in_addr *)(mtod(m, caddr_t) +
1622df8bae1dSRodney W. Grimes 	    sizeof(struct in_addr) + OPTSIZ);
1623df8bae1dSRodney W. Grimes #undef OPTSIZ
1624df8bae1dSRodney W. Grimes 	/*
1625df8bae1dSRodney W. Grimes 	 * Record return path as an IP source route,
1626df8bae1dSRodney W. Grimes 	 * reversing the path (pointers are now aligned).
1627df8bae1dSRodney W. Grimes 	 */
1628df8bae1dSRodney W. Grimes 	while (p >= ip_srcrt.route) {
1629df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1630df8bae1dSRodney W. Grimes 		if (ipprintfs)
1631af38c68cSLuigi Rizzo 			printf(" %lx", (u_long)ntohl(q->s_addr));
1632df8bae1dSRodney W. Grimes #endif
1633df8bae1dSRodney W. Grimes 		*q++ = *p--;
1634df8bae1dSRodney W. Grimes 	}
1635df8bae1dSRodney W. Grimes 	/*
1636df8bae1dSRodney W. Grimes 	 * Last hop goes to final destination.
1637df8bae1dSRodney W. Grimes 	 */
1638df8bae1dSRodney W. Grimes 	*q = ip_srcrt.dst;
1639df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1640df8bae1dSRodney W. Grimes 	if (ipprintfs)
1641af38c68cSLuigi Rizzo 		printf(" %lx\n", (u_long)ntohl(q->s_addr));
1642df8bae1dSRodney W. Grimes #endif
1643df8bae1dSRodney W. Grimes 	return (m);
1644df8bae1dSRodney W. Grimes }
1645df8bae1dSRodney W. Grimes 
1646df8bae1dSRodney W. Grimes /*
1647df8bae1dSRodney W. Grimes  * Strip out IP options, at higher
1648df8bae1dSRodney W. Grimes  * level protocol in the kernel.
1649df8bae1dSRodney W. Grimes  * Second argument is buffer to which options
1650df8bae1dSRodney W. Grimes  * will be moved, and return value is their length.
1651df8bae1dSRodney W. Grimes  * XXX should be deleted; last arg currently ignored.
1652df8bae1dSRodney W. Grimes  */
1653df8bae1dSRodney W. Grimes void
1654df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt)
1655df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1656df8bae1dSRodney W. Grimes 	struct mbuf *mopt;
1657df8bae1dSRodney W. Grimes {
1658df8bae1dSRodney W. Grimes 	register int i;
1659df8bae1dSRodney W. Grimes 	struct ip *ip = mtod(m, struct ip *);
1660df8bae1dSRodney W. Grimes 	register caddr_t opts;
1661df8bae1dSRodney W. Grimes 	int olen;
1662df8bae1dSRodney W. Grimes 
166353be11f6SPoul-Henning Kamp 	olen = (ip->ip_hl << 2) - sizeof (struct ip);
1664df8bae1dSRodney W. Grimes 	opts = (caddr_t)(ip + 1);
1665df8bae1dSRodney W. Grimes 	i = m->m_len - (sizeof (struct ip) + olen);
1666df8bae1dSRodney W. Grimes 	bcopy(opts + olen, opts, (unsigned)i);
1667df8bae1dSRodney W. Grimes 	m->m_len -= olen;
1668df8bae1dSRodney W. Grimes 	if (m->m_flags & M_PKTHDR)
1669df8bae1dSRodney W. Grimes 		m->m_pkthdr.len -= olen;
167053be11f6SPoul-Henning Kamp 	ip->ip_v = IPVERSION;
167153be11f6SPoul-Henning Kamp 	ip->ip_hl = sizeof(struct ip) >> 2;
1672df8bae1dSRodney W. Grimes }
1673df8bae1dSRodney W. Grimes 
1674df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = {
1675df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
1676df8bae1dSRodney W. Grimes 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
1677df8bae1dSRodney W. Grimes 	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
1678df8bae1dSRodney W. Grimes 	EMSGSIZE,	EHOSTUNREACH,	0,		0,
1679df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
16803b8123b7SJesper Skriver 	ENOPROTOOPT,	ECONNREFUSED
1681df8bae1dSRodney W. Grimes };
1682df8bae1dSRodney W. Grimes 
1683df8bae1dSRodney W. Grimes /*
1684df8bae1dSRodney W. Grimes  * Forward a packet.  If some error occurs return the sender
1685df8bae1dSRodney W. Grimes  * an icmp packet.  Note we can't always generate a meaningful
1686df8bae1dSRodney W. Grimes  * icmp message because icmp doesn't have a large enough repertoire
1687df8bae1dSRodney W. Grimes  * of codes and types.
1688df8bae1dSRodney W. Grimes  *
1689df8bae1dSRodney W. Grimes  * If not forwarding, just drop the packet.  This could be confusing
1690df8bae1dSRodney W. Grimes  * if ipforwarding was zero but some routing protocol was advancing
1691df8bae1dSRodney W. Grimes  * us as a gateway to somewhere.  However, we must let the routing
1692df8bae1dSRodney W. Grimes  * protocol deal with that.
1693df8bae1dSRodney W. Grimes  *
1694df8bae1dSRodney W. Grimes  * The srcrt parameter indicates whether the packet is being forwarded
1695df8bae1dSRodney W. Grimes  * via a source route.
1696df8bae1dSRodney W. Grimes  */
16970312fbe9SPoul-Henning Kamp static void
16982b25acc1SLuigi Rizzo ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
1699df8bae1dSRodney W. Grimes {
17002b25acc1SLuigi Rizzo 	struct ip *ip = mtod(m, struct ip *);
17012b25acc1SLuigi Rizzo 	struct rtentry *rt;
170226f9a767SRodney W. Grimes 	int error, type = 0, code = 0;
1703df8bae1dSRodney W. Grimes 	struct mbuf *mcopy;
1704df8bae1dSRodney W. Grimes 	n_long dest;
17053efc3014SJulian Elischer 	struct in_addr pkt_dst;
1706df8bae1dSRodney W. Grimes 	struct ifnet *destifp;
1707b9234fafSSam Leffler #if defined(IPSEC) || defined(FAST_IPSEC)
17086a800098SYoshinobu Inoue 	struct ifnet dummyifp;
17096a800098SYoshinobu Inoue #endif
1710df8bae1dSRodney W. Grimes 
1711df8bae1dSRodney W. Grimes 	dest = 0;
17123efc3014SJulian Elischer 	/*
17133efc3014SJulian Elischer 	 * Cache the destination address of the packet; this may be
17143efc3014SJulian Elischer 	 * changed by use of 'ipfw fwd'.
17153efc3014SJulian Elischer 	 */
17162b25acc1SLuigi Rizzo 	pkt_dst = next_hop ? next_hop->sin_addr : ip->ip_dst;
17173efc3014SJulian Elischer 
1718df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1719df8bae1dSRodney W. Grimes 	if (ipprintfs)
172061ce519bSPoul-Henning Kamp 		printf("forward: src %lx dst %lx ttl %x\n",
17213efc3014SJulian Elischer 		    (u_long)ip->ip_src.s_addr, (u_long)pkt_dst.s_addr,
1722162886e2SBruce Evans 		    ip->ip_ttl);
1723df8bae1dSRodney W. Grimes #endif
1724100ba1a6SJordan K. Hubbard 
1725100ba1a6SJordan K. Hubbard 
17263efc3014SJulian Elischer 	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(pkt_dst) == 0) {
1727df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1728df8bae1dSRodney W. Grimes 		m_freem(m);
1729df8bae1dSRodney W. Grimes 		return;
1730df8bae1dSRodney W. Grimes 	}
17311b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
17321b968362SDag-Erling Smørgrav 	if (!ipstealth) {
17331b968362SDag-Erling Smørgrav #endif
1734df8bae1dSRodney W. Grimes 		if (ip->ip_ttl <= IPTTLDEC) {
17351b968362SDag-Erling Smørgrav 			icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
17361b968362SDag-Erling Smørgrav 			    dest, 0);
1737df8bae1dSRodney W. Grimes 			return;
1738df8bae1dSRodney W. Grimes 		}
17391b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
17401b968362SDag-Erling Smørgrav 	}
17411b968362SDag-Erling Smørgrav #endif
1742df8bae1dSRodney W. Grimes 
17433efc3014SJulian Elischer 	if (ip_rtaddr(pkt_dst, &ipforward_rt) == 0) {
1744df8bae1dSRodney W. Grimes 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
1745df8bae1dSRodney W. Grimes 		return;
17464078ffb1SRuslan Ermilov 	} else
1747df8bae1dSRodney W. Grimes 		rt = ipforward_rt.ro_rt;
1748df8bae1dSRodney W. Grimes 
1749df8bae1dSRodney W. Grimes 	/*
1750bfef7ed4SIan Dowse 	 * Save the IP header and at most 8 bytes of the payload,
1751bfef7ed4SIan Dowse 	 * in case we need to generate an ICMP message to the src.
1752bfef7ed4SIan Dowse 	 *
17534d2e3692SLuigi Rizzo 	 * XXX this can be optimized a lot by saving the data in a local
17544d2e3692SLuigi Rizzo 	 * buffer on the stack (72 bytes at most), and only allocating the
17554d2e3692SLuigi Rizzo 	 * mbuf if really necessary. The vast majority of the packets
17564d2e3692SLuigi Rizzo 	 * are forwarded without having to send an ICMP back (either
17574d2e3692SLuigi Rizzo 	 * because unnecessary, or because rate limited), so we are
17584d2e3692SLuigi Rizzo 	 * really we are wasting a lot of work here.
17594d2e3692SLuigi Rizzo 	 *
1760bfef7ed4SIan Dowse 	 * We don't use m_copy() because it might return a reference
1761bfef7ed4SIan Dowse 	 * to a shared cluster. Both this function and ip_output()
1762bfef7ed4SIan Dowse 	 * assume exclusive access to the IP header in `m', so any
1763bfef7ed4SIan Dowse 	 * data in a cluster may change before we reach icmp_error().
1764df8bae1dSRodney W. Grimes 	 */
1765bfef7ed4SIan Dowse 	MGET(mcopy, M_DONTWAIT, m->m_type);
17669967cafcSSam Leffler 	if (mcopy != NULL && !m_dup_pkthdr(mcopy, m, M_DONTWAIT)) {
17679967cafcSSam Leffler 		/*
17689967cafcSSam Leffler 		 * It's probably ok if the pkthdr dup fails (because
17699967cafcSSam Leffler 		 * the deep copy of the tag chain failed), but for now
17709967cafcSSam Leffler 		 * be conservative and just discard the copy since
17719967cafcSSam Leffler 		 * code below may some day want the tags.
17729967cafcSSam Leffler 		 */
17739967cafcSSam Leffler 		m_free(mcopy);
17749967cafcSSam Leffler 		mcopy = NULL;
17759967cafcSSam Leffler 	}
1776bfef7ed4SIan Dowse 	if (mcopy != NULL) {
177753be11f6SPoul-Henning Kamp 		mcopy->m_len = imin((ip->ip_hl << 2) + 8,
1778bfef7ed4SIan Dowse 		    (int)ip->ip_len);
1779bfef7ed4SIan Dowse 		m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
1780e316463aSRobert Watson #ifdef MAC
1781e316463aSRobert Watson 		/*
1782e316463aSRobert Watson 		 * XXXMAC: This will eventually become an explicit
1783e316463aSRobert Watson 		 * labeling point.
1784e316463aSRobert Watson 		 */
1785e316463aSRobert Watson 		mac_create_mbuf_from_mbuf(m, mcopy);
1786e316463aSRobert Watson #endif
1787bfef7ed4SIan Dowse 	}
178804287599SRuslan Ermilov 
178904287599SRuslan Ermilov #ifdef IPSTEALTH
179004287599SRuslan Ermilov 	if (!ipstealth) {
179104287599SRuslan Ermilov #endif
179204287599SRuslan Ermilov 		ip->ip_ttl -= IPTTLDEC;
179304287599SRuslan Ermilov #ifdef IPSTEALTH
179404287599SRuslan Ermilov 	}
179504287599SRuslan Ermilov #endif
1796df8bae1dSRodney W. Grimes 
1797df8bae1dSRodney W. Grimes 	/*
1798df8bae1dSRodney W. Grimes 	 * If forwarding packet using same interface that it came in on,
1799df8bae1dSRodney W. Grimes 	 * perhaps should send a redirect to sender to shortcut a hop.
1800df8bae1dSRodney W. Grimes 	 * Only send redirect if source is sending directly to us,
1801df8bae1dSRodney W. Grimes 	 * and if packet was not source routed (or has any options).
1802df8bae1dSRodney W. Grimes 	 * Also, don't send redirect if forwarding using a default route
1803df8bae1dSRodney W. Grimes 	 * or a route modified by a redirect.
1804df8bae1dSRodney W. Grimes 	 */
1805df8bae1dSRodney W. Grimes 	if (rt->rt_ifp == m->m_pkthdr.rcvif &&
1806df8bae1dSRodney W. Grimes 	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
1807df8bae1dSRodney W. Grimes 	    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
18082b25acc1SLuigi Rizzo 	    ipsendredirects && !srcrt && !next_hop) {
1809df8bae1dSRodney W. Grimes #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
1810df8bae1dSRodney W. Grimes 		u_long src = ntohl(ip->ip_src.s_addr);
1811df8bae1dSRodney W. Grimes 
1812df8bae1dSRodney W. Grimes 		if (RTA(rt) &&
1813df8bae1dSRodney W. Grimes 		    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1814df8bae1dSRodney W. Grimes 		    if (rt->rt_flags & RTF_GATEWAY)
1815df8bae1dSRodney W. Grimes 			dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
1816df8bae1dSRodney W. Grimes 		    else
18173efc3014SJulian Elischer 			dest = pkt_dst.s_addr;
1818df8bae1dSRodney W. Grimes 		    /* Router requirements says to only send host redirects */
1819df8bae1dSRodney W. Grimes 		    type = ICMP_REDIRECT;
1820df8bae1dSRodney W. Grimes 		    code = ICMP_REDIRECT_HOST;
1821df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1822df8bae1dSRodney W. Grimes 		    if (ipprintfs)
1823df8bae1dSRodney W. Grimes 		        printf("redirect (%d) to %lx\n", code, (u_long)dest);
1824df8bae1dSRodney W. Grimes #endif
1825df8bae1dSRodney W. Grimes 		}
1826df8bae1dSRodney W. Grimes 	}
1827df8bae1dSRodney W. Grimes 
1828ea779ff3SLuigi Rizzo     {
1829ea779ff3SLuigi Rizzo 	struct m_hdr tag;
1830ea779ff3SLuigi Rizzo 
1831ea779ff3SLuigi Rizzo 	if (next_hop) {
1832ea779ff3SLuigi Rizzo 		/* Pass IPFORWARD info if available */
1833ea779ff3SLuigi Rizzo 
1834ea779ff3SLuigi Rizzo 		tag.mh_type = MT_TAG;
1835ea779ff3SLuigi Rizzo 		tag.mh_flags = PACKET_TAG_IPFORWARD;
1836ea779ff3SLuigi Rizzo 		tag.mh_data = (caddr_t)next_hop;
1837ea779ff3SLuigi Rizzo 		tag.mh_next = m;
1838ea779ff3SLuigi Rizzo 		m = (struct mbuf *)&tag;
1839ea779ff3SLuigi Rizzo 	}
1840b97d15cbSGarrett Wollman 	error = ip_output(m, (struct mbuf *)0, &ipforward_rt,
18415d846453SSam Leffler 			  IP_FORWARDING, 0, NULL);
1842ea779ff3SLuigi Rizzo     }
1843df8bae1dSRodney W. Grimes 	if (error)
1844df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1845df8bae1dSRodney W. Grimes 	else {
1846df8bae1dSRodney W. Grimes 		ipstat.ips_forward++;
1847df8bae1dSRodney W. Grimes 		if (type)
1848df8bae1dSRodney W. Grimes 			ipstat.ips_redirectsent++;
1849df8bae1dSRodney W. Grimes 		else {
18501f91d8c5SDavid Greenman 			if (mcopy) {
18511f91d8c5SDavid Greenman 				ipflow_create(&ipforward_rt, mcopy);
1852df8bae1dSRodney W. Grimes 				m_freem(mcopy);
18531f91d8c5SDavid Greenman 			}
1854df8bae1dSRodney W. Grimes 			return;
1855df8bae1dSRodney W. Grimes 		}
1856df8bae1dSRodney W. Grimes 	}
1857df8bae1dSRodney W. Grimes 	if (mcopy == NULL)
1858df8bae1dSRodney W. Grimes 		return;
1859df8bae1dSRodney W. Grimes 	destifp = NULL;
1860df8bae1dSRodney W. Grimes 
1861df8bae1dSRodney W. Grimes 	switch (error) {
1862df8bae1dSRodney W. Grimes 
1863df8bae1dSRodney W. Grimes 	case 0:				/* forwarded, but need redirect */
1864df8bae1dSRodney W. Grimes 		/* type, code set above */
1865df8bae1dSRodney W. Grimes 		break;
1866df8bae1dSRodney W. Grimes 
1867df8bae1dSRodney W. Grimes 	case ENETUNREACH:		/* shouldn't happen, checked above */
1868df8bae1dSRodney W. Grimes 	case EHOSTUNREACH:
1869df8bae1dSRodney W. Grimes 	case ENETDOWN:
1870df8bae1dSRodney W. Grimes 	case EHOSTDOWN:
1871df8bae1dSRodney W. Grimes 	default:
1872df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1873df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_HOST;
1874df8bae1dSRodney W. Grimes 		break;
1875df8bae1dSRodney W. Grimes 
1876df8bae1dSRodney W. Grimes 	case EMSGSIZE:
1877df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1878df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_NEEDFRAG;
18795d846453SSam Leffler #ifdef IPSEC
18806a800098SYoshinobu Inoue 		/*
18816a800098SYoshinobu Inoue 		 * If the packet is routed over IPsec tunnel, tell the
18826a800098SYoshinobu Inoue 		 * originator the tunnel MTU.
18836a800098SYoshinobu Inoue 		 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
18846a800098SYoshinobu Inoue 		 * XXX quickhack!!!
18856a800098SYoshinobu Inoue 		 */
18866a800098SYoshinobu Inoue 		if (ipforward_rt.ro_rt) {
18876a800098SYoshinobu Inoue 			struct secpolicy *sp = NULL;
18886a800098SYoshinobu Inoue 			int ipsecerror;
18896a800098SYoshinobu Inoue 			int ipsechdr;
18906a800098SYoshinobu Inoue 			struct route *ro;
18916a800098SYoshinobu Inoue 
18926a800098SYoshinobu Inoue 			sp = ipsec4_getpolicybyaddr(mcopy,
18936a800098SYoshinobu Inoue 						    IPSEC_DIR_OUTBOUND,
18946a800098SYoshinobu Inoue 			                            IP_FORWARDING,
18956a800098SYoshinobu Inoue 			                            &ipsecerror);
18966a800098SYoshinobu Inoue 
18976a800098SYoshinobu Inoue 			if (sp == NULL)
18986a800098SYoshinobu Inoue 				destifp = ipforward_rt.ro_rt->rt_ifp;
18996a800098SYoshinobu Inoue 			else {
19006a800098SYoshinobu Inoue 				/* count IPsec header size */
19016a800098SYoshinobu Inoue 				ipsechdr = ipsec4_hdrsiz(mcopy,
19026a800098SYoshinobu Inoue 							 IPSEC_DIR_OUTBOUND,
19036a800098SYoshinobu Inoue 							 NULL);
19046a800098SYoshinobu Inoue 
19056a800098SYoshinobu Inoue 				/*
19066a800098SYoshinobu Inoue 				 * find the correct route for outer IPv4
19076a800098SYoshinobu Inoue 				 * header, compute tunnel MTU.
19086a800098SYoshinobu Inoue 				 *
19096a800098SYoshinobu Inoue 				 * XXX BUG ALERT
19106a800098SYoshinobu Inoue 				 * The "dummyifp" code relies upon the fact
19116a800098SYoshinobu Inoue 				 * that icmp_error() touches only ifp->if_mtu.
19126a800098SYoshinobu Inoue 				 */
19136a800098SYoshinobu Inoue 				/*XXX*/
19146a800098SYoshinobu Inoue 				destifp = NULL;
19156a800098SYoshinobu Inoue 				if (sp->req != NULL
19166a800098SYoshinobu Inoue 				 && sp->req->sav != NULL
19176a800098SYoshinobu Inoue 				 && sp->req->sav->sah != NULL) {
19186a800098SYoshinobu Inoue 					ro = &sp->req->sav->sah->sa_route;
19196a800098SYoshinobu Inoue 					if (ro->ro_rt && ro->ro_rt->rt_ifp) {
19206a800098SYoshinobu Inoue 						dummyifp.if_mtu =
19216a800098SYoshinobu Inoue 						    ro->ro_rt->rt_ifp->if_mtu;
19226a800098SYoshinobu Inoue 						dummyifp.if_mtu -= ipsechdr;
19236a800098SYoshinobu Inoue 						destifp = &dummyifp;
19246a800098SYoshinobu Inoue 					}
19256a800098SYoshinobu Inoue 				}
19266a800098SYoshinobu Inoue 
19276a800098SYoshinobu Inoue 				key_freesp(sp);
19286a800098SYoshinobu Inoue 			}
19296a800098SYoshinobu Inoue 		}
1930b9234fafSSam Leffler #elif FAST_IPSEC
1931b9234fafSSam Leffler 		/*
1932b9234fafSSam Leffler 		 * If the packet is routed over IPsec tunnel, tell the
1933b9234fafSSam Leffler 		 * originator the tunnel MTU.
1934b9234fafSSam Leffler 		 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
1935b9234fafSSam Leffler 		 * XXX quickhack!!!
1936b9234fafSSam Leffler 		 */
1937b9234fafSSam Leffler 		if (ipforward_rt.ro_rt) {
1938b9234fafSSam Leffler 			struct secpolicy *sp = NULL;
1939b9234fafSSam Leffler 			int ipsecerror;
1940b9234fafSSam Leffler 			int ipsechdr;
1941b9234fafSSam Leffler 			struct route *ro;
1942b9234fafSSam Leffler 
1943b9234fafSSam Leffler 			sp = ipsec_getpolicybyaddr(mcopy,
1944b9234fafSSam Leffler 						   IPSEC_DIR_OUTBOUND,
1945b9234fafSSam Leffler 			                           IP_FORWARDING,
1946b9234fafSSam Leffler 			                           &ipsecerror);
1947b9234fafSSam Leffler 
1948b9234fafSSam Leffler 			if (sp == NULL)
1949b9234fafSSam Leffler 				destifp = ipforward_rt.ro_rt->rt_ifp;
1950b9234fafSSam Leffler 			else {
1951b9234fafSSam Leffler 				/* count IPsec header size */
1952b9234fafSSam Leffler 				ipsechdr = ipsec4_hdrsiz(mcopy,
1953b9234fafSSam Leffler 							 IPSEC_DIR_OUTBOUND,
1954b9234fafSSam Leffler 							 NULL);
1955b9234fafSSam Leffler 
1956b9234fafSSam Leffler 				/*
1957b9234fafSSam Leffler 				 * find the correct route for outer IPv4
1958b9234fafSSam Leffler 				 * header, compute tunnel MTU.
1959b9234fafSSam Leffler 				 *
1960b9234fafSSam Leffler 				 * XXX BUG ALERT
1961b9234fafSSam Leffler 				 * The "dummyifp" code relies upon the fact
1962b9234fafSSam Leffler 				 * that icmp_error() touches only ifp->if_mtu.
1963b9234fafSSam Leffler 				 */
1964b9234fafSSam Leffler 				/*XXX*/
1965b9234fafSSam Leffler 				destifp = NULL;
1966b9234fafSSam Leffler 				if (sp->req != NULL
1967b9234fafSSam Leffler 				 && sp->req->sav != NULL
1968b9234fafSSam Leffler 				 && sp->req->sav->sah != NULL) {
1969b9234fafSSam Leffler 					ro = &sp->req->sav->sah->sa_route;
1970b9234fafSSam Leffler 					if (ro->ro_rt && ro->ro_rt->rt_ifp) {
1971b9234fafSSam Leffler 						dummyifp.if_mtu =
1972b9234fafSSam Leffler 						    ro->ro_rt->rt_ifp->if_mtu;
1973b9234fafSSam Leffler 						dummyifp.if_mtu -= ipsechdr;
1974b9234fafSSam Leffler 						destifp = &dummyifp;
1975b9234fafSSam Leffler 					}
1976b9234fafSSam Leffler 				}
1977b9234fafSSam Leffler 
1978b9234fafSSam Leffler 				KEY_FREESP(&sp);
1979b9234fafSSam Leffler 			}
1980b9234fafSSam Leffler 		}
1981b9234fafSSam Leffler #else /* !IPSEC && !FAST_IPSEC */
19825d846453SSam Leffler 		if (ipforward_rt.ro_rt)
19835d846453SSam Leffler 			destifp = ipforward_rt.ro_rt->rt_ifp;
19846a800098SYoshinobu Inoue #endif /*IPSEC*/
1985df8bae1dSRodney W. Grimes 		ipstat.ips_cantfrag++;
1986df8bae1dSRodney W. Grimes 		break;
1987df8bae1dSRodney W. Grimes 
1988df8bae1dSRodney W. Grimes 	case ENOBUFS:
1989df285b3dSMike Silbersack 		/*
1990df285b3dSMike Silbersack 		 * A router should not generate ICMP_SOURCEQUENCH as
1991df285b3dSMike Silbersack 		 * required in RFC1812 Requirements for IP Version 4 Routers.
1992df285b3dSMike Silbersack 		 * Source quench could be a big problem under DoS attacks,
1993df285b3dSMike Silbersack 		 * or if the underlying interface is rate-limited.
1994df285b3dSMike Silbersack 		 * Those who need source quench packets may re-enable them
1995df285b3dSMike Silbersack 		 * via the net.inet.ip.sendsourcequench sysctl.
1996df285b3dSMike Silbersack 		 */
1997df285b3dSMike Silbersack 		if (ip_sendsourcequench == 0) {
1998df285b3dSMike Silbersack 			m_freem(mcopy);
1999df285b3dSMike Silbersack 			return;
2000df285b3dSMike Silbersack 		} else {
2001df8bae1dSRodney W. Grimes 			type = ICMP_SOURCEQUENCH;
2002df8bae1dSRodney W. Grimes 			code = 0;
2003df285b3dSMike Silbersack 		}
2004df8bae1dSRodney W. Grimes 		break;
20053a06e3e0SRuslan Ermilov 
20063a06e3e0SRuslan Ermilov 	case EACCES:			/* ipfw denied packet */
20073a06e3e0SRuslan Ermilov 		m_freem(mcopy);
20083a06e3e0SRuslan Ermilov 		return;
2009df8bae1dSRodney W. Grimes 	}
2010df8bae1dSRodney W. Grimes 	icmp_error(mcopy, type, code, dest, destifp);
2011df8bae1dSRodney W. Grimes }
2012df8bae1dSRodney W. Grimes 
201382c23ebaSBill Fenner void
201482c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m)
201582c23ebaSBill Fenner 	register struct inpcb *inp;
201682c23ebaSBill Fenner 	register struct mbuf **mp;
201782c23ebaSBill Fenner 	register struct ip *ip;
201882c23ebaSBill Fenner 	register struct mbuf *m;
201982c23ebaSBill Fenner {
202082c23ebaSBill Fenner 	if (inp->inp_socket->so_options & SO_TIMESTAMP) {
202182c23ebaSBill Fenner 		struct timeval tv;
202282c23ebaSBill Fenner 
202382c23ebaSBill Fenner 		microtime(&tv);
202482c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
202582c23ebaSBill Fenner 			SCM_TIMESTAMP, SOL_SOCKET);
202682c23ebaSBill Fenner 		if (*mp)
202782c23ebaSBill Fenner 			mp = &(*mp)->m_next;
20284cc20ab1SSeigo Tanimura 	}
202982c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVDSTADDR) {
203082c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
203182c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
203282c23ebaSBill Fenner 		if (*mp)
203382c23ebaSBill Fenner 			mp = &(*mp)->m_next;
203482c23ebaSBill Fenner 	}
203582c23ebaSBill Fenner #ifdef notyet
203682c23ebaSBill Fenner 	/* XXX
203782c23ebaSBill Fenner 	 * Moving these out of udp_input() made them even more broken
203882c23ebaSBill Fenner 	 * than they already were.
203982c23ebaSBill Fenner 	 */
204082c23ebaSBill Fenner 	/* options were tossed already */
204182c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVOPTS) {
204282c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) opts_deleted_above,
204382c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
204482c23ebaSBill Fenner 		if (*mp)
204582c23ebaSBill Fenner 			mp = &(*mp)->m_next;
204682c23ebaSBill Fenner 	}
204782c23ebaSBill Fenner 	/* ip_srcroute doesn't do what we want here, need to fix */
204882c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVRETOPTS) {
204982c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) ip_srcroute(),
205082c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
205182c23ebaSBill Fenner 		if (*mp)
205282c23ebaSBill Fenner 			mp = &(*mp)->m_next;
205382c23ebaSBill Fenner 	}
205482c23ebaSBill Fenner #endif
205582c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVIF) {
2056d314ad7bSJulian Elischer 		struct ifnet *ifp;
2057d314ad7bSJulian Elischer 		struct sdlbuf {
205882c23ebaSBill Fenner 			struct sockaddr_dl sdl;
2059d314ad7bSJulian Elischer 			u_char	pad[32];
2060d314ad7bSJulian Elischer 		} sdlbuf;
2061d314ad7bSJulian Elischer 		struct sockaddr_dl *sdp;
2062d314ad7bSJulian Elischer 		struct sockaddr_dl *sdl2 = &sdlbuf.sdl;
206382c23ebaSBill Fenner 
2064d314ad7bSJulian Elischer 		if (((ifp = m->m_pkthdr.rcvif))
2065d314ad7bSJulian Elischer 		&& ( ifp->if_index && (ifp->if_index <= if_index))) {
2066f9132cebSJonathan Lemon 			sdp = (struct sockaddr_dl *)
2067f9132cebSJonathan Lemon 			    (ifaddr_byindex(ifp->if_index)->ifa_addr);
2068d314ad7bSJulian Elischer 			/*
2069d314ad7bSJulian Elischer 			 * Change our mind and don't try copy.
2070d314ad7bSJulian Elischer 			 */
2071d314ad7bSJulian Elischer 			if ((sdp->sdl_family != AF_LINK)
2072d314ad7bSJulian Elischer 			|| (sdp->sdl_len > sizeof(sdlbuf))) {
2073d314ad7bSJulian Elischer 				goto makedummy;
2074d314ad7bSJulian Elischer 			}
2075d314ad7bSJulian Elischer 			bcopy(sdp, sdl2, sdp->sdl_len);
2076d314ad7bSJulian Elischer 		} else {
2077d314ad7bSJulian Elischer makedummy:
2078d314ad7bSJulian Elischer 			sdl2->sdl_len
2079d314ad7bSJulian Elischer 				= offsetof(struct sockaddr_dl, sdl_data[0]);
2080d314ad7bSJulian Elischer 			sdl2->sdl_family = AF_LINK;
2081d314ad7bSJulian Elischer 			sdl2->sdl_index = 0;
2082d314ad7bSJulian Elischer 			sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;
2083d314ad7bSJulian Elischer 		}
2084d314ad7bSJulian Elischer 		*mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,
208582c23ebaSBill Fenner 			IP_RECVIF, IPPROTO_IP);
208682c23ebaSBill Fenner 		if (*mp)
208782c23ebaSBill Fenner 			mp = &(*mp)->m_next;
208882c23ebaSBill Fenner 	}
208982c23ebaSBill Fenner }
209082c23ebaSBill Fenner 
20914d2e3692SLuigi Rizzo /*
20924d2e3692SLuigi Rizzo  * XXX these routines are called from the upper part of the kernel.
20934d2e3692SLuigi Rizzo  * They need to be locked when we remove Giant.
20944d2e3692SLuigi Rizzo  *
20954d2e3692SLuigi Rizzo  * They could also be moved to ip_mroute.c, since all the RSVP
20964d2e3692SLuigi Rizzo  *  handling is done there already.
20974d2e3692SLuigi Rizzo  */
20984d2e3692SLuigi Rizzo static int ip_rsvp_on;
20994d2e3692SLuigi Rizzo struct socket *ip_rsvpd;
2100df8bae1dSRodney W. Grimes int
2101f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so)
2102f0068c4aSGarrett Wollman {
2103f0068c4aSGarrett Wollman 	if (so->so_type != SOCK_RAW ||
2104f0068c4aSGarrett Wollman 	    so->so_proto->pr_protocol != IPPROTO_RSVP)
2105f0068c4aSGarrett Wollman 		return EOPNOTSUPP;
2106f0068c4aSGarrett Wollman 
2107f0068c4aSGarrett Wollman 	if (ip_rsvpd != NULL)
2108f0068c4aSGarrett Wollman 		return EADDRINUSE;
2109f0068c4aSGarrett Wollman 
2110f0068c4aSGarrett Wollman 	ip_rsvpd = so;
21111c5de19aSGarrett Wollman 	/*
21121c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-increment
21131c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
21141c5de19aSGarrett Wollman 	 */
21151c5de19aSGarrett Wollman 	if (!ip_rsvp_on) {
21161c5de19aSGarrett Wollman 		ip_rsvp_on = 1;
21171c5de19aSGarrett Wollman 		rsvp_on++;
21181c5de19aSGarrett Wollman 	}
2119f0068c4aSGarrett Wollman 
2120f0068c4aSGarrett Wollman 	return 0;
2121f0068c4aSGarrett Wollman }
2122f0068c4aSGarrett Wollman 
2123f0068c4aSGarrett Wollman int
2124f0068c4aSGarrett Wollman ip_rsvp_done(void)
2125f0068c4aSGarrett Wollman {
2126f0068c4aSGarrett Wollman 	ip_rsvpd = NULL;
21271c5de19aSGarrett Wollman 	/*
21281c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-decrement
21291c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
21301c5de19aSGarrett Wollman 	 */
21311c5de19aSGarrett Wollman 	if (ip_rsvp_on) {
21321c5de19aSGarrett Wollman 		ip_rsvp_on = 0;
21331c5de19aSGarrett Wollman 		rsvp_on--;
21341c5de19aSGarrett Wollman 	}
2135f0068c4aSGarrett Wollman 	return 0;
2136f0068c4aSGarrett Wollman }
2137bbb4330bSLuigi Rizzo 
2138bbb4330bSLuigi Rizzo void
2139bbb4330bSLuigi Rizzo rsvp_input(struct mbuf *m, int off)	/* XXX must fixup manually */
2140bbb4330bSLuigi Rizzo {
2141bbb4330bSLuigi Rizzo 	if (rsvp_input_p) { /* call the real one if loaded */
2142bbb4330bSLuigi Rizzo 		rsvp_input_p(m, off);
2143bbb4330bSLuigi Rizzo 		return;
2144bbb4330bSLuigi Rizzo 	}
2145bbb4330bSLuigi Rizzo 
2146bbb4330bSLuigi Rizzo 	/* Can still get packets with rsvp_on = 0 if there is a local member
2147bbb4330bSLuigi Rizzo 	 * of the group to which the RSVP packet is addressed.  But in this
2148bbb4330bSLuigi Rizzo 	 * case we want to throw the packet away.
2149bbb4330bSLuigi Rizzo 	 */
2150bbb4330bSLuigi Rizzo 
2151bbb4330bSLuigi Rizzo 	if (!rsvp_on) {
2152bbb4330bSLuigi Rizzo 		m_freem(m);
2153bbb4330bSLuigi Rizzo 		return;
2154bbb4330bSLuigi Rizzo 	}
2155bbb4330bSLuigi Rizzo 
2156bbb4330bSLuigi Rizzo 	if (ip_rsvpd != NULL) {
2157bbb4330bSLuigi Rizzo 		rip_input(m, off);
2158bbb4330bSLuigi Rizzo 		return;
2159bbb4330bSLuigi Rizzo 	}
2160bbb4330bSLuigi Rizzo 	/* Drop the packet */
2161bbb4330bSLuigi Rizzo 	m_freem(m);
2162bbb4330bSLuigi Rizzo }
2163