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