背景说明
RNDIS是一个以太网端口 ( Ethernet port )。最开始是微软控制的,用以取代 CDC Ethernet 的协议。
公开发布的 RNDIS规范很模糊,并且不必要的复杂。 ActiveSync 等规范术语使情况更糟糕。
简而言之,它是一个微软控制的,而不是开源生态系统控制的协议。 Linux 支持它仅仅是因为微软不支持 CDC以太网标准。
RNDIS数据传输模型很复杂,每个USB 消息都包含了多个以太网包。
RNDIS默认期待自己作为USB配置中的唯一功能;因此你不能把它用于USB复合设备;并且它期待自己是第一个usb配置。
很不幸,微软的RNDIS驱动程序充满了bug,经常死机或者系统冻结,且经常和规范矛盾。
对于Linux开源社区而言,既然改正这些bug, 或者从微软拿到精确的RNDIS规范文档从而绕过它都不可能,
也许你可以避免使用 RNDIS。
代码分析
kernel/drivers/usb/gadget/f_rndis.c 文件开头即定义了 f_rndis 数据结构
struct f_rndis {
struct gether port;
u8 ctrl_id, data_id;
u8 ethaddr[ETH_ALEN];
u32 vendorID;
const char *manufacturer;
int config;
struct usb_ep *notify;
struct usb_request *notify_req;
atomic_t notify_count;
};
随后,f_rndis.c 分别定义了各种 usb 接口 和 usb 描述符。
static struct usb_interface_descriptor rndis_control_intf = {
.bLength = sizeof rndis_control_intf,
.bDescriptorType = USB_DT_INTERFACE,
/* status endpoint is optional; this could be patched later */
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_COMM,
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
.bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR,
};
其后, 分别定义了 full speed, high speed, super speed的描述符。
static struct usb_descriptor_header *eth_ss_function[] = {
(struct usb_descriptor_header *) &rndis_iad_descriptor,
/* control interface matches ACM, not Ethernet */
(struct usb_descriptor_header *) &rndis_control_intf,
(struct usb_descriptor_header *) &header_desc,
(struct usb_descriptor_header *) &call_mgmt_descriptor,
(struct usb_descriptor_header *) &rndis_acm_descriptor,
(struct usb_descriptor_header *) &rndis_union_desc,
(struct usb_descriptor_header *) &ss_notify_desc,
(struct usb_descriptor_header *) &ss_intr_comp_desc,
/* data interface has no altsetting */
(struct usb_descriptor_he