X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..fe8ab488e9161c46dd9885d58fc52996dc0249ff:/bsd/netinet/in_mcast.c diff --git a/bsd/netinet/in_mcast.c b/bsd/netinet/in_mcast.c index 1854fd26e..893665ada 100644 --- a/bsd/netinet/in_mcast.c +++ b/bsd/netinet/in_mcast.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011 Apple Inc. All rights reserved. + * Copyright (c) 2010-2013 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -243,9 +243,6 @@ static void ipms_free(struct ip_msource *); static struct in_msource *inms_alloc(int); static void inms_free(struct in_msource *); -#define IMO_CAST_TO_NONCONST(x) ((struct ip_moptions *)(void *)(uintptr_t)x) -#define INM_CAST_TO_NONCONST(x) ((struct in_multi *)(void *)(uintptr_t)x) - static __inline int ip_msource_cmp(const struct ip_msource *a, const struct ip_msource *b) { @@ -345,9 +342,9 @@ imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp, int idx; int nmships; - IMO_LOCK_ASSERT_HELD(IMO_CAST_TO_NONCONST(imo)); + IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions *, imo)); - gsin = (const struct sockaddr_in *)group; + 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) @@ -388,7 +385,7 @@ imo_match_source(const struct ip_moptions *imo, const size_t gidx, struct ip_msource *ims; const sockunion_t *psa; - IMO_LOCK_ASSERT_HELD(IMO_CAST_TO_NONCONST(imo)); + IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions *, imo)); VERIFY(src->sa_family == AF_INET); VERIFY(gidx != (size_t)-1 && gidx < imo->imo_num_memberships); @@ -399,7 +396,7 @@ imo_match_source(const struct ip_moptions *imo, const size_t gidx, imf = &imo->imo_mfilters[gidx]; /* Source trees are keyed in host byte order. */ - psa = (const sockunion_t *)src; + psa = (sockunion_t *)(uintptr_t)(size_t)src; find.ims_haddr = ntohl(psa->sin.sin_addr.s_addr); ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find); @@ -420,7 +417,7 @@ imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, struct in_msource *ims; int mode; - IMO_LOCK_ASSERT_HELD(IMO_CAST_TO_NONCONST(imo)); + IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions *, imo)); VERIFY(ifp != NULL); gidx = imo_match_group(imo, ifp, group); @@ -448,9 +445,21 @@ imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, } int -imo_clone(struct ip_moptions *from, struct ip_moptions *to) +imo_clone(struct inpcb *from_inp, struct inpcb *to_inp) { int i, err = 0; + struct ip_moptions *from; + struct ip_moptions *to; + + from = inp_findmoptions(from_inp); + if (from == NULL) + return (ENOMEM); + + to = inp_findmoptions(to_inp); + if (to == NULL) { + IMO_REMREF(from); + return (ENOMEM); + } IMO_LOCK(from); IMO_LOCK(to); @@ -497,16 +506,21 @@ imo_clone(struct ip_moptions *from, struct ip_moptions *to) * Source filtering doesn't apply to OpenTransport socket, * so simply hold additional reference count per membership. */ - for (i = 0; i < from->imo_num_memberships; i++) { - to->imo_membership[i] = from->imo_membership[i]; - INM_ADDREF(from->imo_membership[i]); + for (i = 0; i < from->imo_num_memberships; i++) { + to->imo_membership[i] = + in_addmulti(&from->imo_membership[i]->inm_addr, + from->imo_membership[i]->inm_ifp); + if (to->imo_membership[i] == NULL) + break; to->imo_num_memberships++; } VERIFY(to->imo_num_memberships == from->imo_num_memberships); done: IMO_UNLOCK(to); + IMO_REMREF(to); IMO_UNLOCK(from); + IMO_REMREF(from); return (err); } @@ -844,7 +858,8 @@ imf_rollback(struct in_mfilter *imf) lims->imsl_st[1] = lims->imsl_st[0]; } else { /* revert source added t1 */ - IGMP_PRINTF(("%s: free inms %p\n", __func__, lims)); + IGMP_PRINTF(("%s: free inms 0x%llx\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(lims))); RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims); inms_free(lims); imf->imf_nsrc--; @@ -904,7 +919,8 @@ imf_reap(struct in_mfilter *imf) lims = (struct in_msource *)ims; if ((lims->imsl_st[0] == MCAST_UNDEFINED) && (lims->imsl_st[1] == MCAST_UNDEFINED)) { - IGMP_PRINTF(("%s: free inms %p\n", __func__, lims)); + IGMP_PRINTF(("%s: free inms 0x%llx\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(lims))); RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims); inms_free(lims); imf->imf_nsrc--; @@ -925,7 +941,8 @@ imf_purge(struct in_mfilter *imf) RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) { lims = (struct in_msource *)ims; - IGMP_PRINTF(("%s: free inms %p\n", __func__, lims)); + IGMP_PRINTF(("%s: free inms 0x%llx\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(lims))); RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims); inms_free(lims); imf->imf_nsrc--; @@ -952,6 +969,7 @@ inm_get_source(struct in_multi *inm, const in_addr_t haddr, struct ip_msource *ims, *nims; #ifdef IGMP_DEBUG struct in_addr ia; + char buf[MAX_IPv4_STR_LEN]; #endif INM_LOCK_ASSERT_HELD(inm); @@ -969,8 +987,9 @@ inm_get_source(struct in_multi *inm, const in_addr_t haddr, ims = nims; #ifdef IGMP_DEBUG ia.s_addr = htonl(haddr); - IGMP_PRINTF(("%s: allocated %s as %p\n", __func__, - inet_ntoa(ia), ims)); + inet_ntop(AF_INET, &ia, buf, sizeof(buf)); + IGMP_PRINTF(("%s: allocated %s as 0x%llx\n", __func__, + buf, (uint64_t)VM_KERNEL_ADDRPERM(ims))); #endif } @@ -990,7 +1009,7 @@ uint8_t ims_get_mode(const struct in_multi *inm, const struct ip_msource *ims, uint8_t t) { - INM_LOCK_ASSERT_HELD(INM_CAST_TO_NONCONST(inm)); + INM_LOCK_ASSERT_HELD(__DECONST(struct in_multi *, inm)); t = !!t; if (inm->inm_st[t].iss_ex > 0 && @@ -1017,22 +1036,26 @@ ims_merge(struct ip_msource *ims, const struct in_msource *lims, #endif if (lims->imsl_st[0] == MCAST_EXCLUDE) { - IGMP_PRINTF(("%s: t1 ex -= %d on %s\n", - __func__, n, inet_ntoa(ia))); + IGMP_INET_PRINTF(ia, + ("%s: t1 ex -= %d on %s\n", + __func__, n, _igmp_inet_buf)); ims->ims_st[1].ex -= n; } else if (lims->imsl_st[0] == MCAST_INCLUDE) { - IGMP_PRINTF(("%s: t1 in -= %d on %s\n", - __func__, n, inet_ntoa(ia))); + IGMP_INET_PRINTF(ia, + ("%s: t1 in -= %d on %s\n", + __func__, n, _igmp_inet_buf)); ims->ims_st[1].in -= n; } if (lims->imsl_st[1] == MCAST_EXCLUDE) { - IGMP_PRINTF(("%s: t1 ex += %d on %s\n", - __func__, n, inet_ntoa(ia))); + IGMP_INET_PRINTF(ia, + ("%s: t1 ex += %d on %s\n", + __func__, n, _igmp_inet_buf)); ims->ims_st[1].ex += n; } else if (lims->imsl_st[1] == MCAST_INCLUDE) { - IGMP_PRINTF(("%s: t1 in += %d on %s\n", - __func__, n, inet_ntoa(ia))); + IGMP_INET_PRINTF(ia, + ("%s: t1 in += %d on %s\n", + __func__, n, _igmp_inet_buf)); ims->ims_st[1].in += n; } } @@ -1166,7 +1189,9 @@ inm_merge(struct in_multi *inm, /*const*/ struct in_mfilter *imf) inm->inm_st[1].iss_asm++; } - IGMP_PRINTF(("%s: merged imf %p to inm %p\n", __func__, imf, inm)); + IGMP_PRINTF(("%s: merged imf 0x%llx to inm 0x%llx\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(imf), + (uint64_t)VM_KERNEL_ADDRPERM(inm))); inm_print(inm); out_reap: @@ -1188,7 +1213,8 @@ inm_commit(struct in_multi *inm) INM_LOCK_ASSERT_HELD(inm); - IGMP_PRINTF(("%s: commit inm %p\n", __func__, inm)); + IGMP_PRINTF(("%s: commit inm 0x%llx\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(inm))); IGMP_PRINTF(("%s: pre commit:\n", __func__)); inm_print(inm); @@ -1213,7 +1239,8 @@ inm_reap(struct in_multi *inm) ims->ims_st[1].ex > 0 || ims->ims_st[1].in > 0 || ims->ims_stp != 0) continue; - IGMP_PRINTF(("%s: free ims %p\n", __func__, ims)); + IGMP_PRINTF(("%s: free ims 0x%llx\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(ims))); RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims); ipms_free(ims); inm->inm_nsrc--; @@ -1231,7 +1258,8 @@ inm_purge(struct in_multi *inm) INM_LOCK_ASSERT_HELD(inm); RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, tims) { - IGMP_PRINTF(("%s: free ims %p\n", __func__, ims)); + IGMP_PRINTF(("%s: free ims 0x%llx\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(ims))); RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims); ipms_free(ims); inm->inm_nsrc--; @@ -1254,10 +1282,12 @@ in_joingroup(struct ifnet *ifp, const struct in_addr *gina, struct in_mfilter timf; struct in_multi *inm = NULL; int error = 0; + struct igmp_tparams itp; - IGMP_PRINTF(("%s: join %s on %p(%s%d))\n", __func__, - inet_ntoa(*gina), ifp, ifp->if_name, ifp->if_unit)); + IGMP_INET_PRINTF(*gina, ("%s: join %s on 0x%llx(%s))\n", __func__, + _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp), if_name(ifp))); + bzero(&itp, sizeof (itp)); *pinm = NULL; /* @@ -1285,15 +1315,17 @@ in_joingroup(struct ifnet *ifp, const struct in_addr *gina, } IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); - error = igmp_change_state(inm); + error = igmp_change_state(inm, &itp); if (error) { IGMP_PRINTF(("%s: failed to update source\n", __func__)); + imf_rollback(imf); goto out_inm_release; } out_inm_release: if (error) { - IGMP_PRINTF(("%s: dropping ref on %p\n", __func__, inm)); + IGMP_PRINTF(("%s: dropping ref on 0x%llx\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(inm))); INM_UNLOCK(inm); INM_REMREF(inm); } else { @@ -1301,6 +1333,9 @@ out_inm_release: *pinm = inm; /* keep refcount from in_getmulti() */ } + /* schedule timer now that we've dropped the lock(s) */ + igmp_set_timeout(&itp); + return (error); } @@ -1318,7 +1353,9 @@ in_leavegroup(struct in_multi *inm, /*const*/ struct in_mfilter *imf) { struct in_mfilter timf; int error, lastref; + struct igmp_tparams itp; + bzero(&itp, sizeof (itp)); error = 0; INM_LOCK_ASSERT_NOTHELD(inm); @@ -1326,10 +1363,11 @@ in_leavegroup(struct in_multi *inm, /*const*/ struct in_mfilter *imf) in_multihead_lock_exclusive(); INM_LOCK(inm); - IGMP_PRINTF(("%s: leave inm %p, %s/%s%d, imf %p\n", __func__, - inm, inet_ntoa(inm->inm_addr), + IGMP_INET_PRINTF(inm->inm_addr, + ("%s: leave inm 0x%llx, %s/%s%d, imf 0x%llx\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(inm), _igmp_inet_buf, (inm_is_ifp_detached(inm) ? "null" : inm->inm_ifp->if_name), - inm->inm_ifp->if_unit, imf)); + inm->inm_ifp->if_unit, (uint64_t)VM_KERNEL_ADDRPERM(imf))); /* * If no imf was specified (i.e. kernel consumer), @@ -1353,7 +1391,7 @@ in_leavegroup(struct in_multi *inm, /*const*/ struct in_mfilter *imf) KASSERT(error == 0, ("%s: failed to merge inm state\n", __func__)); IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); - error = igmp_change_state(inm); + error = igmp_change_state(inm, &itp); #if IGMP_DEBUG if (error) IGMP_PRINTF(("%s: failed igmp downcall\n", __func__)); @@ -1367,6 +1405,9 @@ in_leavegroup(struct in_multi *inm, /*const*/ struct in_mfilter *imf) if (lastref) INM_REMREF(inm); /* for in_multihead list */ + /* schedule timer now that we've dropped the lock(s) */ + igmp_set_timeout(&itp); + return (error); } @@ -1424,7 +1465,9 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) uint16_t fmode; int error, doblock; unsigned int ifindex = 0; + struct igmp_tparams itp; + bzero(&itp, sizeof (itp)); ifp = NULL; error = 0; doblock = 0; @@ -1458,8 +1501,9 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) if (sopt->sopt_name == IP_BLOCK_SOURCE) doblock = 1; - IGMP_PRINTF(("%s: imr_interface = %s, ifp = %p\n", - __func__, inet_ntoa(mreqs.imr_interface), ifp)); + IGMP_INET_PRINTF(mreqs.imr_interface, + ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__, + _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp))); break; } @@ -1542,8 +1586,9 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) */ ims = imo_match_source(imo, idx, &ssa->sa); if ((ims != NULL && doblock) || (ims == NULL && !doblock)) { - IGMP_PRINTF(("%s: source %s %spresent\n", __func__, - inet_ntoa(ssa->sin.sin_addr), doblock ? "" : "not ")); + IGMP_INET_PRINTF(ssa->sin.sin_addr, + ("%s: source %s %spresent\n", __func__, + _igmp_inet_buf, doblock ? "" : "not ")); error = EADDRNOTAVAIL; goto out_imo_locked; } @@ -1579,7 +1624,7 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) } IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); - error = igmp_change_state(inm); + error = igmp_change_state(inm, &itp); INM_UNLOCK(inm); #if IGMP_DEBUG if (error) @@ -1597,6 +1642,10 @@ out_imf_rollback: out_imo_locked: IMO_UNLOCK(imo); IMO_REMREF(imo); /* from inp_findmoptions() */ + + /* schedule timer now that we've dropped the lock(s) */ + igmp_set_timeout(&itp); + return (error); } @@ -1710,7 +1759,11 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) if (ifp == NULL) return (EADDRNOTAVAIL); - + + if ((size_t) msfr.msfr_nsrcs > + UINT32_MAX / sizeof(struct sockaddr_storage)) + msfr.msfr_nsrcs = UINT32_MAX / sizeof(struct sockaddr_storage); + if (msfr.msfr_nsrcs > in_mcast_maxsocksrc) msfr.msfr_nsrcs = in_mcast_maxsocksrc; @@ -1750,12 +1803,13 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) tss = NULL; if (tmp_ptr != USER_ADDR_NULL && msfr.msfr_nsrcs > 0) { - tss = _MALLOC(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs, + tss = _MALLOC((size_t) msfr.msfr_nsrcs * sizeof(*tss), M_TEMP, M_WAITOK | M_ZERO); if (tss == NULL) { IMO_UNLOCK(imo); return (ENOBUFS); } + bzero(tss, (size_t) msfr.msfr_nsrcs * sizeof(*tss)); } /* @@ -1785,8 +1839,7 @@ inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) IMO_UNLOCK(imo); if (tss != NULL) { - error = copyout(tss, tmp_ptr, - sizeof(struct sockaddr_storage) * ncsrcs); + error = copyout(tss, tmp_ptr, ncsrcs * sizeof(*tss)); FREE(tss, M_TEMP); if (error) return (error); @@ -1833,26 +1886,14 @@ inp_getmoptions(struct inpcb *inp, struct sockopt *sopt) * If socket is neither of type SOCK_RAW or SOCK_DGRAM, * or is a divert socket, reject it. */ - if (inp->inp_socket->so_proto->pr_protocol == IPPROTO_DIVERT || - (inp->inp_socket->so_proto->pr_type != SOCK_RAW && - inp->inp_socket->so_proto->pr_type != SOCK_DGRAM)) { + if (SOCK_PROTO(inp->inp_socket) == IPPROTO_DIVERT || + (SOCK_TYPE(inp->inp_socket) != SOCK_RAW && + SOCK_TYPE(inp->inp_socket) != SOCK_DGRAM)) { return (EOPNOTSUPP); } 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) { @@ -1980,7 +2021,7 @@ inp_lookup_mcast_ifp(const struct inpcb *inp, unsigned int ifscope = IFSCOPE_NONE; if (inp != NULL && (inp->inp_flags & INP_BOUND_IF)) - ifscope = inp->inp_boundif; + ifscope = inp->inp_boundifp->if_index; bzero(&ro, sizeof (ro)); memcpy(&ro.ro_dst, gsin, sizeof(struct sockaddr_in)); @@ -1988,7 +2029,6 @@ inp_lookup_mcast_ifp(const struct inpcb *inp, if (ro.ro_rt != NULL) { ifp = ro.ro_rt->rt_ifp; VERIFY(ifp != NULL); - rtfree(ro.ro_rt); } else { struct in_ifaddr *ia; struct ifnet *mifp; @@ -2007,6 +2047,7 @@ inp_lookup_mcast_ifp(const struct inpcb *inp, } lck_rw_done(in_ifaddr_rwlock); } + ROUTE_RELEASE(&ro); } return (ifp); @@ -2032,7 +2073,9 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) struct in_msource *lims; size_t idx; int error, is_new; + struct igmp_tparams itp; + bzero(&itp, sizeof (itp)); ifp = NULL; imf = NULL; error = 0; @@ -2086,8 +2129,9 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) ifp = inp_lookup_mcast_ifp(inp, &gsa->sin, mreqs.imr_interface); - IGMP_PRINTF(("%s: imr_interface = %s, ifp = %p\n", - __func__, inet_ntoa(mreqs.imr_interface), ifp)); + IGMP_INET_PRINTF(mreqs.imr_interface, + ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__, + _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp))); break; } @@ -2285,7 +2329,7 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) goto out_imf_rollback; } IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); - error = igmp_change_state(inm); + error = igmp_change_state(inm, &itp); INM_UNLOCK(inm); if (error) { IGMP_PRINTF(("%s: failed igmp downcall\n", @@ -2315,6 +2359,10 @@ out_imo_free: out_imo_locked: IMO_UNLOCK(imo); IMO_REMREF(imo); /* from inp_findmoptions() */ + + /* schedule timer now that we've dropped the lock(s) */ + igmp_set_timeout(&itp); + return (error); } @@ -2338,7 +2386,9 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) size_t idx; int error, is_final; unsigned int ifindex = 0; + struct igmp_tparams itp; + bzero(&itp, sizeof (itp)); ifp = NULL; error = 0; is_final = 1; @@ -2390,8 +2440,9 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) if (!in_nullhost(mreqs.imr_interface)) ifp = ip_multicast_if(&mreqs.imr_interface, &ifindex); - IGMP_PRINTF(("%s: imr_interface = %s, ifp = %p\n", - __func__, inet_ntoa(mreqs.imr_interface), ifp)); + IGMP_INET_PRINTF(mreqs.imr_interface, + ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__, + _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp))); break; @@ -2479,8 +2530,9 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) } ims = imo_match_source(imo, idx, &ssa->sa); if (ims == NULL) { - IGMP_PRINTF(("%s: source %s %spresent\n", __func__, - inet_ntoa(ssa->sin.sin_addr), "not ")); + IGMP_INET_PRINTF(ssa->sin.sin_addr, + ("%s: source %s %spresent\n", __func__, + _igmp_inet_buf, "not ")); error = EADDRNOTAVAIL; goto out_locked; } @@ -2516,7 +2568,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) } IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); - error = igmp_change_state(inm); + error = igmp_change_state(inm, &itp); if (error) { IGMP_PRINTF(("%s: failed igmp downcall\n", __func__)); } @@ -2546,6 +2598,10 @@ out_imf_rollback: out_locked: IMO_UNLOCK(imo); IMO_REMREF(imo); /* from inp_findmoptions() */ + + /* schedule timer now that we've dropped the lock(s) */ + igmp_set_timeout(&itp); + return (error); } @@ -2607,14 +2663,16 @@ inp_set_multicast_if(struct inpcb *inp, struct sockopt *sopt) } else { ifp = ip_multicast_if(&addr, &ifindex); if (ifp == NULL) { - IGMP_PRINTF(("%s: can't find ifp for addr=%s\n", - __func__, inet_ntoa(addr))); + IGMP_INET_PRINTF(addr, + ("%s: can't find ifp for addr=%s\n", + __func__, _igmp_inet_buf)); return (EADDRNOTAVAIL); } } + /* XXX remove? */ #ifdef IGMP_DEBUG0 - IGMP_PRINTF(("%s: ifp = %p, addr = %s\n", __func__, ifp, - inet_ntoa(addr))); + IGMP_PRINTF(("%s: ifp = 0x%llx, addr = %s\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(ifp), inet_ntoa(addr))); #endif } @@ -2651,9 +2709,12 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) struct in_mfilter *imf; struct ip_moptions *imo; struct in_multi *inm; - size_t idx; + size_t idx; int error; - user_addr_t tmp_ptr; + user_addr_t tmp_ptr; + struct igmp_tparams itp; + + bzero(&itp, sizeof (itp)); if (IS_64BIT_PROCESS(current_proc())) { error = sooptcopyin(sopt, &msfr64, @@ -2673,6 +2734,10 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) memcpy(&msfr, &msfr32, sizeof(msfr)); } + if ((size_t) msfr.msfr_nsrcs > + UINT32_MAX / sizeof(struct sockaddr_storage)) + msfr.msfr_nsrcs = UINT32_MAX / sizeof(struct sockaddr_storage); + if (msfr.msfr_nsrcs > in_mcast_maxsocksrc) return (ENOBUFS); @@ -2742,14 +2807,14 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) IGMP_PRINTF(("%s: loading %lu source list entries\n", __func__, (unsigned long)msfr.msfr_nsrcs)); - kss = _MALLOC(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs, + kss = _MALLOC((size_t) msfr.msfr_nsrcs * sizeof(*kss), M_TEMP, M_WAITOK); if (kss == NULL) { error = ENOMEM; goto out_imo_locked; } error = copyin(tmp_ptr, kss, - sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs); + (size_t) msfr.msfr_nsrcs * sizeof(*kss)); if (error) { FREE(kss, M_TEMP); goto out_imo_locked; @@ -2809,7 +2874,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) } IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); - error = igmp_change_state(inm); + error = igmp_change_state(inm, &itp); INM_UNLOCK(inm); #ifdef IGMP_DEBUG if (error) @@ -2828,6 +2893,9 @@ out_imo_locked: IMO_UNLOCK(imo); IMO_REMREF(imo); /* from inp_findmoptions() */ + /* schedule timer now that we've dropped the lock(s) */ + igmp_set_timeout(&itp); + return (error); } @@ -2839,9 +2907,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) @@ -2857,42 +2922,12 @@ inp_setmoptions(struct inpcb *inp, struct sockopt *sopt) * If socket is neither of type SOCK_RAW or SOCK_DGRAM, * or is a divert socket, reject it. */ - if (inp->inp_socket->so_proto->pr_protocol == IPPROTO_DIVERT || - (inp->inp_socket->so_proto->pr_type != SOCK_RAW && - inp->inp_socket->so_proto->pr_type != SOCK_DGRAM)) + if (SOCK_PROTO(inp->inp_socket) == IPPROTO_DIVERT || + (SOCK_TYPE(inp->inp_socket) != SOCK_RAW && + SOCK_TYPE(inp->inp_socket) != SOCK_DGRAM)) 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; @@ -3104,8 +3139,9 @@ sysctl_ip_mcast_filters SYSCTL_HANDLER_ARGS group.s_addr = name[1]; if (!IN_MULTICAST(ntohl(group.s_addr))) { - IGMP_PRINTF(("%s: group %s is not multicast\n", - __func__, inet_ntoa(group))); + IGMP_INET_PRINTF(group, + ("%s: group %s is not multicast\n", + __func__, _igmp_inet_buf)); ifnet_head_done(); return (EINVAL); } @@ -3137,8 +3173,8 @@ sysctl_ip_mcast_filters SYSCTL_HANDLER_ARGS #ifdef IGMP_DEBUG struct in_addr ina; ina.s_addr = htonl(ims->ims_haddr); - IGMP_PRINTF(("%s: visit node %s\n", __func__, - inet_ntoa(ina))); + IGMP_INET_PRINTF(ina, + ("%s: visit node %s\n", __func__, _igmp_inet_buf)); #endif /* * Only copy-out sources which are in-mode. @@ -3572,6 +3608,7 @@ inm_mode_str(const int mode) static const char *inm_statestrs[] = { "not-member\n", "silent\n", + "reporting\n", "idle\n", "lazy\n", "sleeping\n", @@ -3596,26 +3633,28 @@ void inm_print(const struct in_multi *inm) { int t; + char buf[MAX_IPv4_STR_LEN]; - INM_LOCK_ASSERT_HELD(INM_CAST_TO_NONCONST(inm)); + INM_LOCK_ASSERT_HELD(__DECONST(struct in_multi *, inm)); if (igmp_debug == 0) return; - printf("%s: --- begin inm %p ---\n", __func__, inm); - printf("addr %s ifp %p(%s%d) ifma %p\n", - inet_ntoa(inm->inm_addr), - inm->inm_ifp, - inm->inm_ifp->if_name, - inm->inm_ifp->if_unit, - inm->inm_ifma); + inet_ntop(AF_INET, &inm->inm_addr, buf, sizeof(buf)); + printf("%s: --- begin inm 0x%llx ---\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(inm)); + printf("addr %s ifp 0x%llx(%s) ifma 0x%llx\n", + buf, + (uint64_t)VM_KERNEL_ADDRPERM(inm->inm_ifp), + if_name(inm->inm_ifp), + (uint64_t)VM_KERNEL_ADDRPERM(inm->inm_ifma)); printf("timer %u state %s refcount %u scq.len %u\n", inm->inm_timer, inm_state_str(inm->inm_state), inm->inm_refcount, inm->inm_scq.ifq_len); - printf("igi %p nsrc %lu sctimer %u scrv %u\n", - inm->inm_igi, + printf("igi 0x%llx nsrc %lu sctimer %u scrv %u\n", + (uint64_t)VM_KERNEL_ADDRPERM(inm->inm_igi), inm->inm_nsrc, inm->inm_sctimer, inm->inm_scrv); @@ -3627,7 +3666,8 @@ inm_print(const struct in_multi *inm) inm->inm_st[t].iss_in, inm->inm_st[t].iss_rec); } - printf("%s: --- end inm %p ---\n", __func__, inm); + printf("%s: --- end inm 0x%llx ---\n", __func__, + (uint64_t)VM_KERNEL_ADDRPERM(inm)); } #else