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