/*
- * Copyright (c) 2010-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2017 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <net/if.h>
#include <net/if_dl.h>
+#include <net/net_api_stats.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip_var.h>
#include <netinet/igmp_var.h>
-#ifndef __SOCKUNION_DECLARED
-union sockunion {
- struct sockaddr_storage ss;
- struct sockaddr sa;
- struct sockaddr_dl sdl;
- struct sockaddr_in sin;
-};
-typedef union sockunion sockunion_t;
-#define __SOCKUNION_DECLARED
-#endif /* __SOCKUNION_DECLARED */
-
/*
* Functions with non-static linkage defined in this file should be
* declared in in_var.h:
static void imf_reap(struct in_mfilter *);
static int imo_grow(struct ip_moptions *, size_t);
static size_t imo_match_group(const struct ip_moptions *,
- const struct ifnet *, const struct sockaddr *);
+ const struct ifnet *, const struct sockaddr_in *);
static struct in_msource *
imo_match_source(const struct ip_moptions *, const size_t,
- const struct sockaddr *);
+ const struct sockaddr_in *);
static void ims_merge(struct ip_msource *ims,
const struct in_msource *lims, const int rollback);
static int in_getmulti(struct ifnet *, const struct in_addr *,
*/
static size_t
imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp,
- const struct sockaddr *group)
+ const struct sockaddr_in *group)
{
- const struct sockaddr_in *gsin;
struct in_multi *pinm;
int idx;
int nmships;
IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions *, imo));
- gsin = (struct sockaddr_in *)(uintptr_t)(size_t)group;
/* The imo_membership array may be lazy allocated. */
if (imo->imo_membership == NULL || imo->imo_num_memberships == 0)
continue;
INM_LOCK(pinm);
if ((ifp == NULL || (pinm->inm_ifp == ifp)) &&
- in_hosteq(pinm->inm_addr, gsin->sin_addr)) {
+ in_hosteq(pinm->inm_addr, group->sin_addr)) {
INM_UNLOCK(pinm);
break;
}
*/
static struct in_msource *
imo_match_source(const struct ip_moptions *imo, const size_t gidx,
- const struct sockaddr *src)
+ const struct sockaddr_in *src)
{
struct ip_msource find;
struct in_mfilter *imf;
struct ip_msource *ims;
- const sockunion_t *psa;
IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions *, imo));
- VERIFY(src->sa_family == AF_INET);
+ VERIFY(src->sin_family == AF_INET);
VERIFY(gidx != (size_t)-1 && gidx < imo->imo_num_memberships);
/* The imo_mfilters array may be lazy allocated. */
imf = &imo->imo_mfilters[gidx];
/* Source trees are keyed in host byte order. */
- psa = (sockunion_t *)(uintptr_t)(size_t)src;
- find.ims_haddr = ntohl(psa->sin.sin_addr.s_addr);
+ find.ims_haddr = ntohl(src->sin_addr.s_addr);
ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find);
return ((struct in_msource *)ims);
*/
int
imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp,
- const struct sockaddr *group, const struct sockaddr *src)
+ const struct sockaddr_in *group, const struct sockaddr_in *src)
{
size_t gidx;
struct in_msource *ims;
static int
inm_merge(struct in_multi *inm, /*const*/ struct in_mfilter *imf)
{
- struct ip_msource *ims, *nims;
+ struct ip_msource *ims, *nims = NULL;
struct in_msource *lims;
int schanged, error;
int nsrc0, nsrc1;
inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt)
{
struct group_source_req gsr;
- sockunion_t *gsa, *ssa;
+ struct sockaddr_in *gsa, *ssa;
struct ifnet *ifp;
struct in_mfilter *imf;
struct ip_moptions *imo;
doblock = 0;
memset(&gsr, 0, sizeof(struct group_source_req));
- gsa = (sockunion_t *)&gsr.gsr_group;
- ssa = (sockunion_t *)&gsr.gsr_source;
+ gsa = (struct sockaddr_in *)&gsr.gsr_group;
+ ssa = (struct sockaddr_in *)&gsr.gsr_source;
switch (sopt->sopt_name) {
case IP_BLOCK_SOURCE:
if (error)
return (error);
- gsa->sin.sin_family = AF_INET;
- gsa->sin.sin_len = sizeof(struct sockaddr_in);
- gsa->sin.sin_addr = mreqs.imr_multiaddr;
+ gsa->sin_family = AF_INET;
+ gsa->sin_len = sizeof(struct sockaddr_in);
+ gsa->sin_addr = mreqs.imr_multiaddr;
- ssa->sin.sin_family = AF_INET;
- ssa->sin.sin_len = sizeof(struct sockaddr_in);
- ssa->sin.sin_addr = mreqs.imr_sourceaddr;
+ ssa->sin_family = AF_INET;
+ ssa->sin_len = sizeof(struct sockaddr_in);
+ ssa->sin_addr = mreqs.imr_sourceaddr;
if (!in_nullhost(mreqs.imr_interface))
ifp = ip_multicast_if(&mreqs.imr_interface, &ifindex);
if (error)
return (error);
- if (gsa->sin.sin_family != AF_INET ||
- gsa->sin.sin_len != sizeof(struct sockaddr_in))
+ if (gsa->sin_family != AF_INET ||
+ gsa->sin_len != sizeof(struct sockaddr_in))
return (EINVAL);
- if (ssa->sin.sin_family != AF_INET ||
- ssa->sin.sin_len != sizeof(struct sockaddr_in))
+ if (ssa->sin_family != AF_INET ||
+ ssa->sin_len != sizeof(struct sockaddr_in))
return (EINVAL);
ifnet_head_lock_shared();
IGMP_PRINTF(("%s: unknown sopt_name %d\n",
__func__, sopt->sopt_name));
return (EOPNOTSUPP);
- break;
}
- if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
+ if (!IN_MULTICAST(ntohl(gsa->sin_addr.s_addr)))
return (EINVAL);
/*
return (ENOMEM);
IMO_LOCK(imo);
- idx = imo_match_group(imo, ifp, &gsa->sa);
+ idx = imo_match_group(imo, ifp, gsa);
if (idx == (size_t)-1 || imo->imo_mfilters == NULL) {
error = EADDRNOTAVAIL;
goto out_imo_locked;
* Asked to unblock, but nothing to unblock.
* If adding a new block entry, allocate it.
*/
- ims = imo_match_source(imo, idx, &ssa->sa);
+ ims = imo_match_source(imo, idx, ssa);
if ((ims != NULL && doblock) || (ims == NULL && !doblock)) {
- IGMP_INET_PRINTF(ssa->sin.sin_addr,
+ IGMP_INET_PRINTF(ssa->sin_addr,
("%s: source %s %spresent\n", __func__,
_igmp_inet_buf, doblock ? "" : "not "));
error = EADDRNOTAVAIL;
*/
if (doblock) {
IGMP_PRINTF(("%s: %s source\n", __func__, "block"));
- ims = imf_graft(imf, fmode, &ssa->sin);
+ ims = imf_graft(imf, fmode, ssa);
if (ims == NULL)
error = ENOMEM;
} else {
IGMP_PRINTF(("%s: %s source\n", __func__, "allow"));
- error = imf_prune(imf, &ssa->sin);
+ error = imf_prune(imf, ssa);
}
if (error) {
static int
inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt)
{
- struct __msfilterreq64 msfr, msfr64;
+ struct __msfilterreq64 msfr = {}, msfr64;
struct __msfilterreq32 msfr32;
- sockunion_t *gsa;
+ struct sockaddr_in *gsa;
struct ifnet *ifp;
struct ip_moptions *imo;
struct in_mfilter *imf;
if (error)
return (error);
/* we never use msfr.msfr_srcs; */
- memcpy(&msfr, &msfr64, sizeof(msfr));
+ memcpy(&msfr, &msfr64, sizeof(msfr64));
} else {
error = sooptcopyin(sopt, &msfr32,
sizeof(struct __msfilterreq32),
if (error)
return (error);
/* we never use msfr.msfr_srcs; */
- memcpy(&msfr, &msfr32, sizeof(msfr));
+ memcpy(&msfr, &msfr32, sizeof(msfr32));
}
ifnet_head_lock_shared();
/*
* Lookup group on the socket.
*/
- gsa = (sockunion_t *)&msfr.msfr_group;
- idx = imo_match_group(imo, ifp, &gsa->sa);
+ gsa = (struct sockaddr_in *)&msfr.msfr_group;
+
+ idx = imo_match_group(imo, ifp, gsa);
if (idx == (size_t)-1 || imo->imo_mfilters == NULL) {
IMO_UNLOCK(imo);
return (EADDRNOTAVAIL);
IMO_UNLOCK(imo);
return (ENOBUFS);
}
- bzero(tss, (size_t) msfr.msfr_nsrcs * sizeof(*tss));
}
/*
msfr32.msfr_ifindex = msfr.msfr_ifindex;
msfr32.msfr_fmode = msfr.msfr_fmode;
msfr32.msfr_nsrcs = msfr.msfr_nsrcs;
- memcpy(&msfr64.msfr_group, &msfr.msfr_group,
+ memcpy(&msfr32.msfr_group, &msfr.msfr_group,
sizeof(struct sockaddr_storage));
error = sooptcopyout(sopt, &msfr32,
sizeof(struct __msfilterreq32));
error = 0;
switch (sopt->sopt_name) {
-#ifdef MROUTING
- case IP_MULTICAST_VIF:
- if (imo != NULL) {
- IMO_LOCK(imo);
- optval = imo->imo_multicast_vif;
- IMO_UNLOCK(imo);
- } else
- optval = -1;
- error = sooptcopyout(sopt, &optval, sizeof(int));
- break;
-#endif /* MROUTING */
-
case IP_MULTICAST_IF:
memset(&mreqn, 0, sizeof(struct ip_mreqn));
if (imo != NULL) {
inp_join_group(struct inpcb *inp, struct sockopt *sopt)
{
struct group_source_req gsr;
- sockunion_t *gsa, *ssa;
+ struct sockaddr_in *gsa, *ssa;
struct ifnet *ifp;
struct in_mfilter *imf;
struct ip_moptions *imo;
is_new = 0;
memset(&gsr, 0, sizeof(struct group_source_req));
- gsa = (sockunion_t *)&gsr.gsr_group;
- gsa->ss.ss_family = AF_UNSPEC;
- ssa = (sockunion_t *)&gsr.gsr_source;
- ssa->ss.ss_family = AF_UNSPEC;
+ gsa = (struct sockaddr_in *)&gsr.gsr_group;
+ gsa->sin_family = AF_UNSPEC;
+ ssa = (struct sockaddr_in *)&gsr.gsr_source;
+ ssa->sin_family = AF_UNSPEC;
switch (sopt->sopt_name) {
case IP_ADD_MEMBERSHIP:
return (error);
}
- gsa->sin.sin_family = AF_INET;
- gsa->sin.sin_len = sizeof(struct sockaddr_in);
- gsa->sin.sin_addr = mreqs.imr_multiaddr;
+ gsa->sin_family = AF_INET;
+ gsa->sin_len = sizeof(struct sockaddr_in);
+ gsa->sin_addr = mreqs.imr_multiaddr;
if (sopt->sopt_name == IP_ADD_SOURCE_MEMBERSHIP) {
- ssa->sin.sin_family = AF_INET;
- ssa->sin.sin_len = sizeof(struct sockaddr_in);
- ssa->sin.sin_addr = mreqs.imr_sourceaddr;
+ ssa->sin_family = AF_INET;
+ ssa->sin_len = sizeof(struct sockaddr_in);
+ ssa->sin_addr = mreqs.imr_sourceaddr;
}
- if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
+ if (!IN_MULTICAST(ntohl(gsa->sin_addr.s_addr)))
return (EINVAL);
- ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
- mreqs.imr_interface);
+ ifp = inp_lookup_mcast_ifp(inp, gsa, mreqs.imr_interface);
IGMP_INET_PRINTF(mreqs.imr_interface,
("%s: imr_interface = %s, ifp = 0x%llx\n", __func__,
_igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp)));
if (error)
return (error);
- if (gsa->sin.sin_family != AF_INET ||
- gsa->sin.sin_len != sizeof(struct sockaddr_in))
+ if (gsa->sin_family != AF_INET ||
+ gsa->sin_len != sizeof(struct sockaddr_in))
return (EINVAL);
/*
* Overwrite the port field if present, as the sockaddr
* being copied in may be matched with a binary comparison.
*/
- gsa->sin.sin_port = 0;
+ gsa->sin_port = 0;
if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) {
- if (ssa->sin.sin_family != AF_INET ||
- ssa->sin.sin_len != sizeof(struct sockaddr_in))
+ if (ssa->sin_family != AF_INET ||
+ ssa->sin_len != sizeof(struct sockaddr_in))
return (EINVAL);
- ssa->sin.sin_port = 0;
+ ssa->sin_port = 0;
}
- if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
+ if (!IN_MULTICAST(ntohl(gsa->sin_addr.s_addr)))
return (EINVAL);
ifnet_head_lock_shared();
IGMP_PRINTF(("%s: unknown sopt_name %d\n",
__func__, sopt->sopt_name));
return (EOPNOTSUPP);
- break;
}
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0)
return (EADDRNOTAVAIL);
+ INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_mcast_join_total);
+ /*
+ * TBD: revisit the criteria for non-OS initiated joins
+ */
+ if (inp->inp_lport == htons(5353)) {
+ INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_mcast_join_os_total);
+ }
+
imo = inp_findmoptions(inp);
if (imo == NULL)
return (ENOMEM);
IMO_LOCK(imo);
- idx = imo_match_group(imo, ifp, &gsa->sa);
+ idx = imo_match_group(imo, ifp, gsa);
if (idx == (size_t)-1) {
is_new = 1;
} else {
inm = imo->imo_membership[idx];
imf = &imo->imo_mfilters[idx];
- if (ssa->ss.ss_family != AF_UNSPEC) {
+ if (ssa->sin_family != AF_UNSPEC) {
/*
* MCAST_JOIN_SOURCE_GROUP on an exclusive membership
* is an error. On an existing inclusive membership,
* full-state SSM API with the delta-based API,
* which is discouraged in the relevant RFCs.
*/
- lims = imo_match_source(imo, idx, &ssa->sa);
+ lims = imo_match_source(imo, idx, ssa);
if (lims != NULL /*&&
lims->imsl_st[1] == MCAST_INCLUDE*/) {
error = EADDRNOTAVAIL;
* been allocated yet if this is a new membership, however,
* the in_mfilter slot will be allocated and must be initialized.
*/
- if (ssa->ss.ss_family != AF_UNSPEC) {
+ if (ssa->sin_family != AF_UNSPEC) {
/* Membership starts in IN mode */
if (is_new) {
IGMP_PRINTF(("%s: new join w/source\n", __func__));
} else {
IGMP_PRINTF(("%s: %s source\n", __func__, "allow"));
}
- lims = imf_graft(imf, MCAST_INCLUDE, &ssa->sin);
+ lims = imf_graft(imf, MCAST_INCLUDE, ssa);
if (lims == NULL) {
IGMP_PRINTF(("%s: merge imf state failed\n",
__func__));
/*
* Begin state merge transaction at IGMP layer.
*/
-
if (is_new) {
+ /*
+ * Unlock socket as we may end up calling ifnet_ioctl() to join (or leave)
+ * the multicast group and we run the risk of a lock ordering issue
+ * if the ifnet thread calls into the socket layer to acquire the pcb list
+ * lock while the input thread delivers multicast packets
+ */
+ IMO_ADDREF_LOCKED(imo);
+ IMO_UNLOCK(imo);
+ socket_unlock(inp->inp_socket, 0);
+
VERIFY(inm == NULL);
- error = in_joingroup(ifp, &gsa->sin.sin_addr, imf, &inm);
+ error = in_joingroup(ifp, &gsa->sin_addr, imf, &inm);
+
+ socket_lock(inp->inp_socket, 0);
+ IMO_REMREF(imo);
+ IMO_LOCK(imo);
+
VERIFY(inm != NULL || error != 0);
if (error)
goto out_imo_free;
{
struct group_source_req gsr;
struct ip_mreq_source mreqs;
- sockunion_t *gsa, *ssa;
+ struct sockaddr_in *gsa, *ssa;
struct ifnet *ifp;
struct in_mfilter *imf;
struct ip_moptions *imo;
is_final = 1;
memset(&gsr, 0, sizeof(struct group_source_req));
- gsa = (sockunion_t *)&gsr.gsr_group;
- gsa->ss.ss_family = AF_UNSPEC;
- ssa = (sockunion_t *)&gsr.gsr_source;
- ssa->ss.ss_family = AF_UNSPEC;
+ gsa = (struct sockaddr_in *)&gsr.gsr_group;
+ ssa = (struct sockaddr_in *)&gsr.gsr_source;
switch (sopt->sopt_name) {
case IP_DROP_MEMBERSHIP:
if (error)
return (error);
- gsa->sin.sin_family = AF_INET;
- gsa->sin.sin_len = sizeof(struct sockaddr_in);
- gsa->sin.sin_addr = mreqs.imr_multiaddr;
+ gsa->sin_family = AF_INET;
+ gsa->sin_len = sizeof(struct sockaddr_in);
+ gsa->sin_addr = mreqs.imr_multiaddr;
if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) {
- ssa->sin.sin_family = AF_INET;
- ssa->sin.sin_len = sizeof(struct sockaddr_in);
- ssa->sin.sin_addr = mreqs.imr_sourceaddr;
+ ssa->sin_family = AF_INET;
+ ssa->sin_len = sizeof(struct sockaddr_in);
+ ssa->sin_addr = mreqs.imr_sourceaddr;
}
/*
* Attempt to look up hinted ifp from interface address.
if (error)
return (error);
- if (gsa->sin.sin_family != AF_INET ||
- gsa->sin.sin_len != sizeof(struct sockaddr_in))
+ if (gsa->sin_family != AF_INET ||
+ gsa->sin_len != sizeof(struct sockaddr_in))
return (EINVAL);
if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) {
- if (ssa->sin.sin_family != AF_INET ||
- ssa->sin.sin_len != sizeof(struct sockaddr_in))
+ if (ssa->sin_family != AF_INET ||
+ ssa->sin_len != sizeof(struct sockaddr_in))
return (EINVAL);
}
IGMP_PRINTF(("%s: unknown sopt_name %d\n",
__func__, sopt->sopt_name));
return (EOPNOTSUPP);
- break;
}
- if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
+ if (!IN_MULTICAST(ntohl(gsa->sin_addr.s_addr)))
return (EINVAL);
/*
return (ENOMEM);
IMO_LOCK(imo);
- idx = imo_match_group(imo, ifp, &gsa->sa);
+ idx = imo_match_group(imo, ifp, gsa);
if (idx == (size_t)-1) {
error = EADDRNOTAVAIL;
goto out_locked;
inm = imo->imo_membership[idx];
imf = &imo->imo_mfilters[idx];
- if (ssa->ss.ss_family != AF_UNSPEC) {
+ if (ssa->sin_family != AF_UNSPEC) {
IGMP_PRINTF(("%s: opt=%d is_final=0\n", __func__,
sopt->sopt_name));
is_final = 0;
error = EADDRNOTAVAIL;
goto out_locked;
}
- ims = imo_match_source(imo, idx, &ssa->sa);
+ ims = imo_match_source(imo, idx, ssa);
if (ims == NULL) {
- IGMP_INET_PRINTF(ssa->sin.sin_addr,
+ IGMP_INET_PRINTF(ssa->sin_addr,
("%s: source %s %spresent\n", __func__,
_igmp_inet_buf, "not "));
error = EADDRNOTAVAIL;
goto out_locked;
}
IGMP_PRINTF(("%s: %s source\n", __func__, "block"));
- error = imf_prune(imf, &ssa->sin);
+ error = imf_prune(imf, ssa);
if (error) {
IGMP_PRINTF(("%s: merge imf state failed\n",
__func__));
* Begin state merge transaction at IGMP layer.
*/
+
if (is_final) {
/*
* Give up the multicast address record to which
imf_reap(imf);
if (is_final) {
- /* Remove the gap in the membership and filter array. */
+ /* Remove the gap in the membership array. */
VERIFY(inm == imo->imo_membership[idx]);
imo->imo_membership[idx] = NULL;
+
+ /*
+ * See inp_join_group() for why we need to unlock
+ */
+ IMO_ADDREF_LOCKED(imo);
+ IMO_UNLOCK(imo);
+ socket_unlock(inp->inp_socket, 0);
+
INM_REMREF(inm);
+
+ socket_lock(inp->inp_socket, 0);
+ IMO_REMREF(imo);
+ IMO_LOCK(imo);
+
for (++idx; idx < imo->imo_num_memberships; ++idx) {
imo->imo_membership[idx-1] = imo->imo_membership[idx];
imo->imo_mfilters[idx-1] = imo->imo_mfilters[idx];
int error = 0 ;
unsigned int ifindex = 0;
+ bzero(&addr, sizeof(addr));
if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) {
/*
* An interface index was specified using the
static int
inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt)
{
- struct __msfilterreq64 msfr, msfr64;
+ struct __msfilterreq64 msfr = {}, msfr64;
struct __msfilterreq32 msfr32;
- sockunion_t *gsa;
+ struct sockaddr_in *gsa;
struct ifnet *ifp;
struct in_mfilter *imf;
struct ip_moptions *imo;
if (error)
return (error);
/* we never use msfr.msfr_srcs; */
- memcpy(&msfr, &msfr64, sizeof(msfr));
+ memcpy(&msfr, &msfr64, sizeof(msfr64));
} else {
error = sooptcopyin(sopt, &msfr32,
sizeof(struct __msfilterreq32),
if (error)
return (error);
/* we never use msfr.msfr_srcs; */
- memcpy(&msfr, &msfr32, sizeof(msfr));
+ memcpy(&msfr, &msfr32, sizeof(msfr32));
}
if ((size_t) msfr.msfr_nsrcs >
msfr.msfr_group.ss_len != sizeof(struct sockaddr_in))
return (EINVAL);
- gsa = (sockunion_t *)&msfr.msfr_group;
- if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
+ gsa = (struct sockaddr_in *)&msfr.msfr_group;
+ if (!IN_MULTICAST(ntohl(gsa->sin_addr.s_addr)))
return (EINVAL);
- gsa->sin.sin_port = 0; /* ignore port */
+ gsa->sin_port = 0; /* ignore port */
ifnet_head_lock_shared();
if (msfr.msfr_ifindex == 0 || (u_int)if_index < msfr.msfr_ifindex) {
return (ENOMEM);
IMO_LOCK(imo);
- idx = imo_match_group(imo, ifp, &gsa->sa);
+ idx = imo_match_group(imo, ifp, gsa);
if (idx == (size_t)-1 || imo->imo_mfilters == NULL) {
error = EADDRNOTAVAIL;
goto out_imo_locked;
* it is not possible to merge the duplicate code, because the idempotence
* of the IPv4 multicast part of the BSD Sockets API must be preserved;
* the effects of these options must be treated as separate and distinct.
- *
- * FUTURE: The IP_MULTICAST_VIF option may be eliminated if MROUTING
- * is refactored to no longer use vifs.
*/
int
inp_setmoptions(struct inpcb *inp, struct sockopt *sopt)
return (EOPNOTSUPP);
switch (sopt->sopt_name) {
-#if MROUTING
- case IP_MULTICAST_VIF: {
- int vifi;
- /*
- * Select a multicast VIF for transmission.
- * Only useful if multicast forwarding is active.
- */
- if (legal_vif_num == NULL) {
- error = EOPNOTSUPP;
- break;
- }
- error = sooptcopyin(sopt, &vifi, sizeof(int), sizeof(int));
- if (error)
- break;
- if (!legal_vif_num(vifi) && (vifi != -1)) {
- error = EINVAL;
- break;
- }
- imo = inp_findmoptions(inp);
- if (imo == NULL) {
- error = ENOMEM;
- break;
- }
- IMO_LOCK(imo);
- imo->imo_multicast_vif = vifi;
- IMO_UNLOCK(imo);
- IMO_REMREF(imo); /* from inp_findmoptions() */
- break;
- }
-#endif
case IP_MULTICAST_IF:
error = inp_set_multicast_if(inp, sopt);
break;
{
#pragma unused(oidp)
- struct in_addr src, group;
+ struct in_addr src = {}, group;
struct ifnet *ifp;
struct in_multi *inm;
struct in_multistep step;
void
in_multihead_lock_assert(int what)
{
- lck_rw_assert(&in_multihead_lock, what);
+#if !MACH_ASSERT
+#pragma unused(what)
+#endif
+ LCK_RW_ASSERT(&in_multihead_lock, what);
}
void