125202Skarels #ifdef	RCSIDENT
225202Skarels static char rcsident[] = "$Header: ip_input.c,v 1.39 85/07/31 09:31:26 walsh Exp $";
325202Skarels #endif
425202Skarels 
525202Skarels #include "../h/param.h"
625202Skarels #include "../h/mbuf.h"
725202Skarels #include "../h/socket.h"
825202Skarels #include "../h/socketvar.h"
925202Skarels #include "../h/errno.h"
1025202Skarels #include "../h/protosw.h"
1125202Skarels #include "../h/domain.h"
1225202Skarels #include "../h/syslog.h"
1325202Skarels 
1425202Skarels #include "../net/if.h"
1525202Skarels #include "../net/route.h"
1625202Skarels #include "../net/raw_cb.h"
1725202Skarels 
1825202Skarels #include "../bbnnet/in.h"
1925202Skarels #include "../bbnnet/net.h"
2025202Skarels #include "../bbnnet/in_pcb.h"
2125202Skarels #include "../bbnnet/in_var.h"
2225202Skarels #include "../bbnnet/ip.h"
2325202Skarels #include "../bbnnet/icmp.h"
2425202Skarels #ifdef	HMP
2525202Skarels #include "../bbnnet/hmp_traps.h"
2625202Skarels #endif
2725202Skarels 
2825202Skarels #ifdef	RCSIDENT
2925202Skarels static char rcsiphdr[] = RCSIPHDR;
3025202Skarels #endif
3125202Skarels 
3225202Skarels #define rawreaders(r)	 	((r)->rcb_next != (r))
3325202Skarels #define any_rawreaders()	rawreaders(&rawcb)
3425202Skarels 
3525202Skarels #define FIELD_OFF(fld, type) (((char *) (&(((type *) 0)->fld))) - ((char *) 0))
3625202Skarels 
3725202Skarels struct in_stat otherstat;
3825202Skarels struct ip_stat ipstat;
3925202Skarels struct {
4025202Skarels  	struct ipq *n_ip_head;		/* -> top of ip reass. queue */
4125202Skarels 	struct ipq *n_ip_tail;		/* -> end of ip reass. queue */
4225202Skarels } ipfrags;
4325202Skarels 
4425202Skarels 
4525202Skarels /*
4625202Skarels  * The protocol layers above IP assume the IP header and the protocol
4725202Skarels  * header are contiguous.  However, need to save the options in case
4825202Skarels  * a connection oriented protocol (RDP/TCP) wants to respond to an
4925202Skarels  * incoming packet (SYN) over the same route if the packet got here
5025202Skarels  * using IP source routing.  This allows connection establishment and
5125202Skarels  * maintenance when the remote end is on a network that is not known
5225202Skarels  * to our gateways.  Only applicable options are Loose/Strict source
5325202Skarels  * routing, so rather than saving them in ip_stripopt() and reinterpreting
5425202Skarels  * them, we'll set up something specific and appropriate here.
5525202Skarels  */
5625202Skarels 
5725202Skarels int nosum = 0;
5825202Skarels int	ip_nhops = 0;
5925202Skarels struct in_addr ip_hops[MAX_IPOPTLEN / sizeof(struct in_addr)];
6025202Skarels 
6125202Skarels /* use a dispatch table for protocol dispatching */
6225202Skarels struct ipswitch ipsw[IPPROTO_MAX];
6325202Skarels 
6425202Skarels extern struct ip *ip_reass();
6525202Skarels 
6625202Skarels 
ip_init()6725202Skarels ip_init()
6825202Skarels {
6925202Skarels     register struct protosw *pr;
7025202Skarels     register int i;
7125202Skarels 
7225202Skarels     pr = pffindproto(PF_INET, IPPROTO_IP, SOCK_RAW);
7325202Skarels 
7425202Skarels     /* build our internal switch table */
7525202Skarels     for(i=0; i < IPPROTO_MAX; i++)
7625202Skarels     {
7725202Skarels 	ipsw[i].ipsw_raw = pr;
7825202Skarels 	ipsw[i].ipsw_user = 0;
7925202Skarels 	ipsw[i].ipsw_hlen = sizeof(struct ip);
8025202Skarels     }
8125202Skarels 
8225202Skarels     for(pr = inetdomain.dom_protosw; pr < inetdomain.dom_protoswNPROTOSW; pr++)
8325202Skarels     {
8425202Skarels 	if (pr->pr_protocol >= IPPROTO_MAX)
8525202Skarels 	    panic("ip_init");
8625202Skarels 
8725202Skarels 	if (pr->pr_type == SOCK_RAW)
8825202Skarels 	    ipsw[pr->pr_protocol].ipsw_raw = pr;
8925202Skarels 	else
9025202Skarels 	    ipsw[pr->pr_protocol].ipsw_user = pr;
9125202Skarels     }
9225202Skarels 
9325202Skarels     ipintrq.ifq_maxlen = IFQ_MAXLEN;	/* got a better number? */
9425202Skarels }
9525202Skarels 
9625202Skarels /*
9725202Skarels  * Being global might be a little gross, but we just got the interface pointer
9825202Skarels  * passed up the week before 4.3 release.
9925202Skarels  */
10025202Skarels struct ifnet *inetifp;
10125202Skarels 
10225202Skarels /*
10325202Skarels  * IP network software interrupt service routine.  Dequeue a message from the
10425202Skarels  * ip input queue, and pass to internal ip input processor (ip_input).
10525202Skarels  */
ipintr()10625202Skarels ipintr()
10725202Skarels {
10825202Skarels     extern char *panicstr;
10925202Skarels     register struct mbuf *m;
11025202Skarels     register int s;
11125202Skarels 
11225202Skarels     /*
11325202Skarels      * Half-hearted attempt to prevent recursive panics due to network
11425202Skarels      * bugs since panic calls boot, which lowers spl.  Note that the
11525202Skarels      * drivers will still store packets in mbufs and that some processing
11625202Skarels      * (ARP, Chaosnet) that occurs at splimp() will still proceed.  At
11725202Skarels      * least this should preserve state information for post-mortem.
11825202Skarels      */
11925202Skarels     if (panicstr == NULL)
12025202Skarels     {
12125202Skarels 	for (;;)
12225202Skarels 	{
12325202Skarels 	    /* for 4.3, Berkeley finally changed imp code to queue up messages
12425202Skarels 	     * for ctlinput path, so don't need to check for them here with our
12525202Skarels 	     * old queueing mechanism
12625202Skarels 	     */
12725202Skarels 
12825202Skarels 	    s = splimp();
12925202Skarels 	    IF_DEQUEUEIF (&ipintrq, m, inetifp);
13025202Skarels 	    splx(s);
13125202Skarels 	    if (m == NULL)
13225202Skarels 		return;
13325202Skarels 
13425202Skarels 	    ip_input(m);
13525202Skarels 	}
13625202Skarels     }
13725202Skarels }
13825202Skarels 
13925202Skarels /*
14025202Skarels  * IP level input routine
14125202Skarels  *
14225202Skarels  * Called from local net level upon recpt of an internet datagram or fragment.
14325202Skarels  * This routine does fragment reassembly, if necessary, and passes completed
14425202Skarels  * datagrams to higher level protocol processing routines on the basis of the
14525202Skarels  * ip header protocol field.  It is passed a pointer to an mbuf chain
14625202Skarels  * containing the datagram/fragment. The mbuf offset+length are set to point
14725202Skarels  * at the ip header.
14825202Skarels  */
ip_input(mp)14925202Skarels ip_input(mp)
15025202Skarels register struct mbuf *mp;
15125202Skarels {
15225202Skarels     register struct ip *ip;
15325202Skarels     register int hlen;
15425202Skarels     register int i;
15525202Skarels     register struct mbuf *m;
15625202Skarels     register struct ipq *fp;
15725202Skarels     int fragsize = 0;
15825202Skarels     struct in_ifaddr *ia;
15925202Skarels     int j;
16025202Skarels     struct inpcb fwdinp;
16125202Skarels 
16225202Skarels     ipstat.ip_total ++;
16325202Skarels     /*
16425202Skarels      * make sure dtom() macro works by getting header out of mbufs using
16525202Skarels      * pages, also make sure header contiguous in first mbuf.
16625202Skarels      */
16725202Skarels     if ((mp->m_off > MMAXOFF) || (mp->m_len < sizeof(struct ip)))
16825202Skarels     {
16925202Skarels 	/*
17025202Skarels 	 * Might as well avoid doing m_pullup twice.
17125202Skarels 	 * Common case is using cluster for large chunk of data.
17225202Skarels 	 */
17325202Skarels 	if (mp->m_len < FIELD_OFF(ip_p, struct ip) + sizeof(ip->ip_p))
17425202Skarels 	    i = sizeof(struct ip);
17525202Skarels 	else
17625202Skarels 	{
17725202Skarels 	    ip = mtod(mp, struct ip *);
17825202Skarels 	    i = ipsw[ip->ip_p].ipsw_hlen;
17925202Skarels 	}
18025202Skarels 
18125202Skarels 	if ((mp = m_pullup(mp, i)) == NULL)
18225202Skarels 	{
18325202Skarels 	    ipstat.ip_tooshort ++;
18425202Skarels 	    return;
18525202Skarels 	}
18625202Skarels     }
18725202Skarels 
18825202Skarels     ip = mtod(mp, struct ip *);
18925202Skarels 
19025202Skarels     /*
19125202Skarels      * make sure header does not overflow mbuf  (is contiguous)
19225202Skarels      */
19325202Skarels     hlen = ip->ip_hl << IP_HLSHIFT;
19425202Skarels     if (hlen > mp->m_len)
19525202Skarels     {
19625202Skarels 	if ((mp = m_pullup(mp, hlen)) == NULL)
19725202Skarels 	{
19825202Skarels 	    ip_log(ip, "ip header overflow");
19925202Skarels #ifdef HMPTRAPS
20025202Skarels 	    /* hmp_trap(T_IP_OVFLO, (caddr_t)0,0); */
20125202Skarels #else
20225202Skarels 	    /* netlog(mp); no longer have mbuf list */
20325202Skarels #endif
20425202Skarels 	    return;
20525202Skarels 	}
20625202Skarels 	ip = mtod(mp, struct ip *);
20725202Skarels     }
20825202Skarels 
20925202Skarels     /*
21025202Skarels      * Adjust msg length to remove any driver padding.  Make sure that
21125202Skarels      * message length matches ip length.
21225202Skarels      */
21325202Skarels     for (i = 0, m = mp; m->m_next != NULL; m = m->m_next)
21425202Skarels 	i += m->m_len;
21525202Skarels     i -= ntohs((u_short)ip->ip_len) - m->m_len;
21625202Skarels     if (i != 0)
21725202Skarels     {
21825202Skarels 	if (i > (int)m->m_len)
21925202Skarels 	    m_adj(mp, -i);
22025202Skarels 	else if (i < 0)
22125202Skarels 	{
22225202Skarels 	    ip_log(ip, "truncated ip packet");
22325202Skarels #ifdef HMPTRAPS
22425202Skarels 	    /* hmp_trap(T_IP_TRUNC, (caddr_t)0, 0); */
22525202Skarels #else
22625202Skarels 	    netlog(mp);
22725202Skarels #endif
22825202Skarels 	    return;
22925202Skarels 	}
23025202Skarels 	else
23125202Skarels 	    m->m_len -= i;
23225202Skarels     }
23325202Skarels 
23425202Skarels     i = (u_short)ip->ip_sum;
23525202Skarels     ip->ip_sum = 0;
23625202Skarels 
23725202Skarels     /* used to do inline cksum here via sed */
23825202Skarels     if (i != (j = (u_short)in_cksum(dtom(ip), hlen)))
23925202Skarels     {
24025202Skarels 	ipstat.ip_badsum++;
24125202Skarels 	if (!nosum)
24225202Skarels 	{
24325202Skarels #ifdef HMPTRAPS
24425202Skarels 	    /* hmp_trap(T_IP_CKSUM, (caddr_t)0,0); */
24525202Skarels #endif
24625202Skarels 	    inet_cksum_err ("ip", ip, (u_long) i, (u_long) j);
24725202Skarels 
24825202Skarels 	    ip->ip_sum = i;
24925202Skarels 	    ic_errmsg (icmp_addr(ip), ip->ip_src,
25025202Skarels 		ICMP_PARM, 0, FIELD_OFF(ip_sum, struct ip),
25125202Skarels 		hlen + ICMP_ERRLEN, (char *) ip);
25225202Skarels 
25325202Skarels 	    netlog(mp);
25425202Skarels 	    return;
25525202Skarels 	}
25625202Skarels     }
25725202Skarels 
25825202Skarels     /*
25925202Skarels      * Make sure this packet is addressed to us before we put fields
26025202Skarels      * in host order and do reassembly (fragments may reach destination
26125202Skarels      * by separate routes.)
26225202Skarels      * Remember that IP source routing option can change ip_dst, so have
26325202Skarels      * to do option processing for all incoming packets with options.
26425202Skarels      * Even if the packet turns out to be for us and we strip them.
26525202Skarels      */
26625202Skarels     fwdinp.inp_route.ro_rt = NULL; /* in case fwd, but no options */
26725202Skarels     ip_nhops = 0;	/* for source routed TCP/RDP... connections */
26825202Skarels     if (hlen > sizeof(struct ip))
26925202Skarels 	/*
27025202Skarels 	 * Any route allocated by ip_opt() 1. will be used by
27125202Skarels 	 * ip_forward(), and 2. will only be needed by ip_forward()
27225202Skarels 	 */
27325202Skarels 	if (! ip_opt (ip, hlen, &fwdinp))
27425202Skarels 	{
27525202Skarels 	    ip_log (ip, "ip option error");
27625202Skarels 	    netlog (mp);
27725202Skarels 	    return;
27825202Skarels 	}
27925202Skarels 
28025202Skarels     /*
28125202Skarels      * if packet is not for us then forward
28225202Skarels      */
28325202Skarels     if ((ia = in_iawithaddr(ip->ip_dst, TRUE)) == NULL)
28425202Skarels     {
28525202Skarels 	ip_forward (&fwdinp, ip, mp, hlen);
28625202Skarels 	return;
28725202Skarels     }
28825202Skarels 
28925202Skarels     ip->ip_len = ntohs((u_short)ip->ip_len);
29025202Skarels     if ((int)(ip->ip_len -= hlen) < 0)
29125202Skarels     {     /* length of data */
29225202Skarels 	ip_log(ip, "ip header length error");
29325202Skarels #ifdef HMPTRAPS
29425202Skarels 	/* hmp_trap(T_IP_HLEN, (caddr_t)0,0); */
29525202Skarels #else
29625202Skarels 	netlog(mp);
29725202Skarels #endif
29825202Skarels 	return;
29925202Skarels     }
30025202Skarels     ip->ip_off = ntohs((u_short)ip->ip_off);
30125202Skarels     ip->ip_mff = ((ip->ip_off & ip_mf) ? TRUE : FALSE);
30225202Skarels     ip->ip_off <<= IP_OFFSHIFT;
30325202Skarels 
30425202Skarels     /* look for chain on reassembly queue with this header */
30525202Skarels 
30625202Skarels     for (fp = ipfrags.n_ip_head; (fp != NULL && (
30725202Skarels 	ip->ip_src.s_addr != fp->iqh.ip_src.s_addr ||
30825202Skarels 	ip->ip_dst.s_addr != fp->iqh.ip_dst.s_addr ||
30925202Skarels 	ip->ip_id != fp->iqh.ip_id ||
31025202Skarels 	ip->ip_p != fp->iqh.ip_p)); fp = fp->iq_next);
31125202Skarels 
31225202Skarels     if (!ip->ip_mff && ip->ip_off == 0)
31325202Skarels     {    /* not fragmented */
31425202Skarels 
31525202Skarels 	if (fp != NULL)
31625202Skarels 	{               /* free existing reass chain */
31725202Skarels 	    struct ip *q;
31825202Skarels 	    struct ip *p;
31925202Skarels 
32025202Skarels 	    q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */
32125202Skarels 	    while (q != (struct ip *)fp)
32225202Skarels 	    {
32325202Skarels 		p = q->ip_next;
32425202Skarels 		m_freem(dtom(q));
32525202Skarels 		q = p;
32625202Skarels 	    }
32725202Skarels 	    ip_freef(fp); /* free header */
32825202Skarels 	}
32925202Skarels 
33025202Skarels 	/*
33125202Skarels 	 * The options aren't of any use to higher level
33225202Skarels 	 * protocols or of any concern to the user process.
33325202Skarels 	 */
33425202Skarels 	if (hlen > sizeof(struct ip))
33525202Skarels 	    ip_stripopt (ip, hlen);
33625202Skarels 
33725202Skarels     }
33825202Skarels     else
33925202Skarels     {
34025202Skarels 	ip = ip_reass(ip, fp, &fragsize);
34125202Skarels 	if (ip == NULL)
34225202Skarels 	    return;
34325202Skarels 	mp = dtom(ip);
34425202Skarels     }
34525202Skarels 
34625202Skarels     /* call next level with completed datagram */
34725202Skarels 
34825202Skarels     /* any raw readers?? */
34925202Skarels     /* if (rawreaders((struct rawcb *)ipsw[ip->ip_p].ipsw_raw->pr_ppcbq)) */
35025202Skarels     if (any_rawreaders())
35125202Skarels     {
35225202Skarels 	otherstat.in_total++;
35325202Skarels 	if (m = m_copy(mp, 0, M_COPYALL))
35425202Skarels 	    ipsw[ip->ip_p].ipsw_raw->pr_input(m);
35525202Skarels     }
35625202Skarels 
35725202Skarels     if (ip->ip_p == IPPROTO_TCP)
35825202Skarels 	/* wish I didn't need this special case for fragsize */
35925202Skarels 	tcp_input(mp, fragsize);
36025202Skarels     else if (ipsw[ip->ip_p].ipsw_user != 0)
36125202Skarels 	/* There's a protocol implementation for these packets */
36225202Skarels 	ipsw[ip->ip_p].ipsw_user->pr_input(mp);
36325202Skarels     else if (ip->ip_p == IPPROTO_ICMP)
36425202Skarels 	/*
36525202Skarels 	 * Since don't want user to get a non-raw ICMP socket, did not make
36625202Skarels 	 * an entry in the protocol jump table; also wanted to be able to
36725202Skarels 	 * make raw ICMP socket.
36825202Skarels 	 */
36925202Skarels 	icmp (mp);
37025202Skarels     else
37125202Skarels     {
37225202Skarels 	/*
37325202Skarels 	 * Don't bother everyone on the net, and remember some other
37425202Skarels 	 * host may support the protocol.
37525202Skarels 	 */
37625202Skarels 	if ((!in_broadcast(ip->ip_src)) && (!in_broadcast(ip->ip_dst)))
37725202Skarels 	    ic_errmsg (icmp_addr(ip), ip->ip_src,
37825202Skarels 		ICMP_UNRCH, ICMP_UNRCH_PR, FIELD_OFF(ip_p, struct ip),
37925202Skarels 		sizeof(struct ip) + ICMP_ERRLEN, (char *) ip);
38025202Skarels 
38125202Skarels 	/* get rid of the packet */
38225202Skarels 	ipstat.ip_drops++;
38325202Skarels 	m_freem(mp);
38425202Skarels     }
38525202Skarels }
38625202Skarels 
38725202Skarels 
38825202Skarels /*
38925202Skarels  * We've received an IP fragment.  Try to perform IP reassembly.
39025202Skarels  */
ip_reass(ip,fp,fragsize)39125202Skarels struct ip *ip_reass(ip, fp, fragsize)
39225202Skarels register struct ip *ip;
39325202Skarels register struct ipq *fp;
39425202Skarels int *fragsize;
39525202Skarels {
39625202Skarels     register struct ip *q, *savq;
39725202Skarels     register struct mbuf *mp;
39825202Skarels     int hlen;
39925202Skarels     int i;
40025202Skarels 
40125202Skarels     mp = dtom(ip);
40225202Skarels     hlen = ip->ip_hl << IP_HLSHIFT;
40325202Skarels 
40425202Skarels     if (ip->ip_off != 0)
40525202Skarels     {
40625202Skarels 	/*
40725202Skarels 	 * Only the first fragment retains the IP header.
40825202Skarels 	 */
40925202Skarels 	mp->m_off += hlen;
41025202Skarels 	mp->m_len -= hlen;
41125202Skarels     }
41225202Skarels 
41325202Skarels     if (fp == NULL)
41425202Skarels     {
41525202Skarels 	/*
41625202Skarels 	 * This is the first fragment of the IP datagram that we've
41725202Skarels 	 * received.  Set up reassembly q header.
41825202Skarels 	 */
41925202Skarels 	struct mbuf *m;
42025202Skarels 
42125202Skarels 	if ((m = m_get(M_WAIT, MT_FTABLE)) == NULL)
42225202Skarels 	{
42325202Skarels 	    m_freem(mp);
42425202Skarels 	    return(NULL);
42525202Skarels 	}
42625202Skarels 
42725202Skarels 	fp = mtod(m, struct ipq *);
42825202Skarels 	fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp;
42925202Skarels 	bcopy((caddr_t)ip, (caddr_t)&fp->iqh, sizeof(struct ip));
43025202Skarels 	fp->iqx.ip_ttl	= MAXTTL;
43125202Skarels 	fp->iq_size	= 0;
43225202Skarels 	/*
43325202Skarels 	 * and enter this into the list of fragmented IP datagrams
43425202Skarels 	 */
43525202Skarels 	fp->iq_next	= NULL;
43625202Skarels 	fp->iq_prev	= ipfrags.n_ip_tail;
43725202Skarels 	if (ipfrags.n_ip_head != NULL)
43825202Skarels 	    ipfrags.n_ip_tail->iq_next = fp;
43925202Skarels 	else
44025202Skarels 	    ipfrags.n_ip_head = fp;
44125202Skarels 	ipfrags.n_ip_tail = fp;
44225202Skarels     }
44325202Skarels 
44425202Skarels     /*
44525202Skarels      * Merge fragment into reass.q
44625202Skarels      *
44725202Skarels      * Algorithm:   Match  start  and  end  bytes  of new
44825202Skarels      * fragment  with  fragments  on  the  queue.   If no
44925202Skarels      * overlaps  are  found,  add  new  frag. to the queue.
45025202Skarels      * Otherwise, adjust start and end of new frag.  so  no
45125202Skarels      * overlap   and   add  remainder  to  queue.   If  any
45225202Skarels      * fragments are completely covered by the new one,  or
45325202Skarels      * if  the  new  one is completely duplicated, free the
45425202Skarels      * fragments.
45525202Skarels      */
45625202Skarels     q = fp->iqx.ip_next; /* -> top of reass. chain */
45725202Skarels     ip->ip_end = ip->ip_off + ip->ip_len - 1;
45825202Skarels 
45925202Skarels     /* record the maximum fragment size for TCP */
46025202Skarels 
46125202Skarels     fp->iq_size = MAX(ip->ip_len, fp->iq_size);
46225202Skarels 
46325202Skarels     /* skip frags which new doesn't overlap at end */
46425202Skarels 
46525202Skarels     while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end))
46625202Skarels 	q = q->ip_next;
46725202Skarels 
46825202Skarels     if (q == (struct ip *)fp)
46925202Skarels     {	/* frag at end of chain */
47025202Skarels 	ip_enq(ip, fp->iqx.ip_prev);
47125202Skarels     }
47225202Skarels     else
47325202Skarels     {			/* frag doesn't overlap any */
47425202Skarels 	if (ip->ip_end < q->ip_off)
47525202Skarels 	{
47625202Skarels 	    ip_enq(ip, q->ip_prev);
47725202Skarels 
47825202Skarels 	    /* new overlaps beginning of next frag only */
47925202Skarels 
48025202Skarels 	}
48125202Skarels 	else if (ip->ip_end < q->ip_end)
48225202Skarels 	{
48325202Skarels 	    if ((i = ip->ip_end-q->ip_off+1) < ip->ip_len)
48425202Skarels 	    {
48525202Skarels 		ip->ip_len -= i;
48625202Skarels 		ip->ip_end -= i;
48725202Skarels 		m_adj(mp, -i);
48825202Skarels 		ip_enq(ip, q->ip_prev);
48925202Skarels 	    }
49025202Skarels 	    else
49125202Skarels 		m_freem(mp);
49225202Skarels 
49325202Skarels 	    /* new overlaps end of previous frag */
49425202Skarels 
49525202Skarels 	}
49625202Skarels 	else
49725202Skarels 	{
49825202Skarels 	    savq = q;
49925202Skarels 	    if (ip->ip_off <= q->ip_off)
50025202Skarels 	    {
50125202Skarels 
50225202Skarels 		/* complete cover */
50325202Skarels 
50425202Skarels 		savq = q->ip_prev;
50525202Skarels 		ip_deq(q);
50625202Skarels 		m_freem(dtom(q));
50725202Skarels 
50825202Skarels 	    }
50925202Skarels 	    else
51025202Skarels 	    {	/* overlap */
51125202Skarels 		if ((i = q->ip_end-ip->ip_off+1)
51225202Skarels 		    < ip->ip_len)
51325202Skarels 		{
51425202Skarels 		    ip->ip_off += i;
51525202Skarels 		    ip->ip_len -= i;
51625202Skarels 		    m_adj(mp, i);
51725202Skarels 		}
51825202Skarels 		else
51925202Skarels 		    ip->ip_len = 0;
52025202Skarels 	    }
52125202Skarels 
52225202Skarels 	    /* new overlaps at beginning of successor frags */
52325202Skarels 
52425202Skarels 	    q = savq->ip_next;
52525202Skarels 	    while ((q != (struct ip *)fp) &&
52625202Skarels 		(ip->ip_len != 0) &&
52725202Skarels 		(q->ip_off <= ip->ip_end))
52825202Skarels 
52925202Skarels 		/* complete cover */
53025202Skarels 
53125202Skarels 		if (q->ip_end <= ip->ip_end)
53225202Skarels 		{
53325202Skarels 		    struct ip *next;
53425202Skarels 
53525202Skarels 		    next = q->ip_next;
53625202Skarels 		    ip_deq(q);
53725202Skarels 		    m_freem(dtom(q));
53825202Skarels 		    q = next;
53925202Skarels 		}
54025202Skarels 		else
54125202Skarels 		{        /* overlap */
54225202Skarels 		    if ((i = ip->ip_end-q->ip_off+1) < ip->ip_len)
54325202Skarels 		    {
54425202Skarels 			ip->ip_len -= i;
54525202Skarels 			ip->ip_end -= i;
54625202Skarels 			m_adj(mp, -i);
54725202Skarels 		    }
54825202Skarels 		    else
54925202Skarels 			ip->ip_len = 0;
55025202Skarels 		    break;
55125202Skarels 		}
55225202Skarels 
55325202Skarels 	    /* enqueue whatever is left of new before successors */
55425202Skarels 
55525202Skarels 	    if (ip->ip_len != 0)
55625202Skarels 	    {
55725202Skarels 		ip_enq(ip, savq);
55825202Skarels 	    }
55925202Skarels 	    else
56025202Skarels 		m_freem(mp);
56125202Skarels 	}
56225202Skarels     }
56325202Skarels 
56425202Skarels     /* check for completed fragment reassembly */
56525202Skarels 
56625202Skarels     if ((i = ip_done(&fp->iqx)) == 0)
56725202Skarels 	return(NULL);
56825202Skarels 
56925202Skarels     ip = fp->iqx.ip_next; /* -> top mbuf */
57025202Skarels     ip->ip_len = i; /* total data length */
57125202Skarels     *fragsize = fp->iq_size;	/* remember for TCP */
57225202Skarels     /* option processing */
57325202Skarels 
57425202Skarels     if ((hlen = ip->ip_hl<<IP_HLSHIFT) > sizeof(struct ip))
57525202Skarels 	ip_stripopt (ip, hlen);
57625202Skarels 
57725202Skarels     ip_mergef(&fp->iqx); /* clean frag chain */
57825202Skarels 
57925202Skarels     /* copy src/dst internet address to header mbuf */
58025202Skarels 
58125202Skarels     ip->ip_src = fp->iqh.ip_src;
58225202Skarels     ip->ip_dst = fp->iqh.ip_dst;
58325202Skarels 
58425202Skarels     ip_freef(fp); /* dequeue header */
58525202Skarels     return(ip);
58625202Skarels }
58725202Skarels 
58825202Skarels /*
58925202Skarels  * Let people control gateway action by patching this:
59025202Skarels  */
59125202Skarels int	ip_forwarding = FALSE;
59225202Skarels 
59325202Skarels /*
59425202Skarels  * Try to forward the packet.  Act like a gateway.
59525202Skarels  */
59625202Skarels ip_forward (fwdinp, ip, mp, hlen)
59725202Skarels struct inpcb	*fwdinp;
59825202Skarels register struct ip	*ip;
59925202Skarels struct mbuf	*mp;
60025202Skarels int hlen;
60125202Skarels {
60225202Skarels     register int		 type, code;
60325202Skarels     register u_short	 len;
60425202Skarels     register struct mbuf	*mcopy;
60525202Skarels     register unsigned		 icmplen;
60625202Skarels     int error;
60725202Skarels 
60825202Skarels     /*
60925202Skarels      * Also copy forwarded packets, just like copy TCP/UDP/RDP...
61025202Skarels      * packets sent to us so that can debug gateway action problems.
61125202Skarels      * It's easy enough for the user-level program to filter these
61225202Skarels      * out.
61325202Skarels      */
61425202Skarels     if (any_rawreaders())
61525202Skarels 	if (mcopy = m_copy(mp, 0, M_COPYALL))
61625202Skarels 	    raw_ip_input (mcopy);
61725202Skarels 
61825202Skarels     if (ip->ip_ttl)
61925202Skarels 	ip->ip_ttl --;
62025202Skarels 
62125202Skarels     len = ntohs(ip->ip_len);
62225202Skarels     icmplen = MIN(len, hlen + ICMP_ERRLEN);
62325202Skarels 
62425202Skarels     if (ip_forwarding && ip->ip_ttl)
62525202Skarels     {
62625202Skarels 	/*
62725202Skarels 	 * Save chunk of ip packet in case there is an error
62825202Skarels 	 */
62925202Skarels 	mcopy = m_copy (mp, 0, (int)icmplen);
63025202Skarels 
63125202Skarels 	/*
63225202Skarels 	 * The packet is not sourced by the local machine, so
63325202Skarels 	 * save ourselves a useless call to ip_route in ip_send().
63425202Skarels 	 * Also, don't want ip_send to work if sending from
63525202Skarels 	 * 8.7.0.2 to 192.1.11.1 via 8.0.0.16, and 8.0.0.16
63625202Skarels 	 * knows about a default gateway on net 8.  This can
63725202Skarels 	 * cause an ENETUNREACH if 192.1.11 is not a network
63825202Skarels 	 * that default gateway knows about.  [8.0.0.16 is on
63925202Skarels 	 * 192.1.11 and ip_route uses default gateway on net 8
64025202Skarels 	 * while rtalloc uses local interface]
64125202Skarels 	 *
64225202Skarels 	 * This route should be found by rtalloc, so let's do
64325202Skarels 	 * it here.
64425202Skarels 	 */
64525202Skarels 	if (fwdinp->inp_route.ro_rt == NULL)
64625202Skarels 	{
64725202Skarels 	    /* Isn't a source routed packet */
64825202Skarels 	    struct rtentry *rt;
64925202Skarels 	    struct sockaddr_in *sin;
65025202Skarels 
65125202Skarels 	    bzero ((caddr_t) fwdinp, sizeof(*fwdinp));
65225202Skarels 	    sin = (struct sockaddr_in *) &fwdinp->inp_route.ro_dst;
65325202Skarels 	    sin->sin_family = AF_INET;
65425202Skarels 	    sin->sin_addr = ip->ip_dst;
65525202Skarels 	    rtalloc (&fwdinp->inp_route);
65625202Skarels 
65725202Skarels 	    /*
65825202Skarels 	     * Check to see if should send ICMP redirect.  Don't
65925202Skarels 	     * send redirect if source routing was used.
66025202Skarels 	     */
66125202Skarels 	    if ((rt = fwdinp->inp_route.ro_rt) != NULL)
66225202Skarels 	    {
66325202Skarels 		sin = (struct sockaddr_in *) &rt->rt_gateway;
66425202Skarels 		if (! (rt->rt_flags & (RTF_GATEWAY|RTF_HOST)))
66525202Skarels 		    send_redirect (ip, ip->ip_dst, ICMP_REDIR_HOST, icmplen);
66625202Skarels 		else if (iptonet(ip->ip_src) == iptonet(sin->sin_addr))
66725202Skarels 		    send_redirect (ip, sin->sin_addr, ICMP_REDIR_NET, icmplen);
66825202Skarels 	    }
66925202Skarels 	}
67025202Skarels 
67125202Skarels 	if (fwdinp->inp_route.ro_rt == NULL)
67225202Skarels 	{
67325202Skarels 	    /* no way to get there from here */
67425202Skarels 	    m_freem(mp);
67525202Skarels 	    type = ICMP_UNRCH;
67625202Skarels 	    code = ICMP_UNRCH_NET;
67725202Skarels 	}
67825202Skarels 	else
67925202Skarels 	{
68025202Skarels 	    error = ip_send (fwdinp, mp, (int)len, TRUE);
68125202Skarels 	    rtfree(fwdinp->inp_route.ro_rt);
68225202Skarels 	    fwdinp->inp_route.ro_rt = NULL;
68325202Skarels 
68425202Skarels 	    if (! error)
68525202Skarels 	    {
68625202Skarels 		ipstat.ip_forwarded ++;
68725202Skarels 		if (mcopy)
68825202Skarels 		    m_freem(mcopy);
68925202Skarels 		return;
69025202Skarels 	    }
69125202Skarels 
69225202Skarels 	    type = ICMP_UNRCH;
69325202Skarels 	    switch (error)
69425202Skarels 	    {
69525202Skarels 	      case ENETUNREACH:
69625202Skarels 	      case ENETDOWN:
69725202Skarels 		code = ICMP_UNRCH_NET;
69825202Skarels 		break;
69925202Skarels 	      case EMSGSIZE:
70025202Skarels 		code = ICMP_UNRCH_FRAG;
70125202Skarels 		break;
70225202Skarels 	      case EHOSTDOWN:
70325202Skarels 	      case EHOSTUNREACH:
70425202Skarels 		code = ICMP_UNRCH_HOST;
70525202Skarels 		break;
70625202Skarels 
70725202Skarels 	      case ENOBUFS:
70825202Skarels 		type = ICMP_SRCQ;
70925202Skarels 		break;
71025202Skarels 
71125202Skarels 	      default:
712*25206Skarels 		log(LOG_INFO, "ip_forward: error %d\n", error);
71325202Skarels 	    }
71425202Skarels 	}
71525202Skarels     }
71625202Skarels     else
71725202Skarels     {
71825202Skarels 	if (ip->ip_ttl == 0)
71925202Skarels 	{
72025202Skarels 	    type = ICMP_TIMEX;
72125202Skarels 	    code = ICMP_TIMEX_XMT;
72225202Skarels 	}
72325202Skarels 	else
72425202Skarels 	{
72525202Skarels 	    type = ICMP_UNRCH;
72625202Skarels 	    code = ICMP_UNRCH_NET;
72725202Skarels 	}
72825202Skarels 	mcopy = mp;
72925202Skarels 	if (fwdinp->inp_route.ro_rt)
73025202Skarels 	{
73125202Skarels 	    /* was source routed by IP option */
73225202Skarels 	    rtfree (fwdinp->inp_route.ro_rt);
73325202Skarels 	    fwdinp->inp_route.ro_rt = NULL;
73425202Skarels 	}
73525202Skarels     }
73625202Skarels 
73725202Skarels     if (mcopy)
73825202Skarels     {
73925202Skarels 	ip = mtod(mcopy, struct ip *);
74025202Skarels 	ic_errmsg (redir_addr(ip), ip->ip_src, type, code, 0, icmplen, (char *) ip);
74125202Skarels #ifdef HMPTRAPS
74225202Skarels 	/* hmp_trap(T_IP_ADDRS, (caddr_t) 0, 0); */
74325202Skarels #else
74425202Skarels 	if (ip_forwarding)
74525202Skarels 	    /*
74625202Skarels 	     * If not acting as a gateway, don't want some one else's
74725202Skarels 	     * misconception to flood our console or logfile.  This error
74825202Skarels 	     * can be found through netstat an ip_drops.
74925202Skarels 	     */
75025202Skarels 	    ip_log(ip, "ip forwarding error");
75125202Skarels 	netlog(mcopy);
75225202Skarels #endif
75325202Skarels     }
75425202Skarels 
75525202Skarels     ipstat.ip_drops++;
75625202Skarels }
75725202Skarels 
75825202Skarels 
75925202Skarels /*
76025202Skarels  * Check to see if fragment reassembly is complete
76125202Skarels  */
ip_done(p)76225202Skarels ip_done(p)
76325202Skarels register struct ip *p;
76425202Skarels {
76525202Skarels     register struct ip *q;
76625202Skarels     register next;
76725202Skarels 
76825202Skarels     q = p->ip_next;
76925202Skarels 
77025202Skarels     if (q->ip_off != 0)
77125202Skarels 	return(0);
77225202Skarels     do
77325202Skarels     {
77425202Skarels 	next = q->ip_end + 1;
77525202Skarels 	q = q->ip_next;
77625202Skarels     }
77725202Skarels     while ((q != p) && (q->ip_off == next));
77825202Skarels 
77925202Skarels     if ((q == p) && !(q->ip_prev->ip_mff))        /* all fragments in */
78025202Skarels 	return(next); /* total data length */
78125202Skarels     else
78225202Skarels 	return(0);
78325202Skarels }
78425202Skarels 
78525202Skarels /*
78625202Skarels  * Merge mbufs of fragments of completed datagram
78725202Skarels  */
ip_mergef(p)78825202Skarels ip_mergef(p)
78925202Skarels register struct ip *p;
79025202Skarels {
79125202Skarels     register struct mbuf *m, *n;
79225202Skarels     register struct ip *q;
79325202Skarels     int dummy;
79425202Skarels 
79525202Skarels     q = p->ip_next; /* -> bottom of reass chain */
79625202Skarels     n = (struct mbuf *)&dummy; /* dummy for init assignment */
79725202Skarels 
79825202Skarels     while (q != p)
79925202Skarels     {        /* through chain */
80025202Skarels 	/*
80125202Skarels 	 * If free mbuf holding q, cannot access q->ip_next in case
80225202Skarels 	 * that mbuf is used by device code for an incoming packet.
80325202Skarels 	 */
80425202Skarels 	register struct ip *next;
80525202Skarels 
80625202Skarels 	next = q->ip_next;
80725202Skarels 	n->m_next = m = dtom(q);
80825202Skarels 	while (m != NULL)
80925202Skarels 	{
81025202Skarels 	    if (m->m_len != 0)
81125202Skarels 	    {
81225202Skarels 		n = m;
81325202Skarels 		m = m->m_next;
81425202Skarels 	    }
81525202Skarels 	    else /* free null mbufs */
81625202Skarels 		n->m_next = m = m_free(m);
81725202Skarels 	}
81825202Skarels 	q = next;
81925202Skarels     }
82025202Skarels }
82125202Skarels 
82225202Skarels /*
82325202Skarels  * Dequeue and free reass.q header
82425202Skarels  */
ip_freef(fp)82525202Skarels ip_freef(fp)
82625202Skarels register struct ipq *fp;
82725202Skarels {
82825202Skarels     if (fp->iq_prev != NULL)
82925202Skarels 	(fp->iq_prev)->iq_next = fp->iq_next;
83025202Skarels     else
83125202Skarels 	ipfrags.n_ip_head = fp->iq_next;
83225202Skarels 
83325202Skarels     if (fp->iq_next != NULL)
83425202Skarels 	(fp->iq_next)->iq_prev = fp->iq_prev;
83525202Skarels     else
83625202Skarels 	ipfrags.n_ip_tail = fp->iq_prev;
83725202Skarels 
83825202Skarels     m_free(dtom(fp));
83925202Skarels }
84025202Skarels 
84125202Skarels ip_stripopt (ip, hlen)
84225202Skarels struct ip	*ip;
84325202Skarels int hlen;
84425202Skarels {
84525202Skarels     int optlen;
84625202Skarels 
84725202Skarels     if ((optlen = (hlen - sizeof(struct ip))) > 0)
84825202Skarels     {
84925202Skarels 	struct mbuf *m;
85025202Skarels 	caddr_t end_of_ip, end_of_opt;
85125202Skarels 	unsigned len;
85225202Skarels 
85325202Skarels 	m = dtom(ip);
85425202Skarels 	end_of_ip = (char *) (ip +1);
85525202Skarels 	end_of_opt = end_of_ip + optlen;
85625202Skarels 	len = m->m_len - hlen;
85725202Skarels 	bcopy (end_of_opt, end_of_ip, len);
85825202Skarels 	m->m_len -= optlen;
85925202Skarels     }
86025202Skarels }
86125202Skarels 
86225202Skarels /*
86325202Skarels  * Process ip options
86425202Skarels  * FALSE -> options were in error, and an icmp message has been sent
86525202Skarels  */
86625202Skarels #define OFF_OLEN	1
86725202Skarels #define OFF_OFFSET	2
86825202Skarels #define MIN_OFF		4	/* since option is a 1, not 0, based array */
86925202Skarels 
87025202Skarels /*
87125202Skarels  * Record route in same form as ip_setopt()
87225202Skarels  */
save_rte(option,dst)87325202Skarels save_rte (option, dst)
87425202Skarels u_char	*option;
87525202Skarels struct in_addr dst;
87625202Skarels {
87725202Skarels     int olen;
87825202Skarels     int off;
87925202Skarels     u_char	*x;
88025202Skarels     struct in_addr *p, *q;
88125202Skarels 
88225202Skarels     if (ip_nhops != 0)
88325202Skarels     {
88425202Skarels 	/* Use both loose and strict source routing? */
885*25206Skarels 	log(LOG_INFO, "ip_nhops %d\n", ip_nhops);
88625202Skarels 	ip_nhops = 0;
88725202Skarels 	return;
88825202Skarels     }
88925202Skarels     olen = option[OFF_OLEN];
89025202Skarels     if (olen > sizeof(ip_hops))
89125202Skarels     {
892*25206Skarels 	log(LOG_INFO, "save_rte: olen %d\n", olen);
89325202Skarels 	return;
89425202Skarels     }
89525202Skarels     off = option[OFF_OFFSET];
89625202Skarels     p = (struct in_addr *) (&option[off - 1]);
89725202Skarels     q = (struct in_addr *) (&option[MIN_OFF -1]);
89825202Skarels 
89925202Skarels     x = (u_char *) ip_hops;
90025202Skarels     x[0] = IP_NOP_OPT;
90125202Skarels     x[1] = option[0];	/* loose/strict source routing */
90225202Skarels     x[2] = (p - q) * sizeof(struct in_addr) + 3;
90325202Skarels     x[3] = MIN_OFF;
90425202Skarels     ip_nhops ++;	/* = 1 (1 long for opt hdr) */
90525202Skarels     p--;	/* p points at first hop for return route */
90625202Skarels 
90725202Skarels     ip_hops[p-q+2] = (*p);	/* save first hop after return route option */
90825202Skarels     p--;	/* it is in what will be ip_hops[ip_nhops]  */
90925202Skarels 
91025202Skarels     /* record return path as an IP source route */
91125202Skarels     while (p >= q)
91225202Skarels     {
91325202Skarels 	ip_hops[ip_nhops] = (*p);
91425202Skarels 	p--;
91525202Skarels 	ip_nhops ++;
91625202Skarels     }
91725202Skarels     /* remember eventual destination is in the option field */
91825202Skarels     ip_hops[ip_nhops] = dst;
91925202Skarels     ip_nhops ++;
92025202Skarels }
92125202Skarels 
ip_opt(ip,hlen,fwdinp)92225202Skarels ip_opt (ip, hlen, fwdinp)
92325202Skarels register struct ip *ip;
92425202Skarels struct inpcb *fwdinp;
92525202Skarels {
92625202Skarels     register u_char	*endopt;
92725202Skarels     register u_char	*option;
92825202Skarels     register int	 olen;
92925202Skarels     register int	 off;
93025202Skarels     int type;
93125202Skarels     int code;
93225202Skarels     struct in_addr nexthop;
93325202Skarels     struct in_ifaddr *ia;
93425202Skarels 
93525202Skarels     endopt = ((u_char *) ip) + hlen;
93625202Skarels     option = (u_char *) (ip +1);
93725202Skarels 
93825202Skarels     while (option < endopt)
93925202Skarels     {
94025202Skarels 	switch (*option)
94125202Skarels 	{
94225202Skarels 	  case IP_END_OPT:
94325202Skarels 	    return (TRUE);
94425202Skarels 
94525202Skarels 	  case IP_NOP_OPT:
94625202Skarels 	    olen = sizeof(u_char);
94725202Skarels 	    break;
94825202Skarels 
94925202Skarels 	  case IP_SEC_OPT:
95025202Skarels 	    olen = option[OFF_OLEN];
95125202Skarels 	    /* so much for security */
95225202Skarels 	    break;
95325202Skarels 
95425202Skarels 	  case IP_LRTE_OPT:
95525202Skarels 	    olen = option[OFF_OLEN];
95625202Skarels 	    off = option[OFF_OFFSET];
95725202Skarels 	    if (off < MIN_OFF)
95825202Skarels 	    {
95925202Skarels 		type = ICMP_PARM;
96025202Skarels 		code = &option[OFF_OFFSET] - ((u_char *) ip);
96125202Skarels 		goto err;
96225202Skarels 	    }
96325202Skarels 	    off--;	/* adjust for use by C */
96425202Skarels 	    if (in_iawithaddr(ip->ip_dst, TRUE) == NULL)
96525202Skarels 		/*
96625202Skarels 		 * With loose routing, may take a few hops
96725202Skarels 		 * to get to current nexthop.
96825202Skarels 		 */
96925202Skarels 		break;
97025202Skarels 
97125202Skarels 	    if (off > (olen - sizeof(struct in_addr)))
97225202Skarels 	    {
97325202Skarels 		/* hints all used up. pkt for us */
97425202Skarels 		save_rte (option, ip->ip_src);
97525202Skarels 		break;
97625202Skarels 	    }
97725202Skarels 
97825202Skarels 	    nexthop = *((struct in_addr *) (option + off));
97925202Skarels 
98025202Skarels 	    /*
98125202Skarels 	     * record outgoing interface
98225202Skarels 	     */
98325202Skarels 	    if (! ip_opt_route(fwdinp, nexthop))
98425202Skarels 	    {
98525202Skarels 		type = ICMP_UNRCH;
98625202Skarels 		/* net? frag? host? */
98725202Skarels 		code = ICMP_UNRCH_SRC;
98825202Skarels 		goto err;
98925202Skarels 	    }
99025202Skarels 	    ip->ip_dst = nexthop;
99125202Skarels 	    option[OFF_OFFSET] += sizeof(struct in_addr);
99225202Skarels 	    if (fwdinp->inp_route.ro_rt == NULL)
99325202Skarels 		/*
99425202Skarels 		 * Destined for ourselves, and we're
99525202Skarels 		 * just going to strip the options off
99625202Skarels 		 */
99725202Skarels 		break;
99825202Skarels 	    *((struct in_addr *) (option + off)) =
99925202Skarels 		IA_INADDR(in_iafromif (fwdinp->inp_route.ro_rt->rt_ifp));
100025202Skarels 	    break;
100125202Skarels 
100225202Skarels 	  case IP_SRTE_OPT:
100325202Skarels 	    olen = option[OFF_OLEN];
100425202Skarels 	    off = option[OFF_OFFSET];
100525202Skarels 	    if (off < MIN_OFF)
100625202Skarels 	    {
100725202Skarels 		type = ICMP_PARM;
100825202Skarels 		code = &option[OFF_OFFSET] - ((u_char *) ip);
100925202Skarels 		goto err;
101025202Skarels 	    }
101125202Skarels 	    off--;	/* adjust for use by C */
101225202Skarels 	    if (in_iawithaddr(ip->ip_dst, TRUE) == NULL)
101325202Skarels 	    {
101425202Skarels 		/* strict path -> someone goofed */
101525202Skarels 		/* should have come in on us for us */
101625202Skarels 		type = ICMP_UNRCH;
101725202Skarels 		code = ICMP_UNRCH_SRC;
101825202Skarels 		goto err;
101925202Skarels 	    }
102025202Skarels 
102125202Skarels 	    if (off > (olen - sizeof(struct in_addr)))
102225202Skarels 	    {
102325202Skarels 		/* hints all used up */
102425202Skarels 		save_rte (option, ip->ip_src);
102525202Skarels 		break;
102625202Skarels 	    }
102725202Skarels 
102825202Skarels 	    nexthop = *((struct in_addr *) (option + off));
102925202Skarels 
103025202Skarels 	    if ((ia = in_iawithnet(nexthop)) == NULL)
103125202Skarels 	    {
103225202Skarels 		/* strict path -> someone goofed
103325202Skarels 		 * we should be directly connected to
103425202Skarels 		 * next hop
103525202Skarels 		 */
103625202Skarels 		type = ICMP_UNRCH;
103725202Skarels 		code = ICMP_UNRCH_SRC;
103825202Skarels 		goto err;
103925202Skarels 	    }
104025202Skarels 	    *((struct in_addr *) (option + off)) = IA_INADDR(ia);
104125202Skarels 
104225202Skarels 	    ip->ip_dst = nexthop;
104325202Skarels 
104425202Skarels 	    option[OFF_OFFSET] += sizeof(struct in_addr);
104525202Skarels 	    break;
104625202Skarels 
104725202Skarels 	  case IP_TIME_OPT:
104825202Skarels 	    olen = option[OFF_OLEN];
104925202Skarels 	    off = option[OFF_OFFSET];
105025202Skarels 	    if (off < MIN_OFF)
105125202Skarels 	    {
105225202Skarels 		type = ICMP_PARM;
105325202Skarels 		code = &option[OFF_OFFSET] - ((u_char *) ip);
105425202Skarels 		goto err;
105525202Skarels 	    }
105625202Skarels 	    off--;	/* adjust for use by C */
105725202Skarels 	    if (off > (olen - sizeof(u_long)))
105825202Skarels 	    {
105925202Skarels 		/* increment overflow count */
106025202Skarels 		if ((option[3] & 0xf0) == 0xf0)
106125202Skarels 		{
106225202Skarels 		    /* overflow overflowed */
106325202Skarels 		    type = ICMP_PARM;
106425202Skarels 		    code = &option[OFF_OLEN] - ((u_char *) ip);
106525202Skarels 		    goto err;
106625202Skarels 		}
106725202Skarels 		option[3] += 0x10;
106825202Skarels 		break;
106925202Skarels 	    }
107025202Skarels 
107125202Skarels 	    if (option[3] & 2)
107225202Skarels 	    {
107325202Skarels 		/* want specific host to stamp */
107425202Skarels 		ia = in_iawithaddr(*((struct in_addr *) (option + off)), FALSE);
107525202Skarels 		if (ia == NULL)
107625202Skarels 		    break;
107725202Skarels 	    }
107825202Skarels 	    else
107925202Skarels 		ia = in_ifaddr;
108025202Skarels 
108125202Skarels 	    if (option[3] & 1)
108225202Skarels 	    {
108325202Skarels 		/* record stamping host */
108425202Skarels 		*((struct in_addr *) (option + off)) = IA_INADDR (ia);
108525202Skarels 		off += sizeof(struct in_addr);
108625202Skarels 		option[OFF_OFFSET] += sizeof(struct in_addr);
108725202Skarels 	    }
108825202Skarels 	    if (off > (olen - sizeof(u_long)))
108925202Skarels 	    {
109025202Skarels 		option[3] += 0x10;
109125202Skarels 		break;
109225202Skarels 	    }
109325202Skarels 	    *((u_long *) (option + off)) = iptime();
109425202Skarels 	    option[OFF_OFFSET] += sizeof(u_long);
109525202Skarels 	    break;
109625202Skarels 
109725202Skarels 	  case IP_STRID_OPT:
109825202Skarels 	    olen = option[OFF_OLEN];
109925202Skarels 	    break;
110025202Skarels 
110125202Skarels 	  case IP_RRTE_OPT:
110225202Skarels 	    olen = option[OFF_OLEN];
110325202Skarels 	    off = option[OFF_OFFSET];
110425202Skarels 	    if (off < MIN_OFF)
110525202Skarels 	    {
110625202Skarels 		type = ICMP_PARM;
110725202Skarels 		code = &option[OFF_OFFSET] - ((u_char *) ip);
110825202Skarels 		goto err;
110925202Skarels 	    }
111025202Skarels 	    off--;	/* adjust for use by C */
111125202Skarels 	    if (off > (olen - sizeof(u_long)))
111225202Skarels 		/* no space left for recording route */
111325202Skarels 		break;
111425202Skarels 
111525202Skarels 	    /* record outgoing interface */
111625202Skarels 	    if (! ip_opt_route(fwdinp, ip->ip_dst))
111725202Skarels 	    {
111825202Skarels 		type = ICMP_UNRCH;
111925202Skarels 		code = ICMP_UNRCH_NET;
112025202Skarels 		goto err;
112125202Skarels 	    }
112225202Skarels 	    option[OFF_OFFSET] += sizeof(struct in_addr);
112325202Skarels 	    if (fwdinp->inp_route.ro_rt == NULL)
112425202Skarels 		/*
112525202Skarels 		 * Destined for us, and we're just
112625202Skarels 		 * going to strip options off
112725202Skarels 		 */
112825202Skarels 		break;
112925202Skarels 	    *((struct in_addr *) (option + off)) =
113025202Skarels 		IA_INADDR(in_iafromif (fwdinp->inp_route.ro_rt->rt_ifp));
113125202Skarels 	    break;
113225202Skarels 	}
113325202Skarels 
113425202Skarels 	option += olen;
113525202Skarels     }
113625202Skarels     return (TRUE);
113725202Skarels 
113825202Skarels err :
113925202Skarels     ic_errmsg (icmp_addr(ip), ip->ip_src,
114025202Skarels 	type, code, option - ((u_char *) ip), hlen, (char *) ip);
114125202Skarels     return (FALSE);
114225202Skarels }
114325202Skarels #undef OFF_OLEN
114425202Skarels #undef OFF_OFFSET
114525202Skarels #undef MIN_OFF
114625202Skarels 
114725202Skarels 
ip_opt_route(fwdinp,dst)114825202Skarels ip_opt_route (fwdinp, dst)
114925202Skarels register struct inpcb *fwdinp;
115025202Skarels struct in_addr dst;
115125202Skarels {
115225202Skarels     register struct sockaddr_in *sin;
115325202Skarels 
115425202Skarels     /* in case they use several options involving routing */
115525202Skarels     if (fwdinp->inp_route.ro_rt)
115625202Skarels 	return (TRUE);
115725202Skarels 
115825202Skarels     bzero ((caddr_t) fwdinp, sizeof(*fwdinp));
115925202Skarels 
116025202Skarels     sin = (struct sockaddr_in *) &fwdinp->inp_route.ro_dst;
116125202Skarels 
116225202Skarels     /* not sure ip_send cares about this stuff ... */
116325202Skarels     sin->sin_family = AF_INET;
116425202Skarels     sin->sin_addr = dst;
116525202Skarels 
116625202Skarels     /* Don't allocate route if not forwarding packet.
116725202Skarels      * This saves us from doing a check in ip_input() to see
116825202Skarels      * if we should do a rtfree() for an uncommon occurrence.
116925202Skarels      */
117025202Skarels 
117125202Skarels     if (in_iawithaddr(dst, TRUE) != NULL)
117225202Skarels 	return (TRUE);
117325202Skarels 
117425202Skarels     rtalloc (&fwdinp->inp_route);
117525202Skarels     return (fwdinp->inp_route.ro_rt != NULL);
117625202Skarels }
117725202Skarels 
117825202Skarels 
117925202Skarels /*
118025202Skarels  * IP fragment reassembly timeout routine.
118125202Skarels  */
ip_timeo()118225202Skarels ip_timeo()
118325202Skarels {
118425202Skarels     register struct ip *p, *q;
118525202Skarels     register struct ipq *fp, *next;
118625202Skarels     register int s;
118725202Skarels 
118825202Skarels     static int timflag;
118925202Skarels 
119025202Skarels     /* check once per sec */
119125202Skarels 
119225202Skarels     if (timflag = !timflag)	/* looks strange, doesn't it? */
119325202Skarels 	return;
119425202Skarels 
119525202Skarels 
119625202Skarels     /* search through reass.q */
119725202Skarels     s = splnet();
119825202Skarels     for (fp = ipfrags.n_ip_head; fp != NULL; fp = next)
119925202Skarels     {
120025202Skarels 	/*
120125202Skarels 	 * If fragment times out, mbufs are freed, and can't
120225202Skarels 	 * use next pointer since mbuf may be grabbed by
120325202Skarels 	 * an interface at splimp
120425202Skarels 	 */
120525202Skarels 	next = fp->iq_next;
120625202Skarels 
120725202Skarels 	if (--(fp->iqx.ip_ttl) == 0)
120825202Skarels 	{  /* time to die */
120925202Skarels 
121025202Skarels 	    q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */
121125202Skarels 	    while (q != (struct ip *)fp)
121225202Skarels 	    {
121325202Skarels 		p = q->ip_next;
121425202Skarels 		/* ### generate timed out in reassembly msg */
121525202Skarels #ifdef HMPTRAPS
121625202Skarels 		/* hmp_trap(T_IP_FDROP, (caddr_t)0,0); */
121725202Skarels #else
121825202Skarels 		m_freem(dtom(q));
121925202Skarels #endif
122025202Skarels 		q = p;
122125202Skarels 	    }
122225202Skarels 	    ip_freef(fp); /* free header */
122325202Skarels 	}
122425202Skarels     }
122525202Skarels     splx(s);
122625202Skarels }
122725202Skarels 
122825202Skarels /*
122925202Skarels  * Called at splimp from uipc_mbuf.c
123025202Skarels  * Network code needs to free up space!  IP fragments dropped.
123125202Skarels  */
ip_drain()123225202Skarels ip_drain()
123325202Skarels {
123425202Skarels     register struct ip *p, *q;
123525202Skarels     register struct ipq *fp;
123625202Skarels 
123725202Skarels     while (fp = ipfrags.n_ip_head)
123825202Skarels     {
123925202Skarels 	q = fp->iqx.ip_next;	/* free mbufs assoc w/chain */
124025202Skarels 	while (q != (struct ip *)fp)
124125202Skarels 	{
124225202Skarels 	    p = q->ip_next;
124325202Skarels 	    m_freem(dtom(q));
124425202Skarels 	    q = p;
124525202Skarels 	}
124625202Skarels 	ip_freef(fp); /* free header */
124725202Skarels     }
124825202Skarels }
124925202Skarels 
125025202Skarels #include "../h/syslog.h"
125125202Skarels 
inet_cksum_err(protoname,ip,was,should_be)125225202Skarels inet_cksum_err (protoname, ip, was, should_be)
125325202Skarels char *protoname;
125425202Skarels struct ip *ip;
125525202Skarels u_long was;
125625202Skarels u_long should_be;
125725202Skarels {
125825202Skarels     union { u_long ul; u_char c[4]; } s, d;
125925202Skarels 
126025202Skarels     s.ul = ip->ip_src.s_addr;
126125202Skarels     d.ul = ip->ip_dst.s_addr;
1262*25206Skarels     log (LOG_INFO,
126325202Skarels 	"%s checksum was 0x%x not 0x%x src %d.%d.%d.%d dst %d.%d.%d.%d\n",
126425202Skarels 	protoname, was, should_be,
126525202Skarels 	s.c[0], s.c[1], s.c[2], s.c[3],
126625202Skarels 	d.c[0], d.c[1], d.c[2], d.c[3]);
126725202Skarels }
126825202Skarels 
126925202Skarels ip_log(ip, emsg)
127025202Skarels struct ip *ip;
127125202Skarels char *emsg;
127225202Skarels {
127325202Skarels     union { u_long ul; u_char c[4]; } s, d;
127425202Skarels 
127525202Skarels     s.ul = ip->ip_src.s_addr;
127625202Skarels     d.ul = ip->ip_dst.s_addr;
1277*25206Skarels     log(LOG_INFO, "%s: src %d.%d.%d.%d dst %d.%d.%d.%d\n",
127825202Skarels 	emsg,
127925202Skarels 	s.c[0], s.c[1], s.c[2], s.c[3],
128025202Skarels 	d.c[0], d.c[1], d.c[2], d.c[3]);
128125202Skarels }
128225202Skarels 
no_route(msg,from,to)128325202Skarels no_route (msg, from, to)
128425202Skarels char	*msg;
128525202Skarels struct in_addr	 from;
128625202Skarels struct in_addr	 to;
128725202Skarels {
128825202Skarels     union { u_long ul; u_char c[4]; } f, t;
128925202Skarels 
129025202Skarels     f.ul = from.s_addr;
129125202Skarels     t.ul = to.s_addr;
1292*25206Skarels     log(LOG_INFO, "%s: no route %d.%d.%d.%d -> %d.%d.%d.%d\n",
129325202Skarels 	msg,
129425202Skarels 	f.c[0], f.c[1], f.c[2], f.c[3],
129525202Skarels 	t.c[0], t.c[1], t.c[2], t.c[3]);
129625202Skarels }
1297