|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1982, 1986, 1988, 1990, 1993 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 ! 55: */ ! 56: ! 57: #define _IP_VHL ! 58: ! 59: #if ISFB31 ! 60: #include "opt_ipfw.h" ! 61: #include "opt_ipdn.h" ! 62: #include "opt_ipdivert.h" ! 63: #include "opt_ipfilter.h" ! 64: #endif ! 65: ! 66: #include <sys/param.h> ! 67: #include <sys/systm.h> ! 68: #include <sys/kernel.h> ! 69: #include <sys/malloc.h> ! 70: #include <sys/mbuf.h> ! 71: #include <sys/protosw.h> ! 72: #include <sys/socket.h> ! 73: #include <sys/socketvar.h> ! 74: ! 75: #include <net/if.h> ! 76: #include <net/route.h> ! 77: ! 78: #include <netinet/in.h> ! 79: #include <netinet/in_systm.h> ! 80: #include <netinet/ip.h> ! 81: #include <netinet/in_pcb.h> ! 82: #include <netinet/in_var.h> ! 83: #include <netinet/ip_var.h> ! 84: #include <net/dlil.h> ! 85: ! 86: #ifdef vax ! 87: #include <machine/mtpr.h> ! 88: #endif ! 89: ! 90: #if ISFB31 ! 91: #include <machine/in_cksum.h> ! 92: ! 93: static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); ! 94: #endif ! 95: ! 96: #if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 ! 97: #undef COMPAT_IPFW ! 98: #define COMPAT_IPFW 1 ! 99: #else ! 100: #undef COMPAT_IPFW ! 101: #endif ! 102: ! 103: #if COMPAT_IPFW ! 104: #include <netinet/ip_fw.h> ! 105: #endif ! 106: ! 107: #if DUMMYNET ! 108: #include <netinet/ip_dummynet.h> ! 109: #endif ! 110: ! 111: #if IPFIREWALL_FORWARD_DEBUG ! 112: #define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\ ! 113: (ntohl(a.s_addr)>>16)&0xFF,\ ! 114: (ntohl(a.s_addr)>>8)&0xFF,\ ! 115: (ntohl(a.s_addr))&0xFF); ! 116: #endif ! 117: ! 118: u_short ip_id; ! 119: ! 120: static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); ! 121: static void ip_mloopback ! 122: __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int)); ! 123: static int ip_getmoptions ! 124: __P((struct sockopt *, struct ip_moptions *)); ! 125: static int ip_pcbopts __P((int, struct mbuf **, struct mbuf *)); ! 126: static int ip_setmoptions ! 127: __P((struct sockopt *, struct ip_moptions **)); ! 128: static u_long lo_dl_tag = 0; ! 129: ! 130: #if IPFILTER_LKM || IPFILTER ! 131: int ip_optcopy __P((struct ip *, struct ip *)); ! 132: extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)); ! 133: #else ! 134: static int ip_optcopy __P((struct ip *, struct ip *)); ! 135: #endif ! 136: ! 137: ! 138: extern struct protosw inetsw[]; ! 139: ! 140: /* ! 141: * IP output. The packet in mbuf chain m contains a skeletal IP ! 142: * header (with len, off, ttl, proto, tos, src, dst). ! 143: * The mbuf chain containing the packet will be freed. ! 144: * The mbuf opt, if present, will not be freed. ! 145: */ ! 146: int ! 147: ip_output(m0, opt, ro, flags, imo) ! 148: struct mbuf *m0; ! 149: struct mbuf *opt; ! 150: struct route *ro; ! 151: int flags; ! 152: struct ip_moptions *imo; ! 153: { ! 154: struct ip *ip, *mhip; ! 155: struct ifnet *ifp; ! 156: u_long dl_tag; ! 157: struct mbuf *m = m0; ! 158: int hlen = sizeof (struct ip); ! 159: int len, off, error = 0; ! 160: struct sockaddr_in *dst; ! 161: struct in_ifaddr *ia; ! 162: int isbroadcast; ! 163: #if IPFIREWALL_FORWARD ! 164: int fwd_rewrite_src = 0; ! 165: #endif ! 166: ! 167: #if !IPDIVERT /* dummy variable for the firewall code to play with */ ! 168: u_short ip_divert_cookie = 0 ; ! 169: #endif ! 170: #if COMPAT_IPFW ! 171: struct ip_fw_chain *rule = NULL ; ! 172: #endif ! 173: ! 174: #if IPFIREWALL && DUMMYNET ! 175: /* ! 176: * dummynet packet are prepended a vestigial mbuf with ! 177: * m_type = MT_DUMMYNET and m_data pointing to the matching ! 178: * rule. ! 179: */ ! 180: if (m->m_type == MT_DUMMYNET) { ! 181: struct mbuf *tmp_m = m ; ! 182: /* ! 183: * the packet was already tagged, so part of the ! 184: * processing was already done, and we need to go down. ! 185: * opt, flags and imo have already been used, and now ! 186: * they are used to hold ifp and hlen and NULL, respectively. ! 187: */ ! 188: rule = (struct ip_fw_chain *)(m->m_data) ; ! 189: m = m->m_next ; ! 190: FREE(tmp_m, M_IPFW); ! 191: ip = mtod(m, struct ip *); ! 192: dst = (struct sockaddr_in *)&ro->ro_dst; ! 193: ifp = (struct ifnet *)opt; ! 194: hlen = IP_VHL_HL(ip->ip_vhl) << 2 ; ! 195: opt = NULL ; ! 196: flags = 0 ; /* XXX is this correct ? */ ! 197: goto sendit; ! 198: } else ! 199: rule = NULL ; ! 200: #endif ! 201: ! 202: #if DIAGNOSTIC ! 203: if ((m->m_flags & M_PKTHDR) == 0) ! 204: panic("ip_output no HDR"); ! 205: if (!ro) ! 206: panic("ip_output no route, proto = %d", ! 207: mtod(m, struct ip *)->ip_p); ! 208: #endif ! 209: if (opt) { ! 210: m = ip_insertoptions(m, opt, &len); ! 211: hlen = len; ! 212: } ! 213: ip = mtod(m, struct ip *); ! 214: /* ! 215: * Fill in IP header. ! 216: */ ! 217: if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { ! 218: ip->ip_vhl = IP_MAKE_VHL(IPVERSION, hlen >> 2); ! 219: ip->ip_off &= IP_DF; ! 220: ip->ip_id = htons(ip_id++); ! 221: ipstat.ips_localout++; ! 222: } else { ! 223: hlen = IP_VHL_HL(ip->ip_vhl) << 2; ! 224: } ! 225: ! 226: dst = (struct sockaddr_in *)&ro->ro_dst; ! 227: /* ! 228: * If there is a cached route, ! 229: * check that it is to the same destination ! 230: * and is still up. If not, free it and try again. ! 231: */ ! 232: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || ! 233: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { ! 234: RTFREE(ro->ro_rt); ! 235: ro->ro_rt = (struct rtentry *)0; ! 236: } ! 237: if (ro->ro_rt == 0) { ! 238: dst->sin_family = AF_INET; ! 239: dst->sin_len = sizeof(*dst); ! 240: dst->sin_addr = ip->ip_dst; ! 241: } ! 242: /* ! 243: * If routing to interface only, ! 244: * short circuit routing lookup. ! 245: */ ! 246: #define ifatoia(ifa) ((struct in_ifaddr *)(ifa)) ! 247: #define sintosa(sin) ((struct sockaddr *)(sin)) ! 248: if (flags & IP_ROUTETOIF) { ! 249: if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 && ! 250: (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) { ! 251: ipstat.ips_noroute++; ! 252: error = ENETUNREACH; ! 253: goto bad; ! 254: } ! 255: ifp = ia->ia_ifp; ! 256: dl_tag = ia->ia_ifa.ifa_dlt; ! 257: ip->ip_ttl = 1; ! 258: isbroadcast = in_broadcast(dst->sin_addr, ifp); ! 259: } else { ! 260: /* ! 261: * If this is the case, we probably don't want to allocate ! 262: * a protocol-cloned route since we didn't get one from the ! 263: * ULP. This lets TCP do its thing, while not burdening ! 264: * forwarding or ICMP with the overhead of cloning a route. ! 265: * Of course, we still want to do any cloning requested by ! 266: * the link layer, as this is probably required in all cases ! 267: * for correct operation (as it is for ARP). ! 268: */ ! 269: if (ro->ro_rt == 0) ! 270: rtalloc_ign(ro, RTF_PRCLONING); ! 271: if (ro->ro_rt == 0) { ! 272: ipstat.ips_noroute++; ! 273: error = EHOSTUNREACH; ! 274: goto bad; ! 275: } ! 276: ia = ifatoia(ro->ro_rt->rt_ifa); ! 277: ifp = ro->ro_rt->rt_ifp; ! 278: dl_tag = ro->ro_rt->rt_dlt; ! 279: ro->ro_rt->rt_use++; ! 280: if (ro->ro_rt->rt_flags & RTF_GATEWAY) ! 281: dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; ! 282: if (ro->ro_rt->rt_flags & RTF_HOST) ! 283: isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST); ! 284: else ! 285: isbroadcast = in_broadcast(dst->sin_addr, ifp); ! 286: } ! 287: if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { ! 288: struct in_multi *inm; ! 289: ! 290: m->m_flags |= M_MCAST; ! 291: /* ! 292: * IP destination address is multicast. Make sure "dst" ! 293: * still points to the address in "ro". (It may have been ! 294: * changed to point to a gateway address, above.) ! 295: */ ! 296: dst = (struct sockaddr_in *)&ro->ro_dst; ! 297: /* ! 298: * See if the caller provided any multicast options ! 299: */ ! 300: if (imo != NULL) { ! 301: ip->ip_ttl = imo->imo_multicast_ttl; ! 302: if (imo->imo_multicast_ifp != NULL) ! 303: ifp = imo->imo_multicast_ifp; ! 304: if (imo->imo_multicast_vif != -1) ! 305: ip->ip_src.s_addr = ! 306: ip_mcast_src(imo->imo_multicast_vif); ! 307: } else ! 308: ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; ! 309: /* ! 310: * Confirm that the outgoing interface supports multicast. ! 311: */ ! 312: if ((imo == NULL) || (imo->imo_multicast_vif == -1)) { ! 313: if ((ifp->if_flags & IFF_MULTICAST) == 0) { ! 314: ipstat.ips_noroute++; ! 315: error = ENETUNREACH; ! 316: goto bad; ! 317: } ! 318: } ! 319: /* ! 320: * If source address not specified yet, use address ! 321: * of outgoing interface. ! 322: */ ! 323: if (ip->ip_src.s_addr == INADDR_ANY) { ! 324: register struct in_ifaddr *ia1; ! 325: ! 326: for (ia1 = in_ifaddrhead.tqh_first; ia1; ! 327: ia1 = ia1->ia_link.tqe_next) ! 328: if (ia1->ia_ifp == ifp) { ! 329: ip->ip_src = IA_SIN(ia1)->sin_addr; ! 330: break; ! 331: } ! 332: } ! 333: ! 334: IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm); ! 335: if (inm != NULL && ! 336: (imo == NULL || imo->imo_multicast_loop)) { ! 337: /* ! 338: * If we belong to the destination multicast group ! 339: * on the outgoing interface, and the caller did not ! 340: * forbid loopback, loop back a copy. ! 341: */ ! 342: ip_mloopback(ifp, m, dst, hlen); ! 343: } ! 344: else { ! 345: /* ! 346: * If we are acting as a multicast router, perform ! 347: * multicast forwarding as if the packet had just ! 348: * arrived on the interface to which we are about ! 349: * to send. The multicast forwarding function ! 350: * recursively calls this function, using the ! 351: * IP_FORWARDING flag to prevent infinite recursion. ! 352: * ! 353: * Multicasts that are looped back by ip_mloopback(), ! 354: * above, will be forwarded by the ip_input() routine, ! 355: * if necessary. ! 356: */ ! 357: if (ip_mrouter && (flags & IP_FORWARDING) == 0) { ! 358: /* ! 359: * Check if rsvp daemon is running. If not, don't ! 360: * set ip_moptions. This ensures that the packet ! 361: * is multicast and not just sent down one link ! 362: * as prescribed by rsvpd. ! 363: */ ! 364: if (!rsvp_on) ! 365: imo = NULL; ! 366: if (ip_mforward(ip, ifp, m, imo) != 0) { ! 367: m_freem(m); ! 368: goto done; ! 369: } ! 370: } ! 371: } ! 372: ! 373: /* ! 374: * Multicasts with a time-to-live of zero may be looped- ! 375: * back, above, but must not be transmitted on a network. ! 376: * Also, multicasts addressed to the loopback interface ! 377: * are not sent -- the above call to ip_mloopback() will ! 378: * loop back a copy if this host actually belongs to the ! 379: * destination group on the loopback interface. ! 380: */ ! 381: if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) { ! 382: m_freem(m); ! 383: goto done; ! 384: } ! 385: ! 386: goto sendit; ! 387: } ! 388: #ifndef notdef ! 389: /* ! 390: * If source address not specified yet, use address ! 391: * of outgoing interface. ! 392: */ ! 393: if (ip->ip_src.s_addr == INADDR_ANY) { ! 394: ip->ip_src = IA_SIN(ia)->sin_addr; ! 395: #if IPFIREWALL_FORWARD ! 396: /* Keep note that we did this - if the firewall changes ! 397: * the next-hop, our interface may change, changing the ! 398: * default source IP. It's a shame so much effort happens ! 399: * twice. Oh well. ! 400: */ ! 401: fwd_rewrite_src++; ! 402: #endif /* IPFIREWALL_FORWARD */ ! 403: } ! 404: #endif /* notdef */ ! 405: /* ! 406: * Verify that we have any chance at all of being able to queue ! 407: * the packet or packet fragments ! 408: */ ! 409: if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >= ! 410: ifp->if_snd.ifq_maxlen) { ! 411: error = ENOBUFS; ! 412: goto bad; ! 413: } ! 414: ! 415: /* ! 416: * Look for broadcast address and ! 417: * and verify user is allowed to send ! 418: * such a packet. ! 419: */ ! 420: if (isbroadcast) { ! 421: if ((ifp->if_flags & IFF_BROADCAST) == 0) { ! 422: error = EADDRNOTAVAIL; ! 423: goto bad; ! 424: } ! 425: if ((flags & IP_ALLOWBROADCAST) == 0) { ! 426: error = EACCES; ! 427: goto bad; ! 428: } ! 429: /* don't allow broadcast messages to be fragmented */ ! 430: if ((u_short)ip->ip_len > ifp->if_mtu) { ! 431: error = EMSGSIZE; ! 432: goto bad; ! 433: } ! 434: m->m_flags |= M_BCAST; ! 435: } else { ! 436: m->m_flags &= ~M_BCAST; ! 437: } ! 438: ! 439: sendit: ! 440: /* ! 441: * IpHack's section. ! 442: * - Xlate: translate packet's addr/port (NAT). ! 443: * - Firewall: deny/allow/etc. ! 444: * - Wrap: fake packet's addr/port <unimpl.> ! 445: * - Encapsulate: put it in another IP and send out. <unimp.> ! 446: */ ! 447: #if IPFILTER || IPFILTER_LKM ! 448: if (fr_checkp) { ! 449: struct mbuf *m1 = m; ! 450: ! 451: if ((error = (*fr_checkp)(ip, hlen, ifp, 1, &m1)) || !m1) ! 452: goto done; ! 453: ip = mtod(m = m1, struct ip *); ! 454: } ! 455: #endif ! 456: ! 457: #if COMPAT_IPFW ! 458: if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, ifp, IP_NAT_OUT)) { ! 459: error = EACCES; ! 460: goto done; ! 461: } ! 462: ! 463: /* ! 464: * Check with the firewall... ! 465: */ ! 466: if (ip_fw_chk_ptr) { ! 467: struct sockaddr_in *old = dst; ! 468: ! 469: off = (*ip_fw_chk_ptr)(&ip, ! 470: hlen, ifp, &ip_divert_cookie, &m, &rule, &dst); ! 471: /* ! 472: * On return we must do the following: ! 473: * m == NULL -> drop the pkt ! 474: * 1<=off<= 0xffff -> DIVERT ! 475: * (off & 0x10000) -> send to a DUMMYNET pipe ! 476: * dst != old -> IPFIREWALL_FORWARD ! 477: * off==0, dst==old -> accept ! 478: * If some of the above modules is not compiled in, then ! 479: * we should't have to check the corresponding condition ! 480: * (because the ipfw control socket should not accept ! 481: * unsupported rules), but better play safe and drop ! 482: * packets in case of doubt. ! 483: */ ! 484: if (!m) { /* firewall said to reject */ ! 485: error = EACCES; ! 486: goto done; ! 487: } ! 488: if (off == 0 && dst == old) /* common case */ ! 489: goto pass ; ! 490: #if DUMMYNET ! 491: if (off & 0x10000) { ! 492: /* ! 493: * pass the pkt to dummynet. Need to include ! 494: * pipe number, m, ifp, ro, hlen because these are ! 495: * not recomputed in the next pass. ! 496: * All other parameters have been already used and ! 497: * so they are not needed anymore. ! 498: * XXX note: if the ifp or ro entry are deleted ! 499: * while a pkt is in dummynet, we are in trouble! ! 500: */ ! 501: dummynet_io(off & 0xffff, DN_TO_IP_OUT, m,ifp,ro,hlen,rule); ! 502: goto done; ! 503: } ! 504: #endif ! 505: #if IPDIVERT ! 506: if (off > 0 && off < 0x10000) { /* Divert packet */ ! 507: ip_divert_port = off & 0xffff ; ! 508: (*ip_protox[IPPROTO_DIVERT]->pr_input)(m, 0); ! 509: goto done; ! 510: } ! 511: #endif ! 512: ! 513: #if IPFIREWALL_FORWARD ! 514: /* Here we check dst to make sure it's directly reachable on the ! 515: * interface we previously thought it was. ! 516: * If it isn't (which may be likely in some situations) we have ! 517: * to re-route it (ie, find a route for the next-hop and the ! 518: * associated interface) and set them here. This is nested ! 519: * forwarding which in most cases is undesirable, except where ! 520: * such control is nigh impossible. So we do it here. ! 521: * And I'm babbling. ! 522: */ ! 523: if (off == 0 && old != dst) { ! 524: struct in_ifaddr *ia; ! 525: ! 526: /* It's changed... */ ! 527: /* There must be a better way to do this next line... */ ! 528: static struct route sro_fwd, *ro_fwd = &sro_fwd; ! 529: #if IPFIREWALL_FORWARD_DEBUG ! 530: printf("IPFIREWALL_FORWARD: New dst ip: "); ! 531: print_ip(dst->sin_addr); ! 532: printf("\n"); ! 533: #endif ! 534: /* ! 535: * We need to figure out if we have been forwarded ! 536: * to a local socket. If so then we should somehow ! 537: * "loop back" to ip_input, and get directed to the ! 538: * PCB as if we had received this packet. This is ! 539: * because it may be dificult to identify the packets ! 540: * you want to forward until they are being output ! 541: * and have selected an interface. (e.g. locally ! 542: * initiated packets) If we used the loopback inteface, ! 543: * we would not be able to control what happens ! 544: * as the packet runs through ip_input() as ! 545: * it is done through a ISR. ! 546: */ ! 547: for (ia = TAILQ_FIRST(&in_ifaddrhead); ia; ! 548: ia = TAILQ_NEXT(ia, ia_link)) { ! 549: /* ! 550: * If the addr to forward to is one ! 551: * of ours, we pretend to ! 552: * be the destination for this packet. ! 553: */ ! 554: if (IA_SIN(ia)->sin_addr.s_addr == ! 555: dst->sin_addr.s_addr) ! 556: break; ! 557: } ! 558: if (ia) { ! 559: /* tell ip_input "dont filter" */ ! 560: ip_fw_fwd_addr = dst; ! 561: if (m->m_pkthdr.rcvif == NULL) ! 562: m->m_pkthdr.rcvif = ifunit("lo0"); ! 563: ip->ip_len = htons((u_short)ip->ip_len); ! 564: ip->ip_off = htons((u_short)ip->ip_off); ! 565: ip->ip_sum = 0; ! 566: ! 567: ip->ip_sum = in_cksum(m, hlen); ! 568: ! 569: ip_input(m); ! 570: goto done; ! 571: } ! 572: /* Some of the logic for this was ! 573: * nicked from above. ! 574: * ! 575: * This rewrites the cached route in a local PCB. ! 576: * Is this what we want to do? ! 577: */ ! 578: bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst)); ! 579: ! 580: ro_fwd->ro_rt = 0; ! 581: rtalloc_ign(ro_fwd, RTF_PRCLONING); ! 582: ! 583: if (ro_fwd->ro_rt == 0) { ! 584: ipstat.ips_noroute++; ! 585: error = EHOSTUNREACH; ! 586: goto bad; ! 587: } ! 588: ! 589: ia = ifatoia(ro_fwd->ro_rt->rt_ifa); ! 590: ifp = ro_fwd->ro_rt->rt_ifp; ! 591: dl_tag = ro->ro_rt->rt_dlt; ! 592: ro_fwd->ro_rt->rt_use++; ! 593: if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY) ! 594: dst = (struct sockaddr_in *)ro_fwd->ro_rt->rt_gateway; ! 595: if (ro_fwd->ro_rt->rt_flags & RTF_HOST) ! 596: isbroadcast = ! 597: (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST); ! 598: else ! 599: isbroadcast = in_broadcast(dst->sin_addr, ifp); ! 600: RTFREE(ro->ro_rt); ! 601: ro->ro_rt = ro_fwd->ro_rt; ! 602: dst = (struct sockaddr_in *)&ro_fwd->ro_dst; ! 603: ! 604: /* ! 605: * If we added a default src ip earlier, ! 606: * which would have been gotten from the-then ! 607: * interface, do it again, from the new one. ! 608: */ ! 609: if (fwd_rewrite_src) ! 610: ip->ip_src = IA_SIN(ia)->sin_addr; ! 611: goto pass ; ! 612: } ! 613: #endif /* IPFIREWALL_FORWARD */ ! 614: /* ! 615: * if we get here, none of the above matches, and ! 616: * we have to drop the pkt ! 617: */ ! 618: m_freem(m); ! 619: error = EACCES; /* not sure this is the right error msg */ ! 620: goto done; ! 621: } ! 622: #endif /* COMPAT_IPFW */ ! 623: ! 624: pass: ! 625: /* ! 626: * If small enough for interface, can just send directly. ! 627: */ ! 628: if ((u_short)ip->ip_len <= ifp->if_mtu) { ! 629: ip->ip_len = htons((u_short)ip->ip_len); ! 630: ip->ip_off = htons((u_short)ip->ip_off); ! 631: ip->ip_sum = 0; ! 632: ip->ip_sum = in_cksum(m, hlen); ! 633: error = dlil_output(dl_tag, m, (void *) ro->ro_rt, ! 634: (struct sockaddr *)dst, 0); ! 635: goto done; ! 636: } ! 637: /* ! 638: * Too large for interface; fragment if possible. ! 639: * Must be able to put at least 8 bytes per fragment. ! 640: */ ! 641: if (ip->ip_off & IP_DF) { ! 642: error = EMSGSIZE; ! 643: /* ! 644: * This case can happen if the user changed the MTU ! 645: * of an interface after enabling IP on it. Because ! 646: * most netifs don't keep track of routes pointing to ! 647: * them, there is no way for one to update all its ! 648: * routes when the MTU is changed. ! 649: */ ! 650: if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST)) ! 651: && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU) ! 652: && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) { ! 653: ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu; ! 654: } ! 655: ipstat.ips_cantfrag++; ! 656: goto bad; ! 657: } ! 658: len = (ifp->if_mtu - hlen) &~ 7; ! 659: if (len < 8) { ! 660: error = EMSGSIZE; ! 661: goto bad; ! 662: } ! 663: ! 664: { ! 665: int mhlen, firstlen = len; ! 666: struct mbuf **mnext = &m->m_nextpkt; ! 667: ! 668: /* ! 669: * Loop through length of segment after first fragment, ! 670: * make new header and copy data of each part and link onto chain. ! 671: */ ! 672: m0 = m; ! 673: mhlen = sizeof (struct ip); ! 674: for (off = hlen + len; off < (u_short)ip->ip_len; off += len) { ! 675: MGETHDR(m, M_DONTWAIT, MT_HEADER); ! 676: if (m == 0) { ! 677: error = ENOBUFS; ! 678: ipstat.ips_odropped++; ! 679: goto sendorfree; ! 680: } ! 681: m->m_flags |= (m0->m_flags & M_MCAST); ! 682: m->m_data += max_linkhdr; ! 683: mhip = mtod(m, struct ip *); ! 684: *mhip = *ip; ! 685: if (hlen > sizeof (struct ip)) { ! 686: mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); ! 687: mhip->ip_vhl = IP_MAKE_VHL(IPVERSION, mhlen >> 2); ! 688: } ! 689: m->m_len = mhlen; ! 690: mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); ! 691: if (ip->ip_off & IP_MF) ! 692: mhip->ip_off |= IP_MF; ! 693: if (off + len >= (u_short)ip->ip_len) ! 694: len = (u_short)ip->ip_len - off; ! 695: else ! 696: mhip->ip_off |= IP_MF; ! 697: mhip->ip_len = htons((u_short)(len + mhlen)); ! 698: m->m_next = m_copy(m0, off, len); ! 699: if (m->m_next == 0) { ! 700: (void) m_free(m); ! 701: error = ENOBUFS; /* ??? */ ! 702: ipstat.ips_odropped++; ! 703: goto sendorfree; ! 704: } ! 705: m->m_pkthdr.len = mhlen + len; ! 706: m->m_pkthdr.rcvif = (struct ifnet *)0; ! 707: mhip->ip_off = htons((u_short)mhip->ip_off); ! 708: mhip->ip_sum = 0; ! 709: mhip->ip_sum = in_cksum(m, mhlen); ! 710: *mnext = m; ! 711: mnext = &m->m_nextpkt; ! 712: ipstat.ips_ofragments++; ! 713: } ! 714: /* ! 715: * Update first fragment by trimming what's been copied out ! 716: * and updating header, then send each fragment (in order). ! 717: */ ! 718: m = m0; ! 719: m_adj(m, hlen + firstlen - (u_short)ip->ip_len); ! 720: m->m_pkthdr.len = hlen + firstlen; ! 721: ip->ip_len = htons((u_short)m->m_pkthdr.len); ! 722: ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); ! 723: ip->ip_sum = 0; ! 724: ip->ip_sum = in_cksum(m, hlen); ! 725: ! 726: sendorfree: ! 727: for (m = m0; m; m = m0) { ! 728: m0 = m->m_nextpkt; ! 729: m->m_nextpkt = 0; ! 730: if (error == 0) ! 731: error = dlil_output(dl_tag, m, (void *) ro->ro_rt, ! 732: (struct sockaddr *)dst, 0); ! 733: else ! 734: m_freem(m); ! 735: } ! 736: ! 737: if (error == 0) ! 738: ipstat.ips_fragmented++; ! 739: } ! 740: done: ! 741: return (error); ! 742: bad: ! 743: m_freem(m0); ! 744: goto done; ! 745: } ! 746: ! 747: /* ! 748: * Insert IP options into preformed packet. ! 749: * Adjust IP destination as required for IP source routing, ! 750: * as indicated by a non-zero in_addr at the start of the options. ! 751: * ! 752: * XXX This routine assumes that the packet has no options in place. ! 753: */ ! 754: static struct mbuf * ! 755: ip_insertoptions(m, opt, phlen) ! 756: register struct mbuf *m; ! 757: struct mbuf *opt; ! 758: int *phlen; ! 759: { ! 760: register struct ipoption *p = mtod(opt, struct ipoption *); ! 761: struct mbuf *n; ! 762: register struct ip *ip = mtod(m, struct ip *); ! 763: unsigned optlen; ! 764: ! 765: optlen = opt->m_len - sizeof(p->ipopt_dst); ! 766: if (optlen + (u_short)ip->ip_len > IP_MAXPACKET) ! 767: return (m); /* XXX should fail */ ! 768: if (p->ipopt_dst.s_addr) ! 769: ip->ip_dst = p->ipopt_dst; ! 770: if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) { ! 771: MGETHDR(n, M_DONTWAIT, MT_HEADER); ! 772: if (n == 0) ! 773: return (m); ! 774: n->m_pkthdr.len = m->m_pkthdr.len + optlen; ! 775: m->m_len -= sizeof(struct ip); ! 776: m->m_data += sizeof(struct ip); ! 777: n->m_next = m; ! 778: m = n; ! 779: m->m_len = optlen + sizeof(struct ip); ! 780: m->m_data += max_linkhdr; ! 781: (void)memcpy(mtod(m, void *), ip, sizeof(struct ip)); ! 782: } else { ! 783: m->m_data -= optlen; ! 784: m->m_len += optlen; ! 785: m->m_pkthdr.len += optlen; ! 786: ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); ! 787: } ! 788: ip = mtod(m, struct ip *); ! 789: bcopy(p->ipopt_list, ip + 1, optlen); ! 790: *phlen = sizeof(struct ip) + optlen; ! 791: ip->ip_vhl = IP_MAKE_VHL(IPVERSION, *phlen >> 2); ! 792: ip->ip_len += optlen; ! 793: return (m); ! 794: } ! 795: ! 796: /* ! 797: * Copy options from ip to jp, ! 798: * omitting those not copied during fragmentation. ! 799: */ ! 800: #if !IPFILTER && !IPFILTER_LKM ! 801: static ! 802: #endif ! 803: int ! 804: ip_optcopy(ip, jp) ! 805: struct ip *ip, *jp; ! 806: { ! 807: register u_char *cp, *dp; ! 808: int opt, optlen, cnt; ! 809: ! 810: cp = (u_char *)(ip + 1); ! 811: dp = (u_char *)(jp + 1); ! 812: cnt = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip); ! 813: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 814: opt = cp[0]; ! 815: if (opt == IPOPT_EOL) ! 816: break; ! 817: if (opt == IPOPT_NOP) { ! 818: /* Preserve for IP mcast tunnel's LSRR alignment. */ ! 819: *dp++ = IPOPT_NOP; ! 820: optlen = 1; ! 821: continue; ! 822: } else ! 823: optlen = cp[IPOPT_OLEN]; ! 824: /* bogus lengths should have been caught by ip_dooptions */ ! 825: if (optlen > cnt) ! 826: optlen = cnt; ! 827: if (IPOPT_COPIED(opt)) { ! 828: bcopy(cp, dp, optlen); ! 829: dp += optlen; ! 830: } ! 831: } ! 832: for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) ! 833: *dp++ = IPOPT_EOL; ! 834: return (optlen); ! 835: } ! 836: ! 837: /* ! 838: * IP socket option processing. ! 839: */ ! 840: int ! 841: ip_ctloutput(so, sopt) ! 842: struct socket *so; ! 843: struct sockopt *sopt; ! 844: { ! 845: struct inpcb *inp = sotoinpcb(so); ! 846: int error, optval; ! 847: ! 848: error = optval = 0; ! 849: if (sopt->sopt_level != IPPROTO_IP) { ! 850: return (EINVAL); ! 851: } ! 852: ! 853: switch (sopt->sopt_dir) { ! 854: case SOPT_SET: ! 855: switch (sopt->sopt_name) { ! 856: case IP_OPTIONS: ! 857: #ifdef notyet ! 858: case IP_RETOPTS: ! 859: #endif ! 860: { ! 861: struct mbuf *m; ! 862: if (sopt->sopt_valsize > MLEN) { ! 863: error = EMSGSIZE; ! 864: break; ! 865: } ! 866: MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_HEADER); ! 867: if (m == 0) { ! 868: error = ENOBUFS; ! 869: break; ! 870: } ! 871: m->m_len = sopt->sopt_valsize; ! 872: error = sooptcopyin(sopt, mtod(m, char *), m->m_len, ! 873: m->m_len); ! 874: ! 875: return (ip_pcbopts(sopt->sopt_name, &inp->inp_options, ! 876: m)); ! 877: } ! 878: ! 879: case IP_TOS: ! 880: case IP_TTL: ! 881: case IP_RECVOPTS: ! 882: case IP_RECVRETOPTS: ! 883: case IP_RECVDSTADDR: ! 884: case IP_RECVIF: ! 885: error = sooptcopyin(sopt, &optval, sizeof optval, ! 886: sizeof optval); ! 887: if (error) ! 888: break; ! 889: ! 890: switch (sopt->sopt_name) { ! 891: case IP_TOS: ! 892: inp->inp_ip_tos = optval; ! 893: break; ! 894: ! 895: case IP_TTL: ! 896: inp->inp_ip_ttl = optval; ! 897: break; ! 898: #define OPTSET(bit) \ ! 899: if (optval) \ ! 900: inp->inp_flags |= bit; \ ! 901: else \ ! 902: inp->inp_flags &= ~bit; ! 903: ! 904: case IP_RECVOPTS: ! 905: OPTSET(INP_RECVOPTS); ! 906: break; ! 907: ! 908: case IP_RECVRETOPTS: ! 909: OPTSET(INP_RECVRETOPTS); ! 910: break; ! 911: ! 912: case IP_RECVDSTADDR: ! 913: OPTSET(INP_RECVDSTADDR); ! 914: break; ! 915: ! 916: case IP_RECVIF: ! 917: OPTSET(INP_RECVIF); ! 918: break; ! 919: } ! 920: break; ! 921: #undef OPTSET ! 922: ! 923: case IP_MULTICAST_IF: ! 924: case IP_MULTICAST_VIF: ! 925: case IP_MULTICAST_TTL: ! 926: case IP_MULTICAST_LOOP: ! 927: case IP_ADD_MEMBERSHIP: ! 928: case IP_DROP_MEMBERSHIP: ! 929: error = ip_setmoptions(sopt, &inp->inp_moptions); ! 930: break; ! 931: ! 932: case IP_PORTRANGE: ! 933: error = sooptcopyin(sopt, &optval, sizeof optval, ! 934: sizeof optval); ! 935: if (error) ! 936: break; ! 937: ! 938: switch (optval) { ! 939: case IP_PORTRANGE_DEFAULT: ! 940: inp->inp_flags &= ~(INP_LOWPORT); ! 941: inp->inp_flags &= ~(INP_HIGHPORT); ! 942: break; ! 943: ! 944: case IP_PORTRANGE_HIGH: ! 945: inp->inp_flags &= ~(INP_LOWPORT); ! 946: inp->inp_flags |= INP_HIGHPORT; ! 947: break; ! 948: ! 949: case IP_PORTRANGE_LOW: ! 950: inp->inp_flags &= ~(INP_HIGHPORT); ! 951: inp->inp_flags |= INP_LOWPORT; ! 952: break; ! 953: ! 954: default: ! 955: error = EINVAL; ! 956: break; ! 957: } ! 958: break; ! 959: ! 960: default: ! 961: error = ENOPROTOOPT; ! 962: break; ! 963: } ! 964: break; ! 965: ! 966: case SOPT_GET: ! 967: switch (sopt->sopt_name) { ! 968: case IP_OPTIONS: ! 969: case IP_RETOPTS: ! 970: if (inp->inp_options) ! 971: error = sooptcopyout(sopt, ! 972: mtod(inp->inp_options, ! 973: char *), ! 974: inp->inp_options->m_len); ! 975: else ! 976: sopt->sopt_valsize = 0; ! 977: break; ! 978: ! 979: case IP_TOS: ! 980: case IP_TTL: ! 981: case IP_RECVOPTS: ! 982: case IP_RECVRETOPTS: ! 983: case IP_RECVDSTADDR: ! 984: case IP_RECVIF: ! 985: case IP_PORTRANGE: ! 986: switch (sopt->sopt_name) { ! 987: ! 988: case IP_TOS: ! 989: optval = inp->inp_ip_tos; ! 990: break; ! 991: ! 992: case IP_TTL: ! 993: optval = inp->inp_ip_ttl; ! 994: break; ! 995: ! 996: #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0) ! 997: ! 998: case IP_RECVOPTS: ! 999: optval = OPTBIT(INP_RECVOPTS); ! 1000: break; ! 1001: ! 1002: case IP_RECVRETOPTS: ! 1003: optval = OPTBIT(INP_RECVRETOPTS); ! 1004: break; ! 1005: ! 1006: case IP_RECVDSTADDR: ! 1007: optval = OPTBIT(INP_RECVDSTADDR); ! 1008: break; ! 1009: ! 1010: case IP_RECVIF: ! 1011: optval = OPTBIT(INP_RECVIF); ! 1012: break; ! 1013: ! 1014: case IP_PORTRANGE: ! 1015: if (inp->inp_flags & INP_HIGHPORT) ! 1016: optval = IP_PORTRANGE_HIGH; ! 1017: else if (inp->inp_flags & INP_LOWPORT) ! 1018: optval = IP_PORTRANGE_LOW; ! 1019: else ! 1020: optval = 0; ! 1021: break; ! 1022: } ! 1023: error = sooptcopyout(sopt, &optval, sizeof optval); ! 1024: break; ! 1025: ! 1026: case IP_MULTICAST_IF: ! 1027: case IP_MULTICAST_VIF: ! 1028: case IP_MULTICAST_TTL: ! 1029: case IP_MULTICAST_LOOP: ! 1030: case IP_ADD_MEMBERSHIP: ! 1031: case IP_DROP_MEMBERSHIP: ! 1032: error = ip_getmoptions(sopt, inp->inp_moptions); ! 1033: break; ! 1034: ! 1035: default: ! 1036: error = ENOPROTOOPT; ! 1037: break; ! 1038: } ! 1039: break; ! 1040: } ! 1041: return (error); ! 1042: } ! 1043: ! 1044: /* ! 1045: * Set up IP options in pcb for insertion in output packets. ! 1046: * Store in mbuf with pointer in pcbopt, adding pseudo-option ! 1047: * with destination address if source routed. ! 1048: */ ! 1049: static int ! 1050: ip_pcbopts(optname, pcbopt, m) ! 1051: int optname; ! 1052: struct mbuf **pcbopt; ! 1053: register struct mbuf *m; ! 1054: { ! 1055: register int cnt, optlen; ! 1056: register u_char *cp; ! 1057: u_char opt; ! 1058: ! 1059: /* turn off any old options */ ! 1060: if (*pcbopt) ! 1061: (void)m_free(*pcbopt); ! 1062: *pcbopt = 0; ! 1063: if (m == (struct mbuf *)0 || m->m_len == 0) { ! 1064: /* ! 1065: * Only turning off any previous options. ! 1066: */ ! 1067: if (m) ! 1068: (void)m_free(m); ! 1069: return (0); ! 1070: } ! 1071: ! 1072: #ifndef vax ! 1073: if (m->m_len % sizeof(int32_t)) ! 1074: goto bad; ! 1075: #endif ! 1076: /* ! 1077: * IP first-hop destination address will be stored before ! 1078: * actual options; move other options back ! 1079: * and clear it when none present. ! 1080: */ ! 1081: if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) ! 1082: goto bad; ! 1083: cnt = m->m_len; ! 1084: m->m_len += sizeof(struct in_addr); ! 1085: cp = mtod(m, u_char *) + sizeof(struct in_addr); ! 1086: ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); ! 1087: bzero(mtod(m, caddr_t), sizeof(struct in_addr)); ! 1088: ! 1089: for (; cnt > 0; cnt -= optlen, cp += optlen) { ! 1090: opt = cp[IPOPT_OPTVAL]; ! 1091: if (opt == IPOPT_EOL) ! 1092: break; ! 1093: if (opt == IPOPT_NOP) ! 1094: optlen = 1; ! 1095: else { ! 1096: optlen = cp[IPOPT_OLEN]; ! 1097: if (optlen <= IPOPT_OLEN || optlen > cnt) ! 1098: goto bad; ! 1099: } ! 1100: switch (opt) { ! 1101: ! 1102: default: ! 1103: break; ! 1104: ! 1105: case IPOPT_LSRR: ! 1106: case IPOPT_SSRR: ! 1107: /* ! 1108: * user process specifies route as: ! 1109: * ->A->B->C->D ! 1110: * D must be our final destination (but we can't ! 1111: * check that since we may not have connected yet). ! 1112: * A is first hop destination, which doesn't appear in ! 1113: * actual IP option, but is stored before the options. ! 1114: */ ! 1115: if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) ! 1116: goto bad; ! 1117: m->m_len -= sizeof(struct in_addr); ! 1118: cnt -= sizeof(struct in_addr); ! 1119: optlen -= sizeof(struct in_addr); ! 1120: cp[IPOPT_OLEN] = optlen; ! 1121: /* ! 1122: * Move first hop before start of options. ! 1123: */ ! 1124: bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), ! 1125: sizeof(struct in_addr)); ! 1126: /* ! 1127: * Then copy rest of options back ! 1128: * to close up the deleted entry. ! 1129: */ ! 1130: ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + ! 1131: sizeof(struct in_addr)), ! 1132: (caddr_t)&cp[IPOPT_OFFSET+1], ! 1133: (unsigned)cnt + sizeof(struct in_addr)); ! 1134: break; ! 1135: } ! 1136: } ! 1137: if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) ! 1138: goto bad; ! 1139: *pcbopt = m; ! 1140: return (0); ! 1141: ! 1142: bad: ! 1143: (void)m_free(m); ! 1144: return (EINVAL); ! 1145: } ! 1146: ! 1147: /* ! 1148: * XXX ! 1149: * The whole multicast option thing needs to be re-thought. ! 1150: * Several of these options are equally applicable to non-multicast ! 1151: * transmission, and one (IP_MULTICAST_TTL) totally duplicates a ! 1152: * standard option (IP_TTL). ! 1153: */ ! 1154: /* ! 1155: * Set the IP multicast options in response to user setsockopt(). ! 1156: */ ! 1157: static int ! 1158: ip_setmoptions(sopt, imop) ! 1159: struct sockopt *sopt; ! 1160: struct ip_moptions **imop; ! 1161: { ! 1162: int error = 0; ! 1163: int i; ! 1164: struct in_addr addr; ! 1165: struct ip_mreq mreq; ! 1166: struct ifnet *ifp; ! 1167: struct ip_moptions *imo = *imop; ! 1168: struct route ro; ! 1169: struct sockaddr_in *dst; ! 1170: int s; ! 1171: ! 1172: if (imo == NULL) { ! 1173: /* ! 1174: * No multicast option buffer attached to the pcb; ! 1175: * allocate one and initialize to default values. ! 1176: */ ! 1177: imo = (struct ip_moptions*) _MALLOC(sizeof(*imo), M_IPMOPTS, ! 1178: M_WAITOK); ! 1179: ! 1180: if (imo == NULL) ! 1181: return (ENOBUFS); ! 1182: *imop = imo; ! 1183: imo->imo_multicast_ifp = NULL; ! 1184: imo->imo_multicast_vif = -1; ! 1185: imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; ! 1186: imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; ! 1187: imo->imo_num_memberships = 0; ! 1188: } ! 1189: ! 1190: switch (sopt->sopt_name) { ! 1191: /* store an index number for the vif you wanna use in the send */ ! 1192: case IP_MULTICAST_VIF: ! 1193: if (legal_vif_num == 0) { ! 1194: error = EOPNOTSUPP; ! 1195: break; ! 1196: } ! 1197: error = sooptcopyin(sopt, &i, sizeof i, sizeof i); ! 1198: if (error) ! 1199: break; ! 1200: if (!legal_vif_num(i) && (i != -1)) { ! 1201: error = EINVAL; ! 1202: break; ! 1203: } ! 1204: imo->imo_multicast_vif = i; ! 1205: break; ! 1206: ! 1207: case IP_MULTICAST_IF: ! 1208: /* ! 1209: * Select the interface for outgoing multicast packets. ! 1210: */ ! 1211: error = sooptcopyin(sopt, &addr, sizeof addr, sizeof addr); ! 1212: if (error) ! 1213: break; ! 1214: /* ! 1215: * INADDR_ANY is used to remove a previous selection. ! 1216: * When no interface is selected, a default one is ! 1217: * chosen every time a multicast packet is sent. ! 1218: */ ! 1219: if (addr.s_addr == INADDR_ANY) { ! 1220: imo->imo_multicast_ifp = NULL; ! 1221: break; ! 1222: } ! 1223: /* ! 1224: * The selected interface is identified by its local ! 1225: * IP address. Find the interface and confirm that ! 1226: * it supports multicasting. ! 1227: */ ! 1228: s = splimp(); ! 1229: INADDR_TO_IFP(addr, ifp); ! 1230: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { ! 1231: splx(s); ! 1232: error = EADDRNOTAVAIL; ! 1233: break; ! 1234: } ! 1235: imo->imo_multicast_ifp = ifp; ! 1236: splx(s); ! 1237: break; ! 1238: ! 1239: case IP_MULTICAST_TTL: ! 1240: /* ! 1241: * Set the IP time-to-live for outgoing multicast packets. ! 1242: * The original multicast API required a char argument, ! 1243: * which is inconsistent with the rest of the socket API. ! 1244: * We allow either a char or an int. ! 1245: */ ! 1246: if (sopt->sopt_valsize == 1) { ! 1247: u_char ttl; ! 1248: error = sooptcopyin(sopt, &ttl, 1, 1); ! 1249: if (error) ! 1250: break; ! 1251: imo->imo_multicast_ttl = ttl; ! 1252: } else { ! 1253: u_int ttl; ! 1254: error = sooptcopyin(sopt, &ttl, sizeof ttl, ! 1255: sizeof ttl); ! 1256: if (error) ! 1257: break; ! 1258: if (ttl > 255) ! 1259: error = EINVAL; ! 1260: else ! 1261: imo->imo_multicast_ttl = ttl; ! 1262: } ! 1263: break; ! 1264: ! 1265: case IP_MULTICAST_LOOP: ! 1266: /* ! 1267: * Set the loopback flag for outgoing multicast packets. ! 1268: * Must be zero or one. The original multicast API required a ! 1269: * char argument, which is inconsistent with the rest ! 1270: * of the socket API. We allow either a char or an int. ! 1271: */ ! 1272: if (sopt->sopt_valsize == 1) { ! 1273: u_char loop; ! 1274: error = sooptcopyin(sopt, &loop, 1, 1); ! 1275: if (error) ! 1276: break; ! 1277: imo->imo_multicast_loop = !!loop; ! 1278: } else { ! 1279: u_int loop; ! 1280: error = sooptcopyin(sopt, &loop, sizeof loop, ! 1281: sizeof loop); ! 1282: if (error) ! 1283: break; ! 1284: imo->imo_multicast_loop = !!loop; ! 1285: } ! 1286: break; ! 1287: ! 1288: case IP_ADD_MEMBERSHIP: ! 1289: /* ! 1290: * Add a multicast group membership. ! 1291: * Group must be a valid IP multicast address. ! 1292: */ ! 1293: error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq); ! 1294: if (error) ! 1295: break; ! 1296: ! 1297: if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) { ! 1298: error = EINVAL; ! 1299: break; ! 1300: } ! 1301: s = splimp(); ! 1302: /* ! 1303: * If no interface address was provided, use the interface of ! 1304: * the route to the given multicast address. ! 1305: */ ! 1306: if (mreq.imr_interface.s_addr == INADDR_ANY) { ! 1307: bzero((caddr_t)&ro, sizeof(ro)); ! 1308: dst = (struct sockaddr_in *)&ro.ro_dst; ! 1309: dst->sin_len = sizeof(*dst); ! 1310: dst->sin_family = AF_INET; ! 1311: dst->sin_addr = mreq.imr_multiaddr; ! 1312: rtalloc(&ro); ! 1313: if (ro.ro_rt == NULL) { ! 1314: error = EADDRNOTAVAIL; ! 1315: splx(s); ! 1316: break; ! 1317: } ! 1318: ifp = ro.ro_rt->rt_ifp; ! 1319: rtfree(ro.ro_rt); ! 1320: } ! 1321: else { ! 1322: INADDR_TO_IFP(mreq.imr_interface, ifp); ! 1323: } ! 1324: ! 1325: /* ! 1326: * See if we found an interface, and confirm that it ! 1327: * supports multicast. ! 1328: */ ! 1329: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { ! 1330: error = EADDRNOTAVAIL; ! 1331: splx(s); ! 1332: break; ! 1333: } ! 1334: /* ! 1335: * See if the membership already exists or if all the ! 1336: * membership slots are full. ! 1337: */ ! 1338: for (i = 0; i < imo->imo_num_memberships; ++i) { ! 1339: if (imo->imo_membership[i]->inm_ifp == ifp && ! 1340: imo->imo_membership[i]->inm_addr.s_addr ! 1341: == mreq.imr_multiaddr.s_addr) ! 1342: break; ! 1343: } ! 1344: if (i < imo->imo_num_memberships) { ! 1345: error = EADDRINUSE; ! 1346: splx(s); ! 1347: break; ! 1348: } ! 1349: if (i == IP_MAX_MEMBERSHIPS) { ! 1350: error = ETOOMANYREFS; ! 1351: splx(s); ! 1352: break; ! 1353: } ! 1354: /* ! 1355: * Everything looks good; add a new record to the multicast ! 1356: * address list for the given interface. ! 1357: */ ! 1358: if ((imo->imo_membership[i] = ! 1359: in_addmulti(&mreq.imr_multiaddr, ifp)) == NULL) { ! 1360: error = ENOBUFS; ! 1361: splx(s); ! 1362: break; ! 1363: } ! 1364: ++imo->imo_num_memberships; ! 1365: splx(s); ! 1366: break; ! 1367: ! 1368: case IP_DROP_MEMBERSHIP: ! 1369: /* ! 1370: * Drop a multicast group membership. ! 1371: * Group must be a valid IP multicast address. ! 1372: */ ! 1373: error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq); ! 1374: if (error) ! 1375: break; ! 1376: ! 1377: if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) { ! 1378: error = EINVAL; ! 1379: break; ! 1380: } ! 1381: ! 1382: s = splimp(); ! 1383: /* ! 1384: * If an interface address was specified, get a pointer ! 1385: * to its ifnet structure. ! 1386: */ ! 1387: if (mreq.imr_interface.s_addr == INADDR_ANY) ! 1388: ifp = NULL; ! 1389: else { ! 1390: INADDR_TO_IFP(mreq.imr_interface, ifp); ! 1391: if (ifp == NULL) { ! 1392: error = EADDRNOTAVAIL; ! 1393: splx(s); ! 1394: break; ! 1395: } ! 1396: } ! 1397: /* ! 1398: * Find the membership in the membership array. ! 1399: */ ! 1400: for (i = 0; i < imo->imo_num_memberships; ++i) { ! 1401: if ((ifp == NULL || ! 1402: imo->imo_membership[i]->inm_ifp == ifp) && ! 1403: imo->imo_membership[i]->inm_addr.s_addr == ! 1404: mreq.imr_multiaddr.s_addr) ! 1405: break; ! 1406: } ! 1407: if (i == imo->imo_num_memberships) { ! 1408: error = EADDRNOTAVAIL; ! 1409: splx(s); ! 1410: break; ! 1411: } ! 1412: /* ! 1413: * Give up the multicast address record to which the ! 1414: * membership points. ! 1415: */ ! 1416: in_delmulti(imo->imo_membership[i]); ! 1417: /* ! 1418: * Remove the gap in the membership array. ! 1419: */ ! 1420: for (++i; i < imo->imo_num_memberships; ++i) ! 1421: imo->imo_membership[i-1] = imo->imo_membership[i]; ! 1422: --imo->imo_num_memberships; ! 1423: splx(s); ! 1424: break; ! 1425: ! 1426: default: ! 1427: error = EOPNOTSUPP; ! 1428: break; ! 1429: } ! 1430: ! 1431: /* ! 1432: * If all options have default values, no need to keep the mbuf. ! 1433: */ ! 1434: if (imo->imo_multicast_ifp == NULL && ! 1435: imo->imo_multicast_vif == -1 && ! 1436: imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL && ! 1437: imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP && ! 1438: imo->imo_num_memberships == 0) { ! 1439: FREE(*imop, M_IPMOPTS); ! 1440: *imop = NULL; ! 1441: } ! 1442: ! 1443: return (error); ! 1444: } ! 1445: ! 1446: /* ! 1447: * Return the IP multicast options in response to user getsockopt(). ! 1448: */ ! 1449: static int ! 1450: ip_getmoptions(sopt, imo) ! 1451: struct sockopt *sopt; ! 1452: register struct ip_moptions *imo; ! 1453: { ! 1454: struct in_addr addr; ! 1455: struct in_ifaddr *ia; ! 1456: int error, optval; ! 1457: u_char coptval; ! 1458: ! 1459: error = 0; ! 1460: switch (sopt->sopt_name) { ! 1461: case IP_MULTICAST_VIF: ! 1462: if (imo != NULL) ! 1463: optval = imo->imo_multicast_vif; ! 1464: else ! 1465: optval = -1; ! 1466: error = sooptcopyout(sopt, &optval, sizeof optval); ! 1467: break; ! 1468: ! 1469: case IP_MULTICAST_IF: ! 1470: if (imo == NULL || imo->imo_multicast_ifp == NULL) ! 1471: addr.s_addr = INADDR_ANY; ! 1472: else { ! 1473: IFP_TO_IA(imo->imo_multicast_ifp, ia); ! 1474: addr.s_addr = (ia == NULL) ? INADDR_ANY ! 1475: : IA_SIN(ia)->sin_addr.s_addr; ! 1476: } ! 1477: error = sooptcopyout(sopt, &addr, sizeof addr); ! 1478: break; ! 1479: ! 1480: case IP_MULTICAST_TTL: ! 1481: if (imo == 0) ! 1482: optval = coptval = IP_DEFAULT_MULTICAST_TTL; ! 1483: else ! 1484: optval = coptval = imo->imo_multicast_ttl; ! 1485: if (sopt->sopt_valsize == 1) ! 1486: error = sooptcopyout(sopt, &coptval, 1); ! 1487: else ! 1488: error = sooptcopyout(sopt, &optval, sizeof optval); ! 1489: break; ! 1490: ! 1491: case IP_MULTICAST_LOOP: ! 1492: if (imo == 0) ! 1493: optval = coptval = IP_DEFAULT_MULTICAST_LOOP; ! 1494: else ! 1495: optval = coptval = imo->imo_multicast_loop; ! 1496: if (sopt->sopt_valsize == 1) ! 1497: error = sooptcopyout(sopt, &coptval, 1); ! 1498: else ! 1499: error = sooptcopyout(sopt, &optval, sizeof optval); ! 1500: break; ! 1501: ! 1502: default: ! 1503: error = ENOPROTOOPT; ! 1504: break; ! 1505: } ! 1506: return (error); ! 1507: } ! 1508: ! 1509: /* ! 1510: * Discard the IP multicast options. ! 1511: */ ! 1512: void ! 1513: ip_freemoptions(imo) ! 1514: register struct ip_moptions *imo; ! 1515: { ! 1516: register int i; ! 1517: ! 1518: if (imo != NULL) { ! 1519: for (i = 0; i < imo->imo_num_memberships; ++i) ! 1520: in_delmulti(imo->imo_membership[i]); ! 1521: FREE(imo, M_IPMOPTS); ! 1522: } ! 1523: } ! 1524: ! 1525: /* ! 1526: * Routine called from ip_output() to loop back a copy of an IP multicast ! 1527: * packet to the input queue of a specified interface. Note that this ! 1528: * calls the output routine of the loopback "driver", but with an interface ! 1529: * pointer that might NOT be a loopback interface -- evil, but easier than ! 1530: * replicating that code here. ! 1531: */ ! 1532: static void ! 1533: ip_mloopback(ifp, m, dst, hlen) ! 1534: struct ifnet *ifp; ! 1535: register struct mbuf *m; ! 1536: register struct sockaddr_in *dst; ! 1537: int hlen; ! 1538: { ! 1539: register struct ip *ip; ! 1540: struct mbuf *copym; ! 1541: ! 1542: copym = m_copy(m, 0, M_COPYALL); ! 1543: if (copym != NULL && (copym->m_flags & M_EXT || copym->m_len < hlen)) ! 1544: copym = m_pullup(copym, hlen); ! 1545: if (copym != NULL) { ! 1546: /* ! 1547: * We don't bother to fragment if the IP length is greater ! 1548: * than the interface's MTU. Can this possibly matter? ! 1549: */ ! 1550: ip = mtod(copym, struct ip *); ! 1551: ip->ip_len = htons((u_short)ip->ip_len); ! 1552: ip->ip_off = htons((u_short)ip->ip_off); ! 1553: ip->ip_sum = 0; ! 1554: ip->ip_sum = in_cksum(copym, hlen); ! 1555: ! 1556: /* ! 1557: * NB: ! 1558: * It's not clear whether there are any lingering ! 1559: * reentrancy problems in other areas which might ! 1560: * be exposed by using ip_input directly (in ! 1561: * particular, everything which modifies the packet ! 1562: * in-place). Yet another option is using the ! 1563: * protosw directly to deliver the looped back ! 1564: * packet. For the moment, we'll err on the side ! 1565: * of safety by using if_simloop(). ! 1566: */ ! 1567: #if 1 /* XXX */ ! 1568: if (dst->sin_family != AF_INET) { ! 1569: printf("ip_mloopback: bad address family %d\n", ! 1570: dst->sin_family); ! 1571: dst->sin_family = AF_INET; ! 1572: } ! 1573: #endif ! 1574: ! 1575: /* ! 1576: * TedW: ! 1577: * We need to send all loopback traffic down to dlil in case ! 1578: * a filter has tapped-in. ! 1579: */ ! 1580: ! 1581: if (lo_dl_tag == 0) ! 1582: dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET, &lo_dl_tag); ! 1583: ! 1584: if (lo_dl_tag) ! 1585: dlil_output(lo_dl_tag, copym, 0, (struct sockaddr *) dst, 0); ! 1586: else { ! 1587: printf("Warning: ip_output call to dlil_find_dltag failed!\n"); ! 1588: m_freem(copym); ! 1589: } ! 1590: ! 1591: /* if_simloop(ifp, copym, (struct sockaddr *)dst, 0);*/ ! 1592: } ! 1593: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.