|
|
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.