Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Sep 2021 07:33:43 GMT
From:      Wojciech Macek <wma@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 28df957acb93 - stable/13 - if_cdce: Add support for setting RX filtering
Message-ID:  <202109280733.18S7Xhsr089371@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by wma:

URL: https://cgit.FreeBSD.org/src/commit/?id=28df957acb9342c52587774d3c4c530ea9980a85

commit 28df957acb9342c52587774d3c4c530ea9980a85
Author:     Kornel Duleba <mindal@semihalf.com>
AuthorDate: 2021-08-31 12:22:30 +0000
Commit:     Wojciech Macek <wma@FreeBSD.org>
CommitDate: 2021-09-28 07:03:48 +0000

    if_cdce: Add support for setting RX filtering
    
    We can now set promisc and allmulti modes.
    Filtering of given multicast addresses is not supported.
    Changing the mode is done by sending a command described in:
    "USB CDC Subclass Specification for Ethernet Devices v1.2, section 6.2.4".
    This means that at least in theory this feature should work with all
    modems that are using this driver.
    
    This fixes Huawei E3372h-320 running new firmware in "HiLink" mode.
    Previously it would reset a few seconds after its mode was changed
    with "usb_modeswitch".
    Setting RX filter to default value at the end of attach function
    fixed that.
    
    Sponsored by:           Stormshield
    Obtained from:          Semihalf
    Differential revision:  https://reviews.freebsd.org/D31766
    MFC after:              2 weeks
    Reviewed by:            hps
    
    (cherry picked from commit f0c393f781f01ffa727f90a8593e26a20869438b)
---
 sys/dev/usb/net/if_cdce.c    | 41 +++++++++++++++++++++++++++++++++++++----
 sys/dev/usb/net/if_cdcereg.h | 15 +++++++++++++++
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c
index 24813ea305e4..ebc68e1f71cc 100644
--- a/sys/dev/usb/net/if_cdce.c
+++ b/sys/dev/usb/net/if_cdce.c
@@ -117,6 +117,7 @@ static int cdce_media_change_cb(struct ifnet *);
 static void cdce_media_status_cb(struct ifnet *, struct ifmediareq *);
 
 static uint32_t	cdce_m_crc32(struct mbuf *, uint32_t, uint32_t);
+static void	cdce_set_filter(struct usb_ether *);
 
 #ifdef USB_DEBUG
 static int cdce_debug = 0;
@@ -593,6 +594,9 @@ cdce_attach_post_sub(struct usb_ether *ue)
 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
 	sc->sc_media.ifm_media = sc->sc_media.ifm_cur->ifm_media;
+	CDCE_LOCK(sc);
+	cdce_set_filter(ue);
+	CDCE_UNLOCK(sc);
 
 	return 0;
 }
@@ -1025,15 +1029,44 @@ cdce_stop(struct usb_ether *ue)
 static void
 cdce_setmulti(struct usb_ether *ue)
 {
-	/* no-op */
-	return;
+
+	cdce_set_filter(ue);
 }
 
 static void
 cdce_setpromisc(struct usb_ether *ue)
 {
-	/* no-op */
-	return;
+
+	cdce_set_filter(ue);
+}
+
+static void
+cdce_set_filter(struct usb_ether *ue)
+{
+	struct cdce_softc *sc = uether_getsc(ue);
+	struct ifnet *ifp = uether_getifp(ue);
+	struct usb_device_request req;
+	uint16_t value;
+
+	value = CDC_PACKET_TYPE_DIRECTED | CDC_PACKET_TYPE_BROADCAST;
+	if (if_getflags(ifp) & IFF_PROMISC)
+		value |= CDC_PACKET_TYPE_PROMISC;
+	if (if_getflags(ifp) & IFF_ALLMULTI)
+		value |= CDC_PACKET_TYPE_ALL_MULTICAST;
+
+	req.bmRequestType = UT_CLASS | UT_INTERFACE;
+	req.bRequest = CDC_SET_ETHERNET_PACKET_FILTER;
+	USETW(req.wValue, value);
+	req.wIndex[0] = sc->sc_ifaces_index[1];
+	req.wIndex[1] = 0;
+	USETW(req.wLength, 0);
+
+	/*
+	 * Function below will drop the sc mutex.
+	 * We can do that since we're called from a separate task,
+	 * that simply wraps the setpromisc/setmulti methods.
+	 */
+	usbd_do_request(sc->sc_ue.ue_udev, &sc->sc_mtx, &req, NULL);
 }
 
 static int
diff --git a/sys/dev/usb/net/if_cdcereg.h b/sys/dev/usb/net/if_cdcereg.h
index 724aa0b9b017..19a7ac354341 100644
--- a/sys/dev/usb/net/if_cdcereg.h
+++ b/sys/dev/usb/net/if_cdcereg.h
@@ -37,6 +37,8 @@
 #ifndef _USB_IF_CDCEREG_H_
 #define	_USB_IF_CDCEREG_H_
 
+#define CDCE_BIT(x) (1 << (x))
+
 #define	CDCE_FRAMES_MAX	8		/* units */
 #define	CDCE_IND_SIZE_MAX 32            /* bytes */
 
@@ -104,6 +106,19 @@ struct cdce_softc {
 #define	CDCE_NOTIFY_DONE		2
 };
 
+/*
+ * Taken from USB CDC Subclass Specification for Ethernet Devices v1.2,
+ * section 6.2.4.
+ */
+
+#define	CDC_SET_ETHERNET_PACKET_FILTER	0x43	/* Command code. */
+
+#define	CDC_PACKET_TYPE_PROMISC		CDCE_BIT(0)
+#define	CDC_PACKET_TYPE_ALL_MULTICAST	CDCE_BIT(1)	/* Allmulti. */
+#define	CDC_PACKET_TYPE_DIRECTED	CDCE_BIT(2)	/* Filter unicast by mac. */
+#define	CDC_PACKET_TYPE_BROADCAST	CDCE_BIT(3)
+#define	CDC_PACKET_TYPE_MULTICAST	CDCE_BIT(4)	/* Multicast filtering, not supported. */
+
 #define	CDCE_LOCK(_sc)			mtx_lock(&(_sc)->sc_mtx)
 #define	CDCE_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
 #define	CDCE_LOCK_ASSERT(_sc, t)	mtx_assert(&(_sc)->sc_mtx, t)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202109280733.18S7Xhsr089371>