|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This product includes software developed by the University of ! 16: * California, Berkeley and its contributors. ! 17: * 4. Neither the name of the University nor the names of its contributors ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 31: * SUCH DAMAGE. ! 32: * ! 33: * @(#)ip_output.c 7.23 (Berkeley) 11/12/90 ! 34: */ ! 35: ! 36: #include "param.h" ! 37: #include "malloc.h" ! 38: #include "mbuf.h" ! 39: #include "errno.h" ! 40: #include "protosw.h" ! 41: #include "socket.h" ! 42: #include "socketvar.h" ! 43: ! 44: #include "../net/if.h" ! 45: #include "../net/route.h" ! 46: ! 47: #include "in.h" ! 48: #include "in_systm.h" ! 49: #include "ip.h" ! 50: #include "in_pcb.h" ! 51: #include "in_var.h" ! 52: #include "ip_var.h" ! 53: ! 54: #ifdef vax ! 55: #include "machine/mtpr.h" ! 56: #endif ! 57: ! 58: struct mbuf *ip_insertoptions(); ! 59: ! 60: /* ! 61: * IP output. The packet in mbuf chain m contains a skeletal IP ! 62: * header (with len, off, ttl, proto, tos, src, dst). ! 63: * The mbuf chain containing the packet will be freed. ! 64: * The mbuf opt, if present, will not be freed. ! 65: */ ! 66: ip_output(m0, opt, ro, flags) ! 67: struct mbuf *m0; ! 68: struct mbuf *opt; ! 69: struct route *ro; ! 70: int flags; ! 71: { ! 72: register struct ip *ip, *mhip; ! 73: register struct ifnet *ifp; ! 74: register struct mbuf *m = m0; ! 75: register int hlen = sizeof (struct ip); ! 76: int len, off, error = 0; ! 77: struct route iproute; ! 78: struct sockaddr_in *dst; ! 79: struct in_ifaddr *ia; ! 80: ! 81: #ifdef DIAGNOSTIC ! 82: if ((m->m_flags & M_PKTHDR) == 0) ! 83: panic("ip_output no HDR"); ! 84: #endif ! 85: if (opt) { ! 86: m = ip_insertoptions(m, opt, &len); ! 87: hlen = len; ! 88: } ! 89: ip = mtod(m, struct ip *); ! 90: /* ! 91: * Fill in IP header. ! 92: */ ! 93: if ((flags & IP_FORWARDING) == 0) { ! 94: ip->ip_v = IPVERSION; ! 95: ip->ip_off &= IP_DF; ! 96: ip->ip_id = htons(ip_id++); ! 97: ip->ip_hl = hlen >> 2; ! 98: } else { ! 99: hlen = ip->ip_hl << 2; ! 100: ipstat.ips_localout++; ! 101: } ! 102: /* ! 103: * Route packet. ! 104: */ ! 105: if (ro == 0) { ! 106: ro = &iproute; ! 107: bzero((caddr_t)ro, sizeof (*ro)); ! 108: } ! 109: dst = (struct sockaddr_in *)&ro->ro_dst; ! 110: /* ! 111: * If there is a cached route, ! 112: * check that it is to the same destination ! 113: * and is still up. If not, free it and try again. ! 114: */ ! 115: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || ! 116: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { ! 117: RTFREE(ro->ro_rt); ! 118: ro->ro_rt = (struct rtentry *)0; ! 119: } ! 120: if (ro->ro_rt == 0) { ! 121: dst->sin_family = AF_INET; ! 122: dst->sin_len = sizeof(*dst); ! 123: dst->sin_addr = ip->ip_dst; ! 124: } ! 125: /* ! 126: * If routing to interface only, ! 127: * short circuit routing lookup. ! 128: */ ! 129: if (flags & IP_ROUTETOIF) { ! 130: ! 131: ia = (struct in_ifaddr *)ifa_ifwithdstaddr((struct sockaddr *)dst); ! 132: if (ia == 0) ! 133: ia = in_iaonnetof(in_netof(ip->ip_dst)); ! 134: if (ia == 0) { ! 135: error = ENETUNREACH; ! 136: goto bad; ! 137: } ! 138: ifp = ia->ia_ifp; ! 139: } else { ! 140: if (ro->ro_rt == 0) ! 141: rtalloc(ro); ! 142: if (ro->ro_rt == 0) { ! 143: error = EHOSTUNREACH; ! 144: goto bad; ! 145: } ! 146: ia = (struct in_ifaddr *)ro->ro_rt->rt_ifa; ! 147: ifp = ro->ro_rt->rt_ifp; ! 148: ro->ro_rt->rt_use++; ! 149: if (ro->ro_rt->rt_flags & RTF_GATEWAY) ! 150: dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; ! 151: } ! 152: #ifndef notdef ! 153: /* ! 154: * If source address not specified yet, use address ! 155: * of outgoing interface. ! 156: */ ! 157: if (ip->ip_src.s_addr == INADDR_ANY) ! 158: ip->ip_src = IA_SIN(ia)->sin_addr; ! 159: #endif ! 160: /* ! 161: * Look for broadcast address and ! 162: * and verify user is allowed to send ! 163: * such a packet. ! 164: */ ! 165: if (in_broadcast(dst->sin_addr)) { ! 166: if ((ifp->if_flags & IFF_BROADCAST) == 0) { ! 167: error = EADDRNOTAVAIL; ! 168: goto bad; ! 169: } ! 170: if ((flags & IP_ALLOWBROADCAST) == 0) { ! 171: error = EACCES; ! 172: goto bad; ! 173: } ! 174: /* don't allow broadcast messages to be fragmented */ ! 175: if ((u_short)ip->ip_len > ifp->if_mtu) { ! 176: error = EMSGSIZE; ! 177: goto bad; ! 178: } ! 179: m->m_flags |= M_BCAST; ! 180: } ! 181: ! 182: /* ! 183: * If small enough for interface, can just send directly. ! 184: */ ! 185: if ((u_short)ip->ip_len <= ifp->if_mtu) { ! 186: ip->ip_len = htons((u_short)ip->ip_len); ! 187: ip->ip_off = htons((u_short)ip->ip_off); ! 188: ip->ip_sum = 0; ! 189: ip->ip_sum = in_cksum(m, hlen); ! 190: error = (*ifp->if_output)(ifp, m, ! 191: (struct sockaddr *)dst, ro->ro_rt); ! 192: goto done; ! 193: } ! 194: ipstat.ips_fragmented++; ! 195: /* ! 196: * Too large for interface; fragment if possible. ! 197: * Must be able to put at least 8 bytes per fragment. ! 198: */ ! 199: if (ip->ip_off & IP_DF) { ! 200: error = EMSGSIZE; ! 201: goto bad; ! 202: } ! 203: len = (ifp->if_mtu - hlen) &~ 7; ! 204: if (len < 8) { ! 205: error = EMSGSIZE; ! 206: goto bad; ! 207: } ! 208: ! 209: { ! 210: int mhlen, firstlen = len; ! 211: struct mbuf **mnext = &m->m_nextpkt; ! 212: ! 213: /* ! 214: * Loop through length of segment after first fragment, ! 215: * make new header and copy data of each part and link onto chain. ! 216: */ ! 217: m0 = m; ! 218: mhlen = sizeof (struct ip); ! 219: for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { ! 220: MGETHDR(m, M_DONTWAIT, MT_HEADER); ! 221: if (m == 0) { ! 222: error = ENOBUFS; ! 223: goto sendorfree; ! 224: } ! 225: m->m_data += max_linkhdr; ! 226: mhip = mtod(m, struct ip *); ! 227: *mhip = *ip; ! 228: if (hlen > sizeof (struct ip)) { ! 229: mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); ! 230: mhip->ip_hl = mhlen >> 2; ! 231: } ! 232: m->m_len = mhlen; ! 233: mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); ! 234: if (ip->ip_off & IP_MF) ! 235: mhip->ip_off |= IP_MF; ! 236: if (off + len >= (u_short)ip->ip_len) ! 237: len = (u_short)ip->ip_len - off; ! 238: else ! 239: mhip->ip_off |= IP_MF; ! 240: mhip->ip_len = htons((u_short)(len + mhlen)); ! 241: m->m_next = m_copy(m0, off, len); ! 242: if (m->m_next == 0) { ! 243: error = ENOBUFS; /* ??? */ ! 244: goto sendorfree; ! 245: } ! 246: m->m_pkthdr.len = mhlen + len; ! 247: m->m_pkthdr.rcvif = (struct ifnet *)0; ! 248: mhip->ip_off = htons((u_short)mhip->ip_off); ! 249: mhip->ip_sum = 0; ! 250: mhip->ip_sum = in_cksum(m, mhlen); ! 251: *mnext = m; ! 252: mnext = &m->m_nextpkt; ! 253: ipstat.ips_ofragments++; ! 254: } ! 255: /* ! 256: * Update first fragment by trimming what's been copied out ! 257: * and updating header, then send each fragment (in order). ! 258: */ ! 259: m = m0; ! 260: m_adj(m, hlen + firstlen - (u_short)ip->ip_len); ! 261: m->m_pkthdr.len = hlen + firstlen; ! 262: ip->ip_len = htons((u_short)m->m_pkthdr.len); ! 263: ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); ! 264: ip->ip_sum = 0; ! 265: ip->ip_sum = in_cksum(m, hlen); ! 266: sendorfree: ! 267: for (m = m0; m; m = m0) { ! 268: m0 = m->m_nextpkt; ! 269: m->m_nextpkt = 0; ! 270: if (error == 0) ! 271: error = (*ifp->if_output)(ifp, m, ! 272: (struct sockaddr *)dst, ro->ro_rt); ! 273: else ! 274: m_freem(m); ! 275: } ! 276: } ! 277: done: ! 278: if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) ! 279: RTFREE(ro->ro_rt); ! 280: return (error); ! 281: bad: ! 282: m_freem(m0); ! 283: goto done; ! 284: } ! 285: ! 286: /* ! 287: * Insert IP options into preformed packet. ! 288: * Adjust IP destination as required for IP source routing, ! 289: * as indicated by a non-zero in_addr at the start of the options. ! 290: */ ! 291: struct mbuf * ! 292: ip_insertoptions(m, opt, phlen) ! 293: register struct mbuf *m; ! 294: struct mbuf *opt; ! 295: int *phlen; ! 296: { ! 297: register struct ipoption *p = mtod(opt, struct ipoption *); ! 298: struct mbuf *n; ! 299: register struct ip *ip = mtod(m, struct ip *); ! 300: unsigned optlen; ! 301: ! 302: optlen = opt->m_len - sizeof(p->ipopt_dst); ! 303: if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) ! 304: return (m); /* XXX should fail */ ! 305: if (p->ipopt_dst.s_addr) ! 306: ip->ip_dst = p->ipopt_dst; ! 307: if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { ! 308: MGETHDR(n, M_DONTWAIT, MT_HEADER); ! 309: if (n == 0) ! 310: return (m); ! 311: n->m_pkthdr.len = m->m_pkthdr.len + optlen; ! 312: m->m_len -= sizeof(struct ip); ! 313: m->m_data += sizeof(struct ip); ! 314: n->m_next = m; ! 315: m = n; ! 316: m->m_len = optlen + sizeof(struct ip); ! 317: m->m_data += max_linkhdr; ! 318: bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); ! 319: } else { ! 320: m->m_data -= optlen; ! 321: m->m_len += optlen; ! 322: m->m_pkthdr.len += optlen; ! 323: ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); ! 324: } ! 325: ip = mtod(m, struct ip *); ! 326: bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); ! 327: *phlen = sizeof(struct ip) + optlen; ! 328: ip->ip_len += optlen; ! 329: return (m); ! 330: } ! 331: ! 332: /* ! 333: * Copy options from ip to jp, ! 334: * omitting those not copied during fragmentation. ! 335: */ ! 336: ip_optcopy(ip, jp) ! 337: struct ip *ip, *jp; ! 338: { ! 339: register u_char *cp, *dp; ! 340: int opt, optlen, cnt; ! 341: ! 342: cp = (u_char *)(ip + 1); ! 343: dp = (u_char *)(jp + 1); ! 344: cnt = (ip->ip_hl << 2) - sizeof (struct ip); ! 345: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 346: opt = cp[0]; ! 347: if (opt == IPOPT_EOL) ! 348: break; ! 349: if (opt == IPOPT_NOP) ! 350: optlen = 1; ! 351: else ! 352: optlen = cp[IPOPT_OLEN]; ! 353: /* bogus lengths should have been caught by ip_dooptions */ ! 354: if (optlen > cnt) ! 355: optlen = cnt; ! 356: if (IPOPT_COPIED(opt)) { ! 357: bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); ! 358: dp += optlen; ! 359: } ! 360: } ! 361: for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) ! 362: *dp++ = IPOPT_EOL; ! 363: return (optlen); ! 364: } ! 365: ! 366: /* ! 367: * IP socket option processing. ! 368: */ ! 369: ip_ctloutput(op, so, level, optname, mp) ! 370: int op; ! 371: struct socket *so; ! 372: int level, optname; ! 373: struct mbuf **mp; ! 374: { ! 375: register struct inpcb *inp = sotoinpcb(so); ! 376: register struct mbuf *m = *mp; ! 377: register int optval; ! 378: int error = 0; ! 379: ! 380: if (level != IPPROTO_IP) ! 381: error = EINVAL; ! 382: else switch (op) { ! 383: ! 384: case PRCO_SETOPT: ! 385: switch (optname) { ! 386: case IP_OPTIONS: ! 387: #ifdef notyet ! 388: case IP_RETOPTS: ! 389: return (ip_pcbopts(optname, &inp->inp_options, m)); ! 390: #else ! 391: return (ip_pcbopts(&inp->inp_options, m)); ! 392: #endif ! 393: ! 394: case IP_TOS: ! 395: case IP_TTL: ! 396: case IP_RECVOPTS: ! 397: case IP_RECVRETOPTS: ! 398: case IP_RECVDSTADDR: ! 399: if (m->m_len != sizeof(int)) ! 400: error = EINVAL; ! 401: else { ! 402: optval = *mtod(m, int *); ! 403: switch (optname) { ! 404: ! 405: case IP_TOS: ! 406: inp->inp_ip.ip_tos = optval; ! 407: break; ! 408: ! 409: case IP_TTL: ! 410: inp->inp_ip.ip_ttl = optval; ! 411: break; ! 412: #define OPTSET(bit) \ ! 413: if (optval) \ ! 414: inp->inp_flags |= bit; \ ! 415: else \ ! 416: inp->inp_flags &= ~bit; ! 417: ! 418: case IP_RECVOPTS: ! 419: OPTSET(INP_RECVOPTS); ! 420: break; ! 421: ! 422: case IP_RECVRETOPTS: ! 423: OPTSET(INP_RECVRETOPTS); ! 424: break; ! 425: ! 426: case IP_RECVDSTADDR: ! 427: OPTSET(INP_RECVDSTADDR); ! 428: break; ! 429: } ! 430: } ! 431: break; ! 432: #undef OPTSET ! 433: ! 434: default: ! 435: error = EINVAL; ! 436: break; ! 437: } ! 438: if (m) ! 439: (void)m_free(m); ! 440: break; ! 441: ! 442: case PRCO_GETOPT: ! 443: switch (optname) { ! 444: case IP_OPTIONS: ! 445: case IP_RETOPTS: ! 446: *mp = m = m_get(M_WAIT, MT_SOOPTS); ! 447: if (inp->inp_options) { ! 448: m->m_len = inp->inp_options->m_len; ! 449: bcopy(mtod(inp->inp_options, caddr_t), ! 450: mtod(m, caddr_t), (unsigned)m->m_len); ! 451: } else ! 452: m->m_len = 0; ! 453: break; ! 454: ! 455: case IP_TOS: ! 456: case IP_TTL: ! 457: case IP_RECVOPTS: ! 458: case IP_RECVRETOPTS: ! 459: case IP_RECVDSTADDR: ! 460: *mp = m = m_get(M_WAIT, MT_SOOPTS); ! 461: m->m_len = sizeof(int); ! 462: switch (optname) { ! 463: ! 464: case IP_TOS: ! 465: optval = inp->inp_ip.ip_tos; ! 466: break; ! 467: ! 468: case IP_TTL: ! 469: optval = inp->inp_ip.ip_ttl; ! 470: break; ! 471: ! 472: #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) ! 473: ! 474: case IP_RECVOPTS: ! 475: optval = OPTBIT(INP_RECVOPTS); ! 476: break; ! 477: ! 478: case IP_RECVRETOPTS: ! 479: optval = OPTBIT(INP_RECVRETOPTS); ! 480: break; ! 481: ! 482: case IP_RECVDSTADDR: ! 483: optval = OPTBIT(INP_RECVDSTADDR); ! 484: break; ! 485: } ! 486: *mtod(m, int *) = optval; ! 487: break; ! 488: ! 489: default: ! 490: error = EINVAL; ! 491: break; ! 492: } ! 493: break; ! 494: } ! 495: return (error); ! 496: } ! 497: ! 498: /* ! 499: * Set up IP options in pcb for insertion in output packets. ! 500: * Store in mbuf with pointer in pcbopt, adding pseudo-option ! 501: * with destination address if source routed. ! 502: */ ! 503: #ifdef notyet ! 504: ip_pcbopts(optname, pcbopt, m) ! 505: int optname; ! 506: #else ! 507: ip_pcbopts(pcbopt, m) ! 508: #endif ! 509: struct mbuf **pcbopt; ! 510: register struct mbuf *m; ! 511: { ! 512: register cnt, optlen; ! 513: register u_char *cp; ! 514: u_char opt; ! 515: ! 516: /* turn off any old options */ ! 517: if (*pcbopt) ! 518: (void)m_free(*pcbopt); ! 519: *pcbopt = 0; ! 520: if (m == (struct mbuf *)0 || m->m_len == 0) { ! 521: /* ! 522: * Only turning off any previous options. ! 523: */ ! 524: if (m) ! 525: (void)m_free(m); ! 526: return (0); ! 527: } ! 528: ! 529: #ifndef vax ! 530: if (m->m_len % sizeof(long)) ! 531: goto bad; ! 532: #endif ! 533: /* ! 534: * IP first-hop destination address will be stored before ! 535: * actual options; move other options back ! 536: * and clear it when none present. ! 537: */ ! 538: if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) ! 539: goto bad; ! 540: cnt = m->m_len; ! 541: m->m_len += sizeof(struct in_addr); ! 542: cp = mtod(m, u_char *) + sizeof(struct in_addr); ! 543: ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); ! 544: bzero(mtod(m, caddr_t), sizeof(struct in_addr)); ! 545: ! 546: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 547: opt = cp[IPOPT_OPTVAL]; ! 548: if (opt == IPOPT_EOL) ! 549: break; ! 550: if (opt == IPOPT_NOP) ! 551: optlen = 1; ! 552: else { ! 553: optlen = cp[IPOPT_OLEN]; ! 554: if (optlen <= IPOPT_OLEN || optlen > cnt) ! 555: goto bad; ! 556: } ! 557: switch (opt) { ! 558: ! 559: default: ! 560: break; ! 561: ! 562: case IPOPT_LSRR: ! 563: case IPOPT_SSRR: ! 564: /* ! 565: * user process specifies route as: ! 566: * ->A->B->C->D ! 567: * D must be our final destination (but we can't ! 568: * check that since we may not have connected yet). ! 569: * A is first hop destination, which doesn't appear in ! 570: * actual IP option, but is stored before the options. ! 571: */ ! 572: if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) ! 573: goto bad; ! 574: m->m_len -= sizeof(struct in_addr); ! 575: cnt -= sizeof(struct in_addr); ! 576: optlen -= sizeof(struct in_addr); ! 577: cp[IPOPT_OLEN] = optlen; ! 578: /* ! 579: * Move first hop before start of options. ! 580: */ ! 581: bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), ! 582: sizeof(struct in_addr)); ! 583: /* ! 584: * Then copy rest of options back ! 585: * to close up the deleted entry. ! 586: */ ! 587: ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + ! 588: sizeof(struct in_addr)), ! 589: (caddr_t)&cp[IPOPT_OFFSET+1], ! 590: (unsigned)cnt + sizeof(struct in_addr)); ! 591: break; ! 592: } ! 593: } ! 594: if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) ! 595: goto bad; ! 596: *pcbopt = m; ! 597: return (0); ! 598: ! 599: bad: ! 600: (void)m_free(m); ! 601: return (EINVAL); ! 602: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.