date and time created 81/10/14 09:56:55 by wnj
[unix-history] / usr / src / sys / netinet / ip_input.c
CommitLineData
e1d82856
BJ
1/* ip_input.c 1.1 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
20int nosum = 0;
21
22ip_input(mp)
23struct 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
34COUNT(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
255ip_done(p) /* check to see if fragment reassembly is complete */
256register struct ip *p;
257{
258 register struct ip *q;
259 register next;
260
261COUNT(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
277ip_mergef(p) /* merge mbufs of fragments of completed datagram */
278register struct ip *p;
279{
280 register struct mbuf *m, *n;
281 register struct ip *q;
282 int dummy;
283
284COUNT(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
302ip_freef(fp) /* deq and free reass.q header */
303register struct ipq *fp;
304{
305COUNT(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
317struct ipq *ip_findf(p) /* does fragment reass chain w/this hdr exist? */
318register struct ip *p;
319{
320 register struct ipq *fp;
321
322COUNT(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
331ip_opt(ip, hlen) /* process ip options */
332struct ip *ip;
333int hlen;
334{
335 register char *p, *q;
336 register i, len;
337 register struct mbuf *m;
338
339COUNT(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
366ip_enq(p, prev)
367register struct ip *p;
368register struct ip *prev;
369{
370COUNT(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
377ip_deq(p)
378register struct ip *p;
379{
380COUNT(IP_DEQ);
381 p->ip_prev->ip_next = p->ip_next;
382 p->ip_next->ip_prev = p->ip_prev;
383}
384
385ip_bswap(p) /* byte swap ip header */
386register struct ip *p;
387{
388COUNT(IP_BSWAP);
389 p->ip_len = ntohs(p->ip_len);
390 p->ip_id = ntohs(p->ip_id);
391 p->ip_off = ntohs(p->ip_off);
392}
393
394ip_timeo() /* frag reass.q timeout routine */
395{
396 register struct ip *q;
397 register struct ipq *fp;
398
399COUNT(IP_TIMEO);
400 timeout(ip_timeo, 0, 60); /* reschedule every second */
401
402 if (netcb.n_ip_lock) /* reass.q must not be in use */
403 return;
404
405 /* search through reass.q */
406
407 for (fp = netcb.n_ip_head; fp != NULL; fp = fp->iq_next)
408
409 if (--(fp->iqx.ip_ttl) == 0) { /* time to die */
410
411 q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */
412 while (q != (struct ip *)fp) {
413 m_freem(dtom(q));
414 q = q->ip_next;
415 }
416 ip_freef(fp); /* free header */
417 }
418}