Deleted Added
full compact
ip6_output.c (189303) ip6_output.c (191672)
1/*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 47 unchanged lines hidden (view full) ---

56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
61 */
62
63#include <sys/cdefs.h>
1/*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 47 unchanged lines hidden (view full) ---

56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
61 */
62
63#include <sys/cdefs.h>
64__FBSDID("$FreeBSD: head/sys/netinet6/ip6_output.c 189303 2009-03-03 13:12:12Z bz $");
64__FBSDID("$FreeBSD: head/sys/netinet6/ip6_output.c 191672 2009-04-29 19:19:13Z bms $");
65
66#include "opt_inet.h"
67#include "opt_inet6.h"
68#include "opt_ipsec.h"
69#include "opt_route.h"
70
71#include <sys/param.h>
72#include <sys/kernel.h>

--- 32 unchanged lines hidden (view full) ---

105#include <netipsec/key.h>
106#include <netinet6/ip6_ipsec.h>
107#endif /* IPSEC */
108
109#include <netinet6/ip6protosw.h>
110#include <netinet6/scope6_var.h>
111#include <netinet6/vinet6.h>
112
65
66#include "opt_inet.h"
67#include "opt_inet6.h"
68#include "opt_ipsec.h"
69#include "opt_route.h"
70
71#include <sys/param.h>
72#include <sys/kernel.h>

--- 32 unchanged lines hidden (view full) ---

105#include <netipsec/key.h>
106#include <netinet6/ip6_ipsec.h>
107#endif /* IPSEC */
108
109#include <netinet6/ip6protosw.h>
110#include <netinet6/scope6_var.h>
111#include <netinet6/vinet6.h>
112
113static MALLOC_DEFINE(M_IP6MOPTS, "ip6_moptions", "internet multicast options");
113extern int in6_mcast_loop;
114
115struct ip6_exthdrs {
116 struct mbuf *ip6e_ip6;
117 struct mbuf *ip6e_hbh;
118 struct mbuf *ip6e_dest1;
119 struct mbuf *ip6e_rthdr;
120 struct mbuf *ip6e_dest2;
121};
122
123static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **,
124 struct ucred *, int));
125static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
126 struct socket *, struct sockopt *));
127static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *);
128static int ip6_setpktopt __P((int, u_char *, int, struct ip6_pktopts *,
129 struct ucred *, int, int, int));
130
114
115struct ip6_exthdrs {
116 struct mbuf *ip6e_ip6;
117 struct mbuf *ip6e_hbh;
118 struct mbuf *ip6e_dest1;
119 struct mbuf *ip6e_rthdr;
120 struct mbuf *ip6e_dest2;
121};
122
123static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **,
124 struct ucred *, int));
125static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
126 struct socket *, struct sockopt *));
127static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *);
128static int ip6_setpktopt __P((int, u_char *, int, struct ip6_pktopts *,
129 struct ucred *, int, int, int));
130
131static int ip6_setmoptions(int, struct ip6_moptions **, struct mbuf *);
132static int ip6_getmoptions(int, struct ip6_moptions *, struct mbuf **);
133static int ip6_copyexthdr(struct mbuf **, caddr_t, int);
134static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
135 struct ip6_frag **));
136static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
137static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
138static int ip6_getpmtu __P((struct route_in6 *, struct route_in6 *,
139 struct ifnet *, struct in6_addr *, u_long *, int *));
140static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);

--- 546 unchanged lines hidden (view full) ---

687 }
688 else if ((rt->rt_flags & RTF_GATEWAY))
689 dst = (struct sockaddr_in6 *)rt->rt_gateway;
690 }
691
692 if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
693 m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
694 } else {
131static int ip6_copyexthdr(struct mbuf **, caddr_t, int);
132static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
133 struct ip6_frag **));
134static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
135static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
136static int ip6_getpmtu __P((struct route_in6 *, struct route_in6 *,
137 struct ifnet *, struct in6_addr *, u_long *, int *));
138static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);

--- 546 unchanged lines hidden (view full) ---

