xref: /freebsd/sys/netinet/ip_input.c (revision ca925d9c17044d218daf631f3b733cb19fb36f69)
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 
3758938916SGarrett Wollman #define	_IP_VHL
3858938916SGarrett Wollman 
39e4f4247aSEivind Eklund #include "opt_bootp.h"
4074a9466cSGary Palmer #include "opt_ipfw.h"
41b715f178SLuigi Rizzo #include "opt_ipdn.h"
42fbd1372aSJoerg Wunsch #include "opt_ipdivert.h"
431ee25934SPeter Wemm #include "opt_ipfilter.h"
4427108a15SDag-Erling Smørgrav #include "opt_ipstealth.h"
456a800098SYoshinobu Inoue #include "opt_ipsec.h"
46c4ac87eaSDarren Reed #include "opt_pfil_hooks.h"
4764dddc18SKris Kennaway #include "opt_random_ip_id.h"
4874a9466cSGary Palmer 
49df8bae1dSRodney W. Grimes #include <sys/param.h>
50df8bae1dSRodney W. Grimes #include <sys/systm.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>
826ddbf1e2SGary Palmer 
836a800098SYoshinobu Inoue #ifdef IPSEC
846a800098SYoshinobu Inoue #include <netinet6/ipsec.h>
856a800098SYoshinobu Inoue #include <netkey/key.h>
866a800098SYoshinobu Inoue #endif
876a800098SYoshinobu Inoue 
88b715f178SLuigi Rizzo #ifdef DUMMYNET
89b715f178SLuigi Rizzo #include <netinet/ip_dummynet.h>
90b715f178SLuigi Rizzo #endif
91b715f178SLuigi Rizzo 
921c5de19aSGarrett Wollman int rsvp_on = 0;
93f708ef1bSPoul-Henning Kamp static int ip_rsvp_on;
94f0068c4aSGarrett Wollman struct socket *ip_rsvpd;
95f0068c4aSGarrett Wollman 
961f91d8c5SDavid Greenman int	ipforwarding = 0;
970312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW,
983d177f46SBill Fumerola     &ipforwarding, 0, "Enable IP forwarding between interfaces");
990312fbe9SPoul-Henning Kamp 
100d4fb926cSGarrett Wollman static int	ipsendredirects = 1; /* XXX */
1010312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW,
1023d177f46SBill Fumerola     &ipsendredirects, 0, "Enable sending IP redirects");
1030312fbe9SPoul-Henning Kamp 
104df8bae1dSRodney W. Grimes int	ip_defttl = IPDEFTTL;
1050312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW,
1063d177f46SBill Fumerola     &ip_defttl, 0, "Maximum TTL on IP packets");
1070312fbe9SPoul-Henning Kamp 
1080312fbe9SPoul-Henning Kamp static int	ip_dosourceroute = 0;
1090312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
1103d177f46SBill Fumerola     &ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
1114fce5804SGuido van Rooij 
1124fce5804SGuido van Rooij static int	ip_acceptsourceroute = 0;
1134fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute,
1143d177f46SBill Fumerola     CTLFLAG_RW, &ip_acceptsourceroute, 0,
1153d177f46SBill Fumerola     "Enable accepting source routed IP packets");
1166a800098SYoshinobu Inoue 
1176a800098SYoshinobu Inoue static int	ip_keepfaith = 0;
1186a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
1196a800098SYoshinobu Inoue 	&ip_keepfaith,	0,
1206a800098SYoshinobu Inoue 	"Enable packet capture for FAITH IPv4->IPv6 translater daemon");
1216a800098SYoshinobu Inoue 
122690a6055SJesper Skriver static int	ip_nfragpackets = 0;
12396c2b042SJesper Skriver static int	ip_maxfragpackets;	/* initialized in ip_init() */
124690a6055SJesper Skriver SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW,
125690a6055SJesper Skriver 	&ip_maxfragpackets, 0,
126690a6055SJesper Skriver 	"Maximum number of IPv4 fragment reassembly queue entries");
127690a6055SJesper Skriver 
128823db0e9SDon Lewis /*
129823db0e9SDon Lewis  * XXX - Setting ip_checkinterface mostly implements the receive side of
130823db0e9SDon Lewis  * the Strong ES model described in RFC 1122, but since the routing table
131a8f12100SDon Lewis  * and transmit implementation do not implement the Strong ES model,
132823db0e9SDon Lewis  * setting this to 1 results in an odd hybrid.
1333f67c834SDon Lewis  *
134a8f12100SDon Lewis  * XXX - ip_checkinterface currently must be disabled if you use ipnat
135a8f12100SDon Lewis  * to translate the destination address to another local interface.
1363f67c834SDon Lewis  *
1373f67c834SDon Lewis  * XXX - ip_checkinterface must be disabled if you add IP aliases
1383f67c834SDon Lewis  * to the loopback interface instead of the interface where the
1393f67c834SDon Lewis  * packets for those addresses are received.
140823db0e9SDon Lewis  */
141b3e95d4eSJonathan Lemon static int	ip_checkinterface = 1;
142b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW,
143b3e95d4eSJonathan Lemon     &ip_checkinterface, 0, "Verify packet arrives on correct interface");
144b3e95d4eSJonathan Lemon 
145df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1460312fbe9SPoul-Henning Kamp static int	ipprintfs = 0;
147df8bae1dSRodney W. Grimes #endif
148df8bae1dSRodney W. Grimes 
149ca925d9cSJonathan Lemon static int	ipqmaxlen = IFQ_MAXLEN;
150ca925d9cSJonathan Lemon 
151df8bae1dSRodney W. Grimes extern	struct domain inetdomain;
152f0ffb944SJulian Elischer extern	struct protosw inetsw[];
153df8bae1dSRodney W. Grimes u_char	ip_protox[IPPROTO_MAX];
15459562606SGarrett Wollman struct	in_ifaddrhead in_ifaddrhead; 		/* first inet address */
155ca925d9cSJonathan Lemon struct	in_ifaddrhashhead *in_ifaddrhashtbl;	/* inet addr hash table  */
156ca925d9cSJonathan Lemon u_long 	in_ifaddrhmask;				/* mask for hash table */
157ca925d9cSJonathan Lemon 
158afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW,
1593d177f46SBill Fumerola     &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue");
1600312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
1613d177f46SBill Fumerola     &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue");
162df8bae1dSRodney W. Grimes 
163f23b4c91SGarrett Wollman struct ipstat ipstat;
164c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW,
1653d177f46SBill Fumerola     &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)");
166194a213eSAndrey A. Chernov 
167194a213eSAndrey A. Chernov /* Packet reassembly stuff */
168194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2      6
169194a213eSAndrey A. Chernov #define IPREASS_NHASH           (1 << IPREASS_NHASH_LOG2)
170194a213eSAndrey A. Chernov #define IPREASS_HMASK           (IPREASS_NHASH - 1)
171194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \
172831a80b0SMatthew Dillon 	(((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
173194a213eSAndrey A. Chernov 
174462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH];
175194a213eSAndrey A. Chernov static int    nipq = 0;         /* total # of reass queues */
176194a213eSAndrey A. Chernov static int    maxnipq;
177367d34f8SBrian Somers const  int    ipintrq_present = 1;
178f23b4c91SGarrett Wollman 
1790312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU
1800312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
1813d177f46SBill Fumerola     &ip_mtu, 0, "Default MTU");
1820312fbe9SPoul-Henning Kamp #endif
1830312fbe9SPoul-Henning Kamp 
1841b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
1851b968362SDag-Erling Smørgrav static int	ipstealth = 0;
1861b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW,
1871b968362SDag-Erling Smørgrav     &ipstealth, 0, "");
1881b968362SDag-Erling Smørgrav #endif
1891b968362SDag-Erling Smørgrav 
190cfe8b629SGarrett Wollman 
19123bf9953SPoul-Henning Kamp /* Firewall hooks */
19223bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr;
19323bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr;
1949fcc0795SLuigi Rizzo int fw_enable = 1 ;
195e7319babSPoul-Henning Kamp 
196b715f178SLuigi Rizzo #ifdef DUMMYNET
197b715f178SLuigi Rizzo ip_dn_ctl_t *ip_dn_ctl_ptr;
198b715f178SLuigi Rizzo #endif
199b715f178SLuigi Rizzo 
200afed1b49SDarren Reed 
201e7319babSPoul-Henning Kamp /*
202df8bae1dSRodney W. Grimes  * We need to save the IP options in case a protocol wants to respond
203df8bae1dSRodney W. Grimes  * to an incoming packet over the same route if the packet got here
204df8bae1dSRodney W. Grimes  * using IP source routing.  This allows connection establishment and
205df8bae1dSRodney W. Grimes  * maintenance when the remote end is on a network that is not known
206df8bae1dSRodney W. Grimes  * to us.
207df8bae1dSRodney W. Grimes  */
2080312fbe9SPoul-Henning Kamp static int	ip_nhops = 0;
209df8bae1dSRodney W. Grimes static	struct ip_srcrt {
210df8bae1dSRodney W. Grimes 	struct	in_addr dst;			/* final destination */
211df8bae1dSRodney W. Grimes 	char	nop;				/* one NOP to align */
212df8bae1dSRodney W. Grimes 	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
213df8bae1dSRodney W. Grimes 	struct	in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
214df8bae1dSRodney W. Grimes } ip_srcrt;
215df8bae1dSRodney W. Grimes 
216f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr;
217f9e354dfSJulian Elischer 
218df8bae1dSRodney W. Grimes static void	save_rte __P((u_char *, struct in_addr));
2190312fbe9SPoul-Henning Kamp static int	ip_dooptions __P((struct mbuf *));
2200312fbe9SPoul-Henning Kamp static void	ip_forward __P((struct mbuf *, int));
221462b86feSPoul-Henning Kamp static void	ip_freef __P((struct ipqhead *, struct ipq *));
2228948e4baSArchie Cobbs #ifdef IPDIVERT
223462b86feSPoul-Henning Kamp static struct	mbuf *ip_reass __P((struct mbuf *, struct ipqhead *, struct ipq *, u_int32_t *, u_int16_t *));
2248948e4baSArchie Cobbs #else
225462b86feSPoul-Henning Kamp static struct	mbuf *ip_reass __P((struct mbuf *, struct ipqhead *, struct ipq *));
2268948e4baSArchie Cobbs #endif
2278948e4baSArchie Cobbs static struct	in_ifaddr *ip_rtaddr __P((struct in_addr));
2280312fbe9SPoul-Henning Kamp static void	ipintr __P((void));
2298948e4baSArchie Cobbs 
230df8bae1dSRodney W. Grimes /*
231df8bae1dSRodney W. Grimes  * IP initialization: fill in IP protocol switch table.
232df8bae1dSRodney W. Grimes  * All protocols not implemented in kernel go to raw IP protocol handler.
233df8bae1dSRodney W. Grimes  */
234df8bae1dSRodney W. Grimes void
235df8bae1dSRodney W. Grimes ip_init()
236df8bae1dSRodney W. Grimes {
237f0ffb944SJulian Elischer 	register struct protosw *pr;
238df8bae1dSRodney W. Grimes 	register int i;
239df8bae1dSRodney W. Grimes 
24059562606SGarrett Wollman 	TAILQ_INIT(&in_ifaddrhead);
241ca925d9cSJonathan Lemon 	in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask);
242f0ffb944SJulian Elischer 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
243df8bae1dSRodney W. Grimes 	if (pr == 0)
244df8bae1dSRodney W. Grimes 		panic("ip_init");
245df8bae1dSRodney W. Grimes 	for (i = 0; i < IPPROTO_MAX; i++)
246df8bae1dSRodney W. Grimes 		ip_protox[i] = pr - inetsw;
247f0ffb944SJulian Elischer 	for (pr = inetdomain.dom_protosw;
248f0ffb944SJulian Elischer 	    pr < inetdomain.dom_protoswNPROTOSW; pr++)
249df8bae1dSRodney W. Grimes 		if (pr->pr_domain->dom_family == PF_INET &&
250df8bae1dSRodney W. Grimes 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
251df8bae1dSRodney W. Grimes 			ip_protox[pr->pr_protocol] = pr - inetsw;
252194a213eSAndrey A. Chernov 
253194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++)
254462b86feSPoul-Henning Kamp 	    TAILQ_INIT(&ipq[i]);
255194a213eSAndrey A. Chernov 
256194a213eSAndrey A. Chernov 	maxnipq = nmbclusters / 4;
25796c2b042SJesper Skriver 	ip_maxfragpackets = nmbclusters / 4;
258194a213eSAndrey A. Chernov 
25964dddc18SKris Kennaway #ifndef RANDOM_IP_ID
260227ee8a1SPoul-Henning Kamp 	ip_id = time_second & 0xffff;
26164dddc18SKris Kennaway #endif
262df8bae1dSRodney W. Grimes 	ipintrq.ifq_maxlen = ipqmaxlen;
263df5e1987SJonathan Lemon 	mtx_init(&ipintrq.ifq_mtx, "ip_inq", MTX_DEF);
264242c5536SPeter Wemm 
265242c5536SPeter Wemm 	register_netisr(NETISR_IP, ipintr);
266df8bae1dSRodney W. Grimes }
267df8bae1dSRodney W. Grimes 
2680312fbe9SPoul-Henning Kamp static struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
2691e3d5af0SRuslan Ermilov struct	route ipforward_rt;
270df8bae1dSRodney W. Grimes 
271df8bae1dSRodney W. Grimes /*
272df8bae1dSRodney W. Grimes  * Ip input routine.  Checksum and byte swap header.  If fragmented
273df8bae1dSRodney W. Grimes  * try to reassemble.  Process options.  Pass to next level.
274df8bae1dSRodney W. Grimes  */
275c67b1d17SGarrett Wollman void
276c67b1d17SGarrett Wollman ip_input(struct mbuf *m)
277df8bae1dSRodney W. Grimes {
27823bf9953SPoul-Henning Kamp 	struct ip *ip;
27923bf9953SPoul-Henning Kamp 	struct ipq *fp;
2805da9f8faSJosef Karthauser 	struct in_ifaddr *ia = NULL;
281ca925d9cSJonathan Lemon 	struct ifaddr *ifa;
282823db0e9SDon Lewis 	int    i, hlen, checkif;
28347c861ecSBrian Somers 	u_short sum;
2848948e4baSArchie Cobbs 	u_int16_t divert_cookie;		/* firewall cookie */
2857538a9a0SJonathan Lemon 	struct in_addr pkt_dst;
2868948e4baSArchie Cobbs #ifdef IPDIVERT
2878948e4baSArchie Cobbs 	u_int32_t divert_info = 0;		/* packet divert/tee info */
288b715f178SLuigi Rizzo #endif
289830cc178SLuigi Rizzo 	struct ip_fw *rule = NULL;
290c4ac87eaSDarren Reed #ifdef PFIL_HOOKS
291c4ac87eaSDarren Reed 	struct packet_filter_hook *pfh;
292c4ac87eaSDarren Reed 	struct mbuf *m0;
293c4ac87eaSDarren Reed 	int rv;
294c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */
295b715f178SLuigi Rizzo 
2968948e4baSArchie Cobbs #ifdef IPDIVERT
2978948e4baSArchie Cobbs 	/* Get and reset firewall cookie */
2988948e4baSArchie Cobbs 	divert_cookie = ip_divert_cookie;
2998948e4baSArchie Cobbs 	ip_divert_cookie = 0;
3008948e4baSArchie Cobbs #else
3018948e4baSArchie Cobbs 	divert_cookie = 0;
3028948e4baSArchie Cobbs #endif
3038948e4baSArchie Cobbs 
304b715f178SLuigi Rizzo #if defined(IPFIREWALL) && defined(DUMMYNET)
305b715f178SLuigi Rizzo         /*
306b715f178SLuigi Rizzo          * dummynet packet are prepended a vestigial mbuf with
307b715f178SLuigi Rizzo          * m_type = MT_DUMMYNET and m_data pointing to the matching
308b715f178SLuigi Rizzo          * rule.
309b715f178SLuigi Rizzo          */
310b715f178SLuigi Rizzo         if (m->m_type == MT_DUMMYNET) {
311830cc178SLuigi Rizzo             rule = (struct ip_fw *)(m->m_data) ;
312b715f178SLuigi Rizzo             m = m->m_next ;
313b715f178SLuigi Rizzo             ip = mtod(m, struct ip *);
314b715f178SLuigi Rizzo             hlen = IP_VHL_HL(ip->ip_vhl) << 2;
315b715f178SLuigi Rizzo             goto iphack ;
316b715f178SLuigi Rizzo         } else
317b715f178SLuigi Rizzo             rule = NULL ;
318b715f178SLuigi Rizzo #endif
319df8bae1dSRodney W. Grimes 
320df8bae1dSRodney W. Grimes #ifdef	DIAGNOSTIC
321ed7509acSJulian Elischer 	if (m == NULL || (m->m_flags & M_PKTHDR) == 0)
32258938916SGarrett Wollman 		panic("ip_input no HDR");
323df8bae1dSRodney W. Grimes #endif
324df8bae1dSRodney W. Grimes 	ipstat.ips_total++;
32558938916SGarrett Wollman 
32658938916SGarrett Wollman 	if (m->m_pkthdr.len < sizeof(struct ip))
32758938916SGarrett Wollman 		goto tooshort;
32858938916SGarrett Wollman 
329df8bae1dSRodney W. Grimes 	if (m->m_len < sizeof (struct ip) &&
330df8bae1dSRodney W. Grimes 	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
331df8bae1dSRodney W. Grimes 		ipstat.ips_toosmall++;
332c67b1d17SGarrett Wollman 		return;
333df8bae1dSRodney W. Grimes 	}
334df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
33558938916SGarrett Wollman 
33658938916SGarrett Wollman 	if (IP_VHL_V(ip->ip_vhl) != IPVERSION) {
337df8bae1dSRodney W. Grimes 		ipstat.ips_badvers++;
338df8bae1dSRodney W. Grimes 		goto bad;
339df8bae1dSRodney W. Grimes 	}
34058938916SGarrett Wollman 
34158938916SGarrett Wollman 	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
342df8bae1dSRodney W. Grimes 	if (hlen < sizeof(struct ip)) {	/* minimum header length */
343df8bae1dSRodney W. Grimes 		ipstat.ips_badhlen++;
344df8bae1dSRodney W. Grimes 		goto bad;
345df8bae1dSRodney W. Grimes 	}
346df8bae1dSRodney W. Grimes 	if (hlen > m->m_len) {
347df8bae1dSRodney W. Grimes 		if ((m = m_pullup(m, hlen)) == 0) {
348df8bae1dSRodney W. Grimes 			ipstat.ips_badhlen++;
349c67b1d17SGarrett Wollman 			return;
350df8bae1dSRodney W. Grimes 		}
351df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
352df8bae1dSRodney W. Grimes 	}
35333841545SHajimu UMEMOTO 
35433841545SHajimu UMEMOTO 	/* 127/8 must not appear on wire - RFC1122 */
35533841545SHajimu UMEMOTO 	if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
35633841545SHajimu UMEMOTO 	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
35733841545SHajimu UMEMOTO 		if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
35833841545SHajimu UMEMOTO 			ipstat.ips_badaddr++;
35933841545SHajimu UMEMOTO 			goto bad;
36033841545SHajimu UMEMOTO 		}
36133841545SHajimu UMEMOTO 	}
36233841545SHajimu UMEMOTO 
363db4f9cc7SJonathan Lemon 	if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
364db4f9cc7SJonathan Lemon 		sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
365db4f9cc7SJonathan Lemon 	} else {
36658938916SGarrett Wollman 		if (hlen == sizeof(struct ip)) {
36747c861ecSBrian Somers 			sum = in_cksum_hdr(ip);
36858938916SGarrett Wollman 		} else {
36947c861ecSBrian Somers 			sum = in_cksum(m, hlen);
37058938916SGarrett Wollman 		}
371db4f9cc7SJonathan Lemon 	}
37247c861ecSBrian Somers 	if (sum) {
373df8bae1dSRodney W. Grimes 		ipstat.ips_badsum++;
374df8bae1dSRodney W. Grimes 		goto bad;
375df8bae1dSRodney W. Grimes 	}
376df8bae1dSRodney W. Grimes 
377df8bae1dSRodney W. Grimes 	/*
378df8bae1dSRodney W. Grimes 	 * Convert fields to host representation.
379df8bae1dSRodney W. Grimes 	 */
380df8bae1dSRodney W. Grimes 	NTOHS(ip->ip_len);
381df8bae1dSRodney W. Grimes 	if (ip->ip_len < hlen) {
382df8bae1dSRodney W. Grimes 		ipstat.ips_badlen++;
383df8bae1dSRodney W. Grimes 		goto bad;
384df8bae1dSRodney W. Grimes 	}
385df8bae1dSRodney W. Grimes 	NTOHS(ip->ip_off);
386df8bae1dSRodney W. Grimes 
387df8bae1dSRodney W. Grimes 	/*
388df8bae1dSRodney W. Grimes 	 * Check that the amount of data in the buffers
389df8bae1dSRodney W. Grimes 	 * is as at least much as the IP header would have us expect.
390df8bae1dSRodney W. Grimes 	 * Trim mbufs if longer than we expect.
391df8bae1dSRodney W. Grimes 	 * Drop packet if shorter than we expect.
392df8bae1dSRodney W. Grimes 	 */
393df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len < ip->ip_len) {
39458938916SGarrett Wollman tooshort:
395df8bae1dSRodney W. Grimes 		ipstat.ips_tooshort++;
396df8bae1dSRodney W. Grimes 		goto bad;
397df8bae1dSRodney W. Grimes 	}
398df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len > ip->ip_len) {
399df8bae1dSRodney W. Grimes 		if (m->m_len == m->m_pkthdr.len) {
400df8bae1dSRodney W. Grimes 			m->m_len = ip->ip_len;
401df8bae1dSRodney W. Grimes 			m->m_pkthdr.len = ip->ip_len;
402df8bae1dSRodney W. Grimes 		} else
403df8bae1dSRodney W. Grimes 			m_adj(m, ip->ip_len - m->m_pkthdr.len);
404df8bae1dSRodney W. Grimes 	}
4053f67c834SDon Lewis 
40633841545SHajimu UMEMOTO #ifdef IPSEC
40733841545SHajimu UMEMOTO 	if (ipsec_gethist(m, NULL))
40833841545SHajimu UMEMOTO 		goto pass;
40933841545SHajimu UMEMOTO #endif
4103f67c834SDon Lewis 
4114dd1662bSUgen J.S. Antsilevich 	/*
4124dd1662bSUgen J.S. Antsilevich 	 * IpHack's section.
4134dd1662bSUgen J.S. Antsilevich 	 * Right now when no processing on packet has done
4144dd1662bSUgen J.S. Antsilevich 	 * and it is still fresh out of network we do our black
4154dd1662bSUgen J.S. Antsilevich 	 * deals with it.
41693e0e116SJulian Elischer 	 * - Firewall: deny/allow/divert
417fed1c7e9SSøren Schmidt 	 * - Xlate: translate packet's addr/port (NAT).
418b715f178SLuigi Rizzo 	 * - Pipe: pass pkt through dummynet.
4194dd1662bSUgen J.S. Antsilevich 	 * - Wrap: fake packet's addr/port <unimpl.>
4204dd1662bSUgen J.S. Antsilevich 	 * - Encapsulate: put it in another IP and send out. <unimp.>
4214dd1662bSUgen J.S. Antsilevich  	 */
422b715f178SLuigi Rizzo 
423dee383e0SEivind Eklund #if defined(IPFIREWALL) && defined(DUMMYNET)
424b715f178SLuigi Rizzo iphack:
425dee383e0SEivind Eklund #endif
426df8bae1dSRodney W. Grimes 
427c4ac87eaSDarren Reed #ifdef PFIL_HOOKS
428c4ac87eaSDarren Reed 	/*
429c4ac87eaSDarren Reed 	 * Run through list of hooks for input packets.  If there are any
430c4ac87eaSDarren Reed 	 * filters which require that additional packets in the flow are
431c4ac87eaSDarren Reed 	 * not fast-forwarded, they must clear the M_CANFASTFWD flag.
432c4ac87eaSDarren Reed 	 * Note that filters must _never_ set this flag, as another filter
433c4ac87eaSDarren Reed 	 * in the list may have previously cleared it.
434c4ac87eaSDarren Reed 	 */
435c4ac87eaSDarren Reed 	m0 = m;
436c4ac87eaSDarren Reed 	pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
437fc2ffbe6SPoul-Henning Kamp 	for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link))
438c4ac87eaSDarren Reed 		if (pfh->pfil_func) {
439c4ac87eaSDarren Reed 			rv = pfh->pfil_func(ip, hlen,
440c4ac87eaSDarren Reed 					    m->m_pkthdr.rcvif, 0, &m0);
441c4ac87eaSDarren Reed 			if (rv)
442beec8214SDarren Reed 				return;
443c4ac87eaSDarren Reed 			m = m0;
444c4ac87eaSDarren Reed 			if (m == NULL)
445c4ac87eaSDarren Reed 				return;
446c4ac87eaSDarren Reed 			ip = mtod(m, struct ip *);
447beec8214SDarren Reed 		}
448c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */
449c4ac87eaSDarren Reed 
4506bc748b0SLuigi Rizzo 	if (fw_enable && ip_fw_chk_ptr) {
451f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD
452f9e354dfSJulian Elischer 		/*
453f9e354dfSJulian Elischer 		 * If we've been forwarded from the output side, then
454f9e354dfSJulian Elischer 		 * skip the firewall a second time
455f9e354dfSJulian Elischer 		 */
456f9e354dfSJulian Elischer 		if (ip_fw_fwd_addr)
457f9e354dfSJulian Elischer 			goto ours;
458f9e354dfSJulian Elischer #endif	/* IPFIREWALL_FORWARD */
459f9e354dfSJulian Elischer 		/*
4608948e4baSArchie Cobbs 		 * See the comment in ip_output for the return values
461b715f178SLuigi Rizzo 		 * produced by the firewall.
462f9e354dfSJulian Elischer 		 */
4638948e4baSArchie Cobbs 		i = (*ip_fw_chk_ptr)(&ip,
4648948e4baSArchie Cobbs 		    hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr);
465507b4b54SLuigi Rizzo 		if (i & IP_FW_PORT_DENY_FLAG) { /* XXX new interface-denied */
466507b4b54SLuigi Rizzo 		    if (m)
467507b4b54SLuigi Rizzo 			m_freem(m);
468b715f178SLuigi Rizzo 		    return ;
469507b4b54SLuigi Rizzo 		}
470507b4b54SLuigi Rizzo 		if (m == NULL) {	/* Packet discarded by firewall */
471507b4b54SLuigi Rizzo 		    static int __debug=10;
472507b4b54SLuigi Rizzo 		    if (__debug >0) {
473507b4b54SLuigi Rizzo 			printf("firewall returns NULL, please update!\n");
474507b4b54SLuigi Rizzo 			__debug-- ;
475507b4b54SLuigi Rizzo 		    }
476507b4b54SLuigi Rizzo 		    return;
477507b4b54SLuigi Rizzo 		}
478b715f178SLuigi Rizzo 		if (i == 0 && ip_fw_fwd_addr == NULL)	/* common case */
479b715f178SLuigi Rizzo 			goto pass;
480b715f178SLuigi Rizzo #ifdef DUMMYNET
4818948e4baSArchie Cobbs                 if ((i & IP_FW_PORT_DYNT_FLAG) != 0) {
4828948e4baSArchie Cobbs                         /* Send packet to the appropriate pipe */
4836a800098SYoshinobu Inoue                         dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule,
4846a800098SYoshinobu Inoue 				    0);
485e4676ba6SJulian Elischer 			return;
48693e0e116SJulian Elischer 		}
487b715f178SLuigi Rizzo #endif
488b715f178SLuigi Rizzo #ifdef IPDIVERT
4898948e4baSArchie Cobbs 		if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
4908948e4baSArchie Cobbs 			/* Divert or tee packet */
4918948e4baSArchie Cobbs 			divert_info = i;
492b715f178SLuigi Rizzo 			goto ours;
493b715f178SLuigi Rizzo 		}
494b715f178SLuigi Rizzo #endif
495b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD
496b715f178SLuigi Rizzo 		if (i == 0 && ip_fw_fwd_addr != NULL)
497b715f178SLuigi Rizzo 			goto pass;
498b715f178SLuigi Rizzo #endif
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 */
514ed1ff184SJulian Elischer 	if (hlen > sizeof (struct ip) && ip_dooptions(m)) {
515ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD
516ed1ff184SJulian Elischer 		ip_fw_fwd_addr = NULL;
517ed1ff184SJulian Elischer #endif
518c67b1d17SGarrett Wollman 		return;
519ed1ff184SJulian Elischer 	}
520df8bae1dSRodney W. Grimes 
521f0068c4aSGarrett Wollman         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
522f0068c4aSGarrett Wollman          * matter if it is destined to another node, or whether it is
523f0068c4aSGarrett Wollman          * a multicast one, RSVP wants it! and prevents it from being forwarded
524f0068c4aSGarrett Wollman          * anywhere else. Also checks if the rsvp daemon is running before
525f0068c4aSGarrett Wollman 	 * grabbing the packet.
526f0068c4aSGarrett Wollman          */
5271c5de19aSGarrett Wollman 	if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
528f0068c4aSGarrett Wollman 		goto ours;
529f0068c4aSGarrett Wollman 
530df8bae1dSRodney W. Grimes 	/*
531df8bae1dSRodney W. Grimes 	 * Check our list of addresses, to see if the packet is for us.
532cc766e04SGarrett Wollman 	 * If we don't have any addresses, assume any unicast packet
533cc766e04SGarrett Wollman 	 * we receive might be for us (and let the upper layers deal
534cc766e04SGarrett Wollman 	 * with it).
535df8bae1dSRodney W. Grimes 	 */
536cc766e04SGarrett Wollman 	if (TAILQ_EMPTY(&in_ifaddrhead) &&
537cc766e04SGarrett Wollman 	    (m->m_flags & (M_MCAST|M_BCAST)) == 0)
538cc766e04SGarrett Wollman 		goto ours;
539cc766e04SGarrett Wollman 
5407538a9a0SJonathan Lemon 	/*
5417538a9a0SJonathan Lemon 	 * Cache the destination address of the packet; this may be
5427538a9a0SJonathan Lemon 	 * changed by use of 'ipfw fwd'.
5437538a9a0SJonathan Lemon 	 */
5447538a9a0SJonathan Lemon 	pkt_dst = ip_fw_fwd_addr == NULL ?
5457538a9a0SJonathan Lemon 	    ip->ip_dst : ip_fw_fwd_addr->sin_addr;
5467538a9a0SJonathan Lemon 
547823db0e9SDon Lewis 	/*
548823db0e9SDon Lewis 	 * Enable a consistency check between the destination address
549823db0e9SDon Lewis 	 * and the arrival interface for a unicast packet (the RFC 1122
550823db0e9SDon Lewis 	 * strong ES model) if IP forwarding is disabled and the packet
551e15ae1b2SDon Lewis 	 * is not locally generated and the packet is not subject to
552e15ae1b2SDon Lewis 	 * 'ipfw fwd'.
5533f67c834SDon Lewis 	 *
5543f67c834SDon Lewis          * XXX - Checking also should be disabled if the destination
5553f67c834SDon Lewis 	 * address is ipnat'ed to a different interface.
5563f67c834SDon Lewis 	 *
557a8f12100SDon Lewis 	 * XXX - Checking is incompatible with IP aliases added
5583f67c834SDon Lewis 	 * to the loopback interface instead of the interface where
5593f67c834SDon Lewis 	 * the packets are received.
560823db0e9SDon Lewis 	 */
561823db0e9SDon Lewis 	checkif = ip_checkinterface && (ipforwarding == 0) &&
5629494d596SBrooks Davis 	    m->m_pkthdr.rcvif != NULL &&
563e15ae1b2SDon Lewis 	    ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
564e15ae1b2SDon Lewis 	    (ip_fw_fwd_addr == NULL);
565823db0e9SDon Lewis 
566ca925d9cSJonathan Lemon 	/*
567ca925d9cSJonathan Lemon 	 * Check for exact addresses in the hash bucket.
568ca925d9cSJonathan Lemon 	 */
569ca925d9cSJonathan Lemon 	LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
570f9e354dfSJulian Elischer 		/*
571823db0e9SDon Lewis 		 * If the address matches, verify that the packet
572823db0e9SDon Lewis 		 * arrived via the correct interface if checking is
573823db0e9SDon Lewis 		 * enabled.
574f9e354dfSJulian Elischer 		 */
575823db0e9SDon Lewis 		if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr &&
576823db0e9SDon Lewis 		    (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif))
577ed1ff184SJulian Elischer 			goto ours;
578ca925d9cSJonathan Lemon 	}
579823db0e9SDon Lewis 	/*
580ca925d9cSJonathan Lemon 	 * Check for broadcast addresses.
581ca925d9cSJonathan Lemon 	 *
582ca925d9cSJonathan Lemon 	 * Only accept broadcast packets that arrive via the matching
583ca925d9cSJonathan Lemon 	 * interface.  Reception of forwarded directed broadcasts would
584ca925d9cSJonathan Lemon 	 * be handled via ip_forward() and ether_output() with the loopback
585ca925d9cSJonathan Lemon 	 * into the stack for SIMPLEX interfaces handled by ether_output().
586823db0e9SDon Lewis 	 */
587ca925d9cSJonathan Lemon 	if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
588ca925d9cSJonathan Lemon 	        TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
589ca925d9cSJonathan Lemon 			if (ifa->ifa_addr->sa_family != AF_INET)
590ca925d9cSJonathan Lemon 				continue;
591ca925d9cSJonathan Lemon 			ia = ifatoia(ifa);
592df8bae1dSRodney W. Grimes 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
5937538a9a0SJonathan Lemon 			    pkt_dst.s_addr)
594df8bae1dSRodney W. Grimes 				goto ours;
5957538a9a0SJonathan Lemon 			if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr)
596df8bae1dSRodney W. Grimes 				goto ours;
597ca925d9cSJonathan Lemon #ifdef BOOTP_COMPAT
598ca925d9cSJonathan Lemon 			if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
599ca925d9cSJonathan Lemon 				goto ours;
600ca925d9cSJonathan Lemon #endif
601df8bae1dSRodney W. Grimes 		}
602df8bae1dSRodney W. Grimes 	}
603df8bae1dSRodney W. Grimes 	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
604df8bae1dSRodney W. Grimes 		struct in_multi *inm;
605df8bae1dSRodney W. Grimes 		if (ip_mrouter) {
606df8bae1dSRodney W. Grimes 			/*
607df8bae1dSRodney W. Grimes 			 * If we are acting as a multicast router, all
608df8bae1dSRodney W. Grimes 			 * incoming multicast packets are passed to the
609df8bae1dSRodney W. Grimes 			 * kernel-level multicast forwarding function.
610df8bae1dSRodney W. Grimes 			 * The packet is returned (relatively) intact; if
611df8bae1dSRodney W. Grimes 			 * ip_mforward() returns a non-zero value, the packet
612df8bae1dSRodney W. Grimes 			 * must be discarded, else it may be accepted below.
613df8bae1dSRodney W. Grimes 			 */
614f0068c4aSGarrett Wollman 			if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) {
615df8bae1dSRodney W. Grimes 				ipstat.ips_cantforward++;
616df8bae1dSRodney W. Grimes 				m_freem(m);
617c67b1d17SGarrett Wollman 				return;
618df8bae1dSRodney W. Grimes 			}
619df8bae1dSRodney W. Grimes 
620df8bae1dSRodney W. Grimes 			/*
621df8bae1dSRodney W. Grimes 			 * The process-level routing demon needs to receive
622df8bae1dSRodney W. Grimes 			 * all multicast IGMP packets, whether or not this
623df8bae1dSRodney W. Grimes 			 * host belongs to their destination groups.
624df8bae1dSRodney W. Grimes 			 */
625df8bae1dSRodney W. Grimes 			if (ip->ip_p == IPPROTO_IGMP)
626df8bae1dSRodney W. Grimes 				goto ours;
627df8bae1dSRodney W. Grimes 			ipstat.ips_forward++;
628df8bae1dSRodney W. Grimes 		}
629df8bae1dSRodney W. Grimes 		/*
630df8bae1dSRodney W. Grimes 		 * See if we belong to the destination multicast group on the
631df8bae1dSRodney W. Grimes 		 * arrival interface.
632df8bae1dSRodney W. Grimes 		 */
633df8bae1dSRodney W. Grimes 		IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
634df8bae1dSRodney W. Grimes 		if (inm == NULL) {
63582c39223SGarrett Wollman 			ipstat.ips_notmember++;
636df8bae1dSRodney W. Grimes 			m_freem(m);
637c67b1d17SGarrett Wollman 			return;
638df8bae1dSRodney W. Grimes 		}
639df8bae1dSRodney W. Grimes 		goto ours;
640df8bae1dSRodney W. Grimes 	}
641df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
642df8bae1dSRodney W. Grimes 		goto ours;
643df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == INADDR_ANY)
644df8bae1dSRodney W. Grimes 		goto ours;
645df8bae1dSRodney W. Grimes 
6466a800098SYoshinobu Inoue 	/*
6476a800098SYoshinobu Inoue 	 * FAITH(Firewall Aided Internet Translator)
6486a800098SYoshinobu Inoue 	 */
6496a800098SYoshinobu Inoue 	if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
6506a800098SYoshinobu Inoue 		if (ip_keepfaith) {
6516a800098SYoshinobu Inoue 			if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP)
6526a800098SYoshinobu Inoue 				goto ours;
6536a800098SYoshinobu Inoue 		}
6546a800098SYoshinobu Inoue 		m_freem(m);
6556a800098SYoshinobu Inoue 		return;
6566a800098SYoshinobu Inoue 	}
6579494d596SBrooks Davis 
658df8bae1dSRodney W. Grimes 	/*
659df8bae1dSRodney W. Grimes 	 * Not for us; forward if possible and desirable.
660df8bae1dSRodney W. Grimes 	 */
661df8bae1dSRodney W. Grimes 	if (ipforwarding == 0) {
662df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
663df8bae1dSRodney W. Grimes 		m_freem(m);
664df8bae1dSRodney W. Grimes 	} else
665df8bae1dSRodney W. Grimes 		ip_forward(m, 0);
666ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD
667ed1ff184SJulian Elischer 	ip_fw_fwd_addr = NULL;
668ed1ff184SJulian Elischer #endif
669c67b1d17SGarrett Wollman 	return;
670df8bae1dSRodney W. Grimes 
671df8bae1dSRodney W. Grimes ours:
6725da9f8faSJosef Karthauser 	/* Count the packet in the ip address stats */
6735da9f8faSJosef Karthauser 	if (ia != NULL) {
6745da9f8faSJosef Karthauser 		ia->ia_ifa.if_ipackets++;
6755da9f8faSJosef Karthauser 		ia->ia_ifa.if_ibytes += m->m_pkthdr.len;
6765da9f8faSJosef Karthauser 	}
677100ba1a6SJordan K. Hubbard 
67863f8d699SJordan K. Hubbard 	/*
679df8bae1dSRodney W. Grimes 	 * If offset or IP_MF are set, must reassemble.
680df8bae1dSRodney W. Grimes 	 * Otherwise, nothing need be done.
681df8bae1dSRodney W. Grimes 	 * (We could look in the reassembly queue to see
682df8bae1dSRodney W. Grimes 	 * if the packet was previously fragmented,
683df8bae1dSRodney W. Grimes 	 * but it's not worth the time; just let them time out.)
684df8bae1dSRodney W. Grimes 	 */
685b6ea1aa5SRuslan Ermilov 	if (ip->ip_off & (IP_MF | IP_OFFMASK)) {
6866a800098SYoshinobu Inoue 
687194a213eSAndrey A. Chernov 		sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
688df8bae1dSRodney W. Grimes 		/*
689df8bae1dSRodney W. Grimes 		 * Look for queue of fragments
690df8bae1dSRodney W. Grimes 		 * of this datagram.
691df8bae1dSRodney W. Grimes 		 */
692462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(fp, &ipq[sum], ipq_list)
693df8bae1dSRodney W. Grimes 			if (ip->ip_id == fp->ipq_id &&
694df8bae1dSRodney W. Grimes 			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
695df8bae1dSRodney W. Grimes 			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
696df8bae1dSRodney W. Grimes 			    ip->ip_p == fp->ipq_p)
697df8bae1dSRodney W. Grimes 				goto found;
698df8bae1dSRodney W. Grimes 
699194a213eSAndrey A. Chernov 		fp = 0;
700194a213eSAndrey A. Chernov 
701194a213eSAndrey A. Chernov 		/* check if there's a place for the new queue */
702194a213eSAndrey A. Chernov 		if (nipq > maxnipq) {
703194a213eSAndrey A. Chernov 		    /*
704194a213eSAndrey A. Chernov 		     * drop something from the tail of the current queue
705194a213eSAndrey A. Chernov 		     * before proceeding further
706194a213eSAndrey A. Chernov 		     */
707462b86feSPoul-Henning Kamp 		    struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead);
708462b86feSPoul-Henning Kamp 		    if (q == NULL) {   /* gak */
709194a213eSAndrey A. Chernov 			for (i = 0; i < IPREASS_NHASH; i++) {
710462b86feSPoul-Henning Kamp 			    struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead);
711462b86feSPoul-Henning Kamp 			    if (r) {
712462b86feSPoul-Henning Kamp 				ip_freef(&ipq[i], r);
713194a213eSAndrey A. Chernov 				break;
714194a213eSAndrey A. Chernov 			    }
715194a213eSAndrey A. Chernov 			}
716194a213eSAndrey A. Chernov 		    } else
717462b86feSPoul-Henning Kamp 			ip_freef(&ipq[sum], q);
718194a213eSAndrey A. Chernov 		}
719194a213eSAndrey A. Chernov found:
720df8bae1dSRodney W. Grimes 		/*
721df8bae1dSRodney W. Grimes 		 * Adjust ip_len to not reflect header,
722df8bae1dSRodney W. Grimes 		 * convert offset of this to bytes.
723df8bae1dSRodney W. Grimes 		 */
724df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
725b6ea1aa5SRuslan Ermilov 		if (ip->ip_off & IP_MF) {
7266effc713SDoug Rabson 		        /*
7276effc713SDoug Rabson 		         * Make sure that fragments have a data length
7286effc713SDoug Rabson 			 * that's a non-zero multiple of 8 bytes.
7296effc713SDoug Rabson 		         */
7306effc713SDoug Rabson 			if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
7316effc713SDoug Rabson 				ipstat.ips_toosmall++; /* XXX */
7326effc713SDoug Rabson 				goto bad;
7336effc713SDoug Rabson 			}
7346effc713SDoug Rabson 			m->m_flags |= M_FRAG;
7356effc713SDoug Rabson 		}
736df8bae1dSRodney W. Grimes 		ip->ip_off <<= 3;
737df8bae1dSRodney W. Grimes 
738df8bae1dSRodney W. Grimes 		/*
739b6ea1aa5SRuslan Ermilov 		 * Attempt reassembly; if it succeeds, proceed.
740df8bae1dSRodney W. Grimes 		 */
741df8bae1dSRodney W. Grimes 		ipstat.ips_fragments++;
742487bdb38SRuslan Ermilov 		m->m_pkthdr.header = ip;
7438948e4baSArchie Cobbs #ifdef IPDIVERT
7446a800098SYoshinobu Inoue 		m = ip_reass(m,
745462b86feSPoul-Henning Kamp 		    &ipq[sum], fp, &divert_info, &divert_cookie);
7468948e4baSArchie Cobbs #else
747462b86feSPoul-Henning Kamp 		m = ip_reass(m, &ipq[sum], fp);
7488948e4baSArchie Cobbs #endif
7496a800098SYoshinobu Inoue 		if (m == 0) {
750f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD
751f9e354dfSJulian Elischer 			ip_fw_fwd_addr = NULL;
752f9e354dfSJulian Elischer #endif
753c67b1d17SGarrett Wollman 			return;
754f9e354dfSJulian Elischer 		}
755df8bae1dSRodney W. Grimes 		ipstat.ips_reassembled++;
7566a800098SYoshinobu Inoue 		ip = mtod(m, struct ip *);
7577e2df452SRuslan Ermilov 		/* Get the header length of the reassembled packet */
7587e2df452SRuslan Ermilov 		hlen = IP_VHL_HL(ip->ip_vhl) << 2;
759af782f1cSBrian Somers #ifdef IPDIVERT
7608948e4baSArchie Cobbs 		/* Restore original checksum before diverting packet */
7618948e4baSArchie Cobbs 		if (divert_info != 0) {
762af782f1cSBrian Somers 			ip->ip_len += hlen;
763af782f1cSBrian Somers 			HTONS(ip->ip_len);
764af782f1cSBrian Somers 			HTONS(ip->ip_off);
765af782f1cSBrian Somers 			ip->ip_sum = 0;
76660123168SRuslan Ermilov 			if (hlen == sizeof(struct ip))
767af782f1cSBrian Somers 				ip->ip_sum = in_cksum_hdr(ip);
76860123168SRuslan Ermilov 			else
76960123168SRuslan Ermilov 				ip->ip_sum = in_cksum(m, hlen);
770af782f1cSBrian Somers 			NTOHS(ip->ip_off);
771af782f1cSBrian Somers 			NTOHS(ip->ip_len);
772af782f1cSBrian Somers 			ip->ip_len -= hlen;
773af782f1cSBrian Somers 		}
774af782f1cSBrian Somers #endif
775df8bae1dSRodney W. Grimes 	} else
776df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
777df8bae1dSRodney W. Grimes 
77893e0e116SJulian Elischer #ifdef IPDIVERT
77993e0e116SJulian Elischer 	/*
7808948e4baSArchie Cobbs 	 * Divert or tee packet to the divert protocol if required.
7818948e4baSArchie Cobbs 	 *
7828948e4baSArchie Cobbs 	 * If divert_info is zero then cookie should be too, so we shouldn't
7838948e4baSArchie Cobbs 	 * need to clear them here.  Assume divert_packet() does so also.
78493e0e116SJulian Elischer 	 */
7858948e4baSArchie Cobbs 	if (divert_info != 0) {
7868948e4baSArchie Cobbs 		struct mbuf *clone = NULL;
7878948e4baSArchie Cobbs 
7888948e4baSArchie Cobbs 		/* Clone packet if we're doing a 'tee' */
7898948e4baSArchie Cobbs 		if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
7908948e4baSArchie Cobbs 			clone = m_dup(m, M_DONTWAIT);
7918948e4baSArchie Cobbs 
7928948e4baSArchie Cobbs 		/* Restore packet header fields to original values */
7938948e4baSArchie Cobbs 		ip->ip_len += hlen;
7948948e4baSArchie Cobbs 		HTONS(ip->ip_len);
7958948e4baSArchie Cobbs 		HTONS(ip->ip_off);
7968948e4baSArchie Cobbs 
7978948e4baSArchie Cobbs 		/* Deliver packet to divert input routine */
7988948e4baSArchie Cobbs 		ip_divert_cookie = divert_cookie;
7998948e4baSArchie Cobbs 		divert_packet(m, 1, divert_info & 0xffff);
800e4676ba6SJulian Elischer 		ipstat.ips_delivered++;
8018948e4baSArchie Cobbs 
8028948e4baSArchie Cobbs 		/* If 'tee', continue with original packet */
8038948e4baSArchie Cobbs 		if (clone == NULL)
80493e0e116SJulian Elischer 			return;
8058948e4baSArchie Cobbs 		m = clone;
8068948e4baSArchie Cobbs 		ip = mtod(m, struct ip *);
80793e0e116SJulian Elischer 	}
80893e0e116SJulian Elischer #endif
80993e0e116SJulian Elischer 
81033841545SHajimu UMEMOTO #ifdef IPSEC
81133841545SHajimu UMEMOTO 	/*
81233841545SHajimu UMEMOTO 	 * enforce IPsec policy checking if we are seeing last header.
81333841545SHajimu UMEMOTO 	 * note that we do not visit this with protocols with pcb layer
81433841545SHajimu UMEMOTO 	 * code - like udp/tcp/raw ip.
81533841545SHajimu UMEMOTO 	 */
81633841545SHajimu UMEMOTO 	if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 &&
81733841545SHajimu UMEMOTO 	    ipsec4_in_reject(m, NULL)) {
81833841545SHajimu UMEMOTO 		ipsecstat.in_polvio++;
81933841545SHajimu UMEMOTO 		goto bad;
82033841545SHajimu UMEMOTO 	}
82133841545SHajimu UMEMOTO #endif
82233841545SHajimu UMEMOTO 
823df8bae1dSRodney W. Grimes 	/*
824df8bae1dSRodney W. Grimes 	 * Switch out to protocol's input routine.
825df8bae1dSRodney W. Grimes 	 */
826df8bae1dSRodney W. Grimes 	ipstat.ips_delivered++;
8276a800098SYoshinobu Inoue     {
828f0ffb944SJulian Elischer 	int off = hlen;
8296a800098SYoshinobu Inoue 
830f0ffb944SJulian Elischer 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off);
831f9e354dfSJulian Elischer #ifdef	IPFIREWALL_FORWARD
832f9e354dfSJulian Elischer 	ip_fw_fwd_addr = NULL;	/* tcp needed it */
833f9e354dfSJulian Elischer #endif
834c67b1d17SGarrett Wollman 	return;
8356a800098SYoshinobu Inoue     }
836df8bae1dSRodney W. Grimes bad:
837f9e354dfSJulian Elischer #ifdef	IPFIREWALL_FORWARD
838f9e354dfSJulian Elischer 	ip_fw_fwd_addr = NULL;
839f9e354dfSJulian Elischer #endif
840df8bae1dSRodney W. Grimes 	m_freem(m);
841c67b1d17SGarrett Wollman }
842c67b1d17SGarrett Wollman 
843c67b1d17SGarrett Wollman /*
844c67b1d17SGarrett Wollman  * IP software interrupt routine - to go away sometime soon
845c67b1d17SGarrett Wollman  */
846c67b1d17SGarrett Wollman static void
847c67b1d17SGarrett Wollman ipintr(void)
848c67b1d17SGarrett Wollman {
849c67b1d17SGarrett Wollman 	struct mbuf *m;
850c67b1d17SGarrett Wollman 
851c67b1d17SGarrett Wollman 	while (1) {
852c67b1d17SGarrett Wollman 		IF_DEQUEUE(&ipintrq, m);
853c67b1d17SGarrett Wollman 		if (m == 0)
854c67b1d17SGarrett Wollman 			return;
855c67b1d17SGarrett Wollman 		ip_input(m);
856c67b1d17SGarrett Wollman 	}
857df8bae1dSRodney W. Grimes }
858df8bae1dSRodney W. Grimes 
859df8bae1dSRodney W. Grimes /*
8608948e4baSArchie Cobbs  * Take incoming datagram fragment and try to reassemble it into
8618948e4baSArchie Cobbs  * whole datagram.  If a chain for reassembly of this datagram already
8628948e4baSArchie Cobbs  * exists, then it is given as fp; otherwise have to make a chain.
8638948e4baSArchie Cobbs  *
8648948e4baSArchie Cobbs  * When IPDIVERT enabled, keep additional state with each packet that
8658948e4baSArchie Cobbs  * tells us if we need to divert or tee the packet we're building.
866df8bae1dSRodney W. Grimes  */
8678948e4baSArchie Cobbs 
8686a800098SYoshinobu Inoue static struct mbuf *
8698948e4baSArchie Cobbs #ifdef IPDIVERT
870462b86feSPoul-Henning Kamp ip_reass(m, head, fp, divinfo, divcookie)
8718948e4baSArchie Cobbs #else
872462b86feSPoul-Henning Kamp ip_reass(m, head, fp)
8738948e4baSArchie Cobbs #endif
874462b86feSPoul-Henning Kamp 	struct mbuf *m;
875462b86feSPoul-Henning Kamp 	struct ipqhead *head;
876462b86feSPoul-Henning Kamp 	struct ipq *fp;
8778948e4baSArchie Cobbs #ifdef IPDIVERT
8788948e4baSArchie Cobbs 	u_int32_t *divinfo;
8798948e4baSArchie Cobbs 	u_int16_t *divcookie;
8808948e4baSArchie Cobbs #endif
881df8bae1dSRodney W. Grimes {
8826effc713SDoug Rabson 	struct ip *ip = mtod(m, struct ip *);
883b6ea1aa5SRuslan Ermilov 	register struct mbuf *p, *q, *nq;
884df8bae1dSRodney W. Grimes 	struct mbuf *t;
8856effc713SDoug Rabson 	int hlen = IP_VHL_HL(ip->ip_vhl) << 2;
886df8bae1dSRodney W. Grimes 	int i, next;
887df8bae1dSRodney W. Grimes 
888df8bae1dSRodney W. Grimes 	/*
889df8bae1dSRodney W. Grimes 	 * Presence of header sizes in mbufs
890df8bae1dSRodney W. Grimes 	 * would confuse code below.
891df8bae1dSRodney W. Grimes 	 */
892df8bae1dSRodney W. Grimes 	m->m_data += hlen;
893df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
894df8bae1dSRodney W. Grimes 
895df8bae1dSRodney W. Grimes 	/*
896df8bae1dSRodney W. Grimes 	 * If first fragment to arrive, create a reassembly queue.
897df8bae1dSRodney W. Grimes 	 */
898df8bae1dSRodney W. Grimes 	if (fp == 0) {
899690a6055SJesper Skriver 		/*
900690a6055SJesper Skriver 		 * Enforce upper bound on number of fragmented packets
901690a6055SJesper Skriver 		 * for which we attempt reassembly;
902690a6055SJesper Skriver 		 * If maxfrag is 0, never accept fragments.
903690a6055SJesper Skriver 		 * If maxfrag is -1, accept all fragments without limitation.
904690a6055SJesper Skriver 		 */
905690a6055SJesper Skriver 		if ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets))
906690a6055SJesper Skriver 			goto dropfrag;
907690a6055SJesper Skriver 		ip_nfragpackets++;
908df8bae1dSRodney W. Grimes 		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
909df8bae1dSRodney W. Grimes 			goto dropfrag;
910df8bae1dSRodney W. Grimes 		fp = mtod(t, struct ipq *);
911462b86feSPoul-Henning Kamp 		TAILQ_INSERT_HEAD(head, fp, ipq_list);
912194a213eSAndrey A. Chernov 		nipq++;
913df8bae1dSRodney W. Grimes 		fp->ipq_ttl = IPFRAGTTL;
914df8bae1dSRodney W. Grimes 		fp->ipq_p = ip->ip_p;
915df8bae1dSRodney W. Grimes 		fp->ipq_id = ip->ip_id;
9166effc713SDoug Rabson 		fp->ipq_src = ip->ip_src;
9176effc713SDoug Rabson 		fp->ipq_dst = ip->ip_dst;
918af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
919af38c68cSLuigi Rizzo 		m->m_nextpkt = NULL;
92093e0e116SJulian Elischer #ifdef IPDIVERT
9218948e4baSArchie Cobbs 		fp->ipq_div_info = 0;
922bb60f459SJulian Elischer 		fp->ipq_div_cookie = 0;
92393e0e116SJulian Elischer #endif
924af38c68cSLuigi Rizzo 		goto inserted;
925df8bae1dSRodney W. Grimes 	}
926df8bae1dSRodney W. Grimes 
9276effc713SDoug Rabson #define GETIP(m)	((struct ip*)((m)->m_pkthdr.header))
9286effc713SDoug Rabson 
929df8bae1dSRodney W. Grimes 	/*
930df8bae1dSRodney W. Grimes 	 * Find a segment which begins after this one does.
931df8bae1dSRodney W. Grimes 	 */
9326effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
9336effc713SDoug Rabson 		if (GETIP(q)->ip_off > ip->ip_off)
934df8bae1dSRodney W. Grimes 			break;
935df8bae1dSRodney W. Grimes 
936df8bae1dSRodney W. Grimes 	/*
937df8bae1dSRodney W. Grimes 	 * If there is a preceding segment, it may provide some of
938df8bae1dSRodney W. Grimes 	 * our data already.  If so, drop the data from the incoming
939af38c68cSLuigi Rizzo 	 * segment.  If it provides all of our data, drop us, otherwise
940af38c68cSLuigi Rizzo 	 * stick new segment in the proper place.
941db4f9cc7SJonathan Lemon 	 *
942db4f9cc7SJonathan Lemon 	 * If some of the data is dropped from the the preceding
943db4f9cc7SJonathan Lemon 	 * segment, then it's checksum is invalidated.
944df8bae1dSRodney W. Grimes 	 */
9456effc713SDoug Rabson 	if (p) {
9466effc713SDoug Rabson 		i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
947df8bae1dSRodney W. Grimes 		if (i > 0) {
948df8bae1dSRodney W. Grimes 			if (i >= ip->ip_len)
949df8bae1dSRodney W. Grimes 				goto dropfrag;
9506a800098SYoshinobu Inoue 			m_adj(m, i);
951db4f9cc7SJonathan Lemon 			m->m_pkthdr.csum_flags = 0;
952df8bae1dSRodney W. Grimes 			ip->ip_off += i;
953df8bae1dSRodney W. Grimes 			ip->ip_len -= i;
954df8bae1dSRodney W. Grimes 		}
955af38c68cSLuigi Rizzo 		m->m_nextpkt = p->m_nextpkt;
956af38c68cSLuigi Rizzo 		p->m_nextpkt = m;
957af38c68cSLuigi Rizzo 	} else {
958af38c68cSLuigi Rizzo 		m->m_nextpkt = fp->ipq_frags;
959af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
960df8bae1dSRodney W. Grimes 	}
961df8bae1dSRodney W. Grimes 
962df8bae1dSRodney W. Grimes 	/*
963df8bae1dSRodney W. Grimes 	 * While we overlap succeeding segments trim them or,
964df8bae1dSRodney W. Grimes 	 * if they are completely covered, dequeue them.
965df8bae1dSRodney W. Grimes 	 */
9666effc713SDoug Rabson 	for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
967af38c68cSLuigi Rizzo 	     q = nq) {
9686effc713SDoug Rabson 		i = (ip->ip_off + ip->ip_len) -
9696effc713SDoug Rabson 		    GETIP(q)->ip_off;
9706effc713SDoug Rabson 		if (i < GETIP(q)->ip_len) {
9716effc713SDoug Rabson 			GETIP(q)->ip_len -= i;
9726effc713SDoug Rabson 			GETIP(q)->ip_off += i;
9736effc713SDoug Rabson 			m_adj(q, i);
974db4f9cc7SJonathan Lemon 			q->m_pkthdr.csum_flags = 0;
975df8bae1dSRodney W. Grimes 			break;
976df8bae1dSRodney W. Grimes 		}
9776effc713SDoug Rabson 		nq = q->m_nextpkt;
978af38c68cSLuigi Rizzo 		m->m_nextpkt = nq;
9796effc713SDoug Rabson 		m_freem(q);
980df8bae1dSRodney W. Grimes 	}
981df8bae1dSRodney W. Grimes 
982af38c68cSLuigi Rizzo inserted:
98393e0e116SJulian Elischer 
98493e0e116SJulian Elischer #ifdef IPDIVERT
98593e0e116SJulian Elischer 	/*
9868948e4baSArchie Cobbs 	 * Transfer firewall instructions to the fragment structure.
9878948e4baSArchie Cobbs 	 * Any fragment diverting causes the whole packet to divert.
98893e0e116SJulian Elischer 	 */
9898948e4baSArchie Cobbs 	fp->ipq_div_info = *divinfo;
9908948e4baSArchie Cobbs 	fp->ipq_div_cookie = *divcookie;
9918948e4baSArchie Cobbs 	*divinfo = 0;
9928948e4baSArchie Cobbs 	*divcookie = 0;
99393e0e116SJulian Elischer #endif
99493e0e116SJulian Elischer 
995df8bae1dSRodney W. Grimes 	/*
996af38c68cSLuigi Rizzo 	 * Check for complete reassembly.
997df8bae1dSRodney W. Grimes 	 */
9986effc713SDoug Rabson 	next = 0;
9996effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
10006effc713SDoug Rabson 		if (GETIP(q)->ip_off != next)
10016effc713SDoug Rabson 			return (0);
10026effc713SDoug Rabson 		next += GETIP(q)->ip_len;
10036effc713SDoug Rabson 	}
10046effc713SDoug Rabson 	/* Make sure the last packet didn't have the IP_MF flag */
10056effc713SDoug Rabson 	if (p->m_flags & M_FRAG)
1006df8bae1dSRodney W. Grimes 		return (0);
1007df8bae1dSRodney W. Grimes 
1008df8bae1dSRodney W. Grimes 	/*
1009430d30d8SBill Fenner 	 * Reassembly is complete.  Make sure the packet is a sane size.
1010430d30d8SBill Fenner 	 */
10116effc713SDoug Rabson 	q = fp->ipq_frags;
10126effc713SDoug Rabson 	ip = GETIP(q);
10136effc713SDoug Rabson 	if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) {
1014430d30d8SBill Fenner 		ipstat.ips_toolong++;
1015462b86feSPoul-Henning Kamp 		ip_freef(head, fp);
1016430d30d8SBill Fenner 		return (0);
1017430d30d8SBill Fenner 	}
1018430d30d8SBill Fenner 
1019430d30d8SBill Fenner 	/*
1020430d30d8SBill Fenner 	 * Concatenate fragments.
1021df8bae1dSRodney W. Grimes 	 */
10226effc713SDoug Rabson 	m = q;
1023df8bae1dSRodney W. Grimes 	t = m->m_next;
1024df8bae1dSRodney W. Grimes 	m->m_next = 0;
1025df8bae1dSRodney W. Grimes 	m_cat(m, t);
10266effc713SDoug Rabson 	nq = q->m_nextpkt;
1027945aa40dSDoug Rabson 	q->m_nextpkt = 0;
10286effc713SDoug Rabson 	for (q = nq; q != NULL; q = nq) {
10296effc713SDoug Rabson 		nq = q->m_nextpkt;
1030945aa40dSDoug Rabson 		q->m_nextpkt = NULL;
1031db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags;
1032db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_data += q->m_pkthdr.csum_data;
1033a8db1d93SJonathan Lemon 		m_cat(m, q);
1034df8bae1dSRodney W. Grimes 	}
1035df8bae1dSRodney W. Grimes 
103693e0e116SJulian Elischer #ifdef IPDIVERT
103793e0e116SJulian Elischer 	/*
10388948e4baSArchie Cobbs 	 * Extract firewall instructions from the fragment structure.
103993e0e116SJulian Elischer 	 */
10408948e4baSArchie Cobbs 	*divinfo = fp->ipq_div_info;
10418948e4baSArchie Cobbs 	*divcookie = fp->ipq_div_cookie;
104293e0e116SJulian Elischer #endif
104393e0e116SJulian Elischer 
1044df8bae1dSRodney W. Grimes 	/*
1045df8bae1dSRodney W. Grimes 	 * Create header for new ip packet by
1046df8bae1dSRodney W. Grimes 	 * modifying header of first packet;
1047df8bae1dSRodney W. Grimes 	 * dequeue and discard fragment reassembly header.
1048df8bae1dSRodney W. Grimes 	 * Make header visible.
1049df8bae1dSRodney W. Grimes 	 */
1050df8bae1dSRodney W. Grimes 	ip->ip_len = next;
10516effc713SDoug Rabson 	ip->ip_src = fp->ipq_src;
10526effc713SDoug Rabson 	ip->ip_dst = fp->ipq_dst;
1053462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(head, fp, ipq_list);
1054194a213eSAndrey A. Chernov 	nipq--;
1055df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1056690a6055SJesper Skriver 	ip_nfragpackets--;
10576effc713SDoug Rabson 	m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2);
10586effc713SDoug Rabson 	m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2);
1059df8bae1dSRodney W. Grimes 	/* some debugging cruft by sklower, below, will go away soon */
1060df8bae1dSRodney W. Grimes 	if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
1061df8bae1dSRodney W. Grimes 		register int plen = 0;
10626a800098SYoshinobu Inoue 		for (t = m; t; t = t->m_next)
10636a800098SYoshinobu Inoue 			plen += t->m_len;
10646a800098SYoshinobu Inoue 		m->m_pkthdr.len = plen;
1065df8bae1dSRodney W. Grimes 	}
10666a800098SYoshinobu Inoue 	return (m);
1067df8bae1dSRodney W. Grimes 
1068df8bae1dSRodney W. Grimes dropfrag:
1069efe39c6aSJulian Elischer #ifdef IPDIVERT
10708948e4baSArchie Cobbs 	*divinfo = 0;
10718948e4baSArchie Cobbs 	*divcookie = 0;
1072efe39c6aSJulian Elischer #endif
1073df8bae1dSRodney W. Grimes 	ipstat.ips_fragdropped++;
1074df8bae1dSRodney W. Grimes 	m_freem(m);
1075df8bae1dSRodney W. Grimes 	return (0);
10766effc713SDoug Rabson 
10776effc713SDoug Rabson #undef GETIP
1078df8bae1dSRodney W. Grimes }
1079df8bae1dSRodney W. Grimes 
1080df8bae1dSRodney W. Grimes /*
1081df8bae1dSRodney W. Grimes  * Free a fragment reassembly header and all
1082df8bae1dSRodney W. Grimes  * associated datagrams.
1083df8bae1dSRodney W. Grimes  */
10840312fbe9SPoul-Henning Kamp static void
1085462b86feSPoul-Henning Kamp ip_freef(fhp, fp)
1086462b86feSPoul-Henning Kamp 	struct ipqhead *fhp;
1087df8bae1dSRodney W. Grimes 	struct ipq *fp;
1088df8bae1dSRodney W. Grimes {
10896effc713SDoug Rabson 	register struct mbuf *q;
1090df8bae1dSRodney W. Grimes 
10916effc713SDoug Rabson 	while (fp->ipq_frags) {
10926effc713SDoug Rabson 		q = fp->ipq_frags;
10936effc713SDoug Rabson 		fp->ipq_frags = q->m_nextpkt;
10946effc713SDoug Rabson 		m_freem(q);
1095df8bae1dSRodney W. Grimes 	}
1096462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(fhp, fp, ipq_list);
1097df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1098690a6055SJesper Skriver 	ip_nfragpackets--;
1099194a213eSAndrey A. Chernov 	nipq--;
1100df8bae1dSRodney W. Grimes }
1101df8bae1dSRodney W. Grimes 
1102df8bae1dSRodney W. Grimes /*
1103df8bae1dSRodney W. Grimes  * IP timer processing;
1104df8bae1dSRodney W. Grimes  * if a timer expires on a reassembly
1105df8bae1dSRodney W. Grimes  * queue, discard it.
1106df8bae1dSRodney W. Grimes  */
1107df8bae1dSRodney W. Grimes void
1108df8bae1dSRodney W. Grimes ip_slowtimo()
1109df8bae1dSRodney W. Grimes {
1110df8bae1dSRodney W. Grimes 	register struct ipq *fp;
1111df8bae1dSRodney W. Grimes 	int s = splnet();
1112194a213eSAndrey A. Chernov 	int i;
1113df8bae1dSRodney W. Grimes 
1114194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1115462b86feSPoul-Henning Kamp 		for(fp = TAILQ_FIRST(&ipq[i]); fp;) {
1116462b86feSPoul-Henning Kamp 			struct ipq *fpp;
1117462b86feSPoul-Henning Kamp 
1118462b86feSPoul-Henning Kamp 			fpp = fp;
1119462b86feSPoul-Henning Kamp 			fp = TAILQ_NEXT(fp, ipq_list);
1120462b86feSPoul-Henning Kamp 			if(--fpp->ipq_ttl == 0) {
1121df8bae1dSRodney W. Grimes 				ipstat.ips_fragtimeout++;
1122462b86feSPoul-Henning Kamp 				ip_freef(&ipq[i], fpp);
1123df8bae1dSRodney W. Grimes 			}
1124df8bae1dSRodney W. Grimes 		}
1125194a213eSAndrey A. Chernov 	}
1126690a6055SJesper Skriver 	/*
1127690a6055SJesper Skriver 	 * If we are over the maximum number of fragments
1128690a6055SJesper Skriver 	 * (due to the limit being lowered), drain off
1129690a6055SJesper Skriver 	 * enough to get down to the new limit.
1130690a6055SJesper Skriver 	 */
1131690a6055SJesper Skriver 	for (i = 0; i < IPREASS_NHASH; i++) {
1132690a6055SJesper Skriver 		if (ip_maxfragpackets >= 0) {
1133690a6055SJesper Skriver 			while (ip_nfragpackets > ip_maxfragpackets &&
1134690a6055SJesper Skriver 				!TAILQ_EMPTY(&ipq[i])) {
1135690a6055SJesper Skriver 				ipstat.ips_fragdropped++;
1136690a6055SJesper Skriver 				ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1137690a6055SJesper Skriver 			}
1138690a6055SJesper Skriver 		}
1139690a6055SJesper Skriver 	}
11401f91d8c5SDavid Greenman 	ipflow_slowtimo();
1141df8bae1dSRodney W. Grimes 	splx(s);
1142df8bae1dSRodney W. Grimes }
1143df8bae1dSRodney W. Grimes 
1144df8bae1dSRodney W. Grimes /*
1145df8bae1dSRodney W. Grimes  * Drain off all datagram fragments.
1146df8bae1dSRodney W. Grimes  */
1147df8bae1dSRodney W. Grimes void
1148df8bae1dSRodney W. Grimes ip_drain()
1149df8bae1dSRodney W. Grimes {
1150194a213eSAndrey A. Chernov 	int     i;
1151ce29ab3aSGarrett Wollman 
1152194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1153462b86feSPoul-Henning Kamp 		while(!TAILQ_EMPTY(&ipq[i])) {
1154194a213eSAndrey A. Chernov 			ipstat.ips_fragdropped++;
1155462b86feSPoul-Henning Kamp 			ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1156194a213eSAndrey A. Chernov 		}
1157194a213eSAndrey A. Chernov 	}
1158ce29ab3aSGarrett Wollman 	in_rtqdrain();
1159df8bae1dSRodney W. Grimes }
1160df8bae1dSRodney W. Grimes 
1161df8bae1dSRodney W. Grimes /*
1162df8bae1dSRodney W. Grimes  * Do option processing on a datagram,
1163df8bae1dSRodney W. Grimes  * possibly discarding it if bad options are encountered,
1164df8bae1dSRodney W. Grimes  * or forwarding it if source-routed.
1165df8bae1dSRodney W. Grimes  * Returns 1 if packet has been forwarded/freed,
1166df8bae1dSRodney W. Grimes  * 0 if the packet should be processed further.
1167df8bae1dSRodney W. Grimes  */
11680312fbe9SPoul-Henning Kamp static int
1169df8bae1dSRodney W. Grimes ip_dooptions(m)
1170df8bae1dSRodney W. Grimes 	struct mbuf *m;
1171df8bae1dSRodney W. Grimes {
1172df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
1173df8bae1dSRodney W. Grimes 	register u_char *cp;
1174df8bae1dSRodney W. Grimes 	register struct ip_timestamp *ipt;
1175df8bae1dSRodney W. Grimes 	register struct in_ifaddr *ia;
1176df8bae1dSRodney W. Grimes 	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
1177df8bae1dSRodney W. Grimes 	struct in_addr *sin, dst;
1178df8bae1dSRodney W. Grimes 	n_time ntime;
1179df8bae1dSRodney W. Grimes 
1180df8bae1dSRodney W. Grimes 	dst = ip->ip_dst;
1181df8bae1dSRodney W. Grimes 	cp = (u_char *)(ip + 1);
118258938916SGarrett Wollman 	cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1183df8bae1dSRodney W. Grimes 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
1184df8bae1dSRodney W. Grimes 		opt = cp[IPOPT_OPTVAL];
1185df8bae1dSRodney W. Grimes 		if (opt == IPOPT_EOL)
1186df8bae1dSRodney W. Grimes 			break;
1187df8bae1dSRodney W. Grimes 		if (opt == IPOPT_NOP)
1188df8bae1dSRodney W. Grimes 			optlen = 1;
1189df8bae1dSRodney W. Grimes 		else {
1190fdcb8debSJun-ichiro itojun Hagino 			if (cnt < IPOPT_OLEN + sizeof(*cp)) {
1191fdcb8debSJun-ichiro itojun Hagino 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1192fdcb8debSJun-ichiro itojun Hagino 				goto bad;
1193fdcb8debSJun-ichiro itojun Hagino 			}
1194df8bae1dSRodney W. Grimes 			optlen = cp[IPOPT_OLEN];
1195707d00a3SJonathan Lemon 			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
1196df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1197df8bae1dSRodney W. Grimes 				goto bad;
1198df8bae1dSRodney W. Grimes 			}
1199df8bae1dSRodney W. Grimes 		}
1200df8bae1dSRodney W. Grimes 		switch (opt) {
1201df8bae1dSRodney W. Grimes 
1202df8bae1dSRodney W. Grimes 		default:
1203df8bae1dSRodney W. Grimes 			break;
1204df8bae1dSRodney W. Grimes 
1205df8bae1dSRodney W. Grimes 		/*
1206df8bae1dSRodney W. Grimes 		 * Source routing with record.
1207df8bae1dSRodney W. Grimes 		 * Find interface with current destination address.
1208df8bae1dSRodney W. Grimes 		 * If none on this machine then drop if strictly routed,
1209df8bae1dSRodney W. Grimes 		 * or do nothing if loosely routed.
1210df8bae1dSRodney W. Grimes 		 * Record interface address and bring up next address
1211df8bae1dSRodney W. Grimes 		 * component.  If strictly routed make sure next
1212df8bae1dSRodney W. Grimes 		 * address is on directly accessible net.
1213df8bae1dSRodney W. Grimes 		 */
1214df8bae1dSRodney W. Grimes 		case IPOPT_LSRR:
1215df8bae1dSRodney W. Grimes 		case IPOPT_SSRR:
121633841545SHajimu UMEMOTO 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
121733841545SHajimu UMEMOTO 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
121833841545SHajimu UMEMOTO 				goto bad;
121933841545SHajimu UMEMOTO 			}
1220df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1221df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1222df8bae1dSRodney W. Grimes 				goto bad;
1223df8bae1dSRodney W. Grimes 			}
1224df8bae1dSRodney W. Grimes 			ipaddr.sin_addr = ip->ip_dst;
1225df8bae1dSRodney W. Grimes 			ia = (struct in_ifaddr *)
1226df8bae1dSRodney W. Grimes 				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
1227df8bae1dSRodney W. Grimes 			if (ia == 0) {
1228df8bae1dSRodney W. Grimes 				if (opt == IPOPT_SSRR) {
1229df8bae1dSRodney W. Grimes 					type = ICMP_UNREACH;
1230df8bae1dSRodney W. Grimes 					code = ICMP_UNREACH_SRCFAIL;
1231df8bae1dSRodney W. Grimes 					goto bad;
1232df8bae1dSRodney W. Grimes 				}
1233bc189bf8SGuido van Rooij 				if (!ip_dosourceroute)
1234bc189bf8SGuido van Rooij 					goto nosourcerouting;
1235df8bae1dSRodney W. Grimes 				/*
1236df8bae1dSRodney W. Grimes 				 * Loose routing, and not at next destination
1237df8bae1dSRodney W. Grimes 				 * yet; nothing to do except forward.
1238df8bae1dSRodney W. Grimes 				 */
1239df8bae1dSRodney W. Grimes 				break;
1240df8bae1dSRodney W. Grimes 			}
1241df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
12425d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr)) {
1243df8bae1dSRodney W. Grimes 				/*
1244df8bae1dSRodney W. Grimes 				 * End of source route.  Should be for us.
1245df8bae1dSRodney W. Grimes 				 */
12464fce5804SGuido van Rooij 				if (!ip_acceptsourceroute)
12474fce5804SGuido van Rooij 					goto nosourcerouting;
1248df8bae1dSRodney W. Grimes 				save_rte(cp, ip->ip_src);
1249df8bae1dSRodney W. Grimes 				break;
1250df8bae1dSRodney W. Grimes 			}
12511025071fSGarrett Wollman 
12521025071fSGarrett Wollman 			if (!ip_dosourceroute) {
12530af8d3ecSDavid Greenman 				if (ipforwarding) {
12540af8d3ecSDavid Greenman 					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
12550af8d3ecSDavid Greenman 					/*
12560af8d3ecSDavid Greenman 					 * Acting as a router, so generate ICMP
12570af8d3ecSDavid Greenman 					 */
1258efa48587SGuido van Rooij nosourcerouting:
1259bc189bf8SGuido van Rooij 					strcpy(buf, inet_ntoa(ip->ip_dst));
12601025071fSGarrett Wollman 					log(LOG_WARNING,
12611025071fSGarrett Wollman 					    "attempted source route from %s to %s\n",
12621025071fSGarrett Wollman 					    inet_ntoa(ip->ip_src), buf);
12631025071fSGarrett Wollman 					type = ICMP_UNREACH;
12641025071fSGarrett Wollman 					code = ICMP_UNREACH_SRCFAIL;
12651025071fSGarrett Wollman 					goto bad;
12660af8d3ecSDavid Greenman 				} else {
12670af8d3ecSDavid Greenman 					/*
12680af8d3ecSDavid Greenman 					 * Not acting as a router, so silently drop.
12690af8d3ecSDavid Greenman 					 */
12700af8d3ecSDavid Greenman 					ipstat.ips_cantforward++;
12710af8d3ecSDavid Greenman 					m_freem(m);
12720af8d3ecSDavid Greenman 					return (1);
12730af8d3ecSDavid Greenman 				}
12741025071fSGarrett Wollman 			}
12751025071fSGarrett Wollman 
1276df8bae1dSRodney W. Grimes 			/*
1277df8bae1dSRodney W. Grimes 			 * locate outgoing interface
1278df8bae1dSRodney W. Grimes 			 */
127994a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, cp + off,
1280df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
12811025071fSGarrett Wollman 
1282df8bae1dSRodney W. Grimes 			if (opt == IPOPT_SSRR) {
1283df8bae1dSRodney W. Grimes #define	INA	struct in_ifaddr *
1284df8bae1dSRodney W. Grimes #define	SA	struct sockaddr *
1285df8bae1dSRodney W. Grimes 			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
1286df8bae1dSRodney W. Grimes 				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
1287df8bae1dSRodney W. Grimes 			} else
1288df8bae1dSRodney W. Grimes 				ia = ip_rtaddr(ipaddr.sin_addr);
1289df8bae1dSRodney W. Grimes 			if (ia == 0) {
1290df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1291df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_SRCFAIL;
1292df8bae1dSRodney W. Grimes 				goto bad;
1293df8bae1dSRodney W. Grimes 			}
1294df8bae1dSRodney W. Grimes 			ip->ip_dst = ipaddr.sin_addr;
129594a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
129694a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1297df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1298df8bae1dSRodney W. Grimes 			/*
1299df8bae1dSRodney W. Grimes 			 * Let ip_intr's mcast routing check handle mcast pkts
1300df8bae1dSRodney W. Grimes 			 */
1301df8bae1dSRodney W. Grimes 			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
1302df8bae1dSRodney W. Grimes 			break;
1303df8bae1dSRodney W. Grimes 
1304df8bae1dSRodney W. Grimes 		case IPOPT_RR:
1305707d00a3SJonathan Lemon 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
1306707d00a3SJonathan Lemon 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1307707d00a3SJonathan Lemon 				goto bad;
1308707d00a3SJonathan Lemon 			}
1309df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1310df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1311df8bae1dSRodney W. Grimes 				goto bad;
1312df8bae1dSRodney W. Grimes 			}
1313df8bae1dSRodney W. Grimes 			/*
1314df8bae1dSRodney W. Grimes 			 * If no space remains, ignore.
1315df8bae1dSRodney W. Grimes 			 */
1316df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
13175d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr))
1318df8bae1dSRodney W. Grimes 				break;
131994a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
1320df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
1321df8bae1dSRodney W. Grimes 			/*
1322df8bae1dSRodney W. Grimes 			 * locate outgoing interface; if we're the destination,
1323df8bae1dSRodney W. Grimes 			 * use the incoming interface (should be same).
1324df8bae1dSRodney W. Grimes 			 */
1325df8bae1dSRodney W. Grimes 			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
1326df8bae1dSRodney W. Grimes 			    (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
1327df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1328df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_HOST;
1329df8bae1dSRodney W. Grimes 				goto bad;
1330df8bae1dSRodney W. Grimes 			}
133194a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
133294a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1333df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1334df8bae1dSRodney W. Grimes 			break;
1335df8bae1dSRodney W. Grimes 
1336df8bae1dSRodney W. Grimes 		case IPOPT_TS:
1337df8bae1dSRodney W. Grimes 			code = cp - (u_char *)ip;
1338df8bae1dSRodney W. Grimes 			ipt = (struct ip_timestamp *)cp;
133933841545SHajimu UMEMOTO 			if (ipt->ipt_len < 4 || ipt->ipt_len > 40) {
134033841545SHajimu UMEMOTO 				code = (u_char *)&ipt->ipt_len - (u_char *)ip;
1341df8bae1dSRodney W. Grimes 				goto bad;
134233841545SHajimu UMEMOTO 			}
134333841545SHajimu UMEMOTO 			if (ipt->ipt_ptr < 5) {
134433841545SHajimu UMEMOTO 				code = (u_char *)&ipt->ipt_ptr - (u_char *)ip;
134533841545SHajimu UMEMOTO 				goto bad;
134633841545SHajimu UMEMOTO 			}
13475d5d5fc0SJonathan Lemon 			if (ipt->ipt_ptr >
13485d5d5fc0SJonathan Lemon 			    ipt->ipt_len - (int)sizeof(int32_t)) {
134933841545SHajimu UMEMOTO 				if (++ipt->ipt_oflw == 0) {
135033841545SHajimu UMEMOTO 					code = (u_char *)&ipt->ipt_ptr -
135133841545SHajimu UMEMOTO 					    (u_char *)ip;
1352df8bae1dSRodney W. Grimes 					goto bad;
135333841545SHajimu UMEMOTO 				}
1354df8bae1dSRodney W. Grimes 				break;
1355df8bae1dSRodney W. Grimes 			}
1356df8bae1dSRodney W. Grimes 			sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
1357df8bae1dSRodney W. Grimes 			switch (ipt->ipt_flg) {
1358df8bae1dSRodney W. Grimes 
1359df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSONLY:
1360df8bae1dSRodney W. Grimes 				break;
1361df8bae1dSRodney W. Grimes 
1362df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSANDADDR:
1363b8e8c209SDavid Greenman 				if (ipt->ipt_ptr - 1 + sizeof(n_time) +
136433841545SHajimu UMEMOTO 				    sizeof(struct in_addr) > ipt->ipt_len) {
136533841545SHajimu UMEMOTO 					code = (u_char *)&ipt->ipt_ptr -
136633841545SHajimu UMEMOTO 					    (u_char *)ip;
1367df8bae1dSRodney W. Grimes 					goto bad;
136833841545SHajimu UMEMOTO 				}
1369df8bae1dSRodney W. Grimes 				ipaddr.sin_addr = dst;
1370df8bae1dSRodney W. Grimes 				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
1371df8bae1dSRodney W. Grimes 							    m->m_pkthdr.rcvif);
1372df8bae1dSRodney W. Grimes 				if (ia == 0)
1373df8bae1dSRodney W. Grimes 					continue;
137494a5d9b6SDavid Greenman 				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
137594a5d9b6SDavid Greenman 				    sizeof(struct in_addr));
1376df8bae1dSRodney W. Grimes 				ipt->ipt_ptr += sizeof(struct in_addr);
1377df8bae1dSRodney W. Grimes 				break;
1378df8bae1dSRodney W. Grimes 
1379df8bae1dSRodney W. Grimes 			case IPOPT_TS_PRESPEC:
1380b8e8c209SDavid Greenman 				if (ipt->ipt_ptr - 1 + sizeof(n_time) +
138133841545SHajimu UMEMOTO 				    sizeof(struct in_addr) > ipt->ipt_len) {
138233841545SHajimu UMEMOTO 					code = (u_char *)&ipt->ipt_ptr -
138333841545SHajimu UMEMOTO 					    (u_char *)ip;
1384df8bae1dSRodney W. Grimes 					goto bad;
138533841545SHajimu UMEMOTO 				}
138694a5d9b6SDavid Greenman 				(void)memcpy(&ipaddr.sin_addr, sin,
1387df8bae1dSRodney W. Grimes 				    sizeof(struct in_addr));
1388df8bae1dSRodney W. Grimes 				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
1389df8bae1dSRodney W. Grimes 					continue;
1390df8bae1dSRodney W. Grimes 				ipt->ipt_ptr += sizeof(struct in_addr);
1391df8bae1dSRodney W. Grimes 				break;
1392df8bae1dSRodney W. Grimes 
1393df8bae1dSRodney W. Grimes 			default:
139433841545SHajimu UMEMOTO 				/* XXX can't take &ipt->ipt_flg */
139533841545SHajimu UMEMOTO 				code = (u_char *)&ipt->ipt_ptr -
139633841545SHajimu UMEMOTO 				    (u_char *)ip + 1;
1397df8bae1dSRodney W. Grimes 				goto bad;
1398df8bae1dSRodney W. Grimes 			}
1399df8bae1dSRodney W. Grimes 			ntime = iptime();
140094a5d9b6SDavid Greenman 			(void)memcpy(cp + ipt->ipt_ptr - 1, &ntime,
1401df8bae1dSRodney W. Grimes 			    sizeof(n_time));
1402df8bae1dSRodney W. Grimes 			ipt->ipt_ptr += sizeof(n_time);
1403df8bae1dSRodney W. Grimes 		}
1404df8bae1dSRodney W. Grimes 	}
140547174b49SAndrey A. Chernov 	if (forward && ipforwarding) {
1406df8bae1dSRodney W. Grimes 		ip_forward(m, 1);
1407df8bae1dSRodney W. Grimes 		return (1);
1408df8bae1dSRodney W. Grimes 	}
1409df8bae1dSRodney W. Grimes 	return (0);
1410df8bae1dSRodney W. Grimes bad:
1411df8bae1dSRodney W. Grimes 	icmp_error(m, type, code, 0, 0);
1412df8bae1dSRodney W. Grimes 	ipstat.ips_badoptions++;
1413df8bae1dSRodney W. Grimes 	return (1);
1414df8bae1dSRodney W. Grimes }
1415df8bae1dSRodney W. Grimes 
1416df8bae1dSRodney W. Grimes /*
1417df8bae1dSRodney W. Grimes  * Given address of next destination (final or next hop),
1418df8bae1dSRodney W. Grimes  * return internet address info of interface to be used to get there.
1419df8bae1dSRodney W. Grimes  */
14200312fbe9SPoul-Henning Kamp static struct in_ifaddr *
1421df8bae1dSRodney W. Grimes ip_rtaddr(dst)
1422df8bae1dSRodney W. Grimes 	 struct in_addr dst;
1423df8bae1dSRodney W. Grimes {
1424df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
1425df8bae1dSRodney W. Grimes 
1426df8bae1dSRodney W. Grimes 	sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
1427df8bae1dSRodney W. Grimes 
14284078ffb1SRuslan Ermilov 	if (ipforward_rt.ro_rt == 0 ||
14294078ffb1SRuslan Ermilov 	    !(ipforward_rt.ro_rt->rt_flags & RTF_UP) ||
14304078ffb1SRuslan Ermilov 	    dst.s_addr != sin->sin_addr.s_addr) {
1431df8bae1dSRodney W. Grimes 		if (ipforward_rt.ro_rt) {
1432df8bae1dSRodney W. Grimes 			RTFREE(ipforward_rt.ro_rt);
1433df8bae1dSRodney W. Grimes 			ipforward_rt.ro_rt = 0;
1434df8bae1dSRodney W. Grimes 		}
1435df8bae1dSRodney W. Grimes 		sin->sin_family = AF_INET;
1436df8bae1dSRodney W. Grimes 		sin->sin_len = sizeof(*sin);
1437df8bae1dSRodney W. Grimes 		sin->sin_addr = dst;
1438df8bae1dSRodney W. Grimes 
14392c17fe93SGarrett Wollman 		rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
1440df8bae1dSRodney W. Grimes 	}
1441df8bae1dSRodney W. Grimes 	if (ipforward_rt.ro_rt == 0)
1442df8bae1dSRodney W. Grimes 		return ((struct in_ifaddr *)0);
14439a10980eSJonathan Lemon 	return (ifatoia(ipforward_rt.ro_rt->rt_ifa));
1444df8bae1dSRodney W. Grimes }
1445df8bae1dSRodney W. Grimes 
1446df8bae1dSRodney W. Grimes /*
1447df8bae1dSRodney W. Grimes  * Save incoming source route for use in replies,
1448df8bae1dSRodney W. Grimes  * to be picked up later by ip_srcroute if the receiver is interested.
1449df8bae1dSRodney W. Grimes  */
1450df8bae1dSRodney W. Grimes void
1451df8bae1dSRodney W. Grimes save_rte(option, dst)
1452df8bae1dSRodney W. Grimes 	u_char *option;
1453df8bae1dSRodney W. Grimes 	struct in_addr dst;
1454df8bae1dSRodney W. Grimes {
1455df8bae1dSRodney W. Grimes 	unsigned olen;
1456df8bae1dSRodney W. Grimes 
1457df8bae1dSRodney W. Grimes 	olen = option[IPOPT_OLEN];
1458df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1459df8bae1dSRodney W. Grimes 	if (ipprintfs)
1460df8bae1dSRodney W. Grimes 		printf("save_rte: olen %d\n", olen);
1461df8bae1dSRodney W. Grimes #endif
1462df8bae1dSRodney W. Grimes 	if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
1463df8bae1dSRodney W. Grimes 		return;
14640453d3cbSBruce Evans 	bcopy(option, ip_srcrt.srcopt, olen);
1465df8bae1dSRodney W. Grimes 	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
1466df8bae1dSRodney W. Grimes 	ip_srcrt.dst = dst;
1467df8bae1dSRodney W. Grimes }
1468df8bae1dSRodney W. Grimes 
1469df8bae1dSRodney W. Grimes /*
1470df8bae1dSRodney W. Grimes  * Retrieve incoming source route for use in replies,
1471df8bae1dSRodney W. Grimes  * in the same form used by setsockopt.
1472df8bae1dSRodney W. Grimes  * The first hop is placed before the options, will be removed later.
1473df8bae1dSRodney W. Grimes  */
1474df8bae1dSRodney W. Grimes struct mbuf *
1475df8bae1dSRodney W. Grimes ip_srcroute()
1476df8bae1dSRodney W. Grimes {
1477df8bae1dSRodney W. Grimes 	register struct in_addr *p, *q;
1478df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1479df8bae1dSRodney W. Grimes 
1480df8bae1dSRodney W. Grimes 	if (ip_nhops == 0)
1481df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1482cfe8b629SGarrett Wollman 	m = m_get(M_DONTWAIT, MT_HEADER);
1483df8bae1dSRodney W. Grimes 	if (m == 0)
1484df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1485df8bae1dSRodney W. Grimes 
1486df8bae1dSRodney W. Grimes #define OPTSIZ	(sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
1487df8bae1dSRodney W. Grimes 
1488df8bae1dSRodney W. Grimes 	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
1489df8bae1dSRodney W. Grimes 	m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
1490df8bae1dSRodney W. Grimes 	    OPTSIZ;
1491df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1492df8bae1dSRodney W. Grimes 	if (ipprintfs)
1493df8bae1dSRodney W. Grimes 		printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
1494df8bae1dSRodney W. Grimes #endif
1495df8bae1dSRodney W. Grimes 
1496df8bae1dSRodney W. Grimes 	/*
1497df8bae1dSRodney W. Grimes 	 * First save first hop for return route
1498df8bae1dSRodney W. Grimes 	 */
1499df8bae1dSRodney W. Grimes 	p = &ip_srcrt.route[ip_nhops - 1];
1500df8bae1dSRodney W. Grimes 	*(mtod(m, struct in_addr *)) = *p--;
1501df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1502df8bae1dSRodney W. Grimes 	if (ipprintfs)
1503af38c68cSLuigi Rizzo 		printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
1504df8bae1dSRodney W. Grimes #endif
1505df8bae1dSRodney W. Grimes 
1506df8bae1dSRodney W. Grimes 	/*
1507df8bae1dSRodney W. Grimes 	 * Copy option fields and padding (nop) to mbuf.
1508df8bae1dSRodney W. Grimes 	 */
1509df8bae1dSRodney W. Grimes 	ip_srcrt.nop = IPOPT_NOP;
1510df8bae1dSRodney W. Grimes 	ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
151194a5d9b6SDavid Greenman 	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
151294a5d9b6SDavid Greenman 	    &ip_srcrt.nop, OPTSIZ);
1513df8bae1dSRodney W. Grimes 	q = (struct in_addr *)(mtod(m, caddr_t) +
1514df8bae1dSRodney W. Grimes 	    sizeof(struct in_addr) + OPTSIZ);
1515df8bae1dSRodney W. Grimes #undef OPTSIZ
1516df8bae1dSRodney W. Grimes 	/*
1517df8bae1dSRodney W. Grimes 	 * Record return path as an IP source route,
1518df8bae1dSRodney W. Grimes 	 * reversing the path (pointers are now aligned).
1519df8bae1dSRodney W. Grimes 	 */
1520df8bae1dSRodney W. Grimes 	while (p >= ip_srcrt.route) {
1521df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1522df8bae1dSRodney W. Grimes 		if (ipprintfs)
1523af38c68cSLuigi Rizzo 			printf(" %lx", (u_long)ntohl(q->s_addr));
1524df8bae1dSRodney W. Grimes #endif
1525df8bae1dSRodney W. Grimes 		*q++ = *p--;
1526df8bae1dSRodney W. Grimes 	}
1527df8bae1dSRodney W. Grimes 	/*
1528df8bae1dSRodney W. Grimes 	 * Last hop goes to final destination.
1529df8bae1dSRodney W. Grimes 	 */
1530df8bae1dSRodney W. Grimes 	*q = ip_srcrt.dst;
1531df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1532df8bae1dSRodney W. Grimes 	if (ipprintfs)
1533af38c68cSLuigi Rizzo 		printf(" %lx\n", (u_long)ntohl(q->s_addr));
1534df8bae1dSRodney W. Grimes #endif
1535df8bae1dSRodney W. Grimes 	return (m);
1536df8bae1dSRodney W. Grimes }
1537df8bae1dSRodney W. Grimes 
1538df8bae1dSRodney W. Grimes /*
1539df8bae1dSRodney W. Grimes  * Strip out IP options, at higher
1540df8bae1dSRodney W. Grimes  * level protocol in the kernel.
1541df8bae1dSRodney W. Grimes  * Second argument is buffer to which options
1542df8bae1dSRodney W. Grimes  * will be moved, and return value is their length.
1543df8bae1dSRodney W. Grimes  * XXX should be deleted; last arg currently ignored.
1544df8bae1dSRodney W. Grimes  */
1545df8bae1dSRodney W. Grimes void
1546df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt)
1547df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1548df8bae1dSRodney W. Grimes 	struct mbuf *mopt;
1549df8bae1dSRodney W. Grimes {
1550df8bae1dSRodney W. Grimes 	register int i;
1551df8bae1dSRodney W. Grimes 	struct ip *ip = mtod(m, struct ip *);
1552df8bae1dSRodney W. Grimes 	register caddr_t opts;
1553df8bae1dSRodney W. Grimes 	int olen;
1554df8bae1dSRodney W. Grimes 
155558938916SGarrett Wollman 	olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1556df8bae1dSRodney W. Grimes 	opts = (caddr_t)(ip + 1);
1557df8bae1dSRodney W. Grimes 	i = m->m_len - (sizeof (struct ip) + olen);
1558df8bae1dSRodney W. Grimes 	bcopy(opts + olen, opts, (unsigned)i);
1559df8bae1dSRodney W. Grimes 	m->m_len -= olen;
1560df8bae1dSRodney W. Grimes 	if (m->m_flags & M_PKTHDR)
1561df8bae1dSRodney W. Grimes 		m->m_pkthdr.len -= olen;
156258938916SGarrett Wollman 	ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2);
1563df8bae1dSRodney W. Grimes }
1564df8bae1dSRodney W. Grimes 
1565df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = {
1566df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
1567df8bae1dSRodney W. Grimes 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
1568df8bae1dSRodney W. Grimes 	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
1569df8bae1dSRodney W. Grimes 	EMSGSIZE,	EHOSTUNREACH,	0,		0,
1570df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
15713b8123b7SJesper Skriver 	ENOPROTOOPT,	ECONNREFUSED
1572df8bae1dSRodney W. Grimes };
1573df8bae1dSRodney W. Grimes 
1574df8bae1dSRodney W. Grimes /*
1575df8bae1dSRodney W. Grimes  * Forward a packet.  If some error occurs return the sender
1576df8bae1dSRodney W. Grimes  * an icmp packet.  Note we can't always generate a meaningful
1577df8bae1dSRodney W. Grimes  * icmp message because icmp doesn't have a large enough repertoire
1578df8bae1dSRodney W. Grimes  * of codes and types.
1579df8bae1dSRodney W. Grimes  *
1580df8bae1dSRodney W. Grimes  * If not forwarding, just drop the packet.  This could be confusing
1581df8bae1dSRodney W. Grimes  * if ipforwarding was zero but some routing protocol was advancing
1582df8bae1dSRodney W. Grimes  * us as a gateway to somewhere.  However, we must let the routing
1583df8bae1dSRodney W. Grimes  * protocol deal with that.
1584df8bae1dSRodney W. Grimes  *
1585df8bae1dSRodney W. Grimes  * The srcrt parameter indicates whether the packet is being forwarded
1586df8bae1dSRodney W. Grimes  * via a source route.
1587df8bae1dSRodney W. Grimes  */
15880312fbe9SPoul-Henning Kamp static void
1589df8bae1dSRodney W. Grimes ip_forward(m, srcrt)
1590df8bae1dSRodney W. Grimes 	struct mbuf *m;
1591df8bae1dSRodney W. Grimes 	int srcrt;
1592df8bae1dSRodney W. Grimes {
1593df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
1594df8bae1dSRodney W. Grimes 	register struct rtentry *rt;
159526f9a767SRodney W. Grimes 	int error, type = 0, code = 0;
1596df8bae1dSRodney W. Grimes 	struct mbuf *mcopy;
1597df8bae1dSRodney W. Grimes 	n_long dest;
1598df8bae1dSRodney W. Grimes 	struct ifnet *destifp;
15996a800098SYoshinobu Inoue #ifdef IPSEC
16006a800098SYoshinobu Inoue 	struct ifnet dummyifp;
16016a800098SYoshinobu Inoue #endif
1602df8bae1dSRodney W. Grimes 
1603df8bae1dSRodney W. Grimes 	dest = 0;
1604df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1605df8bae1dSRodney W. Grimes 	if (ipprintfs)
160661ce519bSPoul-Henning Kamp 		printf("forward: src %lx dst %lx ttl %x\n",
1607162886e2SBruce Evans 		    (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr,
1608162886e2SBruce Evans 		    ip->ip_ttl);
1609df8bae1dSRodney W. Grimes #endif
1610100ba1a6SJordan K. Hubbard 
1611100ba1a6SJordan K. Hubbard 
161292af003dSGarrett Wollman 	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
1613df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1614df8bae1dSRodney W. Grimes 		m_freem(m);
1615df8bae1dSRodney W. Grimes 		return;
1616df8bae1dSRodney W. Grimes 	}
16171b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
16181b968362SDag-Erling Smørgrav 	if (!ipstealth) {
16191b968362SDag-Erling Smørgrav #endif
1620df8bae1dSRodney W. Grimes 		if (ip->ip_ttl <= IPTTLDEC) {
16211b968362SDag-Erling Smørgrav 			icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
16221b968362SDag-Erling Smørgrav 			    dest, 0);
1623df8bae1dSRodney W. Grimes 			return;
1624df8bae1dSRodney W. Grimes 		}
16251b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
16261b968362SDag-Erling Smørgrav 	}
16271b968362SDag-Erling Smørgrav #endif
1628df8bae1dSRodney W. Grimes 
16294078ffb1SRuslan Ermilov 	if (ip_rtaddr(ip->ip_dst) == 0) {
1630df8bae1dSRodney W. Grimes 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
1631df8bae1dSRodney W. Grimes 		return;
16324078ffb1SRuslan Ermilov 	} else
1633df8bae1dSRodney W. Grimes 		rt = ipforward_rt.ro_rt;
1634df8bae1dSRodney W. Grimes 
1635df8bae1dSRodney W. Grimes 	/*
1636bfef7ed4SIan Dowse 	 * Save the IP header and at most 8 bytes of the payload,
1637bfef7ed4SIan Dowse 	 * in case we need to generate an ICMP message to the src.
1638bfef7ed4SIan Dowse 	 *
1639bfef7ed4SIan Dowse 	 * We don't use m_copy() because it might return a reference
1640bfef7ed4SIan Dowse 	 * to a shared cluster. Both this function and ip_output()
1641bfef7ed4SIan Dowse 	 * assume exclusive access to the IP header in `m', so any
1642bfef7ed4SIan Dowse 	 * data in a cluster may change before we reach icmp_error().
1643df8bae1dSRodney W. Grimes 	 */
1644bfef7ed4SIan Dowse 	MGET(mcopy, M_DONTWAIT, m->m_type);
1645bfef7ed4SIan Dowse 	if (mcopy != NULL) {
1646bfef7ed4SIan Dowse 		M_COPY_PKTHDR(mcopy, m);
1647bfef7ed4SIan Dowse 		mcopy->m_len = imin((IP_VHL_HL(ip->ip_vhl) << 2) + 8,
1648bfef7ed4SIan Dowse 		    (int)ip->ip_len);
1649bfef7ed4SIan Dowse 		m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
1650bfef7ed4SIan Dowse 	}
165104287599SRuslan Ermilov 
165204287599SRuslan Ermilov #ifdef IPSTEALTH
165304287599SRuslan Ermilov 	if (!ipstealth) {
165404287599SRuslan Ermilov #endif
165504287599SRuslan Ermilov 		ip->ip_ttl -= IPTTLDEC;
165604287599SRuslan Ermilov #ifdef IPSTEALTH
165704287599SRuslan Ermilov 	}
165804287599SRuslan Ermilov #endif
1659df8bae1dSRodney W. Grimes 
1660df8bae1dSRodney W. Grimes 	/*
1661df8bae1dSRodney W. Grimes 	 * If forwarding packet using same interface that it came in on,
1662df8bae1dSRodney W. Grimes 	 * perhaps should send a redirect to sender to shortcut a hop.
1663df8bae1dSRodney W. Grimes 	 * Only send redirect if source is sending directly to us,
1664df8bae1dSRodney W. Grimes 	 * and if packet was not source routed (or has any options).
1665df8bae1dSRodney W. Grimes 	 * Also, don't send redirect if forwarding using a default route
1666df8bae1dSRodney W. Grimes 	 * or a route modified by a redirect.
1667df8bae1dSRodney W. Grimes 	 */
1668df8bae1dSRodney W. Grimes 	if (rt->rt_ifp == m->m_pkthdr.rcvif &&
1669df8bae1dSRodney W. Grimes 	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
1670df8bae1dSRodney W. Grimes 	    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
1671df8bae1dSRodney W. Grimes 	    ipsendredirects && !srcrt) {
1672df8bae1dSRodney W. Grimes #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
1673df8bae1dSRodney W. Grimes 		u_long src = ntohl(ip->ip_src.s_addr);
1674df8bae1dSRodney W. Grimes 
1675df8bae1dSRodney W. Grimes 		if (RTA(rt) &&
1676df8bae1dSRodney W. Grimes 		    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1677df8bae1dSRodney W. Grimes 		    if (rt->rt_flags & RTF_GATEWAY)
1678df8bae1dSRodney W. Grimes 			dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
1679df8bae1dSRodney W. Grimes 		    else
1680df8bae1dSRodney W. Grimes 			dest = ip->ip_dst.s_addr;
1681df8bae1dSRodney W. Grimes 		    /* Router requirements says to only send host redirects */
1682df8bae1dSRodney W. Grimes 		    type = ICMP_REDIRECT;
1683df8bae1dSRodney W. Grimes 		    code = ICMP_REDIRECT_HOST;
1684df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1685df8bae1dSRodney W. Grimes 		    if (ipprintfs)
1686df8bae1dSRodney W. Grimes 		        printf("redirect (%d) to %lx\n", code, (u_long)dest);
1687df8bae1dSRodney W. Grimes #endif
1688df8bae1dSRodney W. Grimes 		}
1689df8bae1dSRodney W. Grimes 	}
1690df8bae1dSRodney W. Grimes 
1691b97d15cbSGarrett Wollman 	error = ip_output(m, (struct mbuf *)0, &ipforward_rt,
1692b97d15cbSGarrett Wollman 			  IP_FORWARDING, 0);
1693df8bae1dSRodney W. Grimes 	if (error)
1694df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1695df8bae1dSRodney W. Grimes 	else {
1696df8bae1dSRodney W. Grimes 		ipstat.ips_forward++;
1697df8bae1dSRodney W. Grimes 		if (type)
1698df8bae1dSRodney W. Grimes 			ipstat.ips_redirectsent++;
1699df8bae1dSRodney W. Grimes 		else {
17001f91d8c5SDavid Greenman 			if (mcopy) {
17011f91d8c5SDavid Greenman 				ipflow_create(&ipforward_rt, mcopy);
1702df8bae1dSRodney W. Grimes 				m_freem(mcopy);
17031f91d8c5SDavid Greenman 			}
1704df8bae1dSRodney W. Grimes 			return;
1705df8bae1dSRodney W. Grimes 		}
1706df8bae1dSRodney W. Grimes 	}
1707df8bae1dSRodney W. Grimes 	if (mcopy == NULL)
1708df8bae1dSRodney W. Grimes 		return;
1709df8bae1dSRodney W. Grimes 	destifp = NULL;
1710df8bae1dSRodney W. Grimes 
1711df8bae1dSRodney W. Grimes 	switch (error) {
1712df8bae1dSRodney W. Grimes 
1713df8bae1dSRodney W. Grimes 	case 0:				/* forwarded, but need redirect */
1714df8bae1dSRodney W. Grimes 		/* type, code set above */
1715df8bae1dSRodney W. Grimes 		break;
1716df8bae1dSRodney W. Grimes 
1717df8bae1dSRodney W. Grimes 	case ENETUNREACH:		/* shouldn't happen, checked above */
1718df8bae1dSRodney W. Grimes 	case EHOSTUNREACH:
1719df8bae1dSRodney W. Grimes 	case ENETDOWN:
1720df8bae1dSRodney W. Grimes 	case EHOSTDOWN:
1721df8bae1dSRodney W. Grimes 	default:
1722df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1723df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_HOST;
1724df8bae1dSRodney W. Grimes 		break;
1725df8bae1dSRodney W. Grimes 
1726df8bae1dSRodney W. Grimes 	case EMSGSIZE:
1727df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1728df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_NEEDFRAG;
17296a800098SYoshinobu Inoue #ifndef IPSEC
1730df8bae1dSRodney W. Grimes 		if (ipforward_rt.ro_rt)
1731df8bae1dSRodney W. Grimes 			destifp = ipforward_rt.ro_rt->rt_ifp;
17326a800098SYoshinobu Inoue #else
17336a800098SYoshinobu Inoue 		/*
17346a800098SYoshinobu Inoue 		 * If the packet is routed over IPsec tunnel, tell the
17356a800098SYoshinobu Inoue 		 * originator the tunnel MTU.
17366a800098SYoshinobu Inoue 		 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
17376a800098SYoshinobu Inoue 		 * XXX quickhack!!!
17386a800098SYoshinobu Inoue 		 */
17396a800098SYoshinobu Inoue 		if (ipforward_rt.ro_rt) {
17406a800098SYoshinobu Inoue 			struct secpolicy *sp = NULL;
17416a800098SYoshinobu Inoue 			int ipsecerror;
17426a800098SYoshinobu Inoue 			int ipsechdr;
17436a800098SYoshinobu Inoue 			struct route *ro;
17446a800098SYoshinobu Inoue 
17456a800098SYoshinobu Inoue 			sp = ipsec4_getpolicybyaddr(mcopy,
17466a800098SYoshinobu Inoue 						    IPSEC_DIR_OUTBOUND,
17476a800098SYoshinobu Inoue 			                            IP_FORWARDING,
17486a800098SYoshinobu Inoue 			                            &ipsecerror);
17496a800098SYoshinobu Inoue 
17506a800098SYoshinobu Inoue 			if (sp == NULL)
17516a800098SYoshinobu Inoue 				destifp = ipforward_rt.ro_rt->rt_ifp;
17526a800098SYoshinobu Inoue 			else {
17536a800098SYoshinobu Inoue 				/* count IPsec header size */
17546a800098SYoshinobu Inoue 				ipsechdr = ipsec4_hdrsiz(mcopy,
17556a800098SYoshinobu Inoue 							 IPSEC_DIR_OUTBOUND,
17566a800098SYoshinobu Inoue 							 NULL);
17576a800098SYoshinobu Inoue 
17586a800098SYoshinobu Inoue 				/*
17596a800098SYoshinobu Inoue 				 * find the correct route for outer IPv4
17606a800098SYoshinobu Inoue 				 * header, compute tunnel MTU.
17616a800098SYoshinobu Inoue 				 *
17626a800098SYoshinobu Inoue 				 * XXX BUG ALERT
17636a800098SYoshinobu Inoue 				 * The "dummyifp" code relies upon the fact
17646a800098SYoshinobu Inoue 				 * that icmp_error() touches only ifp->if_mtu.
17656a800098SYoshinobu Inoue 				 */
17666a800098SYoshinobu Inoue 				/*XXX*/
17676a800098SYoshinobu Inoue 				destifp = NULL;
17686a800098SYoshinobu Inoue 				if (sp->req != NULL
17696a800098SYoshinobu Inoue 				 && sp->req->sav != NULL
17706a800098SYoshinobu Inoue 				 && sp->req->sav->sah != NULL) {
17716a800098SYoshinobu Inoue 					ro = &sp->req->sav->sah->sa_route;
17726a800098SYoshinobu Inoue 					if (ro->ro_rt && ro->ro_rt->rt_ifp) {
17736a800098SYoshinobu Inoue 						dummyifp.if_mtu =
17746a800098SYoshinobu Inoue 						    ro->ro_rt->rt_ifp->if_mtu;
17756a800098SYoshinobu Inoue 						dummyifp.if_mtu -= ipsechdr;
17766a800098SYoshinobu Inoue 						destifp = &dummyifp;
17776a800098SYoshinobu Inoue 					}
17786a800098SYoshinobu Inoue 				}
17796a800098SYoshinobu Inoue 
17806a800098SYoshinobu Inoue 				key_freesp(sp);
17816a800098SYoshinobu Inoue 			}
17826a800098SYoshinobu Inoue 		}
17836a800098SYoshinobu Inoue #endif /*IPSEC*/
1784df8bae1dSRodney W. Grimes 		ipstat.ips_cantfrag++;
1785df8bae1dSRodney W. Grimes 		break;
1786df8bae1dSRodney W. Grimes 
1787df8bae1dSRodney W. Grimes 	case ENOBUFS:
1788df8bae1dSRodney W. Grimes 		type = ICMP_SOURCEQUENCH;
1789df8bae1dSRodney W. Grimes 		code = 0;
1790df8bae1dSRodney W. Grimes 		break;
17913a06e3e0SRuslan Ermilov 
17923a06e3e0SRuslan Ermilov 	case EACCES:			/* ipfw denied packet */
17933a06e3e0SRuslan Ermilov 		m_freem(mcopy);
17943a06e3e0SRuslan Ermilov 		return;
1795df8bae1dSRodney W. Grimes 	}
1796df8bae1dSRodney W. Grimes 	icmp_error(mcopy, type, code, dest, destifp);
1797df8bae1dSRodney W. Grimes }
1798df8bae1dSRodney W. Grimes 
179982c23ebaSBill Fenner void
180082c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m)
180182c23ebaSBill Fenner 	register struct inpcb *inp;
180282c23ebaSBill Fenner 	register struct mbuf **mp;
180382c23ebaSBill Fenner 	register struct ip *ip;
180482c23ebaSBill Fenner 	register struct mbuf *m;
180582c23ebaSBill Fenner {
180682c23ebaSBill Fenner 	if (inp->inp_socket->so_options & SO_TIMESTAMP) {
180782c23ebaSBill Fenner 		struct timeval tv;
180882c23ebaSBill Fenner 
180982c23ebaSBill Fenner 		microtime(&tv);
181082c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
181182c23ebaSBill Fenner 			SCM_TIMESTAMP, SOL_SOCKET);
181282c23ebaSBill Fenner 		if (*mp)
181382c23ebaSBill Fenner 			mp = &(*mp)->m_next;
181482c23ebaSBill Fenner 	}
181582c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVDSTADDR) {
181682c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
181782c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
181882c23ebaSBill Fenner 		if (*mp)
181982c23ebaSBill Fenner 			mp = &(*mp)->m_next;
182082c23ebaSBill Fenner 	}
182182c23ebaSBill Fenner #ifdef notyet
182282c23ebaSBill Fenner 	/* XXX
182382c23ebaSBill Fenner 	 * Moving these out of udp_input() made them even more broken
182482c23ebaSBill Fenner 	 * than they already were.
182582c23ebaSBill Fenner 	 */
182682c23ebaSBill Fenner 	/* options were tossed already */
182782c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVOPTS) {
182882c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) opts_deleted_above,
182982c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
183082c23ebaSBill Fenner 		if (*mp)
183182c23ebaSBill Fenner 			mp = &(*mp)->m_next;
183282c23ebaSBill Fenner 	}
183382c23ebaSBill Fenner 	/* ip_srcroute doesn't do what we want here, need to fix */
183482c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVRETOPTS) {
183582c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) ip_srcroute(),
183682c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
183782c23ebaSBill Fenner 		if (*mp)
183882c23ebaSBill Fenner 			mp = &(*mp)->m_next;
183982c23ebaSBill Fenner 	}
184082c23ebaSBill Fenner #endif
184182c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVIF) {
1842d314ad7bSJulian Elischer 		struct ifnet *ifp;
1843d314ad7bSJulian Elischer 		struct sdlbuf {
184482c23ebaSBill Fenner 			struct sockaddr_dl sdl;
1845d314ad7bSJulian Elischer 			u_char	pad[32];
1846d314ad7bSJulian Elischer 		} sdlbuf;
1847d314ad7bSJulian Elischer 		struct sockaddr_dl *sdp;
1848d314ad7bSJulian Elischer 		struct sockaddr_dl *sdl2 = &sdlbuf.sdl;
184982c23ebaSBill Fenner 
1850d314ad7bSJulian Elischer 		if (((ifp = m->m_pkthdr.rcvif))
1851d314ad7bSJulian Elischer 		&& ( ifp->if_index && (ifp->if_index <= if_index))) {
1852f9132cebSJonathan Lemon 			sdp = (struct sockaddr_dl *)
1853f9132cebSJonathan Lemon 			    (ifaddr_byindex(ifp->if_index)->ifa_addr);
1854d314ad7bSJulian Elischer 			/*
1855d314ad7bSJulian Elischer 			 * Change our mind and don't try copy.
1856d314ad7bSJulian Elischer 			 */
1857d314ad7bSJulian Elischer 			if ((sdp->sdl_family != AF_LINK)
1858d314ad7bSJulian Elischer 			|| (sdp->sdl_len > sizeof(sdlbuf))) {
1859d314ad7bSJulian Elischer 				goto makedummy;
1860d314ad7bSJulian Elischer 			}
1861d314ad7bSJulian Elischer 			bcopy(sdp, sdl2, sdp->sdl_len);
1862d314ad7bSJulian Elischer 		} else {
1863d314ad7bSJulian Elischer makedummy:
1864d314ad7bSJulian Elischer 			sdl2->sdl_len
1865d314ad7bSJulian Elischer 				= offsetof(struct sockaddr_dl, sdl_data[0]);
1866d314ad7bSJulian Elischer 			sdl2->sdl_family = AF_LINK;
1867d314ad7bSJulian Elischer 			sdl2->sdl_index = 0;
1868d314ad7bSJulian Elischer 			sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;
1869d314ad7bSJulian Elischer 		}
1870d314ad7bSJulian Elischer 		*mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,
187182c23ebaSBill Fenner 			IP_RECVIF, IPPROTO_IP);
187282c23ebaSBill Fenner 		if (*mp)
187382c23ebaSBill Fenner 			mp = &(*mp)->m_next;
187482c23ebaSBill Fenner 	}
187582c23ebaSBill Fenner }
187682c23ebaSBill Fenner 
1877df8bae1dSRodney W. Grimes int
1878f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so)
1879f0068c4aSGarrett Wollman {
1880f0068c4aSGarrett Wollman 	if (so->so_type != SOCK_RAW ||
1881f0068c4aSGarrett Wollman 	    so->so_proto->pr_protocol != IPPROTO_RSVP)
1882f0068c4aSGarrett Wollman 	  return EOPNOTSUPP;
1883f0068c4aSGarrett Wollman 
1884f0068c4aSGarrett Wollman 	if (ip_rsvpd != NULL)
1885f0068c4aSGarrett Wollman 	  return EADDRINUSE;
1886f0068c4aSGarrett Wollman 
1887f0068c4aSGarrett Wollman 	ip_rsvpd = so;
18881c5de19aSGarrett Wollman 	/*
18891c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-increment
18901c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
18911c5de19aSGarrett Wollman 	 */
18921c5de19aSGarrett Wollman 	if (!ip_rsvp_on) {
18931c5de19aSGarrett Wollman 		ip_rsvp_on = 1;
18941c5de19aSGarrett Wollman 		rsvp_on++;
18951c5de19aSGarrett Wollman 	}
1896f0068c4aSGarrett Wollman 
1897f0068c4aSGarrett Wollman 	return 0;
1898f0068c4aSGarrett Wollman }
1899f0068c4aSGarrett Wollman 
1900f0068c4aSGarrett Wollman int
1901f0068c4aSGarrett Wollman ip_rsvp_done(void)
1902f0068c4aSGarrett Wollman {
1903f0068c4aSGarrett Wollman 	ip_rsvpd = NULL;
19041c5de19aSGarrett Wollman 	/*
19051c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-decrement
19061c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
19071c5de19aSGarrett Wollman 	 */
19081c5de19aSGarrett Wollman 	if (ip_rsvp_on) {
19091c5de19aSGarrett Wollman 		ip_rsvp_on = 0;
19101c5de19aSGarrett Wollman 		rsvp_on--;
19111c5de19aSGarrett Wollman 	}
1912f0068c4aSGarrett Wollman 	return 0;
1913f0068c4aSGarrett Wollman }
1914