]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if_vlan.c
xnu-3789.41.3.tar.gz
[apple/xnu.git] / bsd / net / if_vlan.c
index 1f98f6ac0449a1119e83e10cd3d890791187d882..2dabd32b27585a72381e8cf47439dbe3a4baa4ed 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2003-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -196,13 +196,15 @@ typedef struct vlan_parent {
     vlan_parent_entry          vlp_parent_list;/* list of parents */
     struct ifnet *             vlp_ifp;        /* interface */
     struct ifvlan_list         vlp_vlan_list;  /* list of VLAN's */
     vlan_parent_entry          vlp_parent_list;/* list of parents */
     struct ifnet *             vlp_ifp;        /* interface */
     struct ifvlan_list         vlp_vlan_list;  /* list of VLAN's */
-#define VLPF_SUPPORTS_VLAN_MTU 0x1
-#define VLPF_CHANGE_IN_PROGRESS        0x2
-#define VLPF_DETACHING         0x4
+#define VLPF_SUPPORTS_VLAN_MTU         0x00000001
+#define VLPF_CHANGE_IN_PROGRESS                0x00000002
+#define VLPF_DETACHING                 0x00000004
+#define VLPF_LINK_EVENT_REQUIRED       0x00000008
     u_int32_t                  vlp_flags;
     u_int32_t                  vlp_flags;
+    u_int32_t                  vlp_event_code;
     struct ifdevmtu            vlp_devmtu;
     struct ifdevmtu            vlp_devmtu;
-    SInt32                     vlp_retain_count;
-    UInt32                     vlp_signature;  /* VLP_SIGNATURE */
+    int32_t                    vlp_retain_count;
+    u_int32_t                  vlp_signature;  /* VLP_SIGNATURE */
 } vlan_parent, * vlan_parent_ref;
 
 #define IFV_SIGNATURE          0xbeefbeef
 } vlan_parent, * vlan_parent_ref;
 
 #define IFV_SIGNATURE          0xbeefbeef
@@ -224,8 +226,8 @@ struct ifvlan {
     u_int32_t                  ifv_flags;
     bpf_packet_func            ifv_bpf_input;
     bpf_packet_func            ifv_bpf_output;
     u_int32_t                  ifv_flags;
     bpf_packet_func            ifv_bpf_input;
     bpf_packet_func            ifv_bpf_output;
-    SInt32                     ifv_retain_count;
-    UInt32                     ifv_signature;  /* IFV_SIGNATURE */
+    int32_t                    ifv_retain_count;
+    u_int32_t                  ifv_signature;  /* IFV_SIGNATURE */
 };
 
 typedef struct ifvlan * ifvlan_ref;
 };
 
 typedef struct ifvlan * ifvlan_ref;
@@ -263,13 +265,6 @@ vlan_parent_flags_set_supports_vlan_mtu(vlan_parent_ref vlp)
     return;
 }
 
     return;
 }
 
-static __inline__ void
-vlan_parent_flags_clear_supports_vlan_mtu(vlan_parent_ref vlp)
-{
-    vlp->vlp_flags &= ~VLPF_SUPPORTS_VLAN_MTU;
-    return;
-}
-
 static __inline__ int
 vlan_parent_flags_change_in_progress(vlan_parent_ref vlp)
 {
 static __inline__ int
 vlan_parent_flags_change_in_progress(vlan_parent_ref vlp)
 {
@@ -303,6 +298,26 @@ vlan_parent_flags_set_detaching(struct vlan_parent * vlp)
     return;
 }
 
     return;
 }
 
