The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/in_mcast.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 2007-2009 Bruce Simpson.
    5  * Copyright (c) 2005 Robert N. M. Watson.
    6  * 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. The name of the author may not be used to endorse or promote
   17  *    products derived from this software without specific prior written
   18  *    permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 
   33 /*
   34  * IPv4 multicast socket, group, and socket option processing module.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD$");
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/lock.h>
   44 #include <sys/malloc.h>
   45 #include <sys/mbuf.h>
   46 #include <sys/protosw.h>
   47 #include <sys/socket.h>
   48 #include <sys/socketvar.h>
   49 #include <sys/protosw.h>
   50 #include <sys/sysctl.h>
   51 #include <sys/ktr.h>
   52 #include <sys/taskqueue.h>
   53 #include <sys/tree.h>
   54 
   55 #include <net/if.h>
   56 #include <net/if_var.h>
   57 #include <net/if_dl.h>
   58 #include <net/route.h>
   59 #include <net/route/nhop.h>
   60 #include <net/vnet.h>
   61 
   62 #include <net/ethernet.h>
   63 
   64 #include <netinet/in.h>
   65 #include <netinet/in_systm.h>
   66 #include <netinet/in_fib.h>
   67 #include <netinet/in_pcb.h>
   68 #include <netinet/in_var.h>
   69 #include <netinet/ip_var.h>
   70 #include <netinet/igmp_var.h>
   71 
   72 #ifndef KTR_IGMPV3
   73 #define KTR_IGMPV3 KTR_INET
   74 #endif
   75 
   76 #ifndef __SOCKUNION_DECLARED
   77 union sockunion {
   78         struct sockaddr_storage ss;
   79         struct sockaddr         sa;
   80         struct sockaddr_dl      sdl;
   81         struct sockaddr_in      sin;
   82 };
   83 typedef union sockunion sockunion_t;
   84 #define __SOCKUNION_DECLARED
   85 #endif /* __SOCKUNION_DECLARED */
   86 
   87 static MALLOC_DEFINE(M_INMFILTER, "in_mfilter",
   88     "IPv4 multicast PCB-layer source filter");
   89 static MALLOC_DEFINE(M_IPMADDR, "in_multi", "IPv4 multicast group");
   90 static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "IPv4 multicast options");
   91 static MALLOC_DEFINE(M_IPMSOURCE, "ip_msource",
   92     "IPv4 multicast IGMP-layer source filter");
   93 
   94 /*
   95  * Locking:
   96  *
   97  * - Lock order is: Giant, IN_MULTI_LOCK, INP_WLOCK,
   98  *   IN_MULTI_LIST_LOCK, IGMP_LOCK, IF_ADDR_LOCK.
   99  * - The IF_ADDR_LOCK is implicitly taken by inm_lookup() earlier, however
  100  *   it can be taken by code in net/if.c also.
  101  * - ip_moptions and in_mfilter are covered by the INP_WLOCK.
  102  *
  103  * struct in_multi is covered by IN_MULTI_LIST_LOCK. There isn't strictly
  104  * any need for in_multi itself to be virtualized -- it is bound to an ifp
  105  * anyway no matter what happens.
  106  */
  107 struct mtx in_multi_list_mtx;
  108 MTX_SYSINIT(in_multi_mtx, &in_multi_list_mtx, "in_multi_list_mtx", MTX_DEF);
  109 
  110 struct mtx in_multi_free_mtx;
  111 MTX_SYSINIT(in_multi_free_mtx, &in_multi_free_mtx, "in_multi_free_mtx", MTX_DEF);
  112 
  113 struct sx in_multi_sx;
  114 SX_SYSINIT(in_multi_sx, &in_multi_sx, "in_multi_sx");
  115 
  116 /*
  117  * Functions with non-static linkage defined in this file should be
  118  * declared in in_var.h:
  119  *  imo_multi_filter()
  120  *  in_joingroup()
  121  *  in_joingroup_locked()
  122  *  in_leavegroup()
  123  *  in_leavegroup_locked()
  124  * and ip_var.h:
  125  *  inp_freemoptions()
  126  *  inp_getmoptions()
  127  *  inp_setmoptions()
  128  */
  129 static void     imf_commit(struct in_mfilter *);
  130 static int      imf_get_source(struct in_mfilter *imf,
  131                     const struct sockaddr_in *psin,
  132                     struct in_msource **);
  133 static struct in_msource *
  134                 imf_graft(struct in_mfilter *, const uint8_t,
  135                     const struct sockaddr_in *);
  136 static void     imf_leave(struct in_mfilter *);
  137 static int      imf_prune(struct in_mfilter *, const struct sockaddr_in *);
  138 static void     imf_purge(struct in_mfilter *);
  139 static void     imf_rollback(struct in_mfilter *);
  140 static void     imf_reap(struct in_mfilter *);
  141 static struct in_mfilter *
  142                 imo_match_group(const struct ip_moptions *,
  143                     const struct ifnet *, const struct sockaddr *);
  144 static struct in_msource *
  145                 imo_match_source(struct in_mfilter *, const struct sockaddr *);
  146 static void     ims_merge(struct ip_msource *ims,
  147                     const struct in_msource *lims, const int rollback);
  148 static int      in_getmulti(struct ifnet *, const struct in_addr *,
  149                     struct in_multi **);
  150 static int      inm_get_source(struct in_multi *inm, const in_addr_t haddr,
  151                     const int noalloc, struct ip_msource **pims);
  152 #ifdef KTR
  153 static int      inm_is_ifp_detached(const struct in_multi *);
  154 #endif
  155 static int      inm_merge(struct in_multi *, /*const*/ struct in_mfilter *);
  156 static void     inm_purge(struct in_multi *);
  157 static void     inm_reap(struct in_multi *);
  158 static void inm_release(struct in_multi *);
  159 static struct ip_moptions *
  160                 inp_findmoptions(struct inpcb *);
  161 static int      inp_get_source_filters(struct inpcb *, struct sockopt *);
  162 static int      inp_join_group(struct inpcb *, struct sockopt *);
  163 static int      inp_leave_group(struct inpcb *, struct sockopt *);
  164 static struct ifnet *
  165                 inp_lookup_mcast_ifp(const struct inpcb *,
  166                     const struct sockaddr_in *, const struct in_addr);
  167 static int      inp_block_unblock_source(struct inpcb *, struct sockopt *);
  168 static int      inp_set_multicast_if(struct inpcb *, struct sockopt *);
  169 static int      inp_set_source_filters(struct inpcb *, struct sockopt *);
  170 static int      sysctl_ip_mcast_filters(SYSCTL_HANDLER_ARGS);
  171 
  172 static SYSCTL_NODE(_net_inet_ip, OID_AUTO, mcast,
  173     CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  174     "IPv4 multicast");
  175 
  176 static u_long in_mcast_maxgrpsrc = IP_MAX_GROUP_SRC_FILTER;
  177 SYSCTL_ULONG(_net_inet_ip_mcast, OID_AUTO, maxgrpsrc,
  178     CTLFLAG_RWTUN, &in_mcast_maxgrpsrc, 0,
  179     "Max source filters per group");
  180 
  181 static u_long in_mcast_maxsocksrc = IP_MAX_SOCK_SRC_FILTER;
  182 SYSCTL_ULONG(_net_inet_ip_mcast, OID_AUTO, maxsocksrc,
  183     CTLFLAG_RWTUN, &in_mcast_maxsocksrc, 0,
  184     "Max source filters per socket");
  185 
  186 int in_mcast_loop = IP_DEFAULT_MULTICAST_LOOP;
  187 SYSCTL_INT(_net_inet_ip_mcast, OID_AUTO, loop, CTLFLAG_RWTUN,
  188     &in_mcast_loop, 0, "Loopback multicast datagrams by default");
  189 
  190 static SYSCTL_NODE(_net_inet_ip_mcast, OID_AUTO, filters,
  191     CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip_mcast_filters,
  192     "Per-interface stack-wide source filters");
  193 
  194 #ifdef KTR
  195 /*
  196  * Inline function which wraps assertions for a valid ifp.
  197  * The ifnet layer will set the ifma's ifp pointer to NULL if the ifp
  198  * is detached.
  199  */
  200 static int __inline
  201 inm_is_ifp_detached(const struct in_multi *inm)
  202 {
  203         struct ifnet *ifp;
  204 
  205         KASSERT(inm->inm_ifma != NULL, ("%s: no ifma", __func__));
  206         ifp = inm->inm_ifma->ifma_ifp;
  207         if (ifp != NULL) {
  208                 /*
  209                  * Sanity check that netinet's notion of ifp is the
  210                  * same as net's.
  211                  */
  212                 KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__));
  213         }
  214 
  215         return (ifp == NULL);
  216 }
  217 #endif
  218 
  219 /*
  220  * Interface detach can happen in a taskqueue thread context, so we must use a
  221  * dedicated thread to avoid deadlocks when draining inm_release tasks.
  222  */
  223 TASKQUEUE_DEFINE_THREAD(inm_free);
  224 static struct in_multi_head inm_free_list = SLIST_HEAD_INITIALIZER();
  225 static void inm_release_task(void *arg __unused, int pending __unused);
  226 static struct task inm_free_task = TASK_INITIALIZER(0, inm_release_task, NULL);
  227 
  228 void
  229 inm_release_wait(void *arg __unused)
  230 {
  231 
  232         /*
  233          * Make sure all pending multicast addresses are freed before
  234          * the VNET or network device is destroyed:
  235          */
  236         taskqueue_drain(taskqueue_inm_free, &inm_free_task);
  237 }
  238 #ifdef VIMAGE
  239 /* XXX-BZ FIXME, see D24914. */
  240 VNET_SYSUNINIT(inm_release_wait, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, inm_release_wait, NULL);
  241 #endif
  242 
  243 void
  244 inm_release_list_deferred(struct in_multi_head *inmh)
  245 {
  246 
  247         if (SLIST_EMPTY(inmh))
  248                 return;
  249         mtx_lock(&in_multi_free_mtx);
  250         SLIST_CONCAT(&inm_free_list, inmh, in_multi, inm_nrele);
  251         mtx_unlock(&in_multi_free_mtx);
  252         taskqueue_enqueue(taskqueue_inm_free, &inm_free_task);
  253 }
  254 
  255 void
  256 inm_disconnect(struct in_multi *inm)
  257 {
  258         struct ifnet *ifp;
  259         struct ifmultiaddr *ifma, *ll_ifma;
  260 
  261         ifp = inm->inm_ifp;
  262         IF_ADDR_WLOCK_ASSERT(ifp);
  263         ifma = inm->inm_ifma;
  264 
  265         if_ref(ifp);
  266         if (ifma->ifma_flags & IFMA_F_ENQUEUED) {
  267                 CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
  268                 ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
  269         }
  270         MCDPRINTF("removed ifma: %p from %s\n", ifma, ifp->if_xname);
  271         if ((ll_ifma = ifma->ifma_llifma) != NULL) {
  272                 MPASS(ifma != ll_ifma);
  273                 ifma->ifma_llifma = NULL;
  274                 MPASS(ll_ifma->ifma_llifma == NULL);
  275                 MPASS(ll_ifma->ifma_ifp == ifp);
  276                 if (--ll_ifma->ifma_refcount == 0) {
  277                         if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
  278                                 CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link);
  279                                 ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
  280                         }
  281                         MCDPRINTF("removed ll_ifma: %p from %s\n", ll_ifma, ifp->if_xname);
  282                         if_freemulti(ll_ifma);
  283                 }
  284         }
  285 }
  286 
  287 void
  288 inm_release_deferred(struct in_multi *inm)
  289 {
  290         struct in_multi_head tmp;
  291 
  292         IN_MULTI_LIST_LOCK_ASSERT();
  293         MPASS(inm->inm_refcount > 0);
  294         if (--inm->inm_refcount == 0) {
  295                 SLIST_INIT(&tmp);
  296                 inm_disconnect(inm);
  297                 inm->inm_ifma->ifma_protospec = NULL;
  298                 SLIST_INSERT_HEAD(&tmp, inm, inm_nrele);
  299                 inm_release_list_deferred(&tmp);
  300         }
  301 }
  302 
  303 static void
  304 inm_release_task(void *arg __unused, int pending __unused)
  305 {
  306         struct in_multi_head inm_free_tmp;
  307         struct in_multi *inm, *tinm;
  308 
  309         SLIST_INIT(&inm_free_tmp);
  310         mtx_lock(&in_multi_free_mtx);
  311         SLIST_CONCAT(&inm_free_tmp, &inm_free_list, in_multi, inm_nrele);
  312         mtx_unlock(&in_multi_free_mtx);
  313         IN_MULTI_LOCK();
  314         SLIST_FOREACH_SAFE(inm, &inm_free_tmp, inm_nrele, tinm) {
  315                 SLIST_REMOVE_HEAD(&inm_free_tmp, inm_nrele);
  316                 MPASS(inm);
  317                 inm_release(inm);
  318         }
  319         IN_MULTI_UNLOCK();
  320 }
  321 
  322 /*
  323  * Initialize an in_mfilter structure to a known state at t0, t1
  324  * with an empty source filter list.
  325  */
  326 static __inline void
  327 imf_init(struct in_mfilter *imf, const int st0, const int st1)
  328 {
  329         memset(imf, 0, sizeof(struct in_mfilter));
  330         RB_INIT(&imf->imf_sources);
  331         imf->imf_st[0] = st0;
  332         imf->imf_st[1] = st1;
  333 }
  334 
  335 struct in_mfilter *
  336 ip_mfilter_alloc(const int mflags, const int st0, const int st1)
  337 {
  338         struct in_mfilter *imf;
  339 
  340         imf = malloc(sizeof(*imf), M_INMFILTER, mflags);
  341         if (imf != NULL)
  342                 imf_init(imf, st0, st1);
  343 
  344         return (imf);
  345 }
  346 
  347 void
  348 ip_mfilter_free(struct in_mfilter *imf)
  349 {
  350 
  351         imf_purge(imf);
  352         free(imf, M_INMFILTER);
  353 }
  354 
  355 /*
  356  * Function for looking up an in_multi record for an IPv4 multicast address
  357  * on a given interface. ifp must be valid. If no record found, return NULL.
  358  * The IN_MULTI_LIST_LOCK and IF_ADDR_LOCK on ifp must be held.
  359  */
  360 struct in_multi *
  361 inm_lookup_locked(struct ifnet *ifp, const struct in_addr ina)
  362 {
  363         struct ifmultiaddr *ifma;
  364         struct in_multi *inm;
  365 
  366         IN_MULTI_LIST_LOCK_ASSERT();
  367         IF_ADDR_LOCK_ASSERT(ifp);
  368 
  369         CK_STAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) {
  370                 inm = inm_ifmultiaddr_get_inm(ifma);
  371                 if (inm == NULL)
  372                         continue;
  373                 if (inm->inm_addr.s_addr == ina.s_addr)
  374                         return (inm);
  375         }
  376         return (NULL);
  377 }
  378 
  379 /*
  380  * Wrapper for inm_lookup_locked().
  381  * The IF_ADDR_LOCK will be taken on ifp and released on return.
  382  */
  383 struct in_multi *
  384 inm_lookup(struct ifnet *ifp, const struct in_addr ina)
  385 {
  386         struct epoch_tracker et;
  387         struct in_multi *inm;
  388 
  389         IN_MULTI_LIST_LOCK_ASSERT();
  390         NET_EPOCH_ENTER(et);
  391 
  392         inm = inm_lookup_locked(ifp, ina);
  393         NET_EPOCH_EXIT(et);
  394 
  395         return (inm);
  396 }
  397 
  398 /*
  399  * Find an IPv4 multicast group entry for this ip_moptions instance
  400  * which matches the specified group, and optionally an interface.
  401  * Return its index into the array, or -1 if not found.
  402  */
  403 static struct in_mfilter *
  404 imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp,
  405     const struct sockaddr *group)
  406 {
  407         const struct sockaddr_in *gsin;
  408         struct in_mfilter *imf;
  409         struct in_multi *inm;
  410 
  411         gsin = (const struct sockaddr_in *)group;
  412 
  413         IP_MFILTER_FOREACH(imf, &imo->imo_head) {
  414                 inm = imf->imf_inm;
  415                 if (inm == NULL)
  416                         continue;
  417                 if ((ifp == NULL || (inm->inm_ifp == ifp)) &&
  418                     in_hosteq(inm->inm_addr, gsin->sin_addr)) {
  419                         break;
  420                 }
  421         }
  422         return (imf);
  423 }
  424 
  425 /*
  426  * Find an IPv4 multicast source entry for this imo which matches
  427  * the given group index for this socket, and source address.
  428  *
  429  * NOTE: This does not check if the entry is in-mode, merely if
  430  * it exists, which may not be the desired behaviour.
  431  */
  432 static struct in_msource *
  433 imo_match_source(struct in_mfilter *imf, const struct sockaddr *src)
  434 {
  435         struct ip_msource        find;
  436         struct ip_msource       *ims;
  437         const sockunion_t       *psa;
  438 
  439         KASSERT(src->sa_family == AF_INET, ("%s: !AF_INET", __func__));
  440 
  441         /* Source trees are keyed in host byte order. */
  442         psa = (const sockunion_t *)src;
  443         find.ims_haddr = ntohl(psa->sin.sin_addr.s_addr);
  444         ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find);
  445 
  446         return ((struct in_msource *)ims);
  447 }
  448 
  449 /*
  450  * Perform filtering for multicast datagrams on a socket by group and source.
  451  *
  452  * Returns 0 if a datagram should be allowed through, or various error codes
  453  * if the socket was not a member of the group, or the source was muted, etc.
  454  */
  455 int
  456 imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp,
  457     const struct sockaddr *group, const struct sockaddr *src)
  458 {
  459         struct in_mfilter *imf;
  460         struct in_msource *ims;
  461         int mode;
  462 
  463         KASSERT(ifp != NULL, ("%s: null ifp", __func__));
  464 
  465         imf = imo_match_group(imo, ifp, group);
  466         if (imf == NULL)
  467                 return (MCAST_NOTGMEMBER);
  468 
  469         /*
  470          * Check if the source was included in an (S,G) join.
  471          * Allow reception on exclusive memberships by default,
  472          * reject reception on inclusive memberships by default.
  473          * Exclude source only if an in-mode exclude filter exists.
  474          * Include source only if an in-mode include filter exists.
  475          * NOTE: We are comparing group state here at IGMP t1 (now)
  476          * with socket-layer t0 (since last downcall).
  477          */
  478         mode = imf->imf_st[1];
  479         ims = imo_match_source(imf, src);
  480 
  481         if ((ims == NULL && mode == MCAST_INCLUDE) ||
  482             (ims != NULL && ims->imsl_st[0] != mode))
  483                 return (MCAST_NOTSMEMBER);
  484 
  485         return (MCAST_PASS);
  486 }
  487 
  488 /*
  489  * Find and return a reference to an in_multi record for (ifp, group),
  490  * and bump its reference count.
  491  * If one does not exist, try to allocate it, and update link-layer multicast
  492  * filters on ifp to listen for group.
  493  * Assumes the IN_MULTI lock is held across the call.
  494  * Return 0 if successful, otherwise return an appropriate error code.
  495  */
  496 static int
  497 in_getmulti(struct ifnet *ifp, const struct in_addr *group,
  498     struct in_multi **pinm)
  499 {
  500         struct sockaddr_in       gsin;
  501         struct ifmultiaddr      *ifma;
  502         struct in_ifinfo        *ii;
  503         struct in_multi         *inm;
  504         int error;
  505 
  506         IN_MULTI_LOCK_ASSERT();
  507 
  508         ii = (struct in_ifinfo *)ifp->if_afdata[AF_INET];
  509         IN_MULTI_LIST_LOCK();
  510         inm = inm_lookup(ifp, *group);
  511         if (inm != NULL) {
  512                 /*
  513                  * If we already joined this group, just bump the
  514                  * refcount and return it.
  515                  */
  516                 KASSERT(inm->inm_refcount >= 1,
  517                     ("%s: bad refcount %d", __func__, inm->inm_refcount));
  518                 inm_acquire_locked(inm);
  519                 *pinm = inm;
  520         }
  521         IN_MULTI_LIST_UNLOCK();
  522         if (inm != NULL)
  523                 return (0);
  524 
  525         memset(&gsin, 0, sizeof(gsin));
  526         gsin.sin_family = AF_INET;
  527         gsin.sin_len = sizeof(struct sockaddr_in);
  528         gsin.sin_addr = *group;
  529 
  530         /*
  531          * Check if a link-layer group is already associated
  532          * with this network-layer group on the given ifnet.
  533          */
  534         error = if_addmulti(ifp, (struct sockaddr *)&gsin, &ifma);
  535         if (error != 0)
  536                 return (error);
  537 
  538         /* XXX ifma_protospec must be covered by IF_ADDR_LOCK */
  539         IN_MULTI_LIST_LOCK();
  540         IF_ADDR_WLOCK(ifp);
  541 
  542         /*
  543          * If something other than netinet is occupying the link-layer
  544          * group, print a meaningful error message and back out of
  545          * the allocation.
  546          * Otherwise, bump the refcount on the existing network-layer
  547          * group association and return it.
  548          */
  549         if (ifma->ifma_protospec != NULL) {
  550                 inm = (struct in_multi *)ifma->ifma_protospec;
  551 #ifdef INVARIANTS
  552                 KASSERT(ifma->ifma_addr != NULL, ("%s: no ifma_addr",
  553                     __func__));
  554                 KASSERT(ifma->ifma_addr->sa_family == AF_INET,
  555                     ("%s: ifma not AF_INET", __func__));
  556                 KASSERT(inm != NULL, ("%s: no ifma_protospec", __func__));
  557                 if (inm->inm_ifma != ifma || inm->inm_ifp != ifp ||
  558                     !in_hosteq(inm->inm_addr, *group)) {
  559                         char addrbuf[INET_ADDRSTRLEN];
  560 
  561                         panic("%s: ifma %p is inconsistent with %p (%s)",
  562                             __func__, ifma, inm, inet_ntoa_r(*group, addrbuf));
  563                 }
  564 #endif
  565                 inm_acquire_locked(inm);
  566                 *pinm = inm;
  567                 goto out_locked;
  568         }
  569 
  570         IF_ADDR_WLOCK_ASSERT(ifp);
  571 
  572         /*
  573          * A new in_multi record is needed; allocate and initialize it.
  574          * We DO NOT perform an IGMP join as the in_ layer may need to
  575          * push an initial source list down to IGMP to support SSM.
  576          *
  577          * The initial source filter state is INCLUDE, {} as per the RFC.
  578          */
  579         inm = malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT | M_ZERO);
  580         if (inm == NULL) {
  581                 IF_ADDR_WUNLOCK(ifp);
  582                 IN_MULTI_LIST_UNLOCK();
  583                 if_delmulti_ifma(ifma);
  584                 return (ENOMEM);
  585         }
  586         inm->inm_addr = *group;
  587         inm->inm_ifp = ifp;
  588         inm->inm_igi = ii->ii_igmp;
  589         inm->inm_ifma = ifma;
  590         inm->inm_refcount = 1;
  591         inm->inm_state = IGMP_NOT_MEMBER;
  592         mbufq_init(&inm->inm_scq, IGMP_MAX_STATE_CHANGES);
  593         inm->inm_st[0].iss_fmode = MCAST_UNDEFINED;
  594         inm->inm_st[1].iss_fmode = MCAST_UNDEFINED;
  595         RB_INIT(&inm->inm_srcs);
  596 
  597         ifma->ifma_protospec = inm;
  598 
  599         *pinm = inm;
  600  out_locked:
  601         IF_ADDR_WUNLOCK(ifp);
  602         IN_MULTI_LIST_UNLOCK();
  603         return (0);
  604 }
  605 
  606 /*
  607  * Drop a reference to an in_multi record.
  608  *
  609  * If the refcount drops to 0, free the in_multi record and
  610  * delete the underlying link-layer membership.
  611  */
  612 static void
  613 inm_release(struct in_multi *inm)
  614 {
  615         struct ifmultiaddr *ifma;
  616         struct ifnet *ifp;
  617 
  618         CTR2(KTR_IGMPV3, "%s: refcount is %d", __func__, inm->inm_refcount);
  619         MPASS(inm->inm_refcount == 0);
  620         CTR2(KTR_IGMPV3, "%s: freeing inm %p", __func__, inm);
  621 
  622         ifma = inm->inm_ifma;
  623         ifp = inm->inm_ifp;
  624 
  625         /* XXX this access is not covered by IF_ADDR_LOCK */
  626         CTR2(KTR_IGMPV3, "%s: purging ifma %p", __func__, ifma);
  627         if (ifp != NULL) {
  628                 CURVNET_SET(ifp->if_vnet);
  629                 inm_purge(inm);
  630                 free(inm, M_IPMADDR);
  631                 if_delmulti_ifma_flags(ifma, 1);
  632                 CURVNET_RESTORE();
  633                 if_rele(ifp);
  634         } else {
  635                 inm_purge(inm);
  636                 free(inm, M_IPMADDR);
  637                 if_delmulti_ifma_flags(ifma, 1);
  638         }
  639 }
  640 
  641 /*
  642  * Clear recorded source entries for a group.
  643  * Used by the IGMP code. Caller must hold the IN_MULTI lock.
  644  * FIXME: Should reap.
  645  */
  646 void
  647 inm_clear_recorded(struct in_multi *inm)
  648 {
  649         struct ip_msource       *ims;
  650 
  651         IN_MULTI_LIST_LOCK_ASSERT();
  652 
  653         RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) {
  654                 if (ims->ims_stp) {
  655                         ims->ims_stp = 0;
  656                         --inm->inm_st[1].iss_rec;
  657                 }
  658         }
  659         KASSERT(inm->inm_st[1].iss_rec == 0,
  660             ("%s: iss_rec %d not 0", __func__, inm->inm_st[1].iss_rec));
  661 }
  662 
  663 /*
  664  * Record a source as pending for a Source-Group IGMPv3 query.
  665  * This lives here as it modifies the shared tree.
  666  *
  667  * inm is the group descriptor.
  668  * naddr is the address of the source to record in network-byte order.
  669  *
  670  * If the net.inet.igmp.sgalloc sysctl is non-zero, we will
  671  * lazy-allocate a source node in response to an SG query.
  672  * Otherwise, no allocation is performed. This saves some memory
  673  * with the trade-off that the source will not be reported to the
  674  * router if joined in the window between the query response and
  675  * the group actually being joined on the local host.
  676  *
  677  * VIMAGE: XXX: Currently the igmp_sgalloc feature has been removed.
  678  * This turns off the allocation of a recorded source entry if
  679  * the group has not been joined.
  680  *
  681  * Return 0 if the source didn't exist or was already marked as recorded.
  682  * Return 1 if the source was marked as recorded by this function.
  683  * Return <0 if any error occurred (negated errno code).
  684  */
  685 int
  686 inm_record_source(struct in_multi *inm, const in_addr_t naddr)
  687 {
  688         struct ip_msource        find;
  689         struct ip_msource       *ims, *nims;
  690 
  691         IN_MULTI_LIST_LOCK_ASSERT();
  692 
  693         find.ims_haddr = ntohl(naddr);
  694         ims = RB_FIND(ip_msource_tree, &inm->inm_srcs, &find);
  695         if (ims && ims->ims_stp)
  696                 return (0);
  697         if (ims == NULL) {
  698                 if (inm->inm_nsrc == in_mcast_maxgrpsrc)
  699                         return (-ENOSPC);
  700                 nims = malloc(sizeof(struct ip_msource), M_IPMSOURCE,
  701                     M_NOWAIT | M_ZERO);
  702                 if (nims == NULL)
  703                         return (-ENOMEM);
  704                 nims->ims_haddr = find.ims_haddr;
  705                 RB_INSERT(ip_msource_tree, &inm->inm_srcs, nims);
  706                 ++inm->inm_nsrc;
  707                 ims = nims;
  708         }
  709 
  710         /*
  711          * Mark the source as recorded and update the recorded
  712          * source count.
  713          */
  714         ++ims->ims_stp;
  715         ++inm->inm_st[1].iss_rec;
  716 
  717         return (1);
  718 }
  719 
  720 /*
  721  * Return a pointer to an in_msource owned by an in_mfilter,
  722  * given its source address.
  723  * Lazy-allocate if needed. If this is a new entry its filter state is
  724  * undefined at t0.
  725  *
  726  * imf is the filter set being modified.
  727  * haddr is the source address in *host* byte-order.
  728  *
  729  * SMPng: May be called with locks held; malloc must not block.
  730  */
  731 static int
  732 imf_get_source(struct in_mfilter *imf, const struct sockaddr_in *psin,
  733     struct in_msource **plims)
  734 {
  735         struct ip_msource        find;
  736         struct ip_msource       *ims, *nims;
  737         struct in_msource       *lims;
  738         int                      error;
  739 
  740         error = 0;
  741         ims = NULL;
  742         lims = NULL;
  743 
  744         /* key is host byte order */
  745         find.ims_haddr = ntohl(psin->sin_addr.s_addr);
  746         ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find);
  747         lims = (struct in_msource *)ims;
  748         if (lims == NULL) {
  749                 if (imf->imf_nsrc == in_mcast_maxsocksrc)
  750                         return (ENOSPC);
  751                 nims = malloc(sizeof(struct in_msource), M_INMFILTER,
  752                     M_NOWAIT | M_ZERO);
  753                 if (nims == NULL)
  754                         return (ENOMEM);
  755                 lims = (struct in_msource *)nims;
  756                 lims->ims_haddr = find.ims_haddr;
  757                 lims->imsl_st[0] = MCAST_UNDEFINED;
  758                 RB_INSERT(ip_msource_tree, &imf->imf_sources, nims);
  759                 ++imf->imf_nsrc;
  760         }
  761 
  762         *plims = lims;
  763 
  764         return (error);
  765 }
  766 
  767 /*
  768  * Graft a source entry into an existing socket-layer filter set,
  769  * maintaining any required invariants and checking allocations.
  770  *
  771  * The source is marked as being in the new filter mode at t1.
  772  *
  773  * Return the pointer to the new node, otherwise return NULL.
  774  */
  775 static struct in_msource *
  776 imf_graft(struct in_mfilter *imf, const uint8_t st1,
  777     const struct sockaddr_in *psin)
  778 {
  779         struct ip_msource       *nims;
  780         struct in_msource       *lims;
  781 
  782         nims = malloc(sizeof(struct in_msource), M_INMFILTER,
  783             M_NOWAIT | M_ZERO);
  784         if (nims == NULL)
  785                 return (NULL);
  786         lims = (struct in_msource *)nims;
  787         lims->ims_haddr = ntohl(psin->sin_addr.s_addr);
  788         lims->imsl_st[0] = MCAST_UNDEFINED;
  789         lims->imsl_st[1] = st1;
  790         RB_INSERT(ip_msource_tree, &imf->imf_sources, nims);
  791         ++imf->imf_nsrc;
  792 
  793         return (lims);
  794 }
  795 
  796 /*
  797  * Prune a source entry from an existing socket-layer filter set,
  798  * maintaining any required invariants and checking allocations.
  799  *
  800  * The source is marked as being left at t1, it is not freed.
  801  *
  802  * Return 0 if no error occurred, otherwise return an errno value.
  803  */
  804 static int
  805 imf_prune(struct in_mfilter *imf, const struct sockaddr_in *psin)
  806 {
  807         struct ip_msource        find;
  808         struct ip_msource       *ims;
  809         struct in_msource       *lims;
  810 
  811         /* key is host byte order */
  812         find.ims_haddr = ntohl(psin->sin_addr.s_addr);
  813         ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find);
  814         if (ims == NULL)
  815                 return (ENOENT);
  816         lims = (struct in_msource *)ims;
  817         lims->imsl_st[1] = MCAST_UNDEFINED;
  818         return (0);
  819 }
  820 
  821 /*
  822  * Revert socket-layer filter set deltas at t1 to t0 state.
  823  */
  824 static void
  825 imf_rollback(struct in_mfilter *imf)
  826 {
  827         struct ip_msource       *ims, *tims;
  828         struct in_msource       *lims;
  829 
  830         RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) {
  831                 lims = (struct in_msource *)ims;
  832                 if (lims->imsl_st[0] == lims->imsl_st[1]) {
  833                         /* no change at t1 */
  834                         continue;
  835                 } else if (lims->imsl_st[0] != MCAST_UNDEFINED) {
  836                         /* revert change to existing source at t1 */
  837                         lims->imsl_st[1] = lims->imsl_st[0];
  838                 } else {
  839                         /* revert source added t1 */
  840                         CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims);
  841                         RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims);
  842                         free(ims, M_INMFILTER);
  843                         imf->imf_nsrc--;
  844                 }
  845         }
  846         imf->imf_st[1] = imf->imf_st[0];
  847 }
  848 
  849 /*
  850  * Mark socket-layer filter set as INCLUDE {} at t1.
  851  */
  852 static void
  853 imf_leave(struct in_mfilter *imf)
  854 {
  855         struct ip_msource       *ims;
  856         struct in_msource       *lims;
  857 
  858         RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) {
  859                 lims = (struct in_msource *)ims;
  860                 lims->imsl_st[1] = MCAST_UNDEFINED;
  861         }
  862         imf->imf_st[1] = MCAST_INCLUDE;
  863 }
  864 
  865 /*
  866  * Mark socket-layer filter set deltas as committed.
  867  */
  868 static void
  869 imf_commit(struct in_mfilter *imf)
  870 {
  871         struct ip_msource       *ims;
  872         struct in_msource       *lims;
  873 
  874         RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) {
  875                 lims = (struct in_msource *)ims;
  876                 lims->imsl_st[0] = lims->imsl_st[1];
  877         }
  878         imf->imf_st[0] = imf->imf_st[1];
  879 }
  880 
  881 /*
  882  * Reap unreferenced sources from socket-layer filter set.
  883  */
  884 static void
  885 imf_reap(struct in_mfilter *imf)
  886 {
  887         struct ip_msource       *ims, *tims;
  888         struct in_msource       *lims;
  889 
  890         RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) {
  891                 lims = (struct in_msource *)ims;
  892                 if ((lims->imsl_st[0] == MCAST_UNDEFINED) &&
  893                     (lims->imsl_st[1] == MCAST_UNDEFINED)) {
  894                         CTR2(KTR_IGMPV3, "%s: free lims %p", __func__, ims);
  895                         RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims);
  896                         free(ims, M_INMFILTER);
  897                         imf->imf_nsrc--;
  898                 }
  899         }
  900 }
  901 
  902 /*
  903  * Purge socket-layer filter set.
  904  */
  905 static void
  906 imf_purge(struct in_mfilter *imf)
  907 {
  908         struct ip_msource       *ims, *tims;
  909 
  910         RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) {
  911                 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims);
  912                 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims);
  913                 free(ims, M_INMFILTER);
  914                 imf->imf_nsrc--;
  915         }
  916         imf->imf_st[0] = imf->imf_st[1] = MCAST_UNDEFINED;
  917         KASSERT(RB_EMPTY(&imf->imf_sources),
  918             ("%s: imf_sources not empty", __func__));
  919 }
  920 
  921 /*
  922  * Look up a source filter entry for a multicast group.
  923  *
  924  * inm is the group descriptor to work with.
  925  * haddr is the host-byte-order IPv4 address to look up.
  926  * noalloc may be non-zero to suppress allocation of sources.
  927  * *pims will be set to the address of the retrieved or allocated source.
  928  *
  929  * SMPng: NOTE: may be called with locks held.
  930  * Return 0 if successful, otherwise return a non-zero error code.
  931  */
  932 static int
  933 inm_get_source(struct in_multi *inm, const in_addr_t haddr,
  934     const int noalloc, struct ip_msource **pims)
  935 {
  936         struct ip_msource        find;
  937         struct ip_msource       *ims, *nims;
  938 
  939         find.ims_haddr = haddr;
  940         ims = RB_FIND(ip_msource_tree, &inm->inm_srcs, &find);
  941         if (ims == NULL && !noalloc) {
  942                 if (inm->inm_nsrc == in_mcast_maxgrpsrc)
  943                         return (ENOSPC);
  944                 nims = malloc(sizeof(struct ip_msource), M_IPMSOURCE,
  945                     M_NOWAIT | M_ZERO);
  946                 if (nims == NULL)
  947                         return (ENOMEM);
  948                 nims->ims_haddr = haddr;
  949                 RB_INSERT(ip_msource_tree, &inm->inm_srcs, nims);
  950                 ++inm->inm_nsrc;
  951                 ims = nims;
  952 #ifdef KTR
  953                 CTR3(KTR_IGMPV3, "%s: allocated 0x%08x as %p", __func__,
  954                     haddr, ims);
  955 #endif
  956         }
  957 
  958         *pims = ims;
  959         return (0);
  960 }
  961 
  962 /*
  963  * Merge socket-layer source into IGMP-layer source.
  964  * If rollback is non-zero, perform the inverse of the merge.
  965  */
  966 static void
  967 ims_merge(struct ip_msource *ims, const struct in_msource *lims,
  968     const int rollback)
  969 {
  970         int n = rollback ? -1 : 1;
  971 
  972         if (lims->imsl_st[0] == MCAST_EXCLUDE) {
  973                 CTR3(KTR_IGMPV3, "%s: t1 ex -= %d on 0x%08x",
  974                     __func__, n, ims->ims_haddr);
  975                 ims->ims_st[1].ex -= n;
  976         } else if (lims->imsl_st[0] == MCAST_INCLUDE) {
  977                 CTR3(KTR_IGMPV3, "%s: t1 in -= %d on 0x%08x",
  978                     __func__, n, ims->ims_haddr);
  979                 ims->ims_st[1].in -= n;
  980         }
  981 
  982         if (lims->imsl_st[1] == MCAST_EXCLUDE) {
  983                 CTR3(KTR_IGMPV3, "%s: t1 ex += %d on 0x%08x",
  984                     __func__, n, ims->ims_haddr);
  985                 ims->ims_st[1].ex += n;
  986         } else if (lims->imsl_st[1] == MCAST_INCLUDE) {
  987                 CTR3(KTR_IGMPV3, "%s: t1 in += %d on 0x%08x",
  988                     __func__, n, ims->ims_haddr);
  989                 ims->ims_st[1].in += n;
  990         }
  991 }
  992 
  993 /*
  994  * Atomically update the global in_multi state, when a membership's
  995  * filter list is being updated in any way.
  996  *
  997  * imf is the per-inpcb-membership group filter pointer.
  998  * A fake imf may be passed for in-kernel consumers.
  999  *
 1000  * XXX This is a candidate for a set-symmetric-difference style loop
 1001  * which would eliminate the repeated lookup from root of ims nodes,
 1002  * as they share the same key space.
 1003  *
 1004  * If any error occurred this function will back out of refcounts
 1005  * and return a non-zero value.
 1006  */
 1007 static int
 1008 inm_merge(struct in_multi *inm, /*const*/ struct in_mfilter *imf)
 1009 {
 1010         struct ip_msource       *ims, *nims;
 1011         struct in_msource       *lims;
 1012         int                      schanged, error;
 1013         int                      nsrc0, nsrc1;
 1014 
 1015         schanged = 0;
 1016         error = 0;
 1017         nsrc1 = nsrc0 = 0;
 1018         IN_MULTI_LIST_LOCK_ASSERT();
 1019 
 1020         /*
 1021          * Update the source filters first, as this may fail.
 1022          * Maintain count of in-mode filters at t0, t1. These are
 1023          * used to work out if we transition into ASM mode or not.
 1024          * Maintain a count of source filters whose state was
 1025          * actually modified by this operation.
 1026          */
 1027         RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) {
 1028                 lims = (struct in_msource *)ims;
 1029                 if (lims->imsl_st[0] == imf->imf_st[0]) nsrc0++;
 1030                 if (lims->imsl_st[1] == imf->imf_st[1]) nsrc1++;
 1031                 if (lims->imsl_st[0] == lims->imsl_st[1]) continue;
 1032                 error = inm_get_source(inm, lims->ims_haddr, 0, &nims);
 1033                 ++schanged;
 1034                 if (error)
 1035                         break;
 1036                 ims_merge(nims, lims, 0);
 1037         }
 1038         if (error) {
 1039                 struct ip_msource *bims;
 1040 
 1041                 RB_FOREACH_REVERSE_FROM(ims, ip_msource_tree, nims) {
 1042                         lims = (struct in_msource *)ims;
 1043                         if (lims->imsl_st[0] == lims->imsl_st[1])
 1044                                 continue;
 1045                         (void)inm_get_source(inm, lims->ims_haddr, 1, &bims);
 1046                         if (bims == NULL)
 1047                                 continue;
 1048                         ims_merge(bims, lims, 1);
 1049                 }
 1050                 goto out_reap;
 1051         }
 1052 
 1053         CTR3(KTR_IGMPV3, "%s: imf filters in-mode: %d at t0, %d at t1",
 1054             __func__, nsrc0, nsrc1);
 1055 
 1056         /* Handle transition between INCLUDE {n} and INCLUDE {} on socket. */
 1057         if (imf->imf_st[0] == imf->imf_st[1] &&
 1058             imf->imf_st[1] == MCAST_INCLUDE) {
 1059                 if (nsrc1 == 0) {
 1060                         CTR1(KTR_IGMPV3, "%s: --in on inm at t1", __func__);
 1061                         --inm->inm_st[1].iss_in;
 1062                 }
 1063         }
 1064 
 1065         /* Handle filter mode transition on socket. */
 1066         if (imf->imf_st[0] != imf->imf_st[1]) {
 1067                 CTR3(KTR_IGMPV3, "%s: imf transition %d to %d",
 1068                     __func__, imf->imf_st[0], imf->imf_st[1]);
 1069 
 1070                 if (imf->imf_st[0] == MCAST_EXCLUDE) {
 1071                         CTR1(KTR_IGMPV3, "%s: --ex on inm at t1", __func__);
 1072                         --inm->inm_st[1].iss_ex;
 1073                 } else if (imf->imf_st[0] == MCAST_INCLUDE) {
 1074                         CTR1(KTR_IGMPV3, "%s: --in on inm at t1", __func__);
 1075                         --inm->inm_st[1].iss_in;
 1076                 }
 1077 
 1078                 if (imf->imf_st[1] == MCAST_EXCLUDE) {
 1079                         CTR1(KTR_IGMPV3, "%s: ex++ on inm at t1", __func__);
 1080                         inm->inm_st[1].iss_ex++;
 1081                 } else if (imf->imf_st[1] == MCAST_INCLUDE && nsrc1 > 0) {
 1082                         CTR1(KTR_IGMPV3, "%s: in++ on inm at t1", __func__);
 1083                         inm->inm_st[1].iss_in++;
 1084                 }
 1085         }
 1086 
 1087         /*
 1088          * Track inm filter state in terms of listener counts.
 1089          * If there are any exclusive listeners, stack-wide
 1090          * membership is exclusive.
 1091          * Otherwise, if only inclusive listeners, stack-wide is inclusive.
 1092          * If no listeners remain, state is undefined at t1,
 1093          * and the IGMP lifecycle for this group should finish.
 1094          */
 1095         if (inm->inm_st[1].iss_ex > 0) {
 1096                 CTR1(KTR_IGMPV3, "%s: transition to EX", __func__);
 1097                 inm->inm_st[1].iss_fmode = MCAST_EXCLUDE;
 1098         } else if (inm->inm_st[1].iss_in > 0) {
 1099                 CTR1(KTR_IGMPV3, "%s: transition to IN", __func__);
 1100                 inm->inm_st[1].iss_fmode = MCAST_INCLUDE;
 1101         } else {
 1102                 CTR1(KTR_IGMPV3, "%s: transition to UNDEF", __func__);
 1103                 inm->inm_st[1].iss_fmode = MCAST_UNDEFINED;
 1104         }
 1105 
 1106         /* Decrement ASM listener count on transition out of ASM mode. */
 1107         if (imf->imf_st[0] == MCAST_EXCLUDE && nsrc0 == 0) {
 1108                 if ((imf->imf_st[1] != MCAST_EXCLUDE) ||
 1109                     (imf->imf_st[1] == MCAST_EXCLUDE && nsrc1 > 0)) {
 1110                         CTR1(KTR_IGMPV3, "%s: --asm on inm at t1", __func__);
 1111                         --inm->inm_st[1].iss_asm;
 1112                 }
 1113         }
 1114 
 1115         /* Increment ASM listener count on transition to ASM mode. */
 1116         if (imf->imf_st[1] == MCAST_EXCLUDE && nsrc1 == 0) {
 1117                 CTR1(KTR_IGMPV3, "%s: asm++ on inm at t1", __func__);
 1118                 inm->inm_st[1].iss_asm++;
 1119         }
 1120 
 1121         CTR3(KTR_IGMPV3, "%s: merged imf %p to inm %p", __func__, imf, inm);
 1122         inm_print(inm);
 1123 
 1124 out_reap:
 1125         if (schanged > 0) {
 1126                 CTR1(KTR_IGMPV3, "%s: sources changed; reaping", __func__);
 1127                 inm_reap(inm);
 1128         }
 1129         return (error);
 1130 }
 1131 
 1132 /*
 1133  * Mark an in_multi's filter set deltas as committed.
 1134  * Called by IGMP after a state change has been enqueued.
 1135  */
 1136 void
 1137 inm_commit(struct in_multi *inm)
 1138 {
 1139         struct ip_msource       *ims;
 1140 
 1141         CTR2(KTR_IGMPV3, "%s: commit inm %p", __func__, inm);
 1142         CTR1(KTR_IGMPV3, "%s: pre commit:", __func__);
 1143         inm_print(inm);
 1144 
 1145         RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) {
 1146                 ims->ims_st[0] = ims->ims_st[1];
 1147         }
 1148         inm->inm_st[0] = inm->inm_st[1];
 1149 }
 1150 
 1151 /*
 1152  * Reap unreferenced nodes from an in_multi's filter set.
 1153  */
 1154 static void
 1155 inm_reap(struct in_multi *inm)
 1156 {
 1157         struct ip_msource       *ims, *tims;
 1158 
 1159         RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, tims) {
 1160                 if (ims->ims_st[0].ex > 0 || ims->ims_st[0].in > 0 ||
 1161                     ims->ims_st[1].ex > 0 || ims->ims_st[1].in > 0 ||
 1162                     ims->ims_stp != 0)
 1163                         continue;
 1164                 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims);
 1165                 RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims);
 1166                 free(ims, M_IPMSOURCE);
 1167                 inm->inm_nsrc--;
 1168         }
 1169 }
 1170 
 1171 /*
 1172  * Purge all source nodes from an in_multi's filter set.
 1173  */
 1174 static void
 1175 inm_purge(struct in_multi *inm)
 1176 {
 1177         struct ip_msource       *ims, *tims;
 1178 
 1179         RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, tims) {
 1180                 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims);
 1181                 RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims);
 1182                 free(ims, M_IPMSOURCE);
 1183                 inm->inm_nsrc--;
 1184         }
 1185 }
 1186 
 1187 /*
 1188  * Join a multicast group; unlocked entry point.
 1189  *
 1190  * SMPng: XXX: in_joingroup() is called from in_control() when Giant
 1191  * is not held. Fortunately, ifp is unlikely to have been detached
 1192  * at this point, so we assume it's OK to recurse.
 1193  */
 1194 int
 1195 in_joingroup(struct ifnet *ifp, const struct in_addr *gina,
 1196     /*const*/ struct in_mfilter *imf, struct in_multi **pinm)
 1197 {
 1198         int error;
 1199 
 1200         IN_MULTI_LOCK();
 1201         error = in_joingroup_locked(ifp, gina, imf, pinm);
 1202         IN_MULTI_UNLOCK();
 1203 
 1204         return (error);
 1205 }
 1206 
 1207 /*
 1208  * Join a multicast group; real entry point.
 1209  *
 1210  * Only preserves atomicity at inm level.
 1211  * NOTE: imf argument cannot be const due to sys/tree.h limitations.
 1212  *
 1213  * If the IGMP downcall fails, the group is not joined, and an error
 1214  * code is returned.
 1215  */
 1216 int
 1217 in_joingroup_locked(struct ifnet *ifp, const struct in_addr *gina,
 1218     /*const*/ struct in_mfilter *imf, struct in_multi **pinm)
 1219 {
 1220         struct in_mfilter        timf;
 1221         struct in_multi         *inm;
 1222         int                      error;
 1223 
 1224         IN_MULTI_LOCK_ASSERT();
 1225         IN_MULTI_LIST_UNLOCK_ASSERT();
 1226 
 1227         CTR4(KTR_IGMPV3, "%s: join 0x%08x on %p(%s))", __func__,
 1228             ntohl(gina->s_addr), ifp, ifp->if_xname);
 1229 
 1230         error = 0;
 1231         inm = NULL;
 1232 
 1233         /*
 1234          * If no imf was specified (i.e. kernel consumer),
 1235          * fake one up and assume it is an ASM join.
 1236          */
 1237         if (imf == NULL) {
 1238                 imf_init(&timf, MCAST_UNDEFINED, MCAST_EXCLUDE);
 1239                 imf = &timf;
 1240         }
 1241 
 1242         error = in_getmulti(ifp, gina, &inm);
 1243         if (error) {
 1244                 CTR1(KTR_IGMPV3, "%s: in_getmulti() failure", __func__);
 1245                 return (error);
 1246         }
 1247         IN_MULTI_LIST_LOCK();
 1248         CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
 1249         error = inm_merge(inm, imf);
 1250         if (error) {
 1251                 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__);
 1252                 goto out_inm_release;
 1253         }
 1254 
 1255         CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
 1256         error = igmp_change_state(inm);
 1257         if (error) {
 1258                 CTR1(KTR_IGMPV3, "%s: failed to update source", __func__);
 1259                 goto out_inm_release;
 1260         }
 1261 
 1262  out_inm_release:
 1263         if (error) {
 1264                 CTR2(KTR_IGMPV3, "%s: dropping ref on %p", __func__, inm);
 1265                 IF_ADDR_WLOCK(ifp);
 1266                 inm_release_deferred(inm);
 1267                 IF_ADDR_WUNLOCK(ifp);
 1268         } else {
 1269                 *pinm = inm;
 1270         }
 1271         IN_MULTI_LIST_UNLOCK();
 1272 
 1273         return (error);
 1274 }
 1275 
 1276 /*
 1277  * Leave a multicast group; unlocked entry point.
 1278  */
 1279 int
 1280 in_leavegroup(struct in_multi *inm, /*const*/ struct in_mfilter *imf)
 1281 {
 1282         int error;
 1283 
 1284         IN_MULTI_LOCK();
 1285         error = in_leavegroup_locked(inm, imf);
 1286         IN_MULTI_UNLOCK();
 1287 
 1288         return (error);
 1289 }
 1290 
 1291 /*
 1292  * Leave a multicast group; real entry point.
 1293  * All source filters will be expunged.
 1294  *
 1295  * Only preserves atomicity at inm level.
 1296  *
 1297  * Holding the write lock for the INP which contains imf
 1298  * is highly advisable. We can't assert for it as imf does not
 1299  * contain a back-pointer to the owning inp.
 1300  *
 1301  * Note: This is not the same as inm_release(*) as this function also
 1302  * makes a state change downcall into IGMP.
 1303  */
 1304 int
 1305 in_leavegroup_locked(struct in_multi *inm, /*const*/ struct in_mfilter *imf)
 1306 {
 1307         struct in_mfilter        timf;
 1308         int                      error;
 1309 
 1310         IN_MULTI_LOCK_ASSERT();
 1311         IN_MULTI_LIST_UNLOCK_ASSERT();
 1312 
 1313         error = 0;
 1314 
 1315         CTR5(KTR_IGMPV3, "%s: leave inm %p, 0x%08x/%s, imf %p", __func__,
 1316             inm, ntohl(inm->inm_addr.s_addr),
 1317             (inm_is_ifp_detached(inm) ? "null" : inm->inm_ifp->if_xname),
 1318             imf);
 1319 
 1320         /*
 1321          * If no imf was specified (i.e. kernel consumer),
 1322          * fake one up and assume it is an ASM join.
 1323          */
 1324         if (imf == NULL) {
 1325                 imf_init(&timf, MCAST_EXCLUDE, MCAST_UNDEFINED);
 1326                 imf = &timf;
 1327         }
 1328 
 1329         /*
 1330          * Begin state merge transaction at IGMP layer.
 1331          *
 1332          * As this particular invocation should not cause any memory
 1333          * to be allocated, and there is no opportunity to roll back
 1334          * the transaction, it MUST NOT fail.
 1335          */
 1336         CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
 1337         IN_MULTI_LIST_LOCK();
 1338         error = inm_merge(inm, imf);
 1339         KASSERT(error == 0, ("%s: failed to merge inm state", __func__));
 1340 
 1341         CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
 1342         CURVNET_SET(inm->inm_ifp->if_vnet);
 1343         error = igmp_change_state(inm);
 1344         IF_ADDR_WLOCK(inm->inm_ifp);
 1345         inm_release_deferred(inm);
 1346         IF_ADDR_WUNLOCK(inm->inm_ifp);
 1347         IN_MULTI_LIST_UNLOCK();
 1348         CURVNET_RESTORE();
 1349         if (error)
 1350                 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__);
 1351 
 1352         CTR2(KTR_IGMPV3, "%s: dropping ref on %p", __func__, inm);
 1353 
 1354         return (error);
 1355 }
 1356 
 1357 /*#ifndef BURN_BRIDGES*/
 1358 
 1359 /*
 1360  * Block or unblock an ASM multicast source on an inpcb.
 1361  * This implements the delta-based API described in RFC 3678.
 1362  *
 1363  * The delta-based API applies only to exclusive-mode memberships.
 1364  * An IGMP downcall will be performed.
 1365  *
 1366  * SMPng: NOTE: Must take Giant as a join may create a new ifma.
 1367  *
 1368  * Return 0 if successful, otherwise return an appropriate error code.
 1369  */
 1370 static int
 1371 inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt)
 1372 {
 1373         struct epoch_tracker             et;
 1374         struct group_source_req          gsr;
 1375         sockunion_t                     *gsa, *ssa;
 1376         struct ifnet                    *ifp;
 1377         struct in_mfilter               *imf;
 1378         struct ip_moptions              *imo;
 1379         struct in_msource               *ims;
 1380         struct in_multi                 *inm;
 1381         uint16_t                         fmode;
 1382         int                              error, doblock;
 1383 
 1384         ifp = NULL;
 1385         error = 0;
 1386         doblock = 0;
 1387 
 1388         memset(&gsr, 0, sizeof(struct group_source_req));
 1389         gsa = (sockunion_t *)&gsr.gsr_group;
 1390         ssa = (sockunion_t *)&gsr.gsr_source;
 1391 
 1392         switch (sopt->sopt_name) {
 1393         case IP_BLOCK_SOURCE:
 1394         case IP_UNBLOCK_SOURCE: {
 1395                 struct ip_mreq_source    mreqs;
 1396 
 1397                 error = sooptcopyin(sopt, &mreqs,
 1398                     sizeof(struct ip_mreq_source),
 1399                     sizeof(struct ip_mreq_source));
 1400                 if (error)
 1401                         return (error);
 1402 
 1403                 gsa->sin.sin_family = AF_INET;
 1404                 gsa->sin.sin_len = sizeof(struct sockaddr_in);
 1405                 gsa->sin.sin_addr = mreqs.imr_multiaddr;
 1406 
 1407                 ssa->sin.sin_family = AF_INET;
 1408                 ssa->sin.sin_len = sizeof(struct sockaddr_in);
 1409                 ssa->sin.sin_addr = mreqs.imr_sourceaddr;
 1410 
 1411                 if (!in_nullhost(mreqs.imr_interface)) {
 1412                         NET_EPOCH_ENTER(et);
 1413                         INADDR_TO_IFP(mreqs.imr_interface, ifp);
 1414                         /* XXXGL: ifref? */
 1415                         NET_EPOCH_EXIT(et);
 1416                 }
 1417                 if (sopt->sopt_name == IP_BLOCK_SOURCE)
 1418                         doblock = 1;
 1419 
 1420                 CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p",
 1421                     __func__, ntohl(mreqs.imr_interface.s_addr), ifp);
 1422                 break;
 1423             }
 1424 
 1425         case MCAST_BLOCK_SOURCE:
 1426         case MCAST_UNBLOCK_SOURCE:
 1427                 error = sooptcopyin(sopt, &gsr,
 1428                     sizeof(struct group_source_req),
 1429                     sizeof(struct group_source_req));
 1430                 if (error)
 1431                         return (error);
 1432 
 1433                 if (gsa->sin.sin_family != AF_INET ||
 1434                     gsa->sin.sin_len != sizeof(struct sockaddr_in))
 1435                         return (EINVAL);
 1436 
 1437                 if (ssa->sin.sin_family != AF_INET ||
 1438                     ssa->sin.sin_len != sizeof(struct sockaddr_in))
 1439                         return (EINVAL);
 1440 
 1441                 NET_EPOCH_ENTER(et);
 1442                 ifp = ifnet_byindex(gsr.gsr_interface);
 1443                 NET_EPOCH_EXIT(et);
 1444                 if (ifp == NULL)
 1445                         return (EADDRNOTAVAIL);
 1446 
 1447                 if (sopt->sopt_name == MCAST_BLOCK_SOURCE)
 1448                         doblock = 1;
 1449                 break;
 1450 
 1451         default:
 1452                 CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d",
 1453                     __func__, sopt->sopt_name);
 1454                 return (EOPNOTSUPP);
 1455                 break;
 1456         }
 1457 
 1458         if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
 1459                 return (EINVAL);
 1460 
 1461         IN_MULTI_LOCK();
 1462 
 1463         /*
 1464          * Check if we are actually a member of this group.
 1465          */
 1466         imo = inp_findmoptions(inp);
 1467         imf = imo_match_group(imo, ifp, &gsa->sa);
 1468         if (imf == NULL) {
 1469                 error = EADDRNOTAVAIL;
 1470                 goto out_inp_locked;
 1471         }
 1472         inm = imf->imf_inm;
 1473 
 1474         /*
 1475          * Attempting to use the delta-based API on an
 1476          * non exclusive-mode membership is an error.
 1477          */
 1478         fmode = imf->imf_st[0];
 1479         if (fmode != MCAST_EXCLUDE) {
 1480                 error = EINVAL;
 1481                 goto out_inp_locked;
 1482         }
 1483 
 1484         /*
 1485          * Deal with error cases up-front:
 1486          *  Asked to block, but already blocked; or
 1487          *  Asked to unblock, but nothing to unblock.
 1488          * If adding a new block entry, allocate it.
 1489          */
 1490         ims = imo_match_source(imf, &ssa->sa);
 1491         if ((ims != NULL && doblock) || (ims == NULL && !doblock)) {
 1492                 CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", __func__,
 1493                     ntohl(ssa->sin.sin_addr.s_addr), doblock ? "" : "not ");
 1494                 error = EADDRNOTAVAIL;
 1495                 goto out_inp_locked;
 1496         }
 1497 
 1498         INP_WLOCK_ASSERT(inp);
 1499 
 1500         /*
 1501          * Begin state merge transaction at socket layer.
 1502          */
 1503         if (doblock) {
 1504                 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "block");
 1505                 ims = imf_graft(imf, fmode, &ssa->sin);
 1506                 if (ims == NULL)
 1507                         error = ENOMEM;
 1508         } else {
 1509                 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "allow");
 1510                 error = imf_prune(imf, &ssa->sin);
 1511         }
 1512 
 1513         if (error) {
 1514                 CTR1(KTR_IGMPV3, "%s: merge imf state failed", __func__);
 1515                 goto out_imf_rollback;
 1516         }
 1517 
 1518         /*
 1519          * Begin state merge transaction at IGMP layer.
 1520          */
 1521         CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
 1522         IN_MULTI_LIST_LOCK();
 1523         error = inm_merge(inm, imf);
 1524         if (error) {
 1525                 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__);
 1526                 IN_MULTI_LIST_UNLOCK();
 1527                 goto out_imf_rollback;
 1528         }
 1529 
 1530         CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
 1531         error = igmp_change_state(inm);
 1532         IN_MULTI_LIST_UNLOCK();
 1533         if (error)
 1534                 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__);
 1535 
 1536 out_imf_rollback:
 1537         if (error)
 1538                 imf_rollback(imf);
 1539         else
 1540                 imf_commit(imf);
 1541 
 1542         imf_reap(imf);
 1543 
 1544 out_inp_locked:
 1545         INP_WUNLOCK(inp);
 1546         IN_MULTI_UNLOCK();
 1547         return (error);
 1548 }
 1549 
 1550 /*
 1551  * Given an inpcb, return its multicast options structure pointer.  Accepts
 1552  * an unlocked inpcb pointer, but will return it locked.  May sleep.
 1553  *
 1554  * SMPng: NOTE: Potentially calls malloc(M_WAITOK) with Giant held.
 1555  * SMPng: NOTE: Returns with the INP write lock held.
 1556  */
 1557 static struct ip_moptions *
 1558 inp_findmoptions(struct inpcb *inp)
 1559 {
 1560         struct ip_moptions       *imo;
 1561 
 1562         INP_WLOCK(inp);
 1563         if (inp->inp_moptions != NULL)
 1564                 return (inp->inp_moptions);
 1565 
 1566         INP_WUNLOCK(inp);
 1567 
 1568         imo = malloc(sizeof(*imo), M_IPMOPTS, M_WAITOK);
 1569 
 1570         imo->imo_multicast_ifp = NULL;
 1571         imo->imo_multicast_addr.s_addr = INADDR_ANY;
 1572         imo->imo_multicast_vif = -1;
 1573         imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
 1574         imo->imo_multicast_loop = in_mcast_loop;
 1575         STAILQ_INIT(&imo->imo_head);
 1576 
 1577         INP_WLOCK(inp);
 1578         if (inp->inp_moptions != NULL) {
 1579                 free(imo, M_IPMOPTS);
 1580                 return (inp->inp_moptions);
 1581         }
 1582         inp->inp_moptions = imo;
 1583         return (imo);
 1584 }
 1585 
 1586 void
 1587 inp_freemoptions(struct ip_moptions *imo)
 1588 {
 1589         struct in_mfilter *imf;
 1590         struct in_multi *inm;
 1591         struct ifnet *ifp;
 1592 
 1593         if (imo == NULL)
 1594                 return;
 1595 
 1596         while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) {
 1597                 ip_mfilter_remove(&imo->imo_head, imf);
 1598 
 1599                 imf_leave(imf);
 1600                 if ((inm = imf->imf_inm) != NULL) {
 1601                         if ((ifp = inm->inm_ifp) != NULL) {
 1602                                 CURVNET_SET(ifp->if_vnet);
 1603                                 (void)in_leavegroup(inm, imf);
 1604                                 CURVNET_RESTORE();
 1605                         } else {
 1606                                 (void)in_leavegroup(inm, imf);
 1607                         }
 1608                 }
 1609                 ip_mfilter_free(imf);
 1610         }
 1611         free(imo, M_IPMOPTS);
 1612 }
 1613 
 1614 /*
 1615  * Atomically get source filters on a socket for an IPv4 multicast group.
 1616  * Called with INP lock held; returns with lock released.
 1617  */
 1618 static int
 1619 inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt)
 1620 {
 1621         struct epoch_tracker     et;
 1622         struct __msfilterreq     msfr;
 1623         sockunion_t             *gsa;
 1624         struct ifnet            *ifp;
 1625         struct ip_moptions      *imo;
 1626         struct in_mfilter       *imf;
 1627         struct ip_msource       *ims;
 1628         struct in_msource       *lims;
 1629         struct sockaddr_in      *psin;
 1630         struct sockaddr_storage *ptss;
 1631         struct sockaddr_storage *tss;
 1632         int                      error;
 1633         size_t                   nsrcs, ncsrcs;
 1634 
 1635         INP_WLOCK_ASSERT(inp);
 1636 
 1637         imo = inp->inp_moptions;
 1638         KASSERT(imo != NULL, ("%s: null ip_moptions", __func__));
 1639 
 1640         INP_WUNLOCK(inp);
 1641 
 1642         error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq),
 1643             sizeof(struct __msfilterreq));
 1644         if (error)
 1645                 return (error);
 1646 
 1647         NET_EPOCH_ENTER(et);
 1648         ifp = ifnet_byindex(msfr.msfr_ifindex);
 1649         NET_EPOCH_EXIT(et);     /* XXXGL: unsafe ifnet pointer left */
 1650         if (ifp == NULL)
 1651                 return (EINVAL);
 1652 
 1653         INP_WLOCK(inp);
 1654 
 1655         /*
 1656          * Lookup group on the socket.
 1657          */
 1658         gsa = (sockunion_t *)&msfr.msfr_group;
 1659         imf = imo_match_group(imo, ifp, &gsa->sa);
 1660         if (imf == NULL) {
 1661                 INP_WUNLOCK(inp);
 1662                 return (EADDRNOTAVAIL);
 1663         }
 1664 
 1665         /*
 1666          * Ignore memberships which are in limbo.
 1667          */
 1668         if (imf->imf_st[1] == MCAST_UNDEFINED) {
 1669                 INP_WUNLOCK(inp);
 1670                 return (EAGAIN);
 1671         }
 1672         msfr.msfr_fmode = imf->imf_st[1];
 1673 
 1674         /*
 1675          * If the user specified a buffer, copy out the source filter
 1676          * entries to userland gracefully.
 1677          * We only copy out the number of entries which userland
 1678          * has asked for, but we always tell userland how big the
 1679          * buffer really needs to be.
 1680          */
 1681         if (msfr.msfr_nsrcs > in_mcast_maxsocksrc)
 1682                 msfr.msfr_nsrcs = in_mcast_maxsocksrc;
 1683         tss = NULL;
 1684         if (msfr.msfr_srcs != NULL && msfr.msfr_nsrcs > 0) {
 1685                 tss = malloc(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs,
 1686                     M_TEMP, M_NOWAIT | M_ZERO);
 1687                 if (tss == NULL) {
 1688                         INP_WUNLOCK(inp);
 1689                         return (ENOBUFS);
 1690                 }
 1691         }
 1692 
 1693         /*
 1694          * Count number of sources in-mode at t0.
 1695          * If buffer space exists and remains, copy out source entries.
 1696          */
 1697         nsrcs = msfr.msfr_nsrcs;
 1698         ncsrcs = 0;
 1699         ptss = tss;
 1700         RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) {
 1701                 lims = (struct in_msource *)ims;
 1702                 if (lims->imsl_st[0] == MCAST_UNDEFINED ||
 1703                     lims->imsl_st[0] != imf->imf_st[0])
 1704                         continue;
 1705                 ++ncsrcs;
 1706                 if (tss != NULL && nsrcs > 0) {
 1707                         psin = (struct sockaddr_in *)ptss;
 1708                         psin->sin_family = AF_INET;
 1709                         psin->sin_len = sizeof(struct sockaddr_in);
 1710                         psin->sin_addr.s_addr = htonl(lims->ims_haddr);
 1711                         psin->sin_port = 0;
 1712                         ++ptss;
 1713                         --nsrcs;
 1714                 }
 1715         }
 1716 
 1717         INP_WUNLOCK(inp);
 1718 
 1719         if (tss != NULL) {
 1720                 error = copyout(tss, msfr.msfr_srcs,
 1721                     sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs);
 1722                 free(tss, M_TEMP);
 1723                 if (error)
 1724                         return (error);
 1725         }
 1726 
 1727         msfr.msfr_nsrcs = ncsrcs;
 1728         error = sooptcopyout(sopt, &msfr, sizeof(struct __msfilterreq));
 1729 
 1730         return (error);
 1731 }
 1732 
 1733 /*
 1734  * Return the IP multicast options in response to user getsockopt().
 1735  */
 1736 int
 1737 inp_getmoptions(struct inpcb *inp, struct sockopt *sopt)
 1738 {
 1739         struct ip_mreqn          mreqn;
 1740         struct ip_moptions      *imo;
 1741         struct ifnet            *ifp;
 1742         struct in_ifaddr        *ia;
 1743         int                      error, optval;
 1744         u_char                   coptval;
 1745 
 1746         INP_WLOCK(inp);
 1747         imo = inp->inp_moptions;
 1748         /* If socket is neither of type SOCK_RAW or SOCK_DGRAM reject it. */
 1749         if (inp->inp_socket->so_proto->pr_type != SOCK_RAW &&
 1750             inp->inp_socket->so_proto->pr_type != SOCK_DGRAM) {
 1751                 INP_WUNLOCK(inp);
 1752                 return (EOPNOTSUPP);
 1753         }
 1754 
 1755         error = 0;
 1756         switch (sopt->sopt_name) {
 1757         case IP_MULTICAST_VIF:
 1758                 if (imo != NULL)
 1759                         optval = imo->imo_multicast_vif;
 1760                 else
 1761                         optval = -1;
 1762                 INP_WUNLOCK(inp);
 1763                 error = sooptcopyout(sopt, &optval, sizeof(int));
 1764                 break;
 1765 
 1766         case IP_MULTICAST_IF:
 1767                 memset(&mreqn, 0, sizeof(struct ip_mreqn));
 1768                 if (imo != NULL) {
 1769                         ifp = imo->imo_multicast_ifp;
 1770                         if (!in_nullhost(imo->imo_multicast_addr)) {
 1771                                 mreqn.imr_address = imo->imo_multicast_addr;
 1772                         } else if (ifp != NULL) {
 1773                                 struct epoch_tracker et;
 1774 
 1775                                 mreqn.imr_ifindex = ifp->if_index;
 1776                                 NET_EPOCH_ENTER(et);
 1777                                 IFP_TO_IA(ifp, ia);
 1778                                 if (ia != NULL)
 1779                                         mreqn.imr_address =
 1780                                             IA_SIN(ia)->sin_addr;
 1781                                 NET_EPOCH_EXIT(et);
 1782                         }
 1783                 }
 1784                 INP_WUNLOCK(inp);
 1785                 if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) {
 1786                         error = sooptcopyout(sopt, &mreqn,
 1787                             sizeof(struct ip_mreqn));
 1788                 } else {
 1789                         error = sooptcopyout(sopt, &mreqn.imr_address,
 1790                             sizeof(struct in_addr));
 1791                 }
 1792                 break;
 1793 
 1794         case IP_MULTICAST_TTL:
 1795                 if (imo == NULL)
 1796                         optval = coptval = IP_DEFAULT_MULTICAST_TTL;
 1797                 else
 1798                         optval = coptval = imo->imo_multicast_ttl;
 1799                 INP_WUNLOCK(inp);
 1800                 if (sopt->sopt_valsize == sizeof(u_char))
 1801                         error = sooptcopyout(sopt, &coptval, sizeof(u_char));
 1802                 else
 1803                         error = sooptcopyout(sopt, &optval, sizeof(int));
 1804                 break;
 1805 
 1806         case IP_MULTICAST_LOOP:
 1807                 if (imo == NULL)
 1808                         optval = coptval = IP_DEFAULT_MULTICAST_LOOP;
 1809                 else
 1810                         optval = coptval = imo->imo_multicast_loop;
 1811                 INP_WUNLOCK(inp);
 1812                 if (sopt->sopt_valsize == sizeof(u_char))
 1813                         error = sooptcopyout(sopt, &coptval, sizeof(u_char));
 1814                 else
 1815                         error = sooptcopyout(sopt, &optval, sizeof(int));
 1816                 break;
 1817 
 1818         case IP_MSFILTER:
 1819                 if (imo == NULL) {
 1820                         error = EADDRNOTAVAIL;
 1821                         INP_WUNLOCK(inp);
 1822                 } else {
 1823                         error = inp_get_source_filters(inp, sopt);
 1824                 }
 1825                 break;
 1826 
 1827         default:
 1828                 INP_WUNLOCK(inp);
 1829                 error = ENOPROTOOPT;
 1830                 break;
 1831         }
 1832 
 1833         INP_UNLOCK_ASSERT(inp);
 1834 
 1835         return (error);
 1836 }
 1837 
 1838 /*
 1839  * Look up the ifnet to use for a multicast group membership,
 1840  * given the IPv4 address of an interface, and the IPv4 group address.
 1841  *
 1842  * This routine exists to support legacy multicast applications
 1843  * which do not understand that multicast memberships are scoped to
 1844  * specific physical links in the networking stack, or which need
 1845  * to join link-scope groups before IPv4 addresses are configured.
 1846  *
 1847  * Use this socket's current FIB number for any required FIB lookup.
 1848  * If ina is INADDR_ANY, look up the group address in the unicast FIB,
 1849  * and use its ifp; usually, this points to the default next-hop.
 1850  *
 1851  * If the FIB lookup fails, attempt to use the first non-loopback
 1852  * interface with multicast capability in the system as a
 1853  * last resort. The legacy IPv4 ASM API requires that we do
 1854  * this in order to allow groups to be joined when the routing
 1855  * table has not yet been populated during boot.
 1856  *
 1857  * Returns NULL if no ifp could be found, otherwise return referenced ifp.
 1858  *
 1859  * FUTURE: Implement IPv4 source-address selection.
 1860  */
 1861 static struct ifnet *
 1862 inp_lookup_mcast_ifp(const struct inpcb *inp,
 1863     const struct sockaddr_in *gsin, const struct in_addr ina)
 1864 {
 1865         struct ifnet *ifp;
 1866         struct nhop_object *nh;
 1867 
 1868         NET_EPOCH_ASSERT();
 1869         KASSERT(inp != NULL, ("%s: inp must not be NULL", __func__));
 1870         KASSERT(gsin->sin_family == AF_INET, ("%s: not AF_INET", __func__));
 1871         KASSERT(IN_MULTICAST(ntohl(gsin->sin_addr.s_addr)),
 1872             ("%s: not multicast", __func__));
 1873 
 1874         ifp = NULL;
 1875         if (!in_nullhost(ina)) {
 1876                 INADDR_TO_IFP(ina, ifp);
 1877                 if (ifp != NULL)
 1878                         if_ref(ifp);
 1879         } else {
 1880                 nh = fib4_lookup(inp->inp_inc.inc_fibnum, gsin->sin_addr, 0, NHR_NONE, 0);
 1881                 if (nh != NULL) {
 1882                         ifp = nh->nh_ifp;
 1883                         if_ref(ifp);
 1884                 } else {
 1885                         struct in_ifaddr *ia;
 1886                         struct ifnet *mifp;
 1887 
 1888                         mifp = NULL;
 1889                         CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
 1890                                 mifp = ia->ia_ifp;
 1891                                 if (!(mifp->if_flags & IFF_LOOPBACK) &&
 1892                                      (mifp->if_flags & IFF_MULTICAST)) {
 1893                                         ifp = mifp;
 1894                                         if_ref(ifp);
 1895                                         break;
 1896                                 }
 1897                         }
 1898                 }
 1899         }
 1900 
 1901         return (ifp);
 1902 }
 1903 
 1904 /*
 1905  * Join an IPv4 multicast group, possibly with a source.
 1906  */
 1907 static int
 1908 inp_join_group(struct inpcb *inp, struct sockopt *sopt)
 1909 {
 1910         struct group_source_req          gsr;
 1911         sockunion_t                     *gsa, *ssa;
 1912         struct ifnet                    *ifp;
 1913         struct in_mfilter               *imf;
 1914         struct ip_moptions              *imo;
 1915         struct in_multi                 *inm;
 1916         struct in_msource               *lims;
 1917         struct epoch_tracker             et;
 1918         int                              error, is_new;
 1919 
 1920         ifp = NULL;
 1921         lims = NULL;
 1922         error = 0;
 1923 
 1924         memset(&gsr, 0, sizeof(struct group_source_req));
 1925         gsa = (sockunion_t *)&gsr.gsr_group;
 1926         gsa->ss.ss_family = AF_UNSPEC;
 1927         ssa = (sockunion_t *)&gsr.gsr_source;
 1928         ssa->ss.ss_family = AF_UNSPEC;
 1929 
 1930         switch (sopt->sopt_name) {
 1931         case IP_ADD_MEMBERSHIP: {
 1932                 struct ip_mreqn mreqn;
 1933 
 1934                 if (sopt->sopt_valsize == sizeof(struct ip_mreqn))
 1935                         error = sooptcopyin(sopt, &mreqn,
 1936                             sizeof(struct ip_mreqn), sizeof(struct ip_mreqn));
 1937                 else
 1938                         error = sooptcopyin(sopt, &mreqn,
 1939                             sizeof(struct ip_mreq), sizeof(struct ip_mreq));
 1940                 if (error)
 1941                         return (error);
 1942 
 1943                 gsa->sin.sin_family = AF_INET;
 1944                 gsa->sin.sin_len = sizeof(struct sockaddr_in);
 1945                 gsa->sin.sin_addr = mreqn.imr_multiaddr;
 1946                 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
 1947                         return (EINVAL);
 1948 
 1949                 NET_EPOCH_ENTER(et);
 1950                 if (sopt->sopt_valsize == sizeof(struct ip_mreqn) &&
 1951                     mreqn.imr_ifindex != 0)
 1952                         ifp = ifnet_byindex_ref(mreqn.imr_ifindex);
 1953                 else
 1954                         ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
 1955                             mreqn.imr_address);
 1956                 NET_EPOCH_EXIT(et);
 1957                 break;
 1958         }
 1959         case IP_ADD_SOURCE_MEMBERSHIP: {
 1960                 struct ip_mreq_source    mreqs;
 1961 
 1962                 error = sooptcopyin(sopt, &mreqs, sizeof(struct ip_mreq_source),
 1963                             sizeof(struct ip_mreq_source));
 1964                 if (error)
 1965                         return (error);
 1966 
 1967                 gsa->sin.sin_family = ssa->sin.sin_family = AF_INET;
 1968                 gsa->sin.sin_len = ssa->sin.sin_len =
 1969                     sizeof(struct sockaddr_in);
 1970 
 1971                 gsa->sin.sin_addr = mreqs.imr_multiaddr;
 1972                 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
 1973                         return (EINVAL);
 1974 
 1975                 ssa->sin.sin_addr = mreqs.imr_sourceaddr;
 1976 
 1977                 NET_EPOCH_ENTER(et);
 1978                 ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
 1979                     mreqs.imr_interface);
 1980                 NET_EPOCH_EXIT(et);
 1981                 CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p",
 1982                     __func__, ntohl(mreqs.imr_interface.s_addr), ifp);
 1983                 break;
 1984         }
 1985 
 1986         case MCAST_JOIN_GROUP:
 1987         case MCAST_JOIN_SOURCE_GROUP:
 1988                 if (sopt->sopt_name == MCAST_JOIN_GROUP) {
 1989                         error = sooptcopyin(sopt, &gsr,
 1990                             sizeof(struct group_req),
 1991                             sizeof(struct group_req));
 1992                 } else if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) {
 1993                         error = sooptcopyin(sopt, &gsr,
 1994                             sizeof(struct group_source_req),
 1995                             sizeof(struct group_source_req));
 1996                 }
 1997                 if (error)
 1998                         return (error);
 1999 
 2000                 if (gsa->sin.sin_family != AF_INET ||
 2001                     gsa->sin.sin_len != sizeof(struct sockaddr_in))
 2002                         return (EINVAL);
 2003 
 2004                 /*
 2005                  * Overwrite the port field if present, as the sockaddr
 2006                  * being copied in may be matched with a binary comparison.
 2007                  */
 2008                 gsa->sin.sin_port = 0;
 2009                 if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) {
 2010                         if (ssa->sin.sin_family != AF_INET ||
 2011                             ssa->sin.sin_len != sizeof(struct sockaddr_in))
 2012                                 return (EINVAL);
 2013                         ssa->sin.sin_port = 0;
 2014                 }
 2015 
 2016                 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
 2017                         return (EINVAL);
 2018 
 2019                 NET_EPOCH_ENTER(et);
 2020                 ifp = ifnet_byindex_ref(gsr.gsr_interface);
 2021                 NET_EPOCH_EXIT(et);
 2022                 if (ifp == NULL)
 2023                         return (EADDRNOTAVAIL);
 2024                 break;
 2025 
 2026         default:
 2027                 CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d",
 2028                     __func__, sopt->sopt_name);
 2029                 return (EOPNOTSUPP);
 2030                 break;
 2031         }
 2032 
 2033         if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
 2034                 if (ifp != NULL)
 2035                         if_rele(ifp);
 2036                 return (EADDRNOTAVAIL);
 2037         }
 2038 
 2039         IN_MULTI_LOCK();
 2040 
 2041         /*
 2042          * Find the membership in the membership list.
 2043          */
 2044         imo = inp_findmoptions(inp);
 2045         imf = imo_match_group(imo, ifp, &gsa->sa);
 2046         if (imf == NULL) {
 2047                 is_new = 1;
 2048                 inm = NULL;
 2049 
 2050                 if (ip_mfilter_count(&imo->imo_head) >= IP_MAX_MEMBERSHIPS) {
 2051                         error = ENOMEM;
 2052                         goto out_inp_locked;
 2053                 }
 2054         } else {
 2055                 is_new = 0;
 2056                 inm = imf->imf_inm;
 2057 
 2058                 if (ssa->ss.ss_family != AF_UNSPEC) {
 2059                         /*
 2060                          * MCAST_JOIN_SOURCE_GROUP on an exclusive membership
 2061                          * is an error. On an existing inclusive membership,
 2062                          * it just adds the source to the filter list.
 2063                          */
 2064                         if (imf->imf_st[1] != MCAST_INCLUDE) {
 2065                                 error = EINVAL;
 2066                                 goto out_inp_locked;
 2067                         }
 2068                         /*
 2069                          * Throw out duplicates.
 2070                          *
 2071                          * XXX FIXME: This makes a naive assumption that
 2072                          * even if entries exist for *ssa in this imf,
 2073                          * they will be rejected as dupes, even if they
 2074                          * are not valid in the current mode (in-mode).
 2075                          *
 2076                          * in_msource is transactioned just as for anything
 2077                          * else in SSM -- but note naive use of inm_graft()
 2078                          * below for allocating new filter entries.
 2079                          *
 2080                          * This is only an issue if someone mixes the
 2081                          * full-state SSM API with the delta-based API,
 2082                          * which is discouraged in the relevant RFCs.
 2083                          */
 2084                         lims = imo_match_source(imf, &ssa->sa);
 2085                         if (lims != NULL /*&&
 2086                             lims->imsl_st[1] == MCAST_INCLUDE*/) {
 2087                                 error = EADDRNOTAVAIL;
 2088                                 goto out_inp_locked;
 2089                         }
 2090                 } else {
 2091                         /*
 2092                          * MCAST_JOIN_GROUP on an existing exclusive
 2093                          * membership is an error; return EADDRINUSE
 2094                          * to preserve 4.4BSD API idempotence, and
 2095                          * avoid tedious detour to code below.
 2096                          * NOTE: This is bending RFC 3678 a bit.
 2097                          *
 2098                          * On an existing inclusive membership, this is also
 2099                          * an error; if you want to change filter mode,
 2100                          * you must use the userland API setsourcefilter().
 2101                          * XXX We don't reject this for imf in UNDEFINED
 2102                          * state at t1, because allocation of a filter
 2103                          * is atomic with allocation of a membership.
 2104                          */
 2105                         error = EINVAL;
 2106                         if (imf->imf_st[1] == MCAST_EXCLUDE)
 2107                                 error = EADDRINUSE;
 2108                         goto out_inp_locked;
 2109                 }
 2110         }
 2111 
 2112         /*
 2113          * Begin state merge transaction at socket layer.
 2114          */
 2115         INP_WLOCK_ASSERT(inp);
 2116 
 2117         /*
 2118          * Graft new source into filter list for this inpcb's
 2119          * membership of the group. The in_multi may not have
 2120          * been allocated yet if this is a new membership, however,
 2121          * the in_mfilter slot will be allocated and must be initialized.
 2122          *
 2123          * Note: Grafting of exclusive mode filters doesn't happen
 2124          * in this path.
 2125          * XXX: Should check for non-NULL lims (node exists but may
 2126          * not be in-mode) for interop with full-state API.
 2127          */
 2128         if (ssa->ss.ss_family != AF_UNSPEC) {
 2129                 /* Membership starts in IN mode */
 2130                 if (is_new) {
 2131                         CTR1(KTR_IGMPV3, "%s: new join w/source", __func__);
 2132                         imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_INCLUDE);
 2133                         if (imf == NULL) {
 2134                                 error = ENOMEM;
 2135                                 goto out_inp_locked;
 2136                         }
 2137                 } else {
 2138                         CTR2(KTR_IGMPV3, "%s: %s source", __func__, "allow");
 2139                 }
 2140                 lims = imf_graft(imf, MCAST_INCLUDE, &ssa->sin);
 2141                 if (lims == NULL) {
 2142                         CTR1(KTR_IGMPV3, "%s: merge imf state failed",
 2143                             __func__);
 2144                         error = ENOMEM;
 2145                         goto out_inp_locked;
 2146                 }
 2147         } else {
 2148                 /* No address specified; Membership starts in EX mode */
 2149                 if (is_new) {
 2150                         CTR1(KTR_IGMPV3, "%s: new join w/o source", __func__);
 2151                         imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_EXCLUDE);
 2152                         if (imf == NULL) {
 2153                                 error = ENOMEM;
 2154                                 goto out_inp_locked;
 2155                         }
 2156                 }
 2157         }
 2158 
 2159         /*
 2160          * Begin state merge transaction at IGMP layer.
 2161          */
 2162         if (is_new) {
 2163                 in_pcbref(inp);
 2164                 INP_WUNLOCK(inp);
 2165 
 2166                 error = in_joingroup_locked(ifp, &gsa->sin.sin_addr, imf,
 2167                     &imf->imf_inm);
 2168 
 2169                 INP_WLOCK(inp);
 2170                 if (in_pcbrele_wlocked(inp)) {
 2171                         error = ENXIO;
 2172                         goto out_inp_unlocked;
 2173                 }
 2174                 if (error) {
 2175                         CTR1(KTR_IGMPV3, "%s: in_joingroup_locked failed",
 2176                             __func__);
 2177                         goto out_inp_locked;
 2178                 }
 2179                 /*
 2180                  * NOTE: Refcount from in_joingroup_locked()
 2181                  * is protecting membership.
 2182                  */
 2183                 ip_mfilter_insert(&imo->imo_head, imf);
 2184         } else {
 2185                 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
 2186                 IN_MULTI_LIST_LOCK();
 2187                 error = inm_merge(inm, imf);
 2188                 if (error) {
 2189                         CTR1(KTR_IGMPV3, "%s: failed to merge inm state",
 2190                                  __func__);
 2191                         IN_MULTI_LIST_UNLOCK();
 2192                         imf_rollback(imf);
 2193                         imf_reap(imf);
 2194                         goto out_inp_locked;
 2195                 }
 2196                 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
 2197                 error = igmp_change_state(inm);
 2198                 IN_MULTI_LIST_UNLOCK();
 2199                 if (error) {
 2200                         CTR1(KTR_IGMPV3, "%s: failed igmp downcall",
 2201                             __func__);
 2202                         imf_rollback(imf);
 2203                         imf_reap(imf);
 2204                         goto out_inp_locked;
 2205                 }
 2206         }
 2207 
 2208         imf_commit(imf);
 2209         imf = NULL;
 2210 
 2211 out_inp_locked:
 2212         INP_WUNLOCK(inp);
 2213 out_inp_unlocked:
 2214         IN_MULTI_UNLOCK();
 2215 
 2216         if (is_new && imf) {
 2217                 if (imf->imf_inm != NULL) {
 2218                         IN_MULTI_LIST_LOCK();
 2219                         IF_ADDR_WLOCK(ifp);
 2220                         inm_release_deferred(imf->imf_inm);
 2221                         IF_ADDR_WUNLOCK(ifp);
 2222                         IN_MULTI_LIST_UNLOCK();
 2223                 }
 2224                 ip_mfilter_free(imf);
 2225         }
 2226         if_rele(ifp);
 2227         return (error);
 2228 }
 2229 
 2230 /*
 2231  * Leave an IPv4 multicast group on an inpcb, possibly with a source.
 2232  */
 2233 static int
 2234 inp_leave_group(struct inpcb *inp, struct sockopt *sopt)
 2235 {
 2236         struct epoch_tracker             et;
 2237         struct group_source_req          gsr;
 2238         struct ip_mreq_source            mreqs;
 2239         sockunion_t                     *gsa, *ssa;
 2240         struct ifnet                    *ifp;
 2241         struct in_mfilter               *imf;
 2242         struct ip_moptions              *imo;
 2243         struct in_msource               *ims;
 2244         struct in_multi                 *inm;
 2245         int                              error;
 2246         bool                             is_final;
 2247 
 2248         ifp = NULL;
 2249         error = 0;
 2250         is_final = true;
 2251 
 2252         memset(&gsr, 0, sizeof(struct group_source_req));
 2253         gsa = (sockunion_t *)&gsr.gsr_group;
 2254         gsa->ss.ss_family = AF_UNSPEC;
 2255         ssa = (sockunion_t *)&gsr.gsr_source;
 2256         ssa->ss.ss_family = AF_UNSPEC;
 2257 
 2258         switch (sopt->sopt_name) {
 2259         case IP_DROP_MEMBERSHIP:
 2260         case IP_DROP_SOURCE_MEMBERSHIP:
 2261                 if (sopt->sopt_name == IP_DROP_MEMBERSHIP) {
 2262                         error = sooptcopyin(sopt, &mreqs,
 2263                             sizeof(struct ip_mreq),
 2264                             sizeof(struct ip_mreq));
 2265                         /*
 2266                          * Swap interface and sourceaddr arguments,
 2267                          * as ip_mreq and ip_mreq_source are laid
 2268                          * out differently.
 2269                          */
 2270                         mreqs.imr_interface = mreqs.imr_sourceaddr;
 2271                         mreqs.imr_sourceaddr.s_addr = INADDR_ANY;
 2272                 } else if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) {
 2273                         error = sooptcopyin(sopt, &mreqs,
 2274                             sizeof(struct ip_mreq_source),
 2275                             sizeof(struct ip_mreq_source));
 2276                 }
 2277                 if (error)
 2278                         return (error);
 2279 
 2280                 gsa->sin.sin_family = AF_INET;
 2281                 gsa->sin.sin_len = sizeof(struct sockaddr_in);
 2282                 gsa->sin.sin_addr = mreqs.imr_multiaddr;
 2283 
 2284                 if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) {
 2285                         ssa->sin.sin_family = AF_INET;
 2286                         ssa->sin.sin_len = sizeof(struct sockaddr_in);
 2287                         ssa->sin.sin_addr = mreqs.imr_sourceaddr;
 2288                 }
 2289 
 2290                 /*
 2291                  * Attempt to look up hinted ifp from interface address.
 2292                  * Fallthrough with null ifp iff lookup fails, to
 2293                  * preserve 4.4BSD mcast API idempotence.
 2294                  * XXX NOTE WELL: The RFC 3678 API is preferred because
 2295                  * using an IPv4 address as a key is racy.
 2296                  */
 2297                 if (!in_nullhost(mreqs.imr_interface)) {
 2298                         NET_EPOCH_ENTER(et);
 2299                         INADDR_TO_IFP(mreqs.imr_interface, ifp);
 2300                         /* XXXGL ifref? */
 2301                         NET_EPOCH_EXIT(et);
 2302                 }
 2303                 CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p",
 2304                     __func__, ntohl(mreqs.imr_interface.s_addr), ifp);
 2305 
 2306                 break;
 2307 
 2308         case MCAST_LEAVE_GROUP:
 2309         case MCAST_LEAVE_SOURCE_GROUP:
 2310                 if (sopt->sopt_name == MCAST_LEAVE_GROUP) {
 2311                         error = sooptcopyin(sopt, &gsr,
 2312                             sizeof(struct group_req),
 2313                             sizeof(struct group_req));
 2314                 } else if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) {
 2315                         error = sooptcopyin(sopt, &gsr,
 2316                             sizeof(struct group_source_req),
 2317                             sizeof(struct group_source_req));
 2318                 }
 2319                 if (error)
 2320                         return (error);
 2321 
 2322                 if (gsa->sin.sin_family != AF_INET ||
 2323                     gsa->sin.sin_len != sizeof(struct sockaddr_in))
 2324                         return (EINVAL);
 2325 
 2326                 if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) {
 2327                         if (ssa->sin.sin_family != AF_INET ||
 2328                             ssa->sin.sin_len != sizeof(struct sockaddr_in))
 2329                                 return (EINVAL);
 2330                 }
 2331 
 2332                 NET_EPOCH_ENTER(et);
 2333                 ifp = ifnet_byindex(gsr.gsr_interface);
 2334                 NET_EPOCH_EXIT(et);     /* XXXGL: unsafe ifp */
 2335                 if (ifp == NULL)
 2336                         return (EADDRNOTAVAIL);
 2337                 break;
 2338 
 2339         default:
 2340                 CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d",
 2341                     __func__, sopt->sopt_name);
 2342                 return (EOPNOTSUPP);
 2343                 break;
 2344         }
 2345 
 2346         if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
 2347                 return (EINVAL);
 2348 
 2349         IN_MULTI_LOCK();
 2350 
 2351         /*
 2352          * Find the membership in the membership list.
 2353          */
 2354         imo = inp_findmoptions(inp);
 2355         imf = imo_match_group(imo, ifp, &gsa->sa);
 2356         if (imf == NULL) {
 2357                 error = EADDRNOTAVAIL;
 2358                 goto out_inp_locked;
 2359         }
 2360         inm = imf->imf_inm;
 2361 
 2362         if (ssa->ss.ss_family != AF_UNSPEC)
 2363                 is_final = false;
 2364 
 2365         /*
 2366          * Begin state merge transaction at socket layer.
 2367          */
 2368         INP_WLOCK_ASSERT(inp);
 2369 
 2370         /*
 2371          * If we were instructed only to leave a given source, do so.
 2372          * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships.
 2373          */
 2374         if (is_final) {
 2375                 ip_mfilter_remove(&imo->imo_head, imf);
 2376                 imf_leave(imf);
 2377 
 2378                 /*
 2379                  * Give up the multicast address record to which
 2380                  * the membership points.
 2381                  */
 2382                 (void) in_leavegroup_locked(imf->imf_inm, imf);
 2383         } else {
 2384                 if (imf->imf_st[0] == MCAST_EXCLUDE) {
 2385                         error = EADDRNOTAVAIL;
 2386                         goto out_inp_locked;
 2387                 }
 2388                 ims = imo_match_source(imf, &ssa->sa);
 2389                 if (ims == NULL) {
 2390                         CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent",
 2391                             __func__, ntohl(ssa->sin.sin_addr.s_addr), "not ");
 2392                         error = EADDRNOTAVAIL;
 2393                         goto out_inp_locked;
 2394                 }
 2395                 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "block");
 2396                 error = imf_prune(imf, &ssa->sin);
 2397                 if (error) {
 2398                         CTR1(KTR_IGMPV3, "%s: merge imf state failed",
 2399                             __func__);
 2400                         goto out_inp_locked;
 2401                 }
 2402         }
 2403 
 2404         /*
 2405          * Begin state merge transaction at IGMP layer.
 2406          */
 2407         if (!is_final) {
 2408                 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
 2409                 IN_MULTI_LIST_LOCK();
 2410                 error = inm_merge(inm, imf);
 2411                 if (error) {
 2412                         CTR1(KTR_IGMPV3, "%s: failed to merge inm state",
 2413                             __func__);
 2414                         IN_MULTI_LIST_UNLOCK();
 2415                         imf_rollback(imf);
 2416                         imf_reap(imf);
 2417                         goto out_inp_locked;
 2418                 }
 2419 
 2420                 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
 2421                 error = igmp_change_state(inm);
 2422                 IN_MULTI_LIST_UNLOCK();
 2423                 if (error) {
 2424                         CTR1(KTR_IGMPV3, "%s: failed igmp downcall",
 2425                             __func__);
 2426                         imf_rollback(imf);
 2427                         imf_reap(imf);
 2428                         goto out_inp_locked;
 2429                 }
 2430         }
 2431         imf_commit(imf);
 2432         imf_reap(imf);
 2433 
 2434 out_inp_locked:
 2435         INP_WUNLOCK(inp);
 2436 
 2437         if (is_final && imf)
 2438                 ip_mfilter_free(imf);
 2439 
 2440         IN_MULTI_UNLOCK();
 2441         return (error);
 2442 }
 2443 
 2444 /*
 2445  * Select the interface for transmitting IPv4 multicast datagrams.
 2446  *
 2447  * Either an instance of struct in_addr or an instance of struct ip_mreqn
 2448  * may be passed to this socket option. An address of INADDR_ANY or an
 2449  * interface index of 0 is used to remove a previous selection.
 2450  * When no interface is selected, one is chosen for every send.
 2451  */
 2452 static int
 2453 inp_set_multicast_if(struct inpcb *inp, struct sockopt *sopt)
 2454 {
 2455         struct in_addr           addr;
 2456         struct ip_mreqn          mreqn;
 2457         struct ifnet            *ifp;
 2458         struct ip_moptions      *imo;
 2459         int                      error;
 2460 
 2461         if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) {
 2462                 /*
 2463                  * An interface index was specified using the
 2464                  * Linux-derived ip_mreqn structure.
 2465                  */
 2466                 error = sooptcopyin(sopt, &mreqn, sizeof(struct ip_mreqn),
 2467                     sizeof(struct ip_mreqn));
 2468                 if (error)
 2469                         return (error);
 2470 
 2471                 if (mreqn.imr_ifindex < 0)
 2472                         return (EINVAL);
 2473 
 2474                 if (mreqn.imr_ifindex == 0) {
 2475                         ifp = NULL;
 2476                 } else {
 2477                         struct epoch_tracker et;
 2478 
 2479                         NET_EPOCH_ENTER(et);
 2480                         ifp = ifnet_byindex(mreqn.imr_ifindex);
 2481                         NET_EPOCH_EXIT(et);     /* XXXGL: unsafe ifp */
 2482                         if (ifp == NULL)
 2483                                 return (EADDRNOTAVAIL);
 2484                 }
 2485         } else {
 2486                 /*
 2487                  * An interface was specified by IPv4 address.
 2488                  * This is the traditional BSD usage.
 2489                  */
 2490                 error = sooptcopyin(sopt, &addr, sizeof(struct in_addr),
 2491                     sizeof(struct in_addr));
 2492                 if (error)
 2493                         return (error);
 2494                 if (in_nullhost(addr)) {
 2495                         ifp = NULL;
 2496                 } else {
 2497                         struct epoch_tracker et;
 2498 
 2499                         NET_EPOCH_ENTER(et);
 2500                         INADDR_TO_IFP(addr, ifp);
 2501                         /* XXXGL ifref? */
 2502                         NET_EPOCH_EXIT(et);
 2503                         if (ifp == NULL)
 2504                                 return (EADDRNOTAVAIL);
 2505                 }
 2506                 CTR3(KTR_IGMPV3, "%s: ifp = %p, addr = 0x%08x", __func__, ifp,
 2507                     ntohl(addr.s_addr));
 2508         }
 2509 
 2510         /* Reject interfaces which do not support multicast. */
 2511         if (ifp != NULL && (ifp->if_flags & IFF_MULTICAST) == 0)
 2512                 return (EOPNOTSUPP);
 2513 
 2514         imo = inp_findmoptions(inp);
 2515         imo->imo_multicast_ifp = ifp;
 2516         imo->imo_multicast_addr.s_addr = INADDR_ANY;
 2517         INP_WUNLOCK(inp);
 2518 
 2519         return (0);
 2520 }
 2521 
 2522 /*
 2523  * Atomically set source filters on a socket for an IPv4 multicast group.
 2524  *
 2525  * SMPng: NOTE: Potentially calls malloc(M_WAITOK) with Giant held.
 2526  */
 2527 static int
 2528 inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt)
 2529 {
 2530         struct epoch_tracker     et;
 2531         struct __msfilterreq     msfr;
 2532         sockunion_t             *gsa;
 2533         struct ifnet            *ifp;
 2534         struct in_mfilter       *imf;
 2535         struct ip_moptions      *imo;
 2536         struct in_multi         *inm;
 2537         int                      error;
 2538 
 2539         error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq),
 2540             sizeof(struct __msfilterreq));
 2541         if (error)
 2542                 return (error);
 2543 
 2544         if (msfr.msfr_nsrcs > in_mcast_maxsocksrc)
 2545                 return (ENOBUFS);
 2546 
 2547         if ((msfr.msfr_fmode != MCAST_EXCLUDE &&
 2548              msfr.msfr_fmode != MCAST_INCLUDE))
 2549                 return (EINVAL);
 2550 
 2551         if (msfr.msfr_group.ss_family != AF_INET ||
 2552             msfr.msfr_group.ss_len != sizeof(struct sockaddr_in))
 2553                 return (EINVAL);
 2554 
 2555         gsa = (sockunion_t *)&msfr.msfr_group;
 2556         if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
 2557                 return (EINVAL);
 2558 
 2559         gsa->sin.sin_port = 0;  /* ignore port */
 2560 
 2561         NET_EPOCH_ENTER(et);
 2562         ifp = ifnet_byindex(msfr.msfr_ifindex);
 2563         NET_EPOCH_EXIT(et);     /* XXXGL: unsafe ifp */
 2564         if (ifp == NULL)
 2565                 return (EADDRNOTAVAIL);
 2566 
 2567         IN_MULTI_LOCK();
 2568 
 2569         /*
 2570          * Take the INP write lock.
 2571          * Check if this socket is a member of this group.
 2572          */
 2573         imo = inp_findmoptions(inp);
 2574         imf = imo_match_group(imo, ifp, &gsa->sa);
 2575         if (imf == NULL) {
 2576                 error = EADDRNOTAVAIL;
 2577                 goto out_inp_locked;
 2578         }
 2579         inm = imf->imf_inm;
 2580 
 2581         /*
 2582          * Begin state merge transaction at socket layer.
 2583          */
 2584         INP_WLOCK_ASSERT(inp);
 2585 
 2586         imf->imf_st[1] = msfr.msfr_fmode;
 2587 
 2588         /*
 2589          * Apply any new source filters, if present.
 2590          * Make a copy of the user-space source vector so
 2591          * that we may copy them with a single copyin. This
 2592          * allows us to deal with page faults up-front.
 2593          */
 2594         if (msfr.msfr_nsrcs > 0) {
 2595                 struct in_msource       *lims;
 2596                 struct sockaddr_in      *psin;
 2597                 struct sockaddr_storage *kss, *pkss;
 2598                 int                      i;
 2599 
 2600                 INP_WUNLOCK(inp);
 2601 
 2602                 CTR2(KTR_IGMPV3, "%s: loading %lu source list entries",
 2603                     __func__, (unsigned long)msfr.msfr_nsrcs);
 2604                 kss = malloc(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs,
 2605                     M_TEMP, M_WAITOK);
 2606                 error = copyin(msfr.msfr_srcs, kss,
 2607                     sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs);
 2608                 if (error) {
 2609                         free(kss, M_TEMP);
 2610                         return (error);
 2611                 }
 2612 
 2613                 INP_WLOCK(inp);
 2614 
 2615                 /*
 2616                  * Mark all source filters as UNDEFINED at t1.
 2617                  * Restore new group filter mode, as imf_leave()
 2618                  * will set it to INCLUDE.
 2619                  */
 2620                 imf_leave(imf);
 2621                 imf->imf_st[1] = msfr.msfr_fmode;
 2622 
 2623                 /*
 2624                  * Update socket layer filters at t1, lazy-allocating
 2625                  * new entries. This saves a bunch of memory at the
 2626                  * cost of one RB_FIND() per source entry; duplicate
 2627                  * entries in the msfr_nsrcs vector are ignored.
 2628                  * If we encounter an error, rollback transaction.
 2629                  *
 2630                  * XXX This too could be replaced with a set-symmetric
 2631                  * difference like loop to avoid walking from root
 2632                  * every time, as the key space is common.
 2633                  */
 2634                 for (i = 0, pkss = kss; i < msfr.msfr_nsrcs; i++, pkss++) {
 2635                         psin = (struct sockaddr_in *)pkss;
 2636                         if (psin->sin_family != AF_INET) {
 2637                                 error = EAFNOSUPPORT;
 2638                                 break;
 2639                         }
 2640                         if (psin->sin_len != sizeof(struct sockaddr_in)) {
 2641                                 error = EINVAL;
 2642                                 break;
 2643                         }
 2644                         error = imf_get_source(imf, psin, &lims);
 2645                         if (error)
 2646                                 break;
 2647                         lims->imsl_st[1] = imf->imf_st[1];
 2648                 }
 2649                 free(kss, M_TEMP);
 2650         }
 2651 
 2652         if (error)
 2653                 goto out_imf_rollback;
 2654 
 2655         INP_WLOCK_ASSERT(inp);
 2656 
 2657         /*
 2658          * Begin state merge transaction at IGMP layer.
 2659          */
 2660         CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
 2661         IN_MULTI_LIST_LOCK();
 2662         error = inm_merge(inm, imf);
 2663         if (error) {
 2664                 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__);
 2665                 IN_MULTI_LIST_UNLOCK();
 2666                 goto out_imf_rollback;
 2667         }
 2668 
 2669         CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
 2670         error = igmp_change_state(inm);
 2671         IN_MULTI_LIST_UNLOCK();
 2672         if (error)
 2673                 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__);
 2674 
 2675 out_imf_rollback:
 2676         if (error)
 2677                 imf_rollback(imf);
 2678         else
 2679                 imf_commit(imf);
 2680 
 2681         imf_reap(imf);
 2682 
 2683 out_inp_locked:
 2684         INP_WUNLOCK(inp);
 2685         IN_MULTI_UNLOCK();
 2686         return (error);
 2687 }
 2688 
 2689 /*
 2690  * Set the IP multicast options in response to user setsockopt().
 2691  *
 2692  * Many of the socket options handled in this function duplicate the
 2693  * functionality of socket options in the regular unicast API. However,
 2694  * it is not possible to merge the duplicate code, because the idempotence
 2695  * of the IPv4 multicast part of the BSD Sockets API must be preserved;
 2696  * the effects of these options must be treated as separate and distinct.
 2697  *
 2698  * SMPng: XXX: Unlocked read of inp_socket believed OK.
 2699  * FUTURE: The IP_MULTICAST_VIF option may be eliminated if MROUTING
 2700  * is refactored to no longer use vifs.
 2701  */
 2702 int
 2703 inp_setmoptions(struct inpcb *inp, struct sockopt *sopt)
 2704 {
 2705         struct ip_moptions      *imo;
 2706         int                      error;
 2707 
 2708         error = 0;
 2709 
 2710         /* If socket is neither of type SOCK_RAW or SOCK_DGRAM, reject it. */
 2711         if (inp->inp_socket->so_proto->pr_type != SOCK_RAW &&
 2712              inp->inp_socket->so_proto->pr_type != SOCK_DGRAM)
 2713                 return (EOPNOTSUPP);
 2714 
 2715         switch (sopt->sopt_name) {
 2716         case IP_MULTICAST_VIF: {
 2717                 int vifi;
 2718                 /*
 2719                  * Select a multicast VIF for transmission.
 2720                  * Only useful if multicast forwarding is active.
 2721                  */
 2722                 if (legal_vif_num == NULL) {
 2723                         error = EOPNOTSUPP;
 2724                         break;
 2725                 }
 2726                 error = sooptcopyin(sopt, &vifi, sizeof(int), sizeof(int));
 2727                 if (error)
 2728                         break;
 2729                 if (!legal_vif_num(vifi) && (vifi != -1)) {
 2730                         error = EINVAL;
 2731                         break;
 2732                 }
 2733                 imo = inp_findmoptions(inp);
 2734                 imo->imo_multicast_vif = vifi;
 2735                 INP_WUNLOCK(inp);
 2736                 break;
 2737         }
 2738 
 2739         case IP_MULTICAST_IF:
 2740                 error = inp_set_multicast_if(inp, sopt);
 2741                 break;
 2742 
 2743         case IP_MULTICAST_TTL: {
 2744                 u_char ttl;
 2745 
 2746                 /*
 2747                  * Set the IP time-to-live for outgoing multicast packets.
 2748                  * The original multicast API required a char argument,
 2749                  * which is inconsistent with the rest of the socket API.
 2750                  * We allow either a char or an int.
 2751                  */
 2752                 if (sopt->sopt_valsize == sizeof(u_char)) {
 2753                         error = sooptcopyin(sopt, &ttl, sizeof(u_char),
 2754                             sizeof(u_char));
 2755                         if (error)
 2756                                 break;
 2757                 } else {
 2758                         u_int ittl;
 2759 
 2760                         error = sooptcopyin(sopt, &ittl, sizeof(u_int),
 2761                             sizeof(u_int));
 2762                         if (error)
 2763                                 break;
 2764                         if (ittl > 255) {
 2765                                 error = EINVAL;
 2766                                 break;
 2767                         }
 2768                         ttl = (u_char)ittl;
 2769                 }
 2770                 imo = inp_findmoptions(inp);
 2771                 imo->imo_multicast_ttl = ttl;
 2772                 INP_WUNLOCK(inp);
 2773                 break;
 2774         }
 2775 
 2776         case IP_MULTICAST_LOOP: {
 2777                 u_char loop;
 2778 
 2779                 /*
 2780                  * Set the loopback flag for outgoing multicast packets.
 2781                  * Must be zero or one.  The original multicast API required a
 2782                  * char argument, which is inconsistent with the rest
 2783                  * of the socket API.  We allow either a char or an int.
 2784                  */
 2785                 if (sopt->sopt_valsize == sizeof(u_char)) {
 2786                         error = sooptcopyin(sopt, &loop, sizeof(u_char),
 2787                             sizeof(u_char));
 2788                         if (error)
 2789                                 break;
 2790                 } else {
 2791                         u_int iloop;
 2792 
 2793                         error = sooptcopyin(sopt, &iloop, sizeof(u_int),
 2794                                             sizeof(u_int));
 2795                         if (error)
 2796                                 break;
 2797                         loop = (u_char)iloop;
 2798                 }
 2799                 imo = inp_findmoptions(inp);
 2800                 imo->imo_multicast_loop = !!loop;
 2801                 INP_WUNLOCK(inp);
 2802                 break;
 2803         }
 2804 
 2805         case IP_ADD_MEMBERSHIP:
 2806         case IP_ADD_SOURCE_MEMBERSHIP:
 2807         case MCAST_JOIN_GROUP:
 2808         case MCAST_JOIN_SOURCE_GROUP:
 2809                 error = inp_join_group(inp, sopt);
 2810                 break;
 2811 
 2812         case IP_DROP_MEMBERSHIP:
 2813         case IP_DROP_SOURCE_MEMBERSHIP:
 2814         case MCAST_LEAVE_GROUP:
 2815         case MCAST_LEAVE_SOURCE_GROUP:
 2816                 error = inp_leave_group(inp, sopt);
 2817                 break;
 2818 
 2819         case IP_BLOCK_SOURCE:
 2820         case IP_UNBLOCK_SOURCE:
 2821         case MCAST_BLOCK_SOURCE:
 2822         case MCAST_UNBLOCK_SOURCE:
 2823                 error = inp_block_unblock_source(inp, sopt);
 2824                 break;
 2825 
 2826         case IP_MSFILTER:
 2827                 error = inp_set_source_filters(inp, sopt);
 2828                 break;
 2829 
 2830         default:
 2831                 error = EOPNOTSUPP;
 2832                 break;
 2833         }
 2834 
 2835         INP_UNLOCK_ASSERT(inp);
 2836 
 2837         return (error);
 2838 }
 2839 
 2840 /*
 2841  * Expose IGMP's multicast filter mode and source list(s) to userland,
 2842  * keyed by (ifindex, group).
 2843  * The filter mode is written out as a uint32_t, followed by
 2844  * 0..n of struct in_addr.
 2845  * For use by ifmcstat(8).
 2846  * SMPng: NOTE: unlocked read of ifindex space.
 2847  */
 2848 static int
 2849 sysctl_ip_mcast_filters(SYSCTL_HANDLER_ARGS)
 2850 {
 2851         struct in_addr                   src, group;
 2852         struct epoch_tracker             et;
 2853         struct ifnet                    *ifp;
 2854         struct ifmultiaddr              *ifma;
 2855         struct in_multi                 *inm;
 2856         struct ip_msource               *ims;
 2857         int                             *name;
 2858         int                              retval;
 2859         u_int                            namelen;
 2860         uint32_t                         fmode, ifindex;
 2861 
 2862         name = (int *)arg1;
 2863         namelen = arg2;
 2864 
 2865         if (req->newptr != NULL)
 2866                 return (EPERM);
 2867 
 2868         if (namelen != 2)
 2869                 return (EINVAL);
 2870 
 2871         group.s_addr = name[1];
 2872         if (!IN_MULTICAST(ntohl(group.s_addr))) {
 2873                 CTR2(KTR_IGMPV3, "%s: group 0x%08x is not multicast",
 2874                     __func__, ntohl(group.s_addr));
 2875                 return (EINVAL);
 2876         }
 2877 
 2878         ifindex = name[0];
 2879         NET_EPOCH_ENTER(et);
 2880         ifp = ifnet_byindex(ifindex);
 2881         if (ifp == NULL) {
 2882                 NET_EPOCH_EXIT(et);
 2883                 CTR2(KTR_IGMPV3, "%s: no ifp for ifindex %u",
 2884                     __func__, ifindex);
 2885                 return (ENOENT);
 2886         }
 2887 
 2888         retval = sysctl_wire_old_buffer(req,
 2889             sizeof(uint32_t) + (in_mcast_maxgrpsrc * sizeof(struct in_addr)));
 2890         if (retval) {
 2891                 NET_EPOCH_EXIT(et);
 2892                 return (retval);
 2893         }
 2894 
 2895         IN_MULTI_LIST_LOCK();
 2896 
 2897         CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
 2898                 inm = inm_ifmultiaddr_get_inm(ifma);
 2899                 if (inm == NULL)
 2900                         continue;
 2901                 if (!in_hosteq(inm->inm_addr, group))
 2902                         continue;
 2903                 fmode = inm->inm_st[1].iss_fmode;
 2904                 retval = SYSCTL_OUT(req, &fmode, sizeof(uint32_t));
 2905                 if (retval != 0)
 2906                         break;
 2907                 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) {
 2908                         CTR2(KTR_IGMPV3, "%s: visit node 0x%08x", __func__,
 2909                             ims->ims_haddr);
 2910                         /*
 2911                          * Only copy-out sources which are in-mode.
 2912                          */
 2913                         if (fmode != ims_get_mode(inm, ims, 1)) {
 2914                                 CTR1(KTR_IGMPV3, "%s: skip non-in-mode",
 2915                                     __func__);
 2916                                 continue;
 2917                         }
 2918                         src.s_addr = htonl(ims->ims_haddr);
 2919                         retval = SYSCTL_OUT(req, &src, sizeof(struct in_addr));
 2920                         if (retval != 0)
 2921                                 break;
 2922                 }
 2923         }
 2924 
 2925         IN_MULTI_LIST_UNLOCK();
 2926         NET_EPOCH_EXIT(et);
 2927 
 2928         return (retval);
 2929 }
 2930 
 2931 #if defined(KTR) && (KTR_COMPILE & KTR_IGMPV3)
 2932 
 2933 static const char *inm_modestrs[] = {
 2934         [MCAST_UNDEFINED] = "un",
 2935         [MCAST_INCLUDE] = "in",
 2936         [MCAST_EXCLUDE] = "ex",
 2937 };
 2938 _Static_assert(MCAST_UNDEFINED == 0 &&
 2939                MCAST_EXCLUDE + 1 == nitems(inm_modestrs),
 2940                "inm_modestrs: no longer matches #defines");
 2941 
 2942 static const char *
 2943 inm_mode_str(const int mode)
 2944 {
 2945 
 2946         if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE)
 2947                 return (inm_modestrs[mode]);
 2948         return ("??");
 2949 }
 2950 
 2951 static const char *inm_statestrs[] = {
 2952         [IGMP_NOT_MEMBER] = "not-member",
 2953         [IGMP_SILENT_MEMBER] = "silent",
 2954         [IGMP_REPORTING_MEMBER] = "reporting",
 2955         [IGMP_IDLE_MEMBER] = "idle",
 2956         [IGMP_LAZY_MEMBER] = "lazy",
 2957         [IGMP_SLEEPING_MEMBER] = "sleeping",
 2958         [IGMP_AWAKENING_MEMBER] = "awakening",
 2959         [IGMP_G_QUERY_PENDING_MEMBER] = "query-pending",
 2960         [IGMP_SG_QUERY_PENDING_MEMBER] = "sg-query-pending",
 2961         [IGMP_LEAVING_MEMBER] = "leaving",
 2962 };
 2963 _Static_assert(IGMP_NOT_MEMBER == 0 &&
 2964                IGMP_LEAVING_MEMBER + 1 == nitems(inm_statestrs),
 2965                "inm_statetrs: no longer matches #defines");
 2966 
 2967 static const char *
 2968 inm_state_str(const int state)
 2969 {
 2970 
 2971         if (state >= IGMP_NOT_MEMBER && state <= IGMP_LEAVING_MEMBER)
 2972                 return (inm_statestrs[state]);
 2973         return ("??");
 2974 }
 2975 
 2976 /*
 2977  * Dump an in_multi structure to the console.
 2978  */
 2979 void
 2980 inm_print(const struct in_multi *inm)
 2981 {
 2982         int t;
 2983         char addrbuf[INET_ADDRSTRLEN];
 2984 
 2985         if ((ktr_mask & KTR_IGMPV3) == 0)
 2986                 return;
 2987 
 2988         printf("%s: --- begin inm %p ---\n", __func__, inm);
 2989         printf("addr %s ifp %p(%s) ifma %p\n",
 2990             inet_ntoa_r(inm->inm_addr, addrbuf),
 2991             inm->inm_ifp,
 2992             inm->inm_ifp->if_xname,
 2993             inm->inm_ifma);
 2994         printf("timer %u state %s refcount %u scq.len %u\n",
 2995             inm->inm_timer,
 2996             inm_state_str(inm->inm_state),
 2997             inm->inm_refcount,
 2998             inm->inm_scq.mq_len);
 2999         printf("igi %p nsrc %lu sctimer %u scrv %u\n",
 3000             inm->inm_igi,
 3001             inm->inm_nsrc,
 3002             inm->inm_sctimer,
 3003             inm->inm_scrv);
 3004         for (t = 0; t < 2; t++) {
 3005                 printf("t%d: fmode %s asm %u ex %u in %u rec %u\n", t,
 3006                     inm_mode_str(inm->inm_st[t].iss_fmode),
 3007                     inm->inm_st[t].iss_asm,
 3008                     inm->inm_st[t].iss_ex,
 3009                     inm->inm_st[t].iss_in,
 3010                     inm->inm_st[t].iss_rec);
 3011         }
 3012         printf("%s: --- end inm %p ---\n", __func__, inm);
 3013 }
 3014 
 3015 #else /* !KTR || !(KTR_COMPILE & KTR_IGMPV3) */
 3016 
 3017 void
 3018 inm_print(const struct in_multi *inm)
 3019 {
 3020 
 3021 }
 3022 
 3023 #endif /* KTR && (KTR_COMPILE & KTR_IGMPV3) */
 3024 
 3025 RB_GENERATE(ip_msource_tree, ip_msource, ims_link, ip_msource_cmp);

Cache object: ec27690bde8a1b0c3789c4c721c33a1d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.