1*25202Skarels #ifdef	RCSIDENT
2*25202Skarels static char rcsident[] = "$Header: ip_input.c,v 1.39 85/07/31 09:31:26 walsh Exp $";
3*25202Skarels #endif
4*25202Skarels 
5*25202Skarels #include "../h/param.h"
6*25202Skarels #include "../h/mbuf.h"
7*25202Skarels #include "../h/socket.h"
8*25202Skarels #include "../h/socketvar.h"
9*25202Skarels #include "../h/errno.h"
10*25202Skarels #include "../h/protosw.h"
11*25202Skarels #include "../h/domain.h"
12*25202Skarels #include "../h/syslog.h"
13*25202Skarels 
14*25202Skarels #include "../net/if.h"
15*25202Skarels #include "../net/route.h"
16*25202Skarels #include "../net/raw_cb.h"
17*25202Skarels 
18*25202Skarels #include "../bbnnet/in.h"
19*25202Skarels #include "../bbnnet/net.h"
20*25202Skarels #include "../bbnnet/in_pcb.h"
21*25202Skarels #include "../bbnnet/in_var.h"
22*25202Skarels #include "../bbnnet/ip.h"
23*25202Skarels #include "../bbnnet/icmp.h"
24*25202Skarels #ifdef	HMP
25*25202Skarels #include "../bbnnet/hmp_traps.h"
26*25202Skarels #endif
27*25202Skarels 
28*25202Skarels #ifdef	RCSIDENT
29*25202Skarels static char rcsiphdr[] = RCSIPHDR;
30*25202Skarels #endif
31*25202Skarels 
32*25202Skarels #define rawreaders(r)	 	((r)->rcb_next != (r))
33*25202Skarels #define any_rawreaders()	rawreaders(&rawcb)
34*25202Skarels 
35*25202Skarels #define FIELD_OFF(fld, type) (((char *) (&(((type *) 0)->fld))) - ((char *) 0))
36*25202Skarels 
37*25202Skarels struct in_stat otherstat;
38*25202Skarels struct ip_stat ipstat;
39*25202Skarels struct {
40*25202Skarels  	struct ipq *n_ip_head;		/* -> top of ip reass. queue */
41*25202Skarels 	struct ipq *n_ip_tail;		/* -> end of ip reass. queue */
42*25202Skarels } ipfrags;
43*25202Skarels 
44*25202Skarels 
45*25202Skarels /*
46*25202Skarels  * The protocol layers above IP assume the IP header and the protocol
47*25202Skarels  * header are contiguous.  However, need to save the options in case
48*25202Skarels  * a connection oriented protocol (RDP/TCP) wants to respond to an
49*25202Skarels  * incoming packet (SYN) over the same route if the packet got here
50*25202Skarels  * using IP source routing.  This allows connection establishment and
51*25202Skarels  * maintenance when the remote end is on a network that is not known
52*25202Skarels  * to our gateways.  Only applicable options are Loose/Strict source
53*25202Skarels  * routing, so rather than saving them in ip_stripopt() and reinterpreting
54*25202Skarels  * them, we'll set up something specific and appropriate here.
55*25202Skarels  */
56*25202Skarels 
57*25202Skarels int nosum = 0;
58*25202Skarels int	ip_nhops = 0;
59*25202Skarels struct in_addr ip_hops[MAX_IPOPTLEN / sizeof(struct in_addr)];
60*25202Skarels 
61*25202Skarels /* use a dispatch table for protocol dispatching */
62*25202Skarels struct ipswitch ipsw[IPPROTO_MAX];
63*25202Skarels 
64*25202Skarels extern struct ip *ip_reass();
65*25202Skarels 
66*25202Skarels 
67*25202Skarels ip_init()
68*25202Skarels {
69*25202Skarels     register struct protosw *pr;
70*25202Skarels     register int i;
71*25202Skarels 
72*25202Skarels     pr = pffindproto(PF_INET, IPPROTO_IP, SOCK_RAW);
73*25202Skarels 
74*25202Skarels     /* build our internal switch table */
75*25202Skarels     for(i=0; i < IPPROTO_MAX; i++)
76*25202Skarels     {
77*25202Skarels 	ipsw[i].ipsw_raw = pr;
78*25202Skarels 	ipsw[i].ipsw_user = 0;
79*25202Skarels 	ipsw[i].ipsw_hlen = sizeof(struct ip);
80*25202Skarels     }
81*25202Skarels 
82*25202Skarels     for(pr = inetdomain.dom_protosw; pr < inetdomain.dom_protoswNPROTOSW; pr++)
83*25202Skarels     {
84*25202Skarels 	if (pr->pr_protocol >= IPPROTO_MAX)
85*25202Skarels 	    panic("ip_init");
86*25202Skarels 
87*25202Skarels 	if (pr->pr_type == SOCK_RAW)
88*25202Skarels 	    ipsw[pr->pr_protocol].ipsw_raw = pr;
89*25202Skarels 	else
90*25202Skarels 	    ipsw[pr->pr_protocol].ipsw_user = pr;
91*25202Skarels     }
92*25202Skarels 
93*25202Skarels     ipintrq.ifq_maxlen = IFQ_MAXLEN;	/* got a better number? */
94*25202Skarels }
95*25202Skarels 
96*25202Skarels /*
97*25202Skarels  * Being global might be a little gross, but we just got the interface pointer
98*25202Skarels  * passed up the week before 4.3 release.
99*25202Skarels  */
100*25202Skarels struct ifnet *inetifp;
101*25202Skarels 
102*25202Skarels /*
103*25202Skarels  * IP network software interrupt service routine.  Dequeue a message from the
104*25202Skarels  * ip input queue, and pass to internal ip input processor (ip_input).
105*25202Skarels  */
106*25202Skarels ipintr()
107*25202Skarels {
108*25202Skarels     extern char *panicstr;
109*25202Skarels     register struct mbuf *m;
110*25202Skarels     register int s;
111*25202Skarels 
112*25202Skarels     /*
113*25202Skarels      * Half-hearted attempt to prevent recursive panics due to network
114*25202Skarels      * bugs since panic calls boot, which lowers spl.  Note that the
115*25202Skarels      * drivers will still store packets in mbufs and that some processing
116*25202Skarels      * (ARP, Chaosnet) that occurs at splimp() will still proceed.  At
117*25202Skarels      * least this should preserve state information for post-mortem.
118*25202Skarels      */
119*25202Skarels     if (panicstr == NULL)
120*25202Skarels     {
121*25202Skarels 	for (;;)
122*25202Skarels 	{
123*25202Skarels 	    /* for 4.3, Berkeley finally changed imp code to queue up messages
124*25202Skarels 	     * for ctlinput path, so don't need to check for them here with our
125*25202Skarels 	     * old queueing mechanism
126*25202Skarels 	     */
127*25202Skarels 
128*25202Skarels 	    s = splimp();
129*25202Skarels 	    IF_DEQUEUEIF (&ipintrq, m, inetifp);
130*25202Skarels 	    splx(s);
131*25202Skarels 	    if (m == NULL)
132*25202Skarels 		return;
133*25202Skarels 
134*25202Skarels 	    ip_input(m);
135*25202Skarels 	}
136*25202Skarels     }
137*25202Skarels }
138*25202Skarels 
139*25202Skarels /*
140*25202Skarels  * IP level input routine
141*25202Skarels  *
142*25202Skarels  * Called from local net level upon recpt of an internet datagram or fragment.
143*25202Skarels  * This routine does fragment reassembly, if necessary, and passes completed
144*25202Skarels  * datagrams to higher level protocol processing routines on the basis of the
145*25202Skarels  * ip header protocol field.  It is passed a pointer to an mbuf chain
146*25202Skarels  * containing the datagram/fragment. The mbuf offset+length are set to point
147*25202Skarels  * at the ip header.
148*25202Skarels  */
149*25202Skarels ip_input(mp)
150*25202Skarels register struct mbuf *mp;
151*25202Skarels {
152*25202Skarels     register struct ip *ip;
153*25202Skarels     register int hlen;
154*25202Skarels     register int i;
155*25202Skarels     register struct mbuf *m;
156*25202Skarels     register struct ipq *fp;
157*25202Skarels     int fragsize = 0;
158*25202Skarels     struct in_ifaddr *ia;
159*25202Skarels     int j;
160*25202Skarels     struct inpcb fwdinp;
161*25202Skarels 
162*25202Skarels     ipstat.ip_total ++;
163*25202Skarels     /*
164*25202Skarels      * make sure dtom() macro works by getting header out of mbufs using
165*25202Skarels      * pages, also make sure header contiguous in first mbuf.
166*25202Skarels      */
167*25202Skarels     if ((mp->m_off > MMAXOFF) || (mp->m_len < sizeof(struct ip)))
168*25202Skarels     {
169*25202Skarels 	/*
170*25202Skarels 	 * Might as well avoid doing m_pullup twice.
171*25202Skarels 	 * Common case is using cluster for large chunk of data.
172*25202Skarels 	 */
173*25202Skarels 	if (mp->m_len < FIELD_OFF(ip_p, struct ip) + sizeof(ip->ip_p))
174*25202Skarels 	    i = sizeof(struct ip);
175*25202Skarels 	else
176*25202Skarels 	{
177*25202Skarels 	    ip = mtod(mp, struct ip *);
178*25202Skarels 	    i = ipsw[ip->ip_p].ipsw_hlen;
179*25202Skarels 	}
180*25202Skarels 
181*25202Skarels 	if ((mp = m_pullup(mp, i)) == NULL)
182*25202Skarels 	{
183*25202Skarels 	    ipstat.ip_tooshort ++;
184*25202Skarels 	    return;
185*25202Skarels 	}
186*25202Skarels     }
187*25202Skarels 
188*25202Skarels     ip = mtod(mp, struct ip *);
189*25202Skarels 
190*25202Skarels     /*
191*25202Skarels      * make sure header does not overflow mbuf  (is contiguous)
192*25202Skarels      */
193*25202Skarels     hlen = ip->ip_hl << IP_HLSHIFT;
194*25202Skarels     if (hlen > mp->m_len)
195*25202Skarels     {
196*25202Skarels 	if ((mp = m_pullup(mp, hlen)) == NULL)
197*25202Skarels 	{
198*25202Skarels 	    ip_log(ip, "ip header overflow");
199*25202Skarels #ifdef HMPTRAPS
200*25202Skarels 	    /* hmp_trap(T_IP_OVFLO, (caddr_t)0,0); */
201*25202Skarels #else
202*25202Skarels 	    /* netlog(mp); no longer have mbuf list */
203*25202Skarels #endif
204*25202Skarels 	    return;
205*25202Skarels 	}
206*25202Skarels 	ip = mtod(mp, struct ip *);
207*25202Skarels     }
208*25202Skarels 
209*25202Skarels     /*
210*25202Skarels      * Adjust msg length to remove any driver padding.  Make sure that
211*25202Skarels      * message length matches ip length.
212*25202Skarels      */
213*25202Skarels     for (i = 0, m = mp; m->m_next != NULL; m = m->m_next)
214*25202Skarels 	i += m->m_len;
215*25202Skarels     i -= ntohs((u_short)ip->ip_len) - m->m_len;
216*25202Skarels     if (i != 0)
217*25202Skarels     {
218*25202Skarels 	if (i > (int)m->m_len)
219*25202Skarels 	    m_adj(mp, -i);
220*25202Skarels 	else if (i < 0)
221*25202Skarels 	{
222*25202Skarels 	    ip_log(ip, "truncated ip packet");
223*25202Skarels #ifdef HMPTRAPS
224*25202Skarels 	    /* hmp_trap(T_IP_TRUNC, (caddr_t)0, 0); */
225*25202Skarels #else
226*25202Skarels 	    netlog(mp);
227*25202Skarels #endif
228*25202Skarels 	    return;
229*25202Skarels 	}
230*25202Skarels 	else
231*25202Skarels 	    m->m_len -= i;
232*25202Skarels     }
233*25202Skarels 
234*25202Skarels     i = (u_short)ip->ip_sum;
235*25202Skarels     ip->ip_sum = 0;
236*25202Skarels 
237*25202Skarels     /* used to do inline cksum here via sed */
238*25202Skarels     if (i != (j = (u_short)in_cksum(dtom(ip), hlen)))
239*25202Skarels     {
240*25202Skarels 	ipstat.ip_badsum++;
241*25202Skarels 	if (!nosum)
242*25202Skarels 	{
243*25202Skarels #ifdef HMPTRAPS
244*25202Skarels 	    /* hmp_trap(T_IP_CKSUM, (caddr_t)0,0); */
245*25202Skarels #endif
246*25202Skarels 	    inet_cksum_err ("ip", ip, (u_long) i, (u_long) j);
247*25202Skarels 
248*25202Skarels 	    ip->ip_sum = i;
249*25202Skarels 	    ic_errmsg (icmp_addr(ip), ip->ip_src,
250*25202Skarels 		ICMP_PARM, 0, FIELD_OFF(ip_sum, struct ip),
251*25202Skarels 		hlen + ICMP_ERRLEN, (char *) ip);
252*25202Skarels 
253*25202Skarels 	    netlog(mp);
254*25202Skarels 	    return;
255*25202Skarels 	}
256*25202Skarels     }
257*25202Skarels 
258*25202Skarels     /*
259*25202Skarels      * Make sure this packet is addressed to us before we put fields
260*25202Skarels      * in host order and do reassembly (fragments may reach destination
261*25202Skarels      * by separate routes.)
262*25202Skarels      * Remember that IP source routing option can change ip_dst, so have
263*25202Skarels      * to do option processing for all incoming packets with options.
264*25202Skarels      * Even if the packet turns out to be for us and we strip them.
265*25202Skarels      */
266*25202Skarels     fwdinp.inp_route.ro_rt = NULL; /* in case fwd, but no options */
267*25202Skarels     ip_nhops = 0;	/* for source routed TCP/RDP... connections */
268*25202Skarels     if (hlen > sizeof(struct ip))
269*25202Skarels 	/*
270*25202Skarels 	 * Any route allocated by ip_opt() 1. will be used by
271*25202Skarels 	 * ip_forward(), and 2. will only be needed by ip_forward()
272*25202Skarels 	 */
273*25202Skarels 	if (! ip_opt (ip, hlen, &fwdinp))
274*25202Skarels 	{
275*25202Skarels 	    ip_log (ip, "ip option error");
276*25202Skarels 	    netlog (mp);
277*25202Skarels 	    return;
278*25202Skarels 	}
279*25202Skarels 
280*25202Skarels     /*
281*25202Skarels      * if packet is not for us then forward
282*25202Skarels      */
283*25202Skarels     if ((ia = in_iawithaddr(ip->ip_dst, TRUE)) == NULL)
284*25202Skarels     {
285*25202Skarels 	ip_forward (&fwdinp, ip, mp, hlen);
286*25202Skarels 	return;
287*25202Skarels     }
288*25202Skarels 
289*25202Skarels     ip->ip_len = ntohs((u_short)ip->ip_len);
290*25202Skarels     if ((int)(ip->ip_len -= hlen) < 0)
291*25202Skarels     {     /* length of data */
292*25202Skarels 	ip_log(ip, "ip header length error");
293*25202Skarels #ifdef HMPTRAPS
294*25202Skarels 	/* hmp_trap(T_IP_HLEN, (caddr_t)0,0); */
295*25202Skarels #else
296*25202Skarels 	netlog(mp);
297*25202Skarels #endif
298*25202Skarels 	return;
299*25202Skarels     }
300*25202Skarels     ip->ip_off = ntohs((u_short)ip->ip_off);
301*25202Skarels     ip->ip_mff = ((ip->ip_off & ip_mf) ? TRUE : FALSE);
302*25202Skarels     ip->ip_off <<= IP_OFFSHIFT;
303*25202Skarels 
304*25202Skarels     /* look for chain on reassembly queue with this header */
305*25202Skarels 
306*25202Skarels     for (fp = ipfrags.n_ip_head; (fp != NULL && (
307*25202Skarels 	ip->ip_src.s_addr != fp->iqh.ip_src.s_addr ||
308*25202Skarels 	ip->ip_dst.s_addr != fp->iqh.ip_dst.s_addr ||
309*25202Skarels 	ip->ip_id != fp->iqh.ip_id ||
310*25202Skarels 	ip->ip_p != fp->iqh.ip_p)); fp = fp->iq_next);
311*25202Skarels 
312*25202Skarels     if (!ip->ip_mff && ip->ip_off == 0)
313*25202Skarels     {    /* not fragmented */
314*25202Skarels 
315*25202Skarels 	if (fp != NULL)
316*25202Skarels 	{               /* free existing reass chain */
317*25202Skarels 	    struct ip *q;
318*25202Skarels 	    struct ip *p;
319*25202Skarels 
320*25202Skarels 	    q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */
321*25202Skarels 	    while (q != (struct ip *)fp)
322*25202Skarels 	    {
323*25202Skarels 		p = q->ip_next;
324*25202Skarels 		m_freem(dtom(q));
325*25202Skarels 		q = p;
326*25202Skarels 	    }
327*25202Skarels 	    ip_freef(fp); /* free header */
328*25202Skarels 	}
329*25202Skarels 
330*25202Skarels 	/*
331*25202Skarels 	 * The options aren't of any use to higher level
332*25202Skarels 	 * protocols or of any concern to the user process.
333*25202Skarels 	 */
334*25202Skarels 	if (hlen > sizeof(struct ip))
335*25202Skarels 	    ip_stripopt (ip, hlen);
336*25202Skarels 
337*25202Skarels     }
338*25202Skarels     else
339*25202Skarels     {
340*25202Skarels 	ip = ip_reass(ip, fp, &fragsize);
341*25202Skarels 	if (ip == NULL)
342*25202Skarels 	    return;
343*25202Skarels 	mp = dtom(ip);
344*25202Skarels     }
345*25202Skarels 
346*25202Skarels     /* call next level with completed datagram */
347*25202Skarels 
348*25202Skarels     /* any raw readers?? */
349*25202Skarels     /* if (rawreaders((struct rawcb *)ipsw[ip->ip_p].ipsw_raw->pr_ppcbq)) */
350*25202Skarels     if (any_rawreaders())
351*25202Skarels     {
352*25202Skarels 	otherstat.in_total++;
353*25202Skarels 	if (m = m_copy(mp, 0, M_COPYALL))
354*25202Skarels 	    ipsw[ip->ip_p].ipsw_raw->pr_input(m);
355*25202Skarels     }
356*25202Skarels 
357*25202Skarels     if (ip->ip_p == IPPROTO_TCP)
358*25202Skarels 	/* wish I didn't need this special case for fragsize */
359*25202Skarels 	tcp_input(mp, fragsize);
360*25202Skarels     else if (ipsw[ip->ip_p].ipsw_user != 0)
361*25202Skarels 	/* There's a protocol implementation for these packets */
362*25202Skarels 	ipsw[ip->ip_p].ipsw_user->pr_input(mp);
363*25202Skarels     else if (ip->ip_p == IPPROTO_ICMP)
364*25202Skarels 	/*
365*25202Skarels 	 * Since don't want user to get a non-raw ICMP socket, did not make
366*25202Skarels 	 * an entry in the protocol jump table; also wanted to be able to
367*25202Skarels 	 * make raw ICMP socket.
368*25202Skarels 	 */
369*25202Skarels 	icmp (mp);
370*25202Skarels     else
371*25202Skarels     {
372*25202Skarels 	/*
373*25202Skarels 	 * Don't bother everyone on the net, and remember some other
374*25202Skarels 	 * host may support the protocol.
375*25202Skarels 	 */
376*25202Skarels 	if ((!in_broadcast(ip->ip_src)) && (!in_broadcast(ip->ip_dst)))
377*25202Skarels 	    ic_errmsg (icmp_addr(ip), ip->ip_src,
378*25202Skarels 		ICMP_UNRCH, ICMP_UNRCH_PR, FIELD_OFF(ip_p, struct ip),
379*25202Skarels 		sizeof(struct ip) + ICMP_ERRLEN, (char *) ip);
380*25202Skarels 
381*25202Skarels 	/* get rid of the packet */
382*25202Skarels 	ipstat.ip_drops++;
383*25202Skarels 	m_freem(mp);
384*25202Skarels     }
385*25202Skarels }
386*25202Skarels 
387*25202Skarels 
388*25202Skarels /*
389*25202Skarels  * We've received an IP fragment.  Try to perform IP reassembly.
390*25202Skarels  */
391*25202Skarels struct ip *ip_reass(ip, fp, fragsize)
392*25202Skarels register struct ip *ip;
393*25202Skarels register struct ipq *fp;
394*25202Skarels int *fragsize;
395*25202Skarels {
396*25202Skarels     register struct ip *q, *savq;
397*25202Skarels     register struct mbuf *mp;
398*25202Skarels     int hlen;
399*25202Skarels     int i;
400*25202Skarels 
401*25202Skarels     mp = dtom(ip);
402*25202Skarels     hlen = ip->ip_hl << IP_HLSHIFT;
403*25202Skarels 
404*25202Skarels     if (ip->ip_off != 0)
405*25202Skarels     {
406*25202Skarels 	/*
407*25202Skarels 	 * Only the first fragment retains the IP header.
408*25202Skarels 	 */
409*25202Skarels 	mp->m_off += hlen;
410*25202Skarels 	mp->m_len -= hlen;
411*25202Skarels     }
412*25202Skarels 
413*25202Skarels     if (fp == NULL)
414*25202Skarels     {
415*25202Skarels 	/*
416*25202Skarels 	 * This is the first fragment of the IP datagram that we've
417*25202Skarels 	 * received.  Set up reassembly q header.
418*25202Skarels 	 */
419*25202Skarels 	struct mbuf *m;
420*25202Skarels 
421*25202Skarels 	if ((m = m_get(M_WAIT, MT_FTABLE)) == NULL)
422*25202Skarels 	{
423*25202Skarels 	    m_freem(mp);
424*25202Skarels 	    return(NULL);
425*25202Skarels 	}
426*25202Skarels 
427*25202Skarels 	fp = mtod(m, struct ipq *);
428*25202Skarels 	fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp;
429*25202Skarels 	bcopy((caddr_t)ip, (caddr_t)&fp->iqh, sizeof(struct ip));
430*25202Skarels 	fp->iqx.ip_ttl	= MAXTTL;
431*25202Skarels 	fp->iq_size	= 0;
432*25202Skarels 	/*
433*25202Skarels 	 * and enter this into the list of fragmented IP datagrams
434*25202Skarels 	 */
435*25202Skarels 	fp->iq_next	= NULL;
436*25202Skarels 	fp->iq_prev	= ipfrags.n_ip_tail;
437*25202Skarels 	if (ipfrags.n_ip_head != NULL)
438*25202Skarels 	    ipfrags.n_ip_tail->iq_next = fp;
439*25202Skarels 	else
440*25202Skarels 	    ipfrags.n_ip_head = fp;
441*25202Skarels 	ipfrags.n_ip_tail = fp;
442*25202Skarels     }
443*25202Skarels 
444*25202Skarels     /*
445*25202Skarels      * Merge fragment into reass.q
446*25202Skarels      *
447*25202Skarels      * Algorithm:   Match  start  and  end  bytes  of new
448*25202Skarels      * fragment  with  fragments  on  the  queue.   If no
449*25202Skarels      * overlaps  are  found,  add  new  frag. to the queue.
450*25202Skarels      * Otherwise, adjust start and end of new frag.  so  no
451*25202Skarels      * overlap   and   add  remainder  to  queue.   If  any
452*25202Skarels      * fragments are completely covered by the new one,  or
453*25202Skarels      * if  the  new  one is completely duplicated, free the
454*25202Skarels      * fragments.
455*25202Skarels      */
456*25202Skarels     q = fp->iqx.ip_next; /* -> top of reass. chain */
457*25202Skarels     ip->ip_end = ip->ip_off + ip->ip_len - 1;
458*25202Skarels 
459*25202Skarels     /* record the maximum fragment size for TCP */
460*25202Skarels 
461*25202Skarels     fp->iq_size = MAX(ip->ip_len, fp->iq_size);
462*25202Skarels 
463*25202Skarels     /* skip frags which new doesn't overlap at end */
464*25202Skarels 
465*25202Skarels     while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end))
466*25202Skarels 	q = q->ip_next;
467*25202Skarels 
468*25202Skarels     if (q == (struct ip *)fp)
469*25202Skarels     {	/* frag at end of chain */
470*25202Skarels 	ip_enq(ip, fp->iqx.ip_prev);
471*25202Skarels     }
472*25202Skarels     else
473*25202Skarels     {			/* frag doesn't overlap any */
474*25202Skarels 	if (ip->ip_end < q->ip_off)
475*25202Skarels 	{
476*25202Skarels 	    ip_enq(ip, q->ip_prev);
477*25202Skarels 
478*25202Skarels 	    /* new overlaps beginning of next frag only */
479*25202Skarels 
480*25202Skarels 	}
481*25202Skarels 	else if (ip->ip_end < q->ip_end)
482*25202Skarels 	{
483*25202Skarels 	    if ((i = ip->ip_end-q->ip_off+1) < ip->ip_len)
484*25202Skarels 	    {
485*25202Skarels 		ip->ip_len -= i;
486*25202Skarels 		ip->ip_end -= i;
487*25202Skarels 		m_adj(mp, -i);
488*25202Skarels 		ip_enq(ip, q->ip_prev);
489*25202Skarels 	    }
490*25202Skarels 	    else
491*25202Skarels 		m_freem(mp);
492*25202Skarels 
493*25202Skarels 	    /* new overlaps end of previous frag */
494*25202Skarels 
495*25202Skarels 	}
496*25202Skarels 	else
497*25202Skarels 	{
498*25202Skarels 	    savq = q;
499*25202Skarels 	    if (ip->ip_off <= q->ip_off)
500*25202Skarels 	    {
501*25202Skarels 
502*25202Skarels 		/* complete cover */
503*25202Skarels 
504*25202Skarels 		savq = q->ip_prev;
505*25202Skarels 		ip_deq(q);
506*25202Skarels 		m_freem(dtom(q));
507*25202Skarels 
508*25202Skarels 	    }
509*25202Skarels 	    else
510*25202Skarels 	    {	/* overlap */
511*25202Skarels 		if ((i = q->ip_end-ip->ip_off+1)
512*25202Skarels 		    < ip->ip_len)
513*25202Skarels 		{
514*25202Skarels 		    ip->ip_off += i;
515*25202Skarels 		    ip->ip_len -= i;
516*25202Skarels 		    m_adj(mp, i);
517*25202Skarels 		}
518*25202Skarels 		else
519*25202Skarels 		    ip->ip_len = 0;
520*25202Skarels 	    }
521*25202Skarels 
522*25202Skarels 	    /* new overlaps at beginning of successor frags */
523*25202Skarels 
524*25202Skarels 	    q = savq->ip_next;
525*25202Skarels 	    while ((q != (struct ip *)fp) &&
526*25202Skarels 		(ip->ip_len != 0) &&
527*25202Skarels 		(q->ip_off <= ip->ip_end))
528*25202Skarels 
529*25202Skarels 		/* complete cover */
530*25202Skarels 
531*25202Skarels 		if (q->ip_end <= ip->ip_end)
532*25202Skarels 		{
533*25202Skarels 		    struct ip *next;
534*25202Skarels 
535*25202Skarels 		    next = q->ip_next;
536*25202Skarels 		    ip_deq(q);
537*25202Skarels 		    m_freem(dtom(q));
538*25202Skarels 		    q = next;
539*25202Skarels 		}
540*25202Skarels 		else
541*25202Skarels 		{        /* overlap */
542*25202Skarels 		    if ((i = ip->ip_end-q->ip_off+1) < ip->ip_len)
543*25202Skarels 		    {
544*25202Skarels 			ip->ip_len -= i;
545*25202Skarels 			ip->ip_end -= i;
546*25202Skarels 			m_adj(mp, -i);
547*25202Skarels 		    }
548*25202Skarels 		    else
549*25202Skarels 			ip->ip_len = 0;
550*25202Skarels 		    break;
551*25202Skarels 		}
552*25202Skarels 
553*25202Skarels 	    /* enqueue whatever is left of new before successors */
554*25202Skarels 
555*25202Skarels 	    if (ip->ip_len != 0)
556*25202Skarels 	    {
557*25202Skarels 		ip_enq(ip, savq);
558*25202Skarels 	    }
559*25202Skarels 	    else
560*25202Skarels 		m_freem(mp);
561*25202Skarels 	}
562*25202Skarels     }
563*25202Skarels 
564*25202Skarels     /* check for completed fragment reassembly */
565*25202Skarels 
566*25202Skarels     if ((i = ip_done(&fp->iqx)) == 0)
567*25202Skarels 	return(NULL);
568*25202Skarels 
569*25202Skarels     ip = fp->iqx.ip_next; /* -> top mbuf */
570*25202Skarels     ip->ip_len = i; /* total data length */
571*25202Skarels     *fragsize = fp->iq_size;	/* remember for TCP */
572*25202Skarels     /* option processing */
573*25202Skarels 
574*25202Skarels     if ((hlen = ip->ip_hl<<IP_HLSHIFT) > sizeof(struct ip))
575*25202Skarels 	ip_stripopt (ip, hlen);
576*25202Skarels 
577*25202Skarels     ip_mergef(&fp->iqx); /* clean frag chain */
578*25202Skarels 
579*25202Skarels     /* copy src/dst internet address to header mbuf */
580*25202Skarels 
581*25202Skarels     ip->ip_src = fp->iqh.ip_src;
582*25202Skarels     ip->ip_dst = fp->iqh.ip_dst;
583*25202Skarels 
584*25202Skarels     ip_freef(fp); /* dequeue header */
585*25202Skarels     return(ip);
586*25202Skarels }
587*25202Skarels 
588*25202Skarels /*
589*25202Skarels  * Let people control gateway action by patching this:
590*25202Skarels  */
591*25202Skarels int	ip_forwarding = FALSE;
592*25202Skarels 
593*25202Skarels /*
594*25202Skarels  * Try to forward the packet.  Act like a gateway.
595*25202Skarels  */
596*25202Skarels ip_forward (fwdinp, ip, mp, hlen)
597*25202Skarels struct inpcb	*fwdinp;
598*25202Skarels register struct ip	*ip;
599*25202Skarels struct mbuf	*mp;
600*25202Skarels int hlen;
601*25202Skarels {
602*25202Skarels     register int		 type, code;
603*25202Skarels     register u_short	 len;
604*25202Skarels     register struct mbuf	*mcopy;
605*25202Skarels     register unsigned		 icmplen;
606*25202Skarels     int error;
607*25202Skarels 
608*25202Skarels     /*
609*25202Skarels      * Also copy forwarded packets, just like copy TCP/UDP/RDP...
610*25202Skarels      * packets sent to us so that can debug gateway action problems.
611*25202Skarels      * It's easy enough for the user-level program to filter these
612*25202Skarels      * out.
613*25202Skarels      */
614*25202Skarels     if (any_rawreaders())
615*25202Skarels 	if (mcopy = m_copy(mp, 0, M_COPYALL))
616*25202Skarels 	    raw_ip_input (mcopy);
617*25202Skarels 
618*25202Skarels     if (ip->ip_ttl)
619*25202Skarels 	ip->ip_ttl --;
620*25202Skarels 
621*25202Skarels     len = ntohs(ip->ip_len);
622*25202Skarels     icmplen = MIN(len, hlen + ICMP_ERRLEN);
623*25202Skarels 
624*25202Skarels     if (ip_forwarding && ip->ip_ttl)
625*25202Skarels     {
626*25202Skarels 	/*
627*25202Skarels 	 * Save chunk of ip packet in case there is an error
628*25202Skarels 	 */
629*25202Skarels 	mcopy = m_copy (mp, 0, (int)icmplen);
630*25202Skarels 
631*25202Skarels 	/*
632*25202Skarels 	 * The packet is not sourced by the local machine, so
633*25202Skarels 	 * save ourselves a useless call to ip_route in ip_send().
634*25202Skarels 	 * Also, don't want ip_send to work if sending from
635*25202Skarels 	 * 8.7.0.2 to 192.1.11.1 via 8.0.0.16, and 8.0.0.16
636*25202Skarels 	 * knows about a default gateway on net 8.  This can
637*25202Skarels 	 * cause an ENETUNREACH if 192.1.11 is not a network
638*25202Skarels 	 * that default gateway knows about.  [8.0.0.16 is on
639*25202Skarels 	 * 192.1.11 and ip_route uses default gateway on net 8
640*25202Skarels 	 * while rtalloc uses local interface]
641*25202Skarels 	 *
642*25202Skarels 	 * This route should be found by rtalloc, so let's do
643*25202Skarels 	 * it here.
644*25202Skarels 	 */
645*25202Skarels 	if (fwdinp->inp_route.ro_rt == NULL)
646*25202Skarels 	{
647*25202Skarels 	    /* Isn't a source routed packet */
648*25202Skarels 	    struct rtentry *rt;
649*25202Skarels 	    struct sockaddr_in *sin;
650*25202Skarels 
651*25202Skarels 	    bzero ((caddr_t) fwdinp, sizeof(*fwdinp));
652*25202Skarels 	    sin = (struct sockaddr_in *) &fwdinp->inp_route.ro_dst;
653*25202Skarels 	    sin->sin_family = AF_INET;
654*25202Skarels 	    sin->sin_addr = ip->ip_dst;
655*25202Skarels 	    rtalloc (&fwdinp->inp_route);
656*25202Skarels 
657*25202Skarels 	    /*
658*25202Skarels 	     * Check to see if should send ICMP redirect.  Don't
659*25202Skarels 	     * send redirect if source routing was used.
660*25202Skarels 	     */
661*25202Skarels 	    if ((rt = fwdinp->inp_route.ro_rt) != NULL)
662*25202Skarels 	    {
663*25202Skarels 		sin = (struct sockaddr_in *) &rt->rt_gateway;
664*25202Skarels 		if (! (rt->rt_flags & (RTF_GATEWAY|RTF_HOST)))
665*25202Skarels 		    send_redirect (ip, ip->ip_dst, ICMP_REDIR_HOST, icmplen);
666*25202Skarels 		else if (iptonet(ip->ip_src) == iptonet(sin->sin_addr))
667*25202Skarels 		    send_redirect (ip, sin->sin_addr, ICMP_REDIR_NET, icmplen);
668*25202Skarels 	    }
669*25202Skarels 	}
670*25202Skarels 
671*25202Skarels 	if (fwdinp->inp_route.ro_rt == NULL)
672*25202Skarels 	{
673*25202Skarels 	    /* no way to get there from here */
674*25202Skarels 	    m_freem(mp);
675*25202Skarels 	    type = ICMP_UNRCH;
676*25202Skarels 	    code = ICMP_UNRCH_NET;
677*25202Skarels 	}
678*25202Skarels 	else
679*25202Skarels 	{
680*25202Skarels 	    error = ip_send (fwdinp, mp, (int)len, TRUE);
681*25202Skarels 	    rtfree(fwdinp->inp_route.ro_rt);
682*25202Skarels 	    fwdinp->inp_route.ro_rt = NULL;
683*25202Skarels 
684*25202Skarels 	    if (! error)
685*25202Skarels 	    {
686*25202Skarels 		ipstat.ip_forwarded ++;
687*25202Skarels 		if (mcopy)
688*25202Skarels 		    m_freem(mcopy);
689*25202Skarels 		return;
690*25202Skarels 	    }
691*25202Skarels 
692*25202Skarels 	    type = ICMP_UNRCH;
693*25202Skarels 	    switch (error)
694*25202Skarels 	    {
695*25202Skarels 	      case ENETUNREACH:
696*25202Skarels 	      case ENETDOWN:
697*25202Skarels 		code = ICMP_UNRCH_NET;
698*25202Skarels 		break;
699*25202Skarels 	      case EMSGSIZE:
700*25202Skarels 		code = ICMP_UNRCH_FRAG;
701*25202Skarels 		break;
702*25202Skarels 	      case EHOSTDOWN:
703*25202Skarels 	      case EHOSTUNREACH:
704*25202Skarels 		code = ICMP_UNRCH_HOST;
705*25202Skarels 		break;
706*25202Skarels 
707*25202Skarels 	      case ENOBUFS:
708*25202Skarels 		type = ICMP_SRCQ;
709*25202Skarels 		break;
710*25202Skarels 
711*25202Skarels 	      default:
712*25202Skarels 		log(KERN_RECOV, "ip_forward: error %d\n", error);
713*25202Skarels 	    }
714*25202Skarels 	}
715*25202Skarels     }
716*25202Skarels     else
717*25202Skarels     {
718*25202Skarels 	if (ip->ip_ttl == 0)
719*25202Skarels 	{
720*25202Skarels 	    type = ICMP_TIMEX;
721*25202Skarels 	    code = ICMP_TIMEX_XMT;
722*25202Skarels 	}
723*25202Skarels 	else
724*25202Skarels 	{
725*25202Skarels 	    type = ICMP_UNRCH;
726*25202Skarels 	    code = ICMP_UNRCH_NET;
727*25202Skarels 	}
728*25202Skarels 	mcopy = mp;
729*25202Skarels 	if (fwdinp->inp_route.ro_rt)
730*25202Skarels 	{
731*25202Skarels 	    /* was source routed by IP option */
732*25202Skarels 	    rtfree (fwdinp->inp_route.ro_rt);
733*25202Skarels 	    fwdinp->inp_route.ro_rt = NULL;
734*25202Skarels 	}
735*25202Skarels     }
736*25202Skarels 
737*25202Skarels     if (mcopy)
738*25202Skarels     {
739*25202Skarels 	ip = mtod(mcopy, struct ip *);
740*25202Skarels 	ic_errmsg (redir_addr(ip), ip->ip_src, type, code, 0, icmplen, (char *) ip);
741*25202Skarels #ifdef HMPTRAPS
742*25202Skarels 	/* hmp_trap(T_IP_ADDRS, (caddr_t) 0, 0); */
743*25202Skarels #else
744*25202Skarels 	if (ip_forwarding)
745*25202Skarels 	    /*
746*25202Skarels 	     * If not acting as a gateway, don't want some one else's
747*25202Skarels 	     * misconception to flood our console or logfile.  This error
748*25202Skarels 	     * can be found through netstat an ip_drops.
749*25202Skarels 	     */
750*25202Skarels 	    ip_log(ip, "ip forwarding error");
751*25202Skarels 	netlog(mcopy);
752*25202Skarels #endif
753*25202Skarels     }
754*25202Skarels 
755*25202Skarels     ipstat.ip_drops++;
756*25202Skarels }
757*25202Skarels 
758*25202Skarels 
759*25202Skarels /*
760*25202Skarels  * Check to see if fragment reassembly is complete
761*25202Skarels  */
762*25202Skarels ip_done(p)
763*25202Skarels register struct ip *p;
764*25202Skarels {
765*25202Skarels     register struct ip *q;
766*25202Skarels     register next;
767*25202Skarels 
768*25202Skarels     q = p->ip_next;
769*25202Skarels 
770*25202Skarels     if (q->ip_off != 0)
771*25202Skarels 	return(0);
772*25202Skarels     do
773*25202Skarels     {
774*25202Skarels 	next = q->ip_end + 1;
775*25202Skarels 	q = q->ip_next;
776*25202Skarels     }
777*25202Skarels     while ((q != p) && (q->ip_off == next));
778*25202Skarels 
779*25202Skarels     if ((q == p) && !(q->ip_prev->ip_mff))        /* all fragments in */
780*25202Skarels 	return(next); /* total data length */
781*25202Skarels     else
782*25202Skarels 	return(0);
783*25202Skarels }
784*25202Skarels 
785*25202Skarels /*
786*25202Skarels  * Merge mbufs of fragments of completed datagram
787*25202Skarels  */
788*25202Skarels ip_mergef(p)
789*25202Skarels register struct ip *p;
790*25202Skarels {
791*25202Skarels     register struct mbuf *m, *n;
792*25202Skarels     register struct ip *q;
793*25202Skarels     int dummy;
794*25202Skarels 
795*25202Skarels     q = p->ip_next; /* -> bottom of reass chain */
796*25202Skarels     n = (struct mbuf *)&dummy; /* dummy for init assignment */
797*25202Skarels 
798*25202Skarels     while (q != p)
799*25202Skarels     {        /* through chain */
800*25202Skarels 	/*
801*25202Skarels 	 * If free mbuf holding q, cannot access q->ip_next in case
802*25202Skarels 	 * that mbuf is used by device code for an incoming packet.
803*25202Skarels 	 */
804*25202Skarels 	register struct ip *next;
805*25202Skarels 
806*25202Skarels 	next = q->ip_next;
807*25202Skarels 	n->m_next = m = dtom(q);
808*25202Skarels 	while (m != NULL)
809*25202Skarels 	{
810*25202Skarels 	    if (m->m_len != 0)
811*25202Skarels 	    {
812*25202Skarels 		n = m;
813*25202Skarels 		m = m->m_next;
814*25202Skarels 	    }
815*25202Skarels 	    else /* free null mbufs */
816*25202Skarels 		n->m_next = m = m_free(m);
817*25202Skarels 	}
818*25202Skarels 	q = next;
819*25202Skarels     }
820*25202Skarels }
821*25202Skarels 
822*25202Skarels /*
823*25202Skarels  * Dequeue and free reass.q header
824*25202Skarels  */
825*25202Skarels ip_freef(fp)
826*25202Skarels register struct ipq *fp;
827*25202Skarels {
828*25202Skarels     if (fp->iq_prev != NULL)
829*25202Skarels 	(fp->iq_prev)->iq_next = fp->iq_next;
830*25202Skarels     else
831*25202Skarels 	ipfrags.n_ip_head = fp->iq_next;
832*25202Skarels 
833*25202Skarels     if (fp->iq_next != NULL)
834*25202Skarels 	(fp->iq_next)->iq_prev = fp->iq_prev;
835*25202Skarels     else
836*25202Skarels 	ipfrags.n_ip_tail = fp->iq_prev;
837*25202Skarels 
838*25202Skarels     m_free(dtom(fp));
839*25202Skarels }
840*25202Skarels 
841*25202Skarels ip_stripopt (ip, hlen)
842*25202Skarels struct ip	*ip;
843*25202Skarels int hlen;
844*25202Skarels {
845*25202Skarels     int optlen;
846*25202Skarels 
847*25202Skarels     if ((optlen = (hlen - sizeof(struct ip))) > 0)
848*25202Skarels     {
849*25202Skarels 	struct mbuf *m;
850*25202Skarels 	caddr_t end_of_ip, end_of_opt;
851*25202Skarels 	unsigned len;
852*25202Skarels 
853*25202Skarels 	m = dtom(ip);
854*25202Skarels 	end_of_ip = (char *) (ip +1);
855*25202Skarels 	end_of_opt = end_of_ip + optlen;
856*25202Skarels 	len = m->m_len - hlen;
857*25202Skarels 	bcopy (end_of_opt, end_of_ip, len);
858*25202Skarels 	m->m_len -= optlen;
859*25202Skarels     }
860*25202Skarels }
861*25202Skarels 
862*25202Skarels /*
863*25202Skarels  * Process ip options
864*25202Skarels  * FALSE -> options were in error, and an icmp message has been sent
865*25202Skarels  */
866*25202Skarels #define OFF_OLEN	1
867*25202Skarels #define OFF_OFFSET	2
868*25202Skarels #define MIN_OFF		4	/* since option is a 1, not 0, based array */
869*25202Skarels 
870*25202Skarels /*
871*25202Skarels  * Record route in same form as ip_setopt()
872*25202Skarels  */
873*25202Skarels save_rte (option, dst)
874*25202Skarels u_char	*option;
875*25202Skarels struct in_addr dst;
876*25202Skarels {
877*25202Skarels     int olen;
878*25202Skarels     int off;
879*25202Skarels     u_char	*x;
880*25202Skarels     struct in_addr *p, *q;
881*25202Skarels 
882*25202Skarels     if (ip_nhops != 0)
883*25202Skarels     {
884*25202Skarels 	/* Use both loose and strict source routing? */
885*25202Skarels 	log(KERN_RECOV, "ip_nhops %d\n", ip_nhops);
886*25202Skarels 	ip_nhops = 0;
887*25202Skarels 	return;
888*25202Skarels     }
889*25202Skarels     olen = option[OFF_OLEN];
890*25202Skarels     if (olen > sizeof(ip_hops))
891*25202Skarels     {
892*25202Skarels 	log(KERN_RECOV, "save_rte: olen %d\n", olen);
893*25202Skarels 	return;
894*25202Skarels     }
895*25202Skarels     off = option[OFF_OFFSET];
896*25202Skarels     p = (struct in_addr *) (&option[off - 1]);
897*25202Skarels     q = (struct in_addr *) (&option[MIN_OFF -1]);
898*25202Skarels 
899*25202Skarels     x = (u_char *) ip_hops;
900*25202Skarels     x[0] = IP_NOP_OPT;
901*25202Skarels     x[1] = option[0];	/* loose/strict source routing */
902*25202Skarels     x[2] = (p - q) * sizeof(struct in_addr) + 3;
903*25202Skarels     x[3] = MIN_OFF;
904*25202Skarels     ip_nhops ++;	/* = 1 (1 long for opt hdr) */
905*25202Skarels     p--;	/* p points at first hop for return route */
906*25202Skarels 
907*25202Skarels     ip_hops[p-q+2] = (*p);	/* save first hop after return route option */
908*25202Skarels     p--;	/* it is in what will be ip_hops[ip_nhops]  */
909*25202Skarels 
910*25202Skarels     /* record return path as an IP source route */
911*25202Skarels     while (p >= q)
912*25202Skarels     {
913*25202Skarels 	ip_hops[ip_nhops] = (*p);
914*25202Skarels 	p--;
915*25202Skarels 	ip_nhops ++;
916*25202Skarels     }
917*25202Skarels     /* remember eventual destination is in the option field */
918*25202Skarels     ip_hops[ip_nhops] = dst;
919*25202Skarels     ip_nhops ++;
920*25202Skarels }
921*25202Skarels 
922*25202Skarels ip_opt (ip, hlen, fwdinp)
923*25202Skarels register struct ip *ip;
924*25202Skarels struct inpcb *fwdinp;
925*25202Skarels {
926*25202Skarels     register u_char	*endopt;
927*25202Skarels     register u_char	*option;
928*25202Skarels     register int	 olen;
929*25202Skarels     register int	 off;
930*25202Skarels     int type;
931*25202Skarels     int code;
932*25202Skarels     struct in_addr nexthop;
933*25202Skarels     struct in_ifaddr *ia;
934*25202Skarels 
935*25202Skarels     endopt = ((u_char *) ip) + hlen;
936*25202Skarels     option = (u_char *) (ip +1);
937*25202Skarels 
938*25202Skarels     while (option < endopt)
939*25202Skarels     {
940*25202Skarels 	switch (*option)
941*25202Skarels 	{
942*25202Skarels 	  case IP_END_OPT:
943*25202Skarels 	    return (TRUE);
944*25202Skarels 
945*25202Skarels 	  case IP_NOP_OPT:
946*25202Skarels 	    olen = sizeof(u_char);
947*25202Skarels 	    break;
948*25202Skarels 
949*25202Skarels 	  case IP_SEC_OPT:
950*25202Skarels 	    olen = option[OFF_OLEN];
951*25202Skarels 	    /* so much for security */
952*25202Skarels 	    break;
953*25202Skarels 
954*25202Skarels 	  case IP_LRTE_OPT:
955*25202Skarels 	    olen = option[OFF_OLEN];
956*25202Skarels 	    off = option[OFF_OFFSET];
957*25202Skarels 	    if (off < MIN_OFF)
958*25202Skarels 	    {
959*25202Skarels 		type = ICMP_PARM;
960*25202Skarels 		code = &option[OFF_OFFSET] - ((u_char *) ip);
961*25202Skarels 		goto err;
962*25202Skarels 	    }
963*25202Skarels 	    off--;	/* adjust for use by C */
964*25202Skarels 	    if (in_iawithaddr(ip->ip_dst, TRUE) == NULL)
965*25202Skarels 		/*
966*25202Skarels 		 * With loose routing, may take a few hops
967*25202Skarels 		 * to get to current nexthop.
968*25202Skarels 		 */
969*25202Skarels 		break;
970*25202Skarels 
971*25202Skarels 	    if (off > (olen - sizeof(struct in_addr)))
972*25202Skarels 	    {
973*25202Skarels 		/* hints all used up. pkt for us */
974*25202Skarels 		save_rte (option, ip->ip_src);
975*25202Skarels 		break;
976*25202Skarels 	    }
977*25202Skarels 
978*25202Skarels 	    nexthop = *((struct in_addr *) (option + off));
979*25202Skarels 
980*25202Skarels 	    /*
981*25202Skarels 	     * record outgoing interface
982*25202Skarels 	     */
983*25202Skarels 	    if (! ip_opt_route(fwdinp, nexthop))
984*25202Skarels 	    {
985*25202Skarels 		type = ICMP_UNRCH;
986*25202Skarels 		/* net? frag? host? */
987*25202Skarels 		code = ICMP_UNRCH_SRC;
988*25202Skarels 		goto err;
989*25202Skarels 	    }
990*25202Skarels 	    ip->ip_dst = nexthop;
991*25202Skarels 	    option[OFF_OFFSET] += sizeof(struct in_addr);
992*25202Skarels 	    if (fwdinp->inp_route.ro_rt == NULL)
993*25202Skarels 		/*
994*25202Skarels 		 * Destined for ourselves, and we're
995*25202Skarels 		 * just going to strip the options off
996*25202Skarels 		 */
997*25202Skarels 		break;
998*25202Skarels 	    *((struct in_addr *) (option + off)) =
999*25202Skarels 		IA_INADDR(in_iafromif (fwdinp->inp_route.ro_rt->rt_ifp));
1000*25202Skarels 	    break;
1001*25202Skarels 
1002*25202Skarels 	  case IP_SRTE_OPT:
1003*25202Skarels 	    olen = option[OFF_OLEN];
1004*25202Skarels 	    off = option[OFF_OFFSET];
1005*25202Skarels 	    if (off < MIN_OFF)
1006*25202Skarels 	    {
1007*25202Skarels 		type = ICMP_PARM;
1008*25202Skarels 		code = &option[OFF_OFFSET] - ((u_char *) ip);
1009*25202Skarels 		goto err;
1010*25202Skarels 	    }
1011*25202Skarels 	    off--;	/* adjust for use by C */
1012*25202Skarels 	    if (in_iawithaddr(ip->ip_dst, TRUE) == NULL)
1013*25202Skarels 	    {
1014*25202Skarels 		/* strict path -> someone goofed */
1015*25202Skarels 		/* should have come in on us for us */
1016*25202Skarels 		type = ICMP_UNRCH;
1017*25202Skarels 		code = ICMP_UNRCH_SRC;
1018*25202Skarels 		goto err;
1019*25202Skarels 	    }
1020*25202Skarels 
1021*25202Skarels 	    if (off > (olen - sizeof(struct in_addr)))
1022*25202Skarels 	    {
1023*25202Skarels 		/* hints all used up */
1024*25202Skarels 		save_rte (option, ip->ip_src);
1025*25202Skarels 		break;
1026*25202Skarels 	    }
1027*25202Skarels 
1028*25202Skarels 	    nexthop = *((struct in_addr *) (option + off));
1029*25202Skarels 
1030*25202Skarels 	    if ((ia = in_iawithnet(nexthop)) == NULL)
1031*25202Skarels 	    {
1032*25202Skarels 		/* strict path -> someone goofed
1033*25202Skarels 		 * we should be directly connected to
1034*25202Skarels 		 * next hop
1035*25202Skarels 		 */
1036*25202Skarels 		type = ICMP_UNRCH;
1037*25202Skarels 		code = ICMP_UNRCH_SRC;
1038*25202Skarels 		goto err;
1039*25202Skarels 	    }
1040*25202Skarels 	    *((struct in_addr *) (option + off)) = IA_INADDR(ia);
1041*25202Skarels 
1042*25202Skarels 	    ip->ip_dst = nexthop;
1043*25202Skarels 
1044*25202Skarels 	    option[OFF_OFFSET] += sizeof(struct in_addr);
1045*25202Skarels 	    break;
1046*25202Skarels 
1047*25202Skarels 	  case IP_TIME_OPT:
1048*25202Skarels 	    olen = option[OFF_OLEN];
1049*25202Skarels 	    off = option[OFF_OFFSET];
1050*25202Skarels 	    if (off < MIN_OFF)
1051*25202Skarels 	    {
1052*25202Skarels 		type = ICMP_PARM;
1053*25202Skarels 		code = &option[OFF_OFFSET] - ((u_char *) ip);
1054*25202Skarels 		goto err;
1055*25202Skarels 	    }
1056*25202Skarels 	    off--;	/* adjust for use by C */
1057*25202Skarels 	    if (off > (olen - sizeof(u_long)))
1058*25202Skarels 	    {
1059*25202Skarels 		/* increment overflow count */
1060*25202Skarels 		if ((option[3] & 0xf0) == 0xf0)
1061*25202Skarels 		{
1062*25202Skarels 		    /* overflow overflowed */
1063*25202Skarels 		    type = ICMP_PARM;
1064*25202Skarels 		    code = &option[OFF_OLEN] - ((u_char *) ip);
1065*25202Skarels 		    goto err;
1066*25202Skarels 		}
1067*25202Skarels 		option[3] += 0x10;
1068*25202Skarels 		break;
1069*25202Skarels 	    }
1070*25202Skarels 
1071*25202Skarels 	    if (option[3] & 2)
1072*25202Skarels 	    {
1073*25202Skarels 		/* want specific host to stamp */
1074*25202Skarels 		ia = in_iawithaddr(*((struct in_addr *) (option + off)), FALSE);
1075*25202Skarels 		if (ia == NULL)
1076*25202Skarels 		    break;
1077*25202Skarels 	    }
1078*25202Skarels 	    else
1079*25202Skarels 		ia = in_ifaddr;
1080*25202Skarels 
1081*25202Skarels 	    if (option[3] & 1)
1082*25202Skarels 	    {
1083*25202Skarels 		/* record stamping host */
1084*25202Skarels 		*((struct in_addr *) (option + off)) = IA_INADDR (ia);
1085*25202Skarels 		off += sizeof(struct in_addr);
1086*25202Skarels 		option[OFF_OFFSET] += sizeof(struct in_addr);
1087*25202Skarels 	    }
1088*25202Skarels 	    if (off > (olen - sizeof(u_long)))
1089*25202Skarels 	    {
1090*25202Skarels 		option[3] += 0x10;
1091*25202Skarels 		break;
1092*25202Skarels 	    }
1093*25202Skarels 	    *((u_long *) (option + off)) = iptime();
1094*25202Skarels 	    option[OFF_OFFSET] += sizeof(u_long);
1095*25202Skarels 	    break;
1096*25202Skarels 
1097*25202Skarels 	  case IP_STRID_OPT:
1098*25202Skarels 	    olen = option[OFF_OLEN];
1099*25202Skarels 	    break;
1100*25202Skarels 
1101*25202Skarels 	  case IP_RRTE_OPT:
1102*25202Skarels 	    olen = option[OFF_OLEN];
1103*25202Skarels 	    off = option[OFF_OFFSET];
1104*25202Skarels 	    if (off < MIN_OFF)
1105*25202Skarels 	    {
1106*25202Skarels 		type = ICMP_PARM;
1107*25202Skarels 		code = &option[OFF_OFFSET] - ((u_char *) ip);
1108*25202Skarels 		goto err;
1109*25202Skarels 	    }
1110*25202Skarels 	    off--;	/* adjust for use by C */
1111*25202Skarels 	    if (off > (olen - sizeof(u_long)))
1112*25202Skarels 		/* no space left for recording route */
1113*25202Skarels 		break;
1114*25202Skarels 
1115*25202Skarels 	    /* record outgoing interface */
1116*25202Skarels 	    if (! ip_opt_route(fwdinp, ip->ip_dst))
1117*25202Skarels 	    {
1118*25202Skarels 		type = ICMP_UNRCH;
1119*25202Skarels 		code = ICMP_UNRCH_NET;
1120*25202Skarels 		goto err;
1121*25202Skarels 	    }
1122*25202Skarels 	    option[OFF_OFFSET] += sizeof(struct in_addr);
1123*25202Skarels 	    if (fwdinp->inp_route.ro_rt == NULL)
1124*25202Skarels 		/*
1125*25202Skarels 		 * Destined for us, and we're just
1126*25202Skarels 		 * going to strip options off
1127*25202Skarels 		 */
1128*25202Skarels 		break;
1129*25202Skarels 	    *((struct in_addr *) (option + off)) =
1130*25202Skarels 		IA_INADDR(in_iafromif (fwdinp->inp_route.ro_rt->rt_ifp));
1131*25202Skarels 	    break;
1132*25202Skarels 	}
1133*25202Skarels 
1134*25202Skarels 	option += olen;
1135*25202Skarels     }
1136*25202Skarels     return (TRUE);
1137*25202Skarels 
1138*25202Skarels err :
1139*25202Skarels     ic_errmsg (icmp_addr(ip), ip->ip_src,
1140*25202Skarels 	type, code, option - ((u_char *) ip), hlen, (char *) ip);
1141*25202Skarels     return (FALSE);
1142*25202Skarels }
1143*25202Skarels #undef OFF_OLEN
1144*25202Skarels #undef OFF_OFFSET
1145*25202Skarels #undef MIN_OFF
1146*25202Skarels 
1147*25202Skarels 
1148*25202Skarels ip_opt_route (fwdinp, dst)
1149*25202Skarels register struct inpcb *fwdinp;
1150*25202Skarels struct in_addr dst;
1151*25202Skarels {
1152*25202Skarels     register struct sockaddr_in *sin;
1153*25202Skarels 
1154*25202Skarels     /* in case they use several options involving routing */
1155*25202Skarels     if (fwdinp->inp_route.ro_rt)
1156*25202Skarels 	return (TRUE);
1157*25202Skarels 
1158*25202Skarels     bzero ((caddr_t) fwdinp, sizeof(*fwdinp));
1159*25202Skarels 
1160*25202Skarels     sin = (struct sockaddr_in *) &fwdinp->inp_route.ro_dst;
1161*25202Skarels 
1162*25202Skarels     /* not sure ip_send cares about this stuff ... */
1163*25202Skarels     sin->sin_family = AF_INET;
1164*25202Skarels     sin->sin_addr = dst;
1165*25202Skarels 
1166*25202Skarels     /* Don't allocate route if not forwarding packet.
1167*25202Skarels      * This saves us from doing a check in ip_input() to see
1168*25202Skarels      * if we should do a rtfree() for an uncommon occurrence.
1169*25202Skarels      */
1170*25202Skarels 
1171*25202Skarels     if (in_iawithaddr(dst, TRUE) != NULL)
1172*25202Skarels 	return (TRUE);
1173*25202Skarels 
1174*25202Skarels     rtalloc (&fwdinp->inp_route);
1175*25202Skarels     return (fwdinp->inp_route.ro_rt != NULL);
1176*25202Skarels }
1177*25202Skarels 
1178*25202Skarels 
1179*25202Skarels /*
1180*25202Skarels  * IP fragment reassembly timeout routine.
1181*25202Skarels  */
1182*25202Skarels ip_timeo()
1183*25202Skarels {
1184*25202Skarels     register struct ip *p, *q;
1185*25202Skarels     register struct ipq *fp, *next;
1186*25202Skarels     register int s;
1187*25202Skarels 
1188*25202Skarels     static int timflag;
1189*25202Skarels 
1190*25202Skarels     /* check once per sec */
1191*25202Skarels 
1192*25202Skarels     if (timflag = !timflag)	/* looks strange, doesn't it? */
1193*25202Skarels 	return;
1194*25202Skarels 
1195*25202Skarels 
1196*25202Skarels     /* search through reass.q */
1197*25202Skarels     s = splnet();
1198*25202Skarels     for (fp = ipfrags.n_ip_head; fp != NULL; fp = next)
1199*25202Skarels     {
1200*25202Skarels 	/*
1201*25202Skarels 	 * If fragment times out, mbufs are freed, and can't
1202*25202Skarels 	 * use next pointer since mbuf may be grabbed by
1203*25202Skarels 	 * an interface at splimp
1204*25202Skarels 	 */
1205*25202Skarels 	next = fp->iq_next;
1206*25202Skarels 
1207*25202Skarels 	if (--(fp->iqx.ip_ttl) == 0)
1208*25202Skarels 	{  /* time to die */
1209*25202Skarels 
1210*25202Skarels 	    q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */
1211*25202Skarels 	    while (q != (struct ip *)fp)
1212*25202Skarels 	    {
1213*25202Skarels 		p = q->ip_next;
1214*25202Skarels 		/* ### generate timed out in reassembly msg */
1215*25202Skarels #ifdef HMPTRAPS
1216*25202Skarels 		/* hmp_trap(T_IP_FDROP, (caddr_t)0,0); */
1217*25202Skarels #else
1218*25202Skarels 		m_freem(dtom(q));
1219*25202Skarels #endif
1220*25202Skarels 		q = p;
1221*25202Skarels 	    }
1222*25202Skarels 	    ip_freef(fp); /* free header */
1223*25202Skarels 	}
1224*25202Skarels     }
1225*25202Skarels     splx(s);
1226*25202Skarels }
1227*25202Skarels 
1228*25202Skarels /*
1229*25202Skarels  * Called at splimp from uipc_mbuf.c
1230*25202Skarels  * Network code needs to free up space!  IP fragments dropped.
1231*25202Skarels  */
1232*25202Skarels ip_drain()
1233*25202Skarels {
1234*25202Skarels     register struct ip *p, *q;
1235*25202Skarels     register struct ipq *fp;
1236*25202Skarels 
1237*25202Skarels     while (fp = ipfrags.n_ip_head)
1238*25202Skarels     {
1239*25202Skarels 	q = fp->iqx.ip_next;	/* free mbufs assoc w/chain */
1240*25202Skarels 	while (q != (struct ip *)fp)
1241*25202Skarels 	{
1242*25202Skarels 	    p = q->ip_next;
1243*25202Skarels 	    m_freem(dtom(q));
1244*25202Skarels 	    q = p;
1245*25202Skarels 	}
1246*25202Skarels 	ip_freef(fp); /* free header */
1247*25202Skarels     }
1248*25202Skarels }
1249*25202Skarels 
1250*25202Skarels #include "../h/syslog.h"
1251*25202Skarels 
1252*25202Skarels inet_cksum_err (protoname, ip, was, should_be)
1253*25202Skarels char *protoname;
1254*25202Skarels struct ip *ip;
1255*25202Skarels u_long was;
1256*25202Skarels u_long should_be;
1257*25202Skarels {
1258*25202Skarels     union { u_long ul; u_char c[4]; } s, d;
1259*25202Skarels 
1260*25202Skarels     s.ul = ip->ip_src.s_addr;
1261*25202Skarels     d.ul = ip->ip_dst.s_addr;
1262*25202Skarels     log (KERN_RECOV,
1263*25202Skarels 	"%s checksum was 0x%x not 0x%x src %d.%d.%d.%d dst %d.%d.%d.%d\n",
1264*25202Skarels 	protoname, was, should_be,
1265*25202Skarels 	s.c[0], s.c[1], s.c[2], s.c[3],
1266*25202Skarels 	d.c[0], d.c[1], d.c[2], d.c[3]);
1267*25202Skarels }
1268*25202Skarels 
1269*25202Skarels ip_log(ip, emsg)
1270*25202Skarels struct ip *ip;
1271*25202Skarels char *emsg;
1272*25202Skarels {
1273*25202Skarels     union { u_long ul; u_char c[4]; } s, d;
1274*25202Skarels 
1275*25202Skarels     s.ul = ip->ip_src.s_addr;
1276*25202Skarels     d.ul = ip->ip_dst.s_addr;
1277*25202Skarels     log(KERN_RECOV, "%s: src %d.%d.%d.%d dst %d.%d.%d.%d\n",
1278*25202Skarels 	emsg,
1279*25202Skarels 	s.c[0], s.c[1], s.c[2], s.c[3],
1280*25202Skarels 	d.c[0], d.c[1], d.c[2], d.c[3]);
1281*25202Skarels }
1282*25202Skarels 
1283*25202Skarels no_route (msg, from, to)
1284*25202Skarels char	*msg;
1285*25202Skarels struct in_addr	 from;
1286*25202Skarels struct in_addr	 to;
1287*25202Skarels {
1288*25202Skarels     union { u_long ul; u_char c[4]; } f, t;
1289*25202Skarels 
1290*25202Skarels     f.ul = from.s_addr;
1291*25202Skarels     t.ul = to.s_addr;
1292*25202Skarels     log(KERN_RECOV, "%s: no route %d.%d.%d.%d -> %d.%d.%d.%d\n",
1293*25202Skarels 	msg,
1294*25202Skarels 	f.c[0], f.c[1], f.c[2], f.c[3],
1295*25202Skarels 	t.c[0], t.c[1], t.c[2], t.c[3]);
1296*25202Skarels }
1297