[PATCH] usb: gadget: legacy: ether: fix RNDIS for Windows hosts
From: amine-ayaou
Date: Fri Oct 30 2026 - 05:17:31 EST
From: Amine Ayaou <amine-ayaou@xxxxxxxxxxx>
Fix RNDIS for Windows hosts by adding Microsoft OS 1.0
descriptor that allows Windows to identify the RNDIS function.
g_ether currently advertises its RNDIS configuration using
the legacy NetChip VID/PID and the RNDIS control interface
class, subclass and protocol values provided by f_rndis
(02/02/FF).
While the Linux rndis_host driver still recognizes the legacy
02/02/FF RNDIS interface descriptors, modern Windows hosts
do not bind the RNDIS driver to g_ether.
Use the existing USB composite framework support for
Microsoft OS 1.0 descriptors to advertise RNDIS when the
RNDIS function is enabled in g_ether.
Use of OS descriptor does not change the existing device IDs
or RNDIS control interface descriptors, keeping compatibility
with older hosts.
(It only adds a string descriptor at index 0xEE and handles
the associated vendor request)
Signed-off-by: Amine Ayaou <amine-ayaou@xxxxxxxxxxx>
---
Notes:
g_ether's RNDIS is useful when a network interface via USB
is needed early during boot, before a filesystem is available
(e.g., nfsroot).
Alternatives for having a network interface via USB during
boot are configfs and g_ncm.
Configuring the gadget through configfs requires userspace,
which is unavailable before mounting the NFS root when
no initramfs is used.
NCM (g_ncm) is not an option on hosts that only provide
RNDIS support.
Tested on BeagleBone Black with a Windows 11 host
(Version 10.0.26200, Build 26200)
RNDIS automatically bound with the patch.
drivers/usb/gadget/legacy/ether.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c
index 99c7fc0d1d597..70de686fa56b7 100644
--- a/drivers/usb/gadget/legacy/ether.c
+++ b/drivers/usb/gadget/legacy/ether.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/nls.h>
#if defined USB_ETH_RNDIS
# undef USB_ETH_RNDIS
@@ -92,8 +93,8 @@ static inline bool has_rndis(void)
#include "u_ecm.h"
#include "u_gether.h"
-#ifdef USB_ETH_RNDIS
#include "u_rndis.h"
+#ifdef USB_ETH_RNDIS
#include "rndis.h"
#else
#define rndis_borrow_net(...) do {} while (0)
@@ -364,6 +365,8 @@ static int eth_bind(struct usb_composite_dev *cdev)
if (has_rndis()) {
/* RNDIS plus ECM-or-Subset */
+ struct f_rndis_opts *rndis_opts = NULL;
+
gether_set_gadget(net, cdev->gadget);
status = gether_register_netdev(net);
if (status)
@@ -387,6 +390,18 @@ static int eth_bind(struct usb_composite_dev *cdev)
device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM);
device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM);
device_desc.bNumConfigurations = 2;
+
+ /* Configure Microsoft OS 1.0 descriptors for RNDIS. */
+ cdev->os_desc_config = &rndis_config_driver;
+ cdev->use_os_string = true;
+ cdev->b_vendor_code = 0xcd; /* arbitrary */
+ utf8s_to_utf16s("MSFT100", 7,
+ UTF16_LITTLE_ENDIAN, (wchar_t *)cdev->qw_sign,
+ OS_STRING_QW_SIGN_LEN / 2);
+ rndis_opts = container_of(fi_rndis, struct f_rndis_opts,
+ func_inst);
+ memcpy(rndis_opts->rndis_ext_compat_id,
+ "RNDIS\0\0\0" "5162001", 16);
}
/* Allocate string descriptor numbers ... note that string
--
2.53.0