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