Changes done by pseudo-driver *after* ether_ifattach() must be undone
*before* ether_ifdetach().  Otherwise it is impossible to ensure we're
leaving a stacked pseudo-interface in a correct state.

Since I don't want to modify every single driver calling ether_ifdetach()
I'm using a new function, if_deactivate() to undo all the pseudo-driver
stuff.
It is safe to call this function multiple times because after the first
time the parent interface won't have any pseudo-interface attached to it.

I'm leaving splnet() below, even if pseudo-interfaces that need it should
take care of raising it, to be on the safe side.  More cleanup might
happen later.

This is a trivial change needed for upcoming if_input() work.

Ok?

Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.327
diff -u -p -r1.327 if.c
--- net/if.c    7 Apr 2015 10:46:20 -0000       1.327
+++ net/if.c    9 Apr 2015 09:15:37 -0000
@@ -521,22 +521,12 @@ nettxintr(void)
        splx(s);
 }
 
-/*
- * Detach an interface from everything in the kernel.  Also deallocate
- * private resources.
- */
 void
-if_detach(struct ifnet *ifp)
+if_deactivate(struct ifnet *ifp)
 {
-       struct ifaddr *ifa;
-       struct ifg_list *ifg;
-       int s = splnet();
-       struct domain *dp;
+       int s;
 
-       ifp->if_flags &= ~IFF_OACTIVE;
-       ifp->if_start = if_detached_start;
-       ifp->if_ioctl = if_detached_ioctl;
-       ifp->if_watchdog = NULL;
+       s = splnet();
 
        /*
         * Call detach hooks from head to tail.  To make sure detach
@@ -545,12 +535,6 @@ if_detach(struct ifnet *ifp)
         */
        dohooks(ifp->if_detachhooks, HOOK_REMOVE | HOOK_FREE);
 
-       /* Remove the watchdog timeout */
-       timeout_del(ifp->if_slowtimo);
-
-       /* Remove the link state task */
-       task_del(systq, ifp->if_linkstatetask);
-
 #if NBRIDGE > 0
        /* Remove the interface from any bridge it is part of.  */
        if (ifp->if_bridgeport)
@@ -562,6 +546,36 @@ if_detach(struct ifnet *ifp)
        if (ifp->if_carp && ifp->if_type != IFT_CARP)
                carp_ifdetach(ifp);
 #endif
+
+       splx(s);
+}
+
+/*
+ * Detach an interface from everything in the kernel.  Also deallocate
+ * private resources.
+ */
+void
+if_detach(struct ifnet *ifp)
+{
+       struct ifaddr *ifa;
+       struct ifg_list *ifg;
+       struct domain *dp;
+       int s;
+
+       /* Undo pseudo-driver changes. */
+       if_deactivate(ifp);
+
+       s = splnet();
+       ifp->if_flags &= ~IFF_OACTIVE;
+       ifp->if_start = if_detached_start;
+       ifp->if_ioctl = if_detached_ioctl;
+       ifp->if_watchdog = NULL;
+
+       /* Remove the watchdog timeout */
+       timeout_del(ifp->if_slowtimo);
+
+       /* Remove the link state task */
+       task_del(systq, ifp->if_linkstatetask);
 
 #if NBPFILTER > 0
        bpfdetach(ifp);
Index: net/if.h
===================================================================
RCS file: /cvs/src/sys/net/if.h,v
retrieving revision 1.161
diff -u -p -r1.161 if.h
--- net/if.h    18 Mar 2015 12:23:15 -0000      1.161
+++ net/if.h    9 Apr 2015 09:15:37 -0000
@@ -446,6 +446,7 @@ void        if_attach(struct ifnet *);
 void   if_attachdomain(void);
 void   if_attachtail(struct ifnet *);
 void   if_attachhead(struct ifnet *);
+void   if_deactivate(struct ifnet *);
 void   if_detach(struct ifnet *);
 void   if_down(struct ifnet *);
 void   if_downall(void);
Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.191
diff -u -p -r1.191 if_ethersubr.c
--- net/if_ethersubr.c  7 Apr 2015 10:46:20 -0000       1.191
+++ net/if_ethersubr.c  9 Apr 2015 09:16:45 -0000
@@ -802,6 +802,9 @@ ether_ifdetach(struct ifnet *ifp)
        struct ifih *ether_ifih;
        struct ether_multi *enm;
 
+       /* Undo pseudo-driver changes. */
+       if_deactivate(ifp);
+
        ether_ifih = SLIST_FIRST(&ifp->if_inputs);
        SLIST_REMOVE_HEAD(&ifp->if_inputs, ifih_next);
 

Reply via email to