685 }
686 else if ((rt->rt_flags & RTF_GATEWAY))
687 dst = (struct sockaddr_in6 *)rt->rt_gateway;
688 }
689
690 if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
691 m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
692 } else {
695 struct in6_multi *in6m;
696
697 m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST;
693 m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST;
698
699 in6_ifstat_inc(ifp, ifs6_out_mcast);
694 in6_ifstat_inc(ifp, ifs6_out_mcast);
700
701 /*
702 * Confirm that the outgoing interface supports multicast.
703 */
704 if (!(ifp->if_flags & IFF_MULTICAST)) {
705 V_ip6stat.ip6s_noroute++;
706 in6_ifstat_inc(ifp, ifs6_out_discard);
707 error = ENETUNREACH;
708 goto bad;
709 }
695 /*
696 * Confirm that the outgoing interface supports multicast.
697 */
698 if (!(ifp->if_flags & IFF_MULTICAST)) {
699 V_ip6stat.ip6s_noroute++;
700 in6_ifstat_inc(ifp, ifs6_out_discard);
701 error = ENETUNREACH;
702 goto bad;
703 }
710 IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
711 if (in6m != NULL &&
712 (im6o == NULL || im6o->im6o_multicast_loop)) {
704 if ((im6o == NULL && in6_mcast_loop) ||
705 (im6o && im6o->im6o_multicast_loop)) {
713 /*
706 /*
714 * If we belong to the destination multicast group
715 * on the outgoing interface, and the caller did not
716 * forbid loopback, loop back a copy.
707 * Loop back multicast datagram if not expressly
708 * forbidden to do so, even if we have not joined
709 * the address; protocols will filter it later,
710 * thus deferring a hash lookup and lock acquisition
711 * at the expense of an m_copym().
717 */
718 ip6_mloopback(ifp, m, dst);
719 } else {
720 /*
721 * If we are acting as a multicast router, perform
722 * multicast forwarding as if the packet had just
723 * arrived on the interface to which we are about
724 * to send. The multicast forwarding function
725 * recursively calls this function, using the
726 * IPV6_FORWARDING flag to prevent infinite recursion.
727 *
728 * Multicasts that are looped back by ip6_mloopback(),
729 * above, will be forwarded by the ip6_input() routine,
730 * if necessary.
731 */
712 */
713 ip6_mloopback(ifp, m, dst);
714 } else {
715 /*
716 * If we are acting as a multicast router, perform
717 * multicast forwarding as if the packet had just
718 * arrived on the interface to which we are about
719 * to send. The multicast forwarding function
720 * recursively calls this function, using the
721 * IPV6_FORWARDING flag to prevent infinite recursion.
722 *
723 * Multicasts that are looped back by ip6_mloopback(),
724 * above, will be forwarded by the ip6_input() routine,
725 * if necessary.
726 */
732 if (ip6_mrouter && (flags & IPV6_FORWARDING) == 0) {
727 if (V_ip6_mrouter && (flags & IPV6_FORWARDING) == 0) {
733 /*
734 * XXX: ip6_mforward expects that rcvif is NULL
735 * when it is called from the originating path.
736 * However, it is not always the case, since
737 * some versions of MGETHDR() does not
738 * initialize the field.
739 */
740 m->m_pkthdr.rcvif = NULL;

--- 956 unchanged lines hidden (view full) ---

1697 }
1698#undef OPTSET
1699
1700 case IPV6_MULTICAST_IF:
1701 case IPV6_MULTICAST_HOPS:
1702 case IPV6_MULTICAST_LOOP:
1703 case IPV6_JOIN_GROUP:
1704 case IPV6_LEAVE_GROUP:
728 /*
729 * XXX: ip6_mforward expects that rcvif is NULL
730 * when it is called from the originating path.
731 * However, it is not always the case, since
732 * some versions of MGETHDR() does not
733 * initialize the field.
734 */
735 m->m_pkthdr.rcvif = NULL;

--- 956 unchanged lines hidden (view full) ---

1692 }
1693#undef OPTSET
1694
1695 case IPV6_MULTICAST_IF:
1696 case IPV6_MULTICAST_HOPS:
1697 case IPV6_MULTICAST_LOOP:
1698 case IPV6_JOIN_GROUP:
1699 case IPV6_LEAVE_GROUP:
1705 {
1706 if (sopt->sopt_valsize > MLEN) {
1707 error = EMSGSIZE;
1708 break;
1709 }
1710 /* XXX */
1711 }
1712 /* FALLTHROUGH */
1713 {
1714 struct mbuf *m;
1715
1716 if (sopt->sopt_valsize > MCLBYTES) {
1717 error = EMSGSIZE;
1718 break;
1719 }
1720 /* XXX */
1721 MGET(m, sopt->sopt_td ? M_WAIT : M_DONTWAIT, MT_DATA);
1722 if (m == 0) {
1723 error = ENOBUFS;
1724 break;
1725 }
1726 if (sopt->sopt_valsize > MLEN) {
1727 MCLGET(m, sopt->sopt_td ? M_WAIT : M_DONTWAIT);
1728 if ((m->m_flags & M_EXT) == 0) {
1729 m_free(m);
1730 error = ENOBUFS;
1731 break;
1732 }
1733 }
1734 m->m_len = sopt->sopt_valsize;
1735 error = sooptcopyin(sopt, mtod(m, char *),
1736 m->m_len, m->m_len);
1737 if (error) {
1738 (void)m_free(m);
1739 break;
1740 }
1741 error = ip6_setmoptions(sopt->sopt_name,
1742 &in6p->in6p_moptions,
1743 m);
1744 (void)m_free(m);
1745 }
1700 case IPV6_MSFILTER:
1701 case MCAST_BLOCK_SOURCE:
1702 case MCAST_UNBLOCK_SOURCE:
1703 case MCAST_JOIN_GROUP:
1704 case MCAST_LEAVE_GROUP:
1705 case MCAST_JOIN_SOURCE_GROUP:
1706 case MCAST_LEAVE_SOURCE_GROUP:
1707 error = ip6_setmoptions(in6p, sopt);
1746 break;
1747
1748 case IPV6_PORTRANGE:
1749 error = sooptcopyin(sopt, &optval,
1750 sizeof optval, sizeof optval);
1751 if (error)
1752 break;
1753

--- 215 unchanged lines hidden (view full) ---

1969 case IPV6_PREFER_TEMPADDR:
1970 error = ip6_getpcbopt(in6p->in6p_outputopts,
1971 optname, sopt);
1972 break;
1973
1974 case IPV6_MULTICAST_IF:
1975 case IPV6_MULTICAST_HOPS:
1976 case IPV6_MULTICAST_LOOP:
1708 break;
1709
1710 case IPV6_PORTRANGE:
1711 error = sooptcopyin(sopt, &optval,
1712 sizeof optval, sizeof optval);
1713 if (error)
1714 break;
1715

--- 215 unchanged lines hidden (view full) ---

1931 case IPV6_PREFER_TEMPADDR:
1932 error = ip6_getpcbopt(in6p->in6p_outputopts,
1933 optname, sopt);
1934 break;
1935
1936 case IPV6_MULTICAST_IF:
1937 case IPV6_MULTICAST_HOPS:
1938 case IPV6_MULTICAST_LOOP:
1977 case IPV6_JOIN_GROUP:
1978 case IPV6_LEAVE_GROUP:
1979 {
1980 struct mbuf *m;
1981 error = ip6_getmoptions(sopt->sopt_name,
1982 in6p->in6p_moptions, &m);
1983 if (error == 0)
1984 error = sooptcopyout(sopt,
1985 mtod(m, char *), m->m_len);
1986 m_freem(m);
1987 }
1939 case IPV6_MSFILTER:
1940 error = ip6_getmoptions(in6p, sopt);
1988 break;
1989
1990#ifdef IPSEC
1991 case IPV6_IPSEC_POLICY:
1992 {
1993 caddr_t req = NULL;
1994 size_t len = 0;
1995 struct mbuf *m = NULL;

--- 404 unchanged lines hidden (view full) ---

2400 return;
2401
2402 ip6_clearpktopts(pktopt, -1);
2403
2404 free(pktopt, M_IP6OPT);
2405}
2406
2407/*
1941 break;
1942
1943#ifdef IPSEC
1944 case IPV6_IPSEC_POLICY:
1945 {
1946 caddr_t req = NULL;
1947 size_t len = 0;
1948 struct mbuf *m = NULL;

--- 404 unchanged lines hidden (view full) ---

2353 return;
2354
2355 ip6_clearpktopts(pktopt, -1);
2356
2357 free(pktopt, M_IP6OPT);
2358}
2359
2360/*
2408 * Set the IP6 multicast options in response to user setsockopt().
2409 */
2410static int
2411ip6_setmoptions(int optname, struct ip6_moptions **im6op, struct mbuf *m)
2412{
2413 INIT_VNET_NET(curvnet);
2414 INIT_VNET_INET6(curvnet);
2415 int error = 0;
2416 u_int loop, ifindex;
2417 struct ipv6_mreq *mreq;
2418 struct ifnet *ifp;
2419 struct ip6_moptions *im6o = *im6op;
2420 struct route_in6 ro;
2421 struct in6_multi_mship *imm;
2422
2423 if (im6o == NULL) {
2424 /*
2425 * No multicast option buffer attached to the pcb;
2426 * allocate one and initialize to default values.
2427 */
2428 im6o = (struct ip6_moptions *)
2429 malloc(sizeof(*im6o), M_IP6MOPTS, M_WAITOK);
2430
2431 if (im6o == NULL)
2432 return (ENOBUFS);
2433 *im6op = im6o;
2434 im6o->im6o_multicast_ifp = NULL;
2435 im6o->im6o_multicast_hlim = V_ip6_defmcasthlim;
2436 im6o->im6o_multicast_loop = IPV6_DEFAULT_MULTICAST_LOOP;
2437 LIST_INIT(&im6o->im6o_memberships);
2438 }
2439
2440 switch (optname) {
2441
2442 case IPV6_MULTICAST_IF:
2443 /*
2444 * Select the interface for outgoing multicast packets.
2445 */
2446 if (m == NULL || m->m_len != sizeof(u_int)) {
2447 error = EINVAL;
2448 break;
2449 }
2450 bcopy(mtod(m, u_int *), &ifindex, sizeof(ifindex));
2451 if (ifindex < 0 || V_if_index < ifindex) {
2452 error = ENXIO; /* XXX EINVAL? */
2453 break;
2454 }
2455 ifp = ifnet_byindex(ifindex);
2456 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
2457 error = EADDRNOTAVAIL;
2458 break;
2459 }
2460 im6o->im6o_multicast_ifp = ifp;
2461 break;
2462
2463 case IPV6_MULTICAST_HOPS:
2464 {
2465 /*
2466 * Set the IP6 hoplimit for outgoing multicast packets.
2467 */
2468 int optval;
2469 if (m == NULL || m->m_len != sizeof(int)) {
2470 error = EINVAL;
2471 break;
2472 }
2473 bcopy(mtod(m, u_int *), &optval, sizeof(optval));
2474 if (optval < -1 || optval >= 256)
2475 error = EINVAL;
2476 else if (optval == -1)
2477 im6o->im6o_multicast_hlim = V_ip6_defmcasthlim;
2478 else
2479 im6o->im6o_multicast_hlim = optval;
2480 break;
2481 }
2482
2483 case IPV6_MULTICAST_LOOP:
2484 /*
2485 * Set the loopback flag for outgoing multicast packets.
2486 * Must be zero or one.
2487 */
2488 if (m == NULL || m->m_len != sizeof(u_int)) {
2489 error = EINVAL;
2490 break;
2491 }
2492 bcopy(mtod(m, u_int *), &loop, sizeof(loop));
2493 if (loop > 1) {
2494 error = EINVAL;
2495 break;
2496 }
2497 im6o->im6o_multicast_loop = loop;
2498 break;
2499
2500 case IPV6_JOIN_GROUP:
2501 /*
2502 * Add a multicast group membership.
2503 * Group must be a valid IP6 multicast address.
2504 */
2505 if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
2506 error = EINVAL;
2507 break;
2508 }
2509 mreq = mtod(m, struct ipv6_mreq *);
2510
2511 if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) {
2512 /*
2513 * We use the unspecified address to specify to accept
2514 * all multicast addresses. Only super user is allowed
2515 * to do this.
2516 */
2517 /* XXX-BZ might need a better PRIV_NETINET_x for this */
2518 error = priv_check(curthread, PRIV_NETINET_MROUTE);
2519 if (error)
2520 break;
2521 } else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
2522 error = EINVAL;
2523 break;
2524 }
2525
2526 /*
2527 * If no interface was explicitly specified, choose an
2528 * appropriate one according to the given multicast address.
2529 */
2530 if (mreq->ipv6mr_interface == 0) {
2531 struct sockaddr_in6 *dst;
2532
2533 /*
2534 * Look up the routing table for the
2535 * address, and choose the outgoing interface.
2536 * XXX: is it a good approach?
2537 */
2538 ro.ro_rt = NULL;
2539 dst = (struct sockaddr_in6 *)&ro.ro_dst;
2540 bzero(dst, sizeof(*dst));
2541 dst->sin6_family = AF_INET6;
2542 dst->sin6_len = sizeof(*dst);
2543 dst->sin6_addr = mreq->ipv6mr_multiaddr;
2544 rtalloc((struct route *)&ro);
2545 if (ro.ro_rt == NULL) {
2546 error = EADDRNOTAVAIL;
2547 break;
2548 }
2549 ifp = ro.ro_rt->rt_ifp;
2550 RTFREE(ro.ro_rt);
2551 } else {
2552 /*
2553 * If the interface is specified, validate it.
2554 */
2555 if (mreq->ipv6mr_interface < 0 ||
2556 V_if_index < mreq->ipv6mr_interface) {
2557 error = ENXIO; /* XXX EINVAL? */
2558 break;
2559 }
2560 ifp = ifnet_byindex(mreq->ipv6mr_interface);
2561 if (!ifp) {
2562 error = ENXIO; /* XXX EINVAL? */
2563 break;
2564 }
2565 }
2566
2567 /*
2568 * See if we found an interface, and confirm that it
2569 * supports multicast
2570 */
2571 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
2572 error = EADDRNOTAVAIL;
2573 break;
2574 }
2575
2576 if (in6_setscope(&mreq->ipv6mr_multiaddr, ifp, NULL)) {
2577 error = EADDRNOTAVAIL; /* XXX: should not happen */
2578 break;
2579 }
2580
2581 /*
2582 * See if the membership already exists.
2583 */
2584 for (imm = im6o->im6o_memberships.lh_first;
2585 imm != NULL; imm = imm->i6mm_chain.le_next)
2586 if (imm->i6mm_maddr->in6m_ifp == ifp &&
2587 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
2588 &mreq->ipv6mr_multiaddr))
2589 break;
2590 if (imm != NULL) {
2591 error = EADDRINUSE;
2592 break;
2593 }
2594 /*
2595 * Everything looks good; add a new record to the multicast
2596 * address list for the given interface.
2597 */
2598 imm = in6_joingroup(ifp, &mreq->ipv6mr_multiaddr, &error, 0);
2599 if (imm == NULL)
2600 break;
2601 LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
2602 break;
2603
2604 case IPV6_LEAVE_GROUP:
2605 /*
2606 * Drop a multicast group membership.
2607 * Group must be a valid IP6 multicast address.
2608 */
2609 if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
2610 error = EINVAL;
2611 break;
2612 }
2613 mreq = mtod(m, struct ipv6_mreq *);
2614
2615 /*
2616 * If an interface address was specified, get a pointer
2617 * to its ifnet structure.
2618 */
2619 if (mreq->ipv6mr_interface < 0 ||
2620 V_if_index < mreq->ipv6mr_interface) {
2621 error = ENXIO; /* XXX EINVAL? */
2622 break;
2623 }
2624 if (mreq->ipv6mr_interface == 0)
2625 ifp = NULL;
2626 else
2627 ifp = ifnet_byindex(mreq->ipv6mr_interface);
2628
2629 /* Fill in the scope zone ID */
2630 if (ifp) {
2631 if (in6_setscope(&mreq->ipv6mr_multiaddr, ifp, NULL)) {
2632 /* XXX: should not happen */
2633 error = EADDRNOTAVAIL;
2634 break;
2635 }
2636 } else if (mreq->ipv6mr_interface != 0) {
2637 /*
2638 * This case happens when the (positive) index is in
2639 * the valid range, but the corresponding interface has
2640 * been detached dynamically (XXX).
2641 */
2642 error = EADDRNOTAVAIL;
2643 break;
2644 } else { /* ipv6mr_interface == 0 */
2645 struct sockaddr_in6 sa6_mc;
2646
2647 /*
2648 * The API spec says as follows:
2649 * If the interface index is specified as 0, the
2650 * system may choose a multicast group membership to
2651 * drop by matching the multicast address only.
2652 * On the other hand, we cannot disambiguate the scope
2653 * zone unless an interface is provided. Thus, we
2654 * check if there's ambiguity with the default scope
2655 * zone as the last resort.
2656 */
2657 bzero(&sa6_mc, sizeof(sa6_mc));
2658 sa6_mc.sin6_family = AF_INET6;
2659 sa6_mc.sin6_len = sizeof(sa6_mc);
2660 sa6_mc.sin6_addr = mreq->ipv6mr_multiaddr;
2661 error = sa6_embedscope(&sa6_mc, V_ip6_use_defzone);
2662 if (error != 0)
2663 break;
2664 mreq->ipv6mr_multiaddr = sa6_mc.sin6_addr;
2665 }
2666
2667 /*
2668 * Find the membership in the membership list.
2669 */
2670 for (imm = im6o->im6o_memberships.lh_first;
2671 imm != NULL; imm = imm->i6mm_chain.le_next) {
2672 if ((ifp == NULL || imm->i6mm_maddr->in6m_ifp == ifp) &&
2673 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
2674 &mreq->ipv6mr_multiaddr))
2675 break;
2676 }
2677 if (imm == NULL) {
2678 /* Unable to resolve interface */
2679 error = EADDRNOTAVAIL;
2680 break;
2681 }
2682 /*
2683 * Give up the multicast address record to which the
2684 * membership points.
2685 */
2686 LIST_REMOVE(imm, i6mm_chain);
2687 in6_delmulti(imm->i6mm_maddr);
2688 free(imm, M_IP6MADDR);
2689 break;
2690
2691 default:
2692 error = EOPNOTSUPP;
2693 break;
2694 }
2695
2696 /*
2697 * If all options have default values, no need to keep the mbuf.
2698 */
2699 if (im6o->im6o_multicast_ifp == NULL &&
2700 im6o->im6o_multicast_hlim == V_ip6_defmcasthlim &&
2701 im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP &&
2702 im6o->im6o_memberships.lh_first == NULL) {
2703 free(*im6op, M_IP6MOPTS);
2704 *im6op = NULL;
2705 }
2706
2707 return (error);
2708}
2709
2710/*
2711 * Return the IP6 multicast options in response to user getsockopt().
2712 */
2713static int
2714ip6_getmoptions(int optname, struct ip6_moptions *im6o, struct mbuf **mp)
2715{
2716 INIT_VNET_INET6(curvnet);
2717 u_int *hlim, *loop, *ifindex;
2718
2719 *mp = m_get(M_WAIT, MT_HEADER); /* XXX */
2720
2721 switch (optname) {
2722
2723 case IPV6_MULTICAST_IF:
2724 ifindex = mtod(*mp, u_int *);
2725 (*mp)->m_len = sizeof(u_int);
2726 if (im6o == NULL || im6o->im6o_multicast_ifp == NULL)
2727 *ifindex = 0;
2728 else
2729 *ifindex = im6o->im6o_multicast_ifp->if_index;
2730 return (0);
2731
2732 case IPV6_MULTICAST_HOPS:
2733 hlim = mtod(*mp, u_int *);
2734 (*mp)->m_len = sizeof(u_int);
2735 if (im6o == NULL)
2736 *hlim = V_ip6_defmcasthlim;
2737 else
2738 *hlim = im6o->im6o_multicast_hlim;
2739 return (0);
2740
2741 case IPV6_MULTICAST_LOOP:
2742 loop = mtod(*mp, u_int *);
2743 (*mp)->m_len = sizeof(u_int);
2744 if (im6o == NULL)
2745 *loop = V_ip6_defmcasthlim;
2746 else
2747 *loop = im6o->im6o_multicast_loop;
2748 return (0);
2749
2750 default:
2751 return (EOPNOTSUPP);
2752 }
2753}
2754
2755/*
2756 * Discard the IP6 multicast options.
2757 */
2758void
2759ip6_freemoptions(struct ip6_moptions *im6o)
2760{
2761 struct in6_multi_mship *imm;
2762
2763 if (im6o == NULL)
2764 return;
2765
2766 while ((imm = im6o->im6o_memberships.lh_first) != NULL) {
2767 LIST_REMOVE(imm, i6mm_chain);
2768 if (imm->i6mm_maddr)
2769 in6_delmulti(imm->i6mm_maddr);
2770 free(imm, M_IP6MADDR);
2771 }
2772 free(im6o, M_IP6MOPTS);
2773}
2774
2775/*
2776 * Set IPv6 outgoing packet options based on advanced API.
2777 */
2778int
2779ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
2780 struct ip6_pktopts *stickyopt, struct ucred *cred, int uproto)
2781{
2782 struct cmsghdr *cm = 0;
2783

--- 550 unchanged lines hidden ---
2361 * Set IPv6 outgoing packet options based on advanced API.
2362 */
2363int
2364ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
2365 struct ip6_pktopts *stickyopt, struct ucred *cred, int uproto)
2366{
2367 struct cmsghdr *cm = 0;
2368

--- 550 unchanged lines hidden ---