diff mbox

cdc_ncm: Handle multicast Ethernet traffic

Message ID bb3265b0-4788-ba51-26a8-44b1a497ab93@det.uvigo.gal (mailing list archive)
State New, archived
Headers show

Commit Message

Miguel Rodríguez Pérez June 29, 2018, 7:53 a.m. UTC
Dell D6000 dock (and I guess other docks too) exposes a CDC_NCM device
for Ethernet traffic. However, multicast Ethernet traffic is not
processed making IPv6 not functional. Other services, like mDNS used for
LAN service discovery are also hindered.

The actual reason is that CDC_NCM driver was not processing requests to
filter (admit) multicast traffic. I provide two patches to the linux
kernel that admit all Ethernet multicast traffic whenever a multicast
group is being joined.

The solution is not optimal, as it makes the system receive more traffic
than that strictly needed, but otherwise this only happens when the
computer is connected to a dock and thus is running on AC power. I
believe it is not worth the hassle to join only the requested groups.
This is the same that is done in the CDN_ETHER driver.

Best regards,
diff mbox

Patch

From 7948d0d33ac15cc7526f2fb5c2f95fde313ce8f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miguel=20Rodr=C3=ADguez=20P=C3=A9rez?=
 <miguel@det.uvigo.gal>
Date: Thu, 28 Jun 2018 17:57:18 +0200
Subject: [PATCH 2/2] Admit multicast traffic

Some CDC_NCM devices are used as docks for laptops. In this case, it
makes sense to accept multicast Ethernet traffic, as these devices
can reside in a proper LAN. Without this, mDNS or IPv6 simply do not
work.
---
 drivers/net/usb/cdc_ncm.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index d6b51e2b9495..50af1d9d0102 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -132,6 +132,33 @@  static void cdc_ncm_get_strings(struct net_device __always_unused *netdev, u32 s
 
 static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx);
 
+static void cdc_ncm_update_filter(struct usbnet *dev)
+{
+       struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+	u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
+	struct net_device *net = dev->net;
+
+	u16 cdc_filter = USB_CDC_PACKET_TYPE_DIRECTED
+			| USB_CDC_PACKET_TYPE_BROADCAST;
+
+	/* filtering on the device is an optional feature and not worth
+	 * the hassle so we just roughly care about snooping and if any
+	 * multicast is requested, we take every multicast
+	 */
+	if (net->flags & IFF_PROMISC)
+		cdc_filter |= USB_CDC_PACKET_TYPE_PROMISCUOUS;
+	if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI))
+		cdc_filter |= USB_CDC_PACKET_TYPE_ALL_MULTICAST;
+
+	usbnet_write_cmd(dev,
+			USB_CDC_SET_ETHERNET_PACKET_FILTER,
+			USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
+			cdc_filter,
+			iface_no,
+			NULL,
+			0);
+}
+
 static const struct ethtool_ops cdc_ncm_ethtool_ops = {
 	.get_link          = usbnet_get_link,
 	.nway_reset        = usbnet_nway_reset,
@@ -1652,6 +1679,7 @@  static const struct driver_info cdc_ncm_info = {
 	.status = cdc_ncm_status,
 	.rx_fixup = cdc_ncm_rx_fixup,
 	.tx_fixup = cdc_ncm_tx_fixup,
+	.set_rx_mode = cdc_ncm_update_filter,
 };
 
 /* Same as cdc_ncm_info, but with FLAG_WWAN */
-- 
2.17.1