Annotation of sys/netinet/ip_output.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ip_output.c,v 1.188 2007/07/20 19:00:35 claudio Exp $ */
! 2: /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1988, 1990, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
! 33: */
! 34:
! 35: #include "pf.h"
! 36:
! 37: #include <sys/param.h>
! 38: #include <sys/systm.h>
! 39: #include <sys/mbuf.h>
! 40: #include <sys/protosw.h>
! 41: #include <sys/socket.h>
! 42: #include <sys/socketvar.h>
! 43: #include <sys/proc.h>
! 44: #include <sys/kernel.h>
! 45:
! 46: #include <net/if.h>
! 47: #include <net/if_enc.h>
! 48: #include <net/route.h>
! 49:
! 50: #include <netinet/in.h>
! 51: #include <netinet/in_systm.h>
! 52: #include <netinet/ip.h>
! 53: #include <netinet/in_pcb.h>
! 54: #include <netinet/in_var.h>
! 55: #include <netinet/ip_var.h>
! 56: #include <netinet/ip_icmp.h>
! 57: #include <netinet/tcp.h>
! 58: #include <netinet/udp.h>
! 59: #include <netinet/tcp_timer.h>
! 60: #include <netinet/tcp_var.h>
! 61: #include <netinet/udp_var.h>
! 62:
! 63: #if NPF > 0
! 64: #include <net/pfvar.h>
! 65: #endif
! 66:
! 67: #ifdef IPSEC
! 68: #ifdef ENCDEBUG
! 69: #define DPRINTF(x) do { if (encdebug) printf x ; } while (0)
! 70: #else
! 71: #define DPRINTF(x)
! 72: #endif
! 73:
! 74: extern u_int8_t get_sa_require(struct inpcb *);
! 75:
! 76: extern int ipsec_auth_default_level;
! 77: extern int ipsec_esp_trans_default_level;
! 78: extern int ipsec_esp_network_default_level;
! 79: extern int ipsec_ipcomp_default_level;
! 80: extern int ipforwarding;
! 81: #endif /* IPSEC */
! 82:
! 83: #ifdef MROUTING
! 84: extern int ipmforwarding;
! 85: #endif
! 86:
! 87: struct mbuf *ip_insertoptions(struct mbuf *, struct mbuf *, int *);
! 88: void ip_mloopback(struct ifnet *, struct mbuf *, struct sockaddr_in *);
! 89:
! 90: /*
! 91: * IP output. The packet in mbuf chain m contains a skeletal IP
! 92: * header (with len, off, ttl, proto, tos, src, dst).
! 93: * The mbuf chain containing the packet will be freed.
! 94: * The mbuf opt, if present, will not be freed.
! 95: */
! 96: int
! 97: ip_output(struct mbuf *m0, ...)
! 98: {
! 99: struct ip *ip;
! 100: struct ifnet *ifp;
! 101: struct mbuf *m = m0;
! 102: int hlen = sizeof (struct ip);
! 103: int len, error = 0;
! 104: struct route iproute;
! 105: struct sockaddr_in *dst;
! 106: struct in_ifaddr *ia;
! 107: struct mbuf *opt;
! 108: struct route *ro;
! 109: int flags;
! 110: struct ip_moptions *imo;
! 111: va_list ap;
! 112: u_int8_t sproto = 0, donerouting = 0;
! 113: u_long mtu;
! 114: #ifdef IPSEC
! 115: u_int32_t icmp_mtu = 0;
! 116: union sockaddr_union sdst;
! 117: u_int32_t sspi;
! 118: struct m_tag *mtag;
! 119: struct tdb_ident *tdbi;
! 120:
! 121: struct inpcb *inp;
! 122: struct tdb *tdb;
! 123: int s;
! 124: #endif /* IPSEC */
! 125:
! 126: va_start(ap, m0);
! 127: opt = va_arg(ap, struct mbuf *);
! 128: ro = va_arg(ap, struct route *);
! 129: flags = va_arg(ap, int);
! 130: imo = va_arg(ap, struct ip_moptions *);
! 131: #ifdef IPSEC
! 132: inp = va_arg(ap, struct inpcb *);
! 133: if (inp && (inp->inp_flags & INP_IPV6) != 0)
! 134: panic("ip_output: IPv6 pcb is passed");
! 135: #endif /* IPSEC */
! 136: va_end(ap);
! 137:
! 138: #ifdef DIAGNOSTIC
! 139: if ((m->m_flags & M_PKTHDR) == 0)
! 140: panic("ip_output no HDR");
! 141: #endif
! 142: if (opt) {
! 143: m = ip_insertoptions(m, opt, &len);
! 144: hlen = len;
! 145: }
! 146:
! 147: ip = mtod(m, struct ip *);
! 148:
! 149: /*
! 150: * Fill in IP header.
! 151: */
! 152: if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
! 153: ip->ip_v = IPVERSION;
! 154: ip->ip_off &= htons(IP_DF);
! 155: ip->ip_id = htons(ip_randomid());
! 156: ip->ip_hl = hlen >> 2;
! 157: ipstat.ips_localout++;
! 158: } else {
! 159: hlen = ip->ip_hl << 2;
! 160: }
! 161:
! 162: /*
! 163: * If we're missing the IP source address, do a route lookup. We'll
! 164: * remember this result, in case we don't need to do any IPsec
! 165: * processing on the packet. We need the source address so we can
! 166: * do an SPD lookup in IPsec; for most packets, the source address
! 167: * is set at a higher level protocol. ICMPs and other packets
! 168: * though (e.g., traceroute) have a source address of zeroes.
! 169: */
! 170: if (ip->ip_src.s_addr == INADDR_ANY) {
! 171: if (flags & IP_ROUTETOETHER) {
! 172: error = EINVAL;
! 173: goto bad;
! 174: }
! 175: donerouting = 1;
! 176:
! 177: if (ro == 0) {
! 178: ro = &iproute;
! 179: bzero((caddr_t)ro, sizeof (*ro));
! 180: }
! 181:
! 182: dst = satosin(&ro->ro_dst);
! 183:
! 184: /*
! 185: * If there is a cached route, check that it is to the same
! 186: * destination and is still up. If not, free it and try again.
! 187: */
! 188: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
! 189: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
! 190: RTFREE(ro->ro_rt);
! 191: ro->ro_rt = (struct rtentry *)0;
! 192: }
! 193:
! 194: if (ro->ro_rt == 0) {
! 195: dst->sin_family = AF_INET;
! 196: dst->sin_len = sizeof(*dst);
! 197: dst->sin_addr = ip->ip_dst;
! 198: }
! 199:
! 200: /*
! 201: * If routing to interface only, short-circuit routing lookup.
! 202: */
! 203: if (flags & IP_ROUTETOIF) {
! 204: if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
! 205: (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
! 206: ipstat.ips_noroute++;
! 207: error = ENETUNREACH;
! 208: goto bad;
! 209: }
! 210:
! 211: ifp = ia->ia_ifp;
! 212: mtu = ifp->if_mtu;
! 213: ip->ip_ttl = 1;
! 214: } else if ((IN_MULTICAST(ip->ip_dst.s_addr) ||
! 215: (ip->ip_dst.s_addr == INADDR_BROADCAST)) &&
! 216: imo != NULL && imo->imo_multicast_ifp != NULL) {
! 217: ifp = imo->imo_multicast_ifp;
! 218: mtu = ifp->if_mtu;
! 219: IFP_TO_IA(ifp, ia);
! 220: } else {
! 221: if (ro->ro_rt == 0)
! 222: rtalloc_mpath(ro, NULL, 0);
! 223:
! 224: if (ro->ro_rt == 0) {
! 225: ipstat.ips_noroute++;
! 226: error = EHOSTUNREACH;
! 227: goto bad;
! 228: }
! 229:
! 230: ia = ifatoia(ro->ro_rt->rt_ifa);
! 231: ifp = ro->ro_rt->rt_ifp;
! 232: if ((mtu = ro->ro_rt->rt_rmx.rmx_mtu) == 0)
! 233: mtu = ifp->if_mtu;
! 234: ro->ro_rt->rt_use++;
! 235:
! 236: if (ro->ro_rt->rt_flags & RTF_GATEWAY)
! 237: dst = satosin(ro->ro_rt->rt_gateway);
! 238: }
! 239:
! 240: /* Set the source IP address */
! 241: if (!IN_MULTICAST(ip->ip_dst.s_addr))
! 242: ip->ip_src = ia->ia_addr.sin_addr;
! 243: }
! 244:
! 245: #ifdef IPSEC
! 246: if (!ipsec_in_use && inp == NULL)
! 247: goto done_spd;
! 248:
! 249: /*
! 250: * splnet is chosen over spltdb because we are not allowed to
! 251: * lower the level, and udp_output calls us in splnet().
! 252: */
! 253: s = splnet();
! 254:
! 255: /* Do we have any pending SAs to apply ? */
! 256: mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
! 257: if (mtag != NULL) {
! 258: #ifdef DIAGNOSTIC
! 259: if (mtag->m_tag_len != sizeof (struct tdb_ident))
! 260: panic("ip_output: tag of length %d (should be %d",
! 261: mtag->m_tag_len, sizeof (struct tdb_ident));
! 262: #endif
! 263: tdbi = (struct tdb_ident *)(mtag + 1);
! 264: tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
! 265: if (tdb == NULL)
! 266: error = -EINVAL;
! 267: m_tag_delete(m, mtag);
! 268: }
! 269: else
! 270: tdb = ipsp_spd_lookup(m, AF_INET, hlen, &error,
! 271: IPSP_DIRECTION_OUT, NULL, inp);
! 272:
! 273: if (tdb == NULL) {
! 274: splx(s);
! 275:
! 276: if (error == 0) {
! 277: /*
! 278: * No IPsec processing required, we'll just send the
! 279: * packet out.
! 280: */
! 281: sproto = 0;
! 282:
! 283: /* Fall through to routing/multicast handling */
! 284: } else {
! 285: /*
! 286: * -EINVAL is used to indicate that the packet should
! 287: * be silently dropped, typically because we've asked
! 288: * key management for an SA.
! 289: */
! 290: if (error == -EINVAL) /* Should silently drop packet */
! 291: error = 0;
! 292:
! 293: m_freem(m);
! 294: goto done;
! 295: }
! 296: } else {
! 297: /* Loop detection */
! 298: for (mtag = m_tag_first(m); mtag != NULL;
! 299: mtag = m_tag_next(m, mtag)) {
! 300: if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE &&
! 301: mtag->m_tag_id !=
! 302: PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED)
! 303: continue;
! 304: tdbi = (struct tdb_ident *)(mtag + 1);
! 305: if (tdbi->spi == tdb->tdb_spi &&
! 306: tdbi->proto == tdb->tdb_sproto &&
! 307: !bcmp(&tdbi->dst, &tdb->tdb_dst,
! 308: sizeof(union sockaddr_union))) {
! 309: splx(s);
! 310: sproto = 0; /* mark as no-IPsec-needed */
! 311: goto done_spd;
! 312: }
! 313: }
! 314:
! 315: /* We need to do IPsec */
! 316: bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
! 317: sspi = tdb->tdb_spi;
! 318: sproto = tdb->tdb_sproto;
! 319: splx(s);
! 320:
! 321: /*
! 322: * If it needs TCP/UDP hardware-checksumming, do the
! 323: * computation now.
! 324: */
! 325: if (m->m_pkthdr.csum_flags & (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT)) {
! 326: in_delayed_cksum(m);
! 327: m->m_pkthdr.csum_flags &=
! 328: ~(M_UDPV4_CSUM_OUT | M_TCPV4_CSUM_OUT);
! 329: }
! 330:
! 331: /* If it's not a multicast packet, try to fast-path */
! 332: if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
! 333: goto sendit;
! 334: }
! 335: }
! 336:
! 337: /* Fall through to the routing/multicast handling code */
! 338: done_spd:
! 339: #endif /* IPSEC */
! 340:
! 341: if (flags & IP_ROUTETOETHER) {
! 342: dst = satosin(&ro->ro_dst);
! 343: ifp = ro->ro_rt->rt_ifp;
! 344: mtu = ifp->if_mtu;
! 345: ro->ro_rt = NULL;
! 346: } else if (donerouting == 0) {
! 347: if (ro == 0) {
! 348: ro = &iproute;
! 349: bzero((caddr_t)ro, sizeof (*ro));
! 350: }
! 351:
! 352: dst = satosin(&ro->ro_dst);
! 353:
! 354: /*
! 355: * If there is a cached route, check that it is to the same
! 356: * destination and is still up. If not, free it and try again.
! 357: */
! 358: if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
! 359: dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
! 360: RTFREE(ro->ro_rt);
! 361: ro->ro_rt = (struct rtentry *)0;
! 362: }
! 363:
! 364: if (ro->ro_rt == 0) {
! 365: dst->sin_family = AF_INET;
! 366: dst->sin_len = sizeof(*dst);
! 367: dst->sin_addr = ip->ip_dst;
! 368: }
! 369:
! 370: /*
! 371: * If routing to interface only, short-circuit routing lookup.
! 372: */
! 373: if (flags & IP_ROUTETOIF) {
! 374: if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
! 375: (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
! 376: ipstat.ips_noroute++;
! 377: error = ENETUNREACH;
! 378: goto bad;
! 379: }
! 380:
! 381: ifp = ia->ia_ifp;
! 382: mtu = ifp->if_mtu;
! 383: ip->ip_ttl = 1;
! 384: } else if ((IN_MULTICAST(ip->ip_dst.s_addr) ||
! 385: (ip->ip_dst.s_addr == INADDR_BROADCAST)) &&
! 386: imo != NULL && imo->imo_multicast_ifp != NULL) {
! 387: ifp = imo->imo_multicast_ifp;
! 388: mtu = ifp->if_mtu;
! 389: IFP_TO_IA(ifp, ia);
! 390: } else {
! 391: if (ro->ro_rt == 0)
! 392: rtalloc_mpath(ro, &ip->ip_src.s_addr, 0);
! 393:
! 394: if (ro->ro_rt == 0) {
! 395: ipstat.ips_noroute++;
! 396: error = EHOSTUNREACH;
! 397: goto bad;
! 398: }
! 399:
! 400: ia = ifatoia(ro->ro_rt->rt_ifa);
! 401: ifp = ro->ro_rt->rt_ifp;
! 402: if ((mtu = ro->ro_rt->rt_rmx.rmx_mtu) == 0)
! 403: mtu = ifp->if_mtu;
! 404: ro->ro_rt->rt_use++;
! 405:
! 406: if (ro->ro_rt->rt_flags & RTF_GATEWAY)
! 407: dst = satosin(ro->ro_rt->rt_gateway);
! 408: }
! 409:
! 410: /* Set the source IP address */
! 411: if (ip->ip_src.s_addr == INADDR_ANY)
! 412: ip->ip_src = ia->ia_addr.sin_addr;
! 413: }
! 414:
! 415: if (IN_MULTICAST(ip->ip_dst.s_addr) ||
! 416: (ip->ip_dst.s_addr == INADDR_BROADCAST)) {
! 417: struct in_multi *inm;
! 418:
! 419: m->m_flags |= (ip->ip_dst.s_addr == INADDR_BROADCAST) ?
! 420: M_BCAST : M_MCAST;
! 421:
! 422: /*
! 423: * IP destination address is multicast. Make sure "dst"
! 424: * still points to the address in "ro". (It may have been
! 425: * changed to point to a gateway address, above.)
! 426: */
! 427: dst = satosin(&ro->ro_dst);
! 428:
! 429: /*
! 430: * See if the caller provided any multicast options
! 431: */
! 432: if (imo != NULL)
! 433: ip->ip_ttl = imo->imo_multicast_ttl;
! 434: else
! 435: ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
! 436:
! 437: /*
! 438: * if we don't know the outgoing ifp yet, we can't generate
! 439: * output
! 440: */
! 441: if (!ifp) {
! 442: ipstat.ips_noroute++;
! 443: error = EHOSTUNREACH;
! 444: goto bad;
! 445: }
! 446:
! 447: /*
! 448: * Confirm that the outgoing interface supports multicast,
! 449: * but only if the packet actually is going out on that
! 450: * interface (i.e., no IPsec is applied).
! 451: */
! 452: if ((((m->m_flags & M_MCAST) &&
! 453: (ifp->if_flags & IFF_MULTICAST) == 0) ||
! 454: ((m->m_flags & M_BCAST) &&
! 455: (ifp->if_flags & IFF_BROADCAST) == 0)) && (sproto == 0)) {
! 456: ipstat.ips_noroute++;
! 457: error = ENETUNREACH;
! 458: goto bad;
! 459: }
! 460:
! 461: /*
! 462: * If source address not specified yet, use address
! 463: * of outgoing interface.
! 464: */
! 465: if (ip->ip_src.s_addr == INADDR_ANY) {
! 466: struct in_ifaddr *ia;
! 467:
! 468: TAILQ_FOREACH(ia, &in_ifaddr, ia_list)
! 469: if (ia->ia_ifp == ifp) {
! 470: ip->ip_src = ia->ia_addr.sin_addr;
! 471: break;
! 472: }
! 473: }
! 474:
! 475: IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
! 476: if (inm != NULL &&
! 477: (imo == NULL || imo->imo_multicast_loop)) {
! 478: /*
! 479: * If we belong to the destination multicast group
! 480: * on the outgoing interface, and the caller did not
! 481: * forbid loopback, loop back a copy.
! 482: * Can't defer TCP/UDP checksumming, do the
! 483: * computation now.
! 484: */
! 485: if (m->m_pkthdr.csum_flags &
! 486: (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT)) {
! 487: in_delayed_cksum(m);
! 488: m->m_pkthdr.csum_flags &=
! 489: ~(M_UDPV4_CSUM_OUT | M_TCPV4_CSUM_OUT);
! 490: }
! 491: ip_mloopback(ifp, m, dst);
! 492: }
! 493: #ifdef MROUTING
! 494: else {
! 495: /*
! 496: * If we are acting as a multicast router, perform
! 497: * multicast forwarding as if the packet had just
! 498: * arrived on the interface to which we are about
! 499: * to send. The multicast forwarding function
! 500: * recursively calls this function, using the
! 501: * IP_FORWARDING flag to prevent infinite recursion.
! 502: *
! 503: * Multicasts that are looped back by ip_mloopback(),
! 504: * above, will be forwarded by the ip_input() routine,
! 505: * if necessary.
! 506: */
! 507: extern struct socket *ip_mrouter;
! 508:
! 509: if (ipmforwarding && ip_mrouter &&
! 510: (flags & IP_FORWARDING) == 0) {
! 511: if (ip_mforward(m, ifp) != 0) {
! 512: m_freem(m);
! 513: goto done;
! 514: }
! 515: }
! 516: }
! 517: #endif
! 518: /*
! 519: * Multicasts with a time-to-live of zero may be looped-
! 520: * back, above, but must not be transmitted on a network.
! 521: * Also, multicasts addressed to the loopback interface
! 522: * are not sent -- the above call to ip_mloopback() will
! 523: * loop back a copy if this host actually belongs to the
! 524: * destination group on the loopback interface.
! 525: */
! 526: if (ip->ip_ttl == 0 || (ifp->if_flags & IFF_LOOPBACK) != 0) {
! 527: m_freem(m);
! 528: goto done;
! 529: }
! 530:
! 531: goto sendit;
! 532: }
! 533:
! 534: /*
! 535: * Look for broadcast address and and verify user is allowed to send
! 536: * such a packet; if the packet is going in an IPsec tunnel, skip
! 537: * this check.
! 538: */
! 539: if ((sproto == 0) && (in_broadcast(dst->sin_addr, ifp))) {
! 540: if ((ifp->if_flags & IFF_BROADCAST) == 0) {
! 541: error = EADDRNOTAVAIL;
! 542: goto bad;
! 543: }
! 544: if ((flags & IP_ALLOWBROADCAST) == 0) {
! 545: error = EACCES;
! 546: goto bad;
! 547: }
! 548:
! 549: /* Don't allow broadcast messages to be fragmented */
! 550: if (ntohs(ip->ip_len) > ifp->if_mtu) {
! 551: error = EMSGSIZE;
! 552: goto bad;
! 553: }
! 554: m->m_flags |= M_BCAST;
! 555: } else
! 556: m->m_flags &= ~M_BCAST;
! 557:
! 558: sendit:
! 559: /*
! 560: * If we're doing Path MTU discovery, we need to set DF unless
! 561: * the route's MTU is locked.
! 562: */
! 563: if ((flags & IP_MTUDISC) && ro && ro->ro_rt &&
! 564: (ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
! 565: ip->ip_off |= htons(IP_DF);
! 566:
! 567: #ifdef IPSEC
! 568: /*
! 569: * Check if the packet needs encapsulation.
! 570: */
! 571: if (sproto != 0) {
! 572: s = splnet();
! 573:
! 574: /*
! 575: * Packet filter
! 576: */
! 577: #if NPF > 0
! 578:
! 579: if (pf_test(PF_OUT, &encif[0].sc_if, &m, NULL) != PF_PASS) {
! 580: error = EHOSTUNREACH;
! 581: splx(s);
! 582: m_freem(m);
! 583: goto done;
! 584: }
! 585: if (m == NULL) {
! 586: splx(s);
! 587: goto done;
! 588: }
! 589: ip = mtod(m, struct ip *);
! 590: hlen = ip->ip_hl << 2;
! 591: #endif
! 592:
! 593: tdb = gettdb(sspi, &sdst, sproto);
! 594: if (tdb == NULL) {
! 595: DPRINTF(("ip_output: unknown TDB"));
! 596: error = EHOSTUNREACH;
! 597: splx(s);
! 598: m_freem(m);
! 599: goto done;
! 600: }
! 601:
! 602: /* Check if we are allowed to fragment */
! 603: if (ip_mtudisc && (ip->ip_off & htons(IP_DF)) && tdb->tdb_mtu &&
! 604: ntohs(ip->ip_len) > tdb->tdb_mtu &&
! 605: tdb->tdb_mtutimeout > time_second) {
! 606: struct rtentry *rt = NULL;
! 607: int rt_mtucloned = 0;
! 608: int transportmode = 0;
! 609:
! 610: transportmode = (tdb->tdb_dst.sa.sa_family == AF_INET) &&
! 611: (tdb->tdb_dst.sin.sin_addr.s_addr ==
! 612: ip->ip_dst.s_addr);
! 613: icmp_mtu = tdb->tdb_mtu;
! 614: splx(s);
! 615:
! 616: /* Find a host route to store the mtu in */
! 617: if (ro != NULL)
! 618: rt = ro->ro_rt;
! 619: /* but don't add a PMTU route for transport mode SAs */
! 620: if (transportmode)
! 621: rt = NULL;
! 622: else if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0) {
! 623: struct sockaddr_in dst = {
! 624: sizeof(struct sockaddr_in), AF_INET};
! 625: dst.sin_addr = ip->ip_dst;
! 626: rt = icmp_mtudisc_clone((struct sockaddr *)&dst);
! 627: rt_mtucloned = 1;
! 628: }
! 629: DPRINTF(("ip_output: spi %08x mtu %d rt %p cloned %d\n",
! 630: ntohl(tdb->tdb_spi), icmp_mtu, rt, rt_mtucloned));
! 631: if (rt != NULL) {
! 632: rt->rt_rmx.rmx_mtu = icmp_mtu;
! 633: if (ro && ro->ro_rt != NULL) {
! 634: RTFREE(ro->ro_rt);
! 635: ro->ro_rt = (struct rtentry *) 0;
! 636: rtalloc(ro);
! 637: }
! 638: if (rt_mtucloned)
! 639: rtfree(rt);
! 640: }
! 641: error = EMSGSIZE;
! 642: goto bad;
! 643: }
! 644:
! 645: /*
! 646: * Clear these -- they'll be set in the recursive invocation
! 647: * as needed.
! 648: */
! 649: m->m_flags &= ~(M_MCAST | M_BCAST);
! 650:
! 651: /* Callee frees mbuf */
! 652: error = ipsp_process_packet(m, tdb, AF_INET, 0);
! 653: splx(s);
! 654: return error; /* Nothing more to be done */
! 655: }
! 656:
! 657: /*
! 658: * If deferred crypto processing is needed, check that the
! 659: * interface supports it.
! 660: */
! 661: if (ipsec_in_use && (mtag = m_tag_find(m,
! 662: PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL)) != NULL &&
! 663: (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
! 664: /* Notify IPsec to do its own crypto. */
! 665: ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
! 666: m_freem(m);
! 667: error = EHOSTUNREACH;
! 668: goto done;
! 669: }
! 670: #endif /* IPSEC */
! 671:
! 672: /* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
! 673: if (m->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) {
! 674: if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
! 675: ifp->if_bridge != NULL) {
! 676: in_delayed_cksum(m);
! 677: m->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */
! 678: }
! 679: } else if (m->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
! 680: if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
! 681: ifp->if_bridge != NULL) {
! 682: in_delayed_cksum(m);
! 683: m->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */
! 684: }
! 685: }
! 686:
! 687: /*
! 688: * Packet filter
! 689: */
! 690: #if NPF > 0
! 691: if (pf_test(PF_OUT, ifp, &m, NULL) != PF_PASS) {
! 692: error = EHOSTUNREACH;
! 693: m_freem(m);
! 694: goto done;
! 695: }
! 696: if (m == NULL)
! 697: goto done;
! 698:
! 699: ip = mtod(m, struct ip *);
! 700: hlen = ip->ip_hl << 2;
! 701: #endif
! 702:
! 703: #ifdef IPSEC
! 704: if (ipsec_in_use && (flags & IP_FORWARDING) && (ipforwarding == 2) &&
! 705: (m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) == NULL)) {
! 706: error = EHOSTUNREACH;
! 707: m_freem(m);
! 708: goto done;
! 709: }
! 710: #endif
! 711:
! 712: /* XXX
! 713: * Try to use jumbograms based on socket option, or the route
! 714: * or... for other reasons later on.
! 715: */
! 716: if ((flags & IP_JUMBO) && ro->ro_rt && (ro->ro_rt->rt_flags & RTF_JUMBO) &&
! 717: ro->ro_rt->rt_ifp)
! 718: mtu = ro->ro_rt->rt_ifp->if_hardmtu;
! 719:
! 720: /*
! 721: * If small enough for interface, can just send directly.
! 722: */
! 723: if (ntohs(ip->ip_len) <= mtu) {
! 724: if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
! 725: ifp->if_bridge == NULL) {
! 726: m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
! 727: ipstat.ips_outhwcsum++;
! 728: } else {
! 729: ip->ip_sum = 0;
! 730: ip->ip_sum = in_cksum(m, hlen);
! 731: }
! 732: /* Update relevant hardware checksum stats for TCP/UDP */
! 733: if (m->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
! 734: tcpstat.tcps_outhwcsum++;
! 735: else if (m->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
! 736: udpstat.udps_outhwcsum++;
! 737: error = (*ifp->if_output)(ifp, m, sintosa(dst), ro->ro_rt);
! 738: goto done;
! 739: }
! 740:
! 741: /*
! 742: * Too large for interface; fragment if possible.
! 743: * Must be able to put at least 8 bytes per fragment.
! 744: */
! 745: if (ip->ip_off & htons(IP_DF)) {
! 746: #ifdef IPSEC
! 747: icmp_mtu = ifp->if_mtu;
! 748: #endif
! 749: error = EMSGSIZE;
! 750: /*
! 751: * This case can happen if the user changed the MTU
! 752: * of an interface after enabling IP on it. Because
! 753: * most netifs don't keep track of routes pointing to
! 754: * them, there is no way for one to update all its
! 755: * routes when the MTU is changed.
! 756: */
! 757: if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST)) &&
! 758: !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU) &&
! 759: (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) {
! 760: ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
! 761: }
! 762: ipstat.ips_cantfrag++;
! 763: goto bad;
! 764: }
! 765:
! 766: error = ip_fragment(m, ifp, mtu);
! 767: if (error) {
! 768: m = m0 = NULL;
! 769: goto bad;
! 770: }
! 771:
! 772: for (; m; m = m0) {
! 773: m0 = m->m_nextpkt;
! 774: m->m_nextpkt = 0;
! 775: if (error == 0)
! 776: error = (*ifp->if_output)(ifp, m, sintosa(dst),
! 777: ro->ro_rt);
! 778: else
! 779: m_freem(m);
! 780: }
! 781:
! 782: if (error == 0)
! 783: ipstat.ips_fragmented++;
! 784:
! 785: done:
! 786: if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
! 787: RTFREE(ro->ro_rt);
! 788: return (error);
! 789: bad:
! 790: #ifdef IPSEC
! 791: if (error == EMSGSIZE && ip_mtudisc && icmp_mtu != 0 && m != NULL)
! 792: ipsec_adjust_mtu(m, icmp_mtu);
! 793: #endif
! 794: m_freem(m0);
! 795: goto done;
! 796: }
! 797:
! 798: int
! 799: ip_fragment(struct mbuf *m, struct ifnet *ifp, u_long mtu)
! 800: {
! 801: struct ip *ip, *mhip;
! 802: struct mbuf *m0;
! 803: int len, hlen, off;
! 804: int mhlen, firstlen;
! 805: struct mbuf **mnext;
! 806: int fragments = 0;
! 807: int s;
! 808: int error = 0;
! 809:
! 810: ip = mtod(m, struct ip *);
! 811: hlen = ip->ip_hl << 2;
! 812:
! 813: len = (mtu - hlen) &~ 7;
! 814: if (len < 8) {
! 815: m_freem(m);
! 816: return (EMSGSIZE);
! 817: }
! 818:
! 819: /*
! 820: * If we are doing fragmentation, we can't defer TCP/UDP
! 821: * checksumming; compute the checksum and clear the flag.
! 822: */
! 823: if (m->m_pkthdr.csum_flags & (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT)) {
! 824: in_delayed_cksum(m);
! 825: m->m_pkthdr.csum_flags &= ~(M_UDPV4_CSUM_OUT | M_TCPV4_CSUM_OUT);
! 826: }
! 827:
! 828: firstlen = len;
! 829: mnext = &m->m_nextpkt;
! 830:
! 831: /*
! 832: * Loop through length of segment after first fragment,
! 833: * make new header and copy data of each part and link onto chain.
! 834: */
! 835: m0 = m;
! 836: mhlen = sizeof (struct ip);
! 837: for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
! 838: MGETHDR(m, M_DONTWAIT, MT_HEADER);
! 839: if (m == 0) {
! 840: ipstat.ips_odropped++;
! 841: error = ENOBUFS;
! 842: goto sendorfree;
! 843: }
! 844: *mnext = m;
! 845: mnext = &m->m_nextpkt;
! 846: m->m_data += max_linkhdr;
! 847: mhip = mtod(m, struct ip *);
! 848: *mhip = *ip;
! 849: /* we must inherit MCAST and BCAST flags */
! 850: m->m_flags |= m0->m_flags & (M_MCAST|M_BCAST);
! 851: if (hlen > sizeof (struct ip)) {
! 852: mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
! 853: mhip->ip_hl = mhlen >> 2;
! 854: }
! 855: m->m_len = mhlen;
! 856: mhip->ip_off = ((off - hlen) >> 3) +
! 857: (ntohs(ip->ip_off) & ~IP_MF);
! 858: if (ip->ip_off & htons(IP_MF))
! 859: mhip->ip_off |= IP_MF;
! 860: if (off + len >= ntohs(ip->ip_len))
! 861: len = ntohs(ip->ip_len) - off;
! 862: else
! 863: mhip->ip_off |= IP_MF;
! 864: mhip->ip_len = htons((u_int16_t)(len + mhlen));
! 865: m->m_next = m_copy(m0, off, len);
! 866: if (m->m_next == 0) {
! 867: ipstat.ips_odropped++;
! 868: error = ENOBUFS;
! 869: goto sendorfree;
! 870: }
! 871: m->m_pkthdr.len = mhlen + len;
! 872: m->m_pkthdr.rcvif = (struct ifnet *)0;
! 873: mhip->ip_off = htons((u_int16_t)mhip->ip_off);
! 874: if ((ifp != NULL) &&
! 875: (ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
! 876: ifp->if_bridge == NULL) {
! 877: m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
! 878: ipstat.ips_outhwcsum++;
! 879: } else {
! 880: mhip->ip_sum = 0;
! 881: mhip->ip_sum = in_cksum(m, mhlen);
! 882: }
! 883: ipstat.ips_ofragments++;
! 884: fragments++;
! 885: }
! 886: /*
! 887: * Update first fragment by trimming what's been copied out
! 888: * and updating header, then send each fragment (in order).
! 889: */
! 890: m = m0;
! 891: m_adj(m, hlen + firstlen - ntohs(ip->ip_len));
! 892: m->m_pkthdr.len = hlen + firstlen;
! 893: ip->ip_len = htons((u_int16_t)m->m_pkthdr.len);
! 894: ip->ip_off |= htons(IP_MF);
! 895: if ((ifp != NULL) &&
! 896: (ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
! 897: ifp->if_bridge == NULL) {
! 898: m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
! 899: ipstat.ips_outhwcsum++;
! 900: } else {
! 901: ip->ip_sum = 0;
! 902: ip->ip_sum = in_cksum(m, hlen);
! 903: }
! 904: sendorfree:
! 905: /*
! 906: * If there is no room for all the fragments, don't queue
! 907: * any of them.
! 908: */
! 909: if (ifp != NULL) {
! 910: s = splnet();
! 911: if (ifp->if_snd.ifq_maxlen - ifp->if_snd.ifq_len < fragments &&
! 912: error == 0) {
! 913: error = ENOBUFS;
! 914: ipstat.ips_odropped++;
! 915: IFQ_INC_DROPS(&ifp->if_snd);
! 916: }
! 917: splx(s);
! 918: }
! 919: if (error) {
! 920: for (m = m0; m; m = m0) {
! 921: m0 = m->m_nextpkt;
! 922: m->m_nextpkt = NULL;
! 923: m_freem(m);
! 924: }
! 925: }
! 926:
! 927: return (error);
! 928: }
! 929:
! 930: /*
! 931: * Insert IP options into preformed packet.
! 932: * Adjust IP destination as required for IP source routing,
! 933: * as indicated by a non-zero in_addr at the start of the options.
! 934: */
! 935: struct mbuf *
! 936: ip_insertoptions(m, opt, phlen)
! 937: struct mbuf *m;
! 938: struct mbuf *opt;
! 939: int *phlen;
! 940: {
! 941: struct ipoption *p = mtod(opt, struct ipoption *);
! 942: struct mbuf *n;
! 943: struct ip *ip = mtod(m, struct ip *);
! 944: unsigned optlen;
! 945:
! 946: optlen = opt->m_len - sizeof(p->ipopt_dst);
! 947: if (optlen + ntohs(ip->ip_len) > IP_MAXPACKET)
! 948: return (m); /* XXX should fail */
! 949: if (p->ipopt_dst.s_addr)
! 950: ip->ip_dst = p->ipopt_dst;
! 951: if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
! 952: MGETHDR(n, M_DONTWAIT, MT_HEADER);
! 953: if (n == 0)
! 954: return (m);
! 955: M_MOVE_HDR(n, m);
! 956: n->m_pkthdr.len += optlen;
! 957: m->m_len -= sizeof(struct ip);
! 958: m->m_data += sizeof(struct ip);
! 959: n->m_next = m;
! 960: m = n;
! 961: m->m_len = optlen + sizeof(struct ip);
! 962: m->m_data += max_linkhdr;
! 963: bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
! 964: } else {
! 965: m->m_data -= optlen;
! 966: m->m_len += optlen;
! 967: m->m_pkthdr.len += optlen;
! 968: ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
! 969: }
! 970: ip = mtod(m, struct ip *);
! 971: bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
! 972: *phlen = sizeof(struct ip) + optlen;
! 973: ip->ip_len = htons(ntohs(ip->ip_len) + optlen);
! 974: return (m);
! 975: }
! 976:
! 977: /*
! 978: * Copy options from ip to jp,
! 979: * omitting those not copied during fragmentation.
! 980: */
! 981: int
! 982: ip_optcopy(ip, jp)
! 983: struct ip *ip, *jp;
! 984: {
! 985: u_char *cp, *dp;
! 986: int opt, optlen, cnt;
! 987:
! 988: cp = (u_char *)(ip + 1);
! 989: dp = (u_char *)(jp + 1);
! 990: cnt = (ip->ip_hl << 2) - sizeof (struct ip);
! 991: for (; cnt > 0; cnt -= optlen, cp += optlen) {
! 992: opt = cp[0];
! 993: if (opt == IPOPT_EOL)
! 994: break;
! 995: if (opt == IPOPT_NOP) {
! 996: /* Preserve for IP mcast tunnel's LSRR alignment. */
! 997: *dp++ = IPOPT_NOP;
! 998: optlen = 1;
! 999: continue;
! 1000: }
! 1001: #ifdef DIAGNOSTIC
! 1002: if (cnt < IPOPT_OLEN + sizeof(*cp))
! 1003: panic("malformed IPv4 option passed to ip_optcopy");
! 1004: #endif
! 1005: optlen = cp[IPOPT_OLEN];
! 1006: #ifdef DIAGNOSTIC
! 1007: if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
! 1008: panic("malformed IPv4 option passed to ip_optcopy");
! 1009: #endif
! 1010: /* bogus lengths should have been caught by ip_dooptions */
! 1011: if (optlen > cnt)
! 1012: optlen = cnt;
! 1013: if (IPOPT_COPIED(opt)) {
! 1014: bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
! 1015: dp += optlen;
! 1016: }
! 1017: }
! 1018: for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
! 1019: *dp++ = IPOPT_EOL;
! 1020: return (optlen);
! 1021: }
! 1022:
! 1023: /*
! 1024: * IP socket option processing.
! 1025: */
! 1026: int
! 1027: ip_ctloutput(op, so, level, optname, mp)
! 1028: int op;
! 1029: struct socket *so;
! 1030: int level, optname;
! 1031: struct mbuf **mp;
! 1032: {
! 1033: struct inpcb *inp = sotoinpcb(so);
! 1034: struct mbuf *m = *mp;
! 1035: int optval = 0;
! 1036: #ifdef IPSEC
! 1037: struct proc *p = curproc; /* XXX */
! 1038: struct ipsec_ref *ipr;
! 1039: u_int16_t opt16val;
! 1040: #endif
! 1041: int error = 0;
! 1042:
! 1043: if (level != IPPROTO_IP) {
! 1044: error = EINVAL;
! 1045: if (op == PRCO_SETOPT && *mp)
! 1046: (void) m_free(*mp);
! 1047: } else switch (op) {
! 1048: case PRCO_SETOPT:
! 1049: switch (optname) {
! 1050: case IP_OPTIONS:
! 1051: #ifdef notyet
! 1052: case IP_RETOPTS:
! 1053: return (ip_pcbopts(optname, &inp->inp_options, m));
! 1054: #else
! 1055: return (ip_pcbopts(&inp->inp_options, m));
! 1056: #endif
! 1057:
! 1058: case IP_TOS:
! 1059: case IP_TTL:
! 1060: case IP_MINTTL:
! 1061: case IP_RECVOPTS:
! 1062: case IP_RECVRETOPTS:
! 1063: case IP_RECVDSTADDR:
! 1064: case IP_RECVIF:
! 1065: case IP_RECVTTL:
! 1066: if (m == NULL || m->m_len != sizeof(int))
! 1067: error = EINVAL;
! 1068: else {
! 1069: optval = *mtod(m, int *);
! 1070: switch (optname) {
! 1071:
! 1072: case IP_TOS:
! 1073: inp->inp_ip.ip_tos = optval;
! 1074: break;
! 1075:
! 1076: case IP_TTL:
! 1077: if (optval > 0 && optval <= MAXTTL)
! 1078: inp->inp_ip.ip_ttl = optval;
! 1079: else
! 1080: error = EINVAL;
! 1081: break;
! 1082:
! 1083: case IP_MINTTL:
! 1084: if (optval > 0 && optval <= MAXTTL)
! 1085: inp->inp_ip_minttl = optval;
! 1086: else
! 1087: error = EINVAL;
! 1088: break;
! 1089: #define OPTSET(bit) \
! 1090: if (optval) \
! 1091: inp->inp_flags |= bit; \
! 1092: else \
! 1093: inp->inp_flags &= ~bit;
! 1094:
! 1095: case IP_RECVOPTS:
! 1096: OPTSET(INP_RECVOPTS);
! 1097: break;
! 1098:
! 1099: case IP_RECVRETOPTS:
! 1100: OPTSET(INP_RECVRETOPTS);
! 1101: break;
! 1102:
! 1103: case IP_RECVDSTADDR:
! 1104: OPTSET(INP_RECVDSTADDR);
! 1105: break;
! 1106: case IP_RECVIF:
! 1107: OPTSET(INP_RECVIF);
! 1108: break;
! 1109: case IP_RECVTTL:
! 1110: OPTSET(INP_RECVTTL);
! 1111: break;
! 1112: }
! 1113: }
! 1114: break;
! 1115: #undef OPTSET
! 1116:
! 1117: case IP_MULTICAST_IF:
! 1118: case IP_MULTICAST_TTL:
! 1119: case IP_MULTICAST_LOOP:
! 1120: case IP_ADD_MEMBERSHIP:
! 1121: case IP_DROP_MEMBERSHIP:
! 1122: error = ip_setmoptions(optname, &inp->inp_moptions, m);
! 1123: break;
! 1124:
! 1125: case IP_PORTRANGE:
! 1126: if (m == 0 || m->m_len != sizeof(int))
! 1127: error = EINVAL;
! 1128: else {
! 1129: optval = *mtod(m, int *);
! 1130:
! 1131: switch (optval) {
! 1132:
! 1133: case IP_PORTRANGE_DEFAULT:
! 1134: inp->inp_flags &= ~(INP_LOWPORT);
! 1135: inp->inp_flags &= ~(INP_HIGHPORT);
! 1136: break;
! 1137:
! 1138: case IP_PORTRANGE_HIGH:
! 1139: inp->inp_flags &= ~(INP_LOWPORT);
! 1140: inp->inp_flags |= INP_HIGHPORT;
! 1141: break;
! 1142:
! 1143: case IP_PORTRANGE_LOW:
! 1144: inp->inp_flags &= ~(INP_HIGHPORT);
! 1145: inp->inp_flags |= INP_LOWPORT;
! 1146: break;
! 1147:
! 1148: default:
! 1149:
! 1150: error = EINVAL;
! 1151: break;
! 1152: }
! 1153: }
! 1154: break;
! 1155: case IP_AUTH_LEVEL:
! 1156: case IP_ESP_TRANS_LEVEL:
! 1157: case IP_ESP_NETWORK_LEVEL:
! 1158: case IP_IPCOMP_LEVEL:
! 1159: #ifndef IPSEC
! 1160: error = EOPNOTSUPP;
! 1161: #else
! 1162: if (m == 0 || m->m_len != sizeof(int)) {
! 1163: error = EINVAL;
! 1164: break;
! 1165: }
! 1166: optval = *mtod(m, int *);
! 1167:
! 1168: if (optval < IPSEC_LEVEL_BYPASS ||
! 1169: optval > IPSEC_LEVEL_UNIQUE) {
! 1170: error = EINVAL;
! 1171: break;
! 1172: }
! 1173:
! 1174: /* Unlink cached output TDB to force a re-search */
! 1175: if (inp->inp_tdb_out) {
! 1176: int s = spltdb();
! 1177: TAILQ_REMOVE(&inp->inp_tdb_out->tdb_inp_out,
! 1178: inp, inp_tdb_out_next);
! 1179: splx(s);
! 1180: }
! 1181:
! 1182: if (inp->inp_tdb_in) {
! 1183: int s = spltdb();
! 1184: TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in,
! 1185: inp, inp_tdb_in_next);
! 1186: splx(s);
! 1187: }
! 1188:
! 1189: switch (optname) {
! 1190: case IP_AUTH_LEVEL:
! 1191: if (optval < ipsec_auth_default_level &&
! 1192: suser(p, 0)) {
! 1193: error = EACCES;
! 1194: break;
! 1195: }
! 1196: inp->inp_seclevel[SL_AUTH] = optval;
! 1197: break;
! 1198:
! 1199: case IP_ESP_TRANS_LEVEL:
! 1200: if (optval < ipsec_esp_trans_default_level &&
! 1201: suser(p, 0)) {
! 1202: error = EACCES;
! 1203: break;
! 1204: }
! 1205: inp->inp_seclevel[SL_ESP_TRANS] = optval;
! 1206: break;
! 1207:
! 1208: case IP_ESP_NETWORK_LEVEL:
! 1209: if (optval < ipsec_esp_network_default_level &&
! 1210: suser(p, 0)) {
! 1211: error = EACCES;
! 1212: break;
! 1213: }
! 1214: inp->inp_seclevel[SL_ESP_NETWORK] = optval;
! 1215: break;
! 1216: case IP_IPCOMP_LEVEL:
! 1217: if (optval < ipsec_ipcomp_default_level &&
! 1218: suser(p, 0)) {
! 1219: error = EACCES;
! 1220: break;
! 1221: }
! 1222: inp->inp_seclevel[SL_IPCOMP] = optval;
! 1223: break;
! 1224: }
! 1225: if (!error)
! 1226: inp->inp_secrequire = get_sa_require(inp);
! 1227: #endif
! 1228: break;
! 1229:
! 1230: case IP_IPSEC_REMOTE_CRED:
! 1231: case IP_IPSEC_REMOTE_AUTH:
! 1232: /* Can't set the remote credential or key */
! 1233: error = EOPNOTSUPP;
! 1234: break;
! 1235:
! 1236: case IP_IPSEC_LOCAL_ID:
! 1237: case IP_IPSEC_REMOTE_ID:
! 1238: case IP_IPSEC_LOCAL_CRED:
! 1239: case IP_IPSEC_LOCAL_AUTH:
! 1240: #ifndef IPSEC
! 1241: error = EOPNOTSUPP;
! 1242: #else
! 1243: if (m->m_len < 2) {
! 1244: error = EINVAL;
! 1245: break;
! 1246: }
! 1247:
! 1248: m_copydata(m, 0, 2, (caddr_t) &opt16val);
! 1249:
! 1250: /* If the type is 0, then we cleanup and return */
! 1251: if (opt16val == 0) {
! 1252: switch (optname) {
! 1253: case IP_IPSEC_LOCAL_ID:
! 1254: if (inp->inp_ipo != NULL &&
! 1255: inp->inp_ipo->ipo_srcid != NULL) {
! 1256: ipsp_reffree(inp->inp_ipo->ipo_srcid);
! 1257: inp->inp_ipo->ipo_srcid = NULL;
! 1258: }
! 1259: break;
! 1260:
! 1261: case IP_IPSEC_REMOTE_ID:
! 1262: if (inp->inp_ipo != NULL &&
! 1263: inp->inp_ipo->ipo_dstid != NULL) {
! 1264: ipsp_reffree(inp->inp_ipo->ipo_dstid);
! 1265: inp->inp_ipo->ipo_dstid = NULL;
! 1266: }
! 1267: break;
! 1268:
! 1269: case IP_IPSEC_LOCAL_CRED:
! 1270: if (inp->inp_ipo != NULL &&
! 1271: inp->inp_ipo->ipo_local_cred != NULL) {
! 1272: ipsp_reffree(inp->inp_ipo->ipo_local_cred);
! 1273: inp->inp_ipo->ipo_local_cred = NULL;
! 1274: }
! 1275: break;
! 1276:
! 1277: case IP_IPSEC_LOCAL_AUTH:
! 1278: if (inp->inp_ipo != NULL &&
! 1279: inp->inp_ipo->ipo_local_auth != NULL) {
! 1280: ipsp_reffree(inp->inp_ipo->ipo_local_auth);
! 1281: inp->inp_ipo->ipo_local_auth = NULL;
! 1282: }
! 1283: break;
! 1284: }
! 1285:
! 1286: error = 0;
! 1287: break;
! 1288: }
! 1289:
! 1290: /* Can't have an empty payload */
! 1291: if (m->m_len == 2) {
! 1292: error = EINVAL;
! 1293: break;
! 1294: }
! 1295:
! 1296: /* Allocate if needed */
! 1297: if (inp->inp_ipo == NULL) {
! 1298: inp->inp_ipo = ipsec_add_policy(inp,
! 1299: AF_INET, IPSP_DIRECTION_OUT);
! 1300: if (inp->inp_ipo == NULL) {
! 1301: error = ENOBUFS;
! 1302: break;
! 1303: }
! 1304: }
! 1305:
! 1306: MALLOC(ipr, struct ipsec_ref *,
! 1307: sizeof(struct ipsec_ref) + m->m_len - 2,
! 1308: M_CREDENTIALS, M_NOWAIT);
! 1309: if (ipr == NULL) {
! 1310: error = ENOBUFS;
! 1311: break;
! 1312: }
! 1313:
! 1314: ipr->ref_count = 1;
! 1315: ipr->ref_malloctype = M_CREDENTIALS;
! 1316: ipr->ref_len = m->m_len - 2;
! 1317: ipr->ref_type = opt16val;
! 1318: m_copydata(m, 2, m->m_len - 2, (caddr_t)(ipr + 1));
! 1319:
! 1320: switch (optname) {
! 1321: case IP_IPSEC_LOCAL_ID:
! 1322: /* Check valid types and NUL-termination */
! 1323: if (ipr->ref_type < IPSP_IDENTITY_PREFIX ||
! 1324: ipr->ref_type > IPSP_IDENTITY_CONNECTION ||
! 1325: ((char *)(ipr + 1))[ipr->ref_len - 1]) {
! 1326: FREE(ipr, M_CREDENTIALS);
! 1327: error = EINVAL;
! 1328: } else {
! 1329: if (inp->inp_ipo->ipo_srcid != NULL)
! 1330: ipsp_reffree(inp->inp_ipo->ipo_srcid);
! 1331: inp->inp_ipo->ipo_srcid = ipr;
! 1332: }
! 1333: break;
! 1334: case IP_IPSEC_REMOTE_ID:
! 1335: /* Check valid types and NUL-termination */
! 1336: if (ipr->ref_type < IPSP_IDENTITY_PREFIX ||
! 1337: ipr->ref_type > IPSP_IDENTITY_CONNECTION ||
! 1338: ((char *)(ipr + 1))[ipr->ref_len - 1]) {
! 1339: FREE(ipr, M_CREDENTIALS);
! 1340: error = EINVAL;
! 1341: } else {
! 1342: if (inp->inp_ipo->ipo_dstid != NULL)
! 1343: ipsp_reffree(inp->inp_ipo->ipo_dstid);
! 1344: inp->inp_ipo->ipo_dstid = ipr;
! 1345: }
! 1346: break;
! 1347: case IP_IPSEC_LOCAL_CRED:
! 1348: if (ipr->ref_type < IPSP_CRED_KEYNOTE ||
! 1349: ipr->ref_type > IPSP_CRED_X509) {
! 1350: FREE(ipr, M_CREDENTIALS);
! 1351: error = EINVAL;
! 1352: } else {
! 1353: if (inp->inp_ipo->ipo_local_cred != NULL)
! 1354: ipsp_reffree(inp->inp_ipo->ipo_local_cred);
! 1355: inp->inp_ipo->ipo_local_cred = ipr;
! 1356: }
! 1357: break;
! 1358: case IP_IPSEC_LOCAL_AUTH:
! 1359: if (ipr->ref_type < IPSP_AUTH_PASSPHRASE ||
! 1360: ipr->ref_type > IPSP_AUTH_RSA) {
! 1361: FREE(ipr, M_CREDENTIALS);
! 1362: error = EINVAL;
! 1363: } else {
! 1364: if (inp->inp_ipo->ipo_local_auth != NULL)
! 1365: ipsp_reffree(inp->inp_ipo->ipo_local_auth);
! 1366: inp->inp_ipo->ipo_local_auth = ipr;
! 1367: }
! 1368: break;
! 1369: }
! 1370:
! 1371: /* Unlink cached output TDB to force a re-search */
! 1372: if (inp->inp_tdb_out) {
! 1373: int s = spltdb();
! 1374: TAILQ_REMOVE(&inp->inp_tdb_out->tdb_inp_out,
! 1375: inp, inp_tdb_out_next);
! 1376: splx(s);
! 1377: }
! 1378:
! 1379: if (inp->inp_tdb_in) {
! 1380: int s = spltdb();
! 1381: TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in,
! 1382: inp, inp_tdb_in_next);
! 1383: splx(s);
! 1384: }
! 1385: #endif
! 1386: break;
! 1387: default:
! 1388: error = ENOPROTOOPT;
! 1389: break;
! 1390: }
! 1391: if (m)
! 1392: (void)m_free(m);
! 1393: break;
! 1394:
! 1395: case PRCO_GETOPT:
! 1396: switch (optname) {
! 1397: case IP_OPTIONS:
! 1398: case IP_RETOPTS:
! 1399: *mp = m = m_get(M_WAIT, MT_SOOPTS);
! 1400: if (inp->inp_options) {
! 1401: m->m_len = inp->inp_options->m_len;
! 1402: bcopy(mtod(inp->inp_options, caddr_t),
! 1403: mtod(m, caddr_t), (unsigned)m->m_len);
! 1404: } else
! 1405: m->m_len = 0;
! 1406: break;
! 1407:
! 1408: case IP_TOS:
! 1409: case IP_TTL:
! 1410: case IP_MINTTL:
! 1411: case IP_RECVOPTS:
! 1412: case IP_RECVRETOPTS:
! 1413: case IP_RECVDSTADDR:
! 1414: case IP_RECVIF:
! 1415: case IP_RECVTTL:
! 1416: *mp = m = m_get(M_WAIT, MT_SOOPTS);
! 1417: m->m_len = sizeof(int);
! 1418: switch (optname) {
! 1419:
! 1420: case IP_TOS:
! 1421: optval = inp->inp_ip.ip_tos;
! 1422: break;
! 1423:
! 1424: case IP_TTL:
! 1425: optval = inp->inp_ip.ip_ttl;
! 1426: break;
! 1427:
! 1428: case IP_MINTTL:
! 1429: optval = inp->inp_ip_minttl;
! 1430: break;
! 1431:
! 1432: #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0)
! 1433:
! 1434: case IP_RECVOPTS:
! 1435: optval = OPTBIT(INP_RECVOPTS);
! 1436: break;
! 1437:
! 1438: case IP_RECVRETOPTS:
! 1439: optval = OPTBIT(INP_RECVRETOPTS);
! 1440: break;
! 1441:
! 1442: case IP_RECVDSTADDR:
! 1443: optval = OPTBIT(INP_RECVDSTADDR);
! 1444: break;
! 1445: case IP_RECVIF:
! 1446: optval = OPTBIT(INP_RECVIF);
! 1447: break;
! 1448: case IP_RECVTTL:
! 1449: optval = OPTBIT(INP_RECVTTL);
! 1450: break;
! 1451: }
! 1452: *mtod(m, int *) = optval;
! 1453: break;
! 1454:
! 1455: case IP_MULTICAST_IF:
! 1456: case IP_MULTICAST_TTL:
! 1457: case IP_MULTICAST_LOOP:
! 1458: case IP_ADD_MEMBERSHIP:
! 1459: case IP_DROP_MEMBERSHIP:
! 1460: error = ip_getmoptions(optname, inp->inp_moptions, mp);
! 1461: break;
! 1462:
! 1463: case IP_PORTRANGE:
! 1464: *mp = m = m_get(M_WAIT, MT_SOOPTS);
! 1465: m->m_len = sizeof(int);
! 1466:
! 1467: if (inp->inp_flags & INP_HIGHPORT)
! 1468: optval = IP_PORTRANGE_HIGH;
! 1469: else if (inp->inp_flags & INP_LOWPORT)
! 1470: optval = IP_PORTRANGE_LOW;
! 1471: else
! 1472: optval = 0;
! 1473:
! 1474: *mtod(m, int *) = optval;
! 1475: break;
! 1476:
! 1477: case IP_AUTH_LEVEL:
! 1478: case IP_ESP_TRANS_LEVEL:
! 1479: case IP_ESP_NETWORK_LEVEL:
! 1480: case IP_IPCOMP_LEVEL:
! 1481: #ifndef IPSEC
! 1482: m->m_len = sizeof(int);
! 1483: *mtod(m, int *) = IPSEC_LEVEL_NONE;
! 1484: #else
! 1485: m->m_len = sizeof(int);
! 1486: switch (optname) {
! 1487: case IP_AUTH_LEVEL:
! 1488: optval = inp->inp_seclevel[SL_AUTH];
! 1489: break;
! 1490:
! 1491: case IP_ESP_TRANS_LEVEL:
! 1492: optval = inp->inp_seclevel[SL_ESP_TRANS];
! 1493: break;
! 1494:
! 1495: case IP_ESP_NETWORK_LEVEL:
! 1496: optval = inp->inp_seclevel[SL_ESP_NETWORK];
! 1497: break;
! 1498: case IP_IPCOMP_LEVEL:
! 1499: optval = inp->inp_seclevel[SL_IPCOMP];
! 1500: break;
! 1501: }
! 1502: *mtod(m, int *) = optval;
! 1503: #endif
! 1504: break;
! 1505: case IP_IPSEC_LOCAL_ID:
! 1506: case IP_IPSEC_REMOTE_ID:
! 1507: case IP_IPSEC_LOCAL_CRED:
! 1508: case IP_IPSEC_REMOTE_CRED:
! 1509: case IP_IPSEC_LOCAL_AUTH:
! 1510: case IP_IPSEC_REMOTE_AUTH:
! 1511: #ifndef IPSEC
! 1512: error = EOPNOTSUPP;
! 1513: #else
! 1514: *mp = m = m_get(M_WAIT, MT_SOOPTS);
! 1515: m->m_len = sizeof(u_int16_t);
! 1516: ipr = NULL;
! 1517: switch (optname) {
! 1518: case IP_IPSEC_LOCAL_ID:
! 1519: if (inp->inp_ipo != NULL)
! 1520: ipr = inp->inp_ipo->ipo_srcid;
! 1521: opt16val = IPSP_IDENTITY_NONE;
! 1522: break;
! 1523: case IP_IPSEC_REMOTE_ID:
! 1524: if (inp->inp_ipo != NULL)
! 1525: ipr = inp->inp_ipo->ipo_dstid;
! 1526: opt16val = IPSP_IDENTITY_NONE;
! 1527: break;
! 1528: case IP_IPSEC_LOCAL_CRED:
! 1529: if (inp->inp_ipo != NULL)
! 1530: ipr = inp->inp_ipo->ipo_local_cred;
! 1531: opt16val = IPSP_CRED_NONE;
! 1532: break;
! 1533: case IP_IPSEC_REMOTE_CRED:
! 1534: ipr = inp->inp_ipsec_remotecred;
! 1535: opt16val = IPSP_CRED_NONE;
! 1536: break;
! 1537: case IP_IPSEC_LOCAL_AUTH:
! 1538: if (inp->inp_ipo != NULL)
! 1539: ipr = inp->inp_ipo->ipo_local_auth;
! 1540: break;
! 1541: case IP_IPSEC_REMOTE_AUTH:
! 1542: ipr = inp->inp_ipsec_remoteauth;
! 1543: break;
! 1544: }
! 1545: if (ipr == NULL)
! 1546: *mtod(m, u_int16_t *) = opt16val;
! 1547: else {
! 1548: size_t len;
! 1549:
! 1550: len = m->m_len + ipr->ref_len;
! 1551: if (len > MCLBYTES) {
! 1552: m_free(m);
! 1553: error = EINVAL;
! 1554: break;
! 1555: }
! 1556: /* allocate mbuf cluster for larger option */
! 1557: if (len > MLEN) {
! 1558: MCLGET(m, M_WAITOK);
! 1559: if ((m->m_flags & M_EXT) == 0) {
! 1560: m_free(m);
! 1561: error = ENOBUFS;
! 1562: break;
! 1563: }
! 1564:
! 1565: }
! 1566: m->m_len = len;
! 1567: *mtod(m, u_int16_t *) = ipr->ref_type;
! 1568: m_copyback(m, sizeof(u_int16_t), ipr->ref_len,
! 1569: ipr + 1);
! 1570: }
! 1571: #endif
! 1572: break;
! 1573: default:
! 1574: error = ENOPROTOOPT;
! 1575: break;
! 1576: }
! 1577: break;
! 1578: }
! 1579: return (error);
! 1580: }
! 1581:
! 1582: /*
! 1583: * Set up IP options in pcb for insertion in output packets.
! 1584: * Store in mbuf with pointer in pcbopt, adding pseudo-option
! 1585: * with destination address if source routed.
! 1586: */
! 1587: int
! 1588: #ifdef notyet
! 1589: ip_pcbopts(optname, pcbopt, m)
! 1590: int optname;
! 1591: #else
! 1592: ip_pcbopts(pcbopt, m)
! 1593: #endif
! 1594: struct mbuf **pcbopt;
! 1595: struct mbuf *m;
! 1596: {
! 1597: int cnt, optlen;
! 1598: u_char *cp;
! 1599: u_char opt;
! 1600:
! 1601: /* turn off any old options */
! 1602: if (*pcbopt)
! 1603: (void)m_free(*pcbopt);
! 1604: *pcbopt = 0;
! 1605: if (m == (struct mbuf *)0 || m->m_len == 0) {
! 1606: /*
! 1607: * Only turning off any previous options.
! 1608: */
! 1609: if (m)
! 1610: (void)m_free(m);
! 1611: return (0);
! 1612: }
! 1613:
! 1614: if (m->m_len % sizeof(int32_t))
! 1615: goto bad;
! 1616:
! 1617: /*
! 1618: * IP first-hop destination address will be stored before
! 1619: * actual options; move other options back
! 1620: * and clear it when none present.
! 1621: */
! 1622: if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
! 1623: goto bad;
! 1624: cnt = m->m_len;
! 1625: m->m_len += sizeof(struct in_addr);
! 1626: cp = mtod(m, u_char *) + sizeof(struct in_addr);
! 1627: ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
! 1628: bzero(mtod(m, caddr_t), sizeof(struct in_addr));
! 1629:
! 1630: for (; cnt > 0; cnt -= optlen, cp += optlen) {
! 1631: opt = cp[IPOPT_OPTVAL];
! 1632: if (opt == IPOPT_EOL)
! 1633: break;
! 1634: if (opt == IPOPT_NOP)
! 1635: optlen = 1;
! 1636: else {
! 1637: if (cnt < IPOPT_OLEN + sizeof(*cp))
! 1638: goto bad;
! 1639: optlen = cp[IPOPT_OLEN];
! 1640: if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt)
! 1641: goto bad;
! 1642: }
! 1643: switch (opt) {
! 1644:
! 1645: default:
! 1646: break;
! 1647:
! 1648: case IPOPT_LSRR:
! 1649: case IPOPT_SSRR:
! 1650: /*
! 1651: * user process specifies route as:
! 1652: * ->A->B->C->D
! 1653: * D must be our final destination (but we can't
! 1654: * check that since we may not have connected yet).
! 1655: * A is first hop destination, which doesn't appear in
! 1656: * actual IP option, but is stored before the options.
! 1657: */
! 1658: if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
! 1659: goto bad;
! 1660: m->m_len -= sizeof(struct in_addr);
! 1661: cnt -= sizeof(struct in_addr);
! 1662: optlen -= sizeof(struct in_addr);
! 1663: cp[IPOPT_OLEN] = optlen;
! 1664: /*
! 1665: * Move first hop before start of options.
! 1666: */
! 1667: bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
! 1668: sizeof(struct in_addr));
! 1669: /*
! 1670: * Then copy rest of options back
! 1671: * to close up the deleted entry.
! 1672: */
! 1673: ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
! 1674: sizeof(struct in_addr)),
! 1675: (caddr_t)&cp[IPOPT_OFFSET+1],
! 1676: (unsigned)cnt - (IPOPT_OFFSET+1));
! 1677: break;
! 1678: }
! 1679: }
! 1680: if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
! 1681: goto bad;
! 1682: *pcbopt = m;
! 1683: return (0);
! 1684:
! 1685: bad:
! 1686: (void)m_free(m);
! 1687: return (EINVAL);
! 1688: }
! 1689:
! 1690: /*
! 1691: * Set the IP multicast options in response to user setsockopt().
! 1692: */
! 1693: int
! 1694: ip_setmoptions(optname, imop, m)
! 1695: int optname;
! 1696: struct ip_moptions **imop;
! 1697: struct mbuf *m;
! 1698: {
! 1699: int error = 0;
! 1700: u_char loop;
! 1701: int i;
! 1702: struct in_addr addr;
! 1703: struct ip_mreq *mreq;
! 1704: struct ifnet *ifp;
! 1705: struct ip_moptions *imo = *imop;
! 1706: struct route ro;
! 1707: struct sockaddr_in *dst;
! 1708:
! 1709: if (imo == NULL) {
! 1710: /*
! 1711: * No multicast option buffer attached to the pcb;
! 1712: * allocate one and initialize to default values.
! 1713: */
! 1714: imo = (struct ip_moptions *)malloc(sizeof(*imo), M_IPMOPTS,
! 1715: M_WAITOK);
! 1716:
! 1717: *imop = imo;
! 1718: imo->imo_multicast_ifp = NULL;
! 1719: imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
! 1720: imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
! 1721: imo->imo_num_memberships = 0;
! 1722: }
! 1723:
! 1724: switch (optname) {
! 1725:
! 1726: case IP_MULTICAST_IF:
! 1727: /*
! 1728: * Select the interface for outgoing multicast packets.
! 1729: */
! 1730: if (m == NULL || m->m_len != sizeof(struct in_addr)) {
! 1731: error = EINVAL;
! 1732: break;
! 1733: }
! 1734: addr = *(mtod(m, struct in_addr *));
! 1735: /*
! 1736: * INADDR_ANY is used to remove a previous selection.
! 1737: * When no interface is selected, a default one is
! 1738: * chosen every time a multicast packet is sent.
! 1739: */
! 1740: if (addr.s_addr == INADDR_ANY) {
! 1741: imo->imo_multicast_ifp = NULL;
! 1742: break;
! 1743: }
! 1744: /*
! 1745: * The selected interface is identified by its local
! 1746: * IP address. Find the interface and confirm that
! 1747: * it supports multicasting.
! 1748: */
! 1749: INADDR_TO_IFP(addr, ifp);
! 1750: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
! 1751: error = EADDRNOTAVAIL;
! 1752: break;
! 1753: }
! 1754: imo->imo_multicast_ifp = ifp;
! 1755: break;
! 1756:
! 1757: case IP_MULTICAST_TTL:
! 1758: /*
! 1759: * Set the IP time-to-live for outgoing multicast packets.
! 1760: */
! 1761: if (m == NULL || m->m_len != 1) {
! 1762: error = EINVAL;
! 1763: break;
! 1764: }
! 1765: imo->imo_multicast_ttl = *(mtod(m, u_char *));
! 1766: break;
! 1767:
! 1768: case IP_MULTICAST_LOOP:
! 1769: /*
! 1770: * Set the loopback flag for outgoing multicast packets.
! 1771: * Must be zero or one.
! 1772: */
! 1773: if (m == NULL || m->m_len != 1 ||
! 1774: (loop = *(mtod(m, u_char *))) > 1) {
! 1775: error = EINVAL;
! 1776: break;
! 1777: }
! 1778: imo->imo_multicast_loop = loop;
! 1779: break;
! 1780:
! 1781: case IP_ADD_MEMBERSHIP:
! 1782: /*
! 1783: * Add a multicast group membership.
! 1784: * Group must be a valid IP multicast address.
! 1785: */
! 1786: if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
! 1787: error = EINVAL;
! 1788: break;
! 1789: }
! 1790: mreq = mtod(m, struct ip_mreq *);
! 1791: if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) {
! 1792: error = EINVAL;
! 1793: break;
! 1794: }
! 1795: /*
! 1796: * If no interface address was provided, use the interface of
! 1797: * the route to the given multicast address.
! 1798: */
! 1799: if (mreq->imr_interface.s_addr == INADDR_ANY) {
! 1800: ro.ro_rt = NULL;
! 1801: dst = satosin(&ro.ro_dst);
! 1802: dst->sin_len = sizeof(*dst);
! 1803: dst->sin_family = AF_INET;
! 1804: dst->sin_addr = mreq->imr_multiaddr;
! 1805: rtalloc(&ro);
! 1806: if (ro.ro_rt == NULL) {
! 1807: error = EADDRNOTAVAIL;
! 1808: break;
! 1809: }
! 1810: ifp = ro.ro_rt->rt_ifp;
! 1811: rtfree(ro.ro_rt);
! 1812: } else {
! 1813: INADDR_TO_IFP(mreq->imr_interface, ifp);
! 1814: }
! 1815: /*
! 1816: * See if we found an interface, and confirm that it
! 1817: * supports multicast.
! 1818: */
! 1819: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
! 1820: error = EADDRNOTAVAIL;
! 1821: break;
! 1822: }
! 1823: /*
! 1824: * See if the membership already exists or if all the
! 1825: * membership slots are full.
! 1826: */
! 1827: for (i = 0; i < imo->imo_num_memberships; ++i) {
! 1828: if (imo->imo_membership[i]->inm_ia->ia_ifp == ifp &&
! 1829: imo->imo_membership[i]->inm_addr.s_addr
! 1830: == mreq->imr_multiaddr.s_addr)
! 1831: break;
! 1832: }
! 1833: if (i < imo->imo_num_memberships) {
! 1834: error = EADDRINUSE;
! 1835: break;
! 1836: }
! 1837: if (i == IP_MAX_MEMBERSHIPS) {
! 1838: error = ETOOMANYREFS;
! 1839: break;
! 1840: }
! 1841: /*
! 1842: * Everything looks good; add a new record to the multicast
! 1843: * address list for the given interface.
! 1844: */
! 1845: if ((imo->imo_membership[i] =
! 1846: in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
! 1847: error = ENOBUFS;
! 1848: break;
! 1849: }
! 1850: ++imo->imo_num_memberships;
! 1851: break;
! 1852:
! 1853: case IP_DROP_MEMBERSHIP:
! 1854: /*
! 1855: * Drop a multicast group membership.
! 1856: * Group must be a valid IP multicast address.
! 1857: */
! 1858: if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
! 1859: error = EINVAL;
! 1860: break;
! 1861: }
! 1862: mreq = mtod(m, struct ip_mreq *);
! 1863: if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) {
! 1864: error = EINVAL;
! 1865: break;
! 1866: }
! 1867: /*
! 1868: * If an interface address was specified, get a pointer
! 1869: * to its ifnet structure.
! 1870: */
! 1871: if (mreq->imr_interface.s_addr == INADDR_ANY)
! 1872: ifp = NULL;
! 1873: else {
! 1874: INADDR_TO_IFP(mreq->imr_interface, ifp);
! 1875: if (ifp == NULL) {
! 1876: error = EADDRNOTAVAIL;
! 1877: break;
! 1878: }
! 1879: }
! 1880: /*
! 1881: * Find the membership in the membership array.
! 1882: */
! 1883: for (i = 0; i < imo->imo_num_memberships; ++i) {
! 1884: if ((ifp == NULL ||
! 1885: imo->imo_membership[i]->inm_ia->ia_ifp == ifp) &&
! 1886: imo->imo_membership[i]->inm_addr.s_addr ==
! 1887: mreq->imr_multiaddr.s_addr)
! 1888: break;
! 1889: }
! 1890: if (i == imo->imo_num_memberships) {
! 1891: error = EADDRNOTAVAIL;
! 1892: break;
! 1893: }
! 1894: /*
! 1895: * Give up the multicast address record to which the
! 1896: * membership points.
! 1897: */
! 1898: in_delmulti(imo->imo_membership[i]);
! 1899: /*
! 1900: * Remove the gap in the membership array.
! 1901: */
! 1902: for (++i; i < imo->imo_num_memberships; ++i)
! 1903: imo->imo_membership[i-1] = imo->imo_membership[i];
! 1904: --imo->imo_num_memberships;
! 1905: break;
! 1906:
! 1907: default:
! 1908: error = EOPNOTSUPP;
! 1909: break;
! 1910: }
! 1911:
! 1912: /*
! 1913: * If all options have default values, no need to keep the mbuf.
! 1914: */
! 1915: if (imo->imo_multicast_ifp == NULL &&
! 1916: imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
! 1917: imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
! 1918: imo->imo_num_memberships == 0) {
! 1919: free(*imop, M_IPMOPTS);
! 1920: *imop = NULL;
! 1921: }
! 1922:
! 1923: return (error);
! 1924: }
! 1925:
! 1926: /*
! 1927: * Return the IP multicast options in response to user getsockopt().
! 1928: */
! 1929: int
! 1930: ip_getmoptions(optname, imo, mp)
! 1931: int optname;
! 1932: struct ip_moptions *imo;
! 1933: struct mbuf **mp;
! 1934: {
! 1935: u_char *ttl;
! 1936: u_char *loop;
! 1937: struct in_addr *addr;
! 1938: struct in_ifaddr *ia;
! 1939:
! 1940: *mp = m_get(M_WAIT, MT_SOOPTS);
! 1941:
! 1942: switch (optname) {
! 1943:
! 1944: case IP_MULTICAST_IF:
! 1945: addr = mtod(*mp, struct in_addr *);
! 1946: (*mp)->m_len = sizeof(struct in_addr);
! 1947: if (imo == NULL || imo->imo_multicast_ifp == NULL)
! 1948: addr->s_addr = INADDR_ANY;
! 1949: else {
! 1950: IFP_TO_IA(imo->imo_multicast_ifp, ia);
! 1951: addr->s_addr = (ia == NULL) ? INADDR_ANY
! 1952: : ia->ia_addr.sin_addr.s_addr;
! 1953: }
! 1954: return (0);
! 1955:
! 1956: case IP_MULTICAST_TTL:
! 1957: ttl = mtod(*mp, u_char *);
! 1958: (*mp)->m_len = 1;
! 1959: *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
! 1960: : imo->imo_multicast_ttl;
! 1961: return (0);
! 1962:
! 1963: case IP_MULTICAST_LOOP:
! 1964: loop = mtod(*mp, u_char *);
! 1965: (*mp)->m_len = 1;
! 1966: *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
! 1967: : imo->imo_multicast_loop;
! 1968: return (0);
! 1969:
! 1970: default:
! 1971: return (EOPNOTSUPP);
! 1972: }
! 1973: }
! 1974:
! 1975: /*
! 1976: * Discard the IP multicast options.
! 1977: */
! 1978: void
! 1979: ip_freemoptions(imo)
! 1980: struct ip_moptions *imo;
! 1981: {
! 1982: int i;
! 1983:
! 1984: if (imo != NULL) {
! 1985: for (i = 0; i < imo->imo_num_memberships; ++i)
! 1986: in_delmulti(imo->imo_membership[i]);
! 1987: free(imo, M_IPMOPTS);
! 1988: }
! 1989: }
! 1990:
! 1991: /*
! 1992: * Routine called from ip_output() to loop back a copy of an IP multicast
! 1993: * packet to the input queue of a specified interface. Note that this
! 1994: * calls the output routine of the loopback "driver", but with an interface
! 1995: * pointer that might NOT be &loif -- easier than replicating that code here.
! 1996: */
! 1997: void
! 1998: ip_mloopback(ifp, m, dst)
! 1999: struct ifnet *ifp;
! 2000: struct mbuf *m;
! 2001: struct sockaddr_in *dst;
! 2002: {
! 2003: struct ip *ip;
! 2004: struct mbuf *copym;
! 2005:
! 2006: copym = m_copym2(m, 0, M_COPYALL, M_DONTWAIT);
! 2007: if (copym != NULL) {
! 2008: /*
! 2009: * We don't bother to fragment if the IP length is greater
! 2010: * than the interface's MTU. Can this possibly matter?
! 2011: */
! 2012: ip = mtod(copym, struct ip *);
! 2013: ip->ip_sum = 0;
! 2014: ip->ip_sum = in_cksum(copym, ip->ip_hl << 2);
! 2015: (void) looutput(ifp, copym, sintosa(dst), NULL);
! 2016: }
! 2017: }
! 2018:
! 2019: /*
! 2020: * Process a delayed payload checksum calculation.
! 2021: */
! 2022: void
! 2023: in_delayed_cksum(struct mbuf *m)
! 2024: {
! 2025: struct ip *ip;
! 2026: u_int16_t csum, offset;
! 2027:
! 2028: ip = mtod(m, struct ip *);
! 2029: offset = ip->ip_hl << 2;
! 2030: csum = in4_cksum(m, 0, offset, m->m_pkthdr.len - offset);
! 2031: if (csum == 0 && ip->ip_p == IPPROTO_UDP)
! 2032: csum = 0xffff;
! 2033:
! 2034: switch (ip->ip_p) {
! 2035: case IPPROTO_TCP:
! 2036: offset += offsetof(struct tcphdr, th_sum);
! 2037: break;
! 2038:
! 2039: case IPPROTO_UDP:
! 2040: offset += offsetof(struct udphdr, uh_sum);
! 2041: break;
! 2042:
! 2043: default:
! 2044: return;
! 2045: }
! 2046:
! 2047: if ((offset + sizeof(u_int16_t)) > m->m_len)
! 2048: m_copyback(m, offset, sizeof(csum), &csum);
! 2049: else
! 2050: *(u_int16_t *)(mtod(m, caddr_t) + offset) = csum;
! 2051: }
CVSweb