xref: /csrg-svn/sys/netinet/ip_input.c (revision 23184)
1*23184Smckusick /*
2*23184Smckusick  * Copyright (c) 1982 Regents of the University of California.
3*23184Smckusick  * All rights reserved.  The Berkeley software License Agreement
4*23184Smckusick  * specifies the terms and conditions for redistribution.
5*23184Smckusick  *
6*23184Smckusick  *	@(#)ip_input.c	6.11 (Berkeley) 06/08/85
7*23184Smckusick  */
84571Swnj 
917060Sbloom #include "param.h"
1017060Sbloom #include "systm.h"
1117060Sbloom #include "mbuf.h"
1217060Sbloom #include "domain.h"
1317060Sbloom #include "protosw.h"
1417060Sbloom #include "socket.h"
1517060Sbloom #include "errno.h"
1617060Sbloom #include "time.h"
1717060Sbloom #include "kernel.h"
188695Sroot 
198695Sroot #include "../net/if.h"
208695Sroot #include "../net/route.h"
2110892Ssam 
2217060Sbloom #include "in.h"
2317060Sbloom #include "in_pcb.h"
2417060Sbloom #include "in_systm.h"
2518376Skarels #include "in_var.h"
2617060Sbloom #include "ip.h"
2717060Sbloom #include "ip_var.h"
2817060Sbloom #include "ip_icmp.h"
2917060Sbloom #include "tcp.h"
304495Swnj 
314898Swnj u_char	ip_protox[IPPROTO_MAX];
326210Swnj int	ipqmaxlen = IFQ_MAXLEN;
3318376Skarels struct	in_ifaddr *in_ifaddr;			/* first inet address */
344898Swnj 
354801Swnj /*
365172Swnj  * IP initialization: fill in IP protocol switch table.
375161Swnj  * All protocols not implemented in kernel go to raw IP protocol handler.
384801Swnj  */
394801Swnj ip_init()
404801Swnj {
414898Swnj 	register struct protosw *pr;
424898Swnj 	register int i;
434495Swnj 
444898Swnj 	pr = pffindproto(PF_INET, IPPROTO_RAW);
454898Swnj 	if (pr == 0)
464898Swnj 		panic("ip_init");
474898Swnj 	for (i = 0; i < IPPROTO_MAX; i++)
489030Sroot 		ip_protox[i] = pr - inetsw;
499030Sroot 	for (pr = inetdomain.dom_protosw;
5017551Skarels 	    pr < inetdomain.dom_protoswNPROTOSW; pr++)
5116990Skarels 		if (pr->pr_domain->dom_family == PF_INET &&
524898Swnj 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
539030Sroot 			ip_protox[pr->pr_protocol] = pr - inetsw;
544801Swnj 	ipq.next = ipq.prev = &ipq;
558172Sroot 	ip_id = time.tv_sec & 0xffff;
566210Swnj 	ipintrq.ifq_maxlen = ipqmaxlen;
574801Swnj }
584801Swnj 
594898Swnj u_char	ipcksum = 1;
604640Swnj struct	ip *ip_reass();
616338Ssam struct	sockaddr_in ipaddr = { AF_INET };
624640Swnj 
634640Swnj /*
644640Swnj  * Ip input routine.  Checksum and byte swap header.  If fragmented
654640Swnj  * try to reassamble.  If complete and fragment queue exists, discard.
664640Swnj  * Process options.  Pass to next level.
674640Swnj  */
685084Swnj ipintr()
694495Swnj {
704923Swnj 	register struct ip *ip;
715084Swnj 	register struct mbuf *m;
728597Sroot 	struct mbuf *m0;
734640Swnj 	register int i;
744495Swnj 	register struct ipq *fp;
7518376Skarels 	register struct in_ifaddr *ia;
765084Swnj 	int hlen, s;
774495Swnj 
785084Swnj next:
794640Swnj 	/*
805084Swnj 	 * Get next datagram off input queue and get IP header
815084Swnj 	 * in first mbuf.
824640Swnj 	 */
835084Swnj 	s = splimp();
845084Swnj 	IF_DEQUEUE(&ipintrq, m);
855084Swnj 	splx(s);
865218Swnj 	if (m == 0)
875084Swnj 		return;
885306Sroot 	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) &&
8911232Ssam 	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
9011232Ssam 		ipstat.ips_toosmall++;
9111232Ssam 		goto next;
9211232Ssam 	}
934640Swnj 	ip = mtod(m, struct ip *);
9418376Skarels 	hlen = ip->ip_hl << 2;
9518376Skarels 	if (hlen < 10) {	/* minimum header length */
9618376Skarels 		ipstat.ips_badhlen++;
9721117Skarels 		goto bad;
9818376Skarels 	}
9918376Skarels 	if (hlen > m->m_len) {
10011232Ssam 		if ((m = m_pullup(m, hlen)) == 0) {
10111232Ssam 			ipstat.ips_badhlen++;
10211232Ssam 			goto next;
10311232Ssam 		}
1045161Swnj 		ip = mtod(m, struct ip *);
1055161Swnj 	}
1064951Swnj 	if (ipcksum)
1075217Swnj 		if (ip->ip_sum = in_cksum(m, hlen)) {
1084951Swnj 			ipstat.ips_badsum++;
1094951Swnj 			goto bad;
1104495Swnj 		}
1114951Swnj 
1124951Swnj 	/*
1134951Swnj 	 * Convert fields to host representation.
1144951Swnj 	 */
1154907Swnj 	ip->ip_len = ntohs((u_short)ip->ip_len);
11611232Ssam 	if (ip->ip_len < hlen) {
11711232Ssam 		ipstat.ips_badlen++;
11811232Ssam 		goto bad;
11911232Ssam 	}
1204640Swnj 	ip->ip_id = ntohs(ip->ip_id);
1214951Swnj 	ip->ip_off = ntohs((u_short)ip->ip_off);
1224495Swnj 
1234543Swnj 	/*
1244640Swnj 	 * Check that the amount of data in the buffers
1254640Swnj 	 * is as at least much as the IP header would have us expect.
1264640Swnj 	 * Trim mbufs if longer than we expect.
1274640Swnj 	 * Drop packet if shorter than we expect.
1284543Swnj 	 */
1296475Sroot 	i = -ip->ip_len;
1305161Swnj 	m0 = m;
1316475Sroot 	for (;;) {
1324495Swnj 		i += m->m_len;
1336475Sroot 		if (m->m_next == 0)
1346475Sroot 			break;
1356475Sroot 		m = m->m_next;
1366088Sroot 	}
1376475Sroot 	if (i != 0) {
1386475Sroot 		if (i < 0) {
1395161Swnj 			ipstat.ips_tooshort++;
14017358Skarels 			m = m0;
1414951Swnj 			goto bad;
1425161Swnj 		}
1436475Sroot 		if (i <= m->m_len)
1446475Sroot 			m->m_len -= i;
1456475Sroot 		else
1466475Sroot 			m_adj(m0, -i);
1474495Swnj 	}
1486475Sroot 	m = m0;
1494495Swnj 
1504640Swnj 	/*
1514640Swnj 	 * Process options and, if not destined for us,
1526583Ssam 	 * ship it on.  ip_dooptions returns 1 when an
1536583Ssam 	 * error was detected (causing an icmp message
15421117Skarels 	 * to be sent and the original packet to be freed).
1554640Swnj 	 */
1566583Ssam 	if (hlen > sizeof (struct ip) && ip_dooptions(ip))
1576583Ssam 		goto next;
1586210Swnj 
1596338Ssam 	/*
16018376Skarels 	 * Check our list of addresses, to see if the packet is for us.
1616338Ssam 	 */
16218376Skarels 	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
16318376Skarels #define	satosin(sa)	((struct sockaddr_in *)(sa))
1646338Ssam 
16518376Skarels 		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
16618376Skarels 			break;
16718376Skarels 		if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
16818376Skarels 		    satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
16918376Skarels 			ip->ip_dst.s_addr)
17018376Skarels 			    break;
17118376Skarels 		/*
17218376Skarels 		 * Look for all-0's host part (old broadcast addr).
17318376Skarels 		 */
17418376Skarels 		if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
17518376Skarels 		    ia->ia_subnet == ntohl(ip->ip_dst.s_addr))
17618376Skarels 			break;
1776338Ssam 	}
17818376Skarels 	if (ia == (struct in_ifaddr *)0) {
1796583Ssam 		ip_forward(ip);
1805084Swnj 		goto next;
1814543Swnj 	}
1824495Swnj 
1834640Swnj 	/*
1844640Swnj 	 * Look for queue of fragments
1854640Swnj 	 * of this datagram.
1864640Swnj 	 */
1874640Swnj 	for (fp = ipq.next; fp != &ipq; fp = fp->next)
1884640Swnj 		if (ip->ip_id == fp->ipq_id &&
1894640Swnj 		    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
1904640Swnj 		    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
1914640Swnj 		    ip->ip_p == fp->ipq_p)
1924640Swnj 			goto found;
1934640Swnj 	fp = 0;
1944640Swnj found:
1954495Swnj 
1964640Swnj 	/*
1974640Swnj 	 * Adjust ip_len to not reflect header,
1984640Swnj 	 * set ip_mff if more fragments are expected,
1994640Swnj 	 * convert offset of this to bytes.
2004640Swnj 	 */
2014640Swnj 	ip->ip_len -= hlen;
2024898Swnj 	((struct ipasfrag *)ip)->ipf_mff = 0;
2034640Swnj 	if (ip->ip_off & IP_MF)
2044898Swnj 		((struct ipasfrag *)ip)->ipf_mff = 1;
2054640Swnj 	ip->ip_off <<= 3;
2064495Swnj 
2074640Swnj 	/*
2084640Swnj 	 * If datagram marked as having more fragments
2094640Swnj 	 * or if this is not the first fragment,
2104640Swnj 	 * attempt reassembly; if it succeeds, proceed.
2114640Swnj 	 */
2124898Swnj 	if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
2134898Swnj 		ip = ip_reass((struct ipasfrag *)ip, fp);
2144640Swnj 		if (ip == 0)
2155084Swnj 			goto next;
2164640Swnj 		hlen = ip->ip_hl << 2;
2174640Swnj 		m = dtom(ip);
2184640Swnj 	} else
2194640Swnj 		if (fp)
22010735Ssam 			ip_freef(fp);
2214951Swnj 
2224951Swnj 	/*
2234951Swnj 	 * Switch out to protocol's input routine.
2244951Swnj 	 */
2259030Sroot 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m);
2265084Swnj 	goto next;
2274951Swnj bad:
2284951Swnj 	m_freem(m);
2295084Swnj 	goto next;
2304640Swnj }
2314495Swnj 
2324640Swnj /*
2334640Swnj  * Take incoming datagram fragment and try to
2344951Swnj  * reassemble it into whole datagram.  If a chain for
2354640Swnj  * reassembly of this datagram already exists, then it
2364640Swnj  * is given as fp; otherwise have to make a chain.
2374640Swnj  */
2384640Swnj struct ip *
2394640Swnj ip_reass(ip, fp)
2404898Swnj 	register struct ipasfrag *ip;
2414640Swnj 	register struct ipq *fp;
2424640Swnj {
2434640Swnj 	register struct mbuf *m = dtom(ip);
2444898Swnj 	register struct ipasfrag *q;
2454640Swnj 	struct mbuf *t;
2464640Swnj 	int hlen = ip->ip_hl << 2;
2474640Swnj 	int i, next;
2484543Swnj 
2494640Swnj 	/*
2504640Swnj 	 * Presence of header sizes in mbufs
2514640Swnj 	 * would confuse code below.
2524640Swnj 	 */
2534640Swnj 	m->m_off += hlen;
2544640Swnj 	m->m_len -= hlen;
2554495Swnj 
2564640Swnj 	/*
2574640Swnj 	 * If first fragment to arrive, create a reassembly queue.
2584640Swnj 	 */
2594640Swnj 	if (fp == 0) {
2609641Ssam 		if ((t = m_get(M_WAIT, MT_FTABLE)) == NULL)
2614640Swnj 			goto dropfrag;
2624640Swnj 		fp = mtod(t, struct ipq *);
2634640Swnj 		insque(fp, &ipq);
2644640Swnj 		fp->ipq_ttl = IPFRAGTTL;
2654640Swnj 		fp->ipq_p = ip->ip_p;
2664640Swnj 		fp->ipq_id = ip->ip_id;
2674898Swnj 		fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
2684898Swnj 		fp->ipq_src = ((struct ip *)ip)->ip_src;
2694898Swnj 		fp->ipq_dst = ((struct ip *)ip)->ip_dst;
2705161Swnj 		q = (struct ipasfrag *)fp;
2715161Swnj 		goto insert;
2724640Swnj 	}
2734495Swnj 
2744640Swnj 	/*
2754640Swnj 	 * Find a segment which begins after this one does.
2764640Swnj 	 */
2774898Swnj 	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
2784640Swnj 		if (q->ip_off > ip->ip_off)
2794640Swnj 			break;
2804495Swnj 
2814640Swnj 	/*
2824640Swnj 	 * If there is a preceding segment, it may provide some of
2834640Swnj 	 * our data already.  If so, drop the data from the incoming
2844640Swnj 	 * segment.  If it provides all of our data, drop us.
2854640Swnj 	 */
2864898Swnj 	if (q->ipf_prev != (struct ipasfrag *)fp) {
2874898Swnj 		i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
2884640Swnj 		if (i > 0) {
2894640Swnj 			if (i >= ip->ip_len)
2904640Swnj 				goto dropfrag;
2914640Swnj 			m_adj(dtom(ip), i);
2924640Swnj 			ip->ip_off += i;
2934640Swnj 			ip->ip_len -= i;
2944640Swnj 		}
2954640Swnj 	}
2964543Swnj 
2974640Swnj 	/*
2984640Swnj 	 * While we overlap succeeding segments trim them or,
2994640Swnj 	 * if they are completely covered, dequeue them.
3004640Swnj 	 */
3014898Swnj 	while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
3024640Swnj 		i = (ip->ip_off + ip->ip_len) - q->ip_off;
3034640Swnj 		if (i < q->ip_len) {
3044640Swnj 			q->ip_len -= i;
3056256Sroot 			q->ip_off += i;
3064640Swnj 			m_adj(dtom(q), i);
3074640Swnj 			break;
3084495Swnj 		}
3094898Swnj 		q = q->ipf_next;
3104898Swnj 		m_freem(dtom(q->ipf_prev));
3114898Swnj 		ip_deq(q->ipf_prev);
3124543Swnj 	}
3134495Swnj 
3145161Swnj insert:
3154640Swnj 	/*
3164640Swnj 	 * Stick new segment in its place;
3174640Swnj 	 * check for complete reassembly.
3184640Swnj 	 */
3194898Swnj 	ip_enq(ip, q->ipf_prev);
3204640Swnj 	next = 0;
3214898Swnj 	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
3224640Swnj 		if (q->ip_off != next)
3234640Swnj 			return (0);
3244640Swnj 		next += q->ip_len;
3254640Swnj 	}
3264898Swnj 	if (q->ipf_prev->ipf_mff)
3274640Swnj 		return (0);
3284495Swnj 
3294640Swnj 	/*
3304640Swnj 	 * Reassembly is complete; concatenate fragments.
3314640Swnj 	 */
3324640Swnj 	q = fp->ipq_next;
3334640Swnj 	m = dtom(q);
3344640Swnj 	t = m->m_next;
3354640Swnj 	m->m_next = 0;
3364640Swnj 	m_cat(m, t);
3376298Swnj 	q = q->ipf_next;
3386298Swnj 	while (q != (struct ipasfrag *)fp) {
3396298Swnj 		t = dtom(q);
3406298Swnj 		q = q->ipf_next;
3416298Swnj 		m_cat(m, t);
3426298Swnj 	}
3434495Swnj 
3444640Swnj 	/*
3454640Swnj 	 * Create header for new ip packet by
3464640Swnj 	 * modifying header of first packet;
3474640Swnj 	 * dequeue and discard fragment reassembly header.
3484640Swnj 	 * Make header visible.
3494640Swnj 	 */
3504640Swnj 	ip = fp->ipq_next;
3514640Swnj 	ip->ip_len = next;
3524898Swnj 	((struct ip *)ip)->ip_src = fp->ipq_src;
3534898Swnj 	((struct ip *)ip)->ip_dst = fp->ipq_dst;
3544640Swnj 	remque(fp);
3554907Swnj 	(void) m_free(dtom(fp));
3564640Swnj 	m = dtom(ip);
3574898Swnj 	m->m_len += sizeof (struct ipasfrag);
3584898Swnj 	m->m_off -= sizeof (struct ipasfrag);
3594898Swnj 	return ((struct ip *)ip);
3604495Swnj 
3614640Swnj dropfrag:
3624640Swnj 	m_freem(m);
3634640Swnj 	return (0);
3644495Swnj }
3654495Swnj 
3664640Swnj /*
3674640Swnj  * Free a fragment reassembly header and all
3684640Swnj  * associated datagrams.
3694640Swnj  */
3704640Swnj ip_freef(fp)
3714640Swnj 	struct ipq *fp;
3724495Swnj {
37310735Ssam 	register struct ipasfrag *q, *p;
3744495Swnj 
37510735Ssam 	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
37610735Ssam 		p = q->ipf_next;
37710735Ssam 		ip_deq(q);
3784640Swnj 		m_freem(dtom(q));
37910735Ssam 	}
38010735Ssam 	remque(fp);
38110735Ssam 	(void) m_free(dtom(fp));
3824495Swnj }
3834495Swnj 
3844640Swnj /*
3854640Swnj  * Put an ip fragment on a reassembly chain.
3864640Swnj  * Like insque, but pointers in middle of structure.
3874640Swnj  */
3884640Swnj ip_enq(p, prev)
3894898Swnj 	register struct ipasfrag *p, *prev;
3904495Swnj {
3914951Swnj 
3924898Swnj 	p->ipf_prev = prev;
3934898Swnj 	p->ipf_next = prev->ipf_next;
3944898Swnj 	prev->ipf_next->ipf_prev = p;
3954898Swnj 	prev->ipf_next = p;
3964495Swnj }
3974495Swnj 
3984640Swnj /*
3994640Swnj  * To ip_enq as remque is to insque.
4004640Swnj  */
4014640Swnj ip_deq(p)
4024898Swnj 	register struct ipasfrag *p;
4034640Swnj {
4044951Swnj 
4054898Swnj 	p->ipf_prev->ipf_next = p->ipf_next;
4064898Swnj 	p->ipf_next->ipf_prev = p->ipf_prev;
4074495Swnj }
4084495Swnj 
4094640Swnj /*
4104640Swnj  * IP timer processing;
4114640Swnj  * if a timer expires on a reassembly
4124640Swnj  * queue, discard it.
4134640Swnj  */
4144801Swnj ip_slowtimo()
4154495Swnj {
4164495Swnj 	register struct ipq *fp;
4174640Swnj 	int s = splnet();
4184951Swnj 
4195243Sroot 	fp = ipq.next;
4205243Sroot 	if (fp == 0) {
4215243Sroot 		splx(s);
4225243Sroot 		return;
4235243Sroot 	}
42410735Ssam 	while (fp != &ipq) {
42510735Ssam 		--fp->ipq_ttl;
42610735Ssam 		fp = fp->next;
42710735Ssam 		if (fp->prev->ipq_ttl == 0)
42810735Ssam 			ip_freef(fp->prev);
42910735Ssam 	}
4304640Swnj 	splx(s);
4314495Swnj }
4324495Swnj 
4334951Swnj /*
4344951Swnj  * Drain off all datagram fragments.
4354951Swnj  */
4364801Swnj ip_drain()
4374801Swnj {
4384801Swnj 
4394951Swnj 	while (ipq.next != &ipq)
44010735Ssam 		ip_freef(ipq.next);
4414801Swnj }
4424923Swnj 
4434640Swnj /*
4444640Swnj  * Do option processing on a datagram,
4454640Swnj  * possibly discarding it if bad options
4464640Swnj  * are encountered.
4474640Swnj  */
4484640Swnj ip_dooptions(ip)
4494640Swnj 	struct ip *ip;
4504495Swnj {
4514640Swnj 	register u_char *cp;
4526583Ssam 	int opt, optlen, cnt, code, type;
4534923Swnj 	struct in_addr *sin;
4544801Swnj 	register struct ip_timestamp *ipt;
45518376Skarels 	register struct ifaddr *ifa;
4564951Swnj 	struct in_addr t;
4574495Swnj 
4584640Swnj 	cp = (u_char *)(ip + 1);
4594640Swnj 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
4604640Swnj 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
4614640Swnj 		opt = cp[0];
4624640Swnj 		if (opt == IPOPT_EOL)
4634640Swnj 			break;
4644640Swnj 		if (opt == IPOPT_NOP)
4654640Swnj 			optlen = 1;
46616392Ssam 		else {
4674640Swnj 			optlen = cp[1];
46817551Skarels 			if (optlen <= 0 || optlen >= cnt)
46917551Skarels 				goto bad;
47016392Ssam 		}
4714640Swnj 		switch (opt) {
4724495Swnj 
4734640Swnj 		default:
4744640Swnj 			break;
4754495Swnj 
4764951Swnj 		/*
4774951Swnj 		 * Source routing with record.
4784951Swnj 		 * Find interface with current destination address.
4794951Swnj 		 * If none on this machine then drop if strictly routed,
4804951Swnj 		 * or do nothing if loosely routed.
4814951Swnj 		 * Record interface address and bring up next address
4824951Swnj 		 * component.  If strictly routed make sure next
4834951Swnj 		 * address on directly accessible net.
4844951Swnj 		 */
4854640Swnj 		case IPOPT_LSRR:
4867508Sroot 		case IPOPT_SSRR:
4874801Swnj 			if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1))
4884640Swnj 				break;
4894923Swnj 			sin = (struct in_addr *)(cp + cp[2]);
4906338Ssam 			ipaddr.sin_addr = *sin;
49118376Skarels 			ifa = ifa_ifwithaddr((struct sockaddr *)&ipaddr);
4926583Ssam 			type = ICMP_UNREACH, code = ICMP_UNREACH_SRCFAIL;
49318376Skarels 			if (ifa == 0) {
4944951Swnj 				if (opt == IPOPT_SSRR)
4954951Swnj 					goto bad;
4964951Swnj 				break;
4974640Swnj 			}
4984951Swnj 			t = ip->ip_dst; ip->ip_dst = *sin; *sin = t;
4994951Swnj 			cp[2] += 4;
5004951Swnj 			if (cp[2] > optlen - (sizeof (long) - 1))
5014951Swnj 				break;
5024951Swnj 			ip->ip_dst = sin[1];
5036338Ssam 			if (opt == IPOPT_SSRR &&
50418376Skarels 			    in_iaonnetof(in_netof(ip->ip_dst)) == 0)
5054951Swnj 				goto bad;
5064640Swnj 			break;
5074495Swnj 
5084640Swnj 		case IPOPT_TS:
5096583Ssam 			code = cp - (u_char *)ip;
5106583Ssam 			type = ICMP_PARAMPROB;
5114801Swnj 			ipt = (struct ip_timestamp *)cp;
5124801Swnj 			if (ipt->ipt_len < 5)
5134640Swnj 				goto bad;
5144801Swnj 			if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
5154801Swnj 				if (++ipt->ipt_oflw == 0)
5164640Swnj 					goto bad;
5174495Swnj 				break;
5184640Swnj 			}
5194923Swnj 			sin = (struct in_addr *)(cp+cp[2]);
5204801Swnj 			switch (ipt->ipt_flg) {
5214495Swnj 
5224640Swnj 			case IPOPT_TS_TSONLY:
5234640Swnj 				break;
5244640Swnj 
5254640Swnj 			case IPOPT_TS_TSANDADDR:
5264801Swnj 				if (ipt->ipt_ptr + 8 > ipt->ipt_len)
5274640Swnj 					goto bad;
52818376Skarels 				if (in_ifaddr == 0)
5296338Ssam 					goto bad;	/* ??? */
53018376Skarels 				*sin++ = IA_SIN(in_ifaddr)->sin_addr;
5314640Swnj 				break;
5324640Swnj 
5334640Swnj 			case IPOPT_TS_PRESPEC:
5346338Ssam 				ipaddr.sin_addr = *sin;
53518376Skarels 				if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0)
5364951Swnj 					continue;
5374801Swnj 				if (ipt->ipt_ptr + 8 > ipt->ipt_len)
5384640Swnj 					goto bad;
5394801Swnj 				ipt->ipt_ptr += 4;
5404640Swnj 				break;
5414640Swnj 
5424495Swnj 			default:
5434640Swnj 				goto bad;
5444495Swnj 			}
5454923Swnj 			*(n_time *)sin = iptime();
5464801Swnj 			ipt->ipt_ptr += 4;
5474640Swnj 		}
5484495Swnj 	}
5496583Ssam 	return (0);
5504640Swnj bad:
5516583Ssam 	icmp_error(ip, type, code);
5526583Ssam 	return (1);
5534495Swnj }
5544495Swnj 
5554640Swnj /*
5564951Swnj  * Strip out IP options, at higher
5574951Swnj  * level protocol in the kernel.
5584951Swnj  * Second argument is buffer to which options
5594951Swnj  * will be moved, and return value is their length.
5604640Swnj  */
5615217Swnj ip_stripoptions(ip, mopt)
5624640Swnj 	struct ip *ip;
5635217Swnj 	struct mbuf *mopt;
5644495Swnj {
5654640Swnj 	register int i;
5664640Swnj 	register struct mbuf *m;
5674640Swnj 	int olen;
5684640Swnj 
5694640Swnj 	olen = (ip->ip_hl<<2) - sizeof (struct ip);
5704951Swnj 	m = dtom(ip);
5714951Swnj 	ip++;
5725217Swnj 	if (mopt) {
5735217Swnj 		mopt->m_len = olen;
5745217Swnj 		mopt->m_off = MMINOFF;
57516544Skarels 		bcopy((caddr_t)ip, mtod(mopt, caddr_t), (unsigned)olen);
5765217Swnj 	}
5774640Swnj 	i = m->m_len - (sizeof (struct ip) + olen);
5784907Swnj 	bcopy((caddr_t)ip+olen, (caddr_t)ip, (unsigned)i);
5795243Sroot 	m->m_len -= olen;
5804495Swnj }
5816583Ssam 
58214670Ssam u_char inetctlerrmap[PRC_NCMDS] = {
5836583Ssam 	ECONNABORTED,	ECONNABORTED,	0,		0,
58414670Ssam 	0,		0,		EHOSTDOWN,	EHOSTUNREACH,
58514670Ssam 	ENETUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
58614670Ssam 	EMSGSIZE,	0,		0,		0,
5876583Ssam 	0,		0,		0,		0
5886583Ssam };
5896583Ssam 
5906583Ssam int	ipprintfs = 0;
5916583Ssam int	ipforwarding = 1;
5926583Ssam /*
5936583Ssam  * Forward a packet.  If some error occurs return the sender
59418376Skarels  * an icmp packet.  Note we can't always generate a meaningful
5956583Ssam  * icmp message because icmp doesn't have a large enough repetoire
5966583Ssam  * of codes and types.
5976583Ssam  */
5986583Ssam ip_forward(ip)
5996583Ssam 	register struct ip *ip;
6006583Ssam {
6016583Ssam 	register int error, type, code;
60218376Skarels 	struct mbuf *mcopy;
6036583Ssam 
6046583Ssam 	if (ipprintfs)
6056583Ssam 		printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
6066583Ssam 			ip->ip_dst, ip->ip_ttl);
60718376Skarels 	ip->ip_id = htons(ip->ip_id);
6086583Ssam 	if (ipforwarding == 0) {
6096583Ssam 		/* can't tell difference between net and host */
6106583Ssam 		type = ICMP_UNREACH, code = ICMP_UNREACH_NET;
6116583Ssam 		goto sendicmp;
6126583Ssam 	}
6136583Ssam 	if (ip->ip_ttl < IPTTLDEC) {
6146583Ssam 		type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;
6156583Ssam 		goto sendicmp;
6166583Ssam 	}
6176583Ssam 	ip->ip_ttl -= IPTTLDEC;
6186609Ssam 
6196609Ssam 	/*
6206609Ssam 	 * Save at most 64 bytes of the packet in case
6216609Ssam 	 * we need to generate an ICMP message to the src.
6226609Ssam 	 */
6237843Sroot 	mcopy = m_copy(dtom(ip), 0, imin(ip->ip_len, 64));
6246583Ssam 
62518376Skarels 	error = ip_output(dtom(ip), (struct mbuf *)0, (struct route *)0,
62618376Skarels 		IP_FORWARDING);
62711540Ssam 	if (error == 0) {
6286609Ssam 		if (mcopy)
6296609Ssam 			m_freem(mcopy);
63021117Skarels 		ipstat.ips_forward++;
6316583Ssam 		return;
6326609Ssam 	}
63321117Skarels 	ipstat.ips_cantforward++;
63411540Ssam 	if (mcopy == NULL)
63511540Ssam 		return;
6366609Ssam 	ip = mtod(mcopy, struct ip *);
6376609Ssam 	type = ICMP_UNREACH, code = 0;		/* need ``undefined'' */
6386609Ssam 	switch (error) {
6396609Ssam 
6406609Ssam 	case ENETUNREACH:
6416609Ssam 	case ENETDOWN:
6426583Ssam 		code = ICMP_UNREACH_NET;
6436609Ssam 		break;
6446609Ssam 
6456609Ssam 	case EMSGSIZE:
6466583Ssam 		code = ICMP_UNREACH_NEEDFRAG;
6476609Ssam 		break;
6486609Ssam 
6496609Ssam 	case EPERM:
6506609Ssam 		code = ICMP_UNREACH_PORT;
6516609Ssam 		break;
6526609Ssam 
6536609Ssam 	case ENOBUFS:
6546609Ssam 		type = ICMP_SOURCEQUENCH;
6556609Ssam 		break;
6566609Ssam 
6576609Ssam 	case EHOSTDOWN:
6586609Ssam 	case EHOSTUNREACH:
6596609Ssam 		code = ICMP_UNREACH_HOST;
6606609Ssam 		break;
6616609Ssam 	}
6626583Ssam sendicmp:
6636583Ssam 	icmp_error(ip, type, code);
6646583Ssam }
665