|
|
1.1 root 1: /* ip_input.c 6.1 83/08/16 */
2:
3: #include "../h/param.h"
4: #include "../h/systm.h"
5: #include "../h/stream.h"
6: #include "../h/inet/mbuf.h"
7: #include "../h/inet/in.h"
8: #include "../h/inet/ip.h"
9: #include "../h/inet/ip_var.h"
10:
11: int ipqmaxlen = 50;
12:
13: u_char ipcksum = 1;
14: struct ip *ip_reass();
15:
16: /*
17: * Ip input routine. Checksum and byte swap header. If fragmented
18: * try to reassamble. If complete and fragment queue exists, discard.
19: * Process options. Pass to next level.
20: */
21: ip_input(m)
22: register struct mbuf *m;
23: {
24: register struct ip *ip;
25: register struct ipq *fp;
26: struct mbuf *m0;
27: register int i;
28: int hlen;
29:
30: if (m == 0)
31: return;
32: if (BLEN(m) < sizeof (struct ip) &&
33: (m = m_pullup(m, sizeof (struct ip))) == 0) {
34: ipstat.ips_toosmall++;
35: return;
36: }
37: ip = mtod(m, struct ip *);
38: if ((hlen = ip->ip_hl << 2) > BLEN(m)) {
39: if ((m = m_pullup(m, hlen)) == 0) {
40: ipstat.ips_badhlen++;
41: return;
42: }
43: ip = mtod(m, struct ip *);
44: }
45: if (ipcksum)
46: if (ip->ip_sum = in_cksum(m, hlen)) {
47: ipstat.ips_badsum++;
48: goto bad;
49: }
50:
51: /*
52: * Convert fields to host representation.
53: */
54: ip->ip_len = ntohs((u_short)ip->ip_len);
55: if (ip->ip_len < hlen) {
56: ipstat.ips_badlen++;
57: goto bad;
58: }
59: ip->ip_id = ntohs(ip->ip_id);
60: ip->ip_off = ntohs((u_short)ip->ip_off);
61:
62: /*
63: * Check that the amount of data in the buffers
64: * is as at least much as the IP header would have us expect.
65: * Trim mbufs if longer than we expect.
66: * Drop packet if shorter than we expect.
67: */
68: i = -ip->ip_len;
69: m0 = m;
70: for (;;) {
71: i += BLEN(m);
72: if (m->m_next == 0)
73: break;
74: m = m->m_next;
75: }
76: if (i != 0) {
77: if (i < 0) {
78: ipstat.ips_tooshort++;
79: goto bad;
80: }
81: if (i <= BLEN(m))
82: m->wptr -= i;
83: else
84: m_adj(m0, -i);
85: }
86: m = m0;
87:
88: /*
89: * Process options and, if not destined for us,
90: * ship it on. ip_dooptions returns 1 when an
91: * error was detected (causing an icmp message
92: * to be sent).
93: */
94: ip->ip_dst = ntohl(ip->ip_dst);
95: ip->ip_src = ntohl(ip->ip_src);
96: if (hlen > sizeof (struct ip) && ip_dooptions(ip))
97: return;
98:
99: if (ip_ifwithaddr(ip->ip_dst) == 0) {
100: ip_forward(ip);
101: return;
102: }
103:
104: /*
105: * Look for queue of fragments
106: * of this datagram.
107: */
108: if(ipq.next == 0 && ipq.prev == 0) /* init, only once */
109: ipq.next = ipq.prev = &ipq;
110: for (fp = ipq.next; fp != &ipq; fp = fp->next)
111: if (ip->ip_id == fp->ipq_id &&
112: ip->ip_src == fp->ipq_src &&
113: ip->ip_dst == fp->ipq_dst &&
114: ip->ip_p == fp->ipq_p)
115: goto found;
116: fp = 0;
117: found:
118:
119: /*
120: * Adjust ip_len to not reflect header,
121: * set ip_mff if more fragments are expected,
122: * convert offset of this to bytes.
123: */
124: ip->ip_len -= hlen;
125: ((struct ipasfrag *)ip)->ipf_mff = 0;
126: if (ip->ip_off & IP_MF)
127: ((struct ipasfrag *)ip)->ipf_mff = 1;
128: ip->ip_off <<= 3;
129:
130: /*
131: * If datagram marked as having more fragments
132: * or if this is not the first fragment,
133: * attempt reassembly; if it succeeds, proceed.
134: */
135: if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
136: ip = ip_reass((struct ipasfrag *)ip, fp);
137: if (ip == 0)
138: return;
139: hlen = ip->ip_hl << 2;
140: m = dtom(ip);
141: } else
142: if (fp)
143: ip_freef(fp);
144:
145: /*
146: * Switch out to protocol's input routine.
147: */
148: ipdrint(m, (unsigned int)(ip->ip_p));
149: return;
150: bad:
151: m_freem(m);
152: }
153:
154: /*
155: * Take incoming datagram fragment and try to
156: * reassemble it into whole datagram. If a chain for
157: * reassembly of this datagram already exists, then it
158: * is given as fp; otherwise have to make a chain.
159: */
160: struct ip *
161: ip_reass(ip, fp)
162: register struct ipasfrag *ip;
163: register struct ipq *fp;
164: {
165: register struct mbuf *m = dtom(ip);
166: register struct ipasfrag *q;
167: struct mbuf *t;
168: int hlen = ip->ip_hl << 2;
169: int i, next;
170:
171: /*
172: * Presence of header sizes in mbufs
173: * would confuse code below.
174: */
175: m->rptr += hlen;
176:
177: /*
178: * If first fragment to arrive, create a reassembly queue.
179: */
180: if (fp == 0) {
181: if ((t = m_get(M_WAIT, MT_FTABLE)) == NULL)
182: goto dropfrag;
183: t->m_next = 0;
184: fp = mtod(t, struct ipq *);
185: insque(fp, &ipq);
186: fp->ipq_ttl = IPFRAGTTL;
187: fp->ipq_p = ip->ip_p;
188: fp->ipq_id = ip->ip_id;
189: fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
190: fp->ipq_src = ((struct ip *)ip)->ip_src;
191: fp->ipq_dst = ((struct ip *)ip)->ip_dst;
192: q = (struct ipasfrag *)fp;
193: goto insert;
194: }
195:
196: /*
197: * Find a segment which begins after this one does.
198: */
199: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
200: if (q->ip_off > ip->ip_off)
201: break;
202:
203: /*
204: * If there is a preceding segment, it may provide some of
205: * our data already. If so, drop the data from the incoming
206: * segment. If it provides all of our data, drop us.
207: */
208: if (q->ipf_prev != (struct ipasfrag *)fp) {
209: i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
210: if (i > 0) {
211: if (i >= ip->ip_len)
212: goto dropfrag;
213: m_adj(dtom(ip), i);
214: ip->ip_off += i;
215: ip->ip_len -= i;
216: }
217: }
218:
219: /*
220: * While we overlap succeeding segments trim them or,
221: * if they are completely covered, dequeue them.
222: */
223: while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
224: i = (ip->ip_off + ip->ip_len) - q->ip_off;
225: if (i < q->ip_len) {
226: q->ip_len -= i;
227: q->ip_off += i;
228: m_adj(dtom(q), i);
229: break;
230: }
231: q = q->ipf_next;
232: m_freem(dtom(q->ipf_prev));
233: ip_deq(q->ipf_prev);
234: }
235:
236: insert:
237: /*
238: * Stick new segment in its place;
239: * check for complete reassembly.
240: */
241: ip_enq(ip, q->ipf_prev);
242: next = 0;
243: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
244: if (q->ip_off != next)
245: return (0);
246: next += q->ip_len;
247: }
248: if (q->ipf_prev->ipf_mff)
249: return (0);
250:
251: /*
252: * Reassembly is complete; concatenate fragments.
253: */
254: q = fp->ipq_next;
255: m = dtom(q);
256: t = m->m_next;
257: m->m_next = 0;
258: m_cat(m, t);
259: q = q->ipf_next;
260: while (q != (struct ipasfrag *)fp) {
261: t = dtom(q);
262: q = q->ipf_next;
263: m_cat(m, t);
264: }
265:
266: /*
267: * Create header for new ip packet by
268: * modifying header of first packet;
269: * dequeue and discard fragment reassembly header.
270: * Make header visible.
271: */
272: ip = fp->ipq_next;
273: ip->ip_len = next;
274: ((struct ip *)ip)->ip_src = fp->ipq_src;
275: ((struct ip *)ip)->ip_dst = fp->ipq_dst;
276: remque(fp);
277: (void) m_free(dtom(fp));
278: m = dtom(ip);
279: m->rptr -= sizeof (struct ipasfrag);
280: return ((struct ip *)ip);
281:
282: dropfrag:
283: m_freem(m);
284: return (0);
285: }
286:
287: /*
288: * Free a fragment reassembly header and all
289: * associated datagrams.
290: */
291: ip_freef(fp)
292: struct ipq *fp;
293: {
294: register struct ipasfrag *q, *p;
295:
296: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
297: p = q->ipf_next;
298: ip_deq(q);
299: m_freem(dtom(q));
300: }
301: remque(fp);
302: (void) m_free(dtom(fp));
303: }
304:
305: /*
306: * Put an ip fragment on a reassembly chain.
307: * Like insque, but pointers in middle of structure.
308: */
309: ip_enq(p, prev)
310: register struct ipasfrag *p, *prev;
311: {
312:
313: p->ipf_prev = prev;
314: p->ipf_next = prev->ipf_next;
315: prev->ipf_next->ipf_prev = p;
316: prev->ipf_next = p;
317: }
318:
319: /*
320: * To ip_enq as remque is to insque.
321: */
322: ip_deq(p)
323: register struct ipasfrag *p;
324: {
325:
326: p->ipf_prev->ipf_next = p->ipf_next;
327: p->ipf_next->ipf_prev = p->ipf_prev;
328: }
329:
330: /*
331: * IP timer processing;
332: * if a timer expires on a reassembly
333: * queue, discard it.
334: */
335: ip_slowtimo()
336: {
337: register struct ipq *fp;
338: int s = spl6();
339:
340: fp = ipq.next;
341: if (fp == 0) {
342: splx(s);
343: return;
344: }
345: while (fp != &ipq) {
346: --fp->ipq_ttl;
347: fp = fp->next;
348: if (fp->prev->ipq_ttl == 0)
349: ip_freef(fp->prev);
350: }
351: timeout(ip_slowtimo, (caddr_t)0, hz);
352: splx(s);
353: }
354:
355: /*
356: * Drain off all datagram fragments.
357: */
358: ip_drain()
359: {
360:
361: while (ipq.next != &ipq)
362: ip_freef(ipq.next);
363: }
364:
365: /*
366: * Do option processing on a datagram,
367: * possibly discarding it if bad options
368: * are encountered.
369: */
370: ip_dooptions(ip)
371: struct ip *ip;
372: {
373: register u_char *cp;
374: int opt, optlen, cnt;
375:
376: cp = (u_char *)(ip + 1);
377: cnt = (ip->ip_hl << 2) - sizeof (struct ip);
378: for (; cnt > 0; cnt -= optlen, cp += optlen) {
379: opt = cp[0];
380: if (opt == IPOPT_EOL)
381: break;
382: if (opt == IPOPT_NOP)
383: optlen = 1;
384: else
385: optlen = cp[1];
386: switch (opt) {
387:
388: default:
389: break;
390: #ifdef FAT_CHANCE
391: /*
392: * Source routing with record.
393: * Find interface with current destination address.
394: * If none on this machine then drop if strictly routed,
395: * or do nothing if loosely routed.
396: * Record interface address and bring up next address
397: * component. If strictly routed make sure next
398: * address on directly accessible net.
399: */
400: case IPOPT_LSRR:
401: case IPOPT_SSRR:
402: if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1))
403: break;
404: sin = (struct in_addr *)(cp + cp[2]);
405: ipaddr.sin_addr = *sin;
406: ifp = if_ifwithaddr((struct sockaddr *)&ipaddr);
407: type = ICMP_UNREACH, code = ICMP_UNREACH_SRCFAIL;
408: if (ifp == 0) {
409: if (opt == IPOPT_SSRR)
410: goto bad;
411: break;
412: }
413: t = ip->ip_dst; ip->ip_dst = *sin; *sin = t;
414: cp[2] += 4;
415: if (cp[2] > optlen - (sizeof (long) - 1))
416: break;
417: ip->ip_dst = sin[1];
418: if (opt == IPOPT_SSRR &&
419: if_ifonnetof(in_netof(ip->ip_dst)) == 0)
420: goto bad;
421: break;
422:
423: case IPOPT_TS:
424: code = cp - (u_char *)ip;
425: type = ICMP_PARAMPROB;
426: ipt = (struct ip_timestamp *)cp;
427: if (ipt->ipt_len < 5)
428: goto bad;
429: if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
430: if (++ipt->ipt_oflw == 0)
431: goto bad;
432: break;
433: }
434: sin = (struct in_addr *)(cp+cp[2]);
435: switch (ipt->ipt_flg) {
436:
437: case IPOPT_TS_TSONLY:
438: break;
439:
440: case IPOPT_TS_TSANDADDR:
441: if (ipt->ipt_ptr + 8 > ipt->ipt_len)
442: goto bad;
443: if (ifinet == 0)
444: goto bad; /* ??? */
445: *sin++ = ((struct sockaddr_in *)&ifinet->if_addr)->sin_addr;
446: break;
447:
448: case IPOPT_TS_PRESPEC:
449: ipaddr.sin_addr = *sin;
450: if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0)
451: continue;
452: if (ipt->ipt_ptr + 8 > ipt->ipt_len)
453: goto bad;
454: ipt->ipt_ptr += 4;
455: break;
456:
457: default:
458: goto bad;
459: }
460: *(n_time *)sin = iptime();
461: ipt->ipt_ptr += 4;
462: #endif FATCHANCE
463: }
464: }
465: return (0);
466: }
467:
468: /*
469: * Strip out IP options, at higher
470: * level protocol in the kernel.
471: * Second argument is buffer to which options
472: * will be moved, and return value is their length.
473: */
474: ip_stripoptions(ip, mopt)
475: struct ip *ip;
476: struct mbuf *mopt;
477: {
478: register int i;
479: register struct mbuf *m;
480: int olen;
481:
482: olen = (ip->ip_hl<<2) - sizeof (struct ip);
483: m = dtom(ip);
484: ip++;
485: if (mopt) {
486: mopt->wptr = mopt->base + olen;
487: mopt->rptr = mopt->base;
488: bcopy((caddr_t)ip, mtod(m, caddr_t), (unsigned)olen);
489: }
490: i = BLEN(m) - (sizeof (struct ip) + olen);
491: bcopy((caddr_t)ip+olen, (caddr_t)ip, (unsigned)i);
492: m->wptr -= olen;
493: }
494:
495: int ipforwarding = 1;
496: extern ipprintfs;
497: /*
498: * Forward a packet. If some error occurs return the sender
499: * and icmp packet. Note we can't always generate a meaningful
500: * icmp message because icmp doesn't have a large enough repetoire
501: * of codes and types.
502: */
503: ip_forward(ip)
504: register struct ip *ip;
505: {
506: struct mbuf *mopt;
507:
508: if(ipprintfs)
509: printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
510: ip->ip_dst, ip->ip_ttl);
511: if (ipforwarding == 0) {
512: return;
513: }
514: if (ip->ip_ttl < IPTTLDEC) {
515: return;
516: }
517: ip->ip_ttl -= IPTTLDEC;
518: mopt = m_get(M_DONTWAIT, MT_DATA);
519: if (mopt == NULL) {
520: m_freem(dtom(ip));
521: return;
522: }
523: mopt->next = 0;
524:
525: ip_stripoptions(ip, mopt);
526:
527: ip_output(dtom(ip), mopt, IP_FORWARDING);
528: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.