Home | History | Annotate | Line # | Download | only in netinet
ip_input.c revision 1.3.4.2
      1      1.1      cgd /*
      2      1.1      cgd  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
      3      1.1      cgd  * All rights reserved.
      4      1.1      cgd  *
      5      1.1      cgd  * Redistribution and use in source and binary forms, with or without
      6      1.1      cgd  * modification, are permitted provided that the following conditions
      7      1.1      cgd  * are met:
      8      1.1      cgd  * 1. Redistributions of source code must retain the above copyright
      9      1.1      cgd  *    notice, this list of conditions and the following disclaimer.
     10      1.1      cgd  * 2. Redistributions in binary form must reproduce the above copyright
     11      1.1      cgd  *    notice, this list of conditions and the following disclaimer in the
     12      1.1      cgd  *    documentation and/or other materials provided with the distribution.
     13      1.1      cgd  * 3. All advertising materials mentioning features or use of this software
     14      1.1      cgd  *    must display the following acknowledgement:
     15      1.1      cgd  *	This product includes software developed by the University of
     16      1.1      cgd  *	California, Berkeley and its contributors.
     17      1.1      cgd  * 4. Neither the name of the University nor the names of its contributors
     18      1.1      cgd  *    may be used to endorse or promote products derived from this software
     19      1.1      cgd  *    without specific prior written permission.
     20      1.1      cgd  *
     21      1.1      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22      1.1      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23      1.1      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24      1.1      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25      1.1      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26      1.1      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27      1.1      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28      1.1      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29      1.1      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30      1.1      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31      1.1      cgd  * SUCH DAMAGE.
     32      1.1      cgd  *
     33      1.3      cgd  *	from: @(#)ip_input.c	7.19 (Berkeley) 5/25/91
     34  1.3.4.2  mycroft  *	$Id: ip_input.c,v 1.3.4.2 1993/11/14 17:54:46 mycroft Exp $
     35      1.1      cgd  */
     36      1.1      cgd 
     37      1.1      cgd #include "param.h"
     38      1.1      cgd #include "systm.h"
     39      1.1      cgd #include "malloc.h"
     40      1.1      cgd #include "mbuf.h"
     41      1.1      cgd #include "domain.h"
     42      1.1      cgd #include "protosw.h"
     43      1.1      cgd #include "socket.h"
     44      1.1      cgd #include "errno.h"
     45      1.1      cgd #include "time.h"
     46      1.1      cgd #include "kernel.h"
     47  1.3.4.1  mycroft 
     48  1.3.4.1  mycroft #include "machine/cpu.h"
     49      1.1      cgd 
     50      1.1      cgd #include "../net/if.h"
     51      1.1      cgd #include "../net/route.h"
     52      1.1      cgd 
     53      1.1      cgd #include "in.h"
     54      1.1      cgd #include "in_systm.h"
     55      1.1      cgd #include "ip.h"
     56      1.1      cgd #include "in_pcb.h"
     57      1.1      cgd #include "in_var.h"
     58      1.1      cgd #include "ip_var.h"
     59      1.1      cgd #include "ip_icmp.h"
     60      1.1      cgd 
     61      1.1      cgd #ifndef	IPFORWARDING
     62      1.1      cgd #ifdef GATEWAY
     63      1.1      cgd #define	IPFORWARDING	1	/* forward IP packets not for us */
     64      1.1      cgd #else /* GATEWAY */
     65      1.1      cgd #define	IPFORWARDING	0	/* don't forward IP packets not for us */
     66      1.1      cgd #endif /* GATEWAY */
     67      1.1      cgd #endif /* IPFORWARDING */
     68      1.1      cgd #ifndef	IPSENDREDIRECTS
     69      1.1      cgd #define	IPSENDREDIRECTS	1
     70      1.1      cgd #endif
     71      1.1      cgd int	ipforwarding = IPFORWARDING;
     72      1.1      cgd int	ipsendredirects = IPSENDREDIRECTS;
     73      1.1      cgd #ifdef DIAGNOSTIC
     74      1.1      cgd int	ipprintfs = 0;
     75      1.1      cgd #endif
     76      1.1      cgd 
     77      1.1      cgd extern	struct domain inetdomain;
     78      1.1      cgd extern	struct protosw inetsw[];
     79      1.1      cgd u_char	ip_protox[IPPROTO_MAX];
     80      1.1      cgd int	ipqmaxlen = IFQ_MAXLEN;
     81      1.1      cgd struct	in_ifaddr *in_ifaddr;			/* first inet address */
     82      1.1      cgd 
     83      1.1      cgd /*
     84      1.1      cgd  * We need to save the IP options in case a protocol wants to respond
     85      1.1      cgd  * to an incoming packet over the same route if the packet got here
     86      1.1      cgd  * using IP source routing.  This allows connection establishment and
     87      1.1      cgd  * maintenance when the remote end is on a network that is not known
     88      1.1      cgd  * to us.
     89      1.1      cgd  */
     90      1.1      cgd int	ip_nhops = 0;
     91      1.1      cgd static	struct ip_srcrt {
     92      1.1      cgd 	struct	in_addr dst;			/* final destination */
     93      1.1      cgd 	char	nop;				/* one NOP to align */
     94      1.1      cgd 	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
     95      1.1      cgd 	struct	in_addr route[MAX_IPOPTLEN/sizeof(struct in_addr)];
     96      1.1      cgd } ip_srcrt;
     97      1.1      cgd 
     98      1.1      cgd #ifdef GATEWAY
     99      1.1      cgd extern	int if_index;
    100      1.1      cgd u_long	*ip_ifmatrix;
    101      1.1      cgd #endif
    102      1.1      cgd 
    103      1.1      cgd /*
    104      1.1      cgd  * IP initialization: fill in IP protocol switch table.
    105      1.1      cgd  * All protocols not implemented in kernel go to raw IP protocol handler.
    106      1.1      cgd  */
    107      1.1      cgd ip_init()
    108      1.1      cgd {
    109      1.1      cgd 	register struct protosw *pr;
    110      1.1      cgd 	register int i;
    111      1.1      cgd 
    112      1.1      cgd 	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
    113      1.1      cgd 	if (pr == 0)
    114      1.1      cgd 		panic("ip_init");
    115      1.1      cgd 	for (i = 0; i < IPPROTO_MAX; i++)
    116      1.1      cgd 		ip_protox[i] = pr - inetsw;
    117      1.1      cgd 	for (pr = inetdomain.dom_protosw;
    118      1.1      cgd 	    pr < inetdomain.dom_protoswNPROTOSW; pr++)
    119      1.1      cgd 		if (pr->pr_domain->dom_family == PF_INET &&
    120      1.1      cgd 		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
    121      1.1      cgd 			ip_protox[pr->pr_protocol] = pr - inetsw;
    122      1.1      cgd 	ipq.next = ipq.prev = &ipq;
    123      1.1      cgd 	ip_id = time.tv_sec & 0xffff;
    124      1.1      cgd 	ipintrq.ifq_maxlen = ipqmaxlen;
    125      1.1      cgd #ifdef GATEWAY
    126      1.1      cgd 	i = (if_index + 1) * (if_index + 1) * sizeof (u_long);
    127      1.1      cgd 	if ((ip_ifmatrix = (u_long *) malloc(i, M_RTABLE, M_WAITOK)) == 0)
    128      1.1      cgd 		panic("no memory for ip_ifmatrix");
    129      1.1      cgd #endif
    130      1.1      cgd }
    131      1.1      cgd 
    132      1.1      cgd struct	ip *ip_reass();
    133      1.1      cgd struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
    134      1.1      cgd struct	route ipforward_rt;
    135      1.1      cgd 
    136      1.1      cgd /*
    137      1.1      cgd  * Ip input routine.  Checksum and byte swap header.  If fragmented
    138      1.1      cgd  * try to reassemble.  Process options.  Pass to next level.
    139      1.1      cgd  */
    140      1.1      cgd ipintr()
    141      1.1      cgd {
    142      1.1      cgd 	register struct ip *ip;
    143      1.1      cgd 	register struct mbuf *m;
    144      1.1      cgd 	register struct ipq *fp;
    145      1.1      cgd 	register struct in_ifaddr *ia;
    146      1.1      cgd 	int hlen, s;
    147  1.3.4.2  mycroft #ifdef DIAGNOSTIC
    148      1.2      cgd 	static int busy = 0;
    149      1.1      cgd 
    150      1.2      cgd 	if (busy)
    151      1.2      cgd 		panic("ipintr: called recursively\n");
    152      1.2      cgd 	++busy;
    153      1.2      cgd #endif
    154      1.1      cgd next:
    155      1.1      cgd 	/*
    156      1.1      cgd 	 * Get next datagram off input queue and get IP header
    157      1.1      cgd 	 * in first mbuf.
    158      1.1      cgd 	 */
    159      1.1      cgd 	s = splimp();
    160      1.1      cgd 	IF_DEQUEUE(&ipintrq, m);
    161      1.1      cgd 	splx(s);
    162      1.2      cgd 	if (m == 0) {
    163  1.3.4.2  mycroft #ifdef DIAGNOSTIC
    164      1.2      cgd 		--busy;
    165      1.2      cgd #endif
    166      1.1      cgd 		return;
    167      1.2      cgd 	}
    168      1.1      cgd #ifdef	DIAGNOSTIC
    169      1.1      cgd 	if ((m->m_flags & M_PKTHDR) == 0)
    170      1.1      cgd 		panic("ipintr no HDR");
    171      1.1      cgd #endif
    172      1.1      cgd 	/*
    173      1.1      cgd 	 * If no IP addresses have been set yet but the interfaces
    174      1.1      cgd 	 * are receiving, can't do anything with incoming packets yet.
    175      1.1      cgd 	 */
    176      1.1      cgd 	if (in_ifaddr == NULL)
    177      1.1      cgd 		goto bad;
    178      1.1      cgd 	ipstat.ips_total++;
    179      1.1      cgd 	if (m->m_len < sizeof (struct ip) &&
    180      1.1      cgd 	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
    181      1.1      cgd 		ipstat.ips_toosmall++;
    182      1.1      cgd 		goto next;
    183      1.1      cgd 	}
    184      1.1      cgd 	ip = mtod(m, struct ip *);
    185      1.1      cgd 	hlen = ip->ip_hl << 2;
    186      1.1      cgd 	if (hlen < sizeof(struct ip)) {	/* minimum header length */
    187      1.1      cgd 		ipstat.ips_badhlen++;
    188      1.1      cgd 		goto bad;
    189      1.1      cgd 	}
    190      1.1      cgd 	if (hlen > m->m_len) {
    191      1.1      cgd 		if ((m = m_pullup(m, hlen)) == 0) {
    192      1.1      cgd 			ipstat.ips_badhlen++;
    193      1.1      cgd 			goto next;
    194      1.1      cgd 		}
    195      1.1      cgd 		ip = mtod(m, struct ip *);
    196      1.1      cgd 	}
    197      1.1      cgd 	if (ip->ip_sum = in_cksum(m, hlen)) {
    198      1.1      cgd 		ipstat.ips_badsum++;
    199      1.1      cgd 		goto bad;
    200      1.1      cgd 	}
    201      1.1      cgd 
    202      1.1      cgd 	/*
    203      1.1      cgd 	 * Convert fields to host representation.
    204      1.1      cgd 	 */
    205      1.1      cgd 	NTOHS(ip->ip_len);
    206      1.1      cgd 	if (ip->ip_len < hlen) {
    207      1.1      cgd 		ipstat.ips_badlen++;
    208      1.1      cgd 		goto bad;
    209      1.1      cgd 	}
    210      1.1      cgd 	NTOHS(ip->ip_id);
    211      1.1      cgd 	NTOHS(ip->ip_off);
    212      1.1      cgd 
    213      1.1      cgd 	/*
    214      1.1      cgd 	 * Check that the amount of data in the buffers
    215      1.1      cgd 	 * is as at least much as the IP header would have us expect.
    216      1.1      cgd 	 * Trim mbufs if longer than we expect.
    217      1.1      cgd 	 * Drop packet if shorter than we expect.
    218      1.1      cgd 	 */
    219      1.1      cgd 	if (m->m_pkthdr.len < ip->ip_len) {
    220      1.1      cgd 		ipstat.ips_tooshort++;
    221      1.1      cgd 		goto bad;
    222      1.1      cgd 	}
    223      1.1      cgd 	if (m->m_pkthdr.len > ip->ip_len) {
    224      1.1      cgd 		if (m->m_len == m->m_pkthdr.len) {
    225      1.1      cgd 			m->m_len = ip->ip_len;
    226      1.1      cgd 			m->m_pkthdr.len = ip->ip_len;
    227      1.1      cgd 		} else
    228      1.1      cgd 			m_adj(m, ip->ip_len - m->m_pkthdr.len);
    229      1.1      cgd 	}
    230      1.1      cgd 
    231      1.1      cgd 	/*
    232      1.1      cgd 	 * Process options and, if not destined for us,
    233      1.1      cgd 	 * ship it on.  ip_dooptions returns 1 when an
    234      1.1      cgd 	 * error was detected (causing an icmp message
    235      1.1      cgd 	 * to be sent and the original packet to be freed).
    236      1.1      cgd 	 */
    237      1.1      cgd 	ip_nhops = 0;		/* for source routed packets */
    238      1.1      cgd 	if (hlen > sizeof (struct ip) && ip_dooptions(m))
    239      1.1      cgd 		goto next;
    240      1.1      cgd 
    241      1.1      cgd 	/*
    242      1.1      cgd 	 * Check our list of addresses, to see if the packet is for us.
    243      1.1      cgd 	 */
    244      1.1      cgd 	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
    245      1.1      cgd #define	satosin(sa)	((struct sockaddr_in *)(sa))
    246      1.1      cgd 
    247      1.1      cgd 		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
    248      1.1      cgd 			goto ours;
    249      1.1      cgd 		if (
    250      1.1      cgd #ifdef	DIRECTED_BROADCAST
    251      1.1      cgd 		    ia->ia_ifp == m->m_pkthdr.rcvif &&
    252      1.1      cgd #endif
    253      1.1      cgd 		    (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
    254      1.1      cgd 			u_long t;
    255      1.1      cgd 
    256      1.1      cgd 			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
    257      1.1      cgd 			    ip->ip_dst.s_addr)
    258      1.1      cgd 				goto ours;
    259      1.1      cgd 			if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
    260      1.1      cgd 				goto ours;
    261      1.1      cgd 			/*
    262      1.1      cgd 			 * Look for all-0's host part (old broadcast addr),
    263      1.1      cgd 			 * either for subnet or net.
    264      1.1      cgd 			 */
    265      1.1      cgd 			t = ntohl(ip->ip_dst.s_addr);
    266      1.1      cgd 			if (t == ia->ia_subnet)
    267      1.1      cgd 				goto ours;
    268      1.1      cgd 			if (t == ia->ia_net)
    269      1.1      cgd 				goto ours;
    270      1.1      cgd 		}
    271      1.1      cgd 	}
    272      1.1      cgd 	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
    273      1.1      cgd 		goto ours;
    274      1.1      cgd 	if (ip->ip_dst.s_addr == INADDR_ANY)
    275      1.1      cgd 		goto ours;
    276      1.1      cgd 
    277      1.1      cgd 	/*
    278      1.1      cgd 	 * Not for us; forward if possible and desirable.
    279      1.1      cgd 	 */
    280      1.1      cgd 	if (ipforwarding == 0) {
    281      1.1      cgd 		ipstat.ips_cantforward++;
    282      1.1      cgd 		m_freem(m);
    283      1.1      cgd 	} else
    284      1.1      cgd 		ip_forward(m, 0);
    285      1.1      cgd 	goto next;
    286      1.1      cgd 
    287      1.1      cgd ours:
    288      1.1      cgd 	/*
    289      1.1      cgd 	 * If offset or IP_MF are set, must reassemble.
    290      1.1      cgd 	 * Otherwise, nothing need be done.
    291      1.1      cgd 	 * (We could look in the reassembly queue to see
    292      1.1      cgd 	 * if the packet was previously fragmented,
    293      1.1      cgd 	 * but it's not worth the time; just let them time out.)
    294      1.1      cgd 	 */
    295      1.1      cgd 	if (ip->ip_off &~ IP_DF) {
    296      1.1      cgd 		if (m->m_flags & M_EXT) {		/* XXX */
    297      1.1      cgd 			if ((m = m_pullup(m, sizeof (struct ip))) == 0) {
    298      1.1      cgd 				ipstat.ips_toosmall++;
    299      1.1      cgd 				goto next;
    300      1.1      cgd 			}
    301      1.1      cgd 			ip = mtod(m, struct ip *);
    302      1.1      cgd 		}
    303      1.1      cgd 		/*
    304      1.1      cgd 		 * Look for queue of fragments
    305      1.1      cgd 		 * of this datagram.
    306      1.1      cgd 		 */
    307      1.1      cgd 		for (fp = ipq.next; fp != &ipq; fp = fp->next)
    308      1.1      cgd 			if (ip->ip_id == fp->ipq_id &&
    309      1.1      cgd 			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
    310      1.1      cgd 			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
    311      1.1      cgd 			    ip->ip_p == fp->ipq_p)
    312      1.1      cgd 				goto found;
    313      1.1      cgd 		fp = 0;
    314      1.1      cgd found:
    315      1.1      cgd 
    316      1.1      cgd 		/*
    317      1.1      cgd 		 * Adjust ip_len to not reflect header,
    318      1.1      cgd 		 * set ip_mff if more fragments are expected,
    319      1.1      cgd 		 * convert offset of this to bytes.
    320      1.1      cgd 		 */
    321      1.1      cgd 		ip->ip_len -= hlen;
    322      1.1      cgd 		((struct ipasfrag *)ip)->ipf_mff = 0;
    323      1.1      cgd 		if (ip->ip_off & IP_MF)
    324      1.1      cgd 			((struct ipasfrag *)ip)->ipf_mff = 1;
    325      1.1      cgd 		ip->ip_off <<= 3;
    326      1.1      cgd 
    327      1.1      cgd 		/*
    328      1.1      cgd 		 * If datagram marked as having more fragments
    329      1.1      cgd 		 * or if this is not the first fragment,
    330      1.1      cgd 		 * attempt reassembly; if it succeeds, proceed.
    331      1.1      cgd 		 */
    332      1.1      cgd 		if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
    333      1.1      cgd 			ipstat.ips_fragments++;
    334      1.1      cgd 			ip = ip_reass((struct ipasfrag *)ip, fp);
    335      1.1      cgd 			if (ip == 0)
    336      1.1      cgd 				goto next;
    337      1.1      cgd 			else
    338      1.1      cgd 				ipstat.ips_reassembled++;
    339      1.1      cgd 			m = dtom(ip);
    340      1.1      cgd 		} else
    341      1.1      cgd 			if (fp)
    342      1.1      cgd 				ip_freef(fp);
    343      1.1      cgd 	} else
    344      1.1      cgd 		ip->ip_len -= hlen;
    345      1.1      cgd 
    346      1.1      cgd 	/*
    347      1.1      cgd 	 * Switch out to protocol's input routine.
    348      1.1      cgd 	 */
    349      1.1      cgd 	ipstat.ips_delivered++;
    350      1.1      cgd 	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen);
    351      1.1      cgd 	goto next;
    352      1.1      cgd bad:
    353      1.1      cgd 	m_freem(m);
    354      1.1      cgd 	goto next;
    355      1.1      cgd }
    356      1.1      cgd 
    357      1.1      cgd /*
    358      1.1      cgd  * Take incoming datagram fragment and try to
    359      1.1      cgd  * reassemble it into whole datagram.  If a chain for
    360      1.1      cgd  * reassembly of this datagram already exists, then it
    361      1.1      cgd  * is given as fp; otherwise have to make a chain.
    362      1.1      cgd  */
    363      1.1      cgd struct ip *
    364      1.1      cgd ip_reass(ip, fp)
    365      1.1      cgd 	register struct ipasfrag *ip;
    366      1.1      cgd 	register struct ipq *fp;
    367      1.1      cgd {
    368      1.1      cgd 	register struct mbuf *m = dtom(ip);
    369      1.1      cgd 	register struct ipasfrag *q;
    370      1.1      cgd 	struct mbuf *t;
    371      1.1      cgd 	int hlen = ip->ip_hl << 2;
    372      1.1      cgd 	int i, next;
    373      1.1      cgd 
    374      1.1      cgd 	/*
    375      1.1      cgd 	 * Presence of header sizes in mbufs
    376      1.1      cgd 	 * would confuse code below.
    377      1.1      cgd 	 */
    378      1.1      cgd 	m->m_data += hlen;
    379      1.1      cgd 	m->m_len -= hlen;
    380      1.1      cgd 
    381      1.1      cgd 	/*
    382      1.1      cgd 	 * If first fragment to arrive, create a reassembly queue.
    383      1.1      cgd 	 */
    384      1.1      cgd 	if (fp == 0) {
    385      1.1      cgd 		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
    386      1.1      cgd 			goto dropfrag;
    387      1.1      cgd 		fp = mtod(t, struct ipq *);
    388      1.1      cgd 		insque(fp, &ipq);
    389      1.1      cgd 		fp->ipq_ttl = IPFRAGTTL;
    390      1.1      cgd 		fp->ipq_p = ip->ip_p;
    391      1.1      cgd 		fp->ipq_id = ip->ip_id;
    392      1.1      cgd 		fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
    393      1.1      cgd 		fp->ipq_src = ((struct ip *)ip)->ip_src;
    394      1.1      cgd 		fp->ipq_dst = ((struct ip *)ip)->ip_dst;
    395      1.1      cgd 		q = (struct ipasfrag *)fp;
    396      1.1      cgd 		goto insert;
    397      1.1      cgd 	}
    398      1.1      cgd 
    399      1.1      cgd 	/*
    400      1.1      cgd 	 * Find a segment which begins after this one does.
    401      1.1      cgd 	 */
    402      1.1      cgd 	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
    403      1.1      cgd 		if (q->ip_off > ip->ip_off)
    404      1.1      cgd 			break;
    405      1.1      cgd 
    406      1.1      cgd 	/*
    407      1.1      cgd 	 * If there is a preceding segment, it may provide some of
    408      1.1      cgd 	 * our data already.  If so, drop the data from the incoming
    409      1.1      cgd 	 * segment.  If it provides all of our data, drop us.
    410      1.1      cgd 	 */
    411      1.1      cgd 	if (q->ipf_prev != (struct ipasfrag *)fp) {
    412      1.1      cgd 		i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
    413      1.1      cgd 		if (i > 0) {
    414      1.1      cgd 			if (i >= ip->ip_len)
    415      1.1      cgd 				goto dropfrag;
    416      1.1      cgd 			m_adj(dtom(ip), i);
    417      1.1      cgd 			ip->ip_off += i;
    418      1.1      cgd 			ip->ip_len -= i;
    419      1.1      cgd 		}
    420      1.1      cgd 	}
    421      1.1      cgd 
    422      1.1      cgd 	/*
    423      1.1      cgd 	 * While we overlap succeeding segments trim them or,
    424      1.1      cgd 	 * if they are completely covered, dequeue them.
    425      1.1      cgd 	 */
    426      1.1      cgd 	while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
    427      1.1      cgd 		i = (ip->ip_off + ip->ip_len) - q->ip_off;
    428      1.1      cgd 		if (i < q->ip_len) {
    429      1.1      cgd 			q->ip_len -= i;
    430      1.1      cgd 			q->ip_off += i;
    431      1.1      cgd 			m_adj(dtom(q), i);
    432      1.1      cgd 			break;
    433      1.1      cgd 		}
    434      1.1      cgd 		q = q->ipf_next;
    435      1.1      cgd 		m_freem(dtom(q->ipf_prev));
    436      1.1      cgd 		ip_deq(q->ipf_prev);
    437      1.1      cgd 	}
    438      1.1      cgd 
    439      1.1      cgd insert:
    440      1.1      cgd 	/*
    441      1.1      cgd 	 * Stick new segment in its place;
    442      1.1      cgd 	 * check for complete reassembly.
    443      1.1      cgd 	 */
    444      1.1      cgd 	ip_enq(ip, q->ipf_prev);
    445      1.1      cgd 	next = 0;
    446      1.1      cgd 	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
    447      1.1      cgd 		if (q->ip_off != next)
    448      1.1      cgd 			return (0);
    449      1.1      cgd 		next += q->ip_len;
    450      1.1      cgd 	}
    451      1.1      cgd 	if (q->ipf_prev->ipf_mff)
    452      1.1      cgd 		return (0);
    453      1.1      cgd 
    454      1.1      cgd 	/*
    455      1.1      cgd 	 * Reassembly is complete; concatenate fragments.
    456      1.1      cgd 	 */
    457      1.1      cgd 	q = fp->ipq_next;
    458      1.1      cgd 	m = dtom(q);
    459      1.1      cgd 	t = m->m_next;
    460      1.1      cgd 	m->m_next = 0;
    461      1.1      cgd 	m_cat(m, t);
    462      1.1      cgd 	q = q->ipf_next;
    463      1.1      cgd 	while (q != (struct ipasfrag *)fp) {
    464      1.1      cgd 		t = dtom(q);
    465      1.1      cgd 		q = q->ipf_next;
    466      1.1      cgd 		m_cat(m, t);
    467      1.1      cgd 	}
    468      1.1      cgd 
    469      1.1      cgd 	/*
    470      1.1      cgd 	 * Create header for new ip packet by
    471      1.1      cgd 	 * modifying header of first packet;
    472      1.1      cgd 	 * dequeue and discard fragment reassembly header.
    473      1.1      cgd 	 * Make header visible.
    474      1.1      cgd 	 */
    475      1.1      cgd 	ip = fp->ipq_next;
    476      1.1      cgd 	ip->ip_len = next;
    477      1.1      cgd 	((struct ip *)ip)->ip_src = fp->ipq_src;
    478      1.1      cgd 	((struct ip *)ip)->ip_dst = fp->ipq_dst;
    479      1.1      cgd 	remque(fp);
    480      1.1      cgd 	(void) m_free(dtom(fp));
    481      1.1      cgd 	m = dtom(ip);
    482      1.1      cgd 	m->m_len += (ip->ip_hl << 2);
    483      1.1      cgd 	m->m_data -= (ip->ip_hl << 2);
    484      1.1      cgd 	/* some debugging cruft by sklower, below, will go away soon */
    485      1.1      cgd 	if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
    486      1.1      cgd 		register int plen = 0;
    487      1.1      cgd 		for (t = m; m; m = m->m_next)
    488      1.1      cgd 			plen += m->m_len;
    489      1.1      cgd 		t->m_pkthdr.len = plen;
    490      1.1      cgd 	}
    491      1.1      cgd 	return ((struct ip *)ip);
    492      1.1      cgd 
    493      1.1      cgd dropfrag:
    494      1.1      cgd 	ipstat.ips_fragdropped++;
    495      1.1      cgd 	m_freem(m);
    496      1.1      cgd 	return (0);
    497      1.1      cgd }
    498      1.1      cgd 
    499      1.1      cgd /*
    500      1.1      cgd  * Free a fragment reassembly header and all
    501      1.1      cgd  * associated datagrams.
    502      1.1      cgd  */
    503      1.1      cgd ip_freef(fp)
    504      1.1      cgd 	struct ipq *fp;
    505      1.1      cgd {
    506      1.1      cgd 	register struct ipasfrag *q, *p;
    507      1.1      cgd 
    508      1.1      cgd 	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
    509      1.1      cgd 		p = q->ipf_next;
    510      1.1      cgd 		ip_deq(q);
    511      1.1      cgd 		m_freem(dtom(q));
    512      1.1      cgd 	}
    513      1.1      cgd 	remque(fp);
    514      1.1      cgd 	(void) m_free(dtom(fp));
    515      1.1      cgd }
    516      1.1      cgd 
    517      1.1      cgd /*
    518      1.1      cgd  * Put an ip fragment on a reassembly chain.
    519      1.1      cgd  * Like insque, but pointers in middle of structure.
    520      1.1      cgd  */
    521      1.1      cgd ip_enq(p, prev)
    522      1.1      cgd 	register struct ipasfrag *p, *prev;
    523      1.1      cgd {
    524      1.1      cgd 
    525      1.1      cgd 	p->ipf_prev = prev;
    526      1.1      cgd 	p->ipf_next = prev->ipf_next;
    527      1.1      cgd 	prev->ipf_next->ipf_prev = p;
    528      1.1      cgd 	prev->ipf_next = p;
    529      1.1      cgd }
    530      1.1      cgd 
    531      1.1      cgd /*
    532      1.1      cgd  * To ip_enq as remque is to insque.
    533      1.1      cgd  */
    534      1.1      cgd ip_deq(p)
    535      1.1      cgd 	register struct ipasfrag *p;
    536      1.1      cgd {
    537      1.1      cgd 
    538      1.1      cgd 	p->ipf_prev->ipf_next = p->ipf_next;
    539      1.1      cgd 	p->ipf_next->ipf_prev = p->ipf_prev;
    540      1.1      cgd }
    541      1.1      cgd 
    542      1.1      cgd /*
    543      1.1      cgd  * IP timer processing;
    544      1.1      cgd  * if a timer expires on a reassembly
    545      1.1      cgd  * queue, discard it.
    546      1.1      cgd  */
    547      1.1      cgd ip_slowtimo()
    548      1.1      cgd {
    549      1.1      cgd 	register struct ipq *fp;
    550      1.1      cgd 	int s = splnet();
    551      1.1      cgd 
    552      1.1      cgd 	fp = ipq.next;
    553      1.1      cgd 	if (fp == 0) {
    554      1.1      cgd 		splx(s);
    555      1.1      cgd 		return;
    556      1.1      cgd 	}
    557      1.1      cgd 	while (fp != &ipq) {
    558      1.1      cgd 		--fp->ipq_ttl;
    559      1.1      cgd 		fp = fp->next;
    560      1.1      cgd 		if (fp->prev->ipq_ttl == 0) {
    561      1.1      cgd 			ipstat.ips_fragtimeout++;
    562      1.1      cgd 			ip_freef(fp->prev);
    563      1.1      cgd 		}
    564      1.1      cgd 	}
    565      1.1      cgd 	splx(s);
    566      1.1      cgd }
    567      1.1      cgd 
    568      1.1      cgd /*
    569      1.1      cgd  * Drain off all datagram fragments.
    570      1.1      cgd  */
    571      1.1      cgd ip_drain()
    572      1.1      cgd {
    573      1.1      cgd 
    574      1.1      cgd 	while (ipq.next != &ipq) {
    575      1.1      cgd 		ipstat.ips_fragdropped++;
    576      1.1      cgd 		ip_freef(ipq.next);
    577      1.1      cgd 	}
    578      1.1      cgd }
    579      1.1      cgd 
    580      1.1      cgd extern struct in_ifaddr *ifptoia();
    581      1.1      cgd struct in_ifaddr *ip_rtaddr();
    582      1.1      cgd 
    583      1.1      cgd /*
    584      1.1      cgd  * Do option processing on a datagram,
    585      1.1      cgd  * possibly discarding it if bad options are encountered,
    586      1.1      cgd  * or forwarding it if source-routed.
    587      1.1      cgd  * Returns 1 if packet has been forwarded/freed,
    588      1.1      cgd  * 0 if the packet should be processed further.
    589      1.1      cgd  */
    590      1.1      cgd ip_dooptions(m)
    591      1.1      cgd 	struct mbuf *m;
    592      1.1      cgd {
    593      1.1      cgd 	register struct ip *ip = mtod(m, struct ip *);
    594      1.1      cgd 	register u_char *cp;
    595      1.1      cgd 	register struct ip_timestamp *ipt;
    596      1.1      cgd 	register struct in_ifaddr *ia;
    597      1.1      cgd 	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
    598      1.1      cgd 	struct in_addr *sin;
    599      1.1      cgd 	n_time ntime;
    600      1.1      cgd 
    601      1.1      cgd 	cp = (u_char *)(ip + 1);
    602      1.1      cgd 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
    603      1.1      cgd 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
    604      1.1      cgd 		opt = cp[IPOPT_OPTVAL];
    605      1.1      cgd 		if (opt == IPOPT_EOL)
    606      1.1      cgd 			break;
    607      1.1      cgd 		if (opt == IPOPT_NOP)
    608      1.1      cgd 			optlen = 1;
    609      1.1      cgd 		else {
    610      1.1      cgd 			optlen = cp[IPOPT_OLEN];
    611      1.1      cgd 			if (optlen <= 0 || optlen > cnt) {
    612      1.1      cgd 				code = &cp[IPOPT_OLEN] - (u_char *)ip;
    613      1.1      cgd 				goto bad;
    614      1.1      cgd 			}
    615      1.1      cgd 		}
    616      1.1      cgd 		switch (opt) {
    617      1.1      cgd 
    618      1.1      cgd 		default:
    619      1.1      cgd 			break;
    620      1.1      cgd 
    621      1.1      cgd 		/*
    622      1.1      cgd 		 * Source routing with record.
    623      1.1      cgd 		 * Find interface with current destination address.
    624      1.1      cgd 		 * If none on this machine then drop if strictly routed,
    625      1.1      cgd 		 * or do nothing if loosely routed.
    626      1.1      cgd 		 * Record interface address and bring up next address
    627      1.1      cgd 		 * component.  If strictly routed make sure next
    628      1.1      cgd 		 * address is on directly accessible net.
    629      1.1      cgd 		 */
    630      1.1      cgd 		case IPOPT_LSRR:
    631      1.1      cgd 		case IPOPT_SSRR:
    632      1.1      cgd 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
    633      1.1      cgd 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
    634      1.1      cgd 				goto bad;
    635      1.1      cgd 			}
    636      1.1      cgd 			ipaddr.sin_addr = ip->ip_dst;
    637      1.1      cgd 			ia = (struct in_ifaddr *)
    638      1.1      cgd 				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
    639      1.1      cgd 			if (ia == 0) {
    640      1.1      cgd 				if (opt == IPOPT_SSRR) {
    641      1.1      cgd 					type = ICMP_UNREACH;
    642      1.1      cgd 					code = ICMP_UNREACH_SRCFAIL;
    643      1.1      cgd 					goto bad;
    644      1.1      cgd 				}
    645      1.1      cgd 				/*
    646      1.1      cgd 				 * Loose routing, and not at next destination
    647      1.1      cgd 				 * yet; nothing to do except forward.
    648      1.1      cgd 				 */
    649      1.1      cgd 				break;
    650      1.1      cgd 			}
    651      1.1      cgd 			off--;			/* 0 origin */
    652      1.1      cgd 			if (off > optlen - sizeof(struct in_addr)) {
    653      1.1      cgd 				/*
    654      1.1      cgd 				 * End of source route.  Should be for us.
    655      1.1      cgd 				 */
    656      1.1      cgd 				save_rte(cp, ip->ip_src);
    657      1.1      cgd 				break;
    658      1.1      cgd 			}
    659      1.1      cgd 			/*
    660      1.1      cgd 			 * locate outgoing interface
    661      1.1      cgd 			 */
    662      1.1      cgd 			bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
    663      1.1      cgd 			    sizeof(ipaddr.sin_addr));
    664      1.1      cgd 			if (opt == IPOPT_SSRR) {
    665      1.1      cgd #define	INA	struct in_ifaddr *
    666      1.1      cgd #define	SA	struct sockaddr *
    667      1.1      cgd 			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
    668      1.1      cgd 				ia = in_iaonnetof(in_netof(ipaddr.sin_addr));
    669      1.1      cgd 			} else
    670      1.1      cgd 				ia = ip_rtaddr(ipaddr.sin_addr);
    671      1.1      cgd 			if (ia == 0) {
    672      1.1      cgd 				type = ICMP_UNREACH;
    673      1.1      cgd 				code = ICMP_UNREACH_SRCFAIL;
    674      1.1      cgd 				goto bad;
    675      1.1      cgd 			}
    676      1.1      cgd 			ip->ip_dst = ipaddr.sin_addr;
    677      1.1      cgd 			bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
    678      1.1      cgd 			    (caddr_t)(cp + off), sizeof(struct in_addr));
    679      1.1      cgd 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
    680      1.1      cgd 			forward = 1;
    681      1.1      cgd 			break;
    682      1.1      cgd 
    683      1.1      cgd 		case IPOPT_RR:
    684      1.1      cgd 			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
    685      1.1      cgd 				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
    686      1.1      cgd 				goto bad;
    687      1.1      cgd 			}
    688      1.1      cgd 			/*
    689      1.1      cgd 			 * If no space remains, ignore.
    690      1.1      cgd 			 */
    691      1.1      cgd 			off--;			/* 0 origin */
    692      1.1      cgd 			if (off > optlen - sizeof(struct in_addr))
    693      1.1      cgd 				break;
    694      1.1      cgd 			bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
    695      1.1      cgd 			    sizeof(ipaddr.sin_addr));
    696      1.1      cgd 			/*
    697      1.1      cgd 			 * locate outgoing interface; if we're the destination,
    698      1.1      cgd 			 * use the incoming interface (should be same).
    699      1.1      cgd 			 */
    700      1.1      cgd 			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
    701      1.1      cgd 			    (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
    702      1.1      cgd 				type = ICMP_UNREACH;
    703      1.1      cgd 				code = ICMP_UNREACH_HOST;
    704      1.1      cgd 				goto bad;
    705      1.1      cgd 			}
    706      1.1      cgd 			bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
    707      1.1      cgd 			    (caddr_t)(cp + off), sizeof(struct in_addr));
    708      1.1      cgd 			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
    709      1.1      cgd 			break;
    710      1.1      cgd 
    711      1.1      cgd 		case IPOPT_TS:
    712      1.1      cgd 			code = cp - (u_char *)ip;
    713      1.1      cgd 			ipt = (struct ip_timestamp *)cp;
    714      1.1      cgd 			if (ipt->ipt_len < 5)
    715      1.1      cgd 				goto bad;
    716      1.1      cgd 			if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
    717      1.1      cgd 				if (++ipt->ipt_oflw == 0)
    718      1.1      cgd 					goto bad;
    719      1.1      cgd 				break;
    720      1.1      cgd 			}
    721      1.1      cgd 			sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
    722      1.1      cgd 			switch (ipt->ipt_flg) {
    723      1.1      cgd 
    724      1.1      cgd 			case IPOPT_TS_TSONLY:
    725      1.1      cgd 				break;
    726      1.1      cgd 
    727      1.1      cgd 			case IPOPT_TS_TSANDADDR:
    728      1.1      cgd 				if (ipt->ipt_ptr + sizeof(n_time) +
    729      1.1      cgd 				    sizeof(struct in_addr) > ipt->ipt_len)
    730      1.1      cgd 					goto bad;
    731      1.1      cgd 				ia = ifptoia(m->m_pkthdr.rcvif);
    732      1.1      cgd 				bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
    733      1.1      cgd 				    (caddr_t)sin, sizeof(struct in_addr));
    734      1.1      cgd 				ipt->ipt_ptr += sizeof(struct in_addr);
    735      1.1      cgd 				break;
    736      1.1      cgd 
    737      1.1      cgd 			case IPOPT_TS_PRESPEC:
    738      1.1      cgd 				if (ipt->ipt_ptr + sizeof(n_time) +
    739      1.1      cgd 				    sizeof(struct in_addr) > ipt->ipt_len)
    740      1.1      cgd 					goto bad;
    741      1.1      cgd 				bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
    742      1.1      cgd 				    sizeof(struct in_addr));
    743      1.1      cgd 				if (ifa_ifwithaddr((SA)&ipaddr) == 0)
    744      1.1      cgd 					continue;
    745      1.1      cgd 				ipt->ipt_ptr += sizeof(struct in_addr);
    746      1.1      cgd 				break;
    747      1.1      cgd 
    748      1.1      cgd 			default:
    749      1.1      cgd 				goto bad;
    750      1.1      cgd 			}
    751      1.1      cgd 			ntime = iptime();
    752      1.1      cgd 			bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
    753      1.1      cgd 			    sizeof(n_time));
    754      1.1      cgd 			ipt->ipt_ptr += sizeof(n_time);
    755      1.1      cgd 		}
    756      1.1      cgd 	}
    757      1.1      cgd 	if (forward) {
    758      1.1      cgd 		ip_forward(m, 1);
    759      1.1      cgd 		return (1);
    760      1.1      cgd 	} else
    761      1.1      cgd 		return (0);
    762      1.1      cgd bad:
    763      1.1      cgd 	icmp_error(m, type, code);
    764      1.1      cgd 	return (1);
    765      1.1      cgd }
    766      1.1      cgd 
    767      1.1      cgd /*
    768      1.1      cgd  * Given address of next destination (final or next hop),
    769      1.1      cgd  * return internet address info of interface to be used to get there.
    770      1.1      cgd  */
    771      1.1      cgd struct in_ifaddr *
    772      1.1      cgd ip_rtaddr(dst)
    773      1.1      cgd 	 struct in_addr dst;
    774      1.1      cgd {
    775      1.1      cgd 	register struct sockaddr_in *sin;
    776      1.1      cgd 
    777      1.1      cgd 	sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
    778      1.1      cgd 
    779      1.1      cgd 	if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
    780      1.1      cgd 		if (ipforward_rt.ro_rt) {
    781      1.1      cgd 			RTFREE(ipforward_rt.ro_rt);
    782      1.1      cgd 			ipforward_rt.ro_rt = 0;
    783      1.1      cgd 		}
    784      1.1      cgd 		sin->sin_family = AF_INET;
    785      1.1      cgd 		sin->sin_len = sizeof(*sin);
    786      1.1      cgd 		sin->sin_addr = dst;
    787      1.1      cgd 
    788      1.1      cgd 		rtalloc(&ipforward_rt);
    789      1.1      cgd 	}
    790      1.1      cgd 	if (ipforward_rt.ro_rt == 0)
    791      1.1      cgd 		return ((struct in_ifaddr *)0);
    792      1.1      cgd 	return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa);
    793      1.1      cgd }
    794      1.1      cgd 
    795      1.1      cgd /*
    796      1.1      cgd  * Save incoming source route for use in replies,
    797      1.1      cgd  * to be picked up later by ip_srcroute if the receiver is interested.
    798      1.1      cgd  */
    799      1.1      cgd save_rte(option, dst)
    800      1.1      cgd 	u_char *option;
    801      1.1      cgd 	struct in_addr dst;
    802      1.1      cgd {
    803      1.1      cgd 	unsigned olen;
    804      1.1      cgd 
    805      1.1      cgd 	olen = option[IPOPT_OLEN];
    806      1.1      cgd #ifdef DIAGNOSTIC
    807      1.1      cgd 	if (ipprintfs)
    808      1.1      cgd 		printf("save_rte: olen %d\n", olen);
    809      1.1      cgd #endif
    810      1.1      cgd 	if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))
    811      1.1      cgd 		return;
    812      1.1      cgd 	bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen);
    813      1.1      cgd 	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
    814      1.1      cgd 	ip_srcrt.dst = dst;
    815      1.1      cgd }
    816      1.1      cgd 
    817      1.1      cgd /*
    818      1.1      cgd  * Retrieve incoming source route for use in replies,
    819      1.1      cgd  * in the same form used by setsockopt.
    820      1.1      cgd  * The first hop is placed before the options, will be removed later.
    821      1.1      cgd  */
    822      1.1      cgd struct mbuf *
    823      1.1      cgd ip_srcroute()
    824      1.1      cgd {
    825      1.1      cgd 	register struct in_addr *p, *q;
    826      1.1      cgd 	register struct mbuf *m;
    827      1.1      cgd 
    828      1.1      cgd 	if (ip_nhops == 0)
    829      1.1      cgd 		return ((struct mbuf *)0);
    830      1.1      cgd 	m = m_get(M_DONTWAIT, MT_SOOPTS);
    831      1.1      cgd 	if (m == 0)
    832      1.1      cgd 		return ((struct mbuf *)0);
    833      1.1      cgd 
    834      1.1      cgd #define OPTSIZ	(sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))
    835      1.1      cgd 
    836      1.1      cgd 	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */
    837      1.1      cgd 	m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +
    838      1.1      cgd 	    OPTSIZ;
    839      1.1      cgd #ifdef DIAGNOSTIC
    840      1.1      cgd 	if (ipprintfs)
    841      1.1      cgd 		printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);
    842      1.1      cgd #endif
    843      1.1      cgd 
    844      1.1      cgd 	/*
    845      1.1      cgd 	 * First save first hop for return route
    846      1.1      cgd 	 */
    847      1.1      cgd 	p = &ip_srcrt.route[ip_nhops - 1];
    848      1.1      cgd 	*(mtod(m, struct in_addr *)) = *p--;
    849      1.1      cgd #ifdef DIAGNOSTIC
    850      1.1      cgd 	if (ipprintfs)
    851      1.1      cgd 		printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr));
    852      1.1      cgd #endif
    853      1.1      cgd 
    854      1.1      cgd 	/*
    855      1.1      cgd 	 * Copy option fields and padding (nop) to mbuf.
    856      1.1      cgd 	 */
    857      1.1      cgd 	ip_srcrt.nop = IPOPT_NOP;
    858      1.1      cgd 	ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;
    859      1.1      cgd 	bcopy((caddr_t)&ip_srcrt.nop,
    860      1.1      cgd 	    mtod(m, caddr_t) + sizeof(struct in_addr), OPTSIZ);
    861      1.1      cgd 	q = (struct in_addr *)(mtod(m, caddr_t) +
    862      1.1      cgd 	    sizeof(struct in_addr) + OPTSIZ);
    863      1.1      cgd #undef OPTSIZ
    864      1.1      cgd 	/*
    865      1.1      cgd 	 * Record return path as an IP source route,
    866      1.1      cgd 	 * reversing the path (pointers are now aligned).
    867      1.1      cgd 	 */
    868      1.1      cgd 	while (p >= ip_srcrt.route) {
    869      1.1      cgd #ifdef DIAGNOSTIC
    870      1.1      cgd 		if (ipprintfs)
    871      1.1      cgd 			printf(" %lx", ntohl(q->s_addr));
    872      1.1      cgd #endif
    873      1.1      cgd 		*q++ = *p--;
    874      1.1      cgd 	}
    875      1.1      cgd 	/*
    876      1.1      cgd 	 * Last hop goes to final destination.
    877      1.1      cgd 	 */
    878      1.1      cgd 	*q = ip_srcrt.dst;
    879      1.1      cgd #ifdef DIAGNOSTIC
    880      1.1      cgd 	if (ipprintfs)
    881      1.1      cgd 		printf(" %lx\n", ntohl(q->s_addr));
    882      1.1      cgd #endif
    883      1.1      cgd 	return (m);
    884      1.1      cgd }
    885      1.1      cgd 
    886      1.1      cgd /*
    887      1.1      cgd  * Strip out IP options, at higher
    888      1.1      cgd  * level protocol in the kernel.
    889      1.1      cgd  * Second argument is buffer to which options
    890      1.1      cgd  * will be moved, and return value is their length.
    891      1.1      cgd  * XXX should be deleted; last arg currently ignored.
    892      1.1      cgd  */
    893      1.1      cgd ip_stripoptions(m, mopt)
    894      1.1      cgd 	register struct mbuf *m;
    895      1.1      cgd 	struct mbuf *mopt;
    896      1.1      cgd {
    897      1.1      cgd 	register int i;
    898      1.1      cgd 	struct ip *ip = mtod(m, struct ip *);
    899      1.1      cgd 	register caddr_t opts;
    900      1.1      cgd 	int olen;
    901      1.1      cgd 
    902      1.1      cgd 	olen = (ip->ip_hl<<2) - sizeof (struct ip);
    903      1.1      cgd 	opts = (caddr_t)(ip + 1);
    904      1.1      cgd 	i = m->m_len - (sizeof (struct ip) + olen);
    905      1.1      cgd 	bcopy(opts  + olen, opts, (unsigned)i);
    906      1.1      cgd 	m->m_len -= olen;
    907      1.1      cgd 	if (m->m_flags & M_PKTHDR)
    908      1.1      cgd 		m->m_pkthdr.len -= olen;
    909      1.1      cgd 	ip->ip_hl = sizeof(struct ip) >> 2;
    910      1.1      cgd }
    911      1.1      cgd 
    912      1.1      cgd u_char inetctlerrmap[PRC_NCMDS] = {
    913      1.1      cgd 	0,		0,		0,		0,
    914      1.1      cgd 	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,
    915      1.1      cgd 	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
    916      1.1      cgd 	EMSGSIZE,	EHOSTUNREACH,	0,		0,
    917      1.1      cgd 	0,		0,		0,		0,
    918      1.1      cgd 	ENOPROTOOPT
    919      1.1      cgd };
    920      1.1      cgd 
    921      1.1      cgd /*
    922      1.1      cgd  * Forward a packet.  If some error occurs return the sender
    923      1.1      cgd  * an icmp packet.  Note we can't always generate a meaningful
    924      1.1      cgd  * icmp message because icmp doesn't have a large enough repertoire
    925      1.1      cgd  * of codes and types.
    926      1.1      cgd  *
    927      1.1      cgd  * If not forwarding, just drop the packet.  This could be confusing
    928      1.1      cgd  * if ipforwarding was zero but some routing protocol was advancing
    929      1.1      cgd  * us as a gateway to somewhere.  However, we must let the routing
    930      1.1      cgd  * protocol deal with that.
    931      1.1      cgd  *
    932      1.1      cgd  * The srcrt parameter indicates whether the packet is being forwarded
    933      1.1      cgd  * via a source route.
    934      1.1      cgd  */
    935      1.1      cgd ip_forward(m, srcrt)
    936      1.1      cgd 	struct mbuf *m;
    937      1.1      cgd 	int srcrt;
    938      1.1      cgd {
    939      1.1      cgd 	register struct ip *ip = mtod(m, struct ip *);
    940      1.1      cgd 	register struct sockaddr_in *sin;
    941      1.1      cgd 	register struct rtentry *rt;
    942      1.1      cgd 	int error, type = 0, code;
    943      1.1      cgd 	struct mbuf *mcopy;
    944      1.1      cgd 	struct in_addr dest;
    945      1.1      cgd 
    946      1.1      cgd 	dest.s_addr = 0;
    947      1.1      cgd #ifdef DIAGNOSTIC
    948      1.1      cgd 	if (ipprintfs)
    949      1.1      cgd 		printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
    950      1.1      cgd 			ip->ip_dst, ip->ip_ttl);
    951      1.1      cgd #endif
    952      1.1      cgd 	if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) {
    953      1.1      cgd 		ipstat.ips_cantforward++;
    954      1.1      cgd 		m_freem(m);
    955      1.1      cgd 		return;
    956      1.1      cgd 	}
    957      1.1      cgd 	HTONS(ip->ip_id);
    958      1.1      cgd 	if (ip->ip_ttl <= IPTTLDEC) {
    959      1.1      cgd 		icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest);
    960      1.1      cgd 		return;
    961      1.1      cgd 	}
    962      1.1      cgd 	ip->ip_ttl -= IPTTLDEC;
    963      1.1      cgd 
    964      1.1      cgd 	sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
    965      1.1      cgd 	if ((rt = ipforward_rt.ro_rt) == 0 ||
    966      1.1      cgd 	    ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
    967      1.1      cgd 		if (ipforward_rt.ro_rt) {
    968      1.1      cgd 			RTFREE(ipforward_rt.ro_rt);
    969      1.1      cgd 			ipforward_rt.ro_rt = 0;
    970      1.1      cgd 		}
    971      1.1      cgd 		sin->sin_family = AF_INET;
    972      1.1      cgd 		sin->sin_len = sizeof(*sin);
    973      1.1      cgd 		sin->sin_addr = ip->ip_dst;
    974      1.1      cgd 
    975      1.1      cgd 		rtalloc(&ipforward_rt);
    976      1.1      cgd 		if (ipforward_rt.ro_rt == 0) {
    977      1.1      cgd 			icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest);
    978      1.1      cgd 			return;
    979      1.1      cgd 		}
    980      1.1      cgd 		rt = ipforward_rt.ro_rt;
    981      1.1      cgd 	}
    982      1.1      cgd 
    983      1.1      cgd 	/*
    984      1.1      cgd 	 * Save at most 64 bytes of the packet in case
    985      1.1      cgd 	 * we need to generate an ICMP message to the src.
    986      1.1      cgd 	 */
    987      1.1      cgd 	mcopy = m_copy(m, 0, imin((int)ip->ip_len, 64));
    988      1.1      cgd 
    989      1.1      cgd #ifdef GATEWAY
    990      1.1      cgd 	ip_ifmatrix[rt->rt_ifp->if_index +
    991      1.1      cgd 	     if_index * m->m_pkthdr.rcvif->if_index]++;
    992      1.1      cgd #endif
    993      1.1      cgd 	/*
    994      1.1      cgd 	 * If forwarding packet using same interface that it came in on,
    995      1.1      cgd 	 * perhaps should send a redirect to sender to shortcut a hop.
    996      1.1      cgd 	 * Only send redirect if source is sending directly to us,
    997      1.1      cgd 	 * and if packet was not source routed (or has any options).
    998      1.1      cgd 	 * Also, don't send redirect if forwarding using a default route
    999      1.1      cgd 	 * or a route modified by a redirect.
   1000      1.1      cgd 	 */
   1001      1.1      cgd #define	satosin(sa)	((struct sockaddr_in *)(sa))
   1002      1.1      cgd 	if (rt->rt_ifp == m->m_pkthdr.rcvif &&
   1003      1.1      cgd 	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
   1004      1.1      cgd 	    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
   1005      1.1      cgd 	    ipsendredirects && !srcrt) {
   1006      1.1      cgd 		struct in_ifaddr *ia;
   1007      1.1      cgd 		u_long src = ntohl(ip->ip_src.s_addr);
   1008      1.1      cgd 		u_long dst = ntohl(ip->ip_dst.s_addr);
   1009      1.1      cgd 
   1010      1.1      cgd 		if ((ia = ifptoia(m->m_pkthdr.rcvif)) &&
   1011      1.1      cgd 		   (src & ia->ia_subnetmask) == ia->ia_subnet) {
   1012      1.1      cgd 		    if (rt->rt_flags & RTF_GATEWAY)
   1013      1.1      cgd 			dest = satosin(rt->rt_gateway)->sin_addr;
   1014      1.1      cgd 		    else
   1015      1.1      cgd 			dest = ip->ip_dst;
   1016      1.1      cgd 		    /*
   1017      1.1      cgd 		     * If the destination is reached by a route to host,
   1018      1.1      cgd 		     * is on a subnet of a local net, or is directly
   1019      1.1      cgd 		     * on the attached net (!), use host redirect.
   1020      1.1      cgd 		     * (We may be the correct first hop for other subnets.)
   1021      1.1      cgd 		     */
   1022      1.1      cgd #define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))
   1023      1.1      cgd 		    type = ICMP_REDIRECT;
   1024      1.1      cgd 		    if ((rt->rt_flags & RTF_HOST) ||
   1025      1.1      cgd 		        (rt->rt_flags & RTF_GATEWAY) == 0)
   1026      1.1      cgd 			    code = ICMP_REDIRECT_HOST;
   1027      1.1      cgd 		    else if (RTA(rt)->ia_subnetmask != RTA(rt)->ia_netmask &&
   1028      1.1      cgd 		        (dst & RTA(rt)->ia_netmask) ==  RTA(rt)->ia_net)
   1029      1.1      cgd 			    code = ICMP_REDIRECT_HOST;
   1030      1.1      cgd 		    else
   1031      1.1      cgd 			    code = ICMP_REDIRECT_NET;
   1032      1.1      cgd #ifdef DIAGNOSTIC
   1033      1.1      cgd 		    if (ipprintfs)
   1034      1.1      cgd 		        printf("redirect (%d) to %x\n", code, dest.s_addr);
   1035      1.1      cgd #endif
   1036      1.1      cgd 		}
   1037      1.1      cgd 	}
   1038      1.1      cgd 
   1039      1.1      cgd 	error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING);
   1040      1.1      cgd 	if (error)
   1041      1.1      cgd 		ipstat.ips_cantforward++;
   1042      1.1      cgd 	else {
   1043      1.1      cgd 		ipstat.ips_forward++;
   1044      1.1      cgd 		if (type)
   1045      1.1      cgd 			ipstat.ips_redirectsent++;
   1046      1.1      cgd 		else {
   1047      1.1      cgd 			if (mcopy)
   1048      1.1      cgd 				m_freem(mcopy);
   1049      1.1      cgd 			return;
   1050      1.1      cgd 		}
   1051      1.1      cgd 	}
   1052      1.1      cgd 	if (mcopy == NULL)
   1053      1.1      cgd 		return;
   1054      1.1      cgd 	switch (error) {
   1055      1.1      cgd 
   1056      1.1      cgd 	case 0:				/* forwarded, but need redirect */
   1057      1.1      cgd 		/* type, code set above */
   1058      1.1      cgd 		break;
   1059      1.1      cgd 
   1060      1.1      cgd 	case ENETUNREACH:		/* shouldn't happen, checked above */
   1061      1.1      cgd 	case EHOSTUNREACH:
   1062      1.1      cgd 	case ENETDOWN:
   1063      1.1      cgd 	case EHOSTDOWN:
   1064      1.1      cgd 	default:
   1065      1.1      cgd 		type = ICMP_UNREACH;
   1066      1.1      cgd 		code = ICMP_UNREACH_HOST;
   1067      1.1      cgd 		break;
   1068      1.1      cgd 
   1069      1.1      cgd 	case EMSGSIZE:
   1070      1.1      cgd 		type = ICMP_UNREACH;
   1071      1.1      cgd 		code = ICMP_UNREACH_NEEDFRAG;
   1072      1.1      cgd 		ipstat.ips_cantfrag++;
   1073      1.1      cgd 		break;
   1074      1.1      cgd 
   1075      1.1      cgd 	case ENOBUFS:
   1076      1.1      cgd 		type = ICMP_SOURCEQUENCH;
   1077      1.1      cgd 		code = 0;
   1078      1.1      cgd 		break;
   1079      1.1      cgd 	}
   1080      1.1      cgd 	icmp_error(mcopy, type, code, dest);
   1081      1.1      cgd }
   1082