Skip to content

Commit bfe9b9d

Browse files
kristrevdavem330
authored andcommitted
cdc_ether: Improve ZTE MF823/831/910 handling
The firmware in several ZTE devices (at least the MF823/831/910 modems/mifis) use OS fingerprinting to determine which type of device to export. In addition, these devices export a REST API which can be used to control the type of device. So far, on Linux, the devices have been seen as RNDIS or CDC Ether. When CDC Ether is used, devices of the same type are, as with RNDIS, exported with the same, bogus random MAC address. In addition, the devices (at least on all firmware revisions I have found) use the bogus MAC when sending traffic routed from external networks. And as a final feature, the devices sometimes export the link state incorrectly. There are also references online to several other ZTE devices displaying this behavior, with several different PIDs and MAC addresses. This patch tries to improve the handling of ZTE devices by doing the following: * Create a new driver_info-struct that is used by ZTE devices that do not have an explicit entry in the product table. This struct is the same as the default cdc_ether driver info, but a new bind- and an rx_fixup-function have been added. * In the new bind function, we check if we have read a random MAC from the device. If we have, then we generate a new random MAC address. This will ensure that all devices get a unique MAC. * The rx_fixup-function replaces the destination MAC address in the skb with that of the device. I have not seen a revision of these devices that behaves correctly (i.e., sets the right destination MAC), so I chose not to do any comparison with for example the known, bogus addresses. * The MF823/MF832/MF910 sometimes export cdc carrier on twice on connect (the correct behavior is off then on). Work around this by manually setting carrier to off if an on-notification is received and the NOCARRIER-bit is not set. This change will affect all devices, but it should take care of similar mistakes made by other manufacturers. I tried to think of/look/test for problems/regressions that could be introduced by this behavior, but could not find any. However, my familiarity with this code path is not that great, so there could be something I have overlooked. I have tested this patch with multiple revisions of all three devices, and they behave as expected. In other words, they all got a valid, random MAC, the correct operational state and I can receive/sent traffic without problems. I also tested with some other cdc_ether devices I have and did not find any problems/regressions caused by the two general changes. v3->v4: * Forgot to remove unused variables, sorry about that (thanks David Miller). v2->v3: * I had forgot to remove the random MAC generation from usbnet_cdc_bind() (thanks Oliver). * Rework logic in the ZTE bind-function a bit. v1->v2: * Only generate random MAC for ZTE devices (thanks Oliver Neukum). * Set random MAC and do RX fixup for all ZTE devices that do not have a product-entry, as the bogus MAC have been seen on devices with several different PIDs/MAC addresses. In other words, it seems to be the default behavior of ZTE CDC Ether devices (thanks Lars Melin). Signed-off-by: Kristian Evensen <[email protected]> Acked-by: Oliver Neukum <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c42d712 commit bfe9b9d

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

drivers/net/usb/cdc_ether.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,12 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
388388
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
389389
netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
390390
event->wValue ? "on" : "off");
391+
392+
/* Work-around for devices with broken off-notifications */
393+
if (event->wValue &&
394+
!test_bit(__LINK_STATE_NOCARRIER, &dev->net->state))
395+
usbnet_link_change(dev, 0, 0);
396+
391397
usbnet_link_change(dev, !!event->wValue, 0);
392398
break;
393399
case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */
@@ -432,6 +438,34 @@ int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
432438
}
433439
EXPORT_SYMBOL_GPL(usbnet_cdc_bind);
434440

441+
static int usbnet_cdc_zte_bind(struct usbnet *dev, struct usb_interface *intf)
442+
{
443+
int status = usbnet_cdc_bind(dev, intf);
444+
445+
if (!status && (dev->net->dev_addr[0] & 0x02))
446+
eth_hw_addr_random(dev->net);
447+
448+
return status;
449+
}
450+
451+
/* Make sure packets have correct destination MAC address
452+
*
453+
* A firmware bug observed on some devices (ZTE MF823/831/910) is that the
454+
* device sends packets with a static, bogus, random MAC address (event if
455+
* device MAC address has been updated). Always set MAC address to that of the
456+
* device.
457+
*/
458+
static int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
459+
{
460+
if (skb->len < ETH_HLEN || !(skb->data[0] & 0x02))
461+
return 1;
462+
463+
skb_reset_mac_header(skb);
464+
ether_addr_copy(eth_hdr(skb)->h_dest, dev->net->dev_addr);
465+
466+
return 1;
467+
}
468+
435469
static const struct driver_info cdc_info = {
436470
.description = "CDC Ethernet Device",
437471
.flags = FLAG_ETHER | FLAG_POINTTOPOINT,
@@ -442,6 +476,17 @@ static const struct driver_info cdc_info = {
442476
.manage_power = usbnet_manage_power,
443477
};
444478

479+
static const struct driver_info zte_cdc_info = {
480+
.description = "ZTE CDC Ethernet Device",
481+
.flags = FLAG_ETHER | FLAG_POINTTOPOINT,
482+
.bind = usbnet_cdc_zte_bind,
483+
.unbind = usbnet_cdc_unbind,
484+
.status = usbnet_cdc_status,
485+
.set_rx_mode = usbnet_cdc_update_filter,
486+
.manage_power = usbnet_manage_power,
487+
.rx_fixup = usbnet_cdc_zte_rx_fixup,
488+
};
489+
445490
static const struct driver_info wwan_info = {
446491
.description = "Mobile Broadband Network Device",
447492
.flags = FLAG_WWAN,
@@ -706,6 +751,12 @@ static const struct usb_device_id products[] = {
706751
USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x81ba, USB_CLASS_COMM,
707752
USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
708753
.driver_info = (kernel_ulong_t)&wwan_info,
754+
}, {
755+
/* ZTE modules */
756+
USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, USB_CLASS_COMM,
757+
USB_CDC_SUBCLASS_ETHERNET,
758+
USB_CDC_PROTO_NONE),
759+
.driver_info = (unsigned long)&zte_cdc_info,
709760
}, {
710761
USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
711762
USB_CDC_PROTO_NONE),

0 commit comments

Comments
 (0)