/*
- * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
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);
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);
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)
{
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);
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;
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.
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;
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);
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) {
}
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));
}
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)) {
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__));
int nallow, nblock;
uint8_t mode, now, then;
rectype_t crt, drt, nrt;
+ u_int16_t ig_numsrc;
INM_LOCK_ASSERT_HELD(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));
}
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.
#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) {