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