|
|
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/mbuf.h" ! 6: #include "../h/domain.h" ! 7: #include "../h/protosw.h" ! 8: #include "../h/socket.h" ! 9: #include "../h/errno.h" ! 10: #include "../h/time.h" ! 11: #include "../h/kernel.h" ! 12: ! 13: #include "../net/if.h" ! 14: #include "../net/route.h" ! 15: ! 16: #include "../netinet/in.h" ! 17: #include "../netinet/in_pcb.h" ! 18: #include "../netinet/in_systm.h" ! 19: #include "../netinet/ip.h" ! 20: #include "../netinet/ip_var.h" ! 21: #include "../netinet/ip_icmp.h" ! 22: #include "../netinet/tcp.h" ! 23: ! 24: #ifdef NET_PERF ! 25: # define IPTRACE1 1 ! 26: # define IPTRACE2 2 ! 27: # define IPTRACE(X,Y) { if (ipprintfs & X) Y} ! 28: # define IPSTUDY(X) {X} ! 29: #else NET_PERF ! 30: # define IPTRACE(X,Y) ! 31: # define IPSTUDY(X) ! 32: #endif NET_PERF ! 33: ! 34: ! 35: int ipprintfs = 0; ! 36: u_char ip_protox[IPPROTO_MAX]; ! 37: int ipqmaxlen = IFQ_MAXLEN; ! 38: struct ifnet *ifinet; /* first inet interface */ ! 39: ! 40: /* ! 41: * Changes: ! 42: * fix mbuf deallocation when length is too short ! 43: * in ip_init(), change the search limit to end of domain table. ! 44: */ ! 45: /* ! 46: * IP initialization: fill in IP protocol switch table. ! 47: * All protocols not implemented in kernel go to raw IP protocol handler. ! 48: */ ! 49: ip_init() ! 50: { ! 51: register struct protosw *pr; ! 52: register int i; ! 53: ! 54: pr = pffindproto(PF_INET, IPPROTO_RAW); ! 55: if (pr == 0) ! 56: panic("ip_init"); ! 57: for (i = 0; i < IPPROTO_MAX; i++) ! 58: ip_protox[i] = pr - inetsw; ! 59: for (pr = inetdomain.dom_protosw; ! 60: pr < inetdomain.dom_protoswNPROTOSW; pr++) ! 61: if (pr->pr_family == PF_INET && ! 62: pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) ! 63: ip_protox[pr->pr_protocol] = pr - inetsw; ! 64: ipq.next = ipq.prev = &ipq; ! 65: ip_id = time.tv_sec & 0xffff; ! 66: ipintrq.ifq_maxlen = ipqmaxlen; ! 67: ifinet = if_ifwithaf(AF_INET); ! 68: } ! 69: ! 70: u_char ipcksum = 1; ! 71: struct ip *ip_reass(); ! 72: struct sockaddr_in ipaddr = { AF_INET }; ! 73: ! 74: /* ! 75: * Ip input routine. Checksum and byte swap header. If fragmented ! 76: * try to reassamble. If complete and fragment queue exists, discard. ! 77: * Process options. Pass to next level. ! 78: */ ! 79: ipintr() ! 80: { ! 81: register struct ip *ip; ! 82: register struct mbuf *m; ! 83: struct mbuf *m0; ! 84: register int i; ! 85: register struct ipq *fp; ! 86: int hlen, s; ! 87: ! 88: next: ! 89: /* ! 90: * Get next datagram off input queue and get IP header ! 91: * in first mbuf. ! 92: */ ! 93: s = splimp(); ! 94: IF_DEQUEUE(&ipintrq, m); ! 95: splx(s); ! 96: if (m == 0) ! 97: return; ! 98: IPTRACE(IPTRACE1, printf("IPintr: DEQUEUE\n");) ! 99: ! 100: if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && ! 101: (m = m_pullup(m, sizeof (struct ip))) == 0) { ! 102: ipstat.ips_toosmall++; ! 103: goto next; ! 104: } ! 105: ip = mtod(m, struct ip *); ! 106: if ((hlen = ip->ip_hl << 2) > m->m_len) { ! 107: if ((m = m_pullup(m, hlen)) == 0) { ! 108: ipstat.ips_badhlen++; ! 109: goto next; ! 110: } ! 111: ip = mtod(m, struct ip *); ! 112: } ! 113: if (ipcksum) ! 114: if (ip->ip_sum = in_cksum(m, hlen)) { ! 115: ipstat.ips_badsum++; ! 116: goto bad; ! 117: } ! 118: ! 119: /* ! 120: * Convert fields to host representation. ! 121: */ ! 122: ip->ip_len = ntohs((u_short)ip->ip_len); ! 123: if (ip->ip_len < hlen) { ! 124: ipstat.ips_badlen++; ! 125: goto bad; ! 126: } ! 127: ip->ip_id = ntohs(ip->ip_id); ! 128: ip->ip_off = ntohs((u_short)ip->ip_off); ! 129: ! 130: /* ! 131: * Check that the amount of data in the buffers ! 132: * is as at least much as the IP header would have us expect. ! 133: * Trim mbufs if longer than we expect. ! 134: * Drop packet if shorter than we expect. ! 135: */ ! 136: i = -ip->ip_len; ! 137: m0 = m; ! 138: for (;;) { ! 139: i += m->m_len; ! 140: if (m->m_next == 0) ! 141: break; ! 142: m = m->m_next; ! 143: } ! 144: if (i != 0) { ! 145: if (i < 0) { ! 146: ipstat.ips_tooshort++; ! 147: m = m0; ! 148: goto bad; ! 149: } ! 150: if (i <= m->m_len) ! 151: m->m_len -= i; ! 152: else ! 153: m_adj(m0, -i); ! 154: } ! 155: m = m0; ! 156: ! 157: /* ! 158: * Process options and, if not destined for us, ! 159: * ship it on. ip_dooptions returns 1 when an ! 160: * error was detected (causing an icmp message ! 161: * to be sent). ! 162: */ ! 163: if (hlen > sizeof (struct ip) && ip_dooptions(ip)) ! 164: goto next; ! 165: ! 166: /* ! 167: * Fast check on the first internet ! 168: * interface in the list. ! 169: */ ! 170: if (ifinet) { ! 171: struct sockaddr_in *sin; ! 172: ! 173: sin = (struct sockaddr_in *)&ifinet->if_addr; ! 174: if (sin->sin_addr.s_addr == ip->ip_dst.s_addr) ! 175: goto ours; ! 176: sin = (struct sockaddr_in *)&ifinet->if_broadaddr; ! 177: if ((ifinet->if_flags & IFF_BROADCAST) && ! 178: sin->sin_addr.s_addr == ip->ip_dst.s_addr) ! 179: goto ours; ! 180: } ! 181: /* BEGIN GROT */ ! 182: #include "nd.h" ! 183: #if NND > 0 ! 184: /* ! 185: * Diskless machines don't initially know ! 186: * their address, so take packets from them ! 187: * if we're acting as a network disk server. ! 188: */ ! 189: if (in_netof(ip->ip_dst) == INADDR_ANY && ! 190: (in_netof(ip->ip_src) == INADDR_ANY && ! 191: in_lnaof(ip->ip_src) != INADDR_ANY)) ! 192: goto ours; ! 193: #endif ! 194: /* END GROT */ ! 195: ipaddr.sin_addr = ip->ip_dst; ! 196: if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0) { ! 197: ip_forward(ip); ! 198: goto next; ! 199: } ! 200: ! 201: ours: ! 202: /* ! 203: * Look for queue of fragments ! 204: * of this datagram. ! 205: */ ! 206: for (fp = ipq.next; fp != &ipq; fp = fp->next) ! 207: if (ip->ip_id == fp->ipq_id && ! 208: ip->ip_src.s_addr == fp->ipq_src.s_addr && ! 209: ip->ip_dst.s_addr == fp->ipq_dst.s_addr && ! 210: ip->ip_p == fp->ipq_p) ! 211: goto found; ! 212: fp = 0; ! 213: found: ! 214: ! 215: /* ! 216: * Adjust ip_len to not reflect header, ! 217: * set ip_mff if more fragments are expected, ! 218: * convert offset of this to bytes. ! 219: */ ! 220: ip->ip_len -= hlen; ! 221: ((struct ipasfrag *)ip)->ipf_mff = 0; ! 222: if (ip->ip_off & IP_MF) ! 223: ((struct ipasfrag *)ip)->ipf_mff = 1; ! 224: ip->ip_off <<= 3; ! 225: ! 226: /* ! 227: * If datagram marked as having more fragments ! 228: * or if this is not the first fragment, ! 229: * attempt reassembly; if it succeeds, proceed. ! 230: */ ! 231: if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { ! 232: ip = ip_reass((struct ipasfrag *)ip, fp); ! 233: if (ip == 0) ! 234: goto next; ! 235: hlen = ip->ip_hl << 2; ! 236: m = dtom(ip); ! 237: } else ! 238: if (fp) ! 239: ip_freef(fp); ! 240: ! 241: /* ! 242: * Switch out to protocol's input routine. ! 243: */ ! 244: IPTRACE(IPTRACE2, printf("Proto #%d\n",ip->ip_p);) ! 245: (*inetsw[ip_protox[ip->ip_p]].pr_input)(m); ! 246: goto next; ! 247: bad: ! 248: m_freem(m); ! 249: goto next; ! 250: } ! 251: ! 252: /* ! 253: * Take incoming datagram fragment and try to ! 254: * reassemble it into whole datagram. If a chain for ! 255: * reassembly of this datagram already exists, then it ! 256: * is given as fp; otherwise have to make a chain. ! 257: */ ! 258: struct ip * ! 259: ip_reass(ip, fp) ! 260: register struct ipasfrag *ip; ! 261: register struct ipq *fp; ! 262: { ! 263: register struct mbuf *m = dtom(ip); ! 264: register struct ipasfrag *q; ! 265: struct mbuf *t; ! 266: int hlen = ip->ip_hl << 2; ! 267: int i, next; ! 268: ! 269: /* ! 270: * Presence of header sizes in mbufs ! 271: * would confuse code below. ! 272: */ ! 273: m->m_off += hlen; ! 274: m->m_len -= hlen; ! 275: ! 276: /* ! 277: * If first fragment to arrive, create a reassembly queue. ! 278: */ ! 279: if (fp == 0) { ! 280: t = m_get(M_WAIT, MT_FTABLE); ! 281: MBUFNULL(7, t); /* for debugging */ ! 282: if (t == NULL) ! 283: goto dropfrag; ! 284: fp = mtod(t, struct ipq *); ! 285: insque(fp, &ipq); ! 286: fp->ipq_ttl = IPFRAGTTL; ! 287: fp->ipq_p = ip->ip_p; ! 288: fp->ipq_id = ip->ip_id; ! 289: fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; ! 290: fp->ipq_src = ((struct ip *)ip)->ip_src; ! 291: fp->ipq_dst = ((struct ip *)ip)->ip_dst; ! 292: q = (struct ipasfrag *)fp; ! 293: goto insert; ! 294: } ! 295: ! 296: /* ! 297: * Find a segment which begins after this one does. ! 298: */ ! 299: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) ! 300: if (q->ip_off > ip->ip_off) ! 301: break; ! 302: ! 303: /* ! 304: * If there is a preceding segment, it may provide some of ! 305: * our data already. If so, drop the data from the incoming ! 306: * segment. If it provides all of our data, drop us. ! 307: */ ! 308: if (q->ipf_prev != (struct ipasfrag *)fp) { ! 309: i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; ! 310: if (i > 0) { ! 311: if (i >= ip->ip_len) ! 312: goto dropfrag; ! 313: m_adj(dtom(ip), i); ! 314: ip->ip_off += i; ! 315: ip->ip_len -= i; ! 316: } ! 317: } ! 318: ! 319: /* ! 320: * While we overlap succeeding segments trim them or, ! 321: * if they are completely covered, dequeue them. ! 322: */ ! 323: while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { ! 324: i = (ip->ip_off + ip->ip_len) - q->ip_off; ! 325: if (i < q->ip_len) { ! 326: q->ip_len -= i; ! 327: q->ip_off += i; ! 328: m_adj(dtom(q), i); ! 329: break; ! 330: } ! 331: q = q->ipf_next; ! 332: m_freem(dtom(q->ipf_prev)); ! 333: ip_deq(q->ipf_prev); ! 334: } ! 335: ! 336: insert: ! 337: /* ! 338: * Stick new segment in its place; ! 339: * check for complete reassembly. ! 340: */ ! 341: ip_enq(ip, q->ipf_prev); ! 342: next = 0; ! 343: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { ! 344: if (q->ip_off != next) ! 345: return (0); ! 346: next += q->ip_len; ! 347: } ! 348: if (q->ipf_prev->ipf_mff) ! 349: return (0); ! 350: ! 351: /* ! 352: * Reassembly is complete; concatenate fragments. ! 353: */ ! 354: q = fp->ipq_next; ! 355: m = dtom(q); ! 356: t = m->m_next; ! 357: m->m_next = 0; ! 358: m_cat(m, t); ! 359: q = q->ipf_next; ! 360: while (q != (struct ipasfrag *)fp) { ! 361: t = dtom(q); ! 362: q = q->ipf_next; ! 363: m_cat(m, t); ! 364: } ! 365: ! 366: /* ! 367: * Create header for new ip packet by ! 368: * modifying header of first packet; ! 369: * dequeue and discard fragment reassembly header. ! 370: * Make header visible. ! 371: */ ! 372: ip = fp->ipq_next; ! 373: ip->ip_len = next; ! 374: ((struct ip *)ip)->ip_src = fp->ipq_src; ! 375: ((struct ip *)ip)->ip_dst = fp->ipq_dst; ! 376: remque(fp); ! 377: (void) m_free(dtom(fp)); ! 378: m = dtom(ip); ! 379: m->m_len += sizeof (struct ipasfrag); ! 380: m->m_off -= sizeof (struct ipasfrag); ! 381: return ((struct ip *)ip); ! 382: ! 383: dropfrag: ! 384: m_freem(m); ! 385: return (0); ! 386: } ! 387: ! 388: /* ! 389: * Free a fragment reassembly header and all ! 390: * associated datagrams. ! 391: */ ! 392: ip_freef(fp) ! 393: struct ipq *fp; ! 394: { ! 395: register struct ipasfrag *q, *p; ! 396: ! 397: for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { ! 398: p = q->ipf_next; ! 399: ip_deq(q); ! 400: m_freem(dtom(q)); ! 401: } ! 402: remque(fp); ! 403: (void) m_free(dtom(fp)); ! 404: } ! 405: ! 406: /* ! 407: * Put an ip fragment on a reassembly chain. ! 408: * Like insque, but pointers in middle of structure. ! 409: */ ! 410: ip_enq(p, prev) ! 411: register struct ipasfrag *p, *prev; ! 412: { ! 413: ! 414: p->ipf_prev = prev; ! 415: p->ipf_next = prev->ipf_next; ! 416: prev->ipf_next->ipf_prev = p; ! 417: prev->ipf_next = p; ! 418: } ! 419: ! 420: /* ! 421: * To ip_enq as remque is to insque. ! 422: */ ! 423: ip_deq(p) ! 424: register struct ipasfrag *p; ! 425: { ! 426: ! 427: p->ipf_prev->ipf_next = p->ipf_next; ! 428: p->ipf_next->ipf_prev = p->ipf_prev; ! 429: } ! 430: ! 431: /* ! 432: * IP timer processing; ! 433: * if a timer expires on a reassembly ! 434: * queue, discard it. ! 435: */ ! 436: ip_slowtimo() ! 437: { ! 438: register struct ipq *fp; ! 439: int s = splnet(); ! 440: ! 441: fp = ipq.next; ! 442: if (fp == 0) { ! 443: splx(s); ! 444: return; ! 445: } ! 446: while (fp != &ipq) { ! 447: --fp->ipq_ttl; ! 448: fp = fp->next; ! 449: if (fp->prev->ipq_ttl == 0) ! 450: ip_freef(fp->prev); ! 451: } ! 452: splx(s); ! 453: } ! 454: ! 455: /* ! 456: * Drain off all datagram fragments. ! 457: */ ! 458: ip_drain() ! 459: { ! 460: ! 461: while (ipq.next != &ipq) ! 462: ip_freef(ipq.next); ! 463: } ! 464: ! 465: /* ! 466: * Do option processing on a datagram, ! 467: * possibly discarding it if bad options ! 468: * are encountered. ! 469: */ ! 470: ip_dooptions(ip) ! 471: struct ip *ip; ! 472: { ! 473: register u_char *cp; ! 474: int opt, optlen, cnt, code, type; ! 475: struct in_addr *sin; ! 476: register struct ip_timestamp *ipt; ! 477: register struct ifnet *ifp; ! 478: struct in_addr t; ! 479: ! 480: cp = (u_char *)(ip + 1); ! 481: cnt = (ip->ip_hl << 2) - sizeof (struct ip); ! 482: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 483: opt = cp[0]; ! 484: if (opt == IPOPT_EOL) ! 485: break; ! 486: if (opt == IPOPT_NOP) ! 487: optlen = 1; ! 488: else ! 489: optlen = cp[1]; ! 490: switch (opt) { ! 491: ! 492: default: ! 493: break; ! 494: ! 495: /* ! 496: * Source routing with record. ! 497: * Find interface with current destination address. ! 498: * If none on this machine then drop if strictly routed, ! 499: * or do nothing if loosely routed. ! 500: * Record interface address and bring up next address ! 501: * component. If strictly routed make sure next ! 502: * address on directly accessible net. ! 503: */ ! 504: case IPOPT_LSRR: ! 505: case IPOPT_SSRR: ! 506: if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1)) ! 507: break; ! 508: sin = (struct in_addr *)(cp + cp[2]); ! 509: ipaddr.sin_addr = *sin; ! 510: ifp = if_ifwithaddr((struct sockaddr *)&ipaddr); ! 511: type = ICMP_UNREACH, code = ICMP_UNREACH_SRCFAIL; ! 512: if (ifp == 0) { ! 513: if (opt == IPOPT_SSRR) { ! 514: IPSTUDY(ipstudy.ips_ssnoifaddr++;) ! 515: goto bad; ! 516: } ! 517: break; ! 518: } ! 519: t = ip->ip_dst; ip->ip_dst = *sin; *sin = t; ! 520: cp[2] += 4; ! 521: if (cp[2] > optlen - (sizeof (long) - 1)) ! 522: break; ! 523: ip->ip_dst = sin[1]; ! 524: if (opt == IPOPT_SSRR && ! 525: if_ifonnetof(in_netof(ip->ip_dst)) == 0) { ! 526: IPSTUDY(ipstudy.ips_ssnoifnet++;) ! 527: goto bad; ! 528: } ! 529: break; ! 530: ! 531: case IPOPT_TS: ! 532: code = cp - (u_char *)ip; ! 533: type = ICMP_PARAMPROB; ! 534: ipt = (struct ip_timestamp *)cp; ! 535: if (ipt->ipt_len < 5) { ! 536: IPSTUDY(ipstudy.ips_oplen++;) ! 537: goto bad; ! 538: } ! 539: if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { ! 540: if (++ipt->ipt_oflw == 0) { ! 541: IPSTUDY(ipstudy.ips_oplen++;) ! 542: goto bad; ! 543: } ! 544: break; ! 545: } ! 546: sin = (struct in_addr *)(cp+cp[2]); ! 547: switch (ipt->ipt_flg) { ! 548: ! 549: case IPOPT_TS_TSONLY: ! 550: break; ! 551: ! 552: case IPOPT_TS_TSANDADDR: ! 553: if (ipt->ipt_ptr + 8 > ipt->ipt_len) { ! 554: IPSTUDY(ipstudy.ips_oplen++;) ! 555: goto bad; ! 556: } ! 557: if (ifinet == 0) { ! 558: IPSTUDY(ipstudy.ips_noif++;) ! 559: goto bad; /* ??? */ ! 560: } ! 561: *sin++ = ((struct sockaddr_in *)&ifinet->if_addr)->sin_addr; ! 562: break; ! 563: ! 564: case IPOPT_TS_PRESPEC: ! 565: ipaddr.sin_addr = *sin; ! 566: if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0) ! 567: continue; ! 568: if (ipt->ipt_ptr + 8 > ipt->ipt_len) { ! 569: IPSTUDY(ipstudy.ips_oplen++;) ! 570: goto bad; ! 571: } ! 572: ipt->ipt_ptr += 4; ! 573: break; ! 574: ! 575: default: ! 576: IPSTUDY(ipstudy.ips_badopt++;) ! 577: goto bad; ! 578: } ! 579: *(n_time *)sin = iptime(); ! 580: ipt->ipt_ptr += 4; ! 581: } ! 582: } ! 583: return (0); ! 584: bad: ! 585: icmp_error(ip, type, code); ! 586: return (1); ! 587: } ! 588: ! 589: /* ! 590: * Strip out IP options, at higher ! 591: * level protocol in the kernel. ! 592: * Second argument is buffer to which options ! 593: * will be moved, and return value is their length. ! 594: */ ! 595: ip_stripoptions(ip, mopt) ! 596: struct ip *ip; ! 597: struct mbuf *mopt; ! 598: { ! 599: register int i; ! 600: register struct mbuf *m; ! 601: int olen; ! 602: ! 603: olen = (ip->ip_hl<<2) - sizeof (struct ip); ! 604: m = dtom(ip); ! 605: ip++; ! 606: if (mopt) { ! 607: mopt->m_len = olen; ! 608: mopt->m_off = MMINOFF; ! 609: bcopy((caddr_t)ip, mtod(m, caddr_t), (unsigned)olen); ! 610: } ! 611: i = m->m_len - (sizeof (struct ip) + olen); ! 612: bcopy((caddr_t)ip+olen, (caddr_t)ip, (unsigned)i); ! 613: m->m_len -= olen; ! 614: } ! 615: ! 616: u_char inetctlerrmap[PRC_NCMDS] = { ! 617: ECONNABORTED, ECONNABORTED, 0, 0, ! 618: 0, 0, EHOSTDOWN, EHOSTUNREACH, ! 619: ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, ! 620: EMSGSIZE, 0, 0, 0, ! 621: 0, 0, 0, 0 ! 622: }; ! 623: ! 624: ip_ctlinput(cmd, arg) ! 625: int cmd; ! 626: caddr_t arg; ! 627: { ! 628: struct in_addr *in; ! 629: int tcp_abort(), udp_abort(); ! 630: extern struct inpcb tcb, udb; ! 631: ! 632: if (cmd < 0 || cmd > PRC_NCMDS) ! 633: return; ! 634: if (inetctlerrmap[cmd] == 0) ! 635: return; /* XXX */ ! 636: if (cmd == PRC_IFDOWN) ! 637: in = &((struct sockaddr_in *)arg)->sin_addr; ! 638: else if (cmd == PRC_HOSTDEAD || cmd == PRC_HOSTUNREACH) ! 639: in = (struct in_addr *)arg; ! 640: else ! 641: in = &((struct icmp *)arg)->icmp_ip.ip_dst; ! 642: /* THIS IS VERY QUESTIONABLE, SHOULD HIT ALL PROTOCOLS */ ! 643: in_pcbnotify(&tcb, in, (int)inetctlerrmap[cmd], tcp_abort); ! 644: in_pcbnotify(&udb, in, (int)inetctlerrmap[cmd], udp_abort); ! 645: } ! 646: ! 647: int ipforwarding = 1; ! 648: /* ! 649: * Forward a packet. If some error occurs return the sender ! 650: * and icmp packet. Note we can't always generate a meaningful ! 651: * icmp message because icmp doesn't have a large enough repetoire ! 652: * of codes and types. ! 653: */ ! 654: ip_forward(ip) ! 655: register struct ip *ip; ! 656: { ! 657: register int error, type, code; ! 658: struct mbuf *mopt, *mcopy; ! 659: ! 660: if (ipprintfs) ! 661: printf("forward: src %x dst %x ttl %x\n", ip->ip_src, ! 662: ip->ip_dst, ip->ip_ttl); ! 663: if (ipforwarding == 0) { ! 664: /* can't tell difference between net and host */ ! 665: IPSTUDY(ipstudy.ips_cantdiffnethost++;) ! 666: type = ICMP_UNREACH, code = ICMP_UNREACH_NET; ! 667: goto sendicmp; ! 668: } ! 669: if (ip->ip_ttl < IPTTLDEC) { ! 670: type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS; ! 671: IPSTUDY(ipstudy.ips_timxceed++;) ! 672: goto sendicmp; ! 673: } ! 674: ip->ip_ttl -= IPTTLDEC; ! 675: mopt = m_get(M_DONTWAIT, MT_DATA); ! 676: MBUFNULL(8, mopt); /* for debugging */ ! 677: if (mopt == NULL) { ! 678: m_freem(dtom(ip)); ! 679: return; ! 680: } ! 681: ! 682: /* ! 683: * Save at most 64 bytes of the packet in case ! 684: * we need to generate an ICMP message to the src. ! 685: */ ! 686: mcopy = m_copy(dtom(ip), 0, imin(ip->ip_len, 64)); ! 687: MBUFNULL(35, mcopy); /* for debugging */ ! 688: ip_stripoptions(ip, mopt); ! 689: ! 690: error = ip_output(dtom(ip), mopt, (struct route *)0, IP_FORWARDING); ! 691: if (error == 0) { ! 692: if (mcopy) ! 693: m_freem(mcopy); ! 694: return; ! 695: } ! 696: if (mcopy == NULL) ! 697: return; ! 698: ip = mtod(mcopy, struct ip *); ! 699: type = ICMP_UNREACH, code = 0; /* need ``undefined'' */ ! 700: switch (error) { ! 701: ! 702: case ENETUNREACH: ! 703: case ENETDOWN: ! 704: IPSTUDY(ipstudy.ips_unreach++;) ! 705: code = ICMP_UNREACH_NET; ! 706: break; ! 707: ! 708: case EMSGSIZE: ! 709: IPSTUDY(ipstudy.ips_msgsize++;) ! 710: code = ICMP_UNREACH_NEEDFRAG; ! 711: break; ! 712: ! 713: case EPERM: ! 714: code = ICMP_UNREACH_PORT; ! 715: IPSTUDY(ipstudy.ips_badport++;) ! 716: break; ! 717: ! 718: case ENOBUFS: ! 719: type = ICMP_SOURCEQUENCH; ! 720: break; ! 721: ! 722: case EHOSTDOWN: ! 723: case EHOSTUNREACH: ! 724: ! 725: IPSTUDY(ipstudy.ips_unreach++;) ! 726: code = ICMP_UNREACH_HOST; ! 727: break; ! 728: } ! 729: sendicmp: ! 730: icmp_error(ip, type, code); ! 731: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.