[RFC 2/4] Allow cdc_ncm to set MAC address in hardware
From: <hidden>
Date: 2019-08-20 22:21:22
Also in:
linux-acpi, linux-usb
Subsystem:
networking drivers, the rest, usb "usbnet" driver framework, usb cdc ethernet driver, usb networking drivers, usb subsystem · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Oliver Neukum, Greg Kroah-Hartman
This patch adds support for pushing a MAC address out to USB based ethernet controllers driven by cdc_ncm. With this change, ifconfig can now set the device's MAC address. For example, the Dell Universal Dock D6000 is driven by cdc_ncm. The D6000 can now have its MAC address set by ifconfig, as it can be done in Windows. This was tested with a D6000 using ifconfig. Signed-off-by: Charles Hyde <redacted> Cc: Mario Limonciello <redacted> Cc: Oliver Neukum <oliver@neukum.org> Cc: netdev@vger.kernel.org Cc: linux-usb@vger.kernel.org --- drivers/net/usb/cdc_ncm.c | 20 +++++++++++++++++++- drivers/net/usb/usbnet.c | 37 ++++++++++++++++++++++++++++--------- include/linux/usb/usbnet.h | 1 + 3 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 50c05d0f44cb..f77c8672f972 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c@@ -750,6 +750,24 @@ int cdc_ncm_change_mtu(struct net_device *net, int new_mtu) } EXPORT_SYMBOL_GPL(cdc_ncm_change_mtu); +/* Provide method to push MAC address to the USB device's ethernet controller. + */ +int cdc_ncm_set_mac_addr(struct net_device *net, void *p) +{ + struct usbnet *dev = netdev_priv(net); + struct sockaddr *addr = p; + + memcpy(dev->net->dev_addr, addr->sa_data, ETH_ALEN); + /* + * Try to push the MAC address out to the device. Ignore any errors, + * to be compatible with prior versions of this source. + */ + usbnet_set_ethernet_addr(dev); + + return eth_mac_addr(net, p); +} +EXPORT_SYMBOL_GPL(cdc_ncm_set_mac_addr); + static const struct net_device_ops cdc_ncm_netdev_ops = { .ndo_open = usbnet_open, .ndo_stop = usbnet_stop,
@@ -757,7 +775,7 @@ static const struct net_device_ops cdc_ncm_netdev_ops = { .ndo_tx_timeout = usbnet_tx_timeout, .ndo_get_stats64 = usbnet_get_stats64, .ndo_change_mtu = cdc_ncm_change_mtu, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = cdc_ncm_set_mac_addr, .ndo_validate_addr = eth_validate_addr, };
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 72514c46b478..72bdac34b0ee 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c@@ -149,20 +149,39 @@ int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress) int tmp = -1, ret; unsigned char buf [13]; - ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf); - if (ret == 12) - tmp = hex2bin(dev->net->dev_addr, buf, 6); - if (tmp < 0) { - dev_dbg(&dev->udev->dev, - "bad MAC string %d fetch, %d\n", iMACAddress, tmp); - if (ret >= 0) - ret = -EINVAL; - return ret; + ret = usb_get_address(dev->udev, buf); + if (ret == 6) + memcpy(dev->net->dev_addr, buf, 6); + else if (ret < 0) { + ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf); + if (ret == 12) + tmp = hex2bin(dev->net->dev_addr, buf, 6); + if (tmp < 0) { + dev_dbg(&dev->udev->dev, + "bad MAC string %d fetch, %d\n", iMACAddress, + tmp); + if (ret >= 0) + ret = -EINVAL; + return ret; + } } return 0; } EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); +int usbnet_set_ethernet_addr(struct usbnet *dev) +{ + int ret; + + ret = usb_set_address(dev->udev, dev->net->dev_addr); + if (ret < 0) { + dev_dbg(&dev->udev->dev, + "bad MAC address put, %d\n", ret); + } + return ret; +} +EXPORT_SYMBOL_GPL(usbnet_set_ethernet_addr); + static void intr_complete (struct urb *urb) { struct usbnet *dev = urb->context;
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index d8860f2d0976..f2b2c5ab5493 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h@@ -258,6 +258,7 @@ extern int usbnet_change_mtu(struct net_device *net, int new_mtu); extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *); extern int usbnet_get_ethernet_addr(struct usbnet *, int); +extern int usbnet_set_ethernet_addr(struct usbnet *); extern void usbnet_defer_kevent(struct usbnet *, int); extern void usbnet_skb_return(struct usbnet *, struct sk_buff *); extern void usbnet_unlink_rx_urbs(struct usbnet *);
--
2.20.1