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