Commit 890d5b40 authored by Marian Postevca's avatar Marian Postevca Committed by Greg Kroah-Hartman

usb: gadget: u_ether: fix race in setting MAC address in setup phase

When listening for notifications through netlink of a new interface being
registered, sporadically, it is possible for the MAC to be read as zero.
The zero MAC address lasts a short period of time and then switches to a
valid random MAC address.

This causes problems for netd in Android, which assumes that the interface
is malfunctioning and will not use it.

In the good case we get this log:
InterfaceController::getCfg() ifName usb0
 hwAddr 92:a8:f0:73:79:5b ipv4Addr 0.0.0.0 flags 0x1002

In the error case we get these logs:
InterfaceController::getCfg() ifName usb0
 hwAddr 00:00:00:00:00:00 ipv4Addr 0.0.0.0 flags 0x1002

netd : interfaceGetCfg("usb0")
netd : interfaceSetCfg() -> ServiceSpecificException
 (99, "[Cannot assign requested address] : ioctl() failed")

The reason for the issue is the order in which the interface is setup,
it is first registered through register_netdev() and after the MAC
address is set.

Fixed by first setting the MAC address of the net_device and after that
calling register_netdev().

Fixes: bcd4a1c4 ("usb: gadget: u_ether: construct with default values and add setters/getters")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarMarian Postevca <posteuca@mutex.one>
Link: https://lore.kernel.org/r/20211204214912.17627-1-posteuca@mutex.oneSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2585cf9d
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/etherdevice.h>
#include "u_ether.h" #include "u_ether.h"
...@@ -863,19 +864,23 @@ int gether_register_netdev(struct net_device *net) ...@@ -863,19 +864,23 @@ int gether_register_netdev(struct net_device *net)
{ {
struct eth_dev *dev; struct eth_dev *dev;
struct usb_gadget *g; struct usb_gadget *g;
struct sockaddr sa;
int status; int status;
if (!net->dev.parent) if (!net->dev.parent)
return -EINVAL; return -EINVAL;
dev = netdev_priv(net); dev = netdev_priv(net);
g = dev->gadget; g = dev->gadget;
net->addr_assign_type = NET_ADDR_RANDOM;
eth_hw_addr_set(net, dev->dev_mac);
status = register_netdev(net); status = register_netdev(net);
if (status < 0) { if (status < 0) {
dev_dbg(&g->dev, "register_netdev failed, %d\n", status); dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
return status; return status;
} else { } else {
INFO(dev, "HOST MAC %pM\n", dev->host_mac); INFO(dev, "HOST MAC %pM\n", dev->host_mac);
INFO(dev, "MAC %pM\n", dev->dev_mac);
/* two kinds of host-initiated state changes: /* two kinds of host-initiated state changes:
* - iff DATA transfer is active, carrier is "on" * - iff DATA transfer is active, carrier is "on"
...@@ -883,15 +888,6 @@ int gether_register_netdev(struct net_device *net) ...@@ -883,15 +888,6 @@ int gether_register_netdev(struct net_device *net)
*/ */
netif_carrier_off(net); netif_carrier_off(net);
} }
sa.sa_family = net->type;
memcpy(sa.sa_data, dev->dev_mac, ETH_ALEN);
rtnl_lock();
status = dev_set_mac_address(net, &sa, NULL);
rtnl_unlock();
if (status)
pr_warn("cannot set self ethernet address: %d\n", status);
else
INFO(dev, "MAC %pM\n", dev->dev_mac);
return status; return status;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment