]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/in_mcast.c
xnu-3789.1.32.tar.gz
[apple/xnu.git] / bsd / netinet / in_mcast.c
index 13f0b9aa97de060d7f861ee59da014531c48ce07..1d1b56563e601d1b8e1765c049d92cd40f85b166 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2010-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -1544,7 +1544,6 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt)
                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)))
@@ -1737,7 +1736,7 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt)
                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),
@@ -1745,7 +1744,7 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt)
                if (error)
                        return (error);
                /* we never use msfr.msfr_srcs; */
-               memcpy(&msfr, &msfr32, sizeof(msfr));
+               memcpy(&msfr, &msfr32, sizeof(msfr32));
        }
 
        ifnet_head_lock_shared();
@@ -1809,7 +1808,6 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt)
                        IMO_UNLOCK(imo);
                        return (ENOBUFS);
                }
-               bzero(tss, (size_t) msfr.msfr_nsrcs * sizeof(*tss));
        }
 
        /*
@@ -1858,7 +1856,7 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt)
                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));
@@ -1894,18 +1892,6 @@ inp_getmoptions(struct inpcb *inp, struct sockopt *sopt)
 
        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) {
@@ -2195,7 +2181,6 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt)
                IGMP_PRINTF(("%s: unknown sopt_name %d\n",
                    __func__, sopt->sopt_name));
                return (EOPNOTSUPP);
-               break;
        }
 
        if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0)
@@ -2322,10 +2307,24 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt)
        /*
         * 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);
+
+               socket_lock(inp->inp_socket, 0);
+               IMO_REMREF(imo);
+               IMO_LOCK(imo);
+
                VERIFY(inm != NULL || error != 0);
                if (error)
                        goto out_imo_free;
@@ -2497,7 +2496,6 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt)
                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)))
@@ -2561,6 +2559,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt)
         * Begin state merge transaction at IGMP layer.
         */
 
+
        if (is_final) {
                /*
                 * Give up the multicast address record to which
@@ -2596,10 +2595,23 @@ out_imf_rollback:
        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];
@@ -2735,7 +2747,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt)
                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),
@@ -2743,7 +2755,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt)
                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 >
@@ -2919,9 +2931,6 @@ 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)
@@ -2943,36 +2952,6 @@ 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;