X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/13f56ec4e58bf8687e2a68032c093c0213dd519b..316670eb35587141e969394ae8537d66b9211e80:/bsd/netinet/igmp.c?ds=sidebyside diff --git a/bsd/netinet/igmp.c b/bsd/netinet/igmp.c index 1142c99e2..7e0cd82e9 100644 --- a/bsd/netinet/igmp.c +++ b/bsd/netinet/igmp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2011 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -556,6 +556,9 @@ igmp_domifattach(struct ifnet *ifp, int how) IGI_ADDREF_LOCKED(igi); /* hold a reference for igi_head */ IGI_ADDREF_LOCKED(igi); /* hold a reference for caller */ IGI_UNLOCK(igi); + ifnet_lock_shared(ifp); + igmp_initsilent(ifp, igi); + ifnet_lock_done(ifp); LIST_INSERT_HEAD(&igi_head, igi, igi_link); @@ -586,6 +589,9 @@ igmp_domifreattach(struct igmp_ifinfo *igi) igi->igi_debug |= IFD_ATTACHED; IGI_ADDREF_LOCKED(igi); /* hold a reference for igi_head */ IGI_UNLOCK(igi); + ifnet_lock_shared(ifp); + igmp_initsilent(ifp, igi); + ifnet_lock_done(ifp); LIST_INSERT_HEAD(&igi_head, igi, igi_link); @@ -651,6 +657,20 @@ igi_delete(const struct ifnet *ifp, struct igmp_inm_relhead *inm_dthead) panic("%s: igmp_ifinfo not found for ifp %p\n", __func__, ifp); } +__private_extern__ void +igmp_initsilent(struct ifnet *ifp, struct igmp_ifinfo *igi) +{ + ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_OWNED); + + IGI_LOCK_ASSERT_NOTHELD(igi); + IGI_LOCK(igi); + if (!(ifp->if_flags & IFF_MULTICAST)) + igi->igi_flags |= IGIF_SILENT; + else + igi->igi_flags &= ~IGIF_SILENT; + IGI_UNLOCK(igi); +} + static void igi_initvar(struct igmp_ifinfo *igi, struct ifnet *ifp, int reattach) { @@ -664,10 +684,6 @@ igi_initvar(struct igmp_ifinfo *igi, struct ifnet *ifp, int reattach) igi->igi_qri = IGMP_QRI_INIT; igi->igi_uri = IGMP_URI_INIT; - /* ifnet is not yet attached; no need to hold ifnet lock */ - if (!(ifp->if_flags & IFF_MULTICAST)) - igi->igi_flags |= IGIF_SILENT; - if (!reattach) SLIST_INIT(&igi->igi_relinmhead); @@ -1553,6 +1569,9 @@ igmp_input(struct mbuf *m, int off) IGMPSTAT_INC(igps_rcv_total); OIGMPSTAT_INC(igps_rcv_total); + /* Expect 32-bit aligned data pointer on strict-align platforms */ + MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); + ip = mtod(m, struct ip *); iphlen = off; @@ -1578,12 +1597,14 @@ igmp_input(struct mbuf *m, int off) else minlen = IGMP_MINLEN; - M_STRUCT_GET(igmp, struct igmp *, m, off, minlen); + /* A bit more expensive than M_STRUCT_GET, but ensures alignment */ + M_STRUCT_GET0(igmp, struct igmp *, m, off, minlen); if (igmp == NULL) { IGMPSTAT_INC(igps_rcv_tooshort); OIGMPSTAT_INC(igps_rcv_tooshort); return; } + VERIFY(IS_P2ALIGNED(igmp, sizeof (u_int32_t))); /* * Validate checksum. @@ -1669,13 +1690,19 @@ igmp_input(struct mbuf *m, int off) return; } igmpv3len = IGMP_V3_QUERY_MINLEN + srclen; - M_STRUCT_GET(igmpv3, struct igmpv3 *, m, + /* + * A bit more expensive than M_STRUCT_GET, + * but ensures alignment. + */ + M_STRUCT_GET0(igmpv3, struct igmpv3 *, m, off, igmpv3len); if (igmpv3 == NULL) { IGMPSTAT_INC(igps_rcv_tooshort); OIGMPSTAT_INC(igps_rcv_tooshort); return; } + VERIFY(IS_P2ALIGNED(igmpv3, + sizeof (u_int32_t))); if (igmp_input_v3_query(ifp, ip, igmpv3) != 0) { m_freem(m); return; @@ -2857,6 +2884,7 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, int type; in_addr_t naddr; uint8_t mode; + u_int16_t ig_numsrc; INM_LOCK_ASSERT_HELD(inm); IGI_LOCK_ASSERT_HELD(inm->inm_igi); @@ -3026,12 +3054,12 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, if (record_has_sources) { if (m == m0) { md = m_last(m); - pig = (struct igmp_grouprec *)(mtod(md, uint8_t *) + - md->m_len - nbytes); + pig = (struct igmp_grouprec *)(void *) + (mtod(md, uint8_t *) + md->m_len - nbytes); } else { md = m_getptr(m, 0, &off); - pig = (struct igmp_grouprec *)(mtod(md, uint8_t *) + - off); + pig = (struct igmp_grouprec *)(void *) + (mtod(md, uint8_t *) + off); } msrcs = 0; RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, nims) { @@ -3065,7 +3093,8 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, } IGMP_PRINTF(("%s: msrcs is %d this packet\n", __func__, msrcs)); - pig->ig_numsrc = htons(msrcs); + ig_numsrc = htons(msrcs); + bcopy(&ig_numsrc, &pig->ig_numsrc, sizeof (ig_numsrc)); nbytes += (msrcs * sizeof(in_addr_t)); } @@ -3114,7 +3143,8 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, if (m == NULL) return (-ENOMEM); md = m_getptr(m, 0, &off); - pig = (struct igmp_grouprec *)(mtod(md, uint8_t *) + off); + pig = (struct igmp_grouprec *)(void *) + (mtod(md, uint8_t *) + off); IGMP_PRINTF(("%s: allocated next packet\n", __func__)); if (!m_append(m, sizeof(struct igmp_grouprec), (void *)&ig)) { @@ -3157,7 +3187,8 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, if (msrcs == m0srcs) break; } - pig->ig_numsrc = htons(msrcs); + ig_numsrc = htons(msrcs); + bcopy(&ig_numsrc, &pig->ig_numsrc, sizeof (ig_numsrc)); nbytes += (msrcs * sizeof(in_addr_t)); IGMP_PRINTF(("%s: enqueueing next packet\n", __func__)); @@ -3216,6 +3247,7 @@ igmp_v3_enqueue_filter_change(struct ifqueue *ifq, struct in_multi *inm) int nallow, nblock; uint8_t mode, now, then; rectype_t crt, drt, nrt; + u_int16_t ig_numsrc; INM_LOCK_ASSERT_HELD(inm); @@ -3301,12 +3333,12 @@ igmp_v3_enqueue_filter_change(struct ifqueue *ifq, struct in_multi *inm) /* new packet; offset in c hain */ md = m_getptr(m, npbytes - sizeof(struct igmp_grouprec), &off); - pig = (struct igmp_grouprec *)(mtod(md, + pig = (struct igmp_grouprec *)(void *)(mtod(md, uint8_t *) + off); } else { /* current packet; offset from last append */ md = m_last(m); - pig = (struct igmp_grouprec *)(mtod(md, + pig = (struct igmp_grouprec *)(void *)(mtod(md, uint8_t *) + md->m_len - sizeof(struct igmp_grouprec)); } @@ -3384,7 +3416,8 @@ igmp_v3_enqueue_filter_change(struct ifqueue *ifq, struct in_multi *inm) pig->ig_type = IGMP_ALLOW_NEW_SOURCES; else if (crt == REC_BLOCK) pig->ig_type = IGMP_BLOCK_OLD_SOURCES; - pig->ig_numsrc = htons(rsrcs); + ig_numsrc = htons(rsrcs); + bcopy(&ig_numsrc, &pig->ig_numsrc, sizeof (ig_numsrc)); /* * Count the new group record, and enqueue this * packet if it wasn't already queued. @@ -3658,6 +3691,13 @@ igmp_sendpkt(struct mbuf *m, struct ifnet *ifp) #ifdef MAC mac_netinet_igmp_send(ifp, m0); #endif + + if (ifp->if_eflags & IFEF_TXSTART) { + /* Use control service class if the interface supports + * transmit-start model. + */ + (void) m_set_service_class(m0, MBUF_SC_CTL); + } bzero(&ro, sizeof (ro)); error = ip_output(m0, ipopts, &ro, 0, imo, NULL); if (ro.ro_rt != NULL) {