[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <1566339663476.54366@Dellteam.com>
Date: Tue, 20 Aug 2019 22:21:03 +0000
From: <Charles.Hyde@...lteam.com>
To: <linux-usb@...r.kernel.org>, <linux-acpi@...r.kernel.org>
CC: <gregkh@...uxfoundation.org>, <Mario.Limonciello@...l.com>,
<oliver@...kum.org>, <netdev@...r.kernel.org>,
<nic_swsd@...ltek.com>
Subject: [RFC 2/4] Allow cdc_ncm to set MAC address in hardware
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 <charles.hyde@...lteam.com>
Cc: Mario Limonciello <mario.limonciello@...l.com>
Cc: Oliver Neukum <oliver@...kum.org>
Cc: netdev@...r.kernel.org
Cc: linux-usb@...r.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
Powered by blists - more mailing lists