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 --- |