mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 13:53:33 +00:00
usbnet: Run unregister_netdev() before unbind() again
[ Upstream commitd1408f6b4d
] Commit2c9d6c2b87
("usbnet: run unbind() before unregister_netdev()") sought to fix a use-after-free on disconnect of USB Ethernet adapters. It turns out that a different fix is necessary to address the issue: https://lore.kernel.org/netdev/18b3541e5372bc9b9fc733d422f4e698c089077c.1650177997.git.lukas@wunner.de/ So the commit was not necessary. The commit made binding and unbinding of USB Ethernet asymmetrical: Before, usbnet_probe() first invoked the ->bind() callback and then register_netdev(). usbnet_disconnect() mirrored that by first invoking unregister_netdev() and then ->unbind(). Since the commit, the order in usbnet_disconnect() is reversed and no longer mirrors usbnet_probe(). One consequence is that a PHY disconnected (and stopped) in ->unbind() is afterwards stopped once more by unregister_netdev() as it closes the netdev before unregistering. That necessitates a contortion in ->stop() because the PHY may only be stopped if it hasn't already been disconnected. Reverting the commit allows making the call to phy_stop() unconditional in ->stop(). Tested-by: Oleksij Rempel <o.rempel@pengutronix.de> # LAN9514/9512/9500 Tested-by: Ferry Toth <fntoth@gmail.com> # LAN9514 Signed-off-by: Lukas Wunner <lukas@wunner.de> Acked-by: Oliver Neukum <oneukum@suse.com> Cc: Martyn Welch <martyn.welch@collabora.com> Cc: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
0794db7ca7
commit
fbda837107
3 changed files with 5 additions and 10 deletions
|
@ -799,11 +799,7 @@ static int ax88772_stop(struct usbnet *dev)
|
|||
{
|
||||
struct asix_common_private *priv = dev->driver_priv;
|
||||
|
||||
/* On unplugged USB, we will get MDIO communication errors and the
|
||||
* PHY will be set in to PHY_HALTED state.
|
||||
*/
|
||||
if (priv->phydev->state != PHY_HALTED)
|
||||
phy_stop(priv->phydev);
|
||||
phy_stop(priv->phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1218,8 +1218,7 @@ static int smsc95xx_start_phy(struct usbnet *dev)
|
|||
|
||||
static int smsc95xx_stop(struct usbnet *dev)
|
||||
{
|
||||
if (dev->net->phydev)
|
||||
phy_stop(dev->net->phydev);
|
||||
phy_stop(dev->net->phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1616,9 +1616,6 @@ void usbnet_disconnect (struct usb_interface *intf)
|
|||
xdev->bus->bus_name, xdev->devpath,
|
||||
dev->driver_info->description);
|
||||
|
||||
if (dev->driver_info->unbind)
|
||||
dev->driver_info->unbind(dev, intf);
|
||||
|
||||
net = dev->net;
|
||||
unregister_netdev (net);
|
||||
|
||||
|
@ -1626,6 +1623,9 @@ void usbnet_disconnect (struct usb_interface *intf)
|
|||
|
||||
usb_scuttle_anchored_urbs(&dev->deferred);
|
||||
|
||||
if (dev->driver_info->unbind)
|
||||
dev->driver_info->unbind(dev, intf);
|
||||
|
||||
usb_kill_urb(dev->interrupt);
|
||||
usb_free_urb(dev->interrupt);
|
||||
kfree(dev->padding_pkt);
|
||||
|
|
Loading…
Reference in a new issue