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);