+static __inline__ int
+vlan_parent_flags_link_event_required(vlan_parent_ref vlp)
+{
+    return ((vlp->vlp_flags & VLPF_LINK_EVENT_REQUIRED) != 0);
+}
+
+static __inline__ void
+vlan_parent_flags_set_link_event_required(vlan_parent_ref vlp)
+{
+    vlp->vlp_flags |= VLPF_LINK_EVENT_REQUIRED;
+    return;
+}
+
+static __inline__ void
+vlan_parent_flags_clear_link_event_required(vlan_parent_ref vlp)
+{
+    vlp->vlp_flags &= ~VLPF_LINK_EVENT_REQUIRED;
+    return;
+}
+
 
 /**
  ** ifvlan_flags in-lines routines
 
 /**
  ** ifvlan_flags in-lines routines
@@ -340,13 +355,6 @@ ifvlan_flags_set_ready(ifvlan_ref ifv)
     return;
 }
 
     return;
 }
 
-static __inline__ void
-ifvlan_flags_clear_ready(ifvlan_ref ifv)
-{
-    ifv->ifv_flags &= ~IFVF_READY;
-    return;
-}
-
 static __inline__ int
 ifvlan_flags_detaching(ifvlan_ref ifv)
 {
 static __inline__ int
 ifvlan_flags_detaching(ifvlan_ref ifv)
 {
@@ -413,7 +421,7 @@ ifvlan_retain(ifvlan_ref ifv)
 static void
 ifvlan_release(ifvlan_ref ifv)
 {
 static void
 ifvlan_release(ifvlan_ref ifv)
 {
-    UInt32             old_retain_count;
+    u_int32_t          old_retain_count;
 
     if (ifv->ifv_signature != IFV_SIGNATURE) {
        panic("ifvlan_release: bad signature\n");
 
     if (ifv->ifv_signature != IFV_SIGNATURE) {
        panic("ifvlan_release: bad signature\n");
@@ -609,7 +617,7 @@ vlan_parent_retain(vlan_parent_ref vlp)
 static void
 vlan_parent_release(vlan_parent_ref vlp)
 {
 static void
 vlan_parent_release(vlan_parent_ref vlp)
 {
-    UInt32             old_retain_count;
+    u_int32_t          old_retain_count;
 
     if (vlp->vlp_signature != VLP_SIGNATURE) {
        panic("vlan_parent_release: signature is bad\n");
 
     if (vlp->vlp_signature != VLP_SIGNATURE) {
        panic("vlan_parent_release: signature is bad\n");
@@ -684,12 +692,34 @@ vlan_parent_wait(vlan_parent_ref vlp, const char * msg)
 static void
 vlan_parent_signal(vlan_parent_ref vlp, const char * msg)
 {
 static void
 vlan_parent_signal(vlan_parent_ref vlp, const char * msg)
 {
+    struct ifnet * vlp_ifp = vlp->vlp_ifp;
+
+    if (vlan_parent_flags_link_event_required(vlp)) {
+       vlan_parent_flags_clear_link_event_required(vlp);
+       if (!vlan_parent_flags_detaching(vlp)) {
+           u_int32_t           event_code = vlp->vlp_event_code;
+           ifvlan_ref          ifv;
+
+           vlan_unlock();
+
+           /* we can safely walk the list unlocked */
+           LIST_FOREACH(ifv, &vlp->vlp_vlan_list, ifv_vlan_list) {
+               struct ifnet *  ifp = ifv->ifv_ifp;
+               
+               interface_link_event(ifp, event_code);
+           }
+           if (g_vlan->verbose) {
+               printf("%s%d: propagated link event to vlans\n",
+                      ifnet_name(vlp_ifp), ifnet_unit(vlp_ifp));
+           }
+           vlan_lock();
+       }
+    }
     vlan_parent_flags_clear_change_in_progress(vlp);
     wakeup((caddr_t)vlp);
     if (g_vlan->verbose) {
     vlan_parent_flags_clear_change_in_progress(vlp);
     wakeup((caddr_t)vlp);
     if (g_vlan->verbose) {
-       struct ifnet * ifp = vlp->vlp_ifp;
-
-       printf("%s%d: %s wakeup\n", ifnet_name(ifp), ifnet_unit(ifp), msg);
+       printf("%s%d: %s wakeup\n",
+              ifnet_name(vlp_ifp), ifnet_unit(vlp_ifp), msg);
     }
     return;
 }
     }
     return;
 }
@@ -822,11 +852,10 @@ vlan_parent_create(struct ifnet * p, vlan_parent_ref * ret_vlp)
     vlan_parent_ref    vlp;
 
     *ret_vlp = NULL;
     vlan_parent_ref    vlp;
 
     *ret_vlp = NULL;
-    vlp = _MALLOC(sizeof(*vlp), M_VLAN, M_WAITOK);
+    vlp = _MALLOC(sizeof(*vlp), M_VLAN, M_WAITOK | M_ZERO);
     if (vlp == NULL) {
        return (ENOMEM);
     }
     if (vlp == NULL) {
        return (ENOMEM);
     }
