X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..3903760236c30e3b5ace7a4eefac3a269d68957c:/bsd/netinet/in_mcast.c diff --git a/bsd/netinet/in_mcast.c b/bsd/netinet/in_mcast.c index 13f0b9aa9..1d1b56563 100644 --- a/bsd/netinet/in_mcast.c +++ b/bsd/netinet/in_mcast.c @@ -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;