Page MenuHomeFreeBSD

D28136.id89428.diff
No OneTemporary

D28136.id89428.diff

diff --git a/sys/dev/usb/net/if_usie.c b/sys/dev/usb/net/if_usie.c
--- a/sys/dev/usb/net/if_usie.c
+++ b/sys/dev/usb/net/if_usie.c
@@ -483,6 +483,7 @@
usbd_transfer_unsetup(sc->sc_if_xfer, USIE_IF_N_XFER);
bpfdetach(sc->sc_ifp);
if_detach(sc->sc_ifp);
+ if_ioctl_drain(sc->sc_ifp);
if_free(sc->sc_ifp);
sc->sc_ifp = NULL;
}
diff --git a/sys/dev/usb/net/uhso.c b/sys/dev/usb/net/uhso.c
--- a/sys/dev/usb/net/uhso.c
+++ b/sys/dev/usb/net/uhso.c
@@ -693,8 +693,9 @@
uhso_if_stop(sc);
bpfdetach(sc->sc_ifp);
if_detach(sc->sc_ifp);
- if_free(sc->sc_ifp);
mtx_unlock(&sc->sc_mtx);
+ if_ioctl_drain(sc->sc_ifp);
+ if_free(sc->sc_ifp);
usbd_transfer_unsetup(sc->sc_if_xfer, UHSO_IFNET_MAX);
}
diff --git a/sys/dev/usb/net/usb_ethernet.c b/sys/dev/usb/net/usb_ethernet.c
--- a/sys/dev/usb/net/usb_ethernet.c
+++ b/sys/dev/usb/net/usb_ethernet.c
@@ -292,6 +292,7 @@
/* free unit */
free_unr(ueunit, ue->ue_unit);
if (ue->ue_ifp != NULL) {
+ if_ioctl_drain(ue->ue_ifp);
if_free(ue->ue_ifp);
ue->ue_ifp = NULL;
}
@@ -311,6 +312,9 @@
ifp = ue->ue_ifp;
if (ifp != NULL) {
+ /* drain all IOCTLs */
+ if_ioctl_drain(ifp);
+
/* we are not running any more */
UE_LOCK(ue);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
diff --git a/sys/dev/usb/usb_pf.c b/sys/dev/usb/usb_pf.c
--- a/sys/dev/usb/usb_pf.c
+++ b/sys/dev/usb/usb_pf.c
@@ -232,6 +232,7 @@
USB_BUS_UNLOCK(ubus);
bpfdetach(ifp);
if_detach(ifp);
+ if_ioctl_drain(ifp);
if_free(ifp);
ifc_free_unit(ifc, unit);
diff --git a/sys/net/if.h b/sys/net/if.h
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -163,6 +163,7 @@
#define IFF_DYING 0x200000 /* (n) interface is winding down */
#define IFF_RENAMING 0x400000 /* (n) interface is being renamed */
#define IFF_NOGROUP 0x800000 /* (n) interface is not part of any groups */
+#define IFF_IOCTL_DRAINED 0x1000000 /* (n) control path has been drained */
/*
* Old names for driver flags so that user space tools can continue to use
@@ -177,7 +178,7 @@
#define IFF_CANTCHANGE \
(IFF_BROADCAST|IFF_POINTOPOINT|IFF_DRV_RUNNING|IFF_DRV_OACTIVE|\
IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_PROMISC|\
- IFF_DYING|IFF_CANTCONFIG|IFF_KNOWSEPOCH)
+ IFF_DYING|IFF_CANTCONFIG|IFF_KNOWSEPOCH|IFF_IOCTL_DRAINED)
/*
* Values for if_link_state.
diff --git a/sys/net/if.c b/sys/net/if.c
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -325,6 +325,9 @@
SX_SYSINIT_FLAGS(ifnet_detach, &ifnet_detach_sxlock, "ifnet_detach_sx",
SX_RECURSE);
+static struct sx ifnet_ioctl_sxlock;
+SX_SYSINIT_FLAGS(ifnet_ioctl, &ifnet_ioctl_sxlock, "ifnet_ioctl_sx", SX_RECURSE);
+
/*
* The allocation of network interfaces is a rather non-atomic affair; we
* need to select an index before we are ready to expose the interface for
@@ -652,6 +655,7 @@
ifq_init(&ifp->if_snd, ifp);
refcount_init(&ifp->if_refcount, 1); /* Index reference. */
+
for (int i = 0; i < IFCOUNTERS; i++)
ifp->if_counters[i] = counter_u64_alloc(M_WAITOK);
ifp->if_get_counter = if_get_counter_default;
@@ -769,6 +773,39 @@
NET_EPOCH_CALL(if_destroy, &ifp->if_epoch_ctx);
}
+/*
+ * Keep track of if_ioctl configuration events.
+ * Returns true on success and false on failure.
+ */
+bool
+if_ioctl_ref(struct ifnet *ifp)
+{
+ bool retval;
+
+ if (ifp->if_flags & IFF_IOCTL_DRAINED)
+ return (false);
+
+ sx_slock(&ifnet_ioctl_sxlock);
+ retval = (ifp->if_flags & IFF_IOCTL_DRAINED) == 0;
+ if (!retval)
+ sx_sunlock(&ifnet_ioctl_sxlock);
+ return (retval);
+}
+
+void
+if_ioctl_drain(struct ifnet *ifp)
+{
+ sx_xlock(&ifnet_ioctl_sxlock);
+ ifp->if_flags |= IFF_IOCTL_DRAINED;
+ sx_xunlock(&ifnet_ioctl_sxlock);
+}
+
+void
+if_ioctl_unref(struct ifnet *ifp)
+{
+ sx_sunlock(&ifnet_ioctl_sxlock);
+}
+
void
ifq_init(struct ifaltq *ifq, struct ifnet *ifp)
{
@@ -2458,8 +2495,8 @@
/*
* Hardware specific interface ioctls.
*/
-int
-ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
+static inline int
+ifhwioctl_sub(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
{
struct ifreq *ifr;
int error = 0, do_ifup = 0;
@@ -2883,6 +2920,18 @@
return (error);
}
+int
+ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
+{
+ int error;
+
+ if (if_ioctl_ref(ifp) == false)
+ return (ENXIO);
+ error = ifhwioctl_sub(cmd, ifp, data, td);
+ if_ioctl_unref(ifp);
+ return (error);
+}
+
/*
* Interface ioctls.
*/
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -663,6 +663,9 @@
void if_ref(struct ifnet *);
void if_rele(struct ifnet *);
bool __result_use_check if_try_ref(struct ifnet *);
+bool __result_use_check if_ioctl_ref(struct ifnet *);
+void if_ioctl_drain(struct ifnet *);
+void if_ioctl_unref(struct ifnet *);
int if_setlladdr(struct ifnet *, const u_char *, int);
int if_tunnel_check_nesting(struct ifnet *, struct mbuf *, uint32_t, int);
void if_up(struct ifnet *);

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 16, 1:32 AM (1 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28763045
Default Alt Text
D28136.id89428.diff (4 KB)

Event Timeline