xref: /csrg-svn/sys/netinet/ip_input.c (revision 4495)
1*4495Swnj /* ip_input.c 1.1 81/10/14 */
2*4495Swnj #include "../h/param.h"
3*4495Swnj #include "../bbnnet/net.h"
4*4495Swnj #include "../bbnnet/tcp.h"
5*4495Swnj #include "../bbnnet/ip.h"
6*4495Swnj #include "../bbnnet/ucb.h"
7*4495Swnj 
8*4495Swnj /*****************************************************************************
9*4495Swnj *                                                                            *
10*4495Swnj *         ip level input routine: called from 1822 level upon receipt        *
11*4495Swnj *         of an internet datagram or fragment.  this routine does            *
12*4495Swnj *         fragment reassembly, if necessary, and passes completed            *
13*4495Swnj *         datagrams to higher level protocol processing routines on          *
14*4495Swnj *         the basis of the ip header protocol field.  it is passed a         *
15*4495Swnj *         pointer to an mbuf chain containing the datagram/fragment.         *
16*4495Swnj *         the mbuf offset/length are set to point at the ip header.          *
17*4495Swnj *                                                                            *
18*4495Swnj *****************************************************************************/
19*4495Swnj 
20*4495Swnj int nosum = 0;
21*4495Swnj 
22*4495Swnj ip_input(mp)
23*4495Swnj struct mbuf *mp;
24*4495Swnj {
25*4495Swnj 	register struct ip *ip, *q;
26*4495Swnj 	register struct ipq *fp;
27*4495Swnj 	register struct mbuf *m;
28*4495Swnj 	register i;
29*4495Swnj 	struct mbuf *n;
30*4495Swnj 	int hlen;
31*4495Swnj 	struct ip *p, *savq;
32*4495Swnj 	struct ipq *ip_findf();
33*4495Swnj 
34*4495Swnj COUNT(IP_INPUT);
35*4495Swnj 	ip = (struct ip *)((int)mp + mp->m_off);        /* ->ip hdr */
36*4495Swnj 
37*4495Swnj 	/* make sure header does not overflow mbuf */
38*4495Swnj 
39*4495Swnj 	if ((hlen = ip->ip_hl << 2) > mp->m_len) {
40*4495Swnj 		printf("ip header overflow\n");
41*4495Swnj 		m_freem(mp);
42*4495Swnj 		return;
43*4495Swnj 	}
44*4495Swnj 
45*4495Swnj 	i = (unsigned short)ip->ip_sum;
46*4495Swnj 	ip->ip_sum = 0;
47*4495Swnj 
48*4495Swnj 	if (i != (unsigned short)cksum(mp, hlen)) {     /* verify checksum */
49*4495Swnj 		netstat.ip_badsum++;
50*4495Swnj 		if (!nosum) {
51*4495Swnj         	  	m_freem(mp);
52*4495Swnj         		return;
53*4495Swnj 		}
54*4495Swnj 	}
55*4495Swnj 
56*4495Swnj 	ip_bswap(ip);                   /* byte-swap header */
57*4495Swnj 
58*4495Swnj 	netcb.n_ip_lock++;      /* lock frag reass.q */
59*4495Swnj 	fp = ip_findf(ip);      /* look for chain on reass.q with this hdr */
60*4495Swnj 
61*4495Swnj 	/* adjust message length to remove any padding */
62*4495Swnj 
63*4495Swnj 	for (i=0, m=mp; m != NULL; m = m->m_next) {
64*4495Swnj 		i += m->m_len;
65*4495Swnj 		n = m;
66*4495Swnj 	}
67*4495Swnj 	i -= ip->ip_len;
68*4495Swnj 
69*4495Swnj 	if (i != 0)
70*4495Swnj         	if (i > (int)n->m_len)
71*4495Swnj         		m_adj(mp, -i);
72*4495Swnj         	else
73*4495Swnj         		n->m_len -= i;
74*4495Swnj 
75*4495Swnj 	ip->ip_len -= hlen;     /* length of data */
76*4495Swnj   	ip->ip_mff = ((ip->ip_off & ip_mf) ? TRUE : FALSE);
77*4495Swnj 	ip->ip_off <<= 3;
78*4495Swnj 	if (!ip->ip_mff && ip->ip_off == 0) {    /* not fragmented */
79*4495Swnj 
80*4495Swnj 		if (fp != NULL) {               /* free existing reass.q chain */
81*4495Swnj 
82*4495Swnj 			q = fp->iqx.ip_next;    /* free mbufs assoc. w/chain */
83*4495Swnj 			while (q != (struct ip *)fp) {
84*4495Swnj 				m_freem(dtom(q));
85*4495Swnj 				q = q->ip_next;
86*4495Swnj 			}
87*4495Swnj 			ip_freef(fp);           /* free header */
88*4495Swnj 		}
89*4495Swnj 		netcb.n_ip_lock = 0;
90*4495Swnj 
91*4495Swnj 		ip_opt(ip, hlen);               /* option processing */
92*4495Swnj 		i = ip->ip_p;
93*4495Swnj 
94*4495Swnj 		/* pass to next level */
95*4495Swnj 
96*4495Swnj 		if (i == TCPROTO)
97*4495Swnj 			tcp_input(mp);
98*4495Swnj 		else
99*4495Swnj 			raw_input(mp, i, UIP);
100*4495Swnj 
101*4495Swnj 	} else {                                /* fragmented */
102*4495Swnj 
103*4495Swnj         	/* -> msg buf beyond ip hdr if not first fragment */
104*4495Swnj 
105*4495Swnj 		if (ip->ip_off != 0) {
106*4495Swnj                 	mp->m_off += hlen;
107*4495Swnj                 	mp->m_len -= hlen;
108*4495Swnj 		}
109*4495Swnj 
110*4495Swnj 		if (fp == NULL) {               /* first fragment of datagram in */
111*4495Swnj 
112*4495Swnj 		/* set up reass.q header: enq it, set up as head of frag
113*4495Swnj 		   chain, set a timer value, and move in ip header */
114*4495Swnj 
115*4495Swnj 			if ((m = m_get(1)) == NULL) {   /* allocate an mbuf */
116*4495Swnj 				m_freem(mp);
117*4495Swnj 				return;
118*4495Swnj 			}
119*4495Swnj 
120*4495Swnj 			fp = (struct ipq *)((int)m + MHEAD);
121*4495Swnj 			fp->iqx.ip_next = fp->iqx.ip_prev = (struct ip *)fp;
122*4495Swnj 			bcopy(ip, &fp->iqh, min(MLEN-28, hlen));
123*4495Swnj 			fp->iqh.ip_ttl = MAXTTL;
124*4495Swnj 			fp->iq_next = NULL;
125*4495Swnj 			fp->iq_prev = netcb.n_ip_tail;
126*4495Swnj 			if (netcb.n_ip_head != NULL)
127*4495Swnj 				netcb.n_ip_tail->iq_next = fp;
128*4495Swnj 			else
129*4495Swnj 				netcb.n_ip_head = fp;
130*4495Swnj 			netcb.n_ip_tail = fp;
131*4495Swnj 		}
132*4495Swnj 
133*4495Swnj                 /***********************************************************
134*4495Swnj                 *                                                          *
135*4495Swnj                 *              merge fragment into reass.q                 *
136*4495Swnj                 *    algorithm:   match  start  and  end  bytes  of new    *
137*4495Swnj                 *    fragment  with  fragments  on  the  queue.   if   no  *
138*4495Swnj                 *    overlaps  are  found,  add  new  frag. to the queue.  *
139*4495Swnj                 *    otherwise, adjust start and end of new frag.  so  no  *
140*4495Swnj                 *    overlap   and   add  remainder  to  queue.   if  any  *
141*4495Swnj                 *    fragments are completely covered by the new one,  or  *
142*4495Swnj                 *    if  the  new  one is completely duplicated, free the  *
143*4495Swnj                 *    fragments.                                            *
144*4495Swnj                 *                                                          *
145*4495Swnj                 ***********************************************************/
146*4495Swnj 
147*4495Swnj 	        q = fp->iqx.ip_next;    /* -> top of reass. chain */
148*4495Swnj 		ip->ip_end = ip->ip_off + ip->ip_len - 1;
149*4495Swnj 
150*4495Swnj 		/* skip frags which new doesn't overlap at end */
151*4495Swnj 
152*4495Swnj 		while ((q != (struct ip *)fp) && (ip->ip_off > q->ip_end))
153*4495Swnj 			q = q->ip_next;
154*4495Swnj 
155*4495Swnj 		if (q == (struct ip *)fp)               /* frag at end of chain */
156*4495Swnj 			ip_enq(ip, fp->iqx.ip_prev);
157*4495Swnj 
158*4495Swnj 		else {
159*4495Swnj 			if (ip->ip_end < q->ip_off)     /* frag doesn't overlap any on chain */
160*4495Swnj 				ip_enq(ip, q->ip_prev);
161*4495Swnj 
162*4495Swnj 			/* new overlaps beginning of next frag only */
163*4495Swnj 
164*4495Swnj 			else if (ip->ip_end < q->ip_end) {
165*4495Swnj 				if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
166*4495Swnj         				ip->ip_len -= i;
167*4495Swnj         				ip->ip_end -= i;
168*4495Swnj 					m_adj(mp, -i);
169*4495Swnj 					ip_enq(ip, q->ip_prev);
170*4495Swnj 				} else
171*4495Swnj 					m_freem(mp);
172*4495Swnj 
173*4495Swnj 			/* new overlaps end of previous frag */
174*4495Swnj 
175*4495Swnj 			} else {
176*4495Swnj 
177*4495Swnj 				savq = q;
178*4495Swnj 				if (ip->ip_off <= q->ip_off) {  /* complete cover */
179*4495Swnj 					savq = q->ip_prev;
180*4495Swnj 					ip_deq(q);
181*4495Swnj 					m_freem(dtom(q));
182*4495Swnj 
183*4495Swnj 				} else {                        /* overlap */
184*4495Swnj 					if ((i = q->ip_end - ip->ip_off + 1) < ip->ip_len) {
185*4495Swnj         					ip->ip_off += i;
186*4495Swnj         					ip->ip_len -= i;
187*4495Swnj         					m_adj(mp, i);
188*4495Swnj 					} else
189*4495Swnj 						ip->ip_len = 0;
190*4495Swnj 				}
191*4495Swnj 
192*4495Swnj 			/* new overlaps at beginning of successor frags */
193*4495Swnj 
194*4495Swnj 				q = savq->ip_next;
195*4495Swnj 				while ((q != (struct ip *)fp) && (ip->ip_len != 0) &&
196*4495Swnj 					(q->ip_off < ip->ip_end))
197*4495Swnj 
198*4495Swnj 					/* complete cover */
199*4495Swnj 
200*4495Swnj 					if (q->ip_end <= ip->ip_end) {
201*4495Swnj 						p = q->ip_next;
202*4495Swnj 						ip_deq(q);
203*4495Swnj 						m_freem(dtom(q));
204*4495Swnj 						q = p;
205*4495Swnj 
206*4495Swnj 					} else {        /* overlap */
207*4495Swnj 
208*4495Swnj 						if ((i = ip->ip_end - q->ip_off + 1) < ip->ip_len) {
209*4495Swnj         						ip->ip_len -= i;
210*4495Swnj         						ip->ip_end -= i;
211*4495Swnj         						m_adj(mp, -i);
212*4495Swnj 						} else
213*4495Swnj 							ip->ip_len = 0;
214*4495Swnj 						break;
215*4495Swnj 					}
216*4495Swnj 
217*4495Swnj 			/* enqueue whatever is left of new before successors */
218*4495Swnj 
219*4495Swnj 				if (ip->ip_len != 0)
220*4495Swnj 					ip_enq(ip, savq);
221*4495Swnj 				else
222*4495Swnj 					m_freem(mp);
223*4495Swnj 			}
224*4495Swnj 		}
225*4495Swnj 
226*4495Swnj 		/* check for completed fragment reassembly */
227*4495Swnj 
228*4495Swnj 		if ((i = ip_done(fp)) > 0) {
229*4495Swnj 
230*4495Swnj 			p = fp->iqx.ip_next;            /* -> top mbuf */
231*4495Swnj 			m = dtom(p);
232*4495Swnj 			p->ip_len = i;                  /* total data length */
233*4495Swnj 			ip_opt(p, p->ip_hl << 2);       /* option processing */
234*4495Swnj 			ip_mergef(fp);                  /* cleanup frag chain */
235*4495Swnj 
236*4495Swnj 			/* copy src/dst internet address to header mbuf */
237*4495Swnj 
238*4495Swnj 			bcopy(&fp->iqh.ip_src, &p->ip_src, 2*sizeof(struct socket));
239*4495Swnj 			ip_freef(fp);                   /* dequeue header */
240*4495Swnj 			netcb.n_ip_lock = 0;
241*4495Swnj 
242*4495Swnj 			/* call next level with completed datagram */
243*4495Swnj 
244*4495Swnj 			i = p->ip_p;
245*4495Swnj 			if (i == TCPROTO)
246*4495Swnj 				tcp_input(m);
247*4495Swnj         		else
248*4495Swnj 				raw_input(m, i, UIP);
249*4495Swnj 		} else
250*4495Swnj 			netcb.n_ip_lock = 0;
251*4495Swnj 	}
252*4495Swnj }
253*4495Swnj 
254*4495Swnj 
255*4495Swnj ip_done(p)      /* check to see if fragment reassembly is complete */
256*4495Swnj register struct ip *p;
257*4495Swnj {
258*4495Swnj 	register struct ip *q;
259*4495Swnj 	register next;
260*4495Swnj 
261*4495Swnj COUNT(IP_DONE);
262*4495Swnj 	q = p->ip_next;
263*4495Swnj 
264*4495Swnj 	if (q->ip_off != 0)
265*4495Swnj 		return(0);
266*4495Swnj 	do {
267*4495Swnj 		next = q->ip_end + 1;
268*4495Swnj 		q = q->ip_next;
269*4495Swnj 	} while ((q != p) && (q->ip_off == next));
270*4495Swnj 
271*4495Swnj 	if ((q == p) && !(q->ip_prev->ip_mff))        /* all fragments in */
272*4495Swnj 		return(next);                         /* total data length */
273*4495Swnj 	else
274*4495Swnj 		return(0);
275*4495Swnj }
276*4495Swnj 
277*4495Swnj ip_mergef(p)    /* merge mbufs of fragments of completed datagram */
278*4495Swnj register struct ip *p;
279*4495Swnj {
280*4495Swnj 	register struct mbuf *m, *n;
281*4495Swnj 	register struct ip *q;
282*4495Swnj 	int dummy;
283*4495Swnj 
284*4495Swnj COUNT(IP_MERGEF);
285*4495Swnj 	q = p->ip_next;                         /* -> bottom of reass chain */
286*4495Swnj 	n = (struct mbuf *)&dummy;              /* dummy for init assignment */
287*4495Swnj 
288*4495Swnj 	while (q != p) {        /* through chain */
289*4495Swnj 
290*4495Swnj 	        n->m_next = m = dtom(q);
291*4495Swnj 		while (m != NULL)
292*4495Swnj 			if (m->m_len != 0) {
293*4495Swnj 				n = m;
294*4495Swnj 				m = m->m_next;
295*4495Swnj 			} else                  /* free null mbufs */
296*4495Swnj 				n->m_next = m = m_free(m);
297*4495Swnj 		q = q->ip_next;
298*4495Swnj 	}
299*4495Swnj }
300*4495Swnj 
301*4495Swnj 
302*4495Swnj ip_freef(fp)	        /* deq and free reass.q header */
303*4495Swnj register struct ipq *fp;
304*4495Swnj {
305*4495Swnj COUNT(IP_FREEF);
306*4495Swnj 	if (fp->iq_prev != NULL)
307*4495Swnj 		(fp->iq_prev)->iq_next = fp->iq_next;
308*4495Swnj 	else
309*4495Swnj 		netcb.n_ip_head = fp->iq_next;
310*4495Swnj 	if (fp->iq_next != NULL)
311*4495Swnj 		(fp->iq_next)->iq_prev = fp->iq_prev;
312*4495Swnj 	else
313*4495Swnj 		netcb.n_ip_tail = fp->iq_prev;
314*4495Swnj 	m_free(dtom(fp));
315*4495Swnj }
316*4495Swnj 
317*4495Swnj struct ipq *ip_findf(p)         /* does fragment reass chain w/this hdr exist? */
318*4495Swnj register struct ip *p;
319*4495Swnj {
320*4495Swnj 	register struct ipq *fp;
321*4495Swnj 
322*4495Swnj COUNT(IP_FINDF);
323*4495Swnj 	for (fp = netcb.n_ip_head; (fp != NULL && (
324*4495Swnj 			p->ip_src.s_addr != fp->iqh.ip_src.s_addr ||
325*4495Swnj 			p->ip_dst.s_addr != fp->iqh.ip_dst.s_addr ||
326*4495Swnj 			p->ip_id != fp->iqh.ip_id ||
327*4495Swnj 			p->ip_p != fp->iqh.ip_p)); fp = fp->iq_next);
328*4495Swnj 	return(fp);
329*4495Swnj }
330*4495Swnj 
331*4495Swnj ip_opt(ip, hlen)        /* process ip options */
332*4495Swnj struct ip *ip;
333*4495Swnj int hlen;
334*4495Swnj {
335*4495Swnj 	register char *p, *q;
336*4495Swnj 	register i, len;
337*4495Swnj 	register struct mbuf *m;
338*4495Swnj 
339*4495Swnj COUNT(IP_OPT);
340*4495Swnj 	p = q = (char *)((int)ip + sizeof(struct ip));  /* -> at options */
341*4495Swnj 
342*4495Swnj 	if ((i = hlen - sizeof(struct ip)) > 0) {       /* any options */
343*4495Swnj 
344*4495Swnj /*      *** IP OPTION PROCESSING ***
345*4495Swnj 
346*4495Swnj 		while (i > 0)
347*4495Swnj 
348*4495Swnj   			switch (*q++) {
349*4495Swnj 			case 0:
350*4495Swnj 			case 1:
351*4495Swnj 				i--;
352*4495Swnj 				break;
353*4495Swnj 
354*4495Swnj 			default:
355*4495Swnj 				i -= *q;
356*4495Swnj 				q += *q;
357*4495Swnj 			}
358*4495Swnj */              q += i;
359*4495Swnj 		m = dtom(q);
360*4495Swnj 		len = (int)m + m->m_off + m->m_len - (int)q;
361*4495Swnj 		bcopy((caddr_t)q, (caddr_t)p, len);    /* remove options */
362*4495Swnj 		m->m_len -= i;
363*4495Swnj 	}
364*4495Swnj }
365*4495Swnj 
366*4495Swnj ip_enq(p, prev)
367*4495Swnj register struct ip *p;
368*4495Swnj register struct ip *prev;
369*4495Swnj {
370*4495Swnj COUNT(IP_ENQ);
371*4495Swnj 	p->ip_prev = prev;
372*4495Swnj 	p->ip_next = prev->ip_next;
373*4495Swnj 	prev->ip_next->ip_prev = p;
374*4495Swnj 	prev->ip_next = p;
375*4495Swnj }
376*4495Swnj 
377*4495Swnj ip_deq(p)
378*4495Swnj register struct ip *p;
379*4495Swnj {
380*4495Swnj COUNT(IP_DEQ);
381*4495Swnj 	p->ip_prev->ip_next = p->ip_next;
382*4495Swnj 	p->ip_next->ip_prev = p->ip_prev;
383*4495Swnj }
384*4495Swnj 
385*4495Swnj ip_bswap(p)    /* byte swap ip header */
386*4495Swnj register struct ip *p;
387*4495Swnj {
388*4495Swnj COUNT(IP_BSWAP);
389*4495Swnj 	p->ip_len = ntohs(p->ip_len);
390*4495Swnj 	p->ip_id = ntohs(p->ip_id);
391*4495Swnj 	p->ip_off = ntohs(p->ip_off);
392*4495Swnj }
393*4495Swnj 
394*4495Swnj ip_timeo()      /* frag reass.q timeout routine */
395*4495Swnj {
396*4495Swnj 	register struct ip *q;
397*4495Swnj 	register struct ipq *fp;
398*4495Swnj 
399*4495Swnj COUNT(IP_TIMEO);
400*4495Swnj 	timeout(ip_timeo, 0, 60);       /* reschedule every second */
401*4495Swnj 
402*4495Swnj 	if (netcb.n_ip_lock)    /* reass.q must not be in use */
403*4495Swnj 		return;
404*4495Swnj 
405*4495Swnj 	/* search through reass.q */
406*4495Swnj 
407*4495Swnj 	for (fp = netcb.n_ip_head; fp != NULL; fp = fp->iq_next)
408*4495Swnj 
409*4495Swnj 		if (--(fp->iqx.ip_ttl) == 0) {  /* time to die */
410*4495Swnj 
411*4495Swnj 			q = fp->iqx.ip_next;    /* free mbufs assoc. w/chain */
412*4495Swnj 			while (q != (struct ip *)fp) {
413*4495Swnj 				m_freem(dtom(q));
414*4495Swnj 				q = q->ip_next;
415*4495Swnj 			}
416*4495Swnj 			ip_freef(fp);           /* free header */
417*4495Swnj 		}
418*4495Swnj }
419