xref: /freebsd/sys/netinet/ip_input.c (revision db4f9cc70389b2004594fea6f910e5091855ddf8)
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"
4674a9466cSGary Palmer 
4782c23ebaSBill Fenner #include <stddef.h>
4882c23ebaSBill Fenner 
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 
61df8bae1dSRodney W. Grimes #include <net/if.h>
62d314ad7bSJulian Elischer #include <net/if_var.h>
6382c23ebaSBill Fenner #include <net/if_dl.h>
64df8bae1dSRodney W. Grimes #include <net/route.h>
65748e0b0aSGarrett Wollman #include <net/netisr.h>
66367d34f8SBrian Somers #include <net/intrq.h>
67df8bae1dSRodney W. Grimes 
68df8bae1dSRodney W. Grimes #include <netinet/in.h>
69df8bae1dSRodney W. Grimes #include <netinet/in_systm.h>
70b5e8ce9fSBruce Evans #include <netinet/in_var.h>
71df8bae1dSRodney W. Grimes #include <netinet/ip.h>
72df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h>
73df8bae1dSRodney W. Grimes #include <netinet/ip_var.h>
74df8bae1dSRodney W. Grimes #include <netinet/ip_icmp.h>
7558938916SGarrett Wollman #include <machine/in_cksum.h>
76df8bae1dSRodney W. Grimes 
776a800098SYoshinobu Inoue #include <netinet/ipprotosw.h>
786a800098SYoshinobu Inoue 
79f0068c4aSGarrett Wollman #include <sys/socketvar.h>
806ddbf1e2SGary Palmer 
816ddbf1e2SGary Palmer #include <netinet/ip_fw.h>
826ddbf1e2SGary Palmer 
836a800098SYoshinobu Inoue #ifdef IPSEC
846a800098SYoshinobu Inoue #include <netinet6/ipsec.h>
856a800098SYoshinobu Inoue #include <netkey/key.h>
866a800098SYoshinobu Inoue #ifdef IPSEC_DEBUG
876a800098SYoshinobu Inoue #include <netkey/key_debug.h>
886a800098SYoshinobu Inoue #else
896a800098SYoshinobu Inoue #define KEYDEBUG(lev,arg)
906a800098SYoshinobu Inoue #endif
916a800098SYoshinobu Inoue #endif
926a800098SYoshinobu Inoue 
936a800098SYoshinobu Inoue #include "faith.h"
946a800098SYoshinobu Inoue #if defined(NFAITH) && NFAITH > 0
956a800098SYoshinobu Inoue #include <net/if_types.h>
966a800098SYoshinobu Inoue #endif
976a800098SYoshinobu Inoue 
98b715f178SLuigi Rizzo #ifdef DUMMYNET
99b715f178SLuigi Rizzo #include <netinet/ip_dummynet.h>
100b715f178SLuigi Rizzo #endif
101b715f178SLuigi Rizzo 
1021c5de19aSGarrett Wollman int rsvp_on = 0;
103f708ef1bSPoul-Henning Kamp static int ip_rsvp_on;
104f0068c4aSGarrett Wollman struct socket *ip_rsvpd;
105f0068c4aSGarrett Wollman 
1061f91d8c5SDavid Greenman int	ipforwarding = 0;
1070312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW,
1083d177f46SBill Fumerola     &ipforwarding, 0, "Enable IP forwarding between interfaces");
1090312fbe9SPoul-Henning Kamp 
110d4fb926cSGarrett Wollman static int	ipsendredirects = 1; /* XXX */
1110312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW,
1123d177f46SBill Fumerola     &ipsendredirects, 0, "Enable sending IP redirects");
1130312fbe9SPoul-Henning Kamp 
114df8bae1dSRodney W. Grimes int	ip_defttl = IPDEFTTL;
1150312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFTTL, ttl, CTLFLAG_RW,
1163d177f46SBill Fumerola     &ip_defttl, 0, "Maximum TTL on IP packets");
1170312fbe9SPoul-Henning Kamp 
1180312fbe9SPoul-Henning Kamp static int	ip_dosourceroute = 0;
1190312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_SOURCEROUTE, sourceroute, CTLFLAG_RW,
1203d177f46SBill Fumerola     &ip_dosourceroute, 0, "Enable forwarding source routed IP packets");
1214fce5804SGuido van Rooij 
1224fce5804SGuido van Rooij static int	ip_acceptsourceroute = 0;
1234fce5804SGuido van Rooij SYSCTL_INT(_net_inet_ip, IPCTL_ACCEPTSOURCEROUTE, accept_sourceroute,
1243d177f46SBill Fumerola     CTLFLAG_RW, &ip_acceptsourceroute, 0,
1253d177f46SBill Fumerola     "Enable accepting source routed IP packets");
1266a800098SYoshinobu Inoue 
1276a800098SYoshinobu Inoue static int	ip_keepfaith = 0;
1286a800098SYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
1296a800098SYoshinobu Inoue 	&ip_keepfaith,	0,
1306a800098SYoshinobu Inoue 	"Enable packet capture for FAITH IPv4->IPv6 translater daemon");
1316a800098SYoshinobu Inoue 
132df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1330312fbe9SPoul-Henning Kamp static int	ipprintfs = 0;
134df8bae1dSRodney W. Grimes #endif
135df8bae1dSRodney W. Grimes 
136df8bae1dSRodney W. Grimes extern	struct domain inetdomain;
1376a800098SYoshinobu Inoue extern	struct ipprotosw inetsw[];
138df8bae1dSRodney W. Grimes u_char	ip_protox[IPPROTO_MAX];
1390312fbe9SPoul-Henning Kamp static int	ipqmaxlen = IFQ_MAXLEN;
14059562606SGarrett Wollman struct	in_ifaddrhead in_ifaddrhead; /* first inet address */
141afed1375SDavid Greenman SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW,
1423d177f46SBill Fumerola     &ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue");
1430312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
1443d177f46SBill Fumerola     &ipintrq.ifq_drops, 0, "Number of packets dropped from the IP input queue");
145df8bae1dSRodney W. Grimes 
146f23b4c91SGarrett Wollman struct ipstat ipstat;
1476fce01c9SGarrett Wollman SYSCTL_STRUCT(_net_inet_ip, IPCTL_STATS, stats, CTLFLAG_RD,
1483d177f46SBill Fumerola     &ipstat, ipstat, "IP statistics (struct ipstat, netinet/ip_var.h)");
149194a213eSAndrey A. Chernov 
150194a213eSAndrey A. Chernov /* Packet reassembly stuff */
151194a213eSAndrey A. Chernov #define IPREASS_NHASH_LOG2      6
152194a213eSAndrey A. Chernov #define IPREASS_NHASH           (1 << IPREASS_NHASH_LOG2)
153194a213eSAndrey A. Chernov #define IPREASS_HMASK           (IPREASS_NHASH - 1)
154194a213eSAndrey A. Chernov #define IPREASS_HASH(x,y) \
155831a80b0SMatthew Dillon 	(((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
156194a213eSAndrey A. Chernov 
157194a213eSAndrey A. Chernov static struct ipq ipq[IPREASS_NHASH];
158194a213eSAndrey A. Chernov static int    nipq = 0;         /* total # of reass queues */
159194a213eSAndrey A. Chernov static int    maxnipq;
160367d34f8SBrian Somers const  int    ipintrq_present = 1;
161f23b4c91SGarrett Wollman 
1620312fbe9SPoul-Henning Kamp #ifdef IPCTL_DEFMTU
1630312fbe9SPoul-Henning Kamp SYSCTL_INT(_net_inet_ip, IPCTL_DEFMTU, mtu, CTLFLAG_RW,
1643d177f46SBill Fumerola     &ip_mtu, 0, "Default MTU");
1650312fbe9SPoul-Henning Kamp #endif
1660312fbe9SPoul-Henning Kamp 
1671b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
1681b968362SDag-Erling Smørgrav static int	ipstealth = 0;
1691b968362SDag-Erling Smørgrav SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_RW,
1701b968362SDag-Erling Smørgrav     &ipstealth, 0, "");
1711b968362SDag-Erling Smørgrav #endif
1721b968362SDag-Erling Smørgrav 
173cfe8b629SGarrett Wollman 
17423bf9953SPoul-Henning Kamp /* Firewall hooks */
17523bf9953SPoul-Henning Kamp ip_fw_chk_t *ip_fw_chk_ptr;
17623bf9953SPoul-Henning Kamp ip_fw_ctl_t *ip_fw_ctl_ptr;
1779fcc0795SLuigi Rizzo int fw_enable = 1 ;
178e7319babSPoul-Henning Kamp 
179b715f178SLuigi Rizzo #ifdef DUMMYNET
180b715f178SLuigi Rizzo ip_dn_ctl_t *ip_dn_ctl_ptr;
181b715f178SLuigi Rizzo #endif
182b715f178SLuigi Rizzo 
183afed1b49SDarren Reed int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)) = NULL;
184afed1b49SDarren Reed 
185afed1b49SDarren Reed 
186e7319babSPoul-Henning Kamp /*
187df8bae1dSRodney W. Grimes  * We need to save the IP options in case a protocol wants to respond
188df8bae1dSRodney W. Grimes  * to an incoming packet over the same route if the packet got here
189df8bae1dSRodney W. Grimes  * using IP source routing.  This allows connection establishment and
190df8bae1dSRodney W. Grimes  * maintenance when the remote end is on a network that is not known
191df8bae1dSRodney W. Grimes  * to us.
192df8bae1dSRodney W. Grimes  */
1930312fbe9SPoul-Henning Kamp static int	ip_nhops = 0;
194df8bae1dSRodney W. Grimes static	struct ip_srcrt {
195df8bae1dSRodney W. Grimes 	struct	in_addr dst;			/* final destination */
196df8bae1dSRodney W. Grimes 	char	nop;				/* one NOP to align */
197df8bae1dSRodney W. Grimes 	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
198df8bae1dSRodney W. Grimes 	struct	in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
199df8bae1dSRodney W. Grimes } ip_srcrt;
200df8bae1dSRodney W. Grimes 
201f9e354dfSJulian Elischer struct sockaddr_in *ip_fw_fwd_addr;
202f9e354dfSJulian Elischer 
203df8bae1dSRodney W. Grimes static void	save_rte __P((u_char *, struct in_addr));
2040312fbe9SPoul-Henning Kamp static int	ip_dooptions __P((struct mbuf *));
2050312fbe9SPoul-Henning Kamp static void	ip_forward __P((struct mbuf *, int));
2060312fbe9SPoul-Henning Kamp static void	ip_freef __P((struct ipq *));
2078948e4baSArchie Cobbs #ifdef IPDIVERT
2086a800098SYoshinobu Inoue static struct	mbuf *ip_reass __P((struct mbuf *,
2098948e4baSArchie Cobbs 			struct ipq *, struct ipq *, u_int32_t *, u_int16_t *));
2108948e4baSArchie Cobbs #else
2116a800098SYoshinobu Inoue static struct	mbuf *ip_reass __P((struct mbuf *, struct ipq *, struct ipq *));
2128948e4baSArchie Cobbs #endif
2138948e4baSArchie Cobbs static struct	in_ifaddr *ip_rtaddr __P((struct in_addr));
2140312fbe9SPoul-Henning Kamp static void	ipintr __P((void));
2158948e4baSArchie Cobbs 
216df8bae1dSRodney W. Grimes /*
217df8bae1dSRodney W. Grimes  * IP initialization: fill in IP protocol switch table.
218df8bae1dSRodney W. Grimes  * All protocols not implemented in kernel go to raw IP protocol handler.
219df8bae1dSRodney W. Grimes  */
220df8bae1dSRodney W. Grimes void
221df8bae1dSRodney W. Grimes ip_init()
222df8bae1dSRodney W. Grimes {
2236a800098SYoshinobu Inoue 	register struct ipprotosw *pr;
224df8bae1dSRodney W. Grimes 	register int i;
225df8bae1dSRodney W. Grimes 
22659562606SGarrett Wollman 	TAILQ_INIT(&in_ifaddrhead);
2276a800098SYoshinobu Inoue 	pr = (struct ipprotosw *)pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
228df8bae1dSRodney W. Grimes 	if (pr == 0)
229df8bae1dSRodney W. Grimes 		panic("ip_init");
230df8bae1dSRodney W. Grimes 	for (i = 0; i < IPPROTO_MAX; i++)
231df8bae1dSRodney W. Grimes 		ip_protox[i] = pr - inetsw;
2326a800098SYoshinobu Inoue 	for (pr = (struct ipprotosw *)inetdomain.dom_protosw;
2336a800098SYoshinobu Inoue 	    pr < (struct ipprotosw *)inetdomain.dom_protoswNPROTOSW; pr++)
234df8bae1dSRodney W. Grimes 		if (pr->pr_domain->dom_family == PF_INET &&
235df8bae1dSRodney W. Grimes 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
236df8bae1dSRodney W. Grimes 			ip_protox[pr->pr_protocol] = pr - inetsw;
237194a213eSAndrey A. Chernov 
238194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++)
239194a213eSAndrey A. Chernov 	    ipq[i].next = ipq[i].prev = &ipq[i];
240194a213eSAndrey A. Chernov 
241194a213eSAndrey A. Chernov 	maxnipq = nmbclusters/4;
242194a213eSAndrey A. Chernov 
243227ee8a1SPoul-Henning Kamp 	ip_id = time_second & 0xffff;
244df8bae1dSRodney W. Grimes 	ipintrq.ifq_maxlen = ipqmaxlen;
245242c5536SPeter Wemm 
246242c5536SPeter Wemm 	register_netisr(NETISR_IP, ipintr);
247df8bae1dSRodney W. Grimes }
248df8bae1dSRodney W. Grimes 
2490312fbe9SPoul-Henning Kamp static struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
250f708ef1bSPoul-Henning Kamp static struct	route ipforward_rt;
251df8bae1dSRodney W. Grimes 
252df8bae1dSRodney W. Grimes /*
253df8bae1dSRodney W. Grimes  * Ip input routine.  Checksum and byte swap header.  If fragmented
254df8bae1dSRodney W. Grimes  * try to reassemble.  Process options.  Pass to next level.
255df8bae1dSRodney W. Grimes  */
256c67b1d17SGarrett Wollman void
257c67b1d17SGarrett Wollman ip_input(struct mbuf *m)
258df8bae1dSRodney W. Grimes {
25923bf9953SPoul-Henning Kamp 	struct ip *ip;
26023bf9953SPoul-Henning Kamp 	struct ipq *fp;
26123bf9953SPoul-Henning Kamp 	struct in_ifaddr *ia;
2626effc713SDoug Rabson 	int    i, hlen, mff;
26347c861ecSBrian Somers 	u_short sum;
2648948e4baSArchie Cobbs 	u_int16_t divert_cookie;		/* firewall cookie */
2658948e4baSArchie Cobbs #ifdef IPDIVERT
2668948e4baSArchie Cobbs 	u_int32_t divert_info = 0;		/* packet divert/tee info */
267b715f178SLuigi Rizzo #endif
268b715f178SLuigi Rizzo 	struct ip_fw_chain *rule = NULL;
269b715f178SLuigi Rizzo 
2708948e4baSArchie Cobbs #ifdef IPDIVERT
2718948e4baSArchie Cobbs 	/* Get and reset firewall cookie */
2728948e4baSArchie Cobbs 	divert_cookie = ip_divert_cookie;
2738948e4baSArchie Cobbs 	ip_divert_cookie = 0;
2748948e4baSArchie Cobbs #else
2758948e4baSArchie Cobbs 	divert_cookie = 0;
2768948e4baSArchie Cobbs #endif
2778948e4baSArchie Cobbs 
278b715f178SLuigi Rizzo #if defined(IPFIREWALL) && defined(DUMMYNET)
279b715f178SLuigi Rizzo         /*
280b715f178SLuigi Rizzo          * dummynet packet are prepended a vestigial mbuf with
281b715f178SLuigi Rizzo          * m_type = MT_DUMMYNET and m_data pointing to the matching
282b715f178SLuigi Rizzo          * rule.
283b715f178SLuigi Rizzo          */
284b715f178SLuigi Rizzo         if (m->m_type == MT_DUMMYNET) {
285b715f178SLuigi Rizzo             rule = (struct ip_fw_chain *)(m->m_data) ;
286b715f178SLuigi Rizzo             m = m->m_next ;
287b715f178SLuigi Rizzo             ip = mtod(m, struct ip *);
288b715f178SLuigi Rizzo             hlen = IP_VHL_HL(ip->ip_vhl) << 2;
289b715f178SLuigi Rizzo             goto iphack ;
290b715f178SLuigi Rizzo         } else
291b715f178SLuigi Rizzo             rule = NULL ;
292b715f178SLuigi Rizzo #endif
293df8bae1dSRodney W. Grimes 
294df8bae1dSRodney W. Grimes #ifdef	DIAGNOSTIC
295ed7509acSJulian Elischer 	if (m == NULL || (m->m_flags & M_PKTHDR) == 0)
29658938916SGarrett Wollman 		panic("ip_input no HDR");
297df8bae1dSRodney W. Grimes #endif
298df8bae1dSRodney W. Grimes 	ipstat.ips_total++;
29958938916SGarrett Wollman 
30058938916SGarrett Wollman 	if (m->m_pkthdr.len < sizeof(struct ip))
30158938916SGarrett Wollman 		goto tooshort;
30258938916SGarrett Wollman 
303df8bae1dSRodney W. Grimes 	if (m->m_len < sizeof (struct ip) &&
304df8bae1dSRodney W. Grimes 	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
305df8bae1dSRodney W. Grimes 		ipstat.ips_toosmall++;
306c67b1d17SGarrett Wollman 		return;
307df8bae1dSRodney W. Grimes 	}
308df8bae1dSRodney W. Grimes 	ip = mtod(m, struct ip *);
30958938916SGarrett Wollman 
31058938916SGarrett Wollman 	if (IP_VHL_V(ip->ip_vhl) != IPVERSION) {
311df8bae1dSRodney W. Grimes 		ipstat.ips_badvers++;
312df8bae1dSRodney W. Grimes 		goto bad;
313df8bae1dSRodney W. Grimes 	}
31458938916SGarrett Wollman 
31558938916SGarrett Wollman 	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
316df8bae1dSRodney W. Grimes 	if (hlen < sizeof(struct ip)) {	/* minimum header length */
317df8bae1dSRodney W. Grimes 		ipstat.ips_badhlen++;
318df8bae1dSRodney W. Grimes 		goto bad;
319df8bae1dSRodney W. Grimes 	}
320df8bae1dSRodney W. Grimes 	if (hlen > m->m_len) {
321df8bae1dSRodney W. Grimes 		if ((m = m_pullup(m, hlen)) == 0) {
322df8bae1dSRodney W. Grimes 			ipstat.ips_badhlen++;
323c67b1d17SGarrett Wollman 			return;
324df8bae1dSRodney W. Grimes 		}
325df8bae1dSRodney W. Grimes 		ip = mtod(m, struct ip *);
326df8bae1dSRodney W. Grimes 	}
327db4f9cc7SJonathan Lemon 	if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
328db4f9cc7SJonathan Lemon 		sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
329db4f9cc7SJonathan Lemon 	} else {
33058938916SGarrett Wollman 		if (hlen == sizeof(struct ip)) {
33147c861ecSBrian Somers 			sum = in_cksum_hdr(ip);
33258938916SGarrett Wollman 		} else {
33347c861ecSBrian Somers 			sum = in_cksum(m, hlen);
33458938916SGarrett Wollman 		}
335db4f9cc7SJonathan Lemon 	}
33647c861ecSBrian Somers 	if (sum) {
337df8bae1dSRodney W. Grimes 		ipstat.ips_badsum++;
338df8bae1dSRodney W. Grimes 		goto bad;
339df8bae1dSRodney W. Grimes 	}
340df8bae1dSRodney W. Grimes 
341df8bae1dSRodney W. Grimes 	/*
342df8bae1dSRodney W. Grimes 	 * Convert fields to host representation.
343df8bae1dSRodney W. Grimes 	 */
344df8bae1dSRodney W. Grimes 	NTOHS(ip->ip_len);
345df8bae1dSRodney W. Grimes 	if (ip->ip_len < hlen) {
346df8bae1dSRodney W. Grimes 		ipstat.ips_badlen++;
347df8bae1dSRodney W. Grimes 		goto bad;
348df8bae1dSRodney W. Grimes 	}
349df8bae1dSRodney W. Grimes 	NTOHS(ip->ip_id);
350df8bae1dSRodney W. Grimes 	NTOHS(ip->ip_off);
351df8bae1dSRodney W. Grimes 
352df8bae1dSRodney W. Grimes 	/*
353df8bae1dSRodney W. Grimes 	 * Check that the amount of data in the buffers
354df8bae1dSRodney W. Grimes 	 * is as at least much as the IP header would have us expect.
355df8bae1dSRodney W. Grimes 	 * Trim mbufs if longer than we expect.
356df8bae1dSRodney W. Grimes 	 * Drop packet if shorter than we expect.
357df8bae1dSRodney W. Grimes 	 */
358df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len < ip->ip_len) {
35958938916SGarrett Wollman tooshort:
360df8bae1dSRodney W. Grimes 		ipstat.ips_tooshort++;
361df8bae1dSRodney W. Grimes 		goto bad;
362df8bae1dSRodney W. Grimes 	}
363df8bae1dSRodney W. Grimes 	if (m->m_pkthdr.len > ip->ip_len) {
364df8bae1dSRodney W. Grimes 		if (m->m_len == m->m_pkthdr.len) {
365df8bae1dSRodney W. Grimes 			m->m_len = ip->ip_len;
366df8bae1dSRodney W. Grimes 			m->m_pkthdr.len = ip->ip_len;
367df8bae1dSRodney W. Grimes 		} else
368df8bae1dSRodney W. Grimes 			m_adj(m, ip->ip_len - m->m_pkthdr.len);
369df8bae1dSRodney W. Grimes 	}
3704dd1662bSUgen J.S. Antsilevich 	/*
3714dd1662bSUgen J.S. Antsilevich 	 * IpHack's section.
3724dd1662bSUgen J.S. Antsilevich 	 * Right now when no processing on packet has done
3734dd1662bSUgen J.S. Antsilevich 	 * and it is still fresh out of network we do our black
3744dd1662bSUgen J.S. Antsilevich 	 * deals with it.
37593e0e116SJulian Elischer 	 * - Firewall: deny/allow/divert
376fed1c7e9SSøren Schmidt 	 * - Xlate: translate packet's addr/port (NAT).
377b715f178SLuigi Rizzo 	 * - Pipe: pass pkt through dummynet.
3784dd1662bSUgen J.S. Antsilevich 	 * - Wrap: fake packet's addr/port <unimpl.>
3794dd1662bSUgen J.S. Antsilevich 	 * - Encapsulate: put it in another IP and send out. <unimp.>
3804dd1662bSUgen J.S. Antsilevich  	 */
381b715f178SLuigi Rizzo 
382dee383e0SEivind Eklund #if defined(IPFIREWALL) && defined(DUMMYNET)
383b715f178SLuigi Rizzo iphack:
384dee383e0SEivind Eklund #endif
385beec8214SDarren Reed 	/*
386beec8214SDarren Reed 	 * Check if we want to allow this packet to be processed.
387beec8214SDarren Reed 	 * Consider it to be bad if not.
388beec8214SDarren Reed 	 */
3891ee25934SPeter Wemm 	if (fr_checkp) {
390beec8214SDarren Reed 		struct	mbuf	*m1 = m;
391df8bae1dSRodney W. Grimes 
392beec8214SDarren Reed 		if ((*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m1) || !m1)
393beec8214SDarren Reed 			return;
394beec8214SDarren Reed 		ip = mtod(m = m1, struct ip *);
395beec8214SDarren Reed 	}
3966bc748b0SLuigi Rizzo 	if (fw_enable && ip_fw_chk_ptr) {
397f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD
398f9e354dfSJulian Elischer 		/*
399f9e354dfSJulian Elischer 		 * If we've been forwarded from the output side, then
400f9e354dfSJulian Elischer 		 * skip the firewall a second time
401f9e354dfSJulian Elischer 		 */
402f9e354dfSJulian Elischer 		if (ip_fw_fwd_addr)
403f9e354dfSJulian Elischer 			goto ours;
404f9e354dfSJulian Elischer #endif	/* IPFIREWALL_FORWARD */
405f9e354dfSJulian Elischer 		/*
4068948e4baSArchie Cobbs 		 * See the comment in ip_output for the return values
407b715f178SLuigi Rizzo 		 * produced by the firewall.
408f9e354dfSJulian Elischer 		 */
4098948e4baSArchie Cobbs 		i = (*ip_fw_chk_ptr)(&ip,
4108948e4baSArchie Cobbs 		    hlen, NULL, &divert_cookie, &m, &rule, &ip_fw_fwd_addr);
4118948e4baSArchie Cobbs 		if (m == NULL)		/* Packet discarded by firewall */
412b715f178SLuigi Rizzo 			return;
413b715f178SLuigi Rizzo 		if (i == 0 && ip_fw_fwd_addr == NULL)	/* common case */
414b715f178SLuigi Rizzo 			goto pass;
415b715f178SLuigi Rizzo #ifdef DUMMYNET
4168948e4baSArchie Cobbs                 if ((i & IP_FW_PORT_DYNT_FLAG) != 0) {
4178948e4baSArchie Cobbs                         /* Send packet to the appropriate pipe */
4186a800098SYoshinobu Inoue                         dummynet_io(i&0xffff,DN_TO_IP_IN,m,NULL,NULL,0, rule,
4196a800098SYoshinobu Inoue 				    0);
420e4676ba6SJulian Elischer 			return;
42193e0e116SJulian Elischer 		}
422b715f178SLuigi Rizzo #endif
423b715f178SLuigi Rizzo #ifdef IPDIVERT
4248948e4baSArchie Cobbs 		if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
4258948e4baSArchie Cobbs 			/* Divert or tee packet */
4268948e4baSArchie Cobbs 			divert_info = i;
427b715f178SLuigi Rizzo 			goto ours;
428b715f178SLuigi Rizzo 		}
429b715f178SLuigi Rizzo #endif
430b715f178SLuigi Rizzo #ifdef IPFIREWALL_FORWARD
431b715f178SLuigi Rizzo 		if (i == 0 && ip_fw_fwd_addr != NULL)
432b715f178SLuigi Rizzo 			goto pass;
433b715f178SLuigi Rizzo #endif
434b715f178SLuigi Rizzo 		/*
435b715f178SLuigi Rizzo 		 * if we get here, the packet must be dropped
436b715f178SLuigi Rizzo 		 */
437b715f178SLuigi Rizzo 		m_freem(m);
438b715f178SLuigi Rizzo 		return;
439b715f178SLuigi Rizzo 	}
440b715f178SLuigi Rizzo pass:
441100ba1a6SJordan K. Hubbard 
442df8bae1dSRodney W. Grimes 	/*
443df8bae1dSRodney W. Grimes 	 * Process options and, if not destined for us,
444df8bae1dSRodney W. Grimes 	 * ship it on.  ip_dooptions returns 1 when an
445df8bae1dSRodney W. Grimes 	 * error was detected (causing an icmp message
446df8bae1dSRodney W. Grimes 	 * to be sent and the original packet to be freed).
447df8bae1dSRodney W. Grimes 	 */
448df8bae1dSRodney W. Grimes 	ip_nhops = 0;		/* for source routed packets */
449ed1ff184SJulian Elischer 	if (hlen > sizeof (struct ip) && ip_dooptions(m)) {
450ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD
451ed1ff184SJulian Elischer 		ip_fw_fwd_addr = NULL;
452ed1ff184SJulian Elischer #endif
453c67b1d17SGarrett Wollman 		return;
454ed1ff184SJulian Elischer 	}
455df8bae1dSRodney W. Grimes 
456f0068c4aSGarrett Wollman         /* greedy RSVP, snatches any PATH packet of the RSVP protocol and no
457f0068c4aSGarrett Wollman          * matter if it is destined to another node, or whether it is
458f0068c4aSGarrett Wollman          * a multicast one, RSVP wants it! and prevents it from being forwarded
459f0068c4aSGarrett Wollman          * anywhere else. Also checks if the rsvp daemon is running before
460f0068c4aSGarrett Wollman 	 * grabbing the packet.
461f0068c4aSGarrett Wollman          */
4621c5de19aSGarrett Wollman 	if (rsvp_on && ip->ip_p==IPPROTO_RSVP)
463f0068c4aSGarrett Wollman 		goto ours;
464f0068c4aSGarrett Wollman 
465df8bae1dSRodney W. Grimes 	/*
466df8bae1dSRodney W. Grimes 	 * Check our list of addresses, to see if the packet is for us.
467cc766e04SGarrett Wollman 	 * If we don't have any addresses, assume any unicast packet
468cc766e04SGarrett Wollman 	 * we receive might be for us (and let the upper layers deal
469cc766e04SGarrett Wollman 	 * with it).
470df8bae1dSRodney W. Grimes 	 */
471cc766e04SGarrett Wollman 	if (TAILQ_EMPTY(&in_ifaddrhead) &&
472cc766e04SGarrett Wollman 	    (m->m_flags & (M_MCAST|M_BCAST)) == 0)
473cc766e04SGarrett Wollman 		goto ours;
474cc766e04SGarrett Wollman 
475d4295c32SJulian Elischer 	for (ia = TAILQ_FIRST(&in_ifaddrhead); ia;
476f9e354dfSJulian Elischer 					ia = TAILQ_NEXT(ia, ia_link)) {
477df8bae1dSRodney W. Grimes #define	satosin(sa)	((struct sockaddr_in *)(sa))
478df8bae1dSRodney W. Grimes 
479432aad0eSTor Egge #ifdef BOOTP_COMPAT
480432aad0eSTor Egge 		if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
481432aad0eSTor Egge 			goto ours;
482432aad0eSTor Egge #endif
483f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD
484f9e354dfSJulian Elischer 		/*
485f9e354dfSJulian Elischer 		 * If the addr to forward to is one of ours, we pretend to
486f9e354dfSJulian Elischer 		 * be the destination for this packet.
487f9e354dfSJulian Elischer 		 */
488ed1ff184SJulian Elischer 		if (ip_fw_fwd_addr == NULL) {
489ed1ff184SJulian Elischer 			if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
490ed1ff184SJulian Elischer 				goto ours;
491ed1ff184SJulian Elischer 		} else if (IA_SIN(ia)->sin_addr.s_addr ==
492f9e354dfSJulian Elischer 					 ip_fw_fwd_addr->sin_addr.s_addr)
493f9e354dfSJulian Elischer 			goto ours;
494ed1ff184SJulian Elischer #else
495ed1ff184SJulian Elischer 		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
496ed1ff184SJulian Elischer 			goto ours;
497f9e354dfSJulian Elischer #endif
4986ed666afSPoul-Henning Kamp 		if (ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) {
499df8bae1dSRodney W. Grimes 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
500df8bae1dSRodney W. Grimes 			    ip->ip_dst.s_addr)
501df8bae1dSRodney W. Grimes 				goto ours;
502df8bae1dSRodney W. Grimes 			if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
503df8bae1dSRodney W. Grimes 				goto ours;
504df8bae1dSRodney W. Grimes 		}
505df8bae1dSRodney W. Grimes 	}
506df8bae1dSRodney W. Grimes 	if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
507df8bae1dSRodney W. Grimes 		struct in_multi *inm;
508df8bae1dSRodney W. Grimes 		if (ip_mrouter) {
509df8bae1dSRodney W. Grimes 			/*
510df8bae1dSRodney W. Grimes 			 * If we are acting as a multicast router, all
511df8bae1dSRodney W. Grimes 			 * incoming multicast packets are passed to the
512df8bae1dSRodney W. Grimes 			 * kernel-level multicast forwarding function.
513df8bae1dSRodney W. Grimes 			 * The packet is returned (relatively) intact; if
514df8bae1dSRodney W. Grimes 			 * ip_mforward() returns a non-zero value, the packet
515df8bae1dSRodney W. Grimes 			 * must be discarded, else it may be accepted below.
516df8bae1dSRodney W. Grimes 			 *
517df8bae1dSRodney W. Grimes 			 * (The IP ident field is put in the same byte order
518df8bae1dSRodney W. Grimes 			 * as expected when ip_mforward() is called from
519df8bae1dSRodney W. Grimes 			 * ip_output().)
520df8bae1dSRodney W. Grimes 			 */
521df8bae1dSRodney W. Grimes 			ip->ip_id = htons(ip->ip_id);
522f0068c4aSGarrett Wollman 			if (ip_mforward(ip, m->m_pkthdr.rcvif, m, 0) != 0) {
523df8bae1dSRodney W. Grimes 				ipstat.ips_cantforward++;
524df8bae1dSRodney W. Grimes 				m_freem(m);
525c67b1d17SGarrett Wollman 				return;
526df8bae1dSRodney W. Grimes 			}
527df8bae1dSRodney W. Grimes 			ip->ip_id = ntohs(ip->ip_id);
528df8bae1dSRodney W. Grimes 
529df8bae1dSRodney W. Grimes 			/*
530df8bae1dSRodney W. Grimes 			 * The process-level routing demon needs to receive
531df8bae1dSRodney W. Grimes 			 * all multicast IGMP packets, whether or not this
532df8bae1dSRodney W. Grimes 			 * host belongs to their destination groups.
533df8bae1dSRodney W. Grimes 			 */
534df8bae1dSRodney W. Grimes 			if (ip->ip_p == IPPROTO_IGMP)
535df8bae1dSRodney W. Grimes 				goto ours;
536df8bae1dSRodney W. Grimes 			ipstat.ips_forward++;
537df8bae1dSRodney W. Grimes 		}
538df8bae1dSRodney W. Grimes 		/*
539df8bae1dSRodney W. Grimes 		 * See if we belong to the destination multicast group on the
540df8bae1dSRodney W. Grimes 		 * arrival interface.
541df8bae1dSRodney W. Grimes 		 */
542df8bae1dSRodney W. Grimes 		IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
543df8bae1dSRodney W. Grimes 		if (inm == NULL) {
54482c39223SGarrett Wollman 			ipstat.ips_notmember++;
545df8bae1dSRodney W. Grimes 			m_freem(m);
546c67b1d17SGarrett Wollman 			return;
547df8bae1dSRodney W. Grimes 		}
548df8bae1dSRodney W. Grimes 		goto ours;
549df8bae1dSRodney W. Grimes 	}
550df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
551df8bae1dSRodney W. Grimes 		goto ours;
552df8bae1dSRodney W. Grimes 	if (ip->ip_dst.s_addr == INADDR_ANY)
553df8bae1dSRodney W. Grimes 		goto ours;
554df8bae1dSRodney W. Grimes 
5556a800098SYoshinobu Inoue #if defined(NFAITH) && 0 < NFAITH
5566a800098SYoshinobu Inoue 	/*
5576a800098SYoshinobu Inoue 	 * FAITH(Firewall Aided Internet Translator)
5586a800098SYoshinobu Inoue 	 */
5596a800098SYoshinobu Inoue 	if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
5606a800098SYoshinobu Inoue 		if (ip_keepfaith) {
5616a800098SYoshinobu Inoue 			if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_ICMP)
5626a800098SYoshinobu Inoue 				goto ours;
5636a800098SYoshinobu Inoue 		}
5646a800098SYoshinobu Inoue 		m_freem(m);
5656a800098SYoshinobu Inoue 		return;
5666a800098SYoshinobu Inoue 	}
5676a800098SYoshinobu Inoue #endif
568df8bae1dSRodney W. Grimes 	/*
569df8bae1dSRodney W. Grimes 	 * Not for us; forward if possible and desirable.
570df8bae1dSRodney W. Grimes 	 */
571df8bae1dSRodney W. Grimes 	if (ipforwarding == 0) {
572df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
573df8bae1dSRodney W. Grimes 		m_freem(m);
574df8bae1dSRodney W. Grimes 	} else
575df8bae1dSRodney W. Grimes 		ip_forward(m, 0);
576ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD
577ed1ff184SJulian Elischer 	ip_fw_fwd_addr = NULL;
578ed1ff184SJulian Elischer #endif
579c67b1d17SGarrett Wollman 	return;
580df8bae1dSRodney W. Grimes 
581df8bae1dSRodney W. Grimes ours:
582100ba1a6SJordan K. Hubbard 
58363f8d699SJordan K. Hubbard 	/*
584df8bae1dSRodney W. Grimes 	 * If offset or IP_MF are set, must reassemble.
585df8bae1dSRodney W. Grimes 	 * Otherwise, nothing need be done.
586df8bae1dSRodney W. Grimes 	 * (We could look in the reassembly queue to see
587df8bae1dSRodney W. Grimes 	 * if the packet was previously fragmented,
588df8bae1dSRodney W. Grimes 	 * but it's not worth the time; just let them time out.)
589df8bae1dSRodney W. Grimes 	 */
590c383a33fSDima Ruban 	if (ip->ip_off & (IP_MF | IP_OFFMASK | IP_RF)) {
5916a800098SYoshinobu Inoue 
5926a800098SYoshinobu Inoue #if 0	/*
5936a800098SYoshinobu Inoue 	 * Reassembly should be able to treat a mbuf cluster, for later
5946a800098SYoshinobu Inoue 	 * operation of contiguous protocol headers on the cluster. (KAME)
5956a800098SYoshinobu Inoue 	 */
596df8bae1dSRodney W. Grimes 		if (m->m_flags & M_EXT) {		/* XXX */
597af38c68cSLuigi Rizzo 			if ((m = m_pullup(m, hlen)) == 0) {
598df8bae1dSRodney W. Grimes 				ipstat.ips_toosmall++;
599ed1ff184SJulian Elischer #ifdef IPFIREWALL_FORWARD
600ed1ff184SJulian Elischer 				ip_fw_fwd_addr = NULL;
601ed1ff184SJulian Elischer #endif
602c67b1d17SGarrett Wollman 				return;
603df8bae1dSRodney W. Grimes 			}
604df8bae1dSRodney W. Grimes 			ip = mtod(m, struct ip *);
605df8bae1dSRodney W. Grimes 		}
6066a800098SYoshinobu Inoue #endif
607194a213eSAndrey A. Chernov 		sum = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
608df8bae1dSRodney W. Grimes 		/*
609df8bae1dSRodney W. Grimes 		 * Look for queue of fragments
610df8bae1dSRodney W. Grimes 		 * of this datagram.
611df8bae1dSRodney W. Grimes 		 */
612194a213eSAndrey A. Chernov 		for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next)
613df8bae1dSRodney W. Grimes 			if (ip->ip_id == fp->ipq_id &&
614df8bae1dSRodney W. Grimes 			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
615df8bae1dSRodney W. Grimes 			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
616df8bae1dSRodney W. Grimes 			    ip->ip_p == fp->ipq_p)
617df8bae1dSRodney W. Grimes 				goto found;
618df8bae1dSRodney W. Grimes 
619194a213eSAndrey A. Chernov 		fp = 0;
620194a213eSAndrey A. Chernov 
621194a213eSAndrey A. Chernov 		/* check if there's a place for the new queue */
622194a213eSAndrey A. Chernov 		if (nipq > maxnipq) {
623194a213eSAndrey A. Chernov 		    /*
624194a213eSAndrey A. Chernov 		     * drop something from the tail of the current queue
625194a213eSAndrey A. Chernov 		     * before proceeding further
626194a213eSAndrey A. Chernov 		     */
627194a213eSAndrey A. Chernov 		    if (ipq[sum].prev == &ipq[sum]) {   /* gak */
628194a213eSAndrey A. Chernov 			for (i = 0; i < IPREASS_NHASH; i++) {
629194a213eSAndrey A. Chernov 			    if (ipq[i].prev != &ipq[i]) {
630194a213eSAndrey A. Chernov 				ip_freef(ipq[i].prev);
631194a213eSAndrey A. Chernov 				break;
632194a213eSAndrey A. Chernov 			    }
633194a213eSAndrey A. Chernov 			}
634194a213eSAndrey A. Chernov 		    } else
635194a213eSAndrey A. Chernov 			ip_freef(ipq[sum].prev);
636194a213eSAndrey A. Chernov 		}
637194a213eSAndrey A. Chernov found:
638df8bae1dSRodney W. Grimes 		/*
639df8bae1dSRodney W. Grimes 		 * Adjust ip_len to not reflect header,
640df8bae1dSRodney W. Grimes 		 * set ip_mff if more fragments are expected,
641df8bae1dSRodney W. Grimes 		 * convert offset of this to bytes.
642df8bae1dSRodney W. Grimes 		 */
643df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
6446effc713SDoug Rabson 		mff = (ip->ip_off & IP_MF) != 0;
6456effc713SDoug Rabson 		if (mff) {
6466effc713SDoug Rabson 		        /*
6476effc713SDoug Rabson 		         * Make sure that fragments have a data length
6486effc713SDoug Rabson 			 * that's a non-zero multiple of 8 bytes.
6496effc713SDoug Rabson 		         */
6506effc713SDoug Rabson 			if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
6516effc713SDoug Rabson 				ipstat.ips_toosmall++; /* XXX */
6526effc713SDoug Rabson 				goto bad;
6536effc713SDoug Rabson 			}
6546effc713SDoug Rabson 			m->m_flags |= M_FRAG;
6556effc713SDoug Rabson 		}
656df8bae1dSRodney W. Grimes 		ip->ip_off <<= 3;
657df8bae1dSRodney W. Grimes 
658df8bae1dSRodney W. Grimes 		/*
659df8bae1dSRodney W. Grimes 		 * If datagram marked as having more fragments
660df8bae1dSRodney W. Grimes 		 * or if this is not the first fragment,
661df8bae1dSRodney W. Grimes 		 * attempt reassembly; if it succeeds, proceed.
662df8bae1dSRodney W. Grimes 		 */
6636effc713SDoug Rabson 		if (mff || ip->ip_off) {
664df8bae1dSRodney W. Grimes 			ipstat.ips_fragments++;
6656effc713SDoug Rabson 			m->m_pkthdr.header = ip;
6668948e4baSArchie Cobbs #ifdef IPDIVERT
6676a800098SYoshinobu Inoue 			m = ip_reass(m,
6688948e4baSArchie Cobbs 			    fp, &ipq[sum], &divert_info, &divert_cookie);
6698948e4baSArchie Cobbs #else
6706a800098SYoshinobu Inoue 			m = ip_reass(m, fp, &ipq[sum]);
6718948e4baSArchie Cobbs #endif
6726a800098SYoshinobu Inoue 			if (m == 0) {
673f9e354dfSJulian Elischer #ifdef IPFIREWALL_FORWARD
674f9e354dfSJulian Elischer 				ip_fw_fwd_addr = NULL;
675f9e354dfSJulian Elischer #endif
676c67b1d17SGarrett Wollman 				return;
677f9e354dfSJulian Elischer 			}
67881aee63dSPoul-Henning Kamp 			/* Get the length of the reassembled packets header */
67981aee63dSPoul-Henning Kamp 			hlen = IP_VHL_HL(ip->ip_vhl) << 2;
680df8bae1dSRodney W. Grimes 			ipstat.ips_reassembled++;
6816a800098SYoshinobu Inoue 			ip = mtod(m, struct ip *);
682af782f1cSBrian Somers #ifdef IPDIVERT
6838948e4baSArchie Cobbs 			/* Restore original checksum before diverting packet */
6848948e4baSArchie Cobbs 			if (divert_info != 0) {
685af782f1cSBrian Somers 				ip->ip_len += hlen;
686af782f1cSBrian Somers 				HTONS(ip->ip_len);
687af782f1cSBrian Somers 				HTONS(ip->ip_off);
688af782f1cSBrian Somers 				HTONS(ip->ip_id);
689af782f1cSBrian Somers 				ip->ip_sum = 0;
690af782f1cSBrian Somers 				ip->ip_sum = in_cksum_hdr(ip);
691af782f1cSBrian Somers 				NTOHS(ip->ip_id);
692af782f1cSBrian Somers 				NTOHS(ip->ip_off);
693af782f1cSBrian Somers 				NTOHS(ip->ip_len);
694af782f1cSBrian Somers 				ip->ip_len -= hlen;
695af782f1cSBrian Somers 			}
696af782f1cSBrian Somers #endif
697df8bae1dSRodney W. Grimes 		} else
698df8bae1dSRodney W. Grimes 			if (fp)
699df8bae1dSRodney W. Grimes 				ip_freef(fp);
700df8bae1dSRodney W. Grimes 	} else
701df8bae1dSRodney W. Grimes 		ip->ip_len -= hlen;
702df8bae1dSRodney W. Grimes 
70393e0e116SJulian Elischer #ifdef IPDIVERT
70493e0e116SJulian Elischer 	/*
7058948e4baSArchie Cobbs 	 * Divert or tee packet to the divert protocol if required.
7068948e4baSArchie Cobbs 	 *
7078948e4baSArchie Cobbs 	 * If divert_info is zero then cookie should be too, so we shouldn't
7088948e4baSArchie Cobbs 	 * need to clear them here.  Assume divert_packet() does so also.
70993e0e116SJulian Elischer 	 */
7108948e4baSArchie Cobbs 	if (divert_info != 0) {
7118948e4baSArchie Cobbs 		struct mbuf *clone = NULL;
7128948e4baSArchie Cobbs 
7138948e4baSArchie Cobbs 		/* Clone packet if we're doing a 'tee' */
7148948e4baSArchie Cobbs 		if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
7158948e4baSArchie Cobbs 			clone = m_dup(m, M_DONTWAIT);
7168948e4baSArchie Cobbs 
7178948e4baSArchie Cobbs 		/* Restore packet header fields to original values */
7188948e4baSArchie Cobbs 		ip->ip_len += hlen;
7198948e4baSArchie Cobbs 		HTONS(ip->ip_len);
7208948e4baSArchie Cobbs 		HTONS(ip->ip_off);
7218948e4baSArchie Cobbs 		HTONS(ip->ip_id);
7228948e4baSArchie Cobbs 
7238948e4baSArchie Cobbs 		/* Deliver packet to divert input routine */
7248948e4baSArchie Cobbs 		ip_divert_cookie = divert_cookie;
7258948e4baSArchie Cobbs 		divert_packet(m, 1, divert_info & 0xffff);
726e4676ba6SJulian Elischer 		ipstat.ips_delivered++;
7278948e4baSArchie Cobbs 
7288948e4baSArchie Cobbs 		/* If 'tee', continue with original packet */
7298948e4baSArchie Cobbs 		if (clone == NULL)
73093e0e116SJulian Elischer 			return;
7318948e4baSArchie Cobbs 		m = clone;
7328948e4baSArchie Cobbs 		ip = mtod(m, struct ip *);
73393e0e116SJulian Elischer 	}
73493e0e116SJulian Elischer #endif
73593e0e116SJulian Elischer 
736df8bae1dSRodney W. Grimes 	/*
737df8bae1dSRodney W. Grimes 	 * Switch out to protocol's input routine.
738df8bae1dSRodney W. Grimes 	 */
739df8bae1dSRodney W. Grimes 	ipstat.ips_delivered++;
7406a800098SYoshinobu Inoue     {
7416a800098SYoshinobu Inoue 	int off = hlen, nh = ip->ip_p;
7426a800098SYoshinobu Inoue 
7436a800098SYoshinobu Inoue 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, off, nh);
744f9e354dfSJulian Elischer #ifdef	IPFIREWALL_FORWARD
745f9e354dfSJulian Elischer 	ip_fw_fwd_addr = NULL;	/* tcp needed it */
746f9e354dfSJulian Elischer #endif
747c67b1d17SGarrett Wollman 	return;
7486a800098SYoshinobu Inoue     }
749df8bae1dSRodney W. Grimes bad:
750f9e354dfSJulian Elischer #ifdef	IPFIREWALL_FORWARD
751f9e354dfSJulian Elischer 	ip_fw_fwd_addr = NULL;
752f9e354dfSJulian Elischer #endif
753df8bae1dSRodney W. Grimes 	m_freem(m);
754c67b1d17SGarrett Wollman }
755c67b1d17SGarrett Wollman 
756c67b1d17SGarrett Wollman /*
757c67b1d17SGarrett Wollman  * IP software interrupt routine - to go away sometime soon
758c67b1d17SGarrett Wollman  */
759c67b1d17SGarrett Wollman static void
760c67b1d17SGarrett Wollman ipintr(void)
761c67b1d17SGarrett Wollman {
762c67b1d17SGarrett Wollman 	int s;
763c67b1d17SGarrett Wollman 	struct mbuf *m;
764c67b1d17SGarrett Wollman 
765c67b1d17SGarrett Wollman 	while(1) {
766c67b1d17SGarrett Wollman 		s = splimp();
767c67b1d17SGarrett Wollman 		IF_DEQUEUE(&ipintrq, m);
768c67b1d17SGarrett Wollman 		splx(s);
769c67b1d17SGarrett Wollman 		if (m == 0)
770c67b1d17SGarrett Wollman 			return;
771c67b1d17SGarrett Wollman 		ip_input(m);
772c67b1d17SGarrett Wollman 	}
773df8bae1dSRodney W. Grimes }
774df8bae1dSRodney W. Grimes 
775df8bae1dSRodney W. Grimes /*
7768948e4baSArchie Cobbs  * Take incoming datagram fragment and try to reassemble it into
7778948e4baSArchie Cobbs  * whole datagram.  If a chain for reassembly of this datagram already
7788948e4baSArchie Cobbs  * exists, then it is given as fp; otherwise have to make a chain.
7798948e4baSArchie Cobbs  *
7808948e4baSArchie Cobbs  * When IPDIVERT enabled, keep additional state with each packet that
7818948e4baSArchie Cobbs  * tells us if we need to divert or tee the packet we're building.
782df8bae1dSRodney W. Grimes  */
7838948e4baSArchie Cobbs 
7846a800098SYoshinobu Inoue static struct mbuf *
7858948e4baSArchie Cobbs #ifdef IPDIVERT
7868948e4baSArchie Cobbs ip_reass(m, fp, where, divinfo, divcookie)
7878948e4baSArchie Cobbs #else
7886effc713SDoug Rabson ip_reass(m, fp, where)
7898948e4baSArchie Cobbs #endif
7906effc713SDoug Rabson 	register struct mbuf *m;
791df8bae1dSRodney W. Grimes 	register struct ipq *fp;
792194a213eSAndrey A. Chernov 	struct   ipq    *where;
7938948e4baSArchie Cobbs #ifdef IPDIVERT
7948948e4baSArchie Cobbs 	u_int32_t *divinfo;
7958948e4baSArchie Cobbs 	u_int16_t *divcookie;
7968948e4baSArchie Cobbs #endif
797df8bae1dSRodney W. Grimes {
7986effc713SDoug Rabson 	struct ip *ip = mtod(m, struct ip *);
7996effc713SDoug Rabson 	register struct mbuf *p = 0, *q, *nq;
800df8bae1dSRodney W. Grimes 	struct mbuf *t;
8016effc713SDoug Rabson 	int hlen = IP_VHL_HL(ip->ip_vhl) << 2;
802df8bae1dSRodney W. Grimes 	int i, next;
803df8bae1dSRodney W. Grimes 
804df8bae1dSRodney W. Grimes 	/*
805df8bae1dSRodney W. Grimes 	 * Presence of header sizes in mbufs
806df8bae1dSRodney W. Grimes 	 * would confuse code below.
807df8bae1dSRodney W. Grimes 	 */
808df8bae1dSRodney W. Grimes 	m->m_data += hlen;
809df8bae1dSRodney W. Grimes 	m->m_len -= hlen;
810df8bae1dSRodney W. Grimes 
811df8bae1dSRodney W. Grimes 	/*
812df8bae1dSRodney W. Grimes 	 * If first fragment to arrive, create a reassembly queue.
813df8bae1dSRodney W. Grimes 	 */
814df8bae1dSRodney W. Grimes 	if (fp == 0) {
815df8bae1dSRodney W. Grimes 		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
816df8bae1dSRodney W. Grimes 			goto dropfrag;
817df8bae1dSRodney W. Grimes 		fp = mtod(t, struct ipq *);
818194a213eSAndrey A. Chernov 		insque(fp, where);
819194a213eSAndrey A. Chernov 		nipq++;
820df8bae1dSRodney W. Grimes 		fp->ipq_ttl = IPFRAGTTL;
821df8bae1dSRodney W. Grimes 		fp->ipq_p = ip->ip_p;
822df8bae1dSRodney W. Grimes 		fp->ipq_id = ip->ip_id;
8236effc713SDoug Rabson 		fp->ipq_src = ip->ip_src;
8246effc713SDoug Rabson 		fp->ipq_dst = ip->ip_dst;
825af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
826af38c68cSLuigi Rizzo 		m->m_nextpkt = NULL;
82793e0e116SJulian Elischer #ifdef IPDIVERT
8288948e4baSArchie Cobbs 		fp->ipq_div_info = 0;
829bb60f459SJulian Elischer 		fp->ipq_div_cookie = 0;
83093e0e116SJulian Elischer #endif
831af38c68cSLuigi Rizzo 		goto inserted;
832df8bae1dSRodney W. Grimes 	}
833df8bae1dSRodney W. Grimes 
8346effc713SDoug Rabson #define GETIP(m)	((struct ip*)((m)->m_pkthdr.header))
8356effc713SDoug Rabson 
836df8bae1dSRodney W. Grimes 	/*
837df8bae1dSRodney W. Grimes 	 * Find a segment which begins after this one does.
838df8bae1dSRodney W. Grimes 	 */
8396effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
8406effc713SDoug Rabson 		if (GETIP(q)->ip_off > ip->ip_off)
841df8bae1dSRodney W. Grimes 			break;
842df8bae1dSRodney W. Grimes 
843df8bae1dSRodney W. Grimes 	/*
844df8bae1dSRodney W. Grimes 	 * If there is a preceding segment, it may provide some of
845df8bae1dSRodney W. Grimes 	 * our data already.  If so, drop the data from the incoming
846af38c68cSLuigi Rizzo 	 * segment.  If it provides all of our data, drop us, otherwise
847af38c68cSLuigi Rizzo 	 * stick new segment in the proper place.
848db4f9cc7SJonathan Lemon 	 *
849db4f9cc7SJonathan Lemon 	 * If some of the data is dropped from the the preceding
850db4f9cc7SJonathan Lemon 	 * segment, then it's checksum is invalidated.
851df8bae1dSRodney W. Grimes 	 */
8526effc713SDoug Rabson 	if (p) {
8536effc713SDoug Rabson 		i = GETIP(p)->ip_off + GETIP(p)->ip_len - ip->ip_off;
854df8bae1dSRodney W. Grimes 		if (i > 0) {
855df8bae1dSRodney W. Grimes 			if (i >= ip->ip_len)
856df8bae1dSRodney W. Grimes 				goto dropfrag;
8576a800098SYoshinobu Inoue 			m_adj(m, i);
858db4f9cc7SJonathan Lemon 			m->m_pkthdr.csum_flags = 0;
859df8bae1dSRodney W. Grimes 			ip->ip_off += i;
860df8bae1dSRodney W. Grimes 			ip->ip_len -= i;
861df8bae1dSRodney W. Grimes 		}
862af38c68cSLuigi Rizzo 		m->m_nextpkt = p->m_nextpkt;
863af38c68cSLuigi Rizzo 		p->m_nextpkt = m;
864af38c68cSLuigi Rizzo 	} else {
865af38c68cSLuigi Rizzo 		m->m_nextpkt = fp->ipq_frags;
866af38c68cSLuigi Rizzo 		fp->ipq_frags = m;
867df8bae1dSRodney W. Grimes 	}
868df8bae1dSRodney W. Grimes 
869df8bae1dSRodney W. Grimes 	/*
870df8bae1dSRodney W. Grimes 	 * While we overlap succeeding segments trim them or,
871df8bae1dSRodney W. Grimes 	 * if they are completely covered, dequeue them.
872df8bae1dSRodney W. Grimes 	 */
8736effc713SDoug Rabson 	for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
874af38c68cSLuigi Rizzo 	     q = nq) {
8756effc713SDoug Rabson 		i = (ip->ip_off + ip->ip_len) -
8766effc713SDoug Rabson 		    GETIP(q)->ip_off;
8776effc713SDoug Rabson 		if (i < GETIP(q)->ip_len) {
8786effc713SDoug Rabson 			GETIP(q)->ip_len -= i;
8796effc713SDoug Rabson 			GETIP(q)->ip_off += i;
8806effc713SDoug Rabson 			m_adj(q, i);
881db4f9cc7SJonathan Lemon 			q->m_pkthdr.csum_flags = 0;
882df8bae1dSRodney W. Grimes 			break;
883df8bae1dSRodney W. Grimes 		}
8846effc713SDoug Rabson 		nq = q->m_nextpkt;
885af38c68cSLuigi Rizzo 		m->m_nextpkt = nq;
8866effc713SDoug Rabson 		m_freem(q);
887df8bae1dSRodney W. Grimes 	}
888df8bae1dSRodney W. Grimes 
889af38c68cSLuigi Rizzo inserted:
89093e0e116SJulian Elischer 
89193e0e116SJulian Elischer #ifdef IPDIVERT
89293e0e116SJulian Elischer 	/*
8938948e4baSArchie Cobbs 	 * Transfer firewall instructions to the fragment structure.
8948948e4baSArchie Cobbs 	 * Any fragment diverting causes the whole packet to divert.
89593e0e116SJulian Elischer 	 */
8968948e4baSArchie Cobbs 	fp->ipq_div_info = *divinfo;
8978948e4baSArchie Cobbs 	fp->ipq_div_cookie = *divcookie;
8988948e4baSArchie Cobbs 	*divinfo = 0;
8998948e4baSArchie Cobbs 	*divcookie = 0;
90093e0e116SJulian Elischer #endif
90193e0e116SJulian Elischer 
902df8bae1dSRodney W. Grimes 	/*
903af38c68cSLuigi Rizzo 	 * Check for complete reassembly.
904df8bae1dSRodney W. Grimes 	 */
9056effc713SDoug Rabson 	next = 0;
9066effc713SDoug Rabson 	for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
9076effc713SDoug Rabson 		if (GETIP(q)->ip_off != next)
9086effc713SDoug Rabson 			return (0);
9096effc713SDoug Rabson 		next += GETIP(q)->ip_len;
9106effc713SDoug Rabson 	}
9116effc713SDoug Rabson 	/* Make sure the last packet didn't have the IP_MF flag */
9126effc713SDoug Rabson 	if (p->m_flags & M_FRAG)
913df8bae1dSRodney W. Grimes 		return (0);
914df8bae1dSRodney W. Grimes 
915df8bae1dSRodney W. Grimes 	/*
916430d30d8SBill Fenner 	 * Reassembly is complete.  Make sure the packet is a sane size.
917430d30d8SBill Fenner 	 */
9186effc713SDoug Rabson 	q = fp->ipq_frags;
9196effc713SDoug Rabson 	ip = GETIP(q);
9206effc713SDoug Rabson 	if (next + (IP_VHL_HL(ip->ip_vhl) << 2) > IP_MAXPACKET) {
921430d30d8SBill Fenner 		ipstat.ips_toolong++;
922430d30d8SBill Fenner 		ip_freef(fp);
923430d30d8SBill Fenner 		return (0);
924430d30d8SBill Fenner 	}
925430d30d8SBill Fenner 
926430d30d8SBill Fenner 	/*
927430d30d8SBill Fenner 	 * Concatenate fragments.
928df8bae1dSRodney W. Grimes 	 */
9296effc713SDoug Rabson 	m = q;
930df8bae1dSRodney W. Grimes 	t = m->m_next;
931df8bae1dSRodney W. Grimes 	m->m_next = 0;
932df8bae1dSRodney W. Grimes 	m_cat(m, t);
9336effc713SDoug Rabson 	nq = q->m_nextpkt;
934945aa40dSDoug Rabson 	q->m_nextpkt = 0;
9356effc713SDoug Rabson 	for (q = nq; q != NULL; q = nq) {
9366effc713SDoug Rabson 		nq = q->m_nextpkt;
937945aa40dSDoug Rabson 		q->m_nextpkt = NULL;
9386effc713SDoug Rabson 		m_cat(m, q);
939db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_flags &= q->m_pkthdr.csum_flags;
940db4f9cc7SJonathan Lemon 		m->m_pkthdr.csum_data += q->m_pkthdr.csum_data;
941df8bae1dSRodney W. Grimes 	}
942df8bae1dSRodney W. Grimes 
94393e0e116SJulian Elischer #ifdef IPDIVERT
94493e0e116SJulian Elischer 	/*
9458948e4baSArchie Cobbs 	 * Extract firewall instructions from the fragment structure.
94693e0e116SJulian Elischer 	 */
9478948e4baSArchie Cobbs 	*divinfo = fp->ipq_div_info;
9488948e4baSArchie Cobbs 	*divcookie = fp->ipq_div_cookie;
94993e0e116SJulian Elischer #endif
95093e0e116SJulian Elischer 
951df8bae1dSRodney W. Grimes 	/*
952df8bae1dSRodney W. Grimes 	 * Create header for new ip packet by
953df8bae1dSRodney W. Grimes 	 * modifying header of first packet;
954df8bae1dSRodney W. Grimes 	 * dequeue and discard fragment reassembly header.
955df8bae1dSRodney W. Grimes 	 * Make header visible.
956df8bae1dSRodney W. Grimes 	 */
957df8bae1dSRodney W. Grimes 	ip->ip_len = next;
9586effc713SDoug Rabson 	ip->ip_src = fp->ipq_src;
9596effc713SDoug Rabson 	ip->ip_dst = fp->ipq_dst;
960df8bae1dSRodney W. Grimes 	remque(fp);
961194a213eSAndrey A. Chernov 	nipq--;
962df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
9636effc713SDoug Rabson 	m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2);
9646effc713SDoug Rabson 	m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2);
965df8bae1dSRodney W. Grimes 	/* some debugging cruft by sklower, below, will go away soon */
966df8bae1dSRodney W. Grimes 	if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
967df8bae1dSRodney W. Grimes 		register int plen = 0;
9686a800098SYoshinobu Inoue 		for (t = m; t; t = t->m_next)
9696a800098SYoshinobu Inoue 			plen += t->m_len;
9706a800098SYoshinobu Inoue 		m->m_pkthdr.len = plen;
971df8bae1dSRodney W. Grimes 	}
9726a800098SYoshinobu Inoue 	return (m);
973df8bae1dSRodney W. Grimes 
974df8bae1dSRodney W. Grimes dropfrag:
975efe39c6aSJulian Elischer #ifdef IPDIVERT
9768948e4baSArchie Cobbs 	*divinfo = 0;
9778948e4baSArchie Cobbs 	*divcookie = 0;
978efe39c6aSJulian Elischer #endif
979df8bae1dSRodney W. Grimes 	ipstat.ips_fragdropped++;
980df8bae1dSRodney W. Grimes 	m_freem(m);
981df8bae1dSRodney W. Grimes 	return (0);
9826effc713SDoug Rabson 
9836effc713SDoug Rabson #undef GETIP
984df8bae1dSRodney W. Grimes }
985df8bae1dSRodney W. Grimes 
986df8bae1dSRodney W. Grimes /*
987df8bae1dSRodney W. Grimes  * Free a fragment reassembly header and all
988df8bae1dSRodney W. Grimes  * associated datagrams.
989df8bae1dSRodney W. Grimes  */
9900312fbe9SPoul-Henning Kamp static void
991df8bae1dSRodney W. Grimes ip_freef(fp)
992df8bae1dSRodney W. Grimes 	struct ipq *fp;
993df8bae1dSRodney W. Grimes {
9946effc713SDoug Rabson 	register struct mbuf *q;
995df8bae1dSRodney W. Grimes 
9966effc713SDoug Rabson 	while (fp->ipq_frags) {
9976effc713SDoug Rabson 		q = fp->ipq_frags;
9986effc713SDoug Rabson 		fp->ipq_frags = q->m_nextpkt;
9996effc713SDoug Rabson 		m_freem(q);
1000df8bae1dSRodney W. Grimes 	}
1001df8bae1dSRodney W. Grimes 	remque(fp);
1002df8bae1dSRodney W. Grimes 	(void) m_free(dtom(fp));
1003194a213eSAndrey A. Chernov 	nipq--;
1004df8bae1dSRodney W. Grimes }
1005df8bae1dSRodney W. Grimes 
1006df8bae1dSRodney W. Grimes /*
1007df8bae1dSRodney W. Grimes  * IP timer processing;
1008df8bae1dSRodney W. Grimes  * if a timer expires on a reassembly
1009df8bae1dSRodney W. Grimes  * queue, discard it.
1010df8bae1dSRodney W. Grimes  */
1011df8bae1dSRodney W. Grimes void
1012df8bae1dSRodney W. Grimes ip_slowtimo()
1013df8bae1dSRodney W. Grimes {
1014df8bae1dSRodney W. Grimes 	register struct ipq *fp;
1015df8bae1dSRodney W. Grimes 	int s = splnet();
1016194a213eSAndrey A. Chernov 	int i;
1017df8bae1dSRodney W. Grimes 
1018194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1019194a213eSAndrey A. Chernov 		fp = ipq[i].next;
1020194a213eSAndrey A. Chernov 		if (fp == 0)
1021194a213eSAndrey A. Chernov 			continue;
1022194a213eSAndrey A. Chernov 		while (fp != &ipq[i]) {
1023df8bae1dSRodney W. Grimes 			--fp->ipq_ttl;
1024df8bae1dSRodney W. Grimes 			fp = fp->next;
1025df8bae1dSRodney W. Grimes 			if (fp->prev->ipq_ttl == 0) {
1026df8bae1dSRodney W. Grimes 				ipstat.ips_fragtimeout++;
1027df8bae1dSRodney W. Grimes 				ip_freef(fp->prev);
1028df8bae1dSRodney W. Grimes 			}
1029df8bae1dSRodney W. Grimes 		}
1030194a213eSAndrey A. Chernov 	}
10311f91d8c5SDavid Greenman 	ipflow_slowtimo();
1032df8bae1dSRodney W. Grimes 	splx(s);
1033df8bae1dSRodney W. Grimes }
1034df8bae1dSRodney W. Grimes 
1035df8bae1dSRodney W. Grimes /*
1036df8bae1dSRodney W. Grimes  * Drain off all datagram fragments.
1037df8bae1dSRodney W. Grimes  */
1038df8bae1dSRodney W. Grimes void
1039df8bae1dSRodney W. Grimes ip_drain()
1040df8bae1dSRodney W. Grimes {
1041194a213eSAndrey A. Chernov 	int     i;
1042ce29ab3aSGarrett Wollman 
1043194a213eSAndrey A. Chernov 	for (i = 0; i < IPREASS_NHASH; i++) {
1044194a213eSAndrey A. Chernov 		while (ipq[i].next != &ipq[i]) {
1045194a213eSAndrey A. Chernov 			ipstat.ips_fragdropped++;
1046194a213eSAndrey A. Chernov 			ip_freef(ipq[i].next);
1047194a213eSAndrey A. Chernov 		}
1048194a213eSAndrey A. Chernov 	}
1049ce29ab3aSGarrett Wollman 	in_rtqdrain();
1050df8bae1dSRodney W. Grimes }
1051df8bae1dSRodney W. Grimes 
1052df8bae1dSRodney W. Grimes /*
1053df8bae1dSRodney W. Grimes  * Do option processing on a datagram,
1054df8bae1dSRodney W. Grimes  * possibly discarding it if bad options are encountered,
1055df8bae1dSRodney W. Grimes  * or forwarding it if source-routed.
1056df8bae1dSRodney W. Grimes  * Returns 1 if packet has been forwarded/freed,
1057df8bae1dSRodney W. Grimes  * 0 if the packet should be processed further.
1058df8bae1dSRodney W. Grimes  */
10590312fbe9SPoul-Henning Kamp static int
1060df8bae1dSRodney W. Grimes ip_dooptions(m)
1061df8bae1dSRodney W. Grimes 	struct mbuf *m;
1062df8bae1dSRodney W. Grimes {
1063df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
1064df8bae1dSRodney W. Grimes 	register u_char *cp;
1065df8bae1dSRodney W. Grimes 	register struct ip_timestamp *ipt;
1066df8bae1dSRodney W. Grimes 	register struct in_ifaddr *ia;
1067df8bae1dSRodney W. Grimes 	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
1068df8bae1dSRodney W. Grimes 	struct in_addr *sin, dst;
1069df8bae1dSRodney W. Grimes 	n_time ntime;
1070df8bae1dSRodney W. Grimes 
1071df8bae1dSRodney W. Grimes 	dst = ip->ip_dst;
1072df8bae1dSRodney W. Grimes 	cp = (u_char *)(ip + 1);
107358938916SGarrett Wollman 	cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1074df8bae1dSRodney W. Grimes 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
1075df8bae1dSRodney W. Grimes 		opt = cp[IPOPT_OPTVAL];
1076df8bae1dSRodney W. Grimes 		if (opt == IPOPT_EOL)
1077df8bae1dSRodney W. Grimes 			break;
1078df8bae1dSRodney W. Grimes 		if (opt == IPOPT_NOP)
1079df8bae1dSRodney W. Grimes 			optlen = 1;
1080df8bae1dSRodney W. Grimes 		else {
1081df8bae1dSRodney W. Grimes 			optlen = cp[IPOPT_OLEN];
1082df8bae1dSRodney W. Grimes 			if (optlen <= 0 || optlen > cnt) {
1083df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
1084df8bae1dSRodney W. Grimes 				goto bad;
1085df8bae1dSRodney W. Grimes 			}
1086df8bae1dSRodney W. Grimes 		}
1087df8bae1dSRodney W. Grimes 		switch (opt) {
1088df8bae1dSRodney W. Grimes 
1089df8bae1dSRodney W. Grimes 		default:
1090df8bae1dSRodney W. Grimes 			break;
1091df8bae1dSRodney W. Grimes 
1092df8bae1dSRodney W. Grimes 		/*
1093df8bae1dSRodney W. Grimes 		 * Source routing with record.
1094df8bae1dSRodney W. Grimes 		 * Find interface with current destination address.
1095df8bae1dSRodney W. Grimes 		 * If none on this machine then drop if strictly routed,
1096df8bae1dSRodney W. Grimes 		 * or do nothing if loosely routed.
1097df8bae1dSRodney W. Grimes 		 * Record interface address and bring up next address
1098df8bae1dSRodney W. Grimes 		 * component.  If strictly routed make sure next
1099df8bae1dSRodney W. Grimes 		 * address is on directly accessible net.
1100df8bae1dSRodney W. Grimes 		 */
1101df8bae1dSRodney W. Grimes 		case IPOPT_LSRR:
1102df8bae1dSRodney W. Grimes 		case IPOPT_SSRR:
1103df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1104df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1105df8bae1dSRodney W. Grimes 				goto bad;
1106df8bae1dSRodney W. Grimes 			}
1107df8bae1dSRodney W. Grimes 			ipaddr.sin_addr = ip->ip_dst;
1108df8bae1dSRodney W. Grimes 			ia = (struct in_ifaddr *)
1109df8bae1dSRodney W. Grimes 				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
1110df8bae1dSRodney W. Grimes 			if (ia == 0) {
1111df8bae1dSRodney W. Grimes 				if (opt == IPOPT_SSRR) {
1112df8bae1dSRodney W. Grimes 					type = ICMP_UNREACH;
1113df8bae1dSRodney W. Grimes 					code = ICMP_UNREACH_SRCFAIL;
1114df8bae1dSRodney W. Grimes 					goto bad;
1115df8bae1dSRodney W. Grimes 				}
1116bc189bf8SGuido van Rooij 				if (!ip_dosourceroute)
1117bc189bf8SGuido van Rooij 					goto nosourcerouting;
1118df8bae1dSRodney W. Grimes 				/*
1119df8bae1dSRodney W. Grimes 				 * Loose routing, and not at next destination
1120df8bae1dSRodney W. Grimes 				 * yet; nothing to do except forward.
1121df8bae1dSRodney W. Grimes 				 */
1122df8bae1dSRodney W. Grimes 				break;
1123df8bae1dSRodney W. Grimes 			}
1124df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
1125df8bae1dSRodney W. Grimes 			if (off > optlen - sizeof(struct in_addr)) {
1126df8bae1dSRodney W. Grimes 				/*
1127df8bae1dSRodney W. Grimes 				 * End of source route.  Should be for us.
1128df8bae1dSRodney W. Grimes 				 */
11294fce5804SGuido van Rooij 				if (!ip_acceptsourceroute)
11304fce5804SGuido van Rooij 					goto nosourcerouting;
1131df8bae1dSRodney W. Grimes 				save_rte(cp, ip->ip_src);
1132df8bae1dSRodney W. Grimes 				break;
1133df8bae1dSRodney W. Grimes 			}
11341025071fSGarrett Wollman 
11351025071fSGarrett Wollman 			if (!ip_dosourceroute) {
11360af8d3ecSDavid Greenman 				if (ipforwarding) {
11370af8d3ecSDavid Greenman 					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
11380af8d3ecSDavid Greenman 					/*
11390af8d3ecSDavid Greenman 					 * Acting as a router, so generate ICMP
11400af8d3ecSDavid Greenman 					 */
1141efa48587SGuido van Rooij nosourcerouting:
1142bc189bf8SGuido van Rooij 					strcpy(buf, inet_ntoa(ip->ip_dst));
11431025071fSGarrett Wollman 					log(LOG_WARNING,
11441025071fSGarrett Wollman 					    "attempted source route from %s to %s\n",
11451025071fSGarrett Wollman 					    inet_ntoa(ip->ip_src), buf);
11461025071fSGarrett Wollman 					type = ICMP_UNREACH;
11471025071fSGarrett Wollman 					code = ICMP_UNREACH_SRCFAIL;
11481025071fSGarrett Wollman 					goto bad;
11490af8d3ecSDavid Greenman 				} else {
11500af8d3ecSDavid Greenman 					/*
11510af8d3ecSDavid Greenman 					 * Not acting as a router, so silently drop.
11520af8d3ecSDavid Greenman 					 */
11530af8d3ecSDavid Greenman 					ipstat.ips_cantforward++;
11540af8d3ecSDavid Greenman 					m_freem(m);
11550af8d3ecSDavid Greenman 					return (1);
11560af8d3ecSDavid Greenman 				}
11571025071fSGarrett Wollman 			}
11581025071fSGarrett Wollman 
1159df8bae1dSRodney W. Grimes 			/*
1160df8bae1dSRodney W. Grimes 			 * locate outgoing interface
1161df8bae1dSRodney W. Grimes 			 */
116294a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, cp + off,
1163df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
11641025071fSGarrett Wollman 
1165df8bae1dSRodney W. Grimes 			if (opt == IPOPT_SSRR) {
1166df8bae1dSRodney W. Grimes #define	INA	struct in_ifaddr *
1167df8bae1dSRodney W. Grimes #define	SA	struct sockaddr *
1168df8bae1dSRodney W. Grimes 			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
1169df8bae1dSRodney W. Grimes 				ia = (INA)ifa_ifwithnet((SA)&ipaddr);
1170df8bae1dSRodney W. Grimes 			} else
1171df8bae1dSRodney W. Grimes 				ia = ip_rtaddr(ipaddr.sin_addr);
1172df8bae1dSRodney W. Grimes 			if (ia == 0) {
1173df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1174df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_SRCFAIL;
1175df8bae1dSRodney W. Grimes 				goto bad;
1176df8bae1dSRodney W. Grimes 			}
1177df8bae1dSRodney W. Grimes 			ip->ip_dst = ipaddr.sin_addr;
117894a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
117994a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1180df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1181df8bae1dSRodney W. Grimes 			/*
1182df8bae1dSRodney W. Grimes 			 * Let ip_intr's mcast routing check handle mcast pkts
1183df8bae1dSRodney W. Grimes 			 */
1184df8bae1dSRodney W. Grimes 			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
1185df8bae1dSRodney W. Grimes 			break;
1186df8bae1dSRodney W. Grimes 
1187df8bae1dSRodney W. Grimes 		case IPOPT_RR:
1188df8bae1dSRodney W. Grimes 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
1189df8bae1dSRodney W. Grimes 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
1190df8bae1dSRodney W. Grimes 				goto bad;
1191df8bae1dSRodney W. Grimes 			}
1192df8bae1dSRodney W. Grimes 			/*
1193df8bae1dSRodney W. Grimes 			 * If no space remains, ignore.
1194df8bae1dSRodney W. Grimes 			 */
1195df8bae1dSRodney W. Grimes 			off--;			/* 0 origin */
1196df8bae1dSRodney W. Grimes 			if (off > optlen - sizeof(struct in_addr))
1197df8bae1dSRodney W. Grimes 				break;
119894a5d9b6SDavid Greenman 			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
1199df8bae1dSRodney W. Grimes 			    sizeof(ipaddr.sin_addr));
1200df8bae1dSRodney W. Grimes 			/*
1201df8bae1dSRodney W. Grimes 			 * locate outgoing interface; if we're the destination,
1202df8bae1dSRodney W. Grimes 			 * use the incoming interface (should be same).
1203df8bae1dSRodney W. Grimes 			 */
1204df8bae1dSRodney W. Grimes 			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
1205df8bae1dSRodney W. Grimes 			    (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
1206df8bae1dSRodney W. Grimes 				type = ICMP_UNREACH;
1207df8bae1dSRodney W. Grimes 				code = ICMP_UNREACH_HOST;
1208df8bae1dSRodney W. Grimes 				goto bad;
1209df8bae1dSRodney W. Grimes 			}
121094a5d9b6SDavid Greenman 			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
121194a5d9b6SDavid Greenman 			    sizeof(struct in_addr));
1212df8bae1dSRodney W. Grimes 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
1213df8bae1dSRodney W. Grimes 			break;
1214df8bae1dSRodney W. Grimes 
1215df8bae1dSRodney W. Grimes 		case IPOPT_TS:
1216df8bae1dSRodney W. Grimes 			code = cp - (u_char *)ip;
1217df8bae1dSRodney W. Grimes 			ipt = (struct ip_timestamp *)cp;
1218df8bae1dSRodney W. Grimes 			if (ipt->ipt_len < 5)
1219df8bae1dSRodney W. Grimes 				goto bad;
12200c8d2590SBruce Evans 			if (ipt->ipt_ptr > ipt->ipt_len - sizeof(int32_t)) {
1221df8bae1dSRodney W. Grimes 				if (++ipt->ipt_oflw == 0)
1222df8bae1dSRodney W. Grimes 					goto bad;
1223df8bae1dSRodney W. Grimes 				break;
1224df8bae1dSRodney W. Grimes 			}
1225df8bae1dSRodney W. Grimes 			sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
1226df8bae1dSRodney W. Grimes 			switch (ipt->ipt_flg) {
1227df8bae1dSRodney W. Grimes 
1228df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSONLY:
1229df8bae1dSRodney W. Grimes 				break;
1230df8bae1dSRodney W. Grimes 
1231df8bae1dSRodney W. Grimes 			case IPOPT_TS_TSANDADDR:
1232b8e8c209SDavid Greenman 				if (ipt->ipt_ptr - 1 + sizeof(n_time) +
1233df8bae1dSRodney W. Grimes 				    sizeof(struct in_addr) > ipt->ipt_len)
1234df8bae1dSRodney W. Grimes 					goto bad;
1235df8bae1dSRodney W. Grimes 				ipaddr.sin_addr = dst;
1236df8bae1dSRodney W. Grimes 				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
1237df8bae1dSRodney W. Grimes 							    m->m_pkthdr.rcvif);
1238df8bae1dSRodney W. Grimes 				if (ia == 0)
1239df8bae1dSRodney W. Grimes 					continue;
124094a5d9b6SDavid Greenman 				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
124194a5d9b6SDavid Greenman 				    sizeof(struct in_addr));
1242df8bae1dSRodney W. Grimes 				ipt->ipt_ptr += sizeof(struct in_addr);
1243df8bae1dSRodney W. Grimes 				break;
1244df8bae1dSRodney W. Grimes 
1245df8bae1dSRodney W. Grimes 			case IPOPT_TS_PRESPEC:
1246b8e8c209SDavid Greenman 				if (ipt->ipt_ptr - 1 + sizeof(n_time) +
1247df8bae1dSRodney W. Grimes 				    sizeof(struct in_addr) > ipt->ipt_len)
1248df8bae1dSRodney W. Grimes 					goto bad;
124994a5d9b6SDavid Greenman 				(void)memcpy(&ipaddr.sin_addr, sin,
1250df8bae1dSRodney W. Grimes 				    sizeof(struct in_addr));
1251df8bae1dSRodney W. Grimes 				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
1252df8bae1dSRodney W. Grimes 					continue;
1253df8bae1dSRodney W. Grimes 				ipt->ipt_ptr += sizeof(struct in_addr);
1254df8bae1dSRodney W. Grimes 				break;
1255df8bae1dSRodney W. Grimes 
1256df8bae1dSRodney W. Grimes 			default:
1257df8bae1dSRodney W. Grimes 				goto bad;
1258df8bae1dSRodney W. Grimes 			}
1259df8bae1dSRodney W. Grimes 			ntime = iptime();
126094a5d9b6SDavid Greenman 			(void)memcpy(cp + ipt->ipt_ptr - 1, &ntime,
1261df8bae1dSRodney W. Grimes 			    sizeof(n_time));
1262df8bae1dSRodney W. Grimes 			ipt->ipt_ptr += sizeof(n_time);
1263df8bae1dSRodney W. Grimes 		}
1264df8bae1dSRodney W. Grimes 	}
126547174b49SAndrey A. Chernov 	if (forward && ipforwarding) {
1266df8bae1dSRodney W. Grimes 		ip_forward(m, 1);
1267df8bae1dSRodney W. Grimes 		return (1);
1268df8bae1dSRodney W. Grimes 	}
1269df8bae1dSRodney W. Grimes 	return (0);
1270df8bae1dSRodney W. Grimes bad:
127158938916SGarrett Wollman 	ip->ip_len -= IP_VHL_HL(ip->ip_vhl) << 2;   /* XXX icmp_error adds in hdr length */
1272df8bae1dSRodney W. Grimes 	icmp_error(m, type, code, 0, 0);
1273df8bae1dSRodney W. Grimes 	ipstat.ips_badoptions++;
1274df8bae1dSRodney W. Grimes 	return (1);
1275df8bae1dSRodney W. Grimes }
1276df8bae1dSRodney W. Grimes 
1277df8bae1dSRodney W. Grimes /*
1278df8bae1dSRodney W. Grimes  * Given address of next destination (final or next hop),
1279df8bae1dSRodney W. Grimes  * return internet address info of interface to be used to get there.
1280df8bae1dSRodney W. Grimes  */
12810312fbe9SPoul-Henning Kamp static struct in_ifaddr *
1282df8bae1dSRodney W. Grimes ip_rtaddr(dst)
1283df8bae1dSRodney W. Grimes 	 struct in_addr dst;
1284df8bae1dSRodney W. Grimes {
1285df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
1286df8bae1dSRodney W. Grimes 
1287df8bae1dSRodney W. Grimes 	sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
1288df8bae1dSRodney W. Grimes 
1289df8bae1dSRodney W. Grimes 	if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
1290df8bae1dSRodney W. Grimes 		if (ipforward_rt.ro_rt) {
1291df8bae1dSRodney W. Grimes 			RTFREE(ipforward_rt.ro_rt);
1292df8bae1dSRodney W. Grimes 			ipforward_rt.ro_rt = 0;
1293df8bae1dSRodney W. Grimes 		}
1294df8bae1dSRodney W. Grimes 		sin->sin_family = AF_INET;
1295df8bae1dSRodney W. Grimes 		sin->sin_len = sizeof(*sin);
1296df8bae1dSRodney W. Grimes 		sin->sin_addr = dst;
1297df8bae1dSRodney W. Grimes 
12982c17fe93SGarrett Wollman 		rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
1299df8bae1dSRodney W. Grimes 	}
1300df8bae1dSRodney W. Grimes 	if (ipforward_rt.ro_rt == 0)
1301df8bae1dSRodney W. Grimes 		return ((struct in_ifaddr *)0);
1302df8bae1dSRodney W. Grimes 	return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa);
1303df8bae1dSRodney W. Grimes }
1304df8bae1dSRodney W. Grimes 
1305df8bae1dSRodney W. Grimes /*
1306df8bae1dSRodney W. Grimes  * Save incoming source route for use in replies,
1307df8bae1dSRodney W. Grimes  * to be picked up later by ip_srcroute if the receiver is interested.
1308df8bae1dSRodney W. Grimes  */
1309df8bae1dSRodney W. Grimes void
1310df8bae1dSRodney W. Grimes save_rte(option, dst)
1311df8bae1dSRodney W. Grimes 	u_char *option;
1312df8bae1dSRodney W. Grimes 	struct in_addr dst;
1313df8bae1dSRodney W. Grimes {
1314df8bae1dSRodney W. Grimes 	unsigned olen;
1315df8bae1dSRodney W. Grimes 
1316df8bae1dSRodney W. Grimes 	olen = option[IPOPT_OLEN];
1317df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1318df8bae1dSRodney W. Grimes 	if (ipprintfs)
1319df8bae1dSRodney W. Grimes 		printf("save_rte: olen %d\n", olen);
1320df8bae1dSRodney W. Grimes #endif
1321df8bae1dSRodney W. Grimes 	if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
1322df8bae1dSRodney W. Grimes 		return;
13230453d3cbSBruce Evans 	bcopy(option, ip_srcrt.srcopt, olen);
1324df8bae1dSRodney W. Grimes 	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
1325df8bae1dSRodney W. Grimes 	ip_srcrt.dst = dst;
1326df8bae1dSRodney W. Grimes }
1327df8bae1dSRodney W. Grimes 
1328df8bae1dSRodney W. Grimes /*
1329df8bae1dSRodney W. Grimes  * Retrieve incoming source route for use in replies,
1330df8bae1dSRodney W. Grimes  * in the same form used by setsockopt.
1331df8bae1dSRodney W. Grimes  * The first hop is placed before the options, will be removed later.
1332df8bae1dSRodney W. Grimes  */
1333df8bae1dSRodney W. Grimes struct mbuf *
1334df8bae1dSRodney W. Grimes ip_srcroute()
1335df8bae1dSRodney W. Grimes {
1336df8bae1dSRodney W. Grimes 	register struct in_addr *p, *q;
1337df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1338df8bae1dSRodney W. Grimes 
1339df8bae1dSRodney W. Grimes 	if (ip_nhops == 0)
1340df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1341cfe8b629SGarrett Wollman 	m = m_get(M_DONTWAIT, MT_HEADER);
1342df8bae1dSRodney W. Grimes 	if (m == 0)
1343df8bae1dSRodney W. Grimes 		return ((struct mbuf *)0);
1344df8bae1dSRodney W. Grimes 
1345df8bae1dSRodney W. Grimes #define OPTSIZ	(sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
1346df8bae1dSRodney W. Grimes 
1347df8bae1dSRodney W. Grimes 	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
1348df8bae1dSRodney W. Grimes 	m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
1349df8bae1dSRodney W. Grimes 	    OPTSIZ;
1350df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1351df8bae1dSRodney W. Grimes 	if (ipprintfs)
1352df8bae1dSRodney W. Grimes 		printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
1353df8bae1dSRodney W. Grimes #endif
1354df8bae1dSRodney W. Grimes 
1355df8bae1dSRodney W. Grimes 	/*
1356df8bae1dSRodney W. Grimes 	 * First save first hop for return route
1357df8bae1dSRodney W. Grimes 	 */
1358df8bae1dSRodney W. Grimes 	p = &ip_srcrt.route[ip_nhops - 1];
1359df8bae1dSRodney W. Grimes 	*(mtod(m, struct in_addr *)) = *p--;
1360df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1361df8bae1dSRodney W. Grimes 	if (ipprintfs)
1362af38c68cSLuigi Rizzo 		printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));
1363df8bae1dSRodney W. Grimes #endif
1364df8bae1dSRodney W. Grimes 
1365df8bae1dSRodney W. Grimes 	/*
1366df8bae1dSRodney W. Grimes 	 * Copy option fields and padding (nop) to mbuf.
1367df8bae1dSRodney W. Grimes 	 */
1368df8bae1dSRodney W. Grimes 	ip_srcrt.nop = IPOPT_NOP;
1369df8bae1dSRodney W. Grimes 	ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
137094a5d9b6SDavid Greenman 	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),
137194a5d9b6SDavid Greenman 	    &ip_srcrt.nop, OPTSIZ);
1372df8bae1dSRodney W. Grimes 	q = (struct in_addr *)(mtod(m, caddr_t) +
1373df8bae1dSRodney W. Grimes 	    sizeof(struct in_addr) + OPTSIZ);
1374df8bae1dSRodney W. Grimes #undef OPTSIZ
1375df8bae1dSRodney W. Grimes 	/*
1376df8bae1dSRodney W. Grimes 	 * Record return path as an IP source route,
1377df8bae1dSRodney W. Grimes 	 * reversing the path (pointers are now aligned).
1378df8bae1dSRodney W. Grimes 	 */
1379df8bae1dSRodney W. Grimes 	while (p >= ip_srcrt.route) {
1380df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1381df8bae1dSRodney W. Grimes 		if (ipprintfs)
1382af38c68cSLuigi Rizzo 			printf(" %lx", (u_long)ntohl(q->s_addr));
1383df8bae1dSRodney W. Grimes #endif
1384df8bae1dSRodney W. Grimes 		*q++ = *p--;
1385df8bae1dSRodney W. Grimes 	}
1386df8bae1dSRodney W. Grimes 	/*
1387df8bae1dSRodney W. Grimes 	 * Last hop goes to final destination.
1388df8bae1dSRodney W. Grimes 	 */
1389df8bae1dSRodney W. Grimes 	*q = ip_srcrt.dst;
1390df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1391df8bae1dSRodney W. Grimes 	if (ipprintfs)
1392af38c68cSLuigi Rizzo 		printf(" %lx\n", (u_long)ntohl(q->s_addr));
1393df8bae1dSRodney W. Grimes #endif
1394df8bae1dSRodney W. Grimes 	return (m);
1395df8bae1dSRodney W. Grimes }
1396df8bae1dSRodney W. Grimes 
1397df8bae1dSRodney W. Grimes /*
1398df8bae1dSRodney W. Grimes  * Strip out IP options, at higher
1399df8bae1dSRodney W. Grimes  * level protocol in the kernel.
1400df8bae1dSRodney W. Grimes  * Second argument is buffer to which options
1401df8bae1dSRodney W. Grimes  * will be moved, and return value is their length.
1402df8bae1dSRodney W. Grimes  * XXX should be deleted; last arg currently ignored.
1403df8bae1dSRodney W. Grimes  */
1404df8bae1dSRodney W. Grimes void
1405df8bae1dSRodney W. Grimes ip_stripoptions(m, mopt)
1406df8bae1dSRodney W. Grimes 	register struct mbuf *m;
1407df8bae1dSRodney W. Grimes 	struct mbuf *mopt;
1408df8bae1dSRodney W. Grimes {
1409df8bae1dSRodney W. Grimes 	register int i;
1410df8bae1dSRodney W. Grimes 	struct ip *ip = mtod(m, struct ip *);
1411df8bae1dSRodney W. Grimes 	register caddr_t opts;
1412df8bae1dSRodney W. Grimes 	int olen;
1413df8bae1dSRodney W. Grimes 
141458938916SGarrett Wollman 	olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);
1415df8bae1dSRodney W. Grimes 	opts = (caddr_t)(ip + 1);
1416df8bae1dSRodney W. Grimes 	i = m->m_len - (sizeof (struct ip) + olen);
1417df8bae1dSRodney W. Grimes 	bcopy(opts + olen, opts, (unsigned)i);
1418df8bae1dSRodney W. Grimes 	m->m_len -= olen;
1419df8bae1dSRodney W. Grimes 	if (m->m_flags & M_PKTHDR)
1420df8bae1dSRodney W. Grimes 		m->m_pkthdr.len -= olen;
142158938916SGarrett Wollman 	ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2);
1422df8bae1dSRodney W. Grimes }
1423df8bae1dSRodney W. Grimes 
1424df8bae1dSRodney W. Grimes u_char inetctlerrmap[PRC_NCMDS] = {
1425df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
1426df8bae1dSRodney W. Grimes 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
1427df8bae1dSRodney W. Grimes 	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
1428df8bae1dSRodney W. Grimes 	EMSGSIZE,	EHOSTUNREACH,	0,		0,
1429df8bae1dSRodney W. Grimes 	0,		0,		0,		0,
1430df8bae1dSRodney W. Grimes 	ENOPROTOOPT
1431df8bae1dSRodney W. Grimes };
1432df8bae1dSRodney W. Grimes 
1433df8bae1dSRodney W. Grimes /*
1434df8bae1dSRodney W. Grimes  * Forward a packet.  If some error occurs return the sender
1435df8bae1dSRodney W. Grimes  * an icmp packet.  Note we can't always generate a meaningful
1436df8bae1dSRodney W. Grimes  * icmp message because icmp doesn't have a large enough repertoire
1437df8bae1dSRodney W. Grimes  * of codes and types.
1438df8bae1dSRodney W. Grimes  *
1439df8bae1dSRodney W. Grimes  * If not forwarding, just drop the packet.  This could be confusing
1440df8bae1dSRodney W. Grimes  * if ipforwarding was zero but some routing protocol was advancing
1441df8bae1dSRodney W. Grimes  * us as a gateway to somewhere.  However, we must let the routing
1442df8bae1dSRodney W. Grimes  * protocol deal with that.
1443df8bae1dSRodney W. Grimes  *
1444df8bae1dSRodney W. Grimes  * The srcrt parameter indicates whether the packet is being forwarded
1445df8bae1dSRodney W. Grimes  * via a source route.
1446df8bae1dSRodney W. Grimes  */
14470312fbe9SPoul-Henning Kamp static void
1448df8bae1dSRodney W. Grimes ip_forward(m, srcrt)
1449df8bae1dSRodney W. Grimes 	struct mbuf *m;
1450df8bae1dSRodney W. Grimes 	int srcrt;
1451df8bae1dSRodney W. Grimes {
1452df8bae1dSRodney W. Grimes 	register struct ip *ip = mtod(m, struct ip *);
1453df8bae1dSRodney W. Grimes 	register struct sockaddr_in *sin;
1454df8bae1dSRodney W. Grimes 	register struct rtentry *rt;
145526f9a767SRodney W. Grimes 	int error, type = 0, code = 0;
1456df8bae1dSRodney W. Grimes 	struct mbuf *mcopy;
1457df8bae1dSRodney W. Grimes 	n_long dest;
1458df8bae1dSRodney W. Grimes 	struct ifnet *destifp;
14596a800098SYoshinobu Inoue #ifdef IPSEC
14606a800098SYoshinobu Inoue 	struct ifnet dummyifp;
14616a800098SYoshinobu Inoue #endif
1462df8bae1dSRodney W. Grimes 
1463df8bae1dSRodney W. Grimes 	dest = 0;
1464df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1465df8bae1dSRodney W. Grimes 	if (ipprintfs)
146661ce519bSPoul-Henning Kamp 		printf("forward: src %lx dst %lx ttl %x\n",
1467162886e2SBruce Evans 		    (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr,
1468162886e2SBruce Evans 		    ip->ip_ttl);
1469df8bae1dSRodney W. Grimes #endif
1470100ba1a6SJordan K. Hubbard 
1471100ba1a6SJordan K. Hubbard 
147292af003dSGarrett Wollman 	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
1473df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1474df8bae1dSRodney W. Grimes 		m_freem(m);
1475df8bae1dSRodney W. Grimes 		return;
1476df8bae1dSRodney W. Grimes 	}
1477df8bae1dSRodney W. Grimes 	HTONS(ip->ip_id);
14781b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
14791b968362SDag-Erling Smørgrav 	if (!ipstealth) {
14801b968362SDag-Erling Smørgrav #endif
1481df8bae1dSRodney W. Grimes 		if (ip->ip_ttl <= IPTTLDEC) {
14821b968362SDag-Erling Smørgrav 			icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
14831b968362SDag-Erling Smørgrav 			    dest, 0);
1484df8bae1dSRodney W. Grimes 			return;
1485df8bae1dSRodney W. Grimes 		}
1486df8bae1dSRodney W. Grimes 		ip->ip_ttl -= IPTTLDEC;
14871b968362SDag-Erling Smørgrav #ifdef IPSTEALTH
14881b968362SDag-Erling Smørgrav 	}
14891b968362SDag-Erling Smørgrav #endif
1490df8bae1dSRodney W. Grimes 
1491df8bae1dSRodney W. Grimes 	sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
1492df8bae1dSRodney W. Grimes 	if ((rt = ipforward_rt.ro_rt) == 0 ||
1493df8bae1dSRodney W. Grimes 	    ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
1494df8bae1dSRodney W. Grimes 		if (ipforward_rt.ro_rt) {
1495df8bae1dSRodney W. Grimes 			RTFREE(ipforward_rt.ro_rt);
1496df8bae1dSRodney W. Grimes 			ipforward_rt.ro_rt = 0;
1497df8bae1dSRodney W. Grimes 		}
1498df8bae1dSRodney W. Grimes 		sin->sin_family = AF_INET;
1499df8bae1dSRodney W. Grimes 		sin->sin_len = sizeof(*sin);
1500df8bae1dSRodney W. Grimes 		sin->sin_addr = ip->ip_dst;
1501df8bae1dSRodney W. Grimes 
15022c17fe93SGarrett Wollman 		rtalloc_ign(&ipforward_rt, RTF_PRCLONING);
1503df8bae1dSRodney W. Grimes 		if (ipforward_rt.ro_rt == 0) {
1504df8bae1dSRodney W. Grimes 			icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
1505df8bae1dSRodney W. Grimes 			return;
1506df8bae1dSRodney W. Grimes 		}
1507df8bae1dSRodney W. Grimes 		rt = ipforward_rt.ro_rt;
1508df8bae1dSRodney W. Grimes 	}
1509df8bae1dSRodney W. Grimes 
1510df8bae1dSRodney W. Grimes 	/*
1511df8bae1dSRodney W. Grimes 	 * Save at most 64 bytes of the packet in case
1512df8bae1dSRodney W. Grimes 	 * we need to generate an ICMP message to the src.
1513df8bae1dSRodney W. Grimes 	 */
1514df8bae1dSRodney W. Grimes 	mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64));
1515df8bae1dSRodney W. Grimes 
1516df8bae1dSRodney W. Grimes 	/*
1517df8bae1dSRodney W. Grimes 	 * If forwarding packet using same interface that it came in on,
1518df8bae1dSRodney W. Grimes 	 * perhaps should send a redirect to sender to shortcut a hop.
1519df8bae1dSRodney W. Grimes 	 * Only send redirect if source is sending directly to us,
1520df8bae1dSRodney W. Grimes 	 * and if packet was not source routed (or has any options).
1521df8bae1dSRodney W. Grimes 	 * Also, don't send redirect if forwarding using a default route
1522df8bae1dSRodney W. Grimes 	 * or a route modified by a redirect.
1523df8bae1dSRodney W. Grimes 	 */
1524df8bae1dSRodney W. Grimes #define	satosin(sa)	((struct sockaddr_in *)(sa))
1525df8bae1dSRodney W. Grimes 	if (rt->rt_ifp == m->m_pkthdr.rcvif &&
1526df8bae1dSRodney W. Grimes 	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
1527df8bae1dSRodney W. Grimes 	    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
1528df8bae1dSRodney W. Grimes 	    ipsendredirects && !srcrt) {
1529df8bae1dSRodney W. Grimes #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
1530df8bae1dSRodney W. Grimes 		u_long src = ntohl(ip->ip_src.s_addr);
1531df8bae1dSRodney W. Grimes 
1532df8bae1dSRodney W. Grimes 		if (RTA(rt) &&
1533df8bae1dSRodney W. Grimes 		    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
1534df8bae1dSRodney W. Grimes 		    if (rt->rt_flags & RTF_GATEWAY)
1535df8bae1dSRodney W. Grimes 			dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
1536df8bae1dSRodney W. Grimes 		    else
1537df8bae1dSRodney W. Grimes 			dest = ip->ip_dst.s_addr;
1538df8bae1dSRodney W. Grimes 		    /* Router requirements says to only send host redirects */
1539df8bae1dSRodney W. Grimes 		    type = ICMP_REDIRECT;
1540df8bae1dSRodney W. Grimes 		    code = ICMP_REDIRECT_HOST;
1541df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
1542df8bae1dSRodney W. Grimes 		    if (ipprintfs)
1543df8bae1dSRodney W. Grimes 		        printf("redirect (%d) to %lx\n", code, (u_long)dest);
1544df8bae1dSRodney W. Grimes #endif
1545df8bae1dSRodney W. Grimes 		}
1546df8bae1dSRodney W. Grimes 	}
1547df8bae1dSRodney W. Grimes 
1548b97d15cbSGarrett Wollman 	error = ip_output(m, (struct mbuf *)0, &ipforward_rt,
1549b97d15cbSGarrett Wollman 			  IP_FORWARDING, 0);
1550df8bae1dSRodney W. Grimes 	if (error)
1551df8bae1dSRodney W. Grimes 		ipstat.ips_cantforward++;
1552df8bae1dSRodney W. Grimes 	else {
1553df8bae1dSRodney W. Grimes 		ipstat.ips_forward++;
1554df8bae1dSRodney W. Grimes 		if (type)
1555df8bae1dSRodney W. Grimes 			ipstat.ips_redirectsent++;
1556df8bae1dSRodney W. Grimes 		else {
15571f91d8c5SDavid Greenman 			if (mcopy) {
15581f91d8c5SDavid Greenman 				ipflow_create(&ipforward_rt, mcopy);
1559df8bae1dSRodney W. Grimes 				m_freem(mcopy);
15601f91d8c5SDavid Greenman 			}
1561df8bae1dSRodney W. Grimes 			return;
1562df8bae1dSRodney W. Grimes 		}
1563df8bae1dSRodney W. Grimes 	}
1564df8bae1dSRodney W. Grimes 	if (mcopy == NULL)
1565df8bae1dSRodney W. Grimes 		return;
1566df8bae1dSRodney W. Grimes 	destifp = NULL;
1567df8bae1dSRodney W. Grimes 
1568df8bae1dSRodney W. Grimes 	switch (error) {
1569df8bae1dSRodney W. Grimes 
1570df8bae1dSRodney W. Grimes 	case 0:				/* forwarded, but need redirect */
1571df8bae1dSRodney W. Grimes 		/* type, code set above */
1572df8bae1dSRodney W. Grimes 		break;
1573df8bae1dSRodney W. Grimes 
1574df8bae1dSRodney W. Grimes 	case ENETUNREACH:		/* shouldn't happen, checked above */
1575df8bae1dSRodney W. Grimes 	case EHOSTUNREACH:
1576df8bae1dSRodney W. Grimes 	case ENETDOWN:
1577df8bae1dSRodney W. Grimes 	case EHOSTDOWN:
1578df8bae1dSRodney W. Grimes 	default:
1579df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1580df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_HOST;
1581df8bae1dSRodney W. Grimes 		break;
1582df8bae1dSRodney W. Grimes 
1583df8bae1dSRodney W. Grimes 	case EMSGSIZE:
1584df8bae1dSRodney W. Grimes 		type = ICMP_UNREACH;
1585df8bae1dSRodney W. Grimes 		code = ICMP_UNREACH_NEEDFRAG;
15866a800098SYoshinobu Inoue #ifndef IPSEC
1587df8bae1dSRodney W. Grimes 		if (ipforward_rt.ro_rt)
1588df8bae1dSRodney W. Grimes 			destifp = ipforward_rt.ro_rt->rt_ifp;
15896a800098SYoshinobu Inoue #else
15906a800098SYoshinobu Inoue 		/*
15916a800098SYoshinobu Inoue 		 * If the packet is routed over IPsec tunnel, tell the
15926a800098SYoshinobu Inoue 		 * originator the tunnel MTU.
15936a800098SYoshinobu Inoue 		 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
15946a800098SYoshinobu Inoue 		 * XXX quickhack!!!
15956a800098SYoshinobu Inoue 		 */
15966a800098SYoshinobu Inoue 		if (ipforward_rt.ro_rt) {
15976a800098SYoshinobu Inoue 			struct secpolicy *sp = NULL;
15986a800098SYoshinobu Inoue 			int ipsecerror;
15996a800098SYoshinobu Inoue 			int ipsechdr;
16006a800098SYoshinobu Inoue 			struct route *ro;
16016a800098SYoshinobu Inoue 
16026a800098SYoshinobu Inoue 			sp = ipsec4_getpolicybyaddr(mcopy,
16036a800098SYoshinobu Inoue 						    IPSEC_DIR_OUTBOUND,
16046a800098SYoshinobu Inoue 			                            IP_FORWARDING,
16056a800098SYoshinobu Inoue 			                            &ipsecerror);
16066a800098SYoshinobu Inoue 
16076a800098SYoshinobu Inoue 			if (sp == NULL)
16086a800098SYoshinobu Inoue 				destifp = ipforward_rt.ro_rt->rt_ifp;
16096a800098SYoshinobu Inoue 			else {
16106a800098SYoshinobu Inoue 				/* count IPsec header size */
16116a800098SYoshinobu Inoue 				ipsechdr = ipsec4_hdrsiz(mcopy,
16126a800098SYoshinobu Inoue 							 IPSEC_DIR_OUTBOUND,
16136a800098SYoshinobu Inoue 							 NULL);
16146a800098SYoshinobu Inoue 
16156a800098SYoshinobu Inoue 				/*
16166a800098SYoshinobu Inoue 				 * find the correct route for outer IPv4
16176a800098SYoshinobu Inoue 				 * header, compute tunnel MTU.
16186a800098SYoshinobu Inoue 				 *
16196a800098SYoshinobu Inoue 				 * XXX BUG ALERT
16206a800098SYoshinobu Inoue 				 * The "dummyifp" code relies upon the fact
16216a800098SYoshinobu Inoue 				 * that icmp_error() touches only ifp->if_mtu.
16226a800098SYoshinobu Inoue 				 */
16236a800098SYoshinobu Inoue 				/*XXX*/
16246a800098SYoshinobu Inoue 				destifp = NULL;
16256a800098SYoshinobu Inoue 				if (sp->req != NULL
16266a800098SYoshinobu Inoue 				 && sp->req->sav != NULL
16276a800098SYoshinobu Inoue 				 && sp->req->sav->sah != NULL) {
16286a800098SYoshinobu Inoue 					ro = &sp->req->sav->sah->sa_route;
16296a800098SYoshinobu Inoue 					if (ro->ro_rt && ro->ro_rt->rt_ifp) {
16306a800098SYoshinobu Inoue 						dummyifp.if_mtu =
16316a800098SYoshinobu Inoue 						    ro->ro_rt->rt_ifp->if_mtu;
16326a800098SYoshinobu Inoue 						dummyifp.if_mtu -= ipsechdr;
16336a800098SYoshinobu Inoue 						destifp = &dummyifp;
16346a800098SYoshinobu Inoue 					}
16356a800098SYoshinobu Inoue 				}
16366a800098SYoshinobu Inoue 
16376a800098SYoshinobu Inoue 				key_freesp(sp);
16386a800098SYoshinobu Inoue 			}
16396a800098SYoshinobu Inoue 		}
16406a800098SYoshinobu Inoue #endif /*IPSEC*/
1641df8bae1dSRodney W. Grimes 		ipstat.ips_cantfrag++;
1642df8bae1dSRodney W. Grimes 		break;
1643df8bae1dSRodney W. Grimes 
1644df8bae1dSRodney W. Grimes 	case ENOBUFS:
1645df8bae1dSRodney W. Grimes 		type = ICMP_SOURCEQUENCH;
1646df8bae1dSRodney W. Grimes 		code = 0;
1647df8bae1dSRodney W. Grimes 		break;
1648df8bae1dSRodney W. Grimes 	}
1649df8bae1dSRodney W. Grimes 	icmp_error(mcopy, type, code, dest, destifp);
1650df8bae1dSRodney W. Grimes }
1651df8bae1dSRodney W. Grimes 
165282c23ebaSBill Fenner void
165382c23ebaSBill Fenner ip_savecontrol(inp, mp, ip, m)
165482c23ebaSBill Fenner 	register struct inpcb *inp;
165582c23ebaSBill Fenner 	register struct mbuf **mp;
165682c23ebaSBill Fenner 	register struct ip *ip;
165782c23ebaSBill Fenner 	register struct mbuf *m;
165882c23ebaSBill Fenner {
165982c23ebaSBill Fenner 	if (inp->inp_socket->so_options & SO_TIMESTAMP) {
166082c23ebaSBill Fenner 		struct timeval tv;
166182c23ebaSBill Fenner 
166282c23ebaSBill Fenner 		microtime(&tv);
166382c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
166482c23ebaSBill Fenner 			SCM_TIMESTAMP, SOL_SOCKET);
166582c23ebaSBill Fenner 		if (*mp)
166682c23ebaSBill Fenner 			mp = &(*mp)->m_next;
166782c23ebaSBill Fenner 	}
166882c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVDSTADDR) {
166982c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) &ip->ip_dst,
167082c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);
167182c23ebaSBill Fenner 		if (*mp)
167282c23ebaSBill Fenner 			mp = &(*mp)->m_next;
167382c23ebaSBill Fenner 	}
167482c23ebaSBill Fenner #ifdef notyet
167582c23ebaSBill Fenner 	/* XXX
167682c23ebaSBill Fenner 	 * Moving these out of udp_input() made them even more broken
167782c23ebaSBill Fenner 	 * than they already were.
167882c23ebaSBill Fenner 	 */
167982c23ebaSBill Fenner 	/* options were tossed already */
168082c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVOPTS) {
168182c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) opts_deleted_above,
168282c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);
168382c23ebaSBill Fenner 		if (*mp)
168482c23ebaSBill Fenner 			mp = &(*mp)->m_next;
168582c23ebaSBill Fenner 	}
168682c23ebaSBill Fenner 	/* ip_srcroute doesn't do what we want here, need to fix */
168782c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVRETOPTS) {
168882c23ebaSBill Fenner 		*mp = sbcreatecontrol((caddr_t) ip_srcroute(),
168982c23ebaSBill Fenner 		    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);
169082c23ebaSBill Fenner 		if (*mp)
169182c23ebaSBill Fenner 			mp = &(*mp)->m_next;
169282c23ebaSBill Fenner 	}
169382c23ebaSBill Fenner #endif
169482c23ebaSBill Fenner 	if (inp->inp_flags & INP_RECVIF) {
1695d314ad7bSJulian Elischer 		struct ifnet *ifp;
1696d314ad7bSJulian Elischer 		struct sdlbuf {
169782c23ebaSBill Fenner 			struct sockaddr_dl sdl;
1698d314ad7bSJulian Elischer 			u_char	pad[32];
1699d314ad7bSJulian Elischer 		} sdlbuf;
1700d314ad7bSJulian Elischer 		struct sockaddr_dl *sdp;
1701d314ad7bSJulian Elischer 		struct sockaddr_dl *sdl2 = &sdlbuf.sdl;
170282c23ebaSBill Fenner 
1703d314ad7bSJulian Elischer 		if (((ifp = m->m_pkthdr.rcvif))
1704d314ad7bSJulian Elischer 		&& ( ifp->if_index && (ifp->if_index <= if_index))) {
1705d314ad7bSJulian Elischer 			sdp = (struct sockaddr_dl *)(ifnet_addrs
1706d314ad7bSJulian Elischer 					[ifp->if_index - 1]->ifa_addr);
1707d314ad7bSJulian Elischer 			/*
1708d314ad7bSJulian Elischer 			 * Change our mind and don't try copy.
1709d314ad7bSJulian Elischer 			 */
1710d314ad7bSJulian Elischer 			if ((sdp->sdl_family != AF_LINK)
1711d314ad7bSJulian Elischer 			|| (sdp->sdl_len > sizeof(sdlbuf))) {
1712d314ad7bSJulian Elischer 				goto makedummy;
1713d314ad7bSJulian Elischer 			}
1714d314ad7bSJulian Elischer 			bcopy(sdp, sdl2, sdp->sdl_len);
1715d314ad7bSJulian Elischer 		} else {
1716d314ad7bSJulian Elischer makedummy:
1717d314ad7bSJulian Elischer 			sdl2->sdl_len
1718d314ad7bSJulian Elischer 				= offsetof(struct sockaddr_dl, sdl_data[0]);
1719d314ad7bSJulian Elischer 			sdl2->sdl_family = AF_LINK;
1720d314ad7bSJulian Elischer 			sdl2->sdl_index = 0;
1721d314ad7bSJulian Elischer 			sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;
1722d314ad7bSJulian Elischer 		}
1723d314ad7bSJulian Elischer 		*mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,
172482c23ebaSBill Fenner 			IP_RECVIF, IPPROTO_IP);
172582c23ebaSBill Fenner 		if (*mp)
172682c23ebaSBill Fenner 			mp = &(*mp)->m_next;
172782c23ebaSBill Fenner 	}
172882c23ebaSBill Fenner }
172982c23ebaSBill Fenner 
1730df8bae1dSRodney W. Grimes int
1731f0068c4aSGarrett Wollman ip_rsvp_init(struct socket *so)
1732f0068c4aSGarrett Wollman {
1733f0068c4aSGarrett Wollman 	if (so->so_type != SOCK_RAW ||
1734f0068c4aSGarrett Wollman 	    so->so_proto->pr_protocol != IPPROTO_RSVP)
1735f0068c4aSGarrett Wollman 	  return EOPNOTSUPP;
1736f0068c4aSGarrett Wollman 
1737f0068c4aSGarrett Wollman 	if (ip_rsvpd != NULL)
1738f0068c4aSGarrett Wollman 	  return EADDRINUSE;
1739f0068c4aSGarrett Wollman 
1740f0068c4aSGarrett Wollman 	ip_rsvpd = so;
17411c5de19aSGarrett Wollman 	/*
17421c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-increment
17431c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
17441c5de19aSGarrett Wollman 	 */
17451c5de19aSGarrett Wollman 	if (!ip_rsvp_on) {
17461c5de19aSGarrett Wollman 		ip_rsvp_on = 1;
17471c5de19aSGarrett Wollman 		rsvp_on++;
17481c5de19aSGarrett Wollman 	}
1749f0068c4aSGarrett Wollman 
1750f0068c4aSGarrett Wollman 	return 0;
1751f0068c4aSGarrett Wollman }
1752f0068c4aSGarrett Wollman 
1753f0068c4aSGarrett Wollman int
1754f0068c4aSGarrett Wollman ip_rsvp_done(void)
1755f0068c4aSGarrett Wollman {
1756f0068c4aSGarrett Wollman 	ip_rsvpd = NULL;
17571c5de19aSGarrett Wollman 	/*
17581c5de19aSGarrett Wollman 	 * This may seem silly, but we need to be sure we don't over-decrement
17591c5de19aSGarrett Wollman 	 * the RSVP counter, in case something slips up.
17601c5de19aSGarrett Wollman 	 */
17611c5de19aSGarrett Wollman 	if (ip_rsvp_on) {
17621c5de19aSGarrett Wollman 		ip_rsvp_on = 0;
17631c5de19aSGarrett Wollman 		rsvp_on--;
17641c5de19aSGarrett Wollman 	}
1765f0068c4aSGarrett Wollman 	return 0;
1766f0068c4aSGarrett Wollman }
1767