]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/igmp.c
xnu-2050.7.9.tar.gz
[apple/xnu.git] / bsd / netinet / igmp.c
index 1142c99e2a7fe729f58adbcc26a7e8dbe6d5806f..7e0cd82e92d01d7975f81e20e0180d4951b14c01 100644 (file)
@@ -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) {