-    bzero(vlp, sizeof(*vlp));
     error = siocgifdevmtu(p, &vlp->vlp_devmtu);
     if (error != 0) {
        printf("vlan_parent_create (%s%d): siocgifdevmtu failed, %d\n",
     error = siocgifdevmtu(p, &vlp->vlp_devmtu);
     if (error != 0) {
        printf("vlan_parent_create (%s%d): siocgifdevmtu failed, %d\n",
@@ -865,9 +894,9 @@ vlan_parent_remove_all_vlans(struct ifnet * p)
     vlan_parent_retain(vlp);
     vlan_parent_wait(vlp, "vlan_parent_remove_all_vlans");
     need_vlp_release++;
     vlan_parent_retain(vlp);
     vlan_parent_wait(vlp, "vlan_parent_remove_all_vlans");
     need_vlp_release++;
-    vlp = parent_list_lookup(p);
+
     /* check again */
     /* check again */
-    if (vlp == NULL) {
+    if (parent_list_lookup(p) != vlp) {
        goto signal_done;
     }
 
        goto signal_done;
     }
 
@@ -948,10 +977,9 @@ vlan_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params)
        if (error != 0) {
                return (error);
        }
        if (error != 0) {
                return (error);
        }
-       ifv = _MALLOC(sizeof(struct ifvlan), M_VLAN, M_WAITOK);
+       ifv = _MALLOC(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
        if (ifv == NULL)
                return ENOBUFS;
        if (ifv == NULL)
                return ENOBUFS;
-       bzero(ifv, sizeof(struct ifvlan));
        ifv->ifv_retain_count = 1;
        ifv->ifv_signature = IFV_SIGNATURE;
        multicast_list_init(&ifv->ifv_multicast);
        ifv->ifv_retain_count = 1;
        ifv->ifv_signature = IFV_SIGNATURE;
        multicast_list_init(&ifv->ifv_multicast);
@@ -1143,7 +1171,7 @@ vlan_output(struct ifnet * ifp, struct mbuf * m)
        m->m_pkthdr.csum_flags |= CSUM_VLAN_TAG_VALID;
        m->m_pkthdr.vlan_tag = tag;
     } else {
        m->m_pkthdr.csum_flags |= CSUM_VLAN_TAG_VALID;
        m->m_pkthdr.vlan_tag = tag;
     } else {
-       M_PREPEND(m, encaplen, M_DONTWAIT);
+       M_PREPEND(m, encaplen, M_DONTWAIT, 1);
        if (m == NULL) {
            printf("%s%d: unable to prepend VLAN header\n", ifnet_name(ifp),
                   ifnet_unit(ifp));
        if (m == NULL) {
            printf("%s%d: unable to prepend VLAN header\n", ifnet_name(ifp),
                   ifnet_unit(ifp));
@@ -1244,7 +1272,6 @@ vlan_input(ifnet_t p, __unused protocol_family_t protocol,
                   ifnet_type(p));
            m_freem(m);
            return 0;
                   ifnet_type(p));
            m_freem(m);
            return 0;
-           break;
        }
     }
     if (tag != 0) {
        }
     }
     if (tag != 0) {
@@ -2028,7 +2055,7 @@ interface_link_event(struct ifnet * ifp, u_int32_t event_code)
     event.header.event_code    = event_code;
     event.header.event_data[0] = ifnet_family(ifp);
     event.unit                 = (u_int32_t) ifnet_unit(ifp);
     event.header.event_code    = event_code;
     event.header.event_data[0] = ifnet_family(ifp);
     event.unit                 = (u_int32_t) ifnet_unit(ifp);
-    strncpy(event.if_name, ifnet_name(ifp), IFNAMSIZ);
+    strlcpy(event.if_name, ifnet_name(ifp), IFNAMSIZ);
     ifnet_event(ifp, &event.header);
     return;
 }
     ifnet_event(ifp, &event.header);
     return;
 }
@@ -2036,7 +2063,6 @@ interface_link_event(struct ifnet * ifp, u_int32_t event_code)
 static void
 vlan_parent_link_event(struct ifnet * p, u_int32_t event_code)
 {
 static void
 vlan_parent_link_event(struct ifnet * p, u_int32_t event_code)
 {
-    ifvlan_ref                 ifv;
     vlan_parent_ref    vlp;
 
     vlan_lock();
     vlan_parent_ref    vlp;
 
     vlan_lock();
@@ -2051,25 +2077,15 @@ vlan_parent_link_event(struct ifnet * p, u_int32_t event_code)
        vlan_unlock();
        return;
     }
        vlan_unlock();
        return;
     }
-
+    vlan_parent_flags_set_link_event_required(vlp);
+    vlp->vlp_event_code = event_code;
+    if (vlan_parent_flags_change_in_progress(vlp)) {
+       /* don't block waiting to generate an event */
+       vlan_unlock();
+       return;
+    }
     vlan_parent_retain(vlp);
     vlan_parent_wait(vlp, "vlan_parent_link_event");
     vlan_parent_retain(vlp);
     vlan_parent_wait(vlp, "vlan_parent_link_event");
-    if (vlan_parent_flags_detaching(vlp)) {
-       goto signal_done;
-    }
-
-    vlan_unlock();
-
-    /* vlan_parent_wait() gives us exclusive access to the list */
-    LIST_FOREACH(ifv, &vlp->vlp_vlan_list, ifv_vlan_list) {
-       struct ifnet *  ifp = ifv->ifv_ifp;
-
-       interface_link_event(ifp, event_code);
-    }
-
-    vlan_lock();
-
- signal_done:
     vlan_parent_signal(vlp, "vlan_parent_link_event");
     vlan_unlock();
     vlan_parent_release(vlp);
     vlan_parent_signal(vlp, "vlan_parent_link_event");
     vlan_unlock();
     vlan_parent_release(vlp);