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