[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