]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/dlil.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / net / dlil.c
index 5f766f6b7af4b45a3771552806493dfe4397fab3..4b24b76f9355c717afdb782ad302b456e89a2251 100644 (file)
@@ -78,8 +78,6 @@
 #define DLIL_PRINTF    kprintf
 #endif
 
-//#define DLIL_ALWAYS_DELAY_DETACH 1
-
 enum {
        kProtoKPI_DLIL  = 0,
        kProtoKPI_v1    = 1
@@ -553,7 +551,6 @@ dlil_init(void)
        
        /* Setup the lock groups we will use */
        grp_attributes = lck_grp_attr_alloc_init();
-       lck_grp_attr_setdefault(grp_attributes);
 
        dlil_lock_group = lck_grp_alloc_init("dlil internal locks", grp_attributes);
 #if IFNET_RW_LOCK
@@ -568,10 +565,8 @@ dlil_init(void)
        
        /* Setup the lock attributes we will use */
        lck_attributes = lck_attr_alloc_init();
-       lck_attr_setdefault(lck_attributes);
        
        ifnet_lock_attr = lck_attr_alloc_init();
-       lck_attr_setdefault(ifnet_lock_attr);
        
        dlil_input_lock = lck_spin_alloc_init(input_lock_grp, lck_attributes);
        input_lock_grp = 0;
@@ -632,34 +627,59 @@ dlil_detach_filter_internal(interface_filter_t filter, int detached)
 {
        int retval = 0;
        
-       
-       /* Take the write lock */
-#if DLIL_ALWAYS_DELAY_DETACH
-       retval = EDEADLK;
-#else
-       if (detached == 0 && (retval = dlil_write_begin()) != 0)
-#endif
-        {
+       if (detached == 0) {
+               ifnet_t                         ifp = NULL;
+               interface_filter_t      entry = NULL;
+
+               /* Take the write lock */
+               retval = dlil_write_begin();
+               if (retval != 0 && retval != EDEADLK)
+                       return retval;
+               
+               /*
+                * At this point either we have the write lock (retval == 0)
+                * or we couldn't get it (retval == EDEADLK) because someone
+                * else up the stack is holding the read lock. It is safe to
+                * read, either the read or write is held. Verify the filter
+                * parameter before proceeding.
+                */
+               ifnet_head_lock_shared();
+               TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+                       TAILQ_FOREACH(entry, &ifp->if_flt_head, filt_next) {
+                               if (entry == filter)
+                                       break;
+                       }
+                       if (entry == filter)
+                               break;
+               }
+               ifnet_head_done();
+               
+               if (entry != filter) {
+                       /* filter parameter is not a valid filter ref */
+                       if (retval == 0) {
+                               dlil_write_end();
+                       }
+                       return EINVAL;
+               }
+               
                if (retval == EDEADLK) {
                        /* Perform a delayed detach */
                        filter->filt_detaching = 1;
                        dlil_detach_waiting = 1;
                        wakeup(&dlil_detach_waiting);
-                       retval = 0;
+                       return 0;
                }
-               return retval;
-       }
-       
-       if (detached == 0)
-               TAILQ_REMOVE(&filter->filt_ifp->if_flt_head, filter, filt_next);
-       
-       /* release the write lock */
-       if (detached == 0)
+               
+               /* Remove the filter from the list */
+               TAILQ_REMOVE(&ifp->if_flt_head, filter, filt_next);
                dlil_write_end();
+       }
        
+       /* Call the detached funciton if there is one */
        if (filter->filt_detached)
                filter->filt_detached(filter->filt_cookie, filter->filt_ifp);
 
+       /* Free the filter */
        FREE(filter, M_NKE);
        
        return retval;
@@ -668,6 +688,8 @@ dlil_detach_filter_internal(interface_filter_t filter, int detached)
 void
 dlil_detach_filter(interface_filter_t filter)
 {
+       if (filter == NULL)
+               return;
        dlil_detach_filter_internal(filter, 0);
 }
 
@@ -972,6 +994,7 @@ dlil_event(struct ifnet *ifp, struct kern_event_msg *event)
        return result;
 }
 
+int
 dlil_output_list(
        struct ifnet* ifp,
        u_long proto_family,
@@ -1964,12 +1987,7 @@ dlil_detach_protocol(struct ifnet *ifp, u_long proto_family)
        int use_reached_zero = 0;
        
 
-#if DLIL_ALWAYS_DELAY_DETACH
-       {
-               retval = EDEADLK;
-#else
        if ((retval = dlil_write_begin()) != 0) {
-#endif
                if (retval == EDEADLK) {
                        retval = 0;
                        dlil_read_begin();