diff --git a/Documentation/ABI/testing/configfs-usb-gadget-rndis b/Documentation/ABI/testing/configfs-usb-gadget-rndis index 9416eda7fe93..52d295607678 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-rndis +++ b/Documentation/ABI/testing/configfs-usb-gadget-rndis @@ -16,4 +16,7 @@ Description: class USB interface class, default is 02 (hex) subclass USB interface subclass, default is 06 (hex) protocol USB interface protocol, default is 00 (hex) + use_ms_rndiscmp Use the MS Windows rndiscmp.inf compatible + class 0xEF, subclass 0x04, protocol 0x01 + instead of the default 0x02/0x06/0x00. ========= ============================================= diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index b47f99d17ee9..bdb2bfc66390 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -681,6 +682,18 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass; rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol; + /* + * Starting with Vista, Windows will match this Class/SubClass/Protocol + * with rndiscmp.inf and load the proper driver without the need for a + * custom .inf. + * Ref: https://msdn.microsoft.com/library/ff538820(v=vs.85).aspx + */ + if (rndis_opts->use_ms_rndiscmp) { + rndis_iad_descriptor.bFunctionClass = USB_CLASS_MISC; + rndis_iad_descriptor.bFunctionSubClass = USB_MISC_SUBCLASS_RNDIS; + rndis_iad_descriptor.bFunctionProtocol = USB_MISC_RNDIS_PROTO_ENET; + } + /* * in drivers/usb/gadget/configfs.c:configfs_composite_bind() * configurations are bound in sequence with list_for_each_entry, @@ -863,6 +876,40 @@ USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass); /* f_rndis_opts_protocol */ USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol); +static ssize_t +rndis_opts_use_ms_rndiscmp_show(struct config_item *item, char *page) +{ + struct f_rndis_opts *opts = to_f_rndis_opts(item); + int ret; + + mutex_lock(&opts->lock); + ret = sprintf(page, "%d\n", opts->use_ms_rndiscmp); + mutex_unlock(&opts->lock); + + return ret; +} + +static ssize_t +rndis_opts_use_ms_rndiscmp_store(struct config_item *item, const char *page, + size_t len) +{ + struct f_rndis_opts *opts = to_f_rndis_opts(item); + int ret; + bool use; + + mutex_lock(&opts->lock); + ret = strtobool(page, &use); + if (!ret) { + opts->use_ms_rndiscmp = use; + ret = len; + } + mutex_unlock(&opts->lock); + + return ret; +} + +CONFIGFS_ATTR(rndis_opts_, use_ms_rndiscmp); + static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_dev_addr, &rndis_opts_attr_host_addr, @@ -871,6 +918,7 @@ static struct configfs_attribute *rndis_attrs[] = { &rndis_opts_attr_class, &rndis_opts_attr_subclass, &rndis_opts_attr_protocol, + &rndis_opts_attr_use_ms_rndiscmp, NULL, }; diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index a8c409b2f52f..5db269110504 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -22,6 +22,7 @@ struct f_rndis_opts { struct net_device *net; bool bound; bool borrowed_net; + bool use_ms_rndiscmp; struct config_group *rndis_interf_group; struct usb_os_desc rndis_os_desc; diff --git a/include/uapi/linux/usb/misc.h b/include/uapi/linux/usb/misc.h new file mode 100644 index 000000000000..a6661f607fb2 --- /dev/null +++ b/include/uapi/linux/usb/misc.h @@ -0,0 +1,14 @@ +/* + * USB Miscellaneous Device Class definitions + * + * Ref: http://www.usb.org/developers/defined_class/#BaseClassEFh + */ + +#ifndef __UAPI_LINUX_USB_MISC_H +#define __UAPI_LINUX_USB_MISC_H + +#define USB_MISC_SUBCLASS_RNDIS 0x04 + +#define USB_MISC_RNDIS_PROTO_ENET 0x01 + +#endif /* __UAPI_LINUX_USB_MISC_H */