xref: /freebsd/sys/netinet/ip_input.c (revision db40007d42fa5f449ed312499635957a39a21d03)
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>
82db69a05dSPaul Saab #include <netinet/ip_dummynet.h>
83db69a05dSPaul Saab 
846a800098SYoshinobu Inoue #ifdef IPSEC
856a800098SYoshinobu Inoue #include <netinet6/ipsec.h>
866a800098SYoshinobu Inoue #include <netkey/key.h>
876a800098SYoshinobu Inoue #endif
886a800098SYoshinobu Inoue 
891c5de19aSGarrett Wollman int rsvp_on = 0;
90f708ef1bSPoul-Henning Kamp static int ip_rsvp_on;
91f0068c4aSGarrett Wollman struct socket *ip_rsvpd;
92f0068c4aSGarrett Wollman 
931f91d8c5SDavid Greenman int	ipforwarding = 0;
940312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW,
953d177f46SBill Fumerola     &ipforwarding, 0, "Enable IP forwarding between interfaces");
960312fbe9SPoul-Henning Kamp 
97d4fb926cSGarrett Wollman static int	ipsendredirects = 1; /* XXX */
980312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW,
993d177f46SBill Fumerola     &ipsendredirects, 0, "Enable sending IP redirects");
1000312fbe9SPoul-Henning Kamp 
101df8bae1dSRodney W. Grimes int	ip_defttl = IPDEFTTL;
1020312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW,
1033d177f46SBill Fumerola     &ip_defttl, 0, "Maximum TTL on IP packets");
1040312fbe9SPoul-Henning Kamp 
1050312fbe9SPoul-Henning Kamp static int	ip_dosourceroute = 0;
1060312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
1073d177f46SBill Fumerola     &ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
1084fce5804SGuido van Rooij 
1094fce5804SGuido van Rooij static int	ip_acceptsourceroute = 0;
1104fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute,
1113d177f46SBill Fumerola     CTLFLAG_RW, &ip_acceptsourceroute, 0,
1123d177f46SBill Fumerola     "Enable accepting source routed IP packets");
1136a800098SYoshinobu Inoue 
1146a800098SYoshinobu Inoue static int	ip_keepfaith = 0;
1156a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
1166a800098SYoshinobu Inoue 	&ip_keepfaith,	0,
1176a800098SYoshinobu Inoue 	"Enable packet capture for FAITH IPv4->IPv6 translater daemon");
1186a800098SYoshinobu Inoue 
119690a6055SJesper Skriver static int	ip_nfragpackets = 0;
12096c2b042SJesper Skriver static int	ip_maxfragpackets;	/* initialized in ip_init() */
121690a6055SJesper Skriver SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW,
122690a6055SJesper Skriver 	&ip_maxfragpackets, 0,
123690a6055SJesper Skriver 	"Maximum number of IPv4 fragment reassembly queue entries");
124690a6055SJesper Skriver 
125823db0e9SDon Lewis /*
126823db0e9SDon Lewis  * XXX - Setting ip_checkinterface mostly implements the receive side of
127823db0e9SDon Lewis  * the Strong ES model described in RFC 1122, but since the routing table
128a8f12100SDon Lewis  * and transmit implementation do not implement the Strong ES model,
129823db0e9SDon Lewis  * setting this to 1 results in an odd hybrid.
1303f67c834SDon Lewis  *
131a8f12100SDon Lewis  * XXX - ip_checkinterface currently must be disabled if you use ipnat
132a8f12100SDon Lewis  * to translate the destination address to another local interface.
1333f67c834SDon Lewis  *
1343f67c834SDon Lewis  * XXX - ip_checkinterface must be disabled if you add IP aliases
1353f67c834SDon Lewis  * to the loopback interface instead of the interface where the
1363f67c834SDon Lewis  * packets for those addresses are received.
137823db0e9SDon Lewis  */
138b3e95d4eSJonathan Lemon static int	ip_checkinterface = 1;
139b3e95d4eSJonathan Lemon SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW,
140b3e95d4eSJonathan Lemon     &ip_checkinterface, 0, "Verify packet arrives on correct interface");
141b3e95d4eSJonathan Lemon 
142df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1430312fbe9SPoul-Henning Kamp static int	ipprintfs = 0;
144df8bae1dSRodney W. Grimes #endif
145df8bae1dSRodney W. Grimes 
146ca925d9cSJonathan Lemon static int	ipqmaxlen = IFQ_MAXLEN;
147ca925d9cSJonathan Lemon 
148df8bae1dSRodney W. Grimes extern	struct domain inetdomain;
149f0ffb944SJulian Elischer extern	struct protosw inetsw[];
150df8bae1dSRodney W. Grimes u_char	ip_protox[IPPROTO_MAX];
15159562606SGarrett Wollman struct	in_ifaddrhead in_ifaddrhead; 		/* first inet address */
152ca925d9cSJonathan Lemon struct	in_ifaddrhashhead *in_ifaddrhashtbl;	/* inet addr hash table  */
153ca925d9cSJonathan Lemon u_long 	in_ifaddrhmask;				/* mask for hash table */
154ca925d9cSJonathan Lemon 
155afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW,
1563d177f46SBill Fumerola     &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue");
1570312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
1583d177f46SBill Fumerola     &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue");
159df8bae1dSRodney W. Grimes 
160f23b4c91SGarrett Wollman struct ipstat ipstat;
161c73d99b5SRuslan Ermilov SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RW,
1623d177f46SBill Fumerola     &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)");
163194a213eSAndrey A. Chernov 
164194a213eSAndrey A. Chernov /* Packet reassembly stuff */
165194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2      6
166194a213eSAndrey A. Chernov #define IPREASS_NHASH           (1 << IPREASS_NHASH_LOG2)
167194a213eSAndrey A. Chernov #define IPREASS_HMASK           (IPREASS_NHASH - 1)
168194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \
169831a80b0SMatthew Dillon 	(((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
170194a213eSAndrey A. Chernov 
171462b86feSPoul-Henning Kamp static TAILQ_HEAD(ipqhead, ipq) ipq[IPREASS_NHASH];
172194a213eSAndrey A. Chernov static int    nipq = 0;         /* total # of reass queues */
173194a213eSAndrey A. Chernov static int    maxnipq;
174f23b4c91SGarrett Wollman 
1750312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU
1760312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
1773d177f46SBill Fumerola     &ip_mtu, 0, "Default MTU");
1780312fbe9SPoul-Henning Kamp #endif
1790312fbe9SPoul-Henning Kamp 
1801b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
1811b968362SDag-Erling Smørgrav static int	ipstealth = 0;
1821b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW,
1831b968362SDag-Erling Smørgrav     &ipstealth, 0, "");
1841b968362SDag-Erling Smørgrav #endif
1851b968362SDag-Erling Smørgrav 
186cfe8b629SGarrett Wollman 
18723bf9953SPoul-Henning Kamp /* Firewall hooks */
18823bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr;
1899fcc0795SLuigi Rizzo int fw_enable = 1 ;
190e7319babSPoul-Henning Kamp 
191db69a05dSPaul Saab /* Dummynet hooks */
192db69a05dSPaul Saab ip_dn_io_t *ip_dn_io_ptr;
193b715f178SLuigi Rizzo 
194afed1b49SDarren Reed 
195e7319babSPoul-Henning Kamp /*
196df8bae1dSRodney W. Grimes  * We need to save the IP options in case a protocol wants to respond
197df8bae1dSRodney W. Grimes  * to an incoming packet over the same route if the packet got here
198df8bae1dSRodney W. Grimes  * using IP source routing.  This allows connection establishment and
199df8bae1dSRodney W. Grimes  * maintenance when the remote end is on a network that is not known
200df8bae1dSRodney W. Grimes  * to us.
201df8bae1dSRodney W. Grimes  */
2020312fbe9SPoul-Henning Kamp static int	ip_nhops = 0;
203df8bae1dSRodney W. Grimes static	struct ip_srcrt {
204df8bae1dSRodney W. Grimes 	struct	in_addr dst;			/* final destination */
205df8bae1dSRodney W. Grimes 	char	nop;				/* one NOP to align */
206df8bae1dSRodney W. Grimes 	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
207df8bae1dSRodney W. Grimes 	struct	in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
208df8bae1dSRodney W. Grimes } ip_srcrt;
209df8bae1dSRodney W. Grimes 
210f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr;
211f9e354dfSJulian Elischer 
2124d77a549SAlfred Perlstein static void	save_rte(u_char *, struct in_addr);
2134d77a549SAlfred Perlstein static int	ip_dooptions(struct mbuf *, int);
2144d77a549SAlfred Perlstein static void	ip_forward(struct mbuf *, int);
2154d77a549SAlfred Perlstein static void	ip_freef(struct ipqhead *, struct ipq *);
2168948e4baSArchie Cobbs #ifdef IPDIVERT
2174d77a549SAlfred Perlstein static struct	mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *, u_int32_t *, u_int16_t *);
2188948e4baSArchie Cobbs #else
2194d77a549SAlfred Perlstein static struct	mbuf *ip_reass(struct mbuf *, struct ipqhead *, struct ipq *);
2208948e4baSArchie Cobbs #endif
2214d77a549SAlfred Perlstein static void	ipintr(void);
2228948e4baSArchie Cobbs 
223df8bae1dSRodney W. Grimes /*
224df8bae1dSRodney W. Grimes  * IP initialization: fill in IP protocol switch table.
225df8bae1dSRodney W. Grimes  * All protocols not implemented in kernel go to raw IP protocol handler.
226df8bae1dSRodney W. Grimes  */
227df8bae1dSRodney W. Grimes void
228df8bae1dSRodney W. Grimes ip_init()
229df8bae1dSRodney W. Grimes {
230f0ffb944SJulian Elischer 	register struct protosw *pr;
231df8bae1dSRodney W. Grimes 	register int i;
232df8bae1dSRodney W. Grimes 
23359562606SGarrett Wollman 	TAILQ_INIT(&in_ifaddrhead);
234ca925d9cSJonathan Lemon 	in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask);
235f0ffb944SJulian Elischer 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
236df8bae1dSRodney W. Grimes 	if (pr == 0)
237df8bae1dSRodney W. Grimes 		panic("ip_init");
238df8bae1dSRodney W. Grimes 	for (i = 0; i < IPPROTO_MAX; i++)
239df8bae1dSRodney W. Grimes 		ip_protox[i] = pr - inetsw;
240f0ffb944SJulian Elischer 	for (pr = inetdomain.dom_protosw;
241f0ffb944SJulian Elischer 	    pr < inetdomain.dom_protoswNPROTOSW; pr++)
242df8bae1dSRodney W. Grimes 		if (pr->pr_domain->dom_family == PF_INET &&
243df8bae1dSRodney W. Grimes 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
244df8bae1dSRodney W. Grimes 			ip_protox[pr->pr_protocol] = pr - inetsw;
245194a213eSAndrey A. Chernov 
246194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++)
247462b86feSPoul-Henning Kamp 	    TAILQ_INIT(&ipq[i]);
248194a213eSAndrey A. Chernov 
249194a213eSAndrey A. Chernov 	maxnipq = nmbclusters / 4;
25096c2b042SJesper Skriver 	ip_maxfragpackets = nmbclusters / 4;
251194a213eSAndrey A. Chernov 
25264dddc18SKris Kennaway #ifndef RANDOM_IP_ID
253227ee8a1SPoul-Henning Kamp 	ip_id = time_second & 0xffff;
25464dddc18SKris Kennaway #endif
255df8bae1dSRodney W. Grimes 	ipintrq.ifq_maxlen = ipqmaxlen;
2566008862bSJohn Baldwin 	mtx_init(&ipintrq.ifq_mtx, "ip_inq", NULL, MTX_DEF);
257bedbd47eSMike Smith 	ipintrq_present = 1;
258242c5536SPeter Wemm 
259242c5536SPeter Wemm 	register_netisr(NETISR_IP, ipintr);
260df8bae1dSRodney W. Grimes }
261df8bae1dSRodney W. Grimes 
2620312fbe9SPoul-Henning Kamp static struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
2631e3d5af0SRuslan Ermilov struct	route ipforward_rt;
264df8bae1dSRodney W. Grimes 
265df8bae1dSRodney W. Grimes /*
266df8bae1dSRodney W. Grimes  * Ip input routine.  Checksum and byte swap header.  If fragmented
267df8bae1dSRodney W. Grimes  * try to reassemble.  Process options.  Pass to next level.
268df8bae1dSRodney W. Grimes  */
269c67b1d17SGarrett Wollman void
270c67b1d17SGarrett Wollman ip_input(struct mbuf *m)
271df8bae1dSRodney W. Grimes {
27223bf9953SPoul-Henning Kamp 	struct ip *ip;
27323bf9953SPoul-Henning Kamp 	struct ipq *fp;
2745da9f8faSJosef Karthauser 	struct in_ifaddr *ia = NULL;
275ca925d9cSJonathan Lemon 	struct ifaddr *ifa;
276823db0e9SDon Lewis 	int    i, hlen, checkif;
27747c861ecSBrian Somers 	u_short sum;
2788948e4baSArchie Cobbs 	u_int16_t divert_cookie;		/* firewall cookie */
2797538a9a0SJonathan Lemon 	struct in_addr pkt_dst;
2808948e4baSArchie Cobbs #ifdef IPDIVERT
2818948e4baSArchie Cobbs 	u_int32_t divert_info = 0;		/* packet divert/tee info */
282b715f178SLuigi Rizzo #endif
283830cc178SLuigi Rizzo 	struct ip_fw *rule = NULL;
284c4ac87eaSDarren Reed #ifdef PFIL_HOOKS
285c4ac87eaSDarren Reed 	struct packet_filter_hook *pfh;
286c4ac87eaSDarren Reed 	struct mbuf *m0;
287c4ac87eaSDarren Reed 	int rv;
288c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */
289b715f178SLuigi Rizzo 
2908948e4baSArchie Cobbs #ifdef IPDIVERT
2918948e4baSArchie Cobbs 	/* Get and reset firewall cookie */
2928948e4baSArchie Cobbs 	divert_cookie = ip_divert_cookie;
2938948e4baSArchie Cobbs 	ip_divert_cookie = 0;
2948948e4baSArchie Cobbs #else
2958948e4baSArchie Cobbs 	divert_cookie = 0;
2968948e4baSArchie Cobbs #endif
2978948e4baSArchie Cobbs 
298b715f178SLuigi Rizzo         /*
299b715f178SLuigi Rizzo          * dummynet packet are prepended a vestigial mbuf with
300b715f178SLuigi Rizzo          * m_type = MT_DUMMYNET and m_data pointing to the matching
301b715f178SLuigi Rizzo          * rule.
302b715f178SLuigi Rizzo          */
303b715f178SLuigi Rizzo         if (m->m_type == MT_DUMMYNET) {
304830cc178SLuigi Rizzo             rule = (struct ip_fw *)(m->m_data) ;
305b715f178SLuigi Rizzo             m = m->m_next ;
306b715f178SLuigi Rizzo             ip = mtod(m, struct ip *);
307b715f178SLuigi Rizzo             hlen = IP_VHL_HL(ip->ip_vhl) << 2;
308b715f178SLuigi Rizzo             goto iphack ;
309b715f178SLuigi Rizzo         } else
310b715f178SLuigi Rizzo             rule = NULL ;
311df8bae1dSRodney W. Grimes 
312db40007dSAndrew R. Reiter 	KASSERT(m != NULL && (m->m_flags & M_PKTHDR) != 0,
313db40007dSAndrew R. Reiter 	    ("ip_input: no HDR"));
314db40007dSAndrew R. Reiter 
315df8bae1dSRodney W. Grimes 	ipstat.ips_total++;
31658938916SGarrett Wollman 
31758938916SGarrett Wollman 	if (m->m_pkthdr.len < sizeof(struct ip))
31858938916SGarrett Wollman 		goto tooshort;
31958938916SGarrett Wollman 
320df8bae1dSRodney W. Grimes 	if (m->m_len < sizeof (struct ip) &&
321df8bae1dSRodney W. Grimes 	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
322df8bae1dSRodney W. Grimes 		ipstat.ips_toosmall++;
323c67b1d17SGarrett Wollman 		return;
324df8bae1dSRodney W. Grimes 	}
325df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
32658938916SGarrett Wollman 
32758938916SGarrett Wollman 	if (IP_VHL_V(ip->ip_vhl) != IPVERSION) {
328df8bae1dSRodney W. Grimes 		ipstat.ips_badvers++;
329df8bae1dSRodney W. Grimes 		goto bad;
330df8bae1dSRodney W. Grimes 	}
33158938916SGarrett Wollman 
33258938916SGarrett Wollman 	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
333df8bae1dSRodney W. Grimes 	if (hlen < sizeof(struct ip)) {	/* minimum header length */
334df8bae1dSRodney W. Grimes 		ipstat.ips_badhlen++;
335df8bae1dSRodney W. Grimes 		goto bad;
336df8bae1dSRodney W. Grimes 	}
337df8bae1dSRodney W. Grimes 	if (hlen > m->m_len) {
338df8bae1dSRodney W. Grimes 		if ((m = m_pullup(m, hlen)) == 0) {
339df8bae1dSRodney W. Grimes 			ipstat.ips_badhlen++;
340c67b1d17SGarrett Wollman 			return;
341df8bae1dSRodney W. Grimes 		}
342df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
343df8bae1dSRodney W. Grimes 	}
34433841545SHajimu UMEMOTO 
34533841545SHajimu UMEMOTO 	/* 127/8 must not appear on wire - RFC1122 */
34633841545SHajimu UMEMOTO 	if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
34733841545SHajimu UMEMOTO 	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
34833841545SHajimu UMEMOTO 		if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
34933841545SHajimu UMEMOTO 			ipstat.ips_badaddr++;
35033841545SHajimu UMEMOTO 			goto bad;
35133841545SHajimu UMEMOTO 		}
35233841545SHajimu UMEMOTO 	}
35333841545SHajimu UMEMOTO 
354db4f9cc7SJonathan Lemon 	if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
355db4f9cc7SJonathan Lemon 		sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
356db4f9cc7SJonathan Lemon 	} else {
35758938916SGarrett Wollman 		if (hlen == sizeof(struct ip)) {
35847c861ecSBrian Somers 			sum = in_cksum_hdr(ip);
35958938916SGarrett Wollman 		} else {
36047c861ecSBrian Somers 			sum = in_cksum(m, hlen);
36158938916SGarrett Wollman 		}
362db4f9cc7SJonathan Lemon 	}
36347c861ecSBrian Somers 	if (sum) {
364df8bae1dSRodney W. Grimes 		ipstat.ips_badsum++;
365df8bae1dSRodney W. Grimes 		goto bad;
366df8bae1dSRodney W. Grimes 	}
367df8bae1dSRodney W. Grimes 
368df8bae1dSRodney W. Grimes 	/*
369df8bae1dSRodney W. Grimes 	 * Convert fields to host representation.
370df8bae1dSRodney W. Grimes 	 */
371fd8e4ebcSMike Barcroft 	ip->ip_len = ntohs(ip->ip_len);
372df8bae1dSRodney W. Grimes 	if (ip->ip_len < hlen) {
373df8bae1dSRodney W. Grimes 		ipstat.ips_badlen++;
374df8bae1dSRodney W. Grimes 		goto bad;
375df8bae1dSRodney W. Grimes 	}
376fd8e4ebcSMike Barcroft 	ip->ip_off = ntohs(ip->ip_off);
377df8bae1dSRodney W. Grimes 
378df8bae1dSRodney W. Grimes 	/*
379df8bae1dSRodney W. Grimes 	 * Check that the amount of data in the buffers
380df8bae1dSRodney W. Grimes 	 * is as at least much as the IP header would have us expect.
381df8bae1dSRodney W. Grimes 	 * Trim mbufs if longer than we expect.
382df8bae1dSRodney W. Grimes 	 * Drop packet if shorter than we expect.
383df8bae1dSRodney W. Grimes 	 */
384df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len < ip->ip_len) {
38558938916SGarrett Wollman tooshort:
386df8bae1dSRodney W. Grimes 		ipstat.ips_tooshort++;
387df8bae1dSRodney W. Grimes 		goto bad;
388df8bae1dSRodney W. Grimes 	}
389df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len > ip->ip_len) {
390df8bae1dSRodney W. Grimes 		if (m->m_len == m->m_pkthdr.len) {
391df8bae1dSRodney W. Grimes 			m->m_len = ip->ip_len;
392df8bae1dSRodney W. Grimes 			m->m_pkthdr.len = ip->ip_len;
393df8bae1dSRodney W. Grimes 		} else
394df8bae1dSRodney W. Grimes 			m_adj(m, ip->ip_len - m->m_pkthdr.len);
395df8bae1dSRodney W. Grimes 	}
3963f67c834SDon Lewis 
39733841545SHajimu UMEMOTO #ifdef IPSEC
39833841545SHajimu UMEMOTO 	if (ipsec_gethist(m, NULL))
39933841545SHajimu UMEMOTO 		goto pass;
40033841545SHajimu UMEMOTO #endif
4013f67c834SDon Lewis 
4024dd1662bSUgen J.S. Antsilevich 	/*
4034dd1662bSUgen J.S. Antsilevich 	 * IpHack's section.
4044dd1662bSUgen J.S. Antsilevich 	 * Right now when no processing on packet has done
4054dd1662bSUgen J.S. Antsilevich 	 * and it is still fresh out of network we do our black
4064dd1662bSUgen J.S. Antsilevich 	 * deals with it.
40793e0e116SJulian Elischer 	 * - Firewall: deny/allow/divert
408fed1c7e9SSøren Schmidt 	 * - Xlate: translate packet's addr/port (NAT).
409b715f178SLuigi Rizzo 	 * - Pipe: pass pkt through dummynet.
4104dd1662bSUgen J.S. Antsilevich 	 * - Wrap: fake packet's addr/port <unimpl.>
4114dd1662bSUgen J.S. Antsilevich 	 * - Encapsulate: put it in another IP and send out. <unimp.>
4124dd1662bSUgen J.S. Antsilevich  	 */
413b715f178SLuigi Rizzo 
414b715f178SLuigi Rizzo iphack:
415df8bae1dSRodney W. Grimes 
416c4ac87eaSDarren Reed #ifdef PFIL_HOOKS
417c4ac87eaSDarren Reed 	/*
418c4ac87eaSDarren Reed 	 * Run through list of hooks for input packets.  If there are any
419c4ac87eaSDarren Reed 	 * filters which require that additional packets in the flow are
420c4ac87eaSDarren Reed 	 * not fast-forwarded, they must clear the M_CANFASTFWD flag.
421c4ac87eaSDarren Reed 	 * Note that filters must _never_ set this flag, as another filter
422c4ac87eaSDarren Reed 	 * in the list may have previously cleared it.
423c4ac87eaSDarren Reed 	 */
424c4ac87eaSDarren Reed 	m0 = m;
425c4ac87eaSDarren Reed 	pfh = pfil_hook_get(PFIL_IN, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
426fc2ffbe6SPoul-Henning Kamp 	for (; pfh; pfh = TAILQ_NEXT(pfh, pfil_link))
427c4ac87eaSDarren Reed 		if (pfh->pfil_func) {
428c4ac87eaSDarren Reed 			rv = pfh->pfil_func(ip, hlen,
429c4ac87eaSDarren Reed 					    m->m_pkthdr.rcvif, 0, &m0);
430c4ac87eaSDarren Reed 			if (rv)
431beec8214SDarren Reed 				return;
432c4ac87eaSDarren Reed 			m = m0;
433c4ac87eaSDarren Reed 			if (m == NULL)
434c4ac87eaSDarren Reed 				return;
435c4ac87eaSDarren Reed 			ip = mtod(m, struct ip *);
436beec8214SDarren Reed 		}
437c4ac87eaSDarren Reed #endif /* PFIL_HOOKS */
438c4ac87eaSDarren Reed 
4397b109fa4SLuigi Rizzo 	if (fw_enable && IPFW_LOADED) {
440f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD
441f9e354dfSJulian Elischer 		/*
442f9e354dfSJulian Elischer 		 * If we've been forwarded from the output side, then
443f9e354dfSJulian Elischer 		 * skip the firewall a second time
444f9e354dfSJulian Elischer 		 */
445f9e354dfSJulian Elischer 		if (ip_fw_fwd_addr)
446f9e354dfSJulian Elischer 			goto ours;
447f9e354dfSJulian Elischer #endif	/* IPFIREWALL_FORWARD */
448f9e354dfSJulian Elischer 		/*
4498948e4baSArchie Cobbs 		 * See the comment in ip_output for the return values
450b715f178SLuigi Rizzo 		 * produced by the firewall.
451f9e354dfSJulian Elischer 		 */
452d60315beSLuigi Rizzo 		i = ip_fw_chk_ptr(&m, NULL /* oif */, &divert_cookie,
453d60315beSLuigi Rizzo 			&rule, &ip_fw_fwd_addr);
454d60315beSLuigi Rizzo 		if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
455507b4b54SLuigi Rizzo 			if (m)
456507b4b54SLuigi Rizzo 				m_freem(m);
457b715f178SLuigi Rizzo 			return;
458507b4b54SLuigi Rizzo 		}
459d60315beSLuigi Rizzo 		ip = mtod(m, struct ip *); /* just in case m changed */
460b715f178SLuigi Rizzo 		if (i == 0 && ip_fw_fwd_addr == NULL)	/* common case */
461b715f178SLuigi Rizzo 			goto pass;
4627b109fa4SLuigi Rizzo                 if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {
4638948e4baSArchie Cobbs                         /* Send packet to the appropriate pipe */
464db69a05dSPaul Saab                         ip_dn_io_ptr(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule,
4656a800098SYoshinobu Inoue 				    0);
466e4676ba6SJulian Elischer 			return;
46793e0e116SJulian Elischer 		}
468b715f178SLuigi Rizzo #ifdef IPDIVERT
4698948e4baSArchie Cobbs 		if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
4708948e4baSArchie Cobbs 			/* Divert or tee packet */
4718948e4baSArchie Cobbs 			divert_info = i;
472b715f178SLuigi Rizzo 			goto ours;
473b715f178SLuigi Rizzo 		}
474b715f178SLuigi Rizzo #endif
475b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD
476b715f178SLuigi Rizzo 		if (i == 0 && ip_fw_fwd_addr != NULL)
477b715f178SLuigi Rizzo 			goto pass;
478b715f178SLuigi Rizzo #endif
479b715f178SLuigi Rizzo 		/*
480b715f178SLuigi Rizzo 		 * if we get here, the packet must be dropped
481b715f178SLuigi Rizzo 		 */
482b715f178SLuigi Rizzo 		m_freem(m);
483b715f178SLuigi Rizzo 		return;
484b715f178SLuigi Rizzo 	}
485b715f178SLuigi Rizzo pass:
486100ba1a6SJordan K. Hubbard 
487df8bae1dSRodney W. Grimes 	/*
488df8bae1dSRodney W. Grimes 	 * Process options and, if not destined for us,
489df8bae1dSRodney W. Grimes 	 * ship it on.  ip_dooptions returns 1 when an
490df8bae1dSRodney W. Grimes 	 * error was detected (causing an icmp message
491df8bae1dSRodney W. Grimes 	 * to be sent and the original packet to be freed).
492df8bae1dSRodney W. Grimes 	 */
493df8bae1dSRodney W. Grimes 	ip_nhops = 0;		/* for source routed packets */
494d0ebc0d2SYaroslav Tykhiy 	if (hlen > sizeof (struct ip) && ip_dooptions(m, 0)) {
495ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD
496ed1ff184SJulian Elischer 		ip_fw_fwd_addr = NULL;
497ed1ff184SJulian Elischer #endif
498c67b1d17SGarrett Wollman 		return;
499ed1ff184SJulian Elischer 	}
500df8bae1dSRodney W. Grimes 
501f0068c4aSGarrett Wollman         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
502f0068c4aSGarrett Wollman          * matter if it is destined to another node, or whether it is
503f0068c4aSGarrett Wollman          * a multicast one, RSVP wants it! and prevents it from being forwarded
504f0068c4aSGarrett Wollman          * anywhere else. Also checks if the rsvp daemon is running before
505f0068c4aSGarrett Wollman 	 * grabbing the packet.
506f0068c4aSGarrett Wollman          */
5071c5de19aSGarrett Wollman 	if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
508f0068c4aSGarrett Wollman 		goto ours;
509f0068c4aSGarrett Wollman 
510df8bae1dSRodney W. Grimes 	/*
511df8bae1dSRodney W. Grimes 	 * Check our list of addresses, to see if the packet is for us.
512cc766e04SGarrett Wollman 	 * If we don't have any addresses, assume any unicast packet
513cc766e04SGarrett Wollman 	 * we receive might be for us (and let the upper layers deal
514cc766e04SGarrett Wollman 	 * with it).
515df8bae1dSRodney W. Grimes 	 */
516cc766e04SGarrett Wollman 	if (TAILQ_EMPTY(&in_ifaddrhead) &&
517cc766e04SGarrett Wollman 	    (m->m_flags & (M_MCAST|M_BCAST)) == 0)
518cc766e04SGarrett Wollman 		goto ours;
519cc766e04SGarrett Wollman 
5207538a9a0SJonathan Lemon 	/*
5217538a9a0SJonathan Lemon 	 * Cache the destination address of the packet; this may be
5227538a9a0SJonathan Lemon 	 * changed by use of 'ipfw fwd'.
5237538a9a0SJonathan Lemon 	 */
5247538a9a0SJonathan Lemon 	pkt_dst = ip_fw_fwd_addr == NULL ?
5257538a9a0SJonathan Lemon 	    ip->ip_dst : ip_fw_fwd_addr->sin_addr;
5267538a9a0SJonathan Lemon 
527823db0e9SDon Lewis 	/*
528823db0e9SDon Lewis 	 * Enable a consistency check between the destination address
529823db0e9SDon Lewis 	 * and the arrival interface for a unicast packet (the RFC 1122
530823db0e9SDon Lewis 	 * strong ES model) if IP forwarding is disabled and the packet
531e15ae1b2SDon Lewis 	 * is not locally generated and the packet is not subject to
532e15ae1b2SDon Lewis 	 * 'ipfw fwd'.
5333f67c834SDon Lewis 	 *
5343f67c834SDon Lewis 	 * XXX - Checking also should be disabled if the destination
5353f67c834SDon Lewis 	 * address is ipnat'ed to a different interface.
5363f67c834SDon Lewis 	 *
537a8f12100SDon Lewis 	 * XXX - Checking is incompatible with IP aliases added
5383f67c834SDon Lewis 	 * to the loopback interface instead of the interface where
5393f67c834SDon Lewis 	 * the packets are received.
540823db0e9SDon Lewis 	 */
541823db0e9SDon Lewis 	checkif = ip_checkinterface && (ipforwarding == 0) &&
5429494d596SBrooks Davis 	    m->m_pkthdr.rcvif != NULL &&
543e15ae1b2SDon Lewis 	    ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
544e15ae1b2SDon Lewis 	    (ip_fw_fwd_addr == NULL);
545823db0e9SDon Lewis 
546ca925d9cSJonathan Lemon 	/*
547ca925d9cSJonathan Lemon 	 * Check for exact addresses in the hash bucket.
548ca925d9cSJonathan Lemon 	 */
549ca925d9cSJonathan Lemon 	LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
550f9e354dfSJulian Elischer 		/*
551823db0e9SDon Lewis 		 * If the address matches, verify that the packet
552823db0e9SDon Lewis 		 * arrived via the correct interface if checking is
553823db0e9SDon Lewis 		 * enabled.
554f9e354dfSJulian Elischer 		 */
555823db0e9SDon Lewis 		if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr &&
556823db0e9SDon Lewis 		    (!checkif || ia->ia_ifp == m->m_pkthdr.rcvif))
557ed1ff184SJulian Elischer 			goto ours;
558ca925d9cSJonathan Lemon 	}
559823db0e9SDon Lewis 	/*
560ca925d9cSJonathan Lemon 	 * Check for broadcast addresses.
561ca925d9cSJonathan Lemon 	 *
562ca925d9cSJonathan Lemon 	 * Only accept broadcast packets that arrive via the matching
563ca925d9cSJonathan Lemon 	 * interface.  Reception of forwarded directed broadcasts would
564ca925d9cSJonathan Lemon 	 * be handled via ip_forward() and ether_output() with the loopback
565ca925d9cSJonathan Lemon 	 * into the stack for SIMPLEX interfaces handled by ether_output().
566823db0e9SDon Lewis 	 */
567ca925d9cSJonathan Lemon 	if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
568ca925d9cSJonathan Lemon 	        TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
569ca925d9cSJonathan Lemon 			if (ifa->ifa_addr->sa_family != AF_INET)
570ca925d9cSJonathan Lemon 				continue;
571ca925d9cSJonathan Lemon 			ia = ifatoia(ifa);
572df8bae1dSRodney W. Grimes 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
5737538a9a0SJonathan Lemon 			    pkt_dst.s_addr)
574df8bae1dSRodney W. Grimes 				goto ours;
5757538a9a0SJonathan Lemon 			if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr)
576df8bae1dSRodney W. Grimes 				goto ours;
577ca925d9cSJonathan Lemon #ifdef BOOTP_COMPAT
578ca925d9cSJonathan Lemon 			if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
579ca925d9cSJonathan Lemon 				goto ours;
580ca925d9cSJonathan Lemon #endif
581df8bae1dSRodney W. Grimes 		}
582df8bae1dSRodney W. Grimes 	}
583df8bae1dSRodney W. Grimes 	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
584df8bae1dSRodney W. Grimes 		struct in_multi *inm;
585df8bae1dSRodney W. Grimes 		if (ip_mrouter) {
586df8bae1dSRodney W. Grimes 			/*
587df8bae1dSRodney W. Grimes 			 * If we are acting as a multicast router, all
588df8bae1dSRodney W. Grimes 			 * incoming multicast packets are passed to the
589df8bae1dSRodney W. Grimes 			 * kernel-level multicast forwarding function.
590df8bae1dSRodney W. Grimes 			 * The packet is returned (relatively) intact; if
591df8bae1dSRodney W. Grimes 			 * ip_mforward() returns a non-zero value, the packet
592df8bae1dSRodney W. Grimes 			 * must be discarded, else it may be accepted below.
593df8bae1dSRodney W. Grimes 			 */
594f0068c4aSGarrett Wollman 			if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) {
595df8bae1dSRodney W. Grimes 				ipstat.ips_cantforward++;
596df8bae1dSRodney W. Grimes 				m_freem(m);
597c67b1d17SGarrett Wollman 				return;
598df8bae1dSRodney W. Grimes 			}
599df8bae1dSRodney W. Grimes 
600df8bae1dSRodney W. Grimes 			/*
60111612afaSDima Dorfman 			 * The process-level routing daemon needs to receive
602df8bae1dSRodney W. Grimes 			 * all multicast IGMP packets, whether or not this
603df8bae1dSRodney W. Grimes 			 * host belongs to their destination groups.
604df8bae1dSRodney W. Grimes 			 */
605df8bae1dSRodney W. Grimes 			if (ip->ip_p == IPPROTO_IGMP)
606df8bae1dSRodney W. Grimes 				goto ours;
607df8bae1dSRodney W. Grimes 			ipstat.ips_forward++;
608df8bae1dSRodney W. Grimes 		}
609df8bae1dSRodney W. Grimes 		/*
610df8bae1dSRodney W. Grimes 		 * See if we belong to the destination multicast group on the
611df8bae1dSRodney W. Grimes 		 * arrival interface.
612df8bae1dSRodney W. Grimes 		 */
613df8bae1dSRodney W. Grimes 		IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
614df8bae1dSRodney W. Grimes 		if (inm == NULL) {
61582c39223SGarrett Wollman 			ipstat.ips_notmember++;
616df8bae1dSRodney W. Grimes 			m_freem(m);
617c67b1d17SGarrett Wollman 			return;
618df8bae1dSRodney W. Grimes 		}
619df8bae1dSRodney W. Grimes 		goto ours;
620df8bae1dSRodney W. Grimes 	}
621df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
622df8bae1dSRodney W. Grimes 		goto ours;
623df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == INADDR_ANY)
624df8bae1dSRodney W. Grimes 		goto ours;
625df8bae1dSRodney W. Grimes 
6266a800098SYoshinobu Inoue 	/*
6276a800098SYoshinobu Inoue 	 * FAITH(Firewall Aided Internet Translator)
6286a800098SYoshinobu Inoue 	 */
6296a800098SYoshinobu Inoue 	if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
6306a800098SYoshinobu Inoue 		if (ip_keepfaith) {
6316a800098SYoshinobu Inoue 			if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP)
6326a800098SYoshinobu Inoue 				goto ours;
6336a800098SYoshinobu Inoue 		}
6346a800098SYoshinobu Inoue 		m_freem(m);
6356a800098SYoshinobu Inoue 		return;
6366a800098SYoshinobu Inoue 	}
6379494d596SBrooks Davis 
638df8bae1dSRodney W. Grimes 	/*
639df8bae1dSRodney W. Grimes 	 * Not for us; forward if possible and desirable.
640df8bae1dSRodney W. Grimes 	 */
641df8bae1dSRodney W. Grimes 	if (ipforwarding == 0) {
642df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
643df8bae1dSRodney W. Grimes 		m_freem(m);
644546f251bSChris D. Faulhaber 	} else {
645546f251bSChris D. Faulhaber #ifdef IPSEC
646546f251bSChris D. Faulhaber 		/*
647546f251bSChris D. Faulhaber 		 * Enforce inbound IPsec SPD.
648546f251bSChris D. Faulhaber 		 */
649546f251bSChris D. Faulhaber 		if (ipsec4_in_reject(m, NULL)) {
650546f251bSChris D. Faulhaber 			ipsecstat.in_polvio++;
651546f251bSChris D. Faulhaber 			goto bad;
652546f251bSChris D. Faulhaber 		}
653546f251bSChris D. Faulhaber #endif /* IPSEC */
654df8bae1dSRodney W. Grimes 		ip_forward(m, 0);
655546f251bSChris D. Faulhaber 	}
656ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD
657ed1ff184SJulian Elischer 	ip_fw_fwd_addr = NULL;
658ed1ff184SJulian Elischer #endif
659c67b1d17SGarrett Wollman 	return;
660df8bae1dSRodney W. Grimes 
661df8bae1dSRodney W. Grimes ours:
662d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
663d0ebc0d2SYaroslav Tykhiy 	/*
664d0ebc0d2SYaroslav Tykhiy 	 * IPSTEALTH: Process non-routing options only
665d0ebc0d2SYaroslav Tykhiy 	 * if the packet is destined for us.
666d0ebc0d2SYaroslav Tykhiy 	 */
667d0ebc0d2SYaroslav Tykhiy 	if (ipstealth && hlen > sizeof (struct ip) && ip_dooptions(m, 1)) {
668d0ebc0d2SYaroslav Tykhiy #ifdef IPFIREWALL_FORWARD
669d0ebc0d2SYaroslav Tykhiy 		ip_fw_fwd_addr = NULL;
670d0ebc0d2SYaroslav Tykhiy #endif
671d0ebc0d2SYaroslav Tykhiy 		return;
672d0ebc0d2SYaroslav Tykhiy 	}
673d0ebc0d2SYaroslav Tykhiy #endif /* IPSTEALTH */
674d0ebc0d2SYaroslav Tykhiy 
6755da9f8faSJosef Karthauser 	/* Count the packet in the ip address stats */
6765da9f8faSJosef Karthauser 	if (ia != NULL) {
6775da9f8faSJosef Karthauser 		ia->ia_ifa.if_ipackets++;
6785da9f8faSJosef Karthauser 		ia->ia_ifa.if_ibytes += m->m_pkthdr.len;
6795da9f8faSJosef Karthauser 	}
680100ba1a6SJordan K. Hubbard 
68163f8d699SJordan K. Hubbard 	/*
682df8bae1dSRodney W. Grimes 	 * If offset or IP_MF are set, must reassemble.
683df8bae1dSRodney W. Grimes 	 * Otherwise, nothing need be done.
684df8bae1dSRodney W. Grimes 	 * (We could look in the reassembly queue to see
685df8bae1dSRodney W. Grimes 	 * if the packet was previously fragmented,
686df8bae1dSRodney W. Grimes 	 * but it's not worth the time; just let them time out.)
687df8bae1dSRodney W. Grimes 	 */
688b6ea1aa5SRuslan Ermilov 	if (ip->ip_off & (IP_MF | IP_OFFMASK)) {
6896a800098SYoshinobu Inoue 
690194a213eSAndrey A. Chernov 		sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
691df8bae1dSRodney W. Grimes 		/*
692df8bae1dSRodney W. Grimes 		 * Look for queue of fragments
693df8bae1dSRodney W. Grimes 		 * of this datagram.
694df8bae1dSRodney W. Grimes 		 */
695462b86feSPoul-Henning Kamp 		TAILQ_FOREACH(fp, &ipq[sum], ipq_list)
696df8bae1dSRodney W. Grimes 			if (ip->ip_id == fp->ipq_id &&
697df8bae1dSRodney W. Grimes 			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
698df8bae1dSRodney W. Grimes 			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
699df8bae1dSRodney W. Grimes 			    ip->ip_p == fp->ipq_p)
700df8bae1dSRodney W. Grimes 				goto found;
701df8bae1dSRodney W. Grimes 
702194a213eSAndrey A. Chernov 		fp = 0;
703194a213eSAndrey A. Chernov 
704194a213eSAndrey A. Chernov 		/* check if there's a place for the new queue */
705194a213eSAndrey A. Chernov 		if (nipq > maxnipq) {
706194a213eSAndrey A. Chernov 		    /*
707194a213eSAndrey A. Chernov 		     * drop something from the tail of the current queue
708194a213eSAndrey A. Chernov 		     * before proceeding further
709194a213eSAndrey A. Chernov 		     */
710462b86feSPoul-Henning Kamp 		    struct ipq *q = TAILQ_LAST(&ipq[sum], ipqhead);
711462b86feSPoul-Henning Kamp 		    if (q == NULL) {   /* gak */
712194a213eSAndrey A. Chernov 			for (i = 0; i < IPREASS_NHASH; i++) {
713462b86feSPoul-Henning Kamp 			    struct ipq *r = TAILQ_LAST(&ipq[i], ipqhead);
714462b86feSPoul-Henning Kamp 			    if (r) {
715462b86feSPoul-Henning Kamp 				ip_freef(&ipq[i], r);
716194a213eSAndrey A. Chernov 				break;
717194a213eSAndrey A. Chernov 			    }
718194a213eSAndrey A. Chernov 			}
719194a213eSAndrey A. Chernov 		    } else
720462b86feSPoul-Henning Kamp 			ip_freef(&ipq[sum], q);
721194a213eSAndrey A. Chernov 		}
722194a213eSAndrey A. Chernov found:
723df8bae1dSRodney W. Grimes 		/*
724df8bae1dSRodney W. Grimes 		 * Adjust ip_len to not reflect header,
725df8bae1dSRodney W. Grimes 		 * convert offset of this to bytes.
726df8bae1dSRodney W. Grimes 		 */
727df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
728b6ea1aa5SRuslan Ermilov 		if (ip->ip_off & IP_MF) {
7296effc713SDoug Rabson 		        /*
7306effc713SDoug Rabson 		         * Make sure that fragments have a data length
7316effc713SDoug Rabson 			 * that's a non-zero multiple of 8 bytes.
7326effc713SDoug Rabson 		         */
7336effc713SDoug Rabson 			if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
7346effc713SDoug Rabson 				ipstat.ips_toosmall++; /* XXX */
7356effc713SDoug Rabson 				goto bad;
7366effc713SDoug Rabson 			}
7376effc713SDoug Rabson 			m->m_flags |= M_FRAG;
7386effc713SDoug Rabson 		}
739df8bae1dSRodney W. Grimes 		ip->ip_off <<= 3;
740df8bae1dSRodney W. Grimes 
741df8bae1dSRodney W. Grimes 		/*
742b6ea1aa5SRuslan Ermilov 		 * Attempt reassembly; if it succeeds, proceed.
743df8bae1dSRodney W. Grimes 		 */
744df8bae1dSRodney W. Grimes 		ipstat.ips_fragments++;
745487bdb38SRuslan Ermilov 		m->m_pkthdr.header = ip;
7468948e4baSArchie Cobbs #ifdef IPDIVERT
7476a800098SYoshinobu Inoue 		m = ip_reass(m,
748462b86feSPoul-Henning Kamp 		    &ipq[sum], fp, &divert_info, &divert_cookie);
7498948e4baSArchie Cobbs #else
750462b86feSPoul-Henning Kamp 		m = ip_reass(m, &ipq[sum], fp);
7518948e4baSArchie Cobbs #endif
7526a800098SYoshinobu Inoue 		if (m == 0) {
753f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD
754f9e354dfSJulian Elischer 			ip_fw_fwd_addr = NULL;
755f9e354dfSJulian Elischer #endif
756c67b1d17SGarrett Wollman 			return;
757f9e354dfSJulian Elischer 		}
758df8bae1dSRodney W. Grimes 		ipstat.ips_reassembled++;
7596a800098SYoshinobu Inoue 		ip = mtod(m, struct ip *);
7607e2df452SRuslan Ermilov 		/* Get the header length of the reassembled packet */
7617e2df452SRuslan Ermilov 		hlen = IP_VHL_HL(ip->ip_vhl) << 2;
762af782f1cSBrian Somers #ifdef IPDIVERT
7638948e4baSArchie Cobbs 		/* Restore original checksum before diverting packet */
7648948e4baSArchie Cobbs 		if (divert_info != 0) {
765af782f1cSBrian Somers 			ip->ip_len += hlen;
766fd8e4ebcSMike Barcroft 			ip->ip_len = htons(ip->ip_len);
767fd8e4ebcSMike Barcroft 			ip->ip_off = htons(ip->ip_off);
768af782f1cSBrian Somers 			ip->ip_sum = 0;
76960123168SRuslan Ermilov 			if (hlen == sizeof(struct ip))
770af782f1cSBrian Somers 				ip->ip_sum = in_cksum_hdr(ip);
77160123168SRuslan Ermilov 			else
77260123168SRuslan Ermilov 				ip->ip_sum = in_cksum(m, hlen);
773fd8e4ebcSMike Barcroft 			ip->ip_off = ntohs(ip->ip_off);
774fd8e4ebcSMike Barcroft 			ip->ip_len = ntohs(ip->ip_len);
775af782f1cSBrian Somers 			ip->ip_len -= hlen;
776af782f1cSBrian Somers 		}
777af782f1cSBrian Somers #endif
778df8bae1dSRodney W. Grimes 	} else
779df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
780df8bae1dSRodney W. Grimes 
78193e0e116SJulian Elischer #ifdef IPDIVERT
78293e0e116SJulian Elischer 	/*
7838948e4baSArchie Cobbs 	 * Divert or tee packet to the divert protocol if required.
7848948e4baSArchie Cobbs 	 *
7858948e4baSArchie Cobbs 	 * If divert_info is zero then cookie should be too, so we shouldn't
7868948e4baSArchie Cobbs 	 * need to clear them here.  Assume divert_packet() does so also.
78793e0e116SJulian Elischer 	 */
7888948e4baSArchie Cobbs 	if (divert_info != 0) {
7898948e4baSArchie Cobbs 		struct mbuf *clone = NULL;
7908948e4baSArchie Cobbs 
7918948e4baSArchie Cobbs 		/* Clone packet if we're doing a 'tee' */
7928948e4baSArchie Cobbs 		if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
7938948e4baSArchie Cobbs 			clone = m_dup(m, M_DONTWAIT);
7948948e4baSArchie Cobbs 
7958948e4baSArchie Cobbs 		/* Restore packet header fields to original values */
7968948e4baSArchie Cobbs 		ip->ip_len += hlen;
797fd8e4ebcSMike Barcroft 		ip->ip_len = htons(ip->ip_len);
798fd8e4ebcSMike Barcroft 		ip->ip_off = htons(ip->ip_off);
7998948e4baSArchie Cobbs 
8008948e4baSArchie Cobbs 		/* Deliver packet to divert input routine */
8018948e4baSArchie Cobbs 		ip_divert_cookie = divert_cookie;
8028948e4baSArchie Cobbs 		divert_packet(m, 1, divert_info & 0xffff);
803e4676ba6SJulian Elischer 		ipstat.ips_delivered++;
8048948e4baSArchie Cobbs 
8058948e4baSArchie Cobbs 		/* If 'tee', continue with original packet */
8068948e4baSArchie Cobbs 		if (clone == NULL)
80793e0e116SJulian Elischer 			return;
8088948e4baSArchie Cobbs 		m = clone;
8098948e4baSArchie Cobbs 		ip = mtod(m, struct ip *);
81056962689SCrist J. Clark 		ip->ip_len += hlen;
81156962689SCrist J. Clark 		divert_info = 0;
81256962689SCrist J. Clark 		goto pass;
81393e0e116SJulian Elischer 	}
81493e0e116SJulian Elischer #endif
81593e0e116SJulian Elischer 
81633841545SHajimu UMEMOTO #ifdef IPSEC
81733841545SHajimu UMEMOTO 	/*
81833841545SHajimu UMEMOTO 	 * enforce IPsec policy checking if we are seeing last header.
81933841545SHajimu UMEMOTO 	 * note that we do not visit this with protocols with pcb layer
82033841545SHajimu UMEMOTO 	 * code - like udp/tcp/raw ip.
82133841545SHajimu UMEMOTO 	 */
82233841545SHajimu UMEMOTO 	if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 &&
82333841545SHajimu UMEMOTO 	    ipsec4_in_reject(m, NULL)) {
82433841545SHajimu UMEMOTO 		ipsecstat.in_polvio++;
82533841545SHajimu UMEMOTO 		goto bad;
82633841545SHajimu UMEMOTO 	}
82733841545SHajimu UMEMOTO #endif
82833841545SHajimu UMEMOTO 
829df8bae1dSRodney W. Grimes 	/*
830df8bae1dSRodney W. Grimes 	 * Switch out to protocol's input routine.
831df8bae1dSRodney W. Grimes 	 */
832df8bae1dSRodney W. Grimes 	ipstat.ips_delivered++;
8336a800098SYoshinobu Inoue     {
834f0ffb944SJulian Elischer 	int off = hlen;
8356a800098SYoshinobu Inoue 
836f0ffb944SJulian Elischer 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off);
837f9e354dfSJulian Elischer #ifdef	IPFIREWALL_FORWARD
838f9e354dfSJulian Elischer 	ip_fw_fwd_addr = NULL;	/* tcp needed it */
839f9e354dfSJulian Elischer #endif
840c67b1d17SGarrett Wollman 	return;
8416a800098SYoshinobu Inoue     }
842df8bae1dSRodney W. Grimes bad:
843f9e354dfSJulian Elischer #ifdef	IPFIREWALL_FORWARD
844f9e354dfSJulian Elischer 	ip_fw_fwd_addr = NULL;
845f9e354dfSJulian Elischer #endif
846df8bae1dSRodney W. Grimes 	m_freem(m);
847c67b1d17SGarrett Wollman }
848c67b1d17SGarrett Wollman 
849c67b1d17SGarrett Wollman /*
850c67b1d17SGarrett Wollman  * IP software interrupt routine - to go away sometime soon
851c67b1d17SGarrett Wollman  */
852c67b1d17SGarrett Wollman static void
853c67b1d17SGarrett Wollman ipintr(void)
854c67b1d17SGarrett Wollman {
855c67b1d17SGarrett Wollman 	struct mbuf *m;
856c67b1d17SGarrett Wollman 
857c67b1d17SGarrett Wollman 	while (1) {
858c67b1d17SGarrett Wollman 		IF_DEQUEUE(&ipintrq, m);
859c67b1d17SGarrett Wollman 		if (m == 0)
860c67b1d17SGarrett Wollman 			return;
861c67b1d17SGarrett Wollman 		ip_input(m);
862c67b1d17SGarrett Wollman 	}
863df8bae1dSRodney W. Grimes }
864df8bae1dSRodney W. Grimes 
865df8bae1dSRodney W. Grimes /*
8668948e4baSArchie Cobbs  * Take incoming datagram fragment and try to reassemble it into
8678948e4baSArchie Cobbs  * whole datagram.  If a chain for reassembly of this datagram already
8688948e4baSArchie Cobbs  * exists, then it is given as fp; otherwise have to make a chain.
8698948e4baSArchie Cobbs  *
8708948e4baSArchie Cobbs  * When IPDIVERT enabled, keep additional state with each packet that
8718948e4baSArchie Cobbs  * tells us if we need to divert or tee the packet we're building.
872df8bae1dSRodney W. Grimes  */
8738948e4baSArchie Cobbs 
8746a800098SYoshinobu Inoue static struct mbuf *
8758948e4baSArchie Cobbs #ifdef IPDIVERT
876462b86feSPoul-Henning Kamp ip_reass(m, head, fp, divinfo, divcookie)
8778948e4baSArchie Cobbs #else
878462b86feSPoul-Henning Kamp ip_reass(m, head, fp)
8798948e4baSArchie Cobbs #endif
880462b86feSPoul-Henning Kamp 	struct mbuf *m;
881462b86feSPoul-Henning Kamp 	struct ipqhead *head;
882462b86feSPoul-Henning Kamp 	struct ipq *fp;
8838948e4baSArchie Cobbs #ifdef IPDIVERT
8848948e4baSArchie Cobbs 	u_int32_t *divinfo;
8858948e4baSArchie Cobbs 	u_int16_t *divcookie;
8868948e4baSArchie Cobbs #endif
887df8bae1dSRodney W. Grimes {
8886effc713SDoug Rabson 	struct ip *ip = mtod(m, struct ip *);
889b6ea1aa5SRuslan Ermilov 	register struct mbuf *p, *q, *nq;
890df8bae1dSRodney W. Grimes 	struct mbuf *t;
8916effc713SDoug Rabson 	int hlen = IP_VHL_HL(ip->ip_vhl) << 2;
892df8bae1dSRodney W. Grimes 	int i, next;
893df8bae1dSRodney W. Grimes 
894df8bae1dSRodney W. Grimes 	/*
895df8bae1dSRodney W. Grimes 	 * Presence of header sizes in mbufs
896df8bae1dSRodney W. Grimes 	 * would confuse code below.
897df8bae1dSRodney W. Grimes 	 */
898df8bae1dSRodney W. Grimes 	m->m_data += hlen;
899df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
900df8bae1dSRodney W. Grimes 
901df8bae1dSRodney W. Grimes 	/*
902df8bae1dSRodney W. Grimes 	 * If first fragment to arrive, create a reassembly queue.
903df8bae1dSRodney W. Grimes 	 */
904df8bae1dSRodney W. Grimes 	if (fp == 0) {
905690a6055SJesper Skriver 		/*
906690a6055SJesper Skriver 		 * Enforce upper bound on number of fragmented packets
907690a6055SJesper Skriver 		 * for which we attempt reassembly;
908690a6055SJesper Skriver 		 * If maxfrag is 0, never accept fragments.
909690a6055SJesper Skriver 		 * If maxfrag is -1, accept all fragments without limitation.
910690a6055SJesper Skriver 		 */
911690a6055SJesper Skriver 		if ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets))
912690a6055SJesper Skriver 			goto dropfrag;
913690a6055SJesper Skriver 		ip_nfragpackets++;
914df8bae1dSRodney W. Grimes 		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
915df8bae1dSRodney W. Grimes 			goto dropfrag;
916df8bae1dSRodney W. Grimes 		fp = mtod(t, struct ipq *);
917462b86feSPoul-Henning Kamp 		TAILQ_INSERT_HEAD(head, fp, ipq_list);
918194a213eSAndrey A. Chernov 		nipq++;
919df8bae1dSRodney W. Grimes 		fp->ipq_ttl = IPFRAGTTL;
920df8bae1dSRodney W. Grimes 		fp->ipq_p = ip->ip_p;
921df8bae1dSRodney W. Grimes 		fp->ipq_id = ip->ip_id;
9226effc713SDoug Rabson 		fp->ipq_src = ip->ip_src;
9236effc713SDoug Rabson 		fp->ipq_dst = ip->ip_dst;
924af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
925af38c68cSLuigi Rizzo 		m->m_nextpkt = NULL;
92693e0e116SJulian Elischer #ifdef IPDIVERT
9278948e4baSArchie Cobbs 		fp->ipq_div_info = 0;
928bb60f459SJulian Elischer 		fp->ipq_div_cookie = 0;
92993e0e116SJulian Elischer #endif
930af38c68cSLuigi Rizzo 		goto inserted;
931df8bae1dSRodney W. Grimes 	}
932df8bae1dSRodney W. Grimes 
9336effc713SDoug Rabson #define GETIP(m)	((struct ip*)((m)->m_pkthdr.header))
9346effc713SDoug Rabson 
935df8bae1dSRodney W. Grimes 	/*
936df8bae1dSRodney W. Grimes 	 * Find a segment which begins after this one does.
937df8bae1dSRodney W. Grimes 	 */
9386effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
9396effc713SDoug Rabson 		if (GETIP(q)->ip_off > ip->ip_off)
940df8bae1dSRodney W. Grimes 			break;
941df8bae1dSRodney W. Grimes 
942df8bae1dSRodney W. Grimes 	/*
943df8bae1dSRodney W. Grimes 	 * If there is a preceding segment, it may provide some of
944df8bae1dSRodney W. Grimes 	 * our data already.  If so, drop the data from the incoming
945af38c68cSLuigi Rizzo 	 * segment.  If it provides all of our data, drop us, otherwise
946af38c68cSLuigi Rizzo 	 * stick new segment in the proper place.
947db4f9cc7SJonathan Lemon 	 *
948db4f9cc7SJonathan Lemon 	 * If some of the data is dropped from the the preceding
949db4f9cc7SJonathan Lemon 	 * segment, then it's checksum is invalidated.
950df8bae1dSRodney W. Grimes 	 */
9516effc713SDoug Rabson 	if (p) {
9526effc713SDoug Rabson 		i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
953df8bae1dSRodney W. Grimes 		if (i > 0) {
954df8bae1dSRodney W. Grimes 			if (i >= ip->ip_len)
955df8bae1dSRodney W. Grimes 				goto dropfrag;
9566a800098SYoshinobu Inoue 			m_adj(m, i);
957db4f9cc7SJonathan Lemon 			m->m_pkthdr.csum_flags = 0;
958df8bae1dSRodney W. Grimes 			ip->ip_off += i;
959df8bae1dSRodney W. Grimes 			ip->ip_len -= i;
960df8bae1dSRodney W. Grimes 		}
961af38c68cSLuigi Rizzo 		m->m_nextpkt = p->m_nextpkt;
962af38c68cSLuigi Rizzo 		p->m_nextpkt = m;
963af38c68cSLuigi Rizzo 	} else {
964af38c68cSLuigi Rizzo 		m->m_nextpkt = fp->ipq_frags;
965af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
966df8bae1dSRodney W. Grimes 	}
967df8bae1dSRodney W. Grimes 
968df8bae1dSRodney W. Grimes 	/*
969df8bae1dSRodney W. Grimes 	 * While we overlap succeeding segments trim them or,
970df8bae1dSRodney W. Grimes 	 * if they are completely covered, dequeue them.
971df8bae1dSRodney W. Grimes 	 */
9726effc713SDoug Rabson 	for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
973af38c68cSLuigi Rizzo 	     q = nq) {
9746effc713SDoug Rabson 		i = (ip->ip_off + ip->ip_len) -
9756effc713SDoug Rabson 		    GETIP(q)->ip_off;
9766effc713SDoug Rabson 		if (i < GETIP(q)->ip_len) {
9776effc713SDoug Rabson 			GETIP(q)->ip_len -= i;
9786effc713SDoug Rabson 			GETIP(q)->ip_off += i;
9796effc713SDoug Rabson 			m_adj(q, i);
980db4f9cc7SJonathan Lemon 			q->m_pkthdr.csum_flags = 0;
981df8bae1dSRodney W. Grimes 			break;
982df8bae1dSRodney W. Grimes 		}
9836effc713SDoug Rabson 		nq = q->m_nextpkt;
984af38c68cSLuigi Rizzo 		m->m_nextpkt = nq;
9856effc713SDoug Rabson 		m_freem(q);
986df8bae1dSRodney W. Grimes 	}
987df8bae1dSRodney W. Grimes 
988af38c68cSLuigi Rizzo inserted:
98993e0e116SJulian Elischer 
99093e0e116SJulian Elischer #ifdef IPDIVERT
99193e0e116SJulian Elischer 	/*
9928948e4baSArchie Cobbs 	 * Transfer firewall instructions to the fragment structure.
9938948e4baSArchie Cobbs 	 * Any fragment diverting causes the whole packet to divert.
99493e0e116SJulian Elischer 	 */
9958948e4baSArchie Cobbs 	fp->ipq_div_info = *divinfo;
9968948e4baSArchie Cobbs 	fp->ipq_div_cookie = *divcookie;
9978948e4baSArchie Cobbs 	*divinfo = 0;
9988948e4baSArchie Cobbs 	*divcookie = 0;
99993e0e116SJulian Elischer #endif
100093e0e116SJulian Elischer 
1001df8bae1dSRodney W. Grimes 	/*
1002af38c68cSLuigi Rizzo 	 * Check for complete reassembly.
1003df8bae1dSRodney W. Grimes 	 */
10046effc713SDoug Rabson 	next = 0;
10056effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
10066effc713SDoug Rabson 		if (GETIP(q)->ip_off != next)
10076effc713SDoug Rabson 			return (0);
10086effc713SDoug Rabson 		next += GETIP(q)->ip_len;
10096effc713SDoug Rabson 	}
10106effc713SDoug Rabson 	/* Make sure the last packet didn't have the IP_MF flag */
10116effc713SDoug Rabson 	if (p->m_flags & M_FRAG)
1012df8bae1dSRodney W. Grimes 		return (0);
1013df8bae1dSRodney W. Grimes 
1014df8bae1dSRodney W. Grimes 	/*
1015430d30d8SBill Fenner 	 * Reassembly is complete.  Make sure the packet is a sane size.
1016430d30d8SBill Fenner 	 */
10176effc713SDoug Rabson 	q = fp->ipq_frags;
10186effc713SDoug Rabson 	ip = GETIP(q);
10196effc713SDoug Rabson 	if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) {
1020430d30d8SBill Fenner 		ipstat.ips_toolong++;
1021462b86feSPoul-Henning Kamp 		ip_freef(head, fp);
1022430d30d8SBill Fenner 		return (0);
1023430d30d8SBill Fenner 	}
1024430d30d8SBill Fenner 
1025430d30d8SBill Fenner 	/*
1026430d30d8SBill Fenner 	 * Concatenate fragments.
1027df8bae1dSRodney W. Grimes 	 */
10286effc713SDoug Rabson 	m = q;
1029df8bae1dSRodney W. Grimes 	t = m->m_next;
1030df8bae1dSRodney W. Grimes 	m->m_next = 0;
1031df8bae1dSRodney W. Grimes 	m_cat(m, t);
10326effc713SDoug Rabson 	nq = q->m_nextpkt;
1033945aa40dSDoug Rabson 	q->m_nextpkt = 0;
10346effc713SDoug Rabson 	for (q = nq; q != NULL; q = nq) {
10356effc713SDoug Rabson 		nq = q->m_nextpkt;
1036945aa40dSDoug Rabson 		q->m_nextpkt = NULL;
1037db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags;
1038db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_data += q->m_pkthdr.csum_data;
1039a8db1d93SJonathan Lemon 		m_cat(m, q);
1040df8bae1dSRodney W. Grimes 	}
1041df8bae1dSRodney W. Grimes 
104293e0e116SJulian Elischer #ifdef IPDIVERT
104393e0e116SJulian Elischer 	/*
10448948e4baSArchie Cobbs 	 * Extract firewall instructions from the fragment structure.
104593e0e116SJulian Elischer 	 */
10468948e4baSArchie Cobbs 	*divinfo = fp->ipq_div_info;
10478948e4baSArchie Cobbs 	*divcookie = fp->ipq_div_cookie;
104893e0e116SJulian Elischer #endif
104993e0e116SJulian Elischer 
1050df8bae1dSRodney W. Grimes 	/*
1051df8bae1dSRodney W. Grimes 	 * Create header for new ip packet by
1052df8bae1dSRodney W. Grimes 	 * modifying header of first packet;
1053df8bae1dSRodney W. Grimes 	 * dequeue and discard fragment reassembly header.
1054df8bae1dSRodney W. Grimes 	 * Make header visible.
1055df8bae1dSRodney W. Grimes 	 */
1056df8bae1dSRodney W. Grimes 	ip->ip_len = next;
10576effc713SDoug Rabson 	ip->ip_src = fp->ipq_src;
10586effc713SDoug Rabson 	ip->ip_dst = fp->ipq_dst;
1059462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(head, fp, ipq_list);
1060194a213eSAndrey A. Chernov 	nipq--;
1061df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1062690a6055SJesper Skriver 	ip_nfragpackets--;
10636effc713SDoug Rabson 	m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2);
10646effc713SDoug Rabson 	m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2);
1065df8bae1dSRodney W. Grimes 	/* some debugging cruft by sklower, below, will go away soon */
1066df8bae1dSRodney W. Grimes 	if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
1067df8bae1dSRodney W. Grimes 		register int plen = 0;
10686a800098SYoshinobu Inoue 		for (t = m; t; t = t->m_next)
10696a800098SYoshinobu Inoue 			plen += t->m_len;
10706a800098SYoshinobu Inoue 		m->m_pkthdr.len = plen;
1071df8bae1dSRodney W. Grimes 	}
10726a800098SYoshinobu Inoue 	return (m);
1073df8bae1dSRodney W. Grimes 
1074df8bae1dSRodney W. Grimes dropfrag:
1075efe39c6aSJulian Elischer #ifdef IPDIVERT
10768948e4baSArchie Cobbs 	*divinfo = 0;
10778948e4baSArchie Cobbs 	*divcookie = 0;
1078efe39c6aSJulian Elischer #endif
1079df8bae1dSRodney W. Grimes 	ipstat.ips_fragdropped++;
1080df8bae1dSRodney W. Grimes 	m_freem(m);
1081df8bae1dSRodney W. Grimes 	return (0);
10826effc713SDoug Rabson 
10836effc713SDoug Rabson #undef GETIP
1084df8bae1dSRodney W. Grimes }
1085df8bae1dSRodney W. Grimes 
1086df8bae1dSRodney W. Grimes /*
1087df8bae1dSRodney W. Grimes  * Free a fragment reassembly header and all
1088df8bae1dSRodney W. Grimes  * associated datagrams.
1089df8bae1dSRodney W. Grimes  */
10900312fbe9SPoul-Henning Kamp static void
1091462b86feSPoul-Henning Kamp ip_freef(fhp, fp)
1092462b86feSPoul-Henning Kamp 	struct ipqhead *fhp;
1093df8bae1dSRodney W. Grimes 	struct ipq *fp;
1094df8bae1dSRodney W. Grimes {
10956effc713SDoug Rabson 	register struct mbuf *q;
1096df8bae1dSRodney W. Grimes 
10976effc713SDoug Rabson 	while (fp->ipq_frags) {
10986effc713SDoug Rabson 		q = fp->ipq_frags;
10996effc713SDoug Rabson 		fp->ipq_frags = q->m_nextpkt;
11006effc713SDoug Rabson 		m_freem(q);
1101df8bae1dSRodney W. Grimes 	}
1102462b86feSPoul-Henning Kamp 	TAILQ_REMOVE(fhp, fp, ipq_list);
1103df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1104690a6055SJesper Skriver 	ip_nfragpackets--;
1105194a213eSAndrey A. Chernov 	nipq--;
1106df8bae1dSRodney W. Grimes }
1107df8bae1dSRodney W. Grimes 
1108df8bae1dSRodney W. Grimes /*
1109df8bae1dSRodney W. Grimes  * IP timer processing;
1110df8bae1dSRodney W. Grimes  * if a timer expires on a reassembly
1111df8bae1dSRodney W. Grimes  * queue, discard it.
1112df8bae1dSRodney W. Grimes  */
1113df8bae1dSRodney W. Grimes void
1114df8bae1dSRodney W. Grimes ip_slowtimo()
1115df8bae1dSRodney W. Grimes {
1116df8bae1dSRodney W. Grimes 	register struct ipq *fp;
1117df8bae1dSRodney W. Grimes 	int s = splnet();
1118194a213eSAndrey A. Chernov 	int i;
1119df8bae1dSRodney W. Grimes 
1120194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1121462b86feSPoul-Henning Kamp 		for(fp = TAILQ_FIRST(&ipq[i]); fp;) {
1122462b86feSPoul-Henning Kamp 			struct ipq *fpp;
1123462b86feSPoul-Henning Kamp 
1124462b86feSPoul-Henning Kamp 			fpp = fp;
1125462b86feSPoul-Henning Kamp 			fp = TAILQ_NEXT(fp, ipq_list);
1126462b86feSPoul-Henning Kamp 			if(--fpp->ipq_ttl == 0) {
1127df8bae1dSRodney W. Grimes 				ipstat.ips_fragtimeout++;
1128462b86feSPoul-Henning Kamp 				ip_freef(&ipq[i], fpp);
1129df8bae1dSRodney W. Grimes 			}
1130df8bae1dSRodney W. Grimes 		}
1131194a213eSAndrey A. Chernov 	}
1132690a6055SJesper Skriver 	/*
1133690a6055SJesper Skriver 	 * If we are over the maximum number of fragments
1134690a6055SJesper Skriver 	 * (due to the limit being lowered), drain off
1135690a6055SJesper Skriver 	 * enough to get down to the new limit.
1136690a6055SJesper Skriver 	 */
1137690a6055SJesper Skriver 	for (i = 0; i < IPREASS_NHASH; i++) {
1138690a6055SJesper Skriver 		if (ip_maxfragpackets >= 0) {
1139690a6055SJesper Skriver 			while (ip_nfragpackets > ip_maxfragpackets &&
1140690a6055SJesper Skriver 				!TAILQ_EMPTY(&ipq[i])) {
1141690a6055SJesper Skriver 				ipstat.ips_fragdropped++;
1142690a6055SJesper Skriver 				ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1143690a6055SJesper Skriver 			}
1144690a6055SJesper Skriver 		}
1145690a6055SJesper Skriver 	}
11461f91d8c5SDavid Greenman 	ipflow_slowtimo();
1147df8bae1dSRodney W. Grimes 	splx(s);
1148df8bae1dSRodney W. Grimes }
1149df8bae1dSRodney W. Grimes 
1150df8bae1dSRodney W. Grimes /*
1151df8bae1dSRodney W. Grimes  * Drain off all datagram fragments.
1152df8bae1dSRodney W. Grimes  */
1153df8bae1dSRodney W. Grimes void
1154df8bae1dSRodney W. Grimes ip_drain()
1155df8bae1dSRodney W. Grimes {
1156194a213eSAndrey A. Chernov 	int     i;
1157ce29ab3aSGarrett Wollman 
1158194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1159462b86feSPoul-Henning Kamp 		while(!TAILQ_EMPTY(&ipq[i])) {
1160194a213eSAndrey A. Chernov 			ipstat.ips_fragdropped++;
1161462b86feSPoul-Henning Kamp 			ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i]));
1162194a213eSAndrey A. Chernov 		}
1163194a213eSAndrey A. Chernov 	}
1164ce29ab3aSGarrett Wollman 	in_rtqdrain();
1165df8bae1dSRodney W. Grimes }
1166df8bae1dSRodney W. Grimes 
1167df8bae1dSRodney W. Grimes /*
1168df8bae1dSRodney W. Grimes  * Do option processing on a datagram,
1169df8bae1dSRodney W. Grimes  * possibly discarding it if bad options are encountered,
1170df8bae1dSRodney W. Grimes  * or forwarding it if source-routed.
1171d0ebc0d2SYaroslav Tykhiy  * The pass argument is used when operating in the IPSTEALTH
1172d0ebc0d2SYaroslav Tykhiy  * mode to tell what options to process:
1173d0ebc0d2SYaroslav Tykhiy  * [LS]SRR (pass 0) or the others (pass 1).
1174d0ebc0d2SYaroslav Tykhiy  * The reason for as many as two passes is that when doing IPSTEALTH,
1175d0ebc0d2SYaroslav Tykhiy  * non-routing options should be processed only if the packet is for us.
1176df8bae1dSRodney W. Grimes  * Returns 1 if packet has been forwarded/freed,
1177df8bae1dSRodney W. Grimes  * 0 if the packet should be processed further.
1178df8bae1dSRodney W. Grimes  */
11790312fbe9SPoul-Henning Kamp static int
1180d0ebc0d2SYaroslav Tykhiy ip_dooptions(m, pass)
1181df8bae1dSRodney W. Grimes 	struct mbuf *m;
1182d0ebc0d2SYaroslav Tykhiy 	int pass;
1183df8bae1dSRodney W. Grimes {
1184df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
1185df8bae1dSRodney W. Grimes 	register u_char *cp;
1186df8bae1dSRodney W. Grimes 	register struct in_ifaddr *ia;
1187df8bae1dSRodney W. Grimes 	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
1188df8bae1dSRodney W. Grimes 	struct in_addr *sin, dst;
1189df8bae1dSRodney W. Grimes 	n_time ntime;
1190df8bae1dSRodney W. Grimes 
1191df8bae1dSRodney W. Grimes 	dst = ip->ip_dst;
1192df8bae1dSRodney W. Grimes 	cp = (u_char *)(ip + 1);
119358938916SGarrett Wollman 	cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1194df8bae1dSRodney W. Grimes 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
1195df8bae1dSRodney W. Grimes 		opt = cp[IPOPT_OPTVAL];
1196df8bae1dSRodney W. Grimes 		if (opt == IPOPT_EOL)
1197df8bae1dSRodney W. Grimes 			break;
1198df8bae1dSRodney W. Grimes 		if (opt == IPOPT_NOP)
1199df8bae1dSRodney W. Grimes 			optlen = 1;
1200df8bae1dSRodney W. Grimes 		else {
1201fdcb8debSJun-ichiro itojun Hagino 			if (cnt < IPOPT_OLEN + sizeof(*cp)) {
1202fdcb8debSJun-ichiro itojun Hagino 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1203fdcb8debSJun-ichiro itojun Hagino 				goto bad;
1204fdcb8debSJun-ichiro itojun Hagino 			}
1205df8bae1dSRodney W. Grimes 			optlen = cp[IPOPT_OLEN];
1206707d00a3SJonathan Lemon 			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
1207df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1208df8bae1dSRodney W. Grimes 				goto bad;
1209df8bae1dSRodney W. Grimes 			}
1210df8bae1dSRodney W. Grimes 		}
1211df8bae1dSRodney W. Grimes 		switch (opt) {
1212df8bae1dSRodney W. Grimes 
1213df8bae1dSRodney W. Grimes 		default:
1214df8bae1dSRodney W. Grimes 			break;
1215df8bae1dSRodney W. Grimes 
1216df8bae1dSRodney W. Grimes 		/*
1217df8bae1dSRodney W. Grimes 		 * Source routing with record.
1218df8bae1dSRodney W. Grimes 		 * Find interface with current destination address.
1219df8bae1dSRodney W. Grimes 		 * If none on this machine then drop if strictly routed,
1220df8bae1dSRodney W. Grimes 		 * or do nothing if loosely routed.
1221df8bae1dSRodney W. Grimes 		 * Record interface address and bring up next address
1222df8bae1dSRodney W. Grimes 		 * component.  If strictly routed make sure next
1223df8bae1dSRodney W. Grimes 		 * address is on directly accessible net.
1224df8bae1dSRodney W. Grimes 		 */
1225df8bae1dSRodney W. Grimes 		case IPOPT_LSRR:
1226df8bae1dSRodney W. Grimes 		case IPOPT_SSRR:
1227d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1228d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass > 0)
1229d0ebc0d2SYaroslav Tykhiy 				break;
1230d0ebc0d2SYaroslav Tykhiy #endif
123133841545SHajimu UMEMOTO 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
123233841545SHajimu UMEMOTO 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
123333841545SHajimu UMEMOTO 				goto bad;
123433841545SHajimu UMEMOTO 			}
1235df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1236df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1237df8bae1dSRodney W. Grimes 				goto bad;
1238df8bae1dSRodney W. Grimes 			}
1239df8bae1dSRodney W. Grimes 			ipaddr.sin_addr = ip->ip_dst;
1240df8bae1dSRodney W. Grimes 			ia = (struct in_ifaddr *)
1241df8bae1dSRodney W. Grimes 				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
1242df8bae1dSRodney W. Grimes 			if (ia == 0) {
1243df8bae1dSRodney W. Grimes 				if (opt == IPOPT_SSRR) {
1244df8bae1dSRodney W. Grimes 					type = ICMP_UNREACH;
1245df8bae1dSRodney W. Grimes 					code = ICMP_UNREACH_SRCFAIL;
1246df8bae1dSRodney W. Grimes 					goto bad;
1247df8bae1dSRodney W. Grimes 				}
1248bc189bf8SGuido van Rooij 				if (!ip_dosourceroute)
1249bc189bf8SGuido van Rooij 					goto nosourcerouting;
1250df8bae1dSRodney W. Grimes 				/*
1251df8bae1dSRodney W. Grimes 				 * Loose routing, and not at next destination
1252df8bae1dSRodney W. Grimes 				 * yet; nothing to do except forward.
1253df8bae1dSRodney W. Grimes 				 */
1254df8bae1dSRodney W. Grimes 				break;
1255df8bae1dSRodney W. Grimes 			}
1256df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
12575d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr)) {
1258df8bae1dSRodney W. Grimes 				/*
1259df8bae1dSRodney W. Grimes 				 * End of source route.  Should be for us.
1260df8bae1dSRodney W. Grimes 				 */
12614fce5804SGuido van Rooij 				if (!ip_acceptsourceroute)
12624fce5804SGuido van Rooij 					goto nosourcerouting;
1263df8bae1dSRodney W. Grimes 				save_rte(cp, ip->ip_src);
1264df8bae1dSRodney W. Grimes 				break;
1265df8bae1dSRodney W. Grimes 			}
1266d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1267d0ebc0d2SYaroslav Tykhiy 			if (ipstealth)
1268d0ebc0d2SYaroslav Tykhiy 				goto dropit;
1269d0ebc0d2SYaroslav Tykhiy #endif
12701025071fSGarrett Wollman 			if (!ip_dosourceroute) {
12710af8d3ecSDavid Greenman 				if (ipforwarding) {
12720af8d3ecSDavid Greenman 					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
12730af8d3ecSDavid Greenman 					/*
12740af8d3ecSDavid Greenman 					 * Acting as a router, so generate ICMP
12750af8d3ecSDavid Greenman 					 */
1276efa48587SGuido van Rooij nosourcerouting:
1277bc189bf8SGuido van Rooij 					strcpy(buf, inet_ntoa(ip->ip_dst));
12781025071fSGarrett Wollman 					log(LOG_WARNING,
12791025071fSGarrett Wollman 					    "attempted source route from %s to %s\n",
12801025071fSGarrett Wollman 					    inet_ntoa(ip->ip_src), buf);
12811025071fSGarrett Wollman 					type = ICMP_UNREACH;
12821025071fSGarrett Wollman 					code = ICMP_UNREACH_SRCFAIL;
12831025071fSGarrett Wollman 					goto bad;
12840af8d3ecSDavid Greenman 				} else {
12850af8d3ecSDavid Greenman 					/*
12860af8d3ecSDavid Greenman 					 * Not acting as a router, so silently drop.
12870af8d3ecSDavid Greenman 					 */
1288d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1289d0ebc0d2SYaroslav Tykhiy dropit:
1290d0ebc0d2SYaroslav Tykhiy #endif
12910af8d3ecSDavid Greenman 					ipstat.ips_cantforward++;
12920af8d3ecSDavid Greenman 					m_freem(m);
12930af8d3ecSDavid Greenman 					return (1);
12940af8d3ecSDavid Greenman 				}
12951025071fSGarrett Wollman 			}
12961025071fSGarrett Wollman 
1297df8bae1dSRodney W. Grimes 			/*
1298df8bae1dSRodney W. Grimes 			 * locate outgoing interface
1299df8bae1dSRodney W. Grimes 			 */
130094a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, cp + off,
1301df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
13021025071fSGarrett Wollman 
1303df8bae1dSRodney W. Grimes 			if (opt == IPOPT_SSRR) {
1304df8bae1dSRodney W. Grimes #define	INA	struct in_ifaddr *
1305df8bae1dSRodney W. Grimes #define	SA	struct sockaddr *
1306df8bae1dSRodney W. Grimes 			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
1307df8bae1dSRodney W. Grimes 				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
1308df8bae1dSRodney W. Grimes 			} else
1309bd714208SRuslan Ermilov 				ia = ip_rtaddr(ipaddr.sin_addr, &ipforward_rt);
1310df8bae1dSRodney W. Grimes 			if (ia == 0) {
1311df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1312df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_SRCFAIL;
1313df8bae1dSRodney W. Grimes 				goto bad;
1314df8bae1dSRodney W. Grimes 			}
1315df8bae1dSRodney W. Grimes 			ip->ip_dst = ipaddr.sin_addr;
131694a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
131794a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1318df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1319df8bae1dSRodney W. Grimes 			/*
1320df8bae1dSRodney W. Grimes 			 * Let ip_intr's mcast routing check handle mcast pkts
1321df8bae1dSRodney W. Grimes 			 */
1322df8bae1dSRodney W. Grimes 			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
1323df8bae1dSRodney W. Grimes 			break;
1324df8bae1dSRodney W. Grimes 
1325df8bae1dSRodney W. Grimes 		case IPOPT_RR:
1326d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1327d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass == 0)
1328d0ebc0d2SYaroslav Tykhiy 				break;
1329d0ebc0d2SYaroslav Tykhiy #endif
1330707d00a3SJonathan Lemon 			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
1331707d00a3SJonathan Lemon 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1332707d00a3SJonathan Lemon 				goto bad;
1333707d00a3SJonathan Lemon 			}
1334df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1335df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1336df8bae1dSRodney W. Grimes 				goto bad;
1337df8bae1dSRodney W. Grimes 			}
1338df8bae1dSRodney W. Grimes 			/*
1339df8bae1dSRodney W. Grimes 			 * If no space remains, ignore.
1340df8bae1dSRodney W. Grimes 			 */
1341df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
13425d5d5fc0SJonathan Lemon 			if (off > optlen - (int)sizeof(struct in_addr))
1343df8bae1dSRodney W. Grimes 				break;
134494a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
1345df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
1346df8bae1dSRodney W. Grimes 			/*
1347df8bae1dSRodney W. Grimes 			 * locate outgoing interface; if we're the destination,
1348df8bae1dSRodney W. Grimes 			 * use the incoming interface (should be same).
1349df8bae1dSRodney W. Grimes 			 */
1350df8bae1dSRodney W. Grimes 			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
1351bd714208SRuslan Ermilov 			    (ia = ip_rtaddr(ipaddr.sin_addr,
1352bd714208SRuslan Ermilov 			    &ipforward_rt)) == 0) {
1353df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1354df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_HOST;
1355df8bae1dSRodney W. Grimes 				goto bad;
1356df8bae1dSRodney W. Grimes 			}
135794a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
135894a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1359df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1360df8bae1dSRodney W. Grimes 			break;
1361df8bae1dSRodney W. Grimes 
1362df8bae1dSRodney W. Grimes 		case IPOPT_TS:
1363d0ebc0d2SYaroslav Tykhiy #ifdef IPSTEALTH
1364d0ebc0d2SYaroslav Tykhiy 			if (ipstealth && pass == 0)
1365d0ebc0d2SYaroslav Tykhiy 				break;
1366d0ebc0d2SYaroslav Tykhiy #endif
1367df8bae1dSRodney W. Grimes 			code = cp - (u_char *)ip;
136807514071SJonathan Lemon 			if (optlen < 4 || optlen > 40) {
136907514071SJonathan Lemon 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1370df8bae1dSRodney W. Grimes 				goto bad;
137133841545SHajimu UMEMOTO 			}
137207514071SJonathan Lemon 			if ((off = cp[IPOPT_OFFSET]) < 5) {
137307514071SJonathan Lemon 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
137433841545SHajimu UMEMOTO 				goto bad;
137533841545SHajimu UMEMOTO 			}
137607514071SJonathan Lemon 			if (off > optlen - (int)sizeof(int32_t)) {
137707514071SJonathan Lemon 				cp[IPOPT_OFFSET + 1] += (1 << 4);
137807514071SJonathan Lemon 				if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) {
137907514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1380df8bae1dSRodney W. Grimes 					goto bad;
138133841545SHajimu UMEMOTO 				}
1382df8bae1dSRodney W. Grimes 				break;
1383df8bae1dSRodney W. Grimes 			}
138407514071SJonathan Lemon 			off--;				/* 0 origin */
138507514071SJonathan Lemon 			sin = (struct in_addr *)(cp + off);
138607514071SJonathan Lemon 			switch (cp[IPOPT_OFFSET + 1] & 0x0f) {
1387df8bae1dSRodney W. Grimes 
1388df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSONLY:
1389df8bae1dSRodney W. Grimes 				break;
1390df8bae1dSRodney W. Grimes 
1391df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSANDADDR:
139207514071SJonathan Lemon 				if (off + sizeof(n_time) +
139307514071SJonathan Lemon 				    sizeof(struct in_addr) > optlen) {
139407514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1395df8bae1dSRodney W. Grimes 					goto bad;
139633841545SHajimu UMEMOTO 				}
1397df8bae1dSRodney W. Grimes 				ipaddr.sin_addr = dst;
1398df8bae1dSRodney W. Grimes 				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
1399df8bae1dSRodney W. Grimes 							    m->m_pkthdr.rcvif);
1400df8bae1dSRodney W. Grimes 				if (ia == 0)
1401df8bae1dSRodney W. Grimes 					continue;
140294a5d9b6SDavid Greenman 				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
140394a5d9b6SDavid Greenman 				    sizeof(struct in_addr));
140407514071SJonathan Lemon 				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1405df8bae1dSRodney W. Grimes 				break;
1406df8bae1dSRodney W. Grimes 
1407df8bae1dSRodney W. Grimes 			case IPOPT_TS_PRESPEC:
140807514071SJonathan Lemon 				if (off + sizeof(n_time) +
140907514071SJonathan Lemon 				    sizeof(struct in_addr) > optlen) {
141007514071SJonathan Lemon 					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1411df8bae1dSRodney W. Grimes 					goto bad;
141233841545SHajimu UMEMOTO 				}
141394a5d9b6SDavid Greenman 				(void)memcpy(&ipaddr.sin_addr, sin,
1414df8bae1dSRodney W. Grimes 				    sizeof(struct in_addr));
1415df8bae1dSRodney W. Grimes 				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
1416df8bae1dSRodney W. Grimes 					continue;
141707514071SJonathan Lemon 				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1418df8bae1dSRodney W. Grimes 				break;
1419df8bae1dSRodney W. Grimes 
1420df8bae1dSRodney W. Grimes 			default:
142107514071SJonathan Lemon 				code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip;
1422df8bae1dSRodney W. Grimes 				goto bad;
1423df8bae1dSRodney W. Grimes 			}
1424df8bae1dSRodney W. Grimes 			ntime = iptime();
142507514071SJonathan Lemon 			(void)memcpy(cp + off, &ntime, sizeof(n_time));
142607514071SJonathan Lemon 			cp[IPOPT_OFFSET] += sizeof(n_time);
1427df8bae1dSRodney W. Grimes 		}
1428df8bae1dSRodney W. Grimes 	}
142947174b49SAndrey A. Chernov 	if (forward && ipforwarding) {
1430df8bae1dSRodney W. Grimes 		ip_forward(m, 1);
1431df8bae1dSRodney W. Grimes 		return (1);
1432df8bae1dSRodney W. Grimes 	}
1433df8bae1dSRodney W. Grimes 	return (0);
1434df8bae1dSRodney W. Grimes bad:
1435df8bae1dSRodney W. Grimes 	icmp_error(m, type, code, 0, 0);
1436df8bae1dSRodney W. Grimes 	ipstat.ips_badoptions++;
1437df8bae1dSRodney W. Grimes 	return (1);
1438df8bae1dSRodney W. Grimes }
1439df8bae1dSRodney W. Grimes 
1440df8bae1dSRodney W. Grimes /*
1441df8bae1dSRodney W. Grimes  * Given address of next destination (final or next hop),
1442df8bae1dSRodney W. Grimes  * return internet address info of interface to be used to get there.
1443df8bae1dSRodney W. Grimes  */
1444bd714208SRuslan Ermilov struct in_ifaddr *
1445bd714208SRuslan Ermilov ip_rtaddr(dst, rt)
1446df8bae1dSRodney W. Grimes 	struct in_addr dst;
1447bd714208SRuslan Ermilov 	struct route *rt;
1448df8bae1dSRodney W. Grimes {
1449df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
1450df8bae1dSRodney W. Grimes 
1451bd714208SRuslan Ermilov 	sin = (struct sockaddr_in *)&rt->ro_dst;
1452df8bae1dSRodney W. Grimes 
1453bd714208SRuslan Ermilov 	if (rt->ro_rt == 0 ||
1454bd714208SRuslan Ermilov 	    !(rt->ro_rt->rt_flags & RTF_UP) ||
14554078ffb1SRuslan Ermilov 	    dst.s_addr != sin->sin_addr.s_addr) {
1456bd714208SRuslan Ermilov 		if (rt->ro_rt) {
1457bd714208SRuslan Ermilov 			RTFREE(rt->ro_rt);
1458bd714208SRuslan Ermilov 			rt->ro_rt = 0;
1459df8bae1dSRodney W. Grimes 		}
1460df8bae1dSRodney W. Grimes 		sin->sin_family = AF_INET;
1461df8bae1dSRodney W. Grimes 		sin->sin_len = sizeof(*sin);
1462df8bae1dSRodney W. Grimes 		sin->sin_addr = dst;
1463df8bae1dSRodney W. Grimes 
1464bd714208SRuslan Ermilov 		rtalloc_ign(rt, RTF_PRCLONING);
1465df8bae1dSRodney W. Grimes 	}
1466bd714208SRuslan Ermilov 	if (rt->ro_rt == 0)
1467df8bae1dSRodney W. Grimes 		return ((struct in_ifaddr *)0);
1468bd714208SRuslan Ermilov 	return (ifatoia(rt->ro_rt->rt_ifa));
1469df8bae1dSRodney W. Grimes }
1470df8bae1dSRodney W. Grimes 
1471df8bae1dSRodney W. Grimes /*
1472df8bae1dSRodney W. Grimes  * Save incoming source route for use in replies,
1473df8bae1dSRodney W. Grimes  * to be picked up later by ip_srcroute if the receiver is interested.
1474df8bae1dSRodney W. Grimes  */
1475df8bae1dSRodney W. Grimes void
1476df8bae1dSRodney W. Grimes save_rte(option, dst)
1477df8bae1dSRodney W. Grimes 	u_char *option;
1478df8bae1dSRodney W. Grimes 	struct in_addr dst;
1479df8bae1dSRodney W. Grimes {
1480df8bae1dSRodney W. Grimes 	unsigned olen;
1481df8bae1dSRodney W. Grimes 
1482df8bae1dSRodney W. Grimes 	olen = option[IPOPT_OLEN];
1483df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1484df8bae1dSRodney W. Grimes 	if (ipprintfs)
1485df8bae1dSRodney W. Grimes 		printf("save_rte: olen %d\n", olen);
1486df8bae1dSRodney W. Grimes #endif
1487df8bae1dSRodney W. Grimes 	if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
1488df8bae1dSRodney W. Grimes 		return;
14890453d3cbSBruce Evans 	bcopy(option, ip_srcrt.srcopt, olen);
1490df8bae1dSRodney W. Grimes 	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
1491df8bae1dSRodney W. Grimes 	ip_srcrt.dst = dst;
1492df8bae1dSRodney W. Grimes }
1493df8bae1dSRodney W. Grimes 
1494df8bae1dSRodney W. Grimes /*
1495df8bae1dSRodney W. Grimes  * Retrieve incoming source route for use in replies,
1496df8bae1dSRodney W. Grimes  * in the same form used by setsockopt.
1497df8bae1dSRodney W. Grimes  * The first hop is placed before the options, will be removed later.
1498df8bae1dSRodney W. Grimes  */
1499df8bae1dSRodney W. Grimes struct mbuf *
1500df8bae1dSRodney W. Grimes ip_srcroute()
1501df8bae1dSRodney W. Grimes {
1502df8bae1dSRodney W. Grimes 	register struct in_addr *p, *q;
1503df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1504df8bae1dSRodney W. Grimes 
1505df8bae1dSRodney W. Grimes 	if (ip_nhops == 0)
1506df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1507cfe8b629SGarrett Wollman 	m = m_get(M_DONTWAIT, MT_HEADER);
1508df8bae1dSRodney W. Grimes 	if (m == 0)
1509df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1510df8bae1dSRodney W. Grimes 
1511df8bae1dSRodney W. Grimes #define OPTSIZ	(sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
1512df8bae1dSRodney W. Grimes 
1513df8bae1dSRodney W. Grimes 	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
1514df8bae1dSRodney W. Grimes 	m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
1515df8bae1dSRodney W. Grimes 	    OPTSIZ;
1516df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1517df8bae1dSRodney W. Grimes 	if (ipprintfs)
1518df8bae1dSRodney W. Grimes 		printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
1519df8bae1dSRodney W. Grimes #endif
1520df8bae1dSRodney W. Grimes 
1521df8bae1dSRodney W. Grimes 	/*
1522df8bae1dSRodney W. Grimes 	 * First save first hop for return route
1523df8bae1dSRodney W. Grimes 	 */
1524df8bae1dSRodney W. Grimes 	p = &ip_srcrt.route[ip_nhops - 1];
1525df8bae1dSRodney W. Grimes 	*(mtod(m, struct in_addr *)) = *p--;
1526df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1527df8bae1dSRodney W. Grimes 	if (ipprintfs)
1528af38c68cSLuigi Rizzo 		printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
1529df8bae1dSRodney W. Grimes #endif
1530df8bae1dSRodney W. Grimes 
1531df8bae1dSRodney W. Grimes 	/*
1532df8bae1dSRodney W. Grimes 	 * Copy option fields and padding (nop) to mbuf.
1533df8bae1dSRodney W. Grimes 	 */
1534df8bae1dSRodney W. Grimes 	ip_srcrt.nop = IPOPT_NOP;
1535df8bae1dSRodney W. Grimes 	ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
153694a5d9b6SDavid Greenman 	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
153794a5d9b6SDavid Greenman 	    &ip_srcrt.nop, OPTSIZ);
1538df8bae1dSRodney W. Grimes 	q = (struct in_addr *)(mtod(m, caddr_t) +
1539df8bae1dSRodney W. Grimes 	    sizeof(struct in_addr) + OPTSIZ);
1540df8bae1dSRodney W. Grimes #undef OPTSIZ
1541df8bae1dSRodney W. Grimes 	/*
1542df8bae1dSRodney W. Grimes 	 * Record return path as an IP source route,
1543df8bae1dSRodney W. Grimes 	 * reversing the path (pointers are now aligned).
1544df8bae1dSRodney W. Grimes 	 */
1545df8bae1dSRodney W. Grimes 	while (p >= ip_srcrt.route) {
1546df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1547df8bae1dSRodney W. Grimes 		if (ipprintfs)
1548af38c68cSLuigi Rizzo 			printf(" %lx", (u_long)ntohl(q->s_addr));
1549df8bae1dSRodney W. Grimes #endif
1550df8bae1dSRodney W. Grimes 		*q++ = *p--;
1551df8bae1dSRodney W. Grimes 	}
1552df8bae1dSRodney W. Grimes 	/*
1553df8bae1dSRodney W. Grimes 	 * Last hop goes to final destination.
1554df8bae1dSRodney W. Grimes 	 */
1555df8bae1dSRodney W. Grimes 	*q = ip_srcrt.dst;
1556df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1557df8bae1dSRodney W. Grimes 	if (ipprintfs)
1558af38c68cSLuigi Rizzo 		printf(" %lx\n", (u_long)ntohl(q->s_addr));
1559df8bae1dSRodney W. Grimes #endif
1560df8bae1dSRodney W. Grimes 	return (m);
1561df8bae1dSRodney W. Grimes }
1562df8bae1dSRodney W. Grimes 
1563df8bae1dSRodney W. Grimes /*
1564df8bae1dSRodney W. Grimes  * Strip out IP options, at higher
1565df8bae1dSRodney W. Grimes  * level protocol in the kernel.
1566df8bae1dSRodney W. Grimes  * Second argument is buffer to which options
1567df8bae1dSRodney W. Grimes  * will be moved, and return value is their length.
1568df8bae1dSRodney W. Grimes  * XXX should be deleted; last arg currently ignored.
1569df8bae1dSRodney W. Grimes  */
1570df8bae1dSRodney W. Grimes void
1571df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt)
1572df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1573df8bae1dSRodney W. Grimes 	struct mbuf *mopt;
1574df8bae1dSRodney W. Grimes {
1575df8bae1dSRodney W. Grimes 	register int i;
1576df8bae1dSRodney W. Grimes 	struct ip *ip = mtod(m, struct ip *);
1577df8bae1dSRodney W. Grimes 	register caddr_t opts;
1578df8bae1dSRodney W. Grimes 	int olen;
1579df8bae1dSRodney W. Grimes 
158058938916SGarrett Wollman 	olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1581df8bae1dSRodney W. Grimes 	opts = (caddr_t)(ip + 1);
1582df8bae1dSRodney W. Grimes 	i = m->m_len - (sizeof (struct ip) + olen);
1583df8bae1dSRodney W. Grimes 	bcopy(opts + olen, opts, (unsigned)i);
1584df8bae1dSRodney W. Grimes 	m->m_len -= olen;
1585df8bae1dSRodney W. Grimes 	if (m->m_flags & M_PKTHDR)
1586df8bae1dSRodney W. Grimes 		m->m_pkthdr.len -= olen;
158758938916SGarrett Wollman 	ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2);
1588df8bae1dSRodney W. Grimes }
1589df8bae1dSRodney W. Grimes 
1590df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = {
1591df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
1592df8bae1dSRodney W. Grimes 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
1593df8bae1dSRodney W. Grimes 	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
1594df8bae1dSRodney W. Grimes 	EMSGSIZE,	EHOSTUNREACH,	0,		0,
1595df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
15963b8123b7SJesper Skriver 	ENOPROTOOPT,	ECONNREFUSED
1597df8bae1dSRodney W. Grimes };
1598df8bae1dSRodney W. Grimes 
1599df8bae1dSRodney W. Grimes /*
1600df8bae1dSRodney W. Grimes  * Forward a packet.  If some error occurs return the sender
1601df8bae1dSRodney W. Grimes  * an icmp packet.  Note we can't always generate a meaningful
1602df8bae1dSRodney W. Grimes  * icmp message because icmp doesn't have a large enough repertoire
1603df8bae1dSRodney W. Grimes  * of codes and types.
1604df8bae1dSRodney W. Grimes  *
1605df8bae1dSRodney W. Grimes  * If not forwarding, just drop the packet.  This could be confusing
1606df8bae1dSRodney W. Grimes  * if ipforwarding was zero but some routing protocol was advancing
1607df8bae1dSRodney W. Grimes  * us as a gateway to somewhere.  However, we must let the routing
1608df8bae1dSRodney W. Grimes  * protocol deal with that.
1609df8bae1dSRodney W. Grimes  *
1610df8bae1dSRodney W. Grimes  * The srcrt parameter indicates whether the packet is being forwarded
1611df8bae1dSRodney W. Grimes  * via a source route.
1612df8bae1dSRodney W. Grimes  */
16130312fbe9SPoul-Henning Kamp static void
1614df8bae1dSRodney W. Grimes ip_forward(m, srcrt)
1615df8bae1dSRodney W. Grimes 	struct mbuf *m;
1616df8bae1dSRodney W. Grimes 	int srcrt;
1617df8bae1dSRodney W. Grimes {
1618df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
1619df8bae1dSRodney W. Grimes 	register struct rtentry *rt;
162026f9a767SRodney W. Grimes 	int error, type = 0, code = 0;
1621df8bae1dSRodney W. Grimes 	struct mbuf *mcopy;
1622df8bae1dSRodney W. Grimes 	n_long dest;
16233efc3014SJulian Elischer 	struct in_addr pkt_dst;
1624df8bae1dSRodney W. Grimes 	struct ifnet *destifp;
16256a800098SYoshinobu Inoue #ifdef IPSEC
16266a800098SYoshinobu Inoue 	struct ifnet dummyifp;
16276a800098SYoshinobu Inoue #endif
1628df8bae1dSRodney W. Grimes 
1629df8bae1dSRodney W. Grimes 	dest = 0;
16303efc3014SJulian Elischer 	/*
16313efc3014SJulian Elischer 	 * Cache the destination address of the packet; this may be
16323efc3014SJulian Elischer 	 * changed by use of 'ipfw fwd'.
16333efc3014SJulian Elischer 	 */
16343efc3014SJulian Elischer 	pkt_dst = ip_fw_fwd_addr == NULL ?
16353efc3014SJulian Elischer 	    ip->ip_dst : ip_fw_fwd_addr->sin_addr;
16363efc3014SJulian Elischer 
1637df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1638df8bae1dSRodney W. Grimes 	if (ipprintfs)
163961ce519bSPoul-Henning Kamp 		printf("forward: src %lx dst %lx ttl %x\n",
16403efc3014SJulian Elischer 		    (u_long)ip->ip_src.s_addr, (u_long)pkt_dst.s_addr,
1641162886e2SBruce Evans 		    ip->ip_ttl);
1642df8bae1dSRodney W. Grimes #endif
1643100ba1a6SJordan K. Hubbard 
1644100ba1a6SJordan K. Hubbard 
16453efc3014SJulian Elischer 	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(pkt_dst) == 0) {
1646df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1647df8bae1dSRodney W. Grimes 		m_freem(m);
1648df8bae1dSRodney W. Grimes 		return;
1649df8bae1dSRodney W. Grimes 	}
16501b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
16511b968362SDag-Erling Smørgrav 	if (!ipstealth) {
16521b968362SDag-Erling Smørgrav #endif
1653df8bae1dSRodney W. Grimes 		if (ip->ip_ttl <= IPTTLDEC) {
16541b968362SDag-Erling Smørgrav 			icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
16551b968362SDag-Erling Smørgrav 			    dest, 0);
1656df8bae1dSRodney W. Grimes 			return;
1657df8bae1dSRodney W. Grimes 		}
16581b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
16591b968362SDag-Erling Smørgrav 	}
16601b968362SDag-Erling Smørgrav #endif
1661df8bae1dSRodney W. Grimes 
16623efc3014SJulian Elischer 	if (ip_rtaddr(pkt_dst, &ipforward_rt) == 0) {
1663df8bae1dSRodney W. Grimes 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
1664df8bae1dSRodney W. Grimes 		return;
16654078ffb1SRuslan Ermilov 	} else
1666df8bae1dSRodney W. Grimes 		rt = ipforward_rt.ro_rt;
1667df8bae1dSRodney W. Grimes 
1668df8bae1dSRodney W. Grimes 	/*
1669bfef7ed4SIan Dowse 	 * Save the IP header and at most 8 bytes of the payload,
1670bfef7ed4SIan Dowse 	 * in case we need to generate an ICMP message to the src.
1671bfef7ed4SIan Dowse 	 *
1672bfef7ed4SIan Dowse 	 * We don't use m_copy() because it might return a reference
1673bfef7ed4SIan Dowse 	 * to a shared cluster. Both this function and ip_output()
1674bfef7ed4SIan Dowse 	 * assume exclusive access to the IP header in `m', so any
1675bfef7ed4SIan Dowse 	 * data in a cluster may change before we reach icmp_error().
1676df8bae1dSRodney W. Grimes 	 */
1677bfef7ed4SIan Dowse 	MGET(mcopy, M_DONTWAIT, m->m_type);
1678bfef7ed4SIan Dowse 	if (mcopy != NULL) {
1679bfef7ed4SIan Dowse 		M_COPY_PKTHDR(mcopy, m);
1680bfef7ed4SIan Dowse 		mcopy->m_len = imin((IP_VHL_HL(ip->ip_vhl) << 2) + 8,
1681bfef7ed4SIan Dowse 		    (int)ip->ip_len);
1682bfef7ed4SIan Dowse 		m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
1683bfef7ed4SIan Dowse 	}
168404287599SRuslan Ermilov 
168504287599SRuslan Ermilov #ifdef IPSTEALTH
168604287599SRuslan Ermilov 	if (!ipstealth) {
168704287599SRuslan Ermilov #endif
168804287599SRuslan Ermilov 		ip->ip_ttl -= IPTTLDEC;
168904287599SRuslan Ermilov #ifdef IPSTEALTH
169004287599SRuslan Ermilov 	}
169104287599SRuslan Ermilov #endif
1692df8bae1dSRodney W. Grimes 
1693df8bae1dSRodney W. Grimes 	/*
1694df8bae1dSRodney W. Grimes 	 * If forwarding packet using same interface that it came in on,
1695df8bae1dSRodney W. Grimes 	 * perhaps should send a redirect to sender to shortcut a hop.
1696df8bae1dSRodney W. Grimes 	 * Only send redirect if source is sending directly to us,
1697df8bae1dSRodney W. Grimes 	 * and if packet was not source routed (or has any options).
1698df8bae1dSRodney W. Grimes 	 * Also, don't send redirect if forwarding using a default route
1699df8bae1dSRodney W. Grimes 	 * or a route modified by a redirect.
1700df8bae1dSRodney W. Grimes 	 */
1701df8bae1dSRodney W. Grimes 	if (rt->rt_ifp == m->m_pkthdr.rcvif &&
1702df8bae1dSRodney W. Grimes 	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
1703df8bae1dSRodney W. Grimes 	    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
17043efc3014SJulian Elischer 	    ipsendredirects && !srcrt && !ip_fw_fwd_addr) {
1705df8bae1dSRodney W. Grimes #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
1706df8bae1dSRodney W. Grimes 		u_long src = ntohl(ip->ip_src.s_addr);
1707df8bae1dSRodney W. Grimes 
1708df8bae1dSRodney W. Grimes 		if (RTA(rt) &&
1709df8bae1dSRodney W. Grimes 		    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1710df8bae1dSRodney W. Grimes 		    if (rt->rt_flags & RTF_GATEWAY)
1711df8bae1dSRodney W. Grimes 			dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
1712df8bae1dSRodney W. Grimes 		    else
17133efc3014SJulian Elischer 			dest = pkt_dst.s_addr;
1714df8bae1dSRodney W. Grimes 		    /* Router requirements says to only send host redirects */
1715df8bae1dSRodney W. Grimes 		    type = ICMP_REDIRECT;
1716df8bae1dSRodney W. Grimes 		    code = ICMP_REDIRECT_HOST;
1717df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1718df8bae1dSRodney W. Grimes 		    if (ipprintfs)
1719df8bae1dSRodney W. Grimes 		        printf("redirect (%d) to %lx\n", code, (u_long)dest);
1720df8bae1dSRodney W. Grimes #endif
1721df8bae1dSRodney W. Grimes 		}
1722df8bae1dSRodney W. Grimes 	}
1723df8bae1dSRodney W. Grimes 
1724b97d15cbSGarrett Wollman 	error = ip_output(m, (struct mbuf *)0, &ipforward_rt,
1725b97d15cbSGarrett Wollman 			  IP_FORWARDING, 0);
1726df8bae1dSRodney W. Grimes 	if (error)
1727df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1728df8bae1dSRodney W. Grimes 	else {
1729df8bae1dSRodney W. Grimes 		ipstat.ips_forward++;
1730df8bae1dSRodney W. Grimes 		if (type)
1731df8bae1dSRodney W. Grimes 			ipstat.ips_redirectsent++;
1732df8bae1dSRodney W. Grimes 		else {
17331f91d8c5SDavid Greenman 			if (mcopy) {
17341f91d8c5SDavid Greenman 				ipflow_create(&ipforward_rt, mcopy);
1735df8bae1dSRodney W. Grimes 				m_freem(mcopy);
17361f91d8c5SDavid Greenman 			}
1737df8bae1dSRodney W. Grimes 			return;
1738df8bae1dSRodney W. Grimes 		}
1739df8bae1dSRodney W. Grimes 	}
1740df8bae1dSRodney W. Grimes 	if (mcopy == NULL)
1741df8bae1dSRodney W. Grimes 		return;
1742df8bae1dSRodney W. Grimes 	destifp = NULL;
1743df8bae1dSRodney W. Grimes 
1744df8bae1dSRodney W. Grimes 	switch (error) {
1745df8bae1dSRodney W. Grimes 
1746df8bae1dSRodney W. Grimes 	case 0:				/* forwarded, but need redirect */
1747df8bae1dSRodney W. Grimes 		/* type, code set above */
1748df8bae1dSRodney W. Grimes 		break;
1749df8bae1dSRodney W. Grimes 
1750df8bae1dSRodney W. Grimes 	case ENETUNREACH:		/* shouldn't happen, checked above */
1751df8bae1dSRodney W. Grimes 	case EHOSTUNREACH:
1752df8bae1dSRodney W. Grimes 	case ENETDOWN:
1753df8bae1dSRodney W. Grimes 	case EHOSTDOWN:
1754df8bae1dSRodney W. Grimes 	default:
1755df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1756df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_HOST;
1757df8bae1dSRodney W. Grimes 		break;
1758df8bae1dSRodney W. Grimes 
1759df8bae1dSRodney W. Grimes 	case EMSGSIZE:
1760df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1761df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_NEEDFRAG;
17626a800098SYoshinobu Inoue #ifndef IPSEC
1763df8bae1dSRodney W. Grimes 		if (ipforward_rt.ro_rt)
1764df8bae1dSRodney W. Grimes 			destifp = ipforward_rt.ro_rt->rt_ifp;
17656a800098SYoshinobu Inoue #else
17666a800098SYoshinobu Inoue 		/*
17676a800098SYoshinobu Inoue 		 * If the packet is routed over IPsec tunnel, tell the
17686a800098SYoshinobu Inoue 		 * originator the tunnel MTU.
17696a800098SYoshinobu Inoue 		 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
17706a800098SYoshinobu Inoue 		 * XXX quickhack!!!
17716a800098SYoshinobu Inoue 		 */
17726a800098SYoshinobu Inoue 		if (ipforward_rt.ro_rt) {
17736a800098SYoshinobu Inoue 			struct secpolicy *sp = NULL;
17746a800098SYoshinobu Inoue 			int ipsecerror;
17756a800098SYoshinobu Inoue 			int ipsechdr;
17766a800098SYoshinobu Inoue 			struct route *ro;
17776a800098SYoshinobu Inoue 
17786a800098SYoshinobu Inoue 			sp = ipsec4_getpolicybyaddr(mcopy,
17796a800098SYoshinobu Inoue 						    IPSEC_DIR_OUTBOUND,
17806a800098SYoshinobu Inoue 			                            IP_FORWARDING,
17816a800098SYoshinobu Inoue 			                            &ipsecerror);
17826a800098SYoshinobu Inoue 
17836a800098SYoshinobu Inoue 			if (sp == NULL)
17846a800098SYoshinobu Inoue 				destifp = ipforward_rt.ro_rt->rt_ifp;
17856a800098SYoshinobu Inoue 			else {
17866a800098SYoshinobu Inoue 				/* count IPsec header size */
17876a800098SYoshinobu Inoue 				ipsechdr = ipsec4_hdrsiz(mcopy,
17886a800098SYoshinobu Inoue 							 IPSEC_DIR_OUTBOUND,
17896a800098SYoshinobu Inoue 							 NULL);
17906a800098SYoshinobu Inoue 
17916a800098SYoshinobu Inoue 				/*
17926a800098SYoshinobu Inoue 				 * find the correct route for outer IPv4
17936a800098SYoshinobu Inoue 				 * header, compute tunnel MTU.
17946a800098SYoshinobu Inoue 				 *
17956a800098SYoshinobu Inoue 				 * XXX BUG ALERT
17966a800098SYoshinobu Inoue 				 * The "dummyifp" code relies upon the fact
17976a800098SYoshinobu Inoue 				 * that icmp_error() touches only ifp->if_mtu.
17986a800098SYoshinobu Inoue 				 */
17996a800098SYoshinobu Inoue 				/*XXX*/
18006a800098SYoshinobu Inoue 				destifp = NULL;
18016a800098SYoshinobu Inoue 				if (sp->req != NULL
18026a800098SYoshinobu Inoue 				 && sp->req->sav != NULL
18036a800098SYoshinobu Inoue 				 && sp->req->sav->sah != NULL) {
18046a800098SYoshinobu Inoue 					ro = &sp->req->sav->sah->sa_route;
18056a800098SYoshinobu Inoue 					if (ro->ro_rt && ro->ro_rt->rt_ifp) {
18066a800098SYoshinobu Inoue 						dummyifp.if_mtu =
18076a800098SYoshinobu Inoue 						    ro->ro_rt->rt_ifp->if_mtu;
18086a800098SYoshinobu Inoue 						dummyifp.if_mtu -= ipsechdr;
18096a800098SYoshinobu Inoue 						destifp = &dummyifp;
18106a800098SYoshinobu Inoue 					}
18116a800098SYoshinobu Inoue 				}
18126a800098SYoshinobu Inoue 
18136a800098SYoshinobu Inoue 				key_freesp(sp);
18146a800098SYoshinobu Inoue 			}
18156a800098SYoshinobu Inoue 		}
18166a800098SYoshinobu Inoue #endif /*IPSEC*/
1817df8bae1dSRodney W. Grimes 		ipstat.ips_cantfrag++;
1818df8bae1dSRodney W. Grimes 		break;
1819df8bae1dSRodney W. Grimes 
1820df8bae1dSRodney W. Grimes 	case ENOBUFS:
1821df8bae1dSRodney W. Grimes 		type = ICMP_SOURCEQUENCH;
1822df8bae1dSRodney W. Grimes 		code = 0;
1823df8bae1dSRodney W. Grimes 		break;
18243a06e3e0SRuslan Ermilov 
18253a06e3e0SRuslan Ermilov 	case EACCES:			/* ipfw denied packet */
18263a06e3e0SRuslan Ermilov 		m_freem(mcopy);
18273a06e3e0SRuslan Ermilov 		return;
1828df8bae1dSRodney W. Grimes 	}
1829df8bae1dSRodney W. Grimes 	icmp_error(mcopy, type, code, dest, destifp);
1830df8bae1dSRodney W. Grimes }
1831df8bae1dSRodney W. Grimes 
183282c23ebaSBill Fenner void
183382c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m)
183482c23ebaSBill Fenner 	register struct inpcb *inp;
183582c23ebaSBill Fenner 	register struct mbuf **mp;
183682c23ebaSBill Fenner 	register struct ip *ip;
183782c23ebaSBill Fenner 	register struct mbuf *m;
183882c23ebaSBill Fenner {
1839243917feSSeigo Tanimura 	SOCK_LOCK(inp->inp_socket);
184082c23ebaSBill Fenner 	if (inp->inp_socket->so_options & SO_TIMESTAMP) {
184182c23ebaSBill Fenner 		struct timeval tv;
184282c23ebaSBill Fenner 
1843243917feSSeigo Tanimura 		SOCK_UNLOCK(inp->inp_socket);
184482c23ebaSBill Fenner 		microtime(&tv);
184582c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
184682c23ebaSBill Fenner 			SCM_TIMESTAMP, SOL_SOCKET);
184782c23ebaSBill Fenner 		if (*mp)
184882c23ebaSBill Fenner 			mp = &(*mp)->m_next;
1849243917feSSeigo Tanimura 	} else
1850243917feSSeigo Tanimura 		SOCK_UNLOCK(inp->inp_socket);
185182c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVDSTADDR) {
185282c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
185382c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
185482c23ebaSBill Fenner 		if (*mp)
185582c23ebaSBill Fenner 			mp = &(*mp)->m_next;
185682c23ebaSBill Fenner 	}
185782c23ebaSBill Fenner #ifdef notyet
185882c23ebaSBill Fenner 	/* XXX
185982c23ebaSBill Fenner 	 * Moving these out of udp_input() made them even more broken
186082c23ebaSBill Fenner 	 * than they already were.
186182c23ebaSBill Fenner 	 */
186282c23ebaSBill Fenner 	/* options were tossed already */
186382c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVOPTS) {
186482c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) opts_deleted_above,
186582c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
186682c23ebaSBill Fenner 		if (*mp)
186782c23ebaSBill Fenner 			mp = &(*mp)->m_next;
186882c23ebaSBill Fenner 	}
186982c23ebaSBill Fenner 	/* ip_srcroute doesn't do what we want here, need to fix */
187082c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVRETOPTS) {
187182c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) ip_srcroute(),
187282c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
187382c23ebaSBill Fenner 		if (*mp)
187482c23ebaSBill Fenner 			mp = &(*mp)->m_next;
187582c23ebaSBill Fenner 	}
187682c23ebaSBill Fenner #endif
187782c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVIF) {
1878d314ad7bSJulian Elischer 		struct ifnet *ifp;
1879d314ad7bSJulian Elischer 		struct sdlbuf {
188082c23ebaSBill Fenner 			struct sockaddr_dl sdl;
1881d314ad7bSJulian Elischer 			u_char	pad[32];
1882d314ad7bSJulian Elischer 		} sdlbuf;
1883d314ad7bSJulian Elischer 		struct sockaddr_dl *sdp;
1884d314ad7bSJulian Elischer 		struct sockaddr_dl *sdl2 = &sdlbuf.sdl;
188582c23ebaSBill Fenner 
1886d314ad7bSJulian Elischer 		if (((ifp = m->m_pkthdr.rcvif))
1887d314ad7bSJulian Elischer 		&& ( ifp->if_index && (ifp->if_index <= if_index))) {
1888f9132cebSJonathan Lemon 			sdp = (struct sockaddr_dl *)
1889f9132cebSJonathan Lemon 			    (ifaddr_byindex(ifp->if_index)->ifa_addr);
1890d314ad7bSJulian Elischer 			/*
1891d314ad7bSJulian Elischer 			 * Change our mind and don't try copy.
1892d314ad7bSJulian Elischer 			 */
1893d314ad7bSJulian Elischer 			if ((sdp->sdl_family != AF_LINK)
1894d314ad7bSJulian Elischer 			|| (sdp->sdl_len > sizeof(sdlbuf))) {
1895d314ad7bSJulian Elischer 				goto makedummy;
1896d314ad7bSJulian Elischer 			}
1897d314ad7bSJulian Elischer 			bcopy(sdp, sdl2, sdp->sdl_len);
1898d314ad7bSJulian Elischer 		} else {
1899d314ad7bSJulian Elischer makedummy:
1900d314ad7bSJulian Elischer 			sdl2->sdl_len
1901d314ad7bSJulian Elischer 				= offsetof(struct sockaddr_dl, sdl_data[0]);
1902d314ad7bSJulian Elischer 			sdl2->sdl_family = AF_LINK;
1903d314ad7bSJulian Elischer 			sdl2->sdl_index = 0;
1904d314ad7bSJulian Elischer 			sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;
1905d314ad7bSJulian Elischer 		}
1906d314ad7bSJulian Elischer 		*mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,
190782c23ebaSBill Fenner 			IP_RECVIF, IPPROTO_IP);
190882c23ebaSBill Fenner 		if (*mp)
190982c23ebaSBill Fenner 			mp = &(*mp)->m_next;
191082c23ebaSBill Fenner 	}
191182c23ebaSBill Fenner }
191282c23ebaSBill Fenner 
1913df8bae1dSRodney W. Grimes int
1914f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so)
1915f0068c4aSGarrett Wollman {
1916f0068c4aSGarrett Wollman 	if (so->so_type != SOCK_RAW ||
1917f0068c4aSGarrett Wollman 	    so->so_proto->pr_protocol != IPPROTO_RSVP)
1918f0068c4aSGarrett Wollman 	  return EOPNOTSUPP;
1919f0068c4aSGarrett Wollman 
1920f0068c4aSGarrett Wollman 	if (ip_rsvpd != NULL)
1921f0068c4aSGarrett Wollman 	  return EADDRINUSE;
1922f0068c4aSGarrett Wollman 
1923f0068c4aSGarrett Wollman 	ip_rsvpd = so;
19241c5de19aSGarrett Wollman 	/*
19251c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-increment
19261c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
19271c5de19aSGarrett Wollman 	 */
19281c5de19aSGarrett Wollman 	if (!ip_rsvp_on) {
19291c5de19aSGarrett Wollman 		ip_rsvp_on = 1;
19301c5de19aSGarrett Wollman 		rsvp_on++;
19311c5de19aSGarrett Wollman 	}
1932f0068c4aSGarrett Wollman 
1933f0068c4aSGarrett Wollman 	return 0;
1934f0068c4aSGarrett Wollman }
1935f0068c4aSGarrett Wollman 
1936f0068c4aSGarrett Wollman int
1937f0068c4aSGarrett Wollman ip_rsvp_done(void)
1938f0068c4aSGarrett Wollman {
1939f0068c4aSGarrett Wollman 	ip_rsvpd = NULL;
19401c5de19aSGarrett Wollman 	/*
19411c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-decrement
19421c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
19431c5de19aSGarrett Wollman 	 */
19441c5de19aSGarrett Wollman 	if (ip_rsvp_on) {
19451c5de19aSGarrett Wollman 		ip_rsvp_on = 0;
19461c5de19aSGarrett Wollman 		rsvp_on--;
19471c5de19aSGarrett Wollman 	}
1948f0068c4aSGarrett Wollman 	return 0;
1949f0068c4aSGarrett Wollman }
1950