2  * Copyright (c) 2010-2013 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  29  * Copyright (c) 2007-2009 Bruce Simpson. 
  30  * Copyright (c) 2005 Robert N. M. Watson. 
  31  * All rights reserved. 
  33  * Redistribution and use in source and binary forms, with or without 
  34  * modification, are permitted provided that the following conditions 
  36  * 1. Redistributions of source code must retain the above copyright 
  37  *    notice, this list of conditions and the following disclaimer. 
  38  * 2. Redistributions in binary form must reproduce the above copyright 
  39  *    notice, this list of conditions and the following disclaimer in the 
  40  *    documentation and/or other materials provided with the distribution. 
  41  * 3. The name of the author may not be used to endorse or promote 
  42  *    products derived from this software without specific prior written 
  45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
  46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
  49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  59  * IPv4 multicast socket, group, and socket option processing module. 
  62 #include <sys/cdefs.h> 
  64 #include <sys/param.h> 
  65 #include <sys/systm.h> 
  66 #include <sys/kernel.h> 
  67 #include <sys/malloc.h> 
  69 #include <sys/protosw.h> 
  70 #include <sys/socket.h> 
  71 #include <sys/socketvar.h> 
  72 #include <sys/protosw.h> 
  73 #include <sys/sysctl.h> 
  75 #include <sys/mcache.h> 
  77 #include <kern/zalloc.h> 
  79 #include <pexpert/pexpert.h> 
  82 #include <net/if_dl.h> 
  83 #include <net/route.h> 
  85 #include <netinet/in.h> 
  86 #include <netinet/in_systm.h> 
  87 #include <netinet/in_pcb.h> 
  88 #include <netinet/in_var.h> 
  89 #include <netinet/ip_var.h> 
  90 #include <netinet/igmp_var.h> 
  92 #ifndef __SOCKUNION_DECLARED 
  94         struct sockaddr_storage ss
; 
  96         struct sockaddr_dl      sdl
; 
  97         struct sockaddr_in      sin
; 
  99 typedef union sockunion sockunion_t
; 
 100 #define __SOCKUNION_DECLARED 
 101 #endif /* __SOCKUNION_DECLARED */ 
 104  * Functions with non-static linkage defined in this file should be 
 105  * declared in in_var.h: 
 116  * XXX: Both carp and pf need to use the legacy (*,G) KPIs in_addmulti() 
 119 static void     imf_commit(struct in_mfilter 
*); 
 120 static int      imf_get_source(struct in_mfilter 
*imf
, 
 121                     const struct sockaddr_in 
*psin
, 
 122                     struct in_msource 
**); 
 123 static struct in_msource 
* 
 124                 imf_graft(struct in_mfilter 
*, const uint8_t, 
 125                     const struct sockaddr_in 
*); 
 126 static int      imf_prune(struct in_mfilter 
*, const struct sockaddr_in 
*); 
 127 static void     imf_rollback(struct in_mfilter 
*); 
 128 static void     imf_reap(struct in_mfilter 
*); 
 129 static int      imo_grow(struct ip_moptions 
*, size_t); 
 130 static size_t   imo_match_group(const struct ip_moptions 
*, 
 131                     const struct ifnet 
*, const struct sockaddr 
*); 
 132 static struct in_msource 
* 
 133                 imo_match_source(const struct ip_moptions 
*, const size_t, 
 134                     const struct sockaddr 
*); 
 135 static void     ims_merge(struct ip_msource 
*ims
, 
 136                     const struct in_msource 
*lims
, const int rollback
); 
 137 static int      in_getmulti(struct ifnet 
*, const struct in_addr 
*, 
 139 static int      in_joingroup(struct ifnet 
*, const struct in_addr 
*, 
 140                     struct in_mfilter 
*, struct in_multi 
**); 
 141 static int      inm_get_source(struct in_multi 
*inm
, const in_addr_t haddr
, 
 142                     const int noalloc
, struct ip_msource 
**pims
); 
 143 static int      inm_is_ifp_detached(const struct in_multi 
*); 
 144 static int      inm_merge(struct in_multi 
*, /*const*/ struct in_mfilter 
*); 
 145 static void     inm_reap(struct in_multi 
*); 
 146 static struct ip_moptions 
* 
 147                 inp_findmoptions(struct inpcb 
*); 
 148 static int      inp_get_source_filters(struct inpcb 
*, struct sockopt 
*); 
 149 static struct ifnet 
* 
 150                 inp_lookup_mcast_ifp(const struct inpcb 
*, 
 151                     const struct sockaddr_in 
*, const struct in_addr
); 
 152 static int      inp_block_unblock_source(struct inpcb 
*, struct sockopt 
*); 
 153 static int      inp_set_multicast_if(struct inpcb 
*, struct sockopt 
*); 
 154 static int      inp_set_source_filters(struct inpcb 
*, struct sockopt 
*); 
 155 static int      sysctl_ip_mcast_filters SYSCTL_HANDLER_ARGS
; 
 156 static struct ifnet 
* ip_multicast_if(struct in_addr 
*, unsigned int *); 
 157 static __inline__ 
int ip_msource_cmp(const struct ip_msource 
*, 
 158     const struct ip_msource 
*); 
 160 SYSCTL_NODE(_net_inet_ip
, OID_AUTO
, mcast
, CTLFLAG_RW 
| CTLFLAG_LOCKED
, 0, "IPv4 multicast"); 
 162 static u_long in_mcast_maxgrpsrc 
= IP_MAX_GROUP_SRC_FILTER
; 
 163 SYSCTL_LONG(_net_inet_ip_mcast
, OID_AUTO
, maxgrpsrc
, 
 164     CTLFLAG_RW 
| CTLFLAG_LOCKED
, &in_mcast_maxgrpsrc
, "Max source filters per group"); 
 166 static u_long in_mcast_maxsocksrc 
= IP_MAX_SOCK_SRC_FILTER
; 
 167 SYSCTL_LONG(_net_inet_ip_mcast
, OID_AUTO
, maxsocksrc
, 
 168     CTLFLAG_RW 
| CTLFLAG_LOCKED
, &in_mcast_maxsocksrc
,  
 169     "Max source filters per socket"); 
 171 int in_mcast_loop 
= IP_DEFAULT_MULTICAST_LOOP
; 
 172 SYSCTL_INT(_net_inet_ip_mcast
, OID_AUTO
, loop
, CTLFLAG_RW 
| CTLFLAG_LOCKED
,  
 173     &in_mcast_loop
, 0, "Loopback multicast datagrams by default"); 
 175 SYSCTL_NODE(_net_inet_ip_mcast
, OID_AUTO
, filters
, 
 176     CTLFLAG_RD 
| CTLFLAG_LOCKED
, sysctl_ip_mcast_filters
, 
 177     "Per-interface stack-wide source filters"); 
 179 RB_GENERATE_PREV(ip_msource_tree
, ip_msource
, ims_link
, ip_msource_cmp
); 
 181 #define INM_TRACE_HIST_SIZE     32      /* size of trace history */ 
 184 __private_extern__ 
unsigned int inm_trace_hist_size 
= INM_TRACE_HIST_SIZE
; 
 186 struct in_multi_dbg 
{ 
 187         struct in_multi         inm
;                    /* in_multi */ 
 188         u_int16_t               inm_refhold_cnt
;        /* # of ref */ 
 189         u_int16_t               inm_refrele_cnt
;        /* # of rele */ 
 191          * Circular lists of inm_addref and inm_remref callers. 
 193         ctrace_t                inm_refhold
[INM_TRACE_HIST_SIZE
]; 
 194         ctrace_t                inm_refrele
[INM_TRACE_HIST_SIZE
]; 
 198         TAILQ_ENTRY(in_multi_dbg
) inm_trash_link
; 
 201 /* List of trash in_multi entries protected by inm_trash_lock */ 
 202 static TAILQ_HEAD(, in_multi_dbg
) inm_trash_head
; 
 203 static decl_lck_mtx_data(, inm_trash_lock
); 
 205 #define INM_ZONE_MAX            64              /* maximum elements in zone */ 
 206 #define INM_ZONE_NAME           "in_multi"      /* zone name */ 
 209 static unsigned int inm_debug 
= 1;              /* debugging (enabled) */ 
 211 static unsigned int inm_debug
;                  /* debugging (disabled) */ 
 213 static unsigned int inm_size
;                   /* size of zone element */ 
 214 static struct zone 
*inm_zone
;                   /* zone for in_multi */ 
 216 #define IPMS_ZONE_MAX           64              /* maximum elements in zone */ 
 217 #define IPMS_ZONE_NAME          "ip_msource"    /* zone name */ 
 219 static unsigned int ipms_size
;                  /* size of zone element */ 
 220 static struct zone 
*ipms_zone
;                  /* zone for ip_msource */ 
 222 #define INMS_ZONE_MAX           64              /* maximum elements in zone */ 
 223 #define INMS_ZONE_NAME          "in_msource"    /* zone name */ 
 225 static unsigned int inms_size
;                  /* size of zone element */ 
 226 static struct zone 
*inms_zone
;                  /* zone for in_msource */ 
 228 /* Lock group and attribute for in_multihead_lock lock */ 
 229 static lck_attr_t       
*in_multihead_lock_attr
; 
 230 static lck_grp_t        
*in_multihead_lock_grp
; 
 231 static lck_grp_attr_t   
*in_multihead_lock_grp_attr
; 
 233 static decl_lck_rw_data(, in_multihead_lock
); 
 234 struct in_multihead in_multihead
; 
 236 static struct in_multi 
*in_multi_alloc(int); 
 237 static void in_multi_free(struct in_multi 
*); 
 238 static void in_multi_attach(struct in_multi 
*); 
 239 static void inm_trace(struct in_multi 
*, int); 
 241 static struct ip_msource 
*ipms_alloc(int); 
 242 static void ipms_free(struct ip_msource 
*); 
 243 static struct in_msource 
*inms_alloc(int); 
 244 static void inms_free(struct in_msource 
*); 
 247 ip_msource_cmp(const struct ip_msource 
*a
, const struct ip_msource 
*b
) 
 250         if (a
->ims_haddr 
< b
->ims_haddr
) 
 252         if (a
->ims_haddr 
== b
->ims_haddr
) 
 258  * Inline function which wraps assertions for a valid ifp. 
 260 static __inline__ 
int 
 261 inm_is_ifp_detached(const struct in_multi 
*inm
) 
 263         VERIFY(inm
->inm_ifma 
!= NULL
); 
 264         VERIFY(inm
->inm_ifp 
== inm
->inm_ifma
->ifma_ifp
); 
 266         return (!ifnet_is_attached(inm
->inm_ifp
, 0)); 
 270  * Initialize an in_mfilter structure to a known state at t0, t1 
 271  * with an empty source filter list. 
 273 static __inline__ 
void 
 274 imf_init(struct in_mfilter 
*imf
, const int st0
, const int st1
) 
 276         memset(imf
, 0, sizeof(struct in_mfilter
)); 
 277         RB_INIT(&imf
->imf_sources
); 
 278         imf
->imf_st
[0] = st0
; 
 279         imf
->imf_st
[1] = st1
; 
 283  * Resize the ip_moptions vector to the next power-of-two minus 1. 
 286 imo_grow(struct ip_moptions 
*imo
, size_t newmax
) 
 288         struct in_multi         
**nmships
; 
 289         struct in_multi         
**omships
; 
 290         struct in_mfilter        
*nmfilters
; 
 291         struct in_mfilter        
*omfilters
; 
 295         IMO_LOCK_ASSERT_HELD(imo
); 
 299         omships 
= imo
->imo_membership
; 
 300         omfilters 
= imo
->imo_mfilters
; 
 301         oldmax 
= imo
->imo_max_memberships
; 
 303                 newmax 
= ((oldmax 
+ 1) * 2) - 1; 
 305         if (newmax 
> IP_MAX_MEMBERSHIPS
) 
 306                 return (ETOOMANYREFS
); 
 308         if ((nmships 
= (struct in_multi 
**)_REALLOC(omships
, 
 309             sizeof (struct in_multi 
*) * newmax
, M_IPMOPTS
, 
 310             M_WAITOK 
| M_ZERO
)) == NULL
) 
 313         imo
->imo_membership 
= nmships
; 
 315         if ((nmfilters 
= (struct in_mfilter 
*)_REALLOC(omfilters
, 
 316             sizeof (struct in_mfilter
) * newmax
, M_INMFILTER
, 
 317             M_WAITOK 
| M_ZERO
)) == NULL
) 
 320         imo
->imo_mfilters 
= nmfilters
; 
 322         /* Initialize newly allocated source filter heads. */ 
 323         for (idx 
= oldmax
; idx 
< newmax
; idx
++) 
 324                 imf_init(&nmfilters
[idx
], MCAST_UNDEFINED
, MCAST_EXCLUDE
); 
 326         imo
->imo_max_memberships 
= newmax
; 
 332  * Find an IPv4 multicast group entry for this ip_moptions instance 
 333  * which matches the specified group, and optionally an interface. 
 334  * Return its index into the array, or -1 if not found. 
 337 imo_match_group(const struct ip_moptions 
*imo
, const struct ifnet 
*ifp
, 
 338     const struct sockaddr 
*group
) 
 340         const struct sockaddr_in 
*gsin
; 
 341         struct in_multi 
*pinm
; 
 345         IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions 
*, imo
)); 
 347         gsin 
= (struct sockaddr_in 
*)(uintptr_t)(size_t)group
; 
 349         /* The imo_membership array may be lazy allocated. */ 
 350         if (imo
->imo_membership 
== NULL 
|| imo
->imo_num_memberships 
== 0) 
 353         nmships 
= imo
->imo_num_memberships
; 
 354         for (idx 
= 0; idx 
< nmships
; idx
++) { 
 355                 pinm 
= imo
->imo_membership
[idx
]; 
 359                 if ((ifp 
== NULL 
|| (pinm
->inm_ifp 
== ifp
)) && 
 360                     in_hosteq(pinm
->inm_addr
, gsin
->sin_addr
)) { 
 373  * Find an IPv4 multicast source entry for this imo which matches 
 374  * the given group index for this socket, and source address. 
 376  * NOTE: This does not check if the entry is in-mode, merely if 
 377  * it exists, which may not be the desired behaviour. 
 379 static struct in_msource 
* 
 380 imo_match_source(const struct ip_moptions 
*imo
, const size_t gidx
, 
 381     const struct sockaddr 
*src
) 
 383         struct ip_msource        find
; 
 384         struct in_mfilter       
*imf
; 
 385         struct ip_msource       
*ims
; 
 386         const sockunion_t       
*psa
; 
 388         IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions 
*, imo
)); 
 390         VERIFY(src
->sa_family 
== AF_INET
); 
 391         VERIFY(gidx 
!= (size_t)-1 && gidx 
< imo
->imo_num_memberships
); 
 393         /* The imo_mfilters array may be lazy allocated. */ 
 394         if (imo
->imo_mfilters 
== NULL
) 
 396         imf 
= &imo
->imo_mfilters
[gidx
]; 
 398         /* Source trees are keyed in host byte order. */ 
 399         psa 
= (sockunion_t 
*)(uintptr_t)(size_t)src
; 
 400         find
.ims_haddr 
= ntohl(psa
->sin
.sin_addr
.s_addr
); 
 401         ims 
= RB_FIND(ip_msource_tree
, &imf
->imf_sources
, &find
); 
 403         return ((struct in_msource 
*)ims
); 
 407  * Perform filtering for multicast datagrams on a socket by group and source. 
 409  * Returns 0 if a datagram should be allowed through, or various error codes 
 410  * if the socket was not a member of the group, or the source was muted, etc. 
 413 imo_multi_filter(const struct ip_moptions 
*imo
, const struct ifnet 
*ifp
, 
 414     const struct sockaddr 
*group
, const struct sockaddr 
*src
) 
 417         struct in_msource 
*ims
; 
 420         IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions 
*, imo
)); 
 423         gidx 
= imo_match_group(imo
, ifp
, group
); 
 424         if (gidx 
== (size_t)-1) 
 425                 return (MCAST_NOTGMEMBER
); 
 428          * Check if the source was included in an (S,G) join. 
 429          * Allow reception on exclusive memberships by default, 
 430          * reject reception on inclusive memberships by default. 
 431          * Exclude source only if an in-mode exclude filter exists. 
 432          * Include source only if an in-mode include filter exists. 
 433          * NOTE: We are comparing group state here at IGMP t1 (now) 
 434          * with socket-layer t0 (since last downcall). 
 436         mode 
= imo
->imo_mfilters
[gidx
].imf_st
[1]; 
 437         ims 
= imo_match_source(imo
, gidx
, src
); 
 439         if ((ims 
== NULL 
&& mode 
== MCAST_INCLUDE
) || 
 440             (ims 
!= NULL 
&& ims
->imsl_st
[0] != mode
)) { 
 441                 return (MCAST_NOTSMEMBER
); 
 448 imo_clone(struct inpcb 
*from_inp
, struct inpcb 
*to_inp
) 
 451         struct ip_moptions 
*from
; 
 452         struct ip_moptions 
*to
; 
 454         from 
= inp_findmoptions(from_inp
); 
 458         to 
= inp_findmoptions(to_inp
); 
 467         to
->imo_multicast_ifp 
= from
->imo_multicast_ifp
; 
 468         to
->imo_multicast_vif 
= from
->imo_multicast_vif
; 
 469         to
->imo_multicast_ttl 
= from
->imo_multicast_ttl
; 
 470         to
->imo_multicast_loop 
= from
->imo_multicast_loop
; 
 473          * We're cloning, so drop any existing memberships and source 
 474          * filters on the destination ip_moptions. 
 476         for (i 
= 0; i 
< to
->imo_num_memberships
; ++i
) { 
 477                 struct in_mfilter 
*imf
; 
 479                 imf 
= to
->imo_mfilters 
? &to
->imo_mfilters
[i
] : NULL
; 
 483                 (void) in_leavegroup(to
->imo_membership
[i
], imf
); 
 488                 INM_REMREF(to
->imo_membership
[i
]); 
 489                 to
->imo_membership
[i
] = NULL
; 
 491         to
->imo_num_memberships 
= 0; 
 493         VERIFY(to
->imo_max_memberships 
!= 0 && from
->imo_max_memberships 
!= 0); 
 494         if (to
->imo_max_memberships 
< from
->imo_max_memberships
) { 
 496                  * Ensure source and destination ip_moptions memberships 
 497                  * and source filters arrays are at least equal in size. 
 499                 err 
= imo_grow(to
, from
->imo_max_memberships
); 
 503         VERIFY(to
->imo_max_memberships 
>= from
->imo_max_memberships
); 
 506          * Source filtering doesn't apply to OpenTransport socket, 
 507          * so simply hold additional reference count per membership. 
 509         for (i 
= 0; i 
< from
->imo_num_memberships
; i
++) { 
 510                 to
->imo_membership
[i
] =  
 511                         in_addmulti(&from
->imo_membership
[i
]->inm_addr
, 
 512                                                 from
->imo_membership
[i
]->inm_ifp
); 
 513                 if (to
->imo_membership
[i
] == NULL
) 
 515                 to
->imo_num_memberships
++; 
 517         VERIFY(to
->imo_num_memberships 
== from
->imo_num_memberships
); 
 529  * Find and return a reference to an in_multi record for (ifp, group), 
 530  * and bump its reference count. 
 531  * If one does not exist, try to allocate it, and update link-layer multicast 
 532  * filters on ifp to listen for group. 
 533  * Return 0 if successful, otherwise return an appropriate error code. 
 536 in_getmulti(struct ifnet 
*ifp
, const struct in_addr 
*group
, 
 537     struct in_multi 
**pinm
) 
 539         struct sockaddr_in       gsin
; 
 540         struct ifmultiaddr      
*ifma
; 
 541         struct in_multi         
*inm
; 
 544         in_multihead_lock_shared(); 
 545         IN_LOOKUP_MULTI(group
, ifp
, inm
); 
 548                 VERIFY(inm
->inm_reqcnt 
>= 1); 
 550                 VERIFY(inm
->inm_reqcnt 
!= 0); 
 553                 in_multihead_lock_done(); 
 555                  * We already joined this group; return the inm 
 556                  * with a refcount held (via lookup) for caller. 
 560         in_multihead_lock_done(); 
 562         bzero(&gsin
, sizeof(gsin
)); 
 563         gsin
.sin_family 
= AF_INET
; 
 564         gsin
.sin_len 
= sizeof(struct sockaddr_in
); 
 565         gsin
.sin_addr 
= *group
; 
 568          * Check if a link-layer group is already associated 
 569          * with this network-layer group on the given ifnet. 
 571         error 
= if_addmulti(ifp
, (struct sockaddr 
*)&gsin
, &ifma
); 
 576          * See comments in inm_remref() for access to ifma_protospec. 
 578         in_multihead_lock_exclusive(); 
 580         if ((inm 
= ifma
->ifma_protospec
) != NULL
) { 
 581                 VERIFY(ifma
->ifma_addr 
!= NULL
); 
 582                 VERIFY(ifma
->ifma_addr
->sa_family 
== AF_INET
); 
 583                 INM_ADDREF(inm
);        /* for caller */ 
 586                 VERIFY(inm
->inm_ifma 
== ifma
); 
 587                 VERIFY(inm
->inm_ifp 
== ifp
); 
 588                 VERIFY(in_hosteq(inm
->inm_addr
, *group
)); 
 589                 if (inm
->inm_debug 
& IFD_ATTACHED
) { 
 590                         VERIFY(inm
->inm_reqcnt 
>= 1); 
 592                         VERIFY(inm
->inm_reqcnt 
!= 0); 
 595                         in_multihead_lock_done(); 
 598                          * We lost the race with another thread doing 
 599                          * in_getmulti(); since this group has already 
 600                          * been joined; return the inm with a refcount 
 606                  * We lost the race with another thread doing in_delmulti(); 
 607                  * the inm referring to the ifma has been detached, thus we 
 608                  * reattach it back to the in_multihead list and return the 
 609                  * inm with a refcount held for the caller. 
 611                 in_multi_attach(inm
); 
 612                 VERIFY((inm
->inm_debug 
& 
 613                     (IFD_ATTACHED 
| IFD_TRASHED
)) == IFD_ATTACHED
); 
 616                 in_multihead_lock_done(); 
 623          * A new in_multi record is needed; allocate and initialize it. 
 624          * We DO NOT perform an IGMP join as the in_ layer may need to 
 625          * push an initial source list down to IGMP to support SSM. 
 627          * The initial source filter state is INCLUDE, {} as per the RFC. 
 629         inm 
= in_multi_alloc(M_WAITOK
); 
 631                 in_multihead_lock_done(); 
 636         inm
->inm_addr 
= *group
; 
 638         inm
->inm_igi 
= IGMP_IFINFO(ifp
); 
 639         VERIFY(inm
->inm_igi 
!= NULL
); 
 640         IGI_ADDREF(inm
->inm_igi
); 
 641         inm
->inm_ifma 
= ifma
;           /* keep refcount from if_addmulti() */ 
 642         inm
->inm_state 
= IGMP_NOT_MEMBER
; 
 644          * Pending state-changes per group are subject to a bounds check. 
 646         inm
->inm_scq
.ifq_maxlen 
= IGMP_MAX_STATE_CHANGES
; 
 647         inm
->inm_st
[0].iss_fmode 
= MCAST_UNDEFINED
; 
 648         inm
->inm_st
[1].iss_fmode 
= MCAST_UNDEFINED
; 
 649         RB_INIT(&inm
->inm_srcs
); 
 651         in_multi_attach(inm
); 
 652         VERIFY((inm
->inm_debug 
& (IFD_ATTACHED 
| IFD_TRASHED
)) == IFD_ATTACHED
); 
 653         INM_ADDREF_LOCKED(inm
);         /* for caller */ 
 657         VERIFY(ifma
->ifma_protospec 
== NULL
); 
 658         ifma
->ifma_protospec 
= inm
; 
 660         in_multihead_lock_done(); 
 666  * Clear recorded source entries for a group. 
 667  * Used by the IGMP code. 
 668  * FIXME: Should reap. 
 671 inm_clear_recorded(struct in_multi 
*inm
) 
 673         struct ip_msource       
*ims
; 
 675         INM_LOCK_ASSERT_HELD(inm
); 
 677         RB_FOREACH(ims
, ip_msource_tree
, &inm
->inm_srcs
) { 
 680                         --inm
->inm_st
[1].iss_rec
; 
 683         VERIFY(inm
->inm_st
[1].iss_rec 
== 0); 
 687  * Record a source as pending for a Source-Group IGMPv3 query. 
 688  * This lives here as it modifies the shared tree. 
 690  * inm is the group descriptor. 
 691  * naddr is the address of the source to record in network-byte order. 
 693  * If the net.inet.igmp.sgalloc sysctl is non-zero, we will 
 694  * lazy-allocate a source node in response to an SG query. 
 695  * Otherwise, no allocation is performed. This saves some memory 
 696  * with the trade-off that the source will not be reported to the 
 697  * router if joined in the window between the query response and 
 698  * the group actually being joined on the local host. 
 700  * Return 0 if the source didn't exist or was already marked as recorded. 
 701  * Return 1 if the source was marked as recorded by this function. 
 702  * Return <0 if any error occured (negated errno code). 
 705 inm_record_source(struct in_multi 
*inm
, const in_addr_t naddr
) 
 707         struct ip_msource        find
; 
 708         struct ip_msource       
*ims
, *nims
; 
 710         INM_LOCK_ASSERT_HELD(inm
); 
 712         find
.ims_haddr 
= ntohl(naddr
); 
 713         ims 
= RB_FIND(ip_msource_tree
, &inm
->inm_srcs
, &find
); 
 714         if (ims 
&& ims
->ims_stp
) 
 717                 if (inm
->inm_nsrc 
== in_mcast_maxgrpsrc
) 
 719                 nims 
= ipms_alloc(M_WAITOK
); 
 722                 nims
->ims_haddr 
= find
.ims_haddr
; 
 723                 RB_INSERT(ip_msource_tree
, &inm
->inm_srcs
, nims
); 
 729          * Mark the source as recorded and update the recorded 
 733         ++inm
->inm_st
[1].iss_rec
; 
 739  * Return a pointer to an in_msource owned by an in_mfilter, 
 740  * given its source address. 
 741  * Lazy-allocate if needed. If this is a new entry its filter state is 
 744  * imf is the filter set being modified. 
 745  * haddr is the source address in *host* byte-order. 
 747  * Caller is expected to be holding imo_lock. 
 750 imf_get_source(struct in_mfilter 
*imf
, const struct sockaddr_in 
*psin
, 
 751     struct in_msource 
**plims
) 
 753         struct ip_msource        find
; 
 754         struct ip_msource       
*ims
; 
 755         struct in_msource       
*lims
; 
 762         /* key is host byte order */ 
 763         find
.ims_haddr 
= ntohl(psin
->sin_addr
.s_addr
); 
 764         ims 
= RB_FIND(ip_msource_tree
, &imf
->imf_sources
, &find
); 
 765         lims 
= (struct in_msource 
*)ims
; 
 767                 if (imf
->imf_nsrc 
== in_mcast_maxsocksrc
) 
 769                 lims 
= inms_alloc(M_WAITOK
); 
 772                 lims
->ims_haddr 
= find
.ims_haddr
; 
 773                 lims
->imsl_st
[0] = MCAST_UNDEFINED
; 
 774                 RB_INSERT(ip_msource_tree
, &imf
->imf_sources
, 
 775                     (struct ip_msource 
*)lims
); 
 785  * Graft a source entry into an existing socket-layer filter set, 
 786  * maintaining any required invariants and checking allocations. 
 788  * The source is marked as being in the new filter mode at t1. 
 790  * Return the pointer to the new node, otherwise return NULL. 
 792  * Caller is expected to be holding imo_lock. 
 794 static struct in_msource 
* 
 795 imf_graft(struct in_mfilter 
*imf
, const uint8_t st1
, 
 796     const struct sockaddr_in 
*psin
) 
 798         struct in_msource       
*lims
; 
 800         lims 
= inms_alloc(M_WAITOK
); 
 803         lims
->ims_haddr 
= ntohl(psin
->sin_addr
.s_addr
); 
 804         lims
->imsl_st
[0] = MCAST_UNDEFINED
; 
 805         lims
->imsl_st
[1] = st1
; 
 806         RB_INSERT(ip_msource_tree
, &imf
->imf_sources
, 
 807             (struct ip_msource 
*)lims
); 
 814  * Prune a source entry from an existing socket-layer filter set, 
 815  * maintaining any required invariants and checking allocations. 
 817  * The source is marked as being left at t1, it is not freed. 
 819  * Return 0 if no error occurred, otherwise return an errno value. 
 821  * Caller is expected to be holding imo_lock. 
 824 imf_prune(struct in_mfilter 
*imf
, const struct sockaddr_in 
*psin
) 
 826         struct ip_msource        find
; 
 827         struct ip_msource       
*ims
; 
 828         struct in_msource       
*lims
; 
 830         /* key is host byte order */ 
 831         find
.ims_haddr 
= ntohl(psin
->sin_addr
.s_addr
); 
 832         ims 
= RB_FIND(ip_msource_tree
, &imf
->imf_sources
, &find
); 
 835         lims 
= (struct in_msource 
*)ims
; 
 836         lims
->imsl_st
[1] = MCAST_UNDEFINED
; 
 841  * Revert socket-layer filter set deltas at t1 to t0 state. 
 843  * Caller is expected to be holding imo_lock. 
 846 imf_rollback(struct in_mfilter 
*imf
) 
 848         struct ip_msource       
*ims
, *tims
; 
 849         struct in_msource       
*lims
; 
 851         RB_FOREACH_SAFE(ims
, ip_msource_tree
, &imf
->imf_sources
, tims
) { 
 852                 lims 
= (struct in_msource 
*)ims
; 
 853                 if (lims
->imsl_st
[0] == lims
->imsl_st
[1]) { 
 854                         /* no change at t1 */ 
 856                 } else if (lims
->imsl_st
[0] != MCAST_UNDEFINED
) { 
 857                         /* revert change to existing source at t1 */ 
 858                         lims
->imsl_st
[1] = lims
->imsl_st
[0]; 
 860                         /* revert source added t1 */ 
 861                         IGMP_PRINTF(("%s: free inms 0x%llx\n", __func__
, 
 862                             (uint64_t)VM_KERNEL_ADDRPERM(lims
))); 
 863                         RB_REMOVE(ip_msource_tree
, &imf
->imf_sources
, ims
); 
 868         imf
->imf_st
[1] = imf
->imf_st
[0]; 
 872  * Mark socket-layer filter set as INCLUDE {} at t1. 
 874  * Caller is expected to be holding imo_lock. 
 877 imf_leave(struct in_mfilter 
*imf
) 
 879         struct ip_msource       
*ims
; 
 880         struct in_msource       
*lims
; 
 882         RB_FOREACH(ims
, ip_msource_tree
, &imf
->imf_sources
) { 
 883                 lims 
= (struct in_msource 
*)ims
; 
 884                 lims
->imsl_st
[1] = MCAST_UNDEFINED
; 
 886         imf
->imf_st
[1] = MCAST_INCLUDE
; 
 890  * Mark socket-layer filter set deltas as committed. 
 892  * Caller is expected to be holding imo_lock. 
 895 imf_commit(struct in_mfilter 
*imf
) 
 897         struct ip_msource       
*ims
; 
 898         struct in_msource       
*lims
; 
 900         RB_FOREACH(ims
, ip_msource_tree
, &imf
->imf_sources
) { 
 901                 lims 
= (struct in_msource 
*)ims
; 
 902                 lims
->imsl_st
[0] = lims
->imsl_st
[1]; 
 904         imf
->imf_st
[0] = imf
->imf_st
[1]; 
 908  * Reap unreferenced sources from socket-layer filter set. 
 910  * Caller is expected to be holding imo_lock. 
 913 imf_reap(struct in_mfilter 
*imf
) 
 915         struct ip_msource       
*ims
, *tims
; 
 916         struct in_msource       
*lims
; 
 918         RB_FOREACH_SAFE(ims
, ip_msource_tree
, &imf
->imf_sources
, tims
) { 
 919                 lims 
= (struct in_msource 
*)ims
; 
 920                 if ((lims
->imsl_st
[0] == MCAST_UNDEFINED
) && 
 921                     (lims
->imsl_st
[1] == MCAST_UNDEFINED
)) { 
 922                         IGMP_PRINTF(("%s: free inms 0x%llx\n", __func__
, 
 923                             (uint64_t)VM_KERNEL_ADDRPERM(lims
))); 
 924                         RB_REMOVE(ip_msource_tree
, &imf
->imf_sources
, ims
); 
 932  * Purge socket-layer filter set. 
 934  * Caller is expected to be holding imo_lock. 
 937 imf_purge(struct in_mfilter 
*imf
) 
 939         struct ip_msource       
*ims
, *tims
; 
 940         struct in_msource       
*lims
; 
 942         RB_FOREACH_SAFE(ims
, ip_msource_tree
, &imf
->imf_sources
, tims
) { 
 943                 lims 
= (struct in_msource 
*)ims
; 
 944                 IGMP_PRINTF(("%s: free inms 0x%llx\n", __func__
, 
 945                     (uint64_t)VM_KERNEL_ADDRPERM(lims
))); 
 946                 RB_REMOVE(ip_msource_tree
, &imf
->imf_sources
, ims
); 
 950         imf
->imf_st
[0] = imf
->imf_st
[1] = MCAST_UNDEFINED
; 
 951         VERIFY(RB_EMPTY(&imf
->imf_sources
)); 
 955  * Look up a source filter entry for a multicast group. 
 957  * inm is the group descriptor to work with. 
 958  * haddr is the host-byte-order IPv4 address to look up. 
 959  * noalloc may be non-zero to suppress allocation of sources. 
 960  * *pims will be set to the address of the retrieved or allocated source. 
 962  * Return 0 if successful, otherwise return a non-zero error code. 
 965 inm_get_source(struct in_multi 
*inm
, const in_addr_t haddr
, 
 966     const int noalloc
, struct ip_msource 
**pims
) 
 968         struct ip_msource        find
; 
 969         struct ip_msource       
*ims
, *nims
; 
 972         char buf
[MAX_IPv4_STR_LEN
]; 
 974         INM_LOCK_ASSERT_HELD(inm
); 
 976         find
.ims_haddr 
= haddr
; 
 977         ims 
= RB_FIND(ip_msource_tree
, &inm
->inm_srcs
, &find
); 
 978         if (ims 
== NULL 
&& !noalloc
) { 
 979                 if (inm
->inm_nsrc 
== in_mcast_maxgrpsrc
) 
 981                 nims 
= ipms_alloc(M_WAITOK
); 
 984                 nims
->ims_haddr 
= haddr
; 
 985                 RB_INSERT(ip_msource_tree
, &inm
->inm_srcs
, nims
); 
 989                 ia
.s_addr 
= htonl(haddr
); 
 990                 inet_ntop(AF_INET
, &ia
, buf
, sizeof(buf
)); 
 991                 IGMP_PRINTF(("%s: allocated %s as 0x%llx\n", __func__
, 
 992                     buf
, (uint64_t)VM_KERNEL_ADDRPERM(ims
))); 
1001  * Helper function to derive the filter mode on a source entry 
1002  * from its internal counters. Predicates are: 
1003  *  A source is only excluded if all listeners exclude it. 
1004  *  A source is only included if no listeners exclude it, 
1005  *  and at least one listener includes it. 
1006  * May be used by ifmcstat(8). 
1009 ims_get_mode(const struct in_multi 
*inm
, const struct ip_msource 
*ims
, 
1012         INM_LOCK_ASSERT_HELD(__DECONST(struct in_multi 
*, inm
)); 
1015         if (inm
->inm_st
[t
].iss_ex 
> 0 && 
1016             inm
->inm_st
[t
].iss_ex 
== ims
->ims_st
[t
].ex
) 
1017                 return (MCAST_EXCLUDE
); 
1018         else if (ims
->ims_st
[t
].in 
> 0 && ims
->ims_st
[t
].ex 
== 0) 
1019                 return (MCAST_INCLUDE
); 
1020         return (MCAST_UNDEFINED
); 
1024  * Merge socket-layer source into IGMP-layer source. 
1025  * If rollback is non-zero, perform the inverse of the merge. 
1028 ims_merge(struct ip_msource 
*ims
, const struct in_msource 
*lims
, 
1031         int n 
= rollback 
? -1 : 1; 
1035         ia
.s_addr 
= htonl(ims
->ims_haddr
); 
1038         if (lims
->imsl_st
[0] == MCAST_EXCLUDE
) { 
1039                 IGMP_INET_PRINTF(ia
, 
1040                     ("%s: t1 ex -= %d on %s\n", 
1041                     __func__
, n
, _igmp_inet_buf
)); 
1042                 ims
->ims_st
[1].ex 
-= n
; 
1043         } else if (lims
->imsl_st
[0] == MCAST_INCLUDE
) { 
1044                 IGMP_INET_PRINTF(ia
, 
1045                     ("%s: t1 in -= %d on %s\n", 
1046                     __func__
, n
, _igmp_inet_buf
)); 
1047                 ims
->ims_st
[1].in 
-= n
; 
1050         if (lims
->imsl_st
[1] == MCAST_EXCLUDE
) { 
1051                 IGMP_INET_PRINTF(ia
, 
1052                     ("%s: t1 ex += %d on %s\n", 
1053                     __func__
, n
, _igmp_inet_buf
)); 
1054                 ims
->ims_st
[1].ex 
+= n
; 
1055         } else if (lims
->imsl_st
[1] == MCAST_INCLUDE
) { 
1056                 IGMP_INET_PRINTF(ia
, 
1057                     ("%s: t1 in += %d on %s\n", 
1058                     __func__
, n
, _igmp_inet_buf
)); 
1059                 ims
->ims_st
[1].in 
+= n
; 
1064  * Atomically update the global in_multi state, when a membership's 
1065  * filter list is being updated in any way. 
1067  * imf is the per-inpcb-membership group filter pointer. 
1068  * A fake imf may be passed for in-kernel consumers. 
1070  * XXX This is a candidate for a set-symmetric-difference style loop 
1071  * which would eliminate the repeated lookup from root of ims nodes, 
1072  * as they share the same key space. 
1074  * If any error occurred this function will back out of refcounts 
1075  * and return a non-zero value. 
1078 inm_merge(struct in_multi 
*inm
, /*const*/ struct in_mfilter 
*imf
) 
1080         struct ip_msource       
*ims
, *nims
; 
1081         struct in_msource       
*lims
; 
1082         int                      schanged
, error
; 
1085         INM_LOCK_ASSERT_HELD(inm
); 
1092          * Update the source filters first, as this may fail. 
1093          * Maintain count of in-mode filters at t0, t1. These are 
1094          * used to work out if we transition into ASM mode or not. 
1095          * Maintain a count of source filters whose state was 
1096          * actually modified by this operation. 
1098         RB_FOREACH(ims
, ip_msource_tree
, &imf
->imf_sources
) { 
1099                 lims 
= (struct in_msource 
*)ims
; 
1100                 if (lims
->imsl_st
[0] == imf
->imf_st
[0]) nsrc0
++; 
1101                 if (lims
->imsl_st
[1] == imf
->imf_st
[1]) nsrc1
++; 
1102                 if (lims
->imsl_st
[0] == lims
->imsl_st
[1]) continue; 
1103                 error 
= inm_get_source(inm
, lims
->ims_haddr
, 0, &nims
); 
1107                 ims_merge(nims
, lims
, 0); 
1110                 struct ip_msource 
*bims
; 
1112                 RB_FOREACH_REVERSE_FROM(ims
, ip_msource_tree
, nims
) { 
1113                         lims 
= (struct in_msource 
*)ims
; 
1114                         if (lims
->imsl_st
[0] == lims
->imsl_st
[1]) 
1116                         (void) inm_get_source(inm
, lims
->ims_haddr
, 1, &bims
); 
1119                         ims_merge(bims
, lims
, 1); 
1124         IGMP_PRINTF(("%s: imf filters in-mode: %d at t0, %d at t1\n", 
1125             __func__
, nsrc0
, nsrc1
)); 
1127         /* Handle transition between INCLUDE {n} and INCLUDE {} on socket. */ 
1128         if (imf
->imf_st
[0] == imf
->imf_st
[1] && 
1129             imf
->imf_st
[1] == MCAST_INCLUDE
) { 
1131                         IGMP_PRINTF(("%s: --in on inm at t1\n", __func__
)); 
1132                         --inm
->inm_st
[1].iss_in
; 
1136         /* Handle filter mode transition on socket. */ 
1137         if (imf
->imf_st
[0] != imf
->imf_st
[1]) { 
1138                 IGMP_PRINTF(("%s: imf transition %d to %d\n", 
1139                     __func__
, imf
->imf_st
[0], imf
->imf_st
[1])); 
1141                 if (imf
->imf_st
[0] == MCAST_EXCLUDE
) { 
1142                         IGMP_PRINTF(("%s: --ex on inm at t1\n", __func__
)); 
1143                         --inm
->inm_st
[1].iss_ex
; 
1144                 } else if (imf
->imf_st
[0] == MCAST_INCLUDE
) { 
1145                         IGMP_PRINTF(("%s: --in on inm at t1\n", __func__
)); 
1146                         --inm
->inm_st
[1].iss_in
; 
1149                 if (imf
->imf_st
[1] == MCAST_EXCLUDE
) { 
1150                         IGMP_PRINTF(("%s: ex++ on inm at t1\n", __func__
)); 
1151                         inm
->inm_st
[1].iss_ex
++; 
1152                 } else if (imf
->imf_st
[1] == MCAST_INCLUDE 
&& nsrc1 
> 0) { 
1153                         IGMP_PRINTF(("%s: in++ on inm at t1\n", __func__
)); 
1154                         inm
->inm_st
[1].iss_in
++; 
1159          * Track inm filter state in terms of listener counts. 
1160          * If there are any exclusive listeners, stack-wide 
1161          * membership is exclusive. 
1162          * Otherwise, if only inclusive listeners, stack-wide is inclusive. 
1163          * If no listeners remain, state is undefined at t1, 
1164          * and the IGMP lifecycle for this group should finish. 
1166         if (inm
->inm_st
[1].iss_ex 
> 0) { 
1167                 IGMP_PRINTF(("%s: transition to EX\n", __func__
)); 
1168                 inm
->inm_st
[1].iss_fmode 
= MCAST_EXCLUDE
; 
1169         } else if (inm
->inm_st
[1].iss_in 
> 0) { 
1170                 IGMP_PRINTF(("%s: transition to IN\n", __func__
)); 
1171                 inm
->inm_st
[1].iss_fmode 
= MCAST_INCLUDE
; 
1173                 IGMP_PRINTF(("%s: transition to UNDEF\n", __func__
)); 
1174                 inm
->inm_st
[1].iss_fmode 
= MCAST_UNDEFINED
; 
1177         /* Decrement ASM listener count on transition out of ASM mode. */ 
1178         if (imf
->imf_st
[0] == MCAST_EXCLUDE 
&& nsrc0 
== 0) { 
1179                 if ((imf
->imf_st
[1] != MCAST_EXCLUDE
) || 
1180                     (imf
->imf_st
[1] == MCAST_EXCLUDE 
&& nsrc1 
> 0)) { 
1181                         IGMP_PRINTF(("%s: --asm on inm at t1\n", __func__
)); 
1182                         --inm
->inm_st
[1].iss_asm
; 
1186         /* Increment ASM listener count on transition to ASM mode. */ 
1187         if (imf
->imf_st
[1] == MCAST_EXCLUDE 
&& nsrc1 
== 0) { 
1188                 IGMP_PRINTF(("%s: asm++ on inm at t1\n", __func__
)); 
1189                 inm
->inm_st
[1].iss_asm
++; 
1192         IGMP_PRINTF(("%s: merged imf 0x%llx to inm 0x%llx\n", __func__
, 
1193             (uint64_t)VM_KERNEL_ADDRPERM(imf
), 
1194             (uint64_t)VM_KERNEL_ADDRPERM(inm
))); 
1199                 IGMP_PRINTF(("%s: sources changed; reaping\n", __func__
)); 
1206  * Mark an in_multi's filter set deltas as committed. 
1207  * Called by IGMP after a state change has been enqueued. 
1210 inm_commit(struct in_multi 
*inm
) 
1212         struct ip_msource       
*ims
; 
1214         INM_LOCK_ASSERT_HELD(inm
); 
1216         IGMP_PRINTF(("%s: commit inm 0x%llx\n", __func__
, 
1217             (uint64_t)VM_KERNEL_ADDRPERM(inm
))); 
1218         IGMP_PRINTF(("%s: pre commit:\n", __func__
)); 
1221         RB_FOREACH(ims
, ip_msource_tree
, &inm
->inm_srcs
) { 
1222                 ims
->ims_st
[0] = ims
->ims_st
[1]; 
1224         inm
->inm_st
[0] = inm
->inm_st
[1]; 
1228  * Reap unreferenced nodes from an in_multi's filter set. 
1231 inm_reap(struct in_multi 
*inm
) 
1233         struct ip_msource       
*ims
, *tims
; 
1235         INM_LOCK_ASSERT_HELD(inm
); 
1237         RB_FOREACH_SAFE(ims
, ip_msource_tree
, &inm
->inm_srcs
, tims
) { 
1238                 if (ims
->ims_st
[0].ex 
> 0 || ims
->ims_st
[0].in 
> 0 || 
1239                     ims
->ims_st
[1].ex 
> 0 || ims
->ims_st
[1].in 
> 0 || 
1242                 IGMP_PRINTF(("%s: free ims 0x%llx\n", __func__
, 
1243                     (uint64_t)VM_KERNEL_ADDRPERM(ims
))); 
1244                 RB_REMOVE(ip_msource_tree
, &inm
->inm_srcs
, ims
); 
1251  * Purge all source nodes from an in_multi's filter set. 
1254 inm_purge(struct in_multi 
*inm
) 
1256         struct ip_msource       
*ims
, *tims
; 
1258         INM_LOCK_ASSERT_HELD(inm
); 
1260         RB_FOREACH_SAFE(ims
, ip_msource_tree
, &inm
->inm_srcs
, tims
) { 
1261                 IGMP_PRINTF(("%s: free ims 0x%llx\n", __func__
, 
1262                     (uint64_t)VM_KERNEL_ADDRPERM(ims
))); 
1263                 RB_REMOVE(ip_msource_tree
, &inm
->inm_srcs
, ims
); 
1270  * Join a multicast group; real entry point. 
1272  * Only preserves atomicity at inm level. 
1273  * NOTE: imf argument cannot be const due to sys/tree.h limitations. 
1275  * If the IGMP downcall fails, the group is not joined, and an error 
1279 in_joingroup(struct ifnet 
*ifp
, const struct in_addr 
*gina
, 
1280     /*const*/ struct in_mfilter 
*imf
, struct in_multi 
**pinm
) 
1282         struct in_mfilter        timf
; 
1283         struct in_multi         
*inm 
= NULL
; 
1285         struct igmp_tparams      itp
; 
1287         IGMP_INET_PRINTF(*gina
, ("%s: join %s on 0x%llx(%s))\n", __func__
, 
1288             _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
))); 
1290         bzero(&itp
, sizeof (itp
)); 
1294          * If no imf was specified (i.e. kernel consumer), 
1295          * fake one up and assume it is an ASM join. 
1298                 imf_init(&timf
, MCAST_UNDEFINED
, MCAST_EXCLUDE
); 
1302         error 
= in_getmulti(ifp
, gina
, &inm
); 
1304                 IGMP_PRINTF(("%s: in_getmulti() failure\n", __func__
)); 
1308         IGMP_PRINTF(("%s: merge inm state\n", __func__
)); 
1311         error 
= inm_merge(inm
, imf
); 
1313                 IGMP_PRINTF(("%s: failed to merge inm state\n", __func__
)); 
1314                 goto out_inm_release
; 
1317         IGMP_PRINTF(("%s: doing igmp downcall\n", __func__
)); 
1318         error 
= igmp_change_state(inm
, &itp
); 
1320                 IGMP_PRINTF(("%s: failed to update source\n", __func__
)); 
1322                 goto out_inm_release
; 
1327                 IGMP_PRINTF(("%s: dropping ref on 0x%llx\n", __func__
, 
1328                     (uint64_t)VM_KERNEL_ADDRPERM(inm
))); 
1333                 *pinm 
= inm
;    /* keep refcount from in_getmulti() */ 
1336         /* schedule timer now that we've dropped the lock(s) */ 
1337         igmp_set_timeout(&itp
); 
1343  * Leave a multicast group; real entry point. 
1344  * All source filters will be expunged. 
1346  * Only preserves atomicity at inm level. 
1348  * Note: This is not the same as inm_release(*) as this function also 
1349  * makes a state change downcall into IGMP. 
1352 in_leavegroup(struct in_multi 
*inm
, /*const*/ struct in_mfilter 
*imf
) 
1354         struct in_mfilter        timf
; 
1356         struct igmp_tparams      itp
; 
1358         bzero(&itp
, sizeof (itp
)); 
1361         INM_LOCK_ASSERT_NOTHELD(inm
); 
1363         in_multihead_lock_exclusive(); 
1366         IGMP_INET_PRINTF(inm
->inm_addr
, 
1367             ("%s: leave inm 0x%llx, %s/%s%d, imf 0x%llx\n", __func__
, 
1368             (uint64_t)VM_KERNEL_ADDRPERM(inm
), _igmp_inet_buf
, 
1369             (inm_is_ifp_detached(inm
) ? "null" : inm
->inm_ifp
->if_name
), 
1370             inm
->inm_ifp
->if_unit
, (uint64_t)VM_KERNEL_ADDRPERM(imf
))); 
1373          * If no imf was specified (i.e. kernel consumer), 
1374          * fake one up and assume it is an ASM join. 
1377                 imf_init(&timf
, MCAST_EXCLUDE
, MCAST_UNDEFINED
); 
1382          * Begin state merge transaction at IGMP layer. 
1384          * As this particular invocation should not cause any memory 
1385          * to be allocated, and there is no opportunity to roll back 
1386          * the transaction, it MUST NOT fail. 
1388         IGMP_PRINTF(("%s: merge inm state\n", __func__
)); 
1390         error 
= inm_merge(inm
, imf
); 
1391         KASSERT(error 
== 0, ("%s: failed to merge inm state\n", __func__
)); 
1393         IGMP_PRINTF(("%s: doing igmp downcall\n", __func__
)); 
1394         error 
= igmp_change_state(inm
, &itp
); 
1397                 IGMP_PRINTF(("%s: failed igmp downcall\n", __func__
)); 
1399         lastref 
= in_multi_detach(inm
); 
1400         VERIFY(!lastref 
|| (!(inm
->inm_debug 
& IFD_ATTACHED
) && 
1401             inm
->inm_reqcnt 
== 0)); 
1403         in_multihead_lock_done(); 
1406                 INM_REMREF(inm
);        /* for in_multihead list */ 
1408         /* schedule timer now that we've dropped the lock(s) */ 
1409         igmp_set_timeout(&itp
); 
1415  * Join an IPv4 multicast group in (*,G) exclusive mode. 
1416  * The group must be a 224.0.0.0/24 link-scope group. 
1417  * This KPI is for legacy kernel consumers only. 
1420 in_addmulti(struct in_addr 
*ap
, struct ifnet 
*ifp
) 
1422         struct in_multi 
*pinm 
= NULL
; 
1425         KASSERT(IN_LOCAL_GROUP(ntohl(ap
->s_addr
)), 
1426             ("%s: %s not in 224.0.0.0/24\n", __func__
, inet_ntoa(*ap
))); 
1428         error 
= in_joingroup(ifp
, ap
, NULL
, &pinm
); 
1429         VERIFY(pinm 
!= NULL 
|| error 
!= 0); 
1435  * Leave an IPv4 multicast group, assumed to be in exclusive (*,G) mode. 
1436  * This KPI is for legacy kernel consumers only. 
1439 in_delmulti(struct in_multi 
*inm
) 
1442         (void) in_leavegroup(inm
, NULL
); 
1446  * Block or unblock an ASM multicast source on an inpcb. 
1447  * This implements the delta-based API described in RFC 3678. 
1449  * The delta-based API applies only to exclusive-mode memberships. 
1450  * An IGMP downcall will be performed. 
1452  * Return 0 if successful, otherwise return an appropriate error code. 
1455 inp_block_unblock_source(struct inpcb 
*inp
, struct sockopt 
*sopt
) 
1457         struct group_source_req          gsr
; 
1458         sockunion_t                     
*gsa
, *ssa
; 
1460         struct in_mfilter               
*imf
; 
1461         struct ip_moptions              
*imo
; 
1462         struct in_msource               
*ims
; 
1463         struct in_multi                 
*inm
; 
1467         unsigned int                     ifindex 
= 0; 
1468         struct igmp_tparams              itp
; 
1470         bzero(&itp
, sizeof (itp
)); 
1475         memset(&gsr
, 0, sizeof(struct group_source_req
)); 
1476         gsa 
= (sockunion_t 
*)&gsr
.gsr_group
; 
1477         ssa 
= (sockunion_t 
*)&gsr
.gsr_source
; 
1479         switch (sopt
->sopt_name
) { 
1480         case IP_BLOCK_SOURCE
: 
1481         case IP_UNBLOCK_SOURCE
: { 
1482                 struct ip_mreq_source    mreqs
; 
1484                 error 
= sooptcopyin(sopt
, &mreqs
, 
1485                     sizeof(struct ip_mreq_source
), 
1486                     sizeof(struct ip_mreq_source
)); 
1490                 gsa
->sin
.sin_family 
= AF_INET
; 
1491                 gsa
->sin
.sin_len 
= sizeof(struct sockaddr_in
); 
1492                 gsa
->sin
.sin_addr 
= mreqs
.imr_multiaddr
; 
1494                 ssa
->sin
.sin_family 
= AF_INET
; 
1495                 ssa
->sin
.sin_len 
= sizeof(struct sockaddr_in
); 
1496                 ssa
->sin
.sin_addr 
= mreqs
.imr_sourceaddr
; 
1498                 if (!in_nullhost(mreqs
.imr_interface
)) 
1499                         ifp 
= ip_multicast_if(&mreqs
.imr_interface
, &ifindex
); 
1501                 if (sopt
->sopt_name 
== IP_BLOCK_SOURCE
) 
1504                 IGMP_INET_PRINTF(mreqs
.imr_interface
, 
1505                     ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__
, 
1506                     _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
))); 
1510         case MCAST_BLOCK_SOURCE
: 
1511         case MCAST_UNBLOCK_SOURCE
: 
1512                 error 
= sooptcopyin(sopt
, &gsr
, 
1513                     sizeof(struct group_source_req
), 
1514                     sizeof(struct group_source_req
)); 
1518                 if (gsa
->sin
.sin_family 
!= AF_INET 
|| 
1519                     gsa
->sin
.sin_len 
!= sizeof(struct sockaddr_in
)) 
1522                 if (ssa
->sin
.sin_family 
!= AF_INET 
|| 
1523                     ssa
->sin
.sin_len 
!= sizeof(struct sockaddr_in
)) 
1526                 ifnet_head_lock_shared(); 
1527                 if (gsr
.gsr_interface 
== 0 || 
1528                     (u_int
)if_index 
< gsr
.gsr_interface
) { 
1530                         return (EADDRNOTAVAIL
); 
1533                 ifp 
= ifindex2ifnet
[gsr
.gsr_interface
]; 
1537                         return (EADDRNOTAVAIL
); 
1539                 if (sopt
->sopt_name 
== MCAST_BLOCK_SOURCE
) 
1544                 IGMP_PRINTF(("%s: unknown sopt_name %d\n", 
1545                     __func__
, sopt
->sopt_name
)); 
1546                 return (EOPNOTSUPP
); 
1550         if (!IN_MULTICAST(ntohl(gsa
->sin
.sin_addr
.s_addr
))) 
1554          * Check if we are actually a member of this group. 
1556         imo 
= inp_findmoptions(inp
); 
1561         idx 
= imo_match_group(imo
, ifp
, &gsa
->sa
); 
1562         if (idx 
== (size_t)-1 || imo
->imo_mfilters 
== NULL
) { 
1563                 error 
= EADDRNOTAVAIL
; 
1564                 goto out_imo_locked
; 
1567         VERIFY(imo
->imo_mfilters 
!= NULL
); 
1568         imf 
= &imo
->imo_mfilters
[idx
]; 
1569         inm 
= imo
->imo_membership
[idx
]; 
1572          * Attempting to use the delta-based API on an 
1573          * non exclusive-mode membership is an error. 
1575         fmode 
= imf
->imf_st
[0]; 
1576         if (fmode 
!= MCAST_EXCLUDE
) { 
1578                 goto out_imo_locked
; 
1582          * Deal with error cases up-front: 
1583          *  Asked to block, but already blocked; or 
1584          *  Asked to unblock, but nothing to unblock. 
1585          * If adding a new block entry, allocate it. 
1587         ims 
= imo_match_source(imo
, idx
, &ssa
->sa
); 
1588         if ((ims 
!= NULL 
&& doblock
) || (ims 
== NULL 
&& !doblock
)) { 
1589                 IGMP_INET_PRINTF(ssa
->sin
.sin_addr
, 
1590                     ("%s: source %s %spresent\n", __func__
, 
1591                     _igmp_inet_buf
, doblock 
? "" : "not ")); 
1592                 error 
= EADDRNOTAVAIL
; 
1593                 goto out_imo_locked
; 
1597          * Begin state merge transaction at socket layer. 
1600                 IGMP_PRINTF(("%s: %s source\n", __func__
, "block")); 
1601                 ims 
= imf_graft(imf
, fmode
, &ssa
->sin
); 
1605                 IGMP_PRINTF(("%s: %s source\n", __func__
, "allow")); 
1606                 error 
= imf_prune(imf
, &ssa
->sin
); 
1610                 IGMP_PRINTF(("%s: merge imf state failed\n", __func__
)); 
1611                 goto out_imf_rollback
; 
1615          * Begin state merge transaction at IGMP layer. 
1618         IGMP_PRINTF(("%s: merge inm state\n", __func__
)); 
1619         error 
= inm_merge(inm
, imf
); 
1621                 IGMP_PRINTF(("%s: failed to merge inm state\n", __func__
)); 
1623                 goto out_imf_rollback
; 
1626         IGMP_PRINTF(("%s: doing igmp downcall\n", __func__
)); 
1627         error 
= igmp_change_state(inm
, &itp
); 
1631                 IGMP_PRINTF(("%s: failed igmp downcall\n", __func__
)); 
1644         IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
1646         /* schedule timer now that we've dropped the lock(s) */ 
1647         igmp_set_timeout(&itp
); 
1653  * Given an inpcb, return its multicast options structure pointer. 
1655  * Caller is responsible for locking the inpcb, and releasing the 
1656  * extra reference held on the imo, upon a successful return. 
1658 static struct ip_moptions 
* 
1659 inp_findmoptions(struct inpcb 
*inp
) 
1661         struct ip_moptions       
*imo
; 
1662         struct in_multi         
**immp
; 
1663         struct in_mfilter        
*imfp
; 
1666         if ((imo 
= inp
->inp_moptions
) != NULL
) { 
1667                 IMO_ADDREF(imo
);        /* for caller */ 
1671         imo 
= ip_allocmoptions(M_WAITOK
); 
1675         immp 
= _MALLOC(sizeof (*immp
) * IP_MIN_MEMBERSHIPS
, M_IPMOPTS
, 
1682         imfp 
= _MALLOC(sizeof (struct in_mfilter
) * IP_MIN_MEMBERSHIPS
, 
1683             M_INMFILTER
, M_WAITOK 
| M_ZERO
); 
1685                 _FREE(immp
, M_IPMOPTS
); 
1690         imo
->imo_multicast_ifp 
= NULL
; 
1691         imo
->imo_multicast_addr
.s_addr 
= INADDR_ANY
; 
1692         imo
->imo_multicast_vif 
= -1; 
1693         imo
->imo_multicast_ttl 
= IP_DEFAULT_MULTICAST_TTL
; 
1694         imo
->imo_multicast_loop 
= in_mcast_loop
; 
1695         imo
->imo_num_memberships 
= 0; 
1696         imo
->imo_max_memberships 
= IP_MIN_MEMBERSHIPS
; 
1697         imo
->imo_membership 
= immp
; 
1699         /* Initialize per-group source filters. */ 
1700         for (idx 
= 0; idx 
< IP_MIN_MEMBERSHIPS
; idx
++) 
1701                 imf_init(&imfp
[idx
], MCAST_UNDEFINED
, MCAST_EXCLUDE
); 
1703         imo
->imo_mfilters 
= imfp
; 
1704         inp
->inp_moptions 
= imo
; /* keep reference from ip_allocmoptions() */ 
1705         IMO_ADDREF(imo
);        /* for caller */ 
1710  * Atomically get source filters on a socket for an IPv4 multicast group. 
1713 inp_get_source_filters(struct inpcb 
*inp
, struct sockopt 
*sopt
) 
1715         struct __msfilterreq64  msfr
, msfr64
; 
1716         struct __msfilterreq32  msfr32
; 
1719         struct ip_moptions      
*imo
; 
1720         struct in_mfilter       
*imf
; 
1721         struct ip_msource       
*ims
; 
1722         struct in_msource       
*lims
; 
1723         struct sockaddr_in      
*psin
; 
1724         struct sockaddr_storage 
*ptss
; 
1725         struct sockaddr_storage 
*tss
; 
1727         size_t                   idx
, nsrcs
, ncsrcs
; 
1728         user_addr_t              tmp_ptr
; 
1730         imo 
= inp
->inp_moptions
; 
1731         VERIFY(imo 
!= NULL
); 
1733         if (IS_64BIT_PROCESS(current_proc())) { 
1734                 error 
= sooptcopyin(sopt
, &msfr64
, 
1735                     sizeof(struct __msfilterreq64
), 
1736                     sizeof(struct __msfilterreq64
)); 
1739                 /* we never use msfr.msfr_srcs; */ 
1740                 memcpy(&msfr
, &msfr64
, sizeof(msfr
)); 
1742                 error 
= sooptcopyin(sopt
, &msfr32
, 
1743                     sizeof(struct __msfilterreq32
), 
1744                     sizeof(struct __msfilterreq32
)); 
1747                 /* we never use msfr.msfr_srcs; */ 
1748                 memcpy(&msfr
, &msfr32
, sizeof(msfr
)); 
1751         ifnet_head_lock_shared(); 
1752         if (msfr
.msfr_ifindex 
== 0 || (u_int
)if_index 
< msfr
.msfr_ifindex
) { 
1754                 return (EADDRNOTAVAIL
); 
1757         ifp 
= ifindex2ifnet
[msfr
.msfr_ifindex
]; 
1761                 return (EADDRNOTAVAIL
); 
1763         if ((size_t) msfr
.msfr_nsrcs 
> 
1764             UINT32_MAX 
/ sizeof(struct sockaddr_storage
)) 
1765                 msfr
.msfr_nsrcs 
= UINT32_MAX 
/ sizeof(struct sockaddr_storage
); 
1767         if (msfr
.msfr_nsrcs 
> in_mcast_maxsocksrc
) 
1768                 msfr
.msfr_nsrcs 
= in_mcast_maxsocksrc
; 
1772          * Lookup group on the socket. 
1774         gsa 
= (sockunion_t 
*)&msfr
.msfr_group
; 
1775         idx 
= imo_match_group(imo
, ifp
, &gsa
->sa
); 
1776         if (idx 
== (size_t)-1 || imo
->imo_mfilters 
== NULL
) { 
1778                 return (EADDRNOTAVAIL
); 
1780         imf 
= &imo
->imo_mfilters
[idx
]; 
1783          * Ignore memberships which are in limbo. 
1785         if (imf
->imf_st
[1] == MCAST_UNDEFINED
) { 
1789         msfr
.msfr_fmode 
= imf
->imf_st
[1]; 
1792          * If the user specified a buffer, copy out the source filter 
1793          * entries to userland gracefully. 
1794          * We only copy out the number of entries which userland 
1795          * has asked for, but we always tell userland how big the 
1796          * buffer really needs to be. 
1799         if (IS_64BIT_PROCESS(current_proc()))  
1800                 tmp_ptr 
= msfr64
.msfr_srcs
; 
1802                 tmp_ptr 
= CAST_USER_ADDR_T(msfr32
.msfr_srcs
); 
1805         if (tmp_ptr 
!= USER_ADDR_NULL 
&& msfr
.msfr_nsrcs 
> 0) { 
1806                 tss 
= _MALLOC((size_t) msfr
.msfr_nsrcs 
* sizeof(*tss
), 
1807                     M_TEMP
, M_WAITOK 
| M_ZERO
); 
1812                 bzero(tss
, (size_t) msfr
.msfr_nsrcs 
* sizeof(*tss
)); 
1816          * Count number of sources in-mode at t0. 
1817          * If buffer space exists and remains, copy out source entries. 
1819         nsrcs 
= msfr
.msfr_nsrcs
; 
1822         RB_FOREACH(ims
, ip_msource_tree
, &imf
->imf_sources
) { 
1823                 lims 
= (struct in_msource 
*)ims
; 
1824                 if (lims
->imsl_st
[0] == MCAST_UNDEFINED 
|| 
1825                     lims
->imsl_st
[0] != imf
->imf_st
[0]) 
1827                 if (tss 
!= NULL 
&& nsrcs 
> 0) { 
1828                         psin 
= (struct sockaddr_in 
*)ptss
; 
1829                         psin
->sin_family 
= AF_INET
; 
1830                         psin
->sin_len 
= sizeof(struct sockaddr_in
); 
1831                         psin
->sin_addr
.s_addr 
= htonl(lims
->ims_haddr
); 
1842                 error 
= copyout(tss
, tmp_ptr
, ncsrcs 
* sizeof(*tss
)); 
1848         msfr
.msfr_nsrcs 
= ncsrcs
; 
1849         if (IS_64BIT_PROCESS(current_proc())) { 
1850                 msfr64
.msfr_ifindex 
= msfr
.msfr_ifindex
; 
1851                 msfr64
.msfr_fmode   
= msfr
.msfr_fmode
; 
1852                 msfr64
.msfr_nsrcs   
= msfr
.msfr_nsrcs
; 
1853                 memcpy(&msfr64
.msfr_group
, &msfr
.msfr_group
, 
1854                     sizeof(struct sockaddr_storage
)); 
1855                 error 
= sooptcopyout(sopt
, &msfr64
, 
1856                     sizeof(struct __msfilterreq64
)); 
1858                 msfr32
.msfr_ifindex 
= msfr
.msfr_ifindex
; 
1859                 msfr32
.msfr_fmode   
= msfr
.msfr_fmode
; 
1860                 msfr32
.msfr_nsrcs   
= msfr
.msfr_nsrcs
; 
1861                 memcpy(&msfr64
.msfr_group
, &msfr
.msfr_group
, 
1862                     sizeof(struct sockaddr_storage
)); 
1863                 error 
= sooptcopyout(sopt
, &msfr32
, 
1864                     sizeof(struct __msfilterreq32
)); 
1871  * Return the IP multicast options in response to user getsockopt(). 
1874 inp_getmoptions(struct inpcb 
*inp
, struct sockopt 
*sopt
) 
1876         struct ip_mreqn          mreqn
; 
1877         struct ip_moptions      
*imo
; 
1879         struct in_ifaddr        
*ia
; 
1881         unsigned int             ifindex
; 
1884         imo 
= inp
->inp_moptions
; 
1886          * If socket is neither of type SOCK_RAW or SOCK_DGRAM, 
1887          * or is a divert socket, reject it. 
1889         if (SOCK_PROTO(inp
->inp_socket
) == IPPROTO_DIVERT 
|| 
1890             (SOCK_TYPE(inp
->inp_socket
) != SOCK_RAW 
&& 
1891             SOCK_TYPE(inp
->inp_socket
) != SOCK_DGRAM
)) { 
1892                 return (EOPNOTSUPP
); 
1896         switch (sopt
->sopt_name
) { 
1897         case IP_MULTICAST_IF
: 
1898                 memset(&mreqn
, 0, sizeof(struct ip_mreqn
)); 
1901                         ifp 
= imo
->imo_multicast_ifp
; 
1902                         if (!in_nullhost(imo
->imo_multicast_addr
)) { 
1903                                 mreqn
.imr_address 
= imo
->imo_multicast_addr
; 
1904                         } else if (ifp 
!= NULL
) { 
1905                                 mreqn
.imr_ifindex 
= ifp
->if_index
; 
1908                                         IFA_LOCK_SPIN(&ia
->ia_ifa
); 
1910                                             IA_SIN(ia
)->sin_addr
; 
1911                                         IFA_UNLOCK(&ia
->ia_ifa
); 
1912                                         IFA_REMREF(&ia
->ia_ifa
); 
1917                 if (sopt
->sopt_valsize 
== sizeof(struct ip_mreqn
)) { 
1918                         error 
= sooptcopyout(sopt
, &mreqn
, 
1919                             sizeof(struct ip_mreqn
)); 
1921                         error 
= sooptcopyout(sopt
, &mreqn
.imr_address
, 
1922                             sizeof(struct in_addr
)); 
1926         case IP_MULTICAST_IFINDEX
: 
1929                 if (imo 
== NULL 
|| imo
->imo_multicast_ifp 
== NULL
) { 
1932                         ifindex 
= imo
->imo_multicast_ifp
->if_index
; 
1936                 error 
= sooptcopyout(sopt
, &ifindex
, sizeof (ifindex
)); 
1939         case IP_MULTICAST_TTL
: 
1941                         optval 
= coptval 
= IP_DEFAULT_MULTICAST_TTL
; 
1944                         optval 
= coptval 
= imo
->imo_multicast_ttl
; 
1947                 if (sopt
->sopt_valsize 
== sizeof(u_char
)) 
1948                         error 
= sooptcopyout(sopt
, &coptval
, sizeof(u_char
)); 
1950                         error 
= sooptcopyout(sopt
, &optval
, sizeof(int)); 
1953         case IP_MULTICAST_LOOP
: 
1955                         optval 
= coptval 
= IP_DEFAULT_MULTICAST_LOOP
; 
1958                         optval 
= coptval 
= imo
->imo_multicast_loop
; 
1961                 if (sopt
->sopt_valsize 
== sizeof(u_char
)) 
1962                         error 
= sooptcopyout(sopt
, &coptval
, sizeof(u_char
)); 
1964                         error 
= sooptcopyout(sopt
, &optval
, sizeof(int)); 
1969                         error 
= EADDRNOTAVAIL
; 
1971                         error 
= inp_get_source_filters(inp
, sopt
); 
1976                 error 
= ENOPROTOOPT
; 
1984  * Look up the ifnet to use for a multicast group membership, 
1985  * given the IPv4 address of an interface, and the IPv4 group address. 
1987  * This routine exists to support legacy multicast applications 
1988  * which do not understand that multicast memberships are scoped to 
1989  * specific physical links in the networking stack, or which need 
1990  * to join link-scope groups before IPv4 addresses are configured. 
1992  * If inp is non-NULL and is bound to an interface, use this socket's 
1993  * inp_boundif for any required routing table lookup. 
1995  * If the route lookup fails, attempt to use the first non-loopback 
1996  * interface with multicast capability in the system as a 
1997  * last resort. The legacy IPv4 ASM API requires that we do 
1998  * this in order to allow groups to be joined when the routing 
1999  * table has not yet been populated during boot. 
2001  * Returns NULL if no ifp could be found. 
2004 static struct ifnet 
* 
2005 inp_lookup_mcast_ifp(const struct inpcb 
*inp
, 
2006     const struct sockaddr_in 
*gsin
, const struct in_addr ina
) 
2009         unsigned int     ifindex 
= 0; 
2011         VERIFY(gsin
->sin_family 
== AF_INET
); 
2012         VERIFY(IN_MULTICAST(ntohl(gsin
->sin_addr
.s_addr
))); 
2015         if (!in_nullhost(ina
)) { 
2016                 struct in_addr new_ina
; 
2017                 memcpy(&new_ina
, &ina
, sizeof(struct in_addr
)); 
2018                 ifp 
= ip_multicast_if(&new_ina
, &ifindex
); 
2021                 unsigned int ifscope 
= IFSCOPE_NONE
; 
2023                 if (inp 
!= NULL 
&& (inp
->inp_flags 
& INP_BOUND_IF
)) 
2024                         ifscope 
= inp
->inp_boundifp
->if_index
; 
2026                 bzero(&ro
, sizeof (ro
)); 
2027                 memcpy(&ro
.ro_dst
, gsin
, sizeof(struct sockaddr_in
)); 
2028                 rtalloc_scoped_ign(&ro
, 0, ifscope
); 
2029                 if (ro
.ro_rt 
!= NULL
) { 
2030                         ifp 
= ro
.ro_rt
->rt_ifp
; 
2031                         VERIFY(ifp 
!= NULL
); 
2033                         struct in_ifaddr 
*ia
; 
2037                         lck_rw_lock_shared(in_ifaddr_rwlock
); 
2038                         TAILQ_FOREACH(ia
, &in_ifaddrhead
, ia_link
) { 
2039                                 IFA_LOCK_SPIN(&ia
->ia_ifa
); 
2041                                 IFA_UNLOCK(&ia
->ia_ifa
); 
2042                                 if (!(mifp
->if_flags 
& IFF_LOOPBACK
) && 
2043                                      (mifp
->if_flags 
& IFF_MULTICAST
)) { 
2048                         lck_rw_done(in_ifaddr_rwlock
); 
2057  * Join an IPv4 multicast group, possibly with a source. 
2059  * NB: sopt->sopt_val might point to the kernel address space. This means that 
2060  * we were called by the IPv6 stack due to the presence of an IPv6 v4 mapped 
2061  * address. In this scenario, sopt_p points to kernproc and sooptcopyin() will 
2062  * just issue an in-kernel memcpy. 
2065 inp_join_group(struct inpcb 
*inp
, struct sockopt 
*sopt
) 
2067         struct group_source_req          gsr
; 
2068         sockunion_t                     
*gsa
, *ssa
; 
2070         struct in_mfilter               
*imf
; 
2071         struct ip_moptions              
*imo
; 
2072         struct in_multi                 
*inm 
= NULL
; 
2073         struct in_msource               
*lims
; 
2076         struct igmp_tparams              itp
; 
2078         bzero(&itp
, sizeof (itp
)); 
2084         memset(&gsr
, 0, sizeof(struct group_source_req
)); 
2085         gsa 
= (sockunion_t 
*)&gsr
.gsr_group
; 
2086         gsa
->ss
.ss_family 
= AF_UNSPEC
; 
2087         ssa 
= (sockunion_t 
*)&gsr
.gsr_source
; 
2088         ssa
->ss
.ss_family 
= AF_UNSPEC
; 
2090         switch (sopt
->sopt_name
) { 
2091         case IP_ADD_MEMBERSHIP
: 
2092         case IP_ADD_SOURCE_MEMBERSHIP
: { 
2093                 struct ip_mreq_source    mreqs
; 
2095                 if (sopt
->sopt_name 
== IP_ADD_MEMBERSHIP
) { 
2096                         error 
= sooptcopyin(sopt
, &mreqs
, 
2097                             sizeof(struct ip_mreq
), 
2098                             sizeof(struct ip_mreq
)); 
2100                          * Do argument switcharoo from ip_mreq into 
2101                          * ip_mreq_source to avoid using two instances. 
2103                         mreqs
.imr_interface 
= mreqs
.imr_sourceaddr
; 
2104                         mreqs
.imr_sourceaddr
.s_addr 
= INADDR_ANY
; 
2105                 } else if (sopt
->sopt_name 
== IP_ADD_SOURCE_MEMBERSHIP
) { 
2106                         error 
= sooptcopyin(sopt
, &mreqs
, 
2107                             sizeof(struct ip_mreq_source
), 
2108                             sizeof(struct ip_mreq_source
)); 
2111                         IGMP_PRINTF(("%s: error copyin IP_ADD_MEMBERSHIP/" 
2112                             "IP_ADD_SOURCE_MEMBERSHIP %d err=%d\n", 
2113                             __func__
, sopt
->sopt_name
, error
)); 
2117                 gsa
->sin
.sin_family 
= AF_INET
; 
2118                 gsa
->sin
.sin_len 
= sizeof(struct sockaddr_in
); 
2119                 gsa
->sin
.sin_addr 
= mreqs
.imr_multiaddr
; 
2121                 if (sopt
->sopt_name 
== IP_ADD_SOURCE_MEMBERSHIP
) { 
2122                         ssa
->sin
.sin_family 
= AF_INET
; 
2123                         ssa
->sin
.sin_len 
= sizeof(struct sockaddr_in
); 
2124                         ssa
->sin
.sin_addr 
= mreqs
.imr_sourceaddr
; 
2127                 if (!IN_MULTICAST(ntohl(gsa
->sin
.sin_addr
.s_addr
))) 
2130                 ifp 
= inp_lookup_mcast_ifp(inp
, &gsa
->sin
, 
2131                     mreqs
.imr_interface
); 
2132                 IGMP_INET_PRINTF(mreqs
.imr_interface
, 
2133                     ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__
, 
2134                     _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
))); 
2138         case MCAST_JOIN_GROUP
: 
2139         case MCAST_JOIN_SOURCE_GROUP
: 
2140                 if (sopt
->sopt_name 
== MCAST_JOIN_GROUP
) { 
2141                         error 
= sooptcopyin(sopt
, &gsr
, 
2142                             sizeof(struct group_req
), 
2143                             sizeof(struct group_req
)); 
2144                 } else if (sopt
->sopt_name 
== MCAST_JOIN_SOURCE_GROUP
) { 
2145                         error 
= sooptcopyin(sopt
, &gsr
, 
2146                             sizeof(struct group_source_req
), 
2147                             sizeof(struct group_source_req
)); 
2152                 if (gsa
->sin
.sin_family 
!= AF_INET 
|| 
2153                     gsa
->sin
.sin_len 
!= sizeof(struct sockaddr_in
)) 
2157                  * Overwrite the port field if present, as the sockaddr 
2158                  * being copied in may be matched with a binary comparison. 
2160                 gsa
->sin
.sin_port 
= 0; 
2161                 if (sopt
->sopt_name 
== MCAST_JOIN_SOURCE_GROUP
) { 
2162                         if (ssa
->sin
.sin_family 
!= AF_INET 
|| 
2163                             ssa
->sin
.sin_len 
!= sizeof(struct sockaddr_in
)) 
2165                         ssa
->sin
.sin_port 
= 0; 
2168                 if (!IN_MULTICAST(ntohl(gsa
->sin
.sin_addr
.s_addr
))) 
2171                 ifnet_head_lock_shared(); 
2172                 if (gsr
.gsr_interface 
== 0 || 
2173                     (u_int
)if_index 
< gsr
.gsr_interface
) { 
2175                         return (EADDRNOTAVAIL
); 
2177                 ifp 
= ifindex2ifnet
[gsr
.gsr_interface
]; 
2183                 IGMP_PRINTF(("%s: unknown sopt_name %d\n", 
2184                     __func__
, sopt
->sopt_name
)); 
2185                 return (EOPNOTSUPP
); 
2189         if (ifp 
== NULL 
|| (ifp
->if_flags 
& IFF_MULTICAST
) == 0) 
2190                 return (EADDRNOTAVAIL
); 
2192         imo 
= inp_findmoptions(inp
); 
2197         idx 
= imo_match_group(imo
, ifp
, &gsa
->sa
); 
2198         if (idx 
== (size_t)-1) { 
2201                 inm 
= imo
->imo_membership
[idx
]; 
2202                 imf 
= &imo
->imo_mfilters
[idx
]; 
2203                 if (ssa
->ss
.ss_family 
!= AF_UNSPEC
) { 
2205                          * MCAST_JOIN_SOURCE_GROUP on an exclusive membership 
2206                          * is an error. On an existing inclusive membership, 
2207                          * it just adds the source to the filter list. 
2209                         if (imf
->imf_st
[1] != MCAST_INCLUDE
) { 
2211                                 goto out_imo_locked
; 
2214                          * Throw out duplicates. 
2216                          * XXX FIXME: This makes a naive assumption that 
2217                          * even if entries exist for *ssa in this imf, 
2218                          * they will be rejected as dupes, even if they 
2219                          * are not valid in the current mode (in-mode). 
2221                          * in_msource is transactioned just as for anything 
2222                          * else in SSM -- but note naive use of inm_graft() 
2223                          * below for allocating new filter entries. 
2225                          * This is only an issue if someone mixes the 
2226                          * full-state SSM API with the delta-based API, 
2227                          * which is discouraged in the relevant RFCs. 
2229                         lims 
= imo_match_source(imo
, idx
, &ssa
->sa
); 
2230                         if (lims 
!= NULL 
/*&& 
2231                             lims->imsl_st[1] == MCAST_INCLUDE*/) { 
2232                                 error 
= EADDRNOTAVAIL
; 
2233                                 goto out_imo_locked
; 
2237                          * MCAST_JOIN_GROUP on an existing exclusive 
2238                          * membership is an error; return EADDRINUSE 
2239                          * to preserve 4.4BSD API idempotence, and 
2240                          * avoid tedious detour to code below. 
2241                          * NOTE: This is bending RFC 3678 a bit. 
2243                          * On an existing inclusive membership, this is also 
2244                          * an error; if you want to change filter mode, 
2245                          * you must use the userland API setsourcefilter(). 
2246                          * XXX We don't reject this for imf in UNDEFINED 
2247                          * state at t1, because allocation of a filter 
2248                          * is atomic with allocation of a membership. 
2251                         /* See comments above for EADDRINUSE */ 
2252                         if (imf
->imf_st
[1] == MCAST_EXCLUDE
) 
2254                         goto out_imo_locked
; 
2259          * Begin state merge transaction at socket layer. 
2263                 if (imo
->imo_num_memberships 
== imo
->imo_max_memberships
) { 
2264                         error 
= imo_grow(imo
, 0); 
2266                                 goto out_imo_locked
; 
2269                  * Allocate the new slot upfront so we can deal with 
2270                  * grafting the new source filter in same code path 
2271                  * as for join-source on existing membership. 
2273                 idx 
= imo
->imo_num_memberships
; 
2274                 imo
->imo_membership
[idx
] = NULL
; 
2275                 imo
->imo_num_memberships
++; 
2276                 VERIFY(imo
->imo_mfilters 
!= NULL
); 
2277                 imf 
= &imo
->imo_mfilters
[idx
]; 
2278                 VERIFY(RB_EMPTY(&imf
->imf_sources
)); 
2282          * Graft new source into filter list for this inpcb's 
2283          * membership of the group. The in_multi may not have 
2284          * been allocated yet if this is a new membership, however, 
2285          * the in_mfilter slot will be allocated and must be initialized. 
2287         if (ssa
->ss
.ss_family 
!= AF_UNSPEC
) { 
2288                 /* Membership starts in IN mode */ 
2290                         IGMP_PRINTF(("%s: new join w/source\n", __func__
)); 
2291                         imf_init(imf
, MCAST_UNDEFINED
, MCAST_INCLUDE
); 
2293                         IGMP_PRINTF(("%s: %s source\n", __func__
, "allow")); 
2295                 lims 
= imf_graft(imf
, MCAST_INCLUDE
, &ssa
->sin
); 
2297                         IGMP_PRINTF(("%s: merge imf state failed\n", 
2303                 /* No address specified; Membership starts in EX mode */ 
2305                         IGMP_PRINTF(("%s: new join w/o source\n", __func__
)); 
2306                         imf_init(imf
, MCAST_UNDEFINED
, MCAST_EXCLUDE
); 
2311          * Begin state merge transaction at IGMP layer. 
2315                 VERIFY(inm 
== NULL
); 
2316                 error 
= in_joingroup(ifp
, &gsa
->sin
.sin_addr
, imf
, &inm
); 
2317                 VERIFY(inm 
!= NULL 
|| error 
!= 0); 
2320                 imo
->imo_membership
[idx
] = inm
; /* from in_joingroup() */ 
2322                 IGMP_PRINTF(("%s: merge inm state\n", __func__
)); 
2324                 error 
= inm_merge(inm
, imf
); 
2326                         IGMP_PRINTF(("%s: failed to merge inm state\n", 
2329                         goto out_imf_rollback
; 
2331                 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__
)); 
2332                 error 
= igmp_change_state(inm
, &itp
); 
2335                         IGMP_PRINTF(("%s: failed igmp downcall\n", 
2337                         goto out_imf_rollback
; 
2353         if (error 
&& is_new
) { 
2354                 VERIFY(inm 
== NULL
); 
2355                 imo
->imo_membership
[idx
] = NULL
; 
2356                 --imo
->imo_num_memberships
; 
2361         IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
2363         /* schedule timer now that we've dropped the lock(s) */ 
2364         igmp_set_timeout(&itp
); 
2370  * Leave an IPv4 multicast group on an inpcb, possibly with a source. 
2372  * NB: sopt->sopt_val might point to the kernel address space. Refer to the 
2373  * block comment on top of inp_join_group() for more information. 
2376 inp_leave_group(struct inpcb 
*inp
, struct sockopt 
*sopt
) 
2378         struct group_source_req          gsr
; 
2379         struct ip_mreq_source            mreqs
; 
2380         sockunion_t                     
*gsa
, *ssa
; 
2382         struct in_mfilter               
*imf
; 
2383         struct ip_moptions              
*imo
; 
2384         struct in_msource               
*ims
; 
2385         struct in_multi                 
*inm 
= NULL
; 
2387         int                              error
, is_final
; 
2388         unsigned int                     ifindex 
= 0; 
2389         struct igmp_tparams              itp
; 
2391         bzero(&itp
, sizeof (itp
)); 
2396         memset(&gsr
, 0, sizeof(struct group_source_req
)); 
2397         gsa 
= (sockunion_t 
*)&gsr
.gsr_group
; 
2398         gsa
->ss
.ss_family 
= AF_UNSPEC
; 
2399         ssa 
= (sockunion_t 
*)&gsr
.gsr_source
; 
2400         ssa
->ss
.ss_family 
= AF_UNSPEC
; 
2402         switch (sopt
->sopt_name
) { 
2403         case IP_DROP_MEMBERSHIP
: 
2404         case IP_DROP_SOURCE_MEMBERSHIP
: 
2405                 if (sopt
->sopt_name 
== IP_DROP_MEMBERSHIP
) { 
2406                         error 
= sooptcopyin(sopt
, &mreqs
, 
2407                             sizeof(struct ip_mreq
), 
2408                             sizeof(struct ip_mreq
)); 
2410                          * Swap interface and sourceaddr arguments, 
2411                          * as ip_mreq and ip_mreq_source are laid 
2414                         mreqs
.imr_interface 
= mreqs
.imr_sourceaddr
; 
2415                         mreqs
.imr_sourceaddr
.s_addr 
= INADDR_ANY
; 
2416                 } else if (sopt
->sopt_name 
== IP_DROP_SOURCE_MEMBERSHIP
) { 
2417                         error 
= sooptcopyin(sopt
, &mreqs
, 
2418                             sizeof(struct ip_mreq_source
), 
2419                             sizeof(struct ip_mreq_source
)); 
2424                 gsa
->sin
.sin_family 
= AF_INET
; 
2425                 gsa
->sin
.sin_len 
= sizeof(struct sockaddr_in
); 
2426                 gsa
->sin
.sin_addr 
= mreqs
.imr_multiaddr
; 
2428                 if (sopt
->sopt_name 
== IP_DROP_SOURCE_MEMBERSHIP
) { 
2429                         ssa
->sin
.sin_family 
= AF_INET
; 
2430                         ssa
->sin
.sin_len 
= sizeof(struct sockaddr_in
); 
2431                         ssa
->sin
.sin_addr 
= mreqs
.imr_sourceaddr
; 
2434                  * Attempt to look up hinted ifp from interface address. 
2435                  * Fallthrough with null ifp iff lookup fails, to 
2436                  * preserve 4.4BSD mcast API idempotence. 
2437                  * XXX NOTE WELL: The RFC 3678 API is preferred because 
2438                  * using an IPv4 address as a key is racy. 
2440                 if (!in_nullhost(mreqs
.imr_interface
)) 
2441                         ifp 
= ip_multicast_if(&mreqs
.imr_interface
, &ifindex
); 
2443                 IGMP_INET_PRINTF(mreqs
.imr_interface
, 
2444                     ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__
, 
2445                     _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
))); 
2449         case MCAST_LEAVE_GROUP
: 
2450         case MCAST_LEAVE_SOURCE_GROUP
: 
2451                 if (sopt
->sopt_name 
== MCAST_LEAVE_GROUP
) { 
2452                         error 
= sooptcopyin(sopt
, &gsr
, 
2453                             sizeof(struct group_req
), 
2454                             sizeof(struct group_req
)); 
2455                 } else if (sopt
->sopt_name 
== MCAST_LEAVE_SOURCE_GROUP
) { 
2456                         error 
= sooptcopyin(sopt
, &gsr
, 
2457                             sizeof(struct group_source_req
), 
2458                             sizeof(struct group_source_req
)); 
2463                 if (gsa
->sin
.sin_family 
!= AF_INET 
|| 
2464                     gsa
->sin
.sin_len 
!= sizeof(struct sockaddr_in
)) 
2467                 if (sopt
->sopt_name 
== MCAST_LEAVE_SOURCE_GROUP
) { 
2468                         if (ssa
->sin
.sin_family 
!= AF_INET 
|| 
2469                             ssa
->sin
.sin_len 
!= sizeof(struct sockaddr_in
)) 
2473                 ifnet_head_lock_shared(); 
2474                 if (gsr
.gsr_interface 
== 0 || 
2475                     (u_int
)if_index 
< gsr
.gsr_interface
) { 
2477                         return (EADDRNOTAVAIL
); 
2480                 ifp 
= ifindex2ifnet
[gsr
.gsr_interface
]; 
2485                 IGMP_PRINTF(("%s: unknown sopt_name %d\n", 
2486                     __func__
, sopt
->sopt_name
)); 
2487                 return (EOPNOTSUPP
); 
2491         if (!IN_MULTICAST(ntohl(gsa
->sin
.sin_addr
.s_addr
))) 
2495          * Find the membership in the membership array. 
2497         imo 
= inp_findmoptions(inp
); 
2502         idx 
= imo_match_group(imo
, ifp
, &gsa
->sa
); 
2503         if (idx 
== (size_t)-1) { 
2504                 error 
= EADDRNOTAVAIL
; 
2507         inm 
= imo
->imo_membership
[idx
]; 
2508         imf 
= &imo
->imo_mfilters
[idx
]; 
2510         if (ssa
->ss
.ss_family 
!= AF_UNSPEC
) { 
2511                 IGMP_PRINTF(("%s: opt=%d is_final=0\n", __func__
, 
2517          * Begin state merge transaction at socket layer. 
2521          * If we were instructed only to leave a given source, do so. 
2522          * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. 
2527                 if (imf
->imf_st
[0] == MCAST_EXCLUDE
) { 
2528                         error 
= EADDRNOTAVAIL
; 
2531                 ims 
= imo_match_source(imo
, idx
, &ssa
->sa
); 
2533                         IGMP_INET_PRINTF(ssa
->sin
.sin_addr
, 
2534                             ("%s: source %s %spresent\n", __func__
, 
2535                             _igmp_inet_buf
, "not ")); 
2536                         error 
= EADDRNOTAVAIL
; 
2539                 IGMP_PRINTF(("%s: %s source\n", __func__
, "block")); 
2540                 error 
= imf_prune(imf
, &ssa
->sin
); 
2542                         IGMP_PRINTF(("%s: merge imf state failed\n", 
2549          * Begin state merge transaction at IGMP layer. 
2554                  * Give up the multicast address record to which 
2555                  * the membership points.  Reference held in imo 
2556                  * will be released below. 
2558                 (void) in_leavegroup(inm
, imf
); 
2560                 IGMP_PRINTF(("%s: merge inm state\n", __func__
)); 
2562                 error 
= inm_merge(inm
, imf
); 
2564                         IGMP_PRINTF(("%s: failed to merge inm state\n", 
2567                         goto out_imf_rollback
; 
2570                 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__
)); 
2571                 error 
= igmp_change_state(inm
, &itp
); 
2573                         IGMP_PRINTF(("%s: failed igmp downcall\n", __func__
)); 
2587                 /* Remove the gap in the membership and filter array. */ 
2588                 VERIFY(inm 
== imo
->imo_membership
[idx
]); 
2589                 imo
->imo_membership
[idx
] = NULL
; 
2591                 for (++idx
; idx 
< imo
->imo_num_memberships
; ++idx
) { 
2592                         imo
->imo_membership
[idx
-1] = imo
->imo_membership
[idx
]; 
2593                         imo
->imo_mfilters
[idx
-1] = imo
->imo_mfilters
[idx
]; 
2595                 imo
->imo_num_memberships
--; 
2600         IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
2602         /* schedule timer now that we've dropped the lock(s) */ 
2603         igmp_set_timeout(&itp
); 
2609  * Select the interface for transmitting IPv4 multicast datagrams. 
2611  * Either an instance of struct in_addr or an instance of struct ip_mreqn 
2612  * may be passed to this socket option. An address of INADDR_ANY or an 
2613  * interface index of 0 is used to remove a previous selection. 
2614  * When no interface is selected, one is chosen for every send. 
2617 inp_set_multicast_if(struct inpcb 
*inp
, struct sockopt 
*sopt
) 
2619         struct in_addr           addr
; 
2620         struct ip_mreqn          mreqn
; 
2622         struct ip_moptions      
*imo
; 
2624         unsigned int             ifindex 
= 0; 
2626         if (sopt
->sopt_valsize 
== sizeof(struct ip_mreqn
)) { 
2628                  * An interface index was specified using the 
2629                  * Linux-derived ip_mreqn structure. 
2631                 error 
= sooptcopyin(sopt
, &mreqn
, sizeof(struct ip_mreqn
), 
2632                     sizeof(struct ip_mreqn
)); 
2636                 ifnet_head_lock_shared(); 
2637                 if (mreqn
.imr_ifindex 
< 0 || if_index 
< mreqn
.imr_ifindex
) { 
2642                 if (mreqn
.imr_ifindex 
== 0) { 
2645                         ifp 
= ifindex2ifnet
[mreqn
.imr_ifindex
]; 
2648                                 return (EADDRNOTAVAIL
); 
2654                  * An interface was specified by IPv4 address. 
2655                  * This is the traditional BSD usage. 
2657                 error 
= sooptcopyin(sopt
, &addr
, sizeof(struct in_addr
), 
2658                     sizeof(struct in_addr
)); 
2661                 if (in_nullhost(addr
)) { 
2664                         ifp 
= ip_multicast_if(&addr
, &ifindex
); 
2666                                 IGMP_INET_PRINTF(addr
, 
2667                                     ("%s: can't find ifp for addr=%s\n", 
2668                                     __func__
, _igmp_inet_buf
)); 
2669                                 return (EADDRNOTAVAIL
); 
2674                 IGMP_PRINTF(("%s: ifp = 0x%llx, addr = %s\n", __func__
, 
2675                     (uint64_t)VM_KERNEL_ADDRPERM(ifp
), inet_ntoa(addr
))); 
2679         /* Reject interfaces which do not support multicast. */ 
2680         if (ifp 
!= NULL 
&& (ifp
->if_flags 
& IFF_MULTICAST
) == 0) 
2681                 return (EOPNOTSUPP
); 
2683         imo 
= inp_findmoptions(inp
); 
2688         imo
->imo_multicast_ifp 
= ifp
; 
2690                 imo
->imo_multicast_addr 
= addr
; 
2692                 imo
->imo_multicast_addr
.s_addr 
= INADDR_ANY
; 
2694         IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
2700  * Atomically set source filters on a socket for an IPv4 multicast group. 
2703 inp_set_source_filters(struct inpcb 
*inp
, struct sockopt 
*sopt
) 
2705         struct __msfilterreq64   msfr
, msfr64
; 
2706         struct __msfilterreq32   msfr32
; 
2709         struct in_mfilter       
*imf
; 
2710         struct ip_moptions      
*imo
; 
2711         struct in_multi         
*inm
; 
2714         user_addr_t              tmp_ptr
; 
2715         struct igmp_tparams      itp
; 
2717         bzero(&itp
, sizeof (itp
)); 
2719         if (IS_64BIT_PROCESS(current_proc())) { 
2720                 error 
= sooptcopyin(sopt
, &msfr64
, 
2721                     sizeof(struct __msfilterreq64
), 
2722                     sizeof(struct __msfilterreq64
)); 
2725                 /* we never use msfr.msfr_srcs; */ 
2726                 memcpy(&msfr
, &msfr64
, sizeof(msfr
)); 
2728                 error 
= sooptcopyin(sopt
, &msfr32
, 
2729                     sizeof(struct __msfilterreq32
), 
2730                     sizeof(struct __msfilterreq32
)); 
2733                 /* we never use msfr.msfr_srcs; */ 
2734                 memcpy(&msfr
, &msfr32
, sizeof(msfr
)); 
2737         if ((size_t) msfr
.msfr_nsrcs 
> 
2738             UINT32_MAX 
/ sizeof(struct sockaddr_storage
)) 
2739                 msfr
.msfr_nsrcs 
= UINT32_MAX 
/ sizeof(struct sockaddr_storage
); 
2741         if (msfr
.msfr_nsrcs 
> in_mcast_maxsocksrc
) 
2744         if ((msfr
.msfr_fmode 
!= MCAST_EXCLUDE 
&& 
2745              msfr
.msfr_fmode 
!= MCAST_INCLUDE
)) 
2748         if (msfr
.msfr_group
.ss_family 
!= AF_INET 
|| 
2749             msfr
.msfr_group
.ss_len 
!= sizeof(struct sockaddr_in
)) 
2752         gsa 
= (sockunion_t 
*)&msfr
.msfr_group
; 
2753         if (!IN_MULTICAST(ntohl(gsa
->sin
.sin_addr
.s_addr
))) 
2756         gsa
->sin
.sin_port 
= 0;  /* ignore port */ 
2758         ifnet_head_lock_shared(); 
2759         if (msfr
.msfr_ifindex 
== 0 || (u_int
)if_index 
< msfr
.msfr_ifindex
) { 
2761                 return (EADDRNOTAVAIL
); 
2764         ifp 
= ifindex2ifnet
[msfr
.msfr_ifindex
]; 
2767                 return (EADDRNOTAVAIL
); 
2770          * Check if this socket is a member of this group. 
2772         imo 
= inp_findmoptions(inp
); 
2777         idx 
= imo_match_group(imo
, ifp
, &gsa
->sa
); 
2778         if (idx 
== (size_t)-1 || imo
->imo_mfilters 
== NULL
) { 
2779                 error 
= EADDRNOTAVAIL
; 
2780                 goto out_imo_locked
; 
2782         inm 
= imo
->imo_membership
[idx
]; 
2783         imf 
= &imo
->imo_mfilters
[idx
]; 
2786          * Begin state merge transaction at socket layer. 
2789         imf
->imf_st
[1] = msfr
.msfr_fmode
; 
2792          * Apply any new source filters, if present. 
2793          * Make a copy of the user-space source vector so 
2794          * that we may copy them with a single copyin. This 
2795          * allows us to deal with page faults up-front. 
2797         if (msfr
.msfr_nsrcs 
> 0) { 
2798                 struct in_msource       
*lims
; 
2799                 struct sockaddr_in      
*psin
; 
2800                 struct sockaddr_storage 
*kss
, *pkss
; 
2803                 if (IS_64BIT_PROCESS(current_proc())) 
2804                         tmp_ptr 
= msfr64
.msfr_srcs
; 
2806                         tmp_ptr 
= CAST_USER_ADDR_T(msfr32
.msfr_srcs
); 
2808                 IGMP_PRINTF(("%s: loading %lu source list entries\n", 
2809                     __func__
, (unsigned long)msfr
.msfr_nsrcs
)); 
2810                 kss 
= _MALLOC((size_t) msfr
.msfr_nsrcs 
* sizeof(*kss
), 
2814                         goto out_imo_locked
; 
2816                 error 
= copyin(tmp_ptr
, kss
, 
2817                     (size_t) msfr
.msfr_nsrcs 
* sizeof(*kss
)); 
2820                         goto out_imo_locked
; 
2824                  * Mark all source filters as UNDEFINED at t1. 
2825                  * Restore new group filter mode, as imf_leave() 
2826                  * will set it to INCLUDE. 
2829                 imf
->imf_st
[1] = msfr
.msfr_fmode
; 
2832                  * Update socket layer filters at t1, lazy-allocating 
2833                  * new entries. This saves a bunch of memory at the 
2834                  * cost of one RB_FIND() per source entry; duplicate 
2835                  * entries in the msfr_nsrcs vector are ignored. 
2836                  * If we encounter an error, rollback transaction. 
2838                  * XXX This too could be replaced with a set-symmetric 
2839                  * difference like loop to avoid walking from root 
2840                  * every time, as the key space is common. 
2842                 for (i 
= 0, pkss 
= kss
; (u_int
)i 
< msfr
.msfr_nsrcs
; 
2844                         psin 
= (struct sockaddr_in 
*)pkss
; 
2845                         if (psin
->sin_family 
!= AF_INET
) { 
2846                                 error 
= EAFNOSUPPORT
; 
2849                         if (psin
->sin_len 
!= sizeof(struct sockaddr_in
)) { 
2853                         error 
= imf_get_source(imf
, psin
, &lims
); 
2856                         lims
->imsl_st
[1] = imf
->imf_st
[1]; 
2862                 goto out_imf_rollback
; 
2865          * Begin state merge transaction at IGMP layer. 
2868         IGMP_PRINTF(("%s: merge inm state\n", __func__
)); 
2869         error 
= inm_merge(inm
, imf
); 
2871                 IGMP_PRINTF(("%s: failed to merge inm state\n", __func__
)); 
2873                 goto out_imf_rollback
; 
2876         IGMP_PRINTF(("%s: doing igmp downcall\n", __func__
)); 
2877         error 
= igmp_change_state(inm
, &itp
); 
2881                 IGMP_PRINTF(("%s: failed igmp downcall\n", __func__
)); 
2894         IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
2896         /* schedule timer now that we've dropped the lock(s) */ 
2897         igmp_set_timeout(&itp
); 
2903  * Set the IP multicast options in response to user setsockopt(). 
2905  * Many of the socket options handled in this function duplicate the 
2906  * functionality of socket options in the regular unicast API. However, 
2907  * it is not possible to merge the duplicate code, because the idempotence 
2908  * of the IPv4 multicast part of the BSD Sockets API must be preserved; 
2909  * the effects of these options must be treated as separate and distinct. 
2912 inp_setmoptions(struct inpcb 
*inp
, struct sockopt 
*sopt
) 
2914         struct ip_moptions      
*imo
; 
2916         unsigned int             ifindex
; 
2922          * If socket is neither of type SOCK_RAW or SOCK_DGRAM, 
2923          * or is a divert socket, reject it. 
2925         if (SOCK_PROTO(inp
->inp_socket
) == IPPROTO_DIVERT 
|| 
2926             (SOCK_TYPE(inp
->inp_socket
) != SOCK_RAW 
&& 
2927              SOCK_TYPE(inp
->inp_socket
) != SOCK_DGRAM
)) 
2928                 return (EOPNOTSUPP
); 
2930         switch (sopt
->sopt_name
) { 
2931         case IP_MULTICAST_IF
: 
2932                 error 
= inp_set_multicast_if(inp
, sopt
); 
2935         case IP_MULTICAST_IFINDEX
: 
2937                  * Select the interface for outgoing multicast packets. 
2939                 error 
= sooptcopyin(sopt
, &ifindex
, sizeof (ifindex
), 
2944                 imo 
= inp_findmoptions(inp
); 
2950                  * Index 0 is used to remove a previous selection. 
2951                  * When no interface is selected, a default one is 
2952                  * chosen every time a multicast packet is sent. 
2956                         imo
->imo_multicast_ifp 
= NULL
; 
2958                         IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
2962                 ifnet_head_lock_shared(); 
2963                 /* Don't need to check is ifindex is < 0 since it's unsigned */ 
2964                 if ((unsigned int)if_index 
< ifindex
) { 
2966                         IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
2967                         error 
= ENXIO
;  /* per IPV6_MULTICAST_IF */ 
2970                 ifp 
= ifindex2ifnet
[ifindex
]; 
2973                 /* If it's detached or isn't a multicast interface, bail out */ 
2974                 if (ifp 
== NULL 
|| !(ifp
->if_flags 
& IFF_MULTICAST
)) { 
2975                         IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
2976                         error 
= EADDRNOTAVAIL
; 
2980                 imo
->imo_multicast_ifp 
= ifp
; 
2982                  * Clear out any remnants of past IP_MULTICAST_IF.  The addr 
2983                  * isn't really used anywhere in the kernel; we could have 
2984                  * iterated thru the addresses of the interface and pick one 
2985                  * here, but that is redundant since ip_getmoptions() already 
2986                  * takes care of that for INADDR_ANY. 
2988                 imo
->imo_multicast_addr
.s_addr 
= INADDR_ANY
; 
2990                 IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
2993         case IP_MULTICAST_TTL
: { 
2997                  * Set the IP time-to-live for outgoing multicast packets. 
2998                  * The original multicast API required a char argument, 
2999                  * which is inconsistent with the rest of the socket API. 
3000                  * We allow either a char or an int. 
3002                 if (sopt
->sopt_valsize 
== sizeof(u_char
)) { 
3003                         error 
= sooptcopyin(sopt
, &ttl
, sizeof(u_char
), 
3010                         error 
= sooptcopyin(sopt
, &ittl
, sizeof(u_int
), 
3020                 imo 
= inp_findmoptions(inp
); 
3026                 imo
->imo_multicast_ttl 
= ttl
; 
3028                 IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
3032         case IP_MULTICAST_LOOP
: { 
3036                  * Set the loopback flag for outgoing multicast packets. 
3037                  * Must be zero or one.  The original multicast API required a 
3038                  * char argument, which is inconsistent with the rest 
3039                  * of the socket API.  We allow either a char or an int. 
3041                 if (sopt
->sopt_valsize 
== sizeof(u_char
)) { 
3042                         error 
= sooptcopyin(sopt
, &loop
, sizeof(u_char
), 
3049                         error 
= sooptcopyin(sopt
, &iloop
, sizeof(u_int
), 
3053                         loop 
= (u_char
)iloop
; 
3055                 imo 
= inp_findmoptions(inp
); 
3061                 imo
->imo_multicast_loop 
= !!loop
; 
3063                 IMO_REMREF(imo
);        /* from inp_findmoptions() */ 
3067         case IP_ADD_MEMBERSHIP
: 
3068         case IP_ADD_SOURCE_MEMBERSHIP
: 
3069         case MCAST_JOIN_GROUP
: 
3070         case MCAST_JOIN_SOURCE_GROUP
: 
3071                 error 
= inp_join_group(inp
, sopt
); 
3074         case IP_DROP_MEMBERSHIP
: 
3075         case IP_DROP_SOURCE_MEMBERSHIP
: 
3076         case MCAST_LEAVE_GROUP
: 
3077         case MCAST_LEAVE_SOURCE_GROUP
: 
3078                 error 
= inp_leave_group(inp
, sopt
); 
3081         case IP_BLOCK_SOURCE
: 
3082         case IP_UNBLOCK_SOURCE
: 
3083         case MCAST_BLOCK_SOURCE
: 
3084         case MCAST_UNBLOCK_SOURCE
: 
3085                 error 
= inp_block_unblock_source(inp
, sopt
); 
3089                 error 
= inp_set_source_filters(inp
, sopt
); 
3101  * Expose IGMP's multicast filter mode and source list(s) to userland, 
3102  * keyed by (ifindex, group). 
3103  * The filter mode is written out as a uint32_t, followed by 
3104  * 0..n of struct in_addr. 
3105  * For use by ifmcstat(8). 
3108 sysctl_ip_mcast_filters SYSCTL_HANDLER_ARGS
 
3110 #pragma unused(oidp) 
3112         struct in_addr                   src
, group
; 
3114         struct in_multi                 
*inm
; 
3115         struct in_multistep             step
; 
3116         struct ip_msource               
*ims
; 
3120         uint32_t                         fmode
, ifindex
; 
3123         namelen 
= (u_int
)arg2
; 
3125         if (req
->newptr 
!= USER_ADDR_NULL
) 
3132         ifnet_head_lock_shared(); 
3133         if (ifindex 
<= 0 || ifindex 
> (u_int
)if_index
) { 
3134                 IGMP_PRINTF(("%s: ifindex %u out of range\n", 
3135                     __func__
, ifindex
)); 
3140         group
.s_addr 
= name
[1]; 
3141         if (!IN_MULTICAST(ntohl(group
.s_addr
))) { 
3142                 IGMP_INET_PRINTF(group
, 
3143                     ("%s: group %s is not multicast\n", 
3144                     __func__
, _igmp_inet_buf
)); 
3149         ifp 
= ifindex2ifnet
[ifindex
]; 
3152                 IGMP_PRINTF(("%s: no ifp for ifindex %u\n", __func__
, ifindex
)); 
3156         in_multihead_lock_shared(); 
3157         IN_FIRST_MULTI(step
, inm
); 
3158         while (inm 
!= NULL
) { 
3160                 if (inm
->inm_ifp 
!= ifp
) 
3163                 if (!in_hosteq(inm
->inm_addr
, group
)) 
3166                 fmode 
= inm
->inm_st
[1].iss_fmode
; 
3167                 retval 
= SYSCTL_OUT(req
, &fmode
, sizeof(uint32_t)); 
3172                 RB_FOREACH(ims
, ip_msource_tree
, &inm
->inm_srcs
) { 
3175                         ina
.s_addr 
= htonl(ims
->ims_haddr
); 
3176                         IGMP_INET_PRINTF(ina
, 
3177                             ("%s: visit node %s\n", __func__
, _igmp_inet_buf
)); 
3180                          * Only copy-out sources which are in-mode. 
3182                         if (fmode 
!= ims_get_mode(inm
, ims
, 1)) { 
3183                                 IGMP_PRINTF(("%s: skip non-in-mode\n", 
3185                                 continue; /* process next source */ 
3187                         src
.s_addr 
= htonl(ims
->ims_haddr
); 
3188                         retval 
= SYSCTL_OUT(req
, &src
, sizeof(struct in_addr
)); 
3190                                 break;  /* process next inm */ 
3194                 IN_NEXT_MULTI(step
, inm
); 
3196         in_multihead_lock_done(); 
3203  * The whole multicast option thing needs to be re-thought. 
3204  * Several of these options are equally applicable to non-multicast 
3205  * transmission, and one (IP_MULTICAST_TTL) totally duplicates a 
3206  * standard option (IP_TTL). 
3209  * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index. 
3211 static struct ifnet 
* 
3212 ip_multicast_if(struct in_addr 
*a
, unsigned int *ifindexp
) 
3214         unsigned int ifindex
; 
3217         if (ifindexp 
!= NULL
) 
3219         if (ntohl(a
->s_addr
) >> 24 == 0) { 
3220                 ifindex 
= ntohl(a
->s_addr
) & 0xffffff; 
3221                 ifnet_head_lock_shared(); 
3222                 /* Don't need to check is ifindex is < 0 since it's unsigned */ 
3223                 if ((unsigned int)if_index 
< ifindex
) { 
3227                 ifp 
= ifindex2ifnet
[ifindex
]; 
3229                 if (ifp 
!= NULL 
&& ifindexp 
!= NULL
) 
3230                         *ifindexp 
= ifindex
; 
3232                 INADDR_TO_IFP(*a
, ifp
); 
3240         PE_parse_boot_argn("ifa_debug", &inm_debug
, sizeof (inm_debug
)); 
3242         /* Setup lock group and attribute for in_multihead */ 
3243         in_multihead_lock_grp_attr 
= lck_grp_attr_alloc_init(); 
3244         in_multihead_lock_grp 
= lck_grp_alloc_init("in_multihead", 
3245             in_multihead_lock_grp_attr
); 
3246         in_multihead_lock_attr 
= lck_attr_alloc_init(); 
3247         lck_rw_init(&in_multihead_lock
, in_multihead_lock_grp
, 
3248             in_multihead_lock_attr
); 
3250         lck_mtx_init(&inm_trash_lock
, in_multihead_lock_grp
, 
3251             in_multihead_lock_attr
); 
3252         TAILQ_INIT(&inm_trash_head
); 
3254         inm_size 
= (inm_debug 
== 0) ? sizeof (struct in_multi
) : 
3255             sizeof (struct in_multi_dbg
); 
3256         inm_zone 
= zinit(inm_size
, INM_ZONE_MAX 
* inm_size
, 
3258         if (inm_zone 
== NULL
) { 
3259                 panic("%s: failed allocating %s", __func__
, INM_ZONE_NAME
); 
3262         zone_change(inm_zone
, Z_EXPAND
, TRUE
); 
3264         ipms_size 
= sizeof (struct ip_msource
); 
3265         ipms_zone 
= zinit(ipms_size
, IPMS_ZONE_MAX 
* ipms_size
, 
3267         if (ipms_zone 
== NULL
) { 
3268                 panic("%s: failed allocating %s", __func__
, IPMS_ZONE_NAME
); 
3271         zone_change(ipms_zone
, Z_EXPAND
, TRUE
); 
3273         inms_size 
= sizeof (struct in_msource
); 
3274         inms_zone 
= zinit(inms_size
, INMS_ZONE_MAX 
* inms_size
, 
3276         if (inms_zone 
== NULL
) { 
3277                 panic("%s: failed allocating %s", __func__
, INMS_ZONE_NAME
); 
3280         zone_change(inms_zone
, Z_EXPAND
, TRUE
); 
3283 static struct in_multi 
* 
3284 in_multi_alloc(int how
) 
3286         struct in_multi 
*inm
; 
3288         inm 
= (how 
== M_WAITOK
) ? zalloc(inm_zone
) : zalloc_noblock(inm_zone
); 
3290                 bzero(inm
, inm_size
); 
3291                 lck_mtx_init(&inm
->inm_lock
, in_multihead_lock_grp
, 
3292                     in_multihead_lock_attr
); 
3293                 inm
->inm_debug 
|= IFD_ALLOC
; 
3294                 if (inm_debug 
!= 0) { 
3295                         inm
->inm_debug 
|= IFD_DEBUG
; 
3296                         inm
->inm_trace 
= inm_trace
; 
3303 in_multi_free(struct in_multi 
*inm
) 
3306         if (inm
->inm_debug 
& IFD_ATTACHED
) { 
3307                 panic("%s: attached inm=%p is being freed", __func__
, inm
); 
3309         } else if (inm
->inm_ifma 
!= NULL
) { 
3310                 panic("%s: ifma not NULL for inm=%p", __func__
, inm
); 
3312         } else if (!(inm
->inm_debug 
& IFD_ALLOC
)) { 
3313                 panic("%s: inm %p cannot be freed", __func__
, inm
); 
3315         } else if (inm
->inm_refcount 
!= 0) { 
3316                 panic("%s: non-zero refcount inm=%p", __func__
, inm
); 
3318         } else if (inm
->inm_reqcnt 
!= 0) { 
3319                 panic("%s: non-zero reqcnt inm=%p", __func__
, inm
); 
3323         /* Free any pending IGMPv3 state-change records */ 
3324         IF_DRAIN(&inm
->inm_scq
); 
3326         inm
->inm_debug 
&= ~IFD_ALLOC
; 
3327         if ((inm
->inm_debug 
& (IFD_DEBUG 
| IFD_TRASHED
)) == 
3328             (IFD_DEBUG 
| IFD_TRASHED
)) { 
3329                 lck_mtx_lock(&inm_trash_lock
); 
3330                 TAILQ_REMOVE(&inm_trash_head
, (struct in_multi_dbg 
*)inm
, 
3332                 lck_mtx_unlock(&inm_trash_lock
); 
3333                 inm
->inm_debug 
&= ~IFD_TRASHED
; 
3337         lck_mtx_destroy(&inm
->inm_lock
, in_multihead_lock_grp
); 
3338         zfree(inm_zone
, inm
); 
3342 in_multi_attach(struct in_multi 
*inm
) 
3344         in_multihead_lock_assert(LCK_RW_ASSERT_EXCLUSIVE
); 
3345         INM_LOCK_ASSERT_HELD(inm
); 
3347         if (inm
->inm_debug 
& IFD_ATTACHED
) { 
3348                 panic("%s: Attempt to attach an already attached inm=%p", 
3351         } else if (inm
->inm_debug 
& IFD_TRASHED
) { 
3352                 panic("%s: Attempt to reattach a detached inm=%p", 
3358         VERIFY(inm
->inm_reqcnt 
== 1); 
3359         INM_ADDREF_LOCKED(inm
); 
3360         inm
->inm_debug 
|= IFD_ATTACHED
; 
3362          * Reattach case:  If debugging is enabled, take it 
3363          * out of the trash list and clear IFD_TRASHED. 
3365         if ((inm
->inm_debug 
& (IFD_DEBUG 
| IFD_TRASHED
)) == 
3366             (IFD_DEBUG 
| IFD_TRASHED
)) { 
3367                 /* Become a regular mutex, just in case */ 
3368                 INM_CONVERT_LOCK(inm
); 
3369                 lck_mtx_lock(&inm_trash_lock
); 
3370                 TAILQ_REMOVE(&inm_trash_head
, (struct in_multi_dbg 
*)inm
, 
3372                 lck_mtx_unlock(&inm_trash_lock
); 
3373                 inm
->inm_debug 
&= ~IFD_TRASHED
; 
3376         LIST_INSERT_HEAD(&in_multihead
, inm
, inm_link
); 
3380 in_multi_detach(struct in_multi 
*inm
) 
3382         in_multihead_lock_assert(LCK_RW_ASSERT_EXCLUSIVE
); 
3383         INM_LOCK_ASSERT_HELD(inm
); 
3385         if (inm
->inm_reqcnt 
== 0) { 
3386                 panic("%s: inm=%p negative reqcnt", __func__
, inm
); 
3391         if (inm
->inm_reqcnt 
> 0) 
3394         if (!(inm
->inm_debug 
& IFD_ATTACHED
)) { 
3395                 panic("%s: Attempt to detach an unattached record inm=%p", 
3398         } else if (inm
->inm_debug 
& IFD_TRASHED
) { 
3399                 panic("%s: inm %p is already in trash list", __func__
, inm
); 
3404          * NOTE: Caller calls IFMA_REMREF 
3406         inm
->inm_debug 
&= ~IFD_ATTACHED
; 
3407         LIST_REMOVE(inm
, inm_link
); 
3409         if (inm
->inm_debug 
& IFD_DEBUG
) { 
3410                 /* Become a regular mutex, just in case */ 
3411                 INM_CONVERT_LOCK(inm
); 
3412                 lck_mtx_lock(&inm_trash_lock
); 
3413                 TAILQ_INSERT_TAIL(&inm_trash_head
, 
3414                     (struct in_multi_dbg 
*)inm
, inm_trash_link
); 
3415                 lck_mtx_unlock(&inm_trash_lock
); 
3416                 inm
->inm_debug 
|= IFD_TRASHED
; 
3423 inm_addref(struct in_multi 
*inm
, int locked
) 
3428                 INM_LOCK_ASSERT_HELD(inm
); 
3430         if (++inm
->inm_refcount 
== 0) { 
3431                 panic("%s: inm=%p wraparound refcnt", __func__
, inm
); 
3433         } else if (inm
->inm_trace 
!= NULL
) { 
3434                 (*inm
->inm_trace
)(inm
, TRUE
); 
3441 inm_remref(struct in_multi 
*inm
, int locked
) 
3443         struct ifmultiaddr 
*ifma
; 
3444         struct igmp_ifinfo 
*igi
; 
3449                 INM_LOCK_ASSERT_HELD(inm
); 
3451         if (inm
->inm_refcount 
== 0 || (inm
->inm_refcount 
== 1 && locked
)) { 
3452                 panic("%s: inm=%p negative/missing refcnt", __func__
, inm
); 
3454         } else if (inm
->inm_trace 
!= NULL
) { 
3455                 (*inm
->inm_trace
)(inm
, FALSE
); 
3458         --inm
->inm_refcount
; 
3459         if (inm
->inm_refcount 
> 0) { 
3466          * Synchronization with in_getmulti().  In the event the inm has been 
3467          * detached, the underlying ifma would still be in the if_multiaddrs 
3468          * list, and thus can be looked up via if_addmulti().  At that point, 
3469          * the only way to find this inm is via ifma_protospec.  To avoid 
3470          * race conditions between the last inm_remref() of that inm and its 
3471          * use via ifma_protospec, in_multihead lock is used for serialization. 
3472          * In order to avoid violating the lock order, we must drop inm_lock 
3473          * before acquiring in_multihead lock.  To prevent the inm from being 
3474          * freed prematurely, we hold an extra reference. 
3476         ++inm
->inm_refcount
; 
3478         in_multihead_lock_shared(); 
3480         --inm
->inm_refcount
; 
3481         if (inm
->inm_refcount 
> 0) { 
3482                 /* We've lost the race, so abort since inm is still in use */ 
3484                 in_multihead_lock_done(); 
3485                 /* If it was locked, return it as such */ 
3491         ifma 
= inm
->inm_ifma
; 
3492         inm
->inm_ifma 
= NULL
; 
3493         inm
->inm_ifp 
= NULL
; 
3495         inm
->inm_igi 
= NULL
; 
3497         IFMA_LOCK_SPIN(ifma
); 
3498         ifma
->ifma_protospec 
= NULL
; 
3500         in_multihead_lock_done(); 
3503         if_delmulti_ifma(ifma
); 
3504         /* Release reference held to the underlying ifmultiaddr */ 
3512 inm_trace(struct in_multi 
*inm
, int refhold
) 
3514         struct in_multi_dbg 
*inm_dbg 
= (struct in_multi_dbg 
*)inm
; 
3519         if (!(inm
->inm_debug 
& IFD_DEBUG
)) { 
3520                 panic("%s: inm %p has no debug structure", __func__
, inm
); 
3524                 cnt 
= &inm_dbg
->inm_refhold_cnt
; 
3525                 tr 
= inm_dbg
->inm_refhold
; 
3527                 cnt 
= &inm_dbg
->inm_refrele_cnt
; 
3528                 tr 
= inm_dbg
->inm_refrele
; 
3531         idx 
= atomic_add_16_ov(cnt
, 1) % INM_TRACE_HIST_SIZE
; 
3532         ctrace_record(&tr
[idx
]); 
3536 in_multihead_lock_exclusive(void) 
3538         lck_rw_lock_exclusive(&in_multihead_lock
); 
3542 in_multihead_lock_shared(void) 
3544         lck_rw_lock_shared(&in_multihead_lock
); 
3548 in_multihead_lock_assert(int what
) 
3550         lck_rw_assert(&in_multihead_lock
, what
); 
3554 in_multihead_lock_done(void) 
3556         lck_rw_done(&in_multihead_lock
); 
3559 static struct ip_msource 
* 
3562         struct ip_msource 
*ims
; 
3564         ims 
= (how 
== M_WAITOK
) ? zalloc(ipms_zone
) : zalloc_noblock(ipms_zone
); 
3566                 bzero(ims
, ipms_size
); 
3572 ipms_free(struct ip_msource 
*ims
) 
3574         zfree(ipms_zone
, ims
); 
3577 static struct in_msource 
* 
3580         struct in_msource 
*inms
; 
3582         inms 
= (how 
== M_WAITOK
) ? zalloc(inms_zone
) : 
3583             zalloc_noblock(inms_zone
); 
3585                 bzero(inms
, inms_size
); 
3591 inms_free(struct in_msource 
*inms
) 
3593         zfree(inms_zone
, inms
); 
3598 static const char *inm_modestrs
[] = { "un\n", "in", "ex" }; 
3601 inm_mode_str(const int mode
) 
3603         if (mode 
>= MCAST_UNDEFINED 
&& mode 
<= MCAST_EXCLUDE
) 
3604                 return (inm_modestrs
[mode
]); 
3608 static const char *inm_statestrs
[] = { 
3617         "sg-query-pending\n", 
3622 inm_state_str(const int state
) 
3624         if (state 
>= IGMP_NOT_MEMBER 
&& state 
<= IGMP_LEAVING_MEMBER
) 
3625                 return (inm_statestrs
[state
]); 
3630  * Dump an in_multi structure to the console. 
3633 inm_print(const struct in_multi 
*inm
) 
3636         char buf
[MAX_IPv4_STR_LEN
]; 
3638         INM_LOCK_ASSERT_HELD(__DECONST(struct in_multi 
*, inm
)); 
3640         if (igmp_debug 
== 0) 
3643         inet_ntop(AF_INET
, &inm
->inm_addr
, buf
, sizeof(buf
)); 
3644         printf("%s: --- begin inm 0x%llx ---\n", __func__
, 
3645             (uint64_t)VM_KERNEL_ADDRPERM(inm
)); 
3646         printf("addr %s ifp 0x%llx(%s) ifma 0x%llx\n", 
3648             (uint64_t)VM_KERNEL_ADDRPERM(inm
->inm_ifp
), 
3649             if_name(inm
->inm_ifp
), 
3650             (uint64_t)VM_KERNEL_ADDRPERM(inm
->inm_ifma
)); 
3651         printf("timer %u state %s refcount %u scq.len %u\n", 
3653             inm_state_str(inm
->inm_state
), 
3655             inm
->inm_scq
.ifq_len
); 
3656         printf("igi 0x%llx nsrc %lu sctimer %u scrv %u\n", 
3657             (uint64_t)VM_KERNEL_ADDRPERM(inm
->inm_igi
), 
3661         for (t 
= 0; t 
< 2; t
++) { 
3662                 printf("t%d: fmode %s asm %u ex %u in %u rec %u\n", t
, 
3663                     inm_mode_str(inm
->inm_st
[t
].iss_fmode
), 
3664                     inm
->inm_st
[t
].iss_asm
, 
3665                     inm
->inm_st
[t
].iss_ex
, 
3666                     inm
->inm_st
[t
].iss_in
, 
3667                     inm
->inm_st
[t
].iss_rec
); 
3669         printf("%s: --- end inm 0x%llx ---\n", __func__
, 
3670             (uint64_t)VM_KERNEL_ADDRPERM(inm
)); 
3676 inm_print(__unused 
const struct in_multi 
*inm
)