Commit | Line | Data |
---|---|---|
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 | ||
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_bswap(p) /* byte swap ip header */ | |
386 | register struct ip *p; | |
387 | { | |
388 | COUNT(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 | ||
394 | ip_timeo() /* frag reass.q timeout routine */ | |
395 | { | |
396 | register struct ip *q; | |
397 | register struct ipq *fp; | |
398 | ||
399 | COUNT(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 | } |