|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1988, 1990, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 ! 59: */ ! 60: ! 61: #include <sys/param.h> ! 62: #include <sys/malloc.h> ! 63: #include <sys/mbuf.h> ! 64: #include <sys/errno.h> ! 65: #include <sys/protosw.h> ! 66: #include <sys/socket.h> ! 67: #include <sys/socketvar.h> ! 68: ! 69: #include <kernserv/machine/spl.h> ! 70: ! 71: #include <net/if.h> ! 72: #include <net/route.h> ! 73: ! 74: #include <netinet/in.h> ! 75: #include <netinet/in_systm.h> ! 76: #include <netinet/ip.h> ! 77: #include <netinet/in_pcb.h> ! 78: #include <netinet/in_var.h> ! 79: #include <netinet/ip_var.h> ! 80: ! 81: #if NEXT ! 82: #import <kern/kdebug.h> ! 83: ! 84: #if KDEBUG ! 85: ! 86: #define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIP, 1) ! 87: #define DBG_LAYER_END NETDBG_CODE(DBG_NETIP, 3) ! 88: #define DBG_FNC_IP_OUTPUT NETDBG_CODE(DBG_NETIP, (1 << 8) | 1) ! 89: #endif ! 90: ! 91: #endif ! 92: ! 93: #ifdef vax ! 94: #include <machine/mtpr.h> ! 95: #endif ! 96: ! 97: static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); ! 98: static void ip_mloopback ! 99: __P((struct ifnet *, struct mbuf *, struct sockaddr_in *)); ! 100: ! 101: /* ! 102: * IP output. The packet in mbuf chain m contains a skeletal IP ! 103: * header (with len, off, ttl, proto, tos, src, dst). ! 104: * The mbuf chain containing the packet will be freed. ! 105: * The mbuf opt, if present, will not be freed. ! 106: */ ! 107: int ! 108: ip_output(m0, opt, ro, flags, imo) ! 109: struct mbuf *m0; ! 110: struct mbuf *opt; ! 111: struct route *ro; ! 112: int flags; ! 113: struct ip_moptions *imo; ! 114: { ! 115: register struct ip *ip, *mhip; ! 116: register struct ifnet *ifp; ! 117: register struct mbuf *m = m0; ! 118: register int hlen = sizeof (struct ip); ! 119: int len, off, error = 0; ! 120: struct route iproute; ! 121: struct sockaddr_in *dst; ! 122: struct in_ifaddr *ia; ! 123: ! 124: ! 125: KERNEL_DEBUG(DBG_FNC_IP_OUTPUT | DBG_FUNC_START, 0,0,0,0,0); ! 126: ! 127: #if DIAGNOSTIC ! 128: if ((m->m_flags & M_PKTHDR) == 0) ! 129: panic("ip_output no HDR"); ! 130: #endif ! 131: if (opt) { ! 132: m = ip_insertoptions(m, opt, &len); ! 133: hlen = len; ! 134: } ! 135: ip = mtod(m, struct ip *); ! 136: /* ! 137: * Fill in IP header. ! 138: */ ! 139: if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { ! 140: ip->ip_v = IPVERSION; ! 141: ip->ip_off &= IP_DF; ! 142: ip->ip_id = htons(ip_id++); ! 143: ip->ip_hl = hlen >> 2; ! 144: ipstat.ips_localout++; ! 145: } else { ! 146: hlen = ip->ip_hl << 2; ! 147: } ! 148: ! 149: ! 150: ! 151: KERNEL_DEBUG(DBG_LAYER_BEG, ip->ip_dst.s_addr, ! 152: ip->ip_src.s_addr, ip->ip_p, ip->ip_off, ip->ip_len); ! 153: ! 154: /* ! 155: * Route packet. ! 156: */ ! 157: if (ro == 0) { ! 158: ro = &iproute; ! 159: bzero((caddr_t)ro, sizeof (*ro)); ! 160: } ! 161: dst = (struct sockaddr_in *)&ro->ro_dst; ! 162: /* ! 163: * If there is a cached route, ! 164: * check that it is to the same destination ! 165: * and is still up. If not, free it and try again. ! 166: */ ! 167: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || ! 168: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { ! 169: RTFREE(ro->ro_rt); ! 170: ro->ro_rt = (struct rtentry *)0; ! 171: } ! 172: if (ro->ro_rt == 0) { ! 173: dst->sin_family = AF_INET; ! 174: dst->sin_len = sizeof(*dst); ! 175: dst->sin_addr = ip->ip_dst; ! 176: } ! 177: /* ! 178: * If routing to interface only, ! 179: * short circuit routing lookup. ! 180: */ ! 181: #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) ! 182: #define sintosa(sin) ((struct sockaddr *)(sin)) ! 183: if (flags & IP_ROUTETOIF) { ! 184: if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 && ! 185: (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) { ! 186: ipstat.ips_noroute++; ! 187: error = ENETUNREACH; ! 188: goto bad; ! 189: } ! 190: ifp = ia->ia_ifp; ! 191: ip->ip_ttl = 1; ! 192: } else { ! 193: if (ro->ro_rt == 0) ! 194: rtalloc(ro); ! 195: if (ro->ro_rt == 0) { ! 196: ipstat.ips_noroute++; ! 197: error = EHOSTUNREACH; ! 198: goto bad; ! 199: } ! 200: ia = ifatoia(ro->ro_rt->rt_ifa); ! 201: ifp = ro->ro_rt->rt_ifp; ! 202: ro->ro_rt->rt_use++; ! 203: if (ro->ro_rt->rt_flags & RTF_GATEWAY) ! 204: dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; ! 205: } ! 206: if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { ! 207: struct in_multi *inm; ! 208: extern struct ifnet loif; ! 209: ! 210: m->m_flags |= M_MCAST; ! 211: /* ! 212: * IP destination address is multicast. Make sure "dst" ! 213: * still points to the address in "ro". (It may have been ! 214: * changed to point to a gateway address, above.) ! 215: */ ! 216: dst = (struct sockaddr_in *)&ro->ro_dst; ! 217: /* ! 218: * See if the caller provided any multicast options ! 219: */ ! 220: if (imo != NULL) { ! 221: ip->ip_ttl = imo->imo_multicast_ttl; ! 222: if (imo->imo_multicast_ifp != NULL) ! 223: ifp = imo->imo_multicast_ifp; ! 224: } else ! 225: ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; ! 226: /* ! 227: * Confirm that the outgoing interface supports multicast. ! 228: */ ! 229: if ((ifp->if_flags & IFF_MULTICAST) == 0) { ! 230: ipstat.ips_noroute++; ! 231: error = ENETUNREACH; ! 232: goto bad; ! 233: } ! 234: /* ! 235: * If source address not specified yet, use address ! 236: * of outgoing interface. ! 237: */ ! 238: if (ip->ip_src.s_addr == INADDR_ANY) { ! 239: register struct in_ifaddr *ia; ! 240: ! 241: for (ia = in_ifaddr; ia; ia = ia->ia_next) ! 242: if (ia->ia_ifp == ifp) { ! 243: ip->ip_src = IA_SIN(ia)->sin_addr; ! 244: break; ! 245: } ! 246: } ! 247: ! 248: IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm); ! 249: if (inm != NULL && ! 250: (imo == NULL || imo->imo_multicast_loop)) { ! 251: /* ! 252: * If we belong to the destination multicast group ! 253: * on the outgoing interface, and the caller did not ! 254: * forbid loopback, loop back a copy. ! 255: */ ! 256: ip_mloopback(ifp, m, dst); ! 257: } ! 258: #if MROUTING ! 259: else { ! 260: /* ! 261: * If we are acting as a multicast router, perform ! 262: * multicast forwarding as if the packet had just ! 263: * arrived on the interface to which we are about ! 264: * to send. The multicast forwarding function ! 265: * recursively calls this function, using the ! 266: * IP_FORWARDING flag to prevent infinite recursion. ! 267: * ! 268: * Multicasts that are looped back by ip_mloopback(), ! 269: * above, will be forwarded by the ip_input() routine, ! 270: * if necessary. ! 271: */ ! 272: extern struct socket *ip_mrouter; ! 273: if (ip_mrouter && (flags & IP_FORWARDING) == 0) { ! 274: if (ip_mforward(m, ifp) != 0) { ! 275: m_freem(m); ! 276: goto done; ! 277: } ! 278: } ! 279: } ! 280: #endif ! 281: /* ! 282: * Multicasts with a time-to-live of zero may be looped- ! 283: * back, above, but must not be transmitted on a network. ! 284: * Also, multicasts addressed to the loopback interface ! 285: * are not sent -- the above call to ip_mloopback() will ! 286: * loop back a copy if this host actually belongs to the ! 287: * destination group on the loopback interface. ! 288: */ ! 289: if (ip->ip_ttl == 0 || ifp == &loif) { ! 290: m_freem(m); ! 291: goto done; ! 292: } ! 293: ! 294: goto sendit; ! 295: } ! 296: #ifndef notdef ! 297: /* ! 298: * If source address not specified yet, use address ! 299: * of outgoing interface. ! 300: */ ! 301: if (ip->ip_src.s_addr == INADDR_ANY) ! 302: ip->ip_src = IA_SIN(ia)->sin_addr; ! 303: #endif ! 304: /* ! 305: * Look for broadcast address and ! 306: * and verify user is allowed to send ! 307: * such a packet. ! 308: */ ! 309: if (in_broadcast(dst->sin_addr, ifp)) { ! 310: if ((ifp->if_flags & IFF_BROADCAST) == 0) { ! 311: error = EADDRNOTAVAIL; ! 312: goto bad; ! 313: } ! 314: if ((flags & IP_ALLOWBROADCAST) == 0) { ! 315: error = EACCES; ! 316: goto bad; ! 317: } ! 318: /* don't allow broadcast messages to be fragmented */ ! 319: if ((u_short)ip->ip_len > ifp->if_mtu) { ! 320: error = EMSGSIZE; ! 321: goto bad; ! 322: } ! 323: m->m_flags |= M_BCAST; ! 324: } else ! 325: m->m_flags &= ~M_BCAST; ! 326: ! 327: sendit: ! 328: /* ! 329: * If small enough for interface, can just send directly. ! 330: */ ! 331: if ((u_short)ip->ip_len <= ifp->if_mtu) { ! 332: ip->ip_len = htons((u_short)ip->ip_len); ! 333: ip->ip_off = htons((u_short)ip->ip_off); ! 334: ip->ip_sum = 0; ! 335: ip->ip_sum = in_cksum(m, hlen); ! 336: error = (*ifp->if_output)(ifp, m, ! 337: (struct sockaddr *)dst, ro->ro_rt); ! 338: goto done; ! 339: } ! 340: /* ! 341: * Too large for interface; fragment if possible. ! 342: * Must be able to put at least 8 bytes per fragment. ! 343: */ ! 344: if (ip->ip_off & IP_DF) { ! 345: error = EMSGSIZE; ! 346: ipstat.ips_cantfrag++; ! 347: goto bad; ! 348: } ! 349: len = (ifp->if_mtu - hlen) &~ 7; ! 350: if (len < 8) { ! 351: error = EMSGSIZE; ! 352: goto bad; ! 353: } ! 354: ! 355: { ! 356: int mhlen, firstlen = len; ! 357: struct mbuf **mnext = &m->m_nextpkt; ! 358: ! 359: /* ! 360: * Loop through length of segment after first fragment, ! 361: * make new header and copy data of each part and link onto chain. ! 362: */ ! 363: m0 = m; ! 364: mhlen = sizeof (struct ip); ! 365: for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { ! 366: MGETHDR(m, M_DONTWAIT, MT_HEADER); ! 367: if (m == 0) { ! 368: error = ENOBUFS; ! 369: ipstat.ips_odropped++; ! 370: goto sendorfree; ! 371: } ! 372: m->m_data += max_linkhdr; ! 373: mhip = mtod(m, struct ip *); ! 374: *mhip = *ip; ! 375: if (hlen > sizeof (struct ip)) { ! 376: mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); ! 377: mhip->ip_hl = mhlen >> 2; ! 378: } ! 379: m->m_len = mhlen; ! 380: mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); ! 381: if (ip->ip_off & IP_MF) ! 382: mhip->ip_off |= IP_MF; ! 383: if (off + len >= (u_short)ip->ip_len) ! 384: len = (u_short)ip->ip_len - off; ! 385: else ! 386: mhip->ip_off |= IP_MF; ! 387: mhip->ip_len = htons((u_short)(len + mhlen)); ! 388: m->m_next = m_copy(m0, off, len); ! 389: if (m->m_next == 0) { ! 390: (void) m_free(m); ! 391: error = ENOBUFS; /* ??? */ ! 392: ipstat.ips_odropped++; ! 393: goto sendorfree; ! 394: } ! 395: m->m_pkthdr.len = mhlen + len; ! 396: m->m_pkthdr.rcvif = (struct ifnet *)0; ! 397: mhip->ip_off = htons((u_short)mhip->ip_off); ! 398: mhip->ip_sum = 0; ! 399: mhip->ip_sum = in_cksum(m, mhlen); ! 400: *mnext = m; ! 401: mnext = &m->m_nextpkt; ! 402: ipstat.ips_ofragments++; ! 403: } ! 404: /* ! 405: * Update first fragment by trimming what's been copied out ! 406: * and updating header, then send each fragment (in order). ! 407: */ ! 408: m = m0; ! 409: m_adj(m, hlen + firstlen - (u_short)ip->ip_len); ! 410: m->m_pkthdr.len = hlen + firstlen; ! 411: ip->ip_len = htons((u_short)m->m_pkthdr.len); ! 412: ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); ! 413: ip->ip_sum = 0; ! 414: ip->ip_sum = in_cksum(m, hlen); ! 415: sendorfree: ! 416: ! 417: KERNEL_DEBUG(DBG_LAYER_END, ip->ip_dst.s_addr, ! 418: ip->ip_src.s_addr, ip->ip_p, ip->ip_off, ip->ip_len); ! 419: ! 420: for (m = m0; m; m = m0) { ! 421: m0 = m->m_nextpkt; ! 422: m->m_nextpkt = 0; ! 423: if (error == 0) ! 424: error = (*ifp->if_output)(ifp, m, ! 425: (struct sockaddr *)dst, ro->ro_rt); ! 426: else ! 427: m_freem(m); ! 428: } ! 429: ! 430: if (error == 0) ! 431: ipstat.ips_fragmented++; ! 432: } ! 433: done: ! 434: if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) ! 435: RTFREE(ro->ro_rt); ! 436: ! 437: KERNEL_DEBUG(DBG_FNC_IP_OUTPUT | DBG_FUNC_END, 0,0,0,0,0); ! 438: ! 439: return (error); ! 440: bad: ! 441: m_freem(m0); ! 442: goto done; ! 443: KERNEL_DEBUG(DBG_FNC_IP_OUTPUT | DBG_FUNC_END, 0,0,0,0,0); ! 444: } ! 445: ! 446: /* ! 447: * Insert IP options into preformed packet. ! 448: * Adjust IP destination as required for IP source routing, ! 449: * as indicated by a non-zero in_addr at the start of the options. ! 450: */ ! 451: static struct mbuf * ! 452: ip_insertoptions(m, opt, phlen) ! 453: register struct mbuf *m; ! 454: struct mbuf *opt; ! 455: int *phlen; ! 456: { ! 457: register struct ipoption *p = mtod(opt, struct ipoption *); ! 458: struct mbuf *n; ! 459: register struct ip *ip = mtod(m, struct ip *); ! 460: unsigned optlen; ! 461: ! 462: optlen = opt->m_len - sizeof(p->ipopt_dst); ! 463: if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) ! 464: return (m); /* XXX should fail */ ! 465: if (p->ipopt_dst.s_addr) ! 466: ip->ip_dst = p->ipopt_dst; ! 467: if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { ! 468: MGETHDR(n, M_DONTWAIT, MT_HEADER); ! 469: if (n == 0) ! 470: return (m); ! 471: n->m_pkthdr.len = m->m_pkthdr.len + optlen; ! 472: m->m_len -= sizeof(struct ip); ! 473: m->m_data += sizeof(struct ip); ! 474: n->m_next = m; ! 475: m = n; ! 476: m->m_len = optlen + sizeof(struct ip); ! 477: m->m_data += max_linkhdr; ! 478: bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); ! 479: } else { ! 480: m->m_data -= optlen; ! 481: m->m_len += optlen; ! 482: m->m_pkthdr.len += optlen; ! 483: ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); ! 484: } ! 485: ip = mtod(m, struct ip *); ! 486: bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); ! 487: *phlen = sizeof(struct ip) + optlen; ! 488: ip->ip_len += optlen; ! 489: return (m); ! 490: } ! 491: ! 492: /* ! 493: * Copy options from ip to jp, ! 494: * omitting those not copied during fragmentation. ! 495: */ ! 496: int ! 497: ip_optcopy(ip, jp) ! 498: struct ip *ip, *jp; ! 499: { ! 500: register u_char *cp, *dp; ! 501: int opt, optlen, cnt; ! 502: ! 503: cp = (u_char *)(ip + 1); ! 504: dp = (u_char *)(jp + 1); ! 505: cnt = (ip->ip_hl << 2) - sizeof (struct ip); ! 506: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 507: opt = cp[0]; ! 508: if (opt == IPOPT_EOL) ! 509: break; ! 510: if (opt == IPOPT_NOP) { ! 511: /* Preserve for IP mcast tunnel's LSRR alignment. */ ! 512: *dp++ = IPOPT_NOP; ! 513: optlen = 1; ! 514: continue; ! 515: } else ! 516: optlen = cp[IPOPT_OLEN]; ! 517: /* bogus lengths should have been caught by ip_dooptions */ ! 518: if (optlen > cnt) ! 519: optlen = cnt; ! 520: if (IPOPT_COPIED(opt)) { ! 521: bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); ! 522: dp += optlen; ! 523: } ! 524: } ! 525: for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) ! 526: *dp++ = IPOPT_EOL; ! 527: return (optlen); ! 528: } ! 529: ! 530: /* ! 531: * IP socket option processing. ! 532: */ ! 533: int ! 534: ip_ctloutput(op, so, level, optname, mp) ! 535: int op; ! 536: struct socket *so; ! 537: int level, optname; ! 538: struct mbuf **mp; ! 539: { ! 540: register struct inpcb *inp = sotoinpcb(so); ! 541: register struct mbuf *m = *mp; ! 542: register int optval; ! 543: int error = 0; ! 544: ! 545: if (level != IPPROTO_IP) { ! 546: error = EINVAL; ! 547: if (op == PRCO_SETOPT && *mp) ! 548: (void) m_free(*mp); ! 549: } else switch (op) { ! 550: ! 551: case PRCO_SETOPT: ! 552: switch (optname) { ! 553: case IP_OPTIONS: ! 554: #ifdef notyet ! 555: case IP_RETOPTS: ! 556: return (ip_pcbopts(optname, &inp->inp_options, m)); ! 557: #else ! 558: return (ip_pcbopts(&inp->inp_options, m)); ! 559: #endif ! 560: ! 561: case IP_TOS: ! 562: case IP_TTL: ! 563: case IP_RECVOPTS: ! 564: case IP_RECVRETOPTS: ! 565: case IP_RECVDSTADDR: ! 566: if (m->m_len != sizeof(int)) ! 567: error = EINVAL; ! 568: else { ! 569: optval = *mtod(m, int *); ! 570: switch (optname) { ! 571: ! 572: case IP_TOS: ! 573: inp->inp_ip.ip_tos = optval; ! 574: break; ! 575: ! 576: case IP_TTL: ! 577: inp->inp_ip.ip_ttl = optval; ! 578: break; ! 579: #define OPTSET(bit) \ ! 580: if (optval) \ ! 581: inp->inp_flags |= bit; \ ! 582: else \ ! 583: inp->inp_flags &= ~bit; ! 584: ! 585: case IP_RECVOPTS: ! 586: OPTSET(INP_RECVOPTS); ! 587: break; ! 588: ! 589: case IP_RECVRETOPTS: ! 590: OPTSET(INP_RECVRETOPTS); ! 591: break; ! 592: ! 593: case IP_RECVDSTADDR: ! 594: OPTSET(INP_RECVDSTADDR); ! 595: break; ! 596: } ! 597: } ! 598: break; ! 599: #undef OPTSET ! 600: ! 601: case IP_MULTICAST_IF: ! 602: case IP_MULTICAST_TTL: ! 603: case IP_MULTICAST_LOOP: ! 604: case IP_ADD_MEMBERSHIP: ! 605: case IP_DROP_MEMBERSHIP: ! 606: error = ip_setmoptions(optname, &inp->inp_moptions, m); ! 607: break; ! 608: ! 609: default: ! 610: error = ENOPROTOOPT; ! 611: break; ! 612: } ! 613: if (m) ! 614: (void)m_free(m); ! 615: break; ! 616: ! 617: case PRCO_GETOPT: ! 618: switch (optname) { ! 619: case IP_OPTIONS: ! 620: case IP_RETOPTS: ! 621: *mp = m = m_get(M_WAIT, MT_SOOPTS); ! 622: if (inp->inp_options) { ! 623: m->m_len = inp->inp_options->m_len; ! 624: bcopy(mtod(inp->inp_options, caddr_t), ! 625: mtod(m, caddr_t), (unsigned)m->m_len); ! 626: } else ! 627: m->m_len = 0; ! 628: break; ! 629: ! 630: case IP_TOS: ! 631: case IP_TTL: ! 632: case IP_RECVOPTS: ! 633: case IP_RECVRETOPTS: ! 634: case IP_RECVDSTADDR: ! 635: *mp = m = m_get(M_WAIT, MT_SOOPTS); ! 636: m->m_len = sizeof(int); ! 637: switch (optname) { ! 638: ! 639: case IP_TOS: ! 640: optval = inp->inp_ip.ip_tos; ! 641: break; ! 642: ! 643: case IP_TTL: ! 644: optval = inp->inp_ip.ip_ttl; ! 645: break; ! 646: ! 647: #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) ! 648: ! 649: case IP_RECVOPTS: ! 650: optval = OPTBIT(INP_RECVOPTS); ! 651: break; ! 652: ! 653: case IP_RECVRETOPTS: ! 654: optval = OPTBIT(INP_RECVRETOPTS); ! 655: break; ! 656: ! 657: case IP_RECVDSTADDR: ! 658: optval = OPTBIT(INP_RECVDSTADDR); ! 659: break; ! 660: } ! 661: *mtod(m, int *) = optval; ! 662: break; ! 663: ! 664: case IP_MULTICAST_IF: ! 665: case IP_MULTICAST_TTL: ! 666: case IP_MULTICAST_LOOP: ! 667: case IP_ADD_MEMBERSHIP: ! 668: case IP_DROP_MEMBERSHIP: ! 669: error = ip_getmoptions(optname, inp->inp_moptions, mp); ! 670: break; ! 671: ! 672: default: ! 673: error = ENOPROTOOPT; ! 674: break; ! 675: } ! 676: break; ! 677: } ! 678: return (error); ! 679: } ! 680: ! 681: /* ! 682: * Set up IP options in pcb for insertion in output packets. ! 683: * Store in mbuf with pointer in pcbopt, adding pseudo-option ! 684: * with destination address if source routed. ! 685: */ ! 686: int ! 687: #ifdef notyet ! 688: ip_pcbopts(optname, pcbopt, m) ! 689: int optname; ! 690: #else ! 691: ip_pcbopts(pcbopt, m) ! 692: #endif ! 693: struct mbuf **pcbopt; ! 694: register struct mbuf *m; ! 695: { ! 696: register cnt, optlen; ! 697: register u_char *cp; ! 698: u_char opt; ! 699: ! 700: /* turn off any old options */ ! 701: if (*pcbopt) ! 702: (void)m_free(*pcbopt); ! 703: *pcbopt = 0; ! 704: if (m == (struct mbuf *)0 || m->m_len == 0) { ! 705: /* ! 706: * Only turning off any previous options. ! 707: */ ! 708: if (m) ! 709: (void)m_free(m); ! 710: return (0); ! 711: } ! 712: ! 713: #ifndef vax ! 714: if (m->m_len % sizeof(long)) ! 715: goto bad; ! 716: #endif ! 717: /* ! 718: * IP first-hop destination address will be stored before ! 719: * actual options; move other options back ! 720: * and clear it when none present. ! 721: */ ! 722: if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) ! 723: goto bad; ! 724: cnt = m->m_len; ! 725: m->m_len += sizeof(struct in_addr); ! 726: cp = mtod(m, u_char *) + sizeof(struct in_addr); ! 727: ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); ! 728: bzero(mtod(m, caddr_t), sizeof(struct in_addr)); ! 729: ! 730: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 731: opt = cp[IPOPT_OPTVAL]; ! 732: if (opt == IPOPT_EOL) ! 733: break; ! 734: if (opt == IPOPT_NOP) ! 735: optlen = 1; ! 736: else { ! 737: optlen = cp[IPOPT_OLEN]; ! 738: if (optlen <= IPOPT_OLEN || optlen > cnt) ! 739: goto bad; ! 740: } ! 741: switch (opt) { ! 742: ! 743: default: ! 744: break; ! 745: ! 746: case IPOPT_LSRR: ! 747: case IPOPT_SSRR: ! 748: /* ! 749: * user process specifies route as: ! 750: * ->A->B->C->D ! 751: * D must be our final destination (but we can't ! 752: * check that since we may not have connected yet). ! 753: * A is first hop destination, which doesn't appear in ! 754: * actual IP option, but is stored before the options. ! 755: */ ! 756: if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) ! 757: goto bad; ! 758: m->m_len -= sizeof(struct in_addr); ! 759: cnt -= sizeof(struct in_addr); ! 760: optlen -= sizeof(struct in_addr); ! 761: cp[IPOPT_OLEN] = optlen; ! 762: /* ! 763: * Move first hop before start of options. ! 764: */ ! 765: bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), ! 766: sizeof(struct in_addr)); ! 767: /* ! 768: * Then copy rest of options back ! 769: * to close up the deleted entry. ! 770: */ ! 771: ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + ! 772: sizeof(struct in_addr)), ! 773: (caddr_t)&cp[IPOPT_OFFSET+1], ! 774: (unsigned)cnt + sizeof(struct in_addr)); ! 775: break; ! 776: } ! 777: } ! 778: if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) ! 779: goto bad; ! 780: *pcbopt = m; ! 781: return (0); ! 782: ! 783: bad: ! 784: (void)m_free(m); ! 785: return (EINVAL); ! 786: } ! 787: ! 788: /* ! 789: * Set the IP multicast options in response to user setsockopt(). ! 790: */ ! 791: int ! 792: ip_setmoptions(optname, imop, m) ! 793: int optname; ! 794: struct ip_moptions **imop; ! 795: struct mbuf *m; ! 796: { ! 797: register int error = 0; ! 798: u_char loop; ! 799: register int i; ! 800: struct in_addr addr; ! 801: register struct ip_mreq *mreq; ! 802: register struct ifnet *ifp; ! 803: register struct ip_moptions *imo = *imop; ! 804: struct route ro; ! 805: register struct sockaddr_in *dst; ! 806: ! 807: if (imo == NULL) { ! 808: /* ! 809: * No multicast option buffer attached to the pcb; ! 810: * allocate one and initialize to default values. ! 811: */ ! 812: imo = (struct ip_moptions*)_MALLOC(sizeof(*imo), M_IPMOPTS, ! 813: M_WAITOK); ! 814: ! 815: if (imo == NULL) ! 816: return (ENOBUFS); ! 817: *imop = imo; ! 818: imo->imo_multicast_ifp = NULL; ! 819: imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; ! 820: imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; ! 821: imo->imo_num_memberships = 0; ! 822: } ! 823: ! 824: switch (optname) { ! 825: ! 826: case IP_MULTICAST_IF: ! 827: /* ! 828: * Select the interface for outgoing multicast packets. ! 829: */ ! 830: if (m == NULL || m->m_len != sizeof(struct in_addr)) { ! 831: error = EINVAL; ! 832: break; ! 833: } ! 834: addr = *(mtod(m, struct in_addr *)); ! 835: /* ! 836: * INADDR_ANY is used to remove a previous selection. ! 837: * When no interface is selected, a default one is ! 838: * chosen every time a multicast packet is sent. ! 839: */ ! 840: if (addr.s_addr == INADDR_ANY) { ! 841: imo->imo_multicast_ifp = NULL; ! 842: break; ! 843: } ! 844: /* ! 845: * The selected interface is identified by its local ! 846: * IP address. Find the interface and confirm that ! 847: * it supports multicasting. ! 848: */ ! 849: INADDR_TO_IFP(addr, ifp); ! 850: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { ! 851: error = EADDRNOTAVAIL; ! 852: break; ! 853: } ! 854: imo->imo_multicast_ifp = ifp; ! 855: break; ! 856: ! 857: case IP_MULTICAST_TTL: ! 858: /* ! 859: * Set the IP time-to-live for outgoing multicast packets. ! 860: */ ! 861: if (m == NULL || m->m_len != 1) { ! 862: error = EINVAL; ! 863: break; ! 864: } ! 865: imo->imo_multicast_ttl = *(mtod(m, u_char *)); ! 866: break; ! 867: ! 868: case IP_MULTICAST_LOOP: ! 869: /* ! 870: * Set the loopback flag for outgoing multicast packets. ! 871: * Must be zero or one. ! 872: */ ! 873: if (m == NULL || m->m_len != 1 || ! 874: (loop = *(mtod(m, u_char *))) > 1) { ! 875: error = EINVAL; ! 876: break; ! 877: } ! 878: imo->imo_multicast_loop = loop; ! 879: break; ! 880: ! 881: case IP_ADD_MEMBERSHIP: ! 882: /* ! 883: * Add a multicast group membership. ! 884: * Group must be a valid IP multicast address. ! 885: */ ! 886: if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { ! 887: error = EINVAL; ! 888: break; ! 889: } ! 890: mreq = mtod(m, struct ip_mreq *); ! 891: if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { ! 892: error = EINVAL; ! 893: break; ! 894: } ! 895: /* ! 896: * If no interface address was provided, use the interface of ! 897: * the route to the given multicast address. ! 898: */ ! 899: if (mreq->imr_interface.s_addr == INADDR_ANY) { ! 900: ro.ro_rt = NULL; ! 901: dst = (struct sockaddr_in *)&ro.ro_dst; ! 902: dst->sin_len = sizeof(*dst); ! 903: dst->sin_family = AF_INET; ! 904: dst->sin_addr = mreq->imr_multiaddr; ! 905: rtalloc(&ro); ! 906: if (ro.ro_rt == NULL) { ! 907: error = EADDRNOTAVAIL; ! 908: break; ! 909: } ! 910: ifp = ro.ro_rt->rt_ifp; ! 911: rtfree(ro.ro_rt); ! 912: } ! 913: else { ! 914: INADDR_TO_IFP(mreq->imr_interface, ifp); ! 915: } ! 916: /* ! 917: * See if we found an interface, and confirm that it ! 918: * supports multicast. ! 919: */ ! 920: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { ! 921: error = EADDRNOTAVAIL; ! 922: break; ! 923: } ! 924: /* ! 925: * See if the membership already exists or if all the ! 926: * membership slots are full. ! 927: */ ! 928: for (i = 0; i < imo->imo_num_memberships; ++i) { ! 929: if (imo->imo_membership[i]->inm_ifp == ifp && ! 930: imo->imo_membership[i]->inm_addr.s_addr ! 931: == mreq->imr_multiaddr.s_addr) ! 932: break; ! 933: } ! 934: if (i < imo->imo_num_memberships) { ! 935: error = EADDRINUSE; ! 936: break; ! 937: } ! 938: if (i == IP_MAX_MEMBERSHIPS) { ! 939: error = ETOOMANYREFS; ! 940: break; ! 941: } ! 942: /* ! 943: * Everything looks good; add a new record to the multicast ! 944: * address list for the given interface. ! 945: */ ! 946: if ((imo->imo_membership[i] = ! 947: in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) { ! 948: error = ENOBUFS; ! 949: break; ! 950: } ! 951: ++imo->imo_num_memberships; ! 952: break; ! 953: ! 954: case IP_DROP_MEMBERSHIP: ! 955: /* ! 956: * Drop a multicast group membership. ! 957: * Group must be a valid IP multicast address. ! 958: */ ! 959: if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { ! 960: error = EINVAL; ! 961: break; ! 962: } ! 963: mreq = mtod(m, struct ip_mreq *); ! 964: if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { ! 965: error = EINVAL; ! 966: break; ! 967: } ! 968: /* ! 969: * If an interface address was specified, get a pointer ! 970: * to its ifnet structure. ! 971: */ ! 972: if (mreq->imr_interface.s_addr == INADDR_ANY) ! 973: ifp = NULL; ! 974: else { ! 975: INADDR_TO_IFP(mreq->imr_interface, ifp); ! 976: if (ifp == NULL) { ! 977: error = EADDRNOTAVAIL; ! 978: break; ! 979: } ! 980: } ! 981: /* ! 982: * Find the membership in the membership array. ! 983: */ ! 984: for (i = 0; i < imo->imo_num_memberships; ++i) { ! 985: if ((ifp == NULL || ! 986: imo->imo_membership[i]->inm_ifp == ifp) && ! 987: imo->imo_membership[i]->inm_addr.s_addr == ! 988: mreq->imr_multiaddr.s_addr) ! 989: break; ! 990: } ! 991: if (i == imo->imo_num_memberships) { ! 992: error = EADDRNOTAVAIL; ! 993: break; ! 994: } ! 995: /* ! 996: * Give up the multicast address record to which the ! 997: * membership points. ! 998: */ ! 999: in_delmulti(imo->imo_membership[i]); ! 1000: /* ! 1001: * Remove the gap in the membership array. ! 1002: */ ! 1003: for (++i; i < imo->imo_num_memberships; ++i) ! 1004: imo->imo_membership[i-1] = imo->imo_membership[i]; ! 1005: --imo->imo_num_memberships; ! 1006: break; ! 1007: ! 1008: default: ! 1009: error = EOPNOTSUPP; ! 1010: break; ! 1011: } ! 1012: ! 1013: /* ! 1014: * If all options have default values, no need to keep the mbuf. ! 1015: */ ! 1016: if (imo->imo_multicast_ifp == NULL && ! 1017: imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL && ! 1018: imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP && ! 1019: imo->imo_num_memberships == 0) { ! 1020: _FREE(*imop, M_IPMOPTS); ! 1021: *imop = NULL; ! 1022: } ! 1023: ! 1024: return (error); ! 1025: } ! 1026: ! 1027: /* ! 1028: * Return the IP multicast options in response to user getsockopt(). ! 1029: */ ! 1030: int ! 1031: ip_getmoptions(optname, imo, mp) ! 1032: int optname; ! 1033: register struct ip_moptions *imo; ! 1034: register struct mbuf **mp; ! 1035: { ! 1036: u_char *ttl; ! 1037: u_char *loop; ! 1038: struct in_addr *addr; ! 1039: struct in_ifaddr *ia; ! 1040: ! 1041: *mp = m_get(M_WAIT, MT_SOOPTS); ! 1042: ! 1043: switch (optname) { ! 1044: ! 1045: case IP_MULTICAST_IF: ! 1046: addr = mtod(*mp, struct in_addr *); ! 1047: (*mp)->m_len = sizeof(struct in_addr); ! 1048: if (imo == NULL || imo->imo_multicast_ifp == NULL) ! 1049: addr->s_addr = INADDR_ANY; ! 1050: else { ! 1051: IFP_TO_IA(imo->imo_multicast_ifp, ia); ! 1052: addr->s_addr = (ia == NULL) ? INADDR_ANY ! 1053: : IA_SIN(ia)->sin_addr.s_addr; ! 1054: } ! 1055: return (0); ! 1056: ! 1057: case IP_MULTICAST_TTL: ! 1058: ttl = mtod(*mp, u_char *); ! 1059: (*mp)->m_len = 1; ! 1060: *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL ! 1061: : imo->imo_multicast_ttl; ! 1062: return (0); ! 1063: ! 1064: case IP_MULTICAST_LOOP: ! 1065: loop = mtod(*mp, u_char *); ! 1066: (*mp)->m_len = 1; ! 1067: *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP ! 1068: : imo->imo_multicast_loop; ! 1069: return (0); ! 1070: ! 1071: default: ! 1072: return (EOPNOTSUPP); ! 1073: } ! 1074: } ! 1075: ! 1076: /* ! 1077: * Discard the IP multicast options. ! 1078: */ ! 1079: void ! 1080: ip_freemoptions(imo) ! 1081: register struct ip_moptions *imo; ! 1082: { ! 1083: register int i; ! 1084: ! 1085: if (imo != NULL) { ! 1086: for (i = 0; i < imo->imo_num_memberships; ++i) ! 1087: in_delmulti(imo->imo_membership[i]); ! 1088: _FREE(imo, M_IPMOPTS); ! 1089: } ! 1090: } ! 1091: ! 1092: /* ! 1093: * Routine called from ip_output() to loop back a copy of an IP multicast ! 1094: * packet to the input queue of a specified interface. Note that this ! 1095: * calls the output routine of the loopback "driver", but with an interface ! 1096: * pointer that might NOT be &loif -- easier than replicating that code here. ! 1097: */ ! 1098: static void ! 1099: ip_mloopback(ifp, m, dst) ! 1100: struct ifnet *ifp; ! 1101: register struct mbuf *m; ! 1102: register struct sockaddr_in *dst; ! 1103: { ! 1104: register struct ip *ip; ! 1105: struct mbuf *copym; ! 1106: ! 1107: copym = m_copy(m, 0, M_COPYALL); ! 1108: if (copym != NULL) { ! 1109: /* ! 1110: * We don't bother to fragment if the IP length is greater ! 1111: * than the interface's MTU. Can this possibly matter? ! 1112: */ ! 1113: ip = mtod(copym, struct ip *); ! 1114: ip->ip_len = htons((u_short)ip->ip_len); ! 1115: ip->ip_off = htons((u_short)ip->ip_off); ! 1116: ip->ip_sum = 0; ! 1117: ip->ip_sum = in_cksum(copym, ip->ip_hl << 2); ! 1118: (void) looutput(ifp, copym, (struct sockaddr *)dst, NULL); ! 1119: } ! 1120: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.