SmartCross 工作日志 #1 – RNDIS Gadget

SmartCross 的设计目标是“易用”。当前的设想是,将 SmartCross 插到电脑上,电脑就会将其识别成一个网卡+声卡。同时,我们在网卡接口上启动一个 DHCP 服务器,这样电脑可以获得自动分配的 IP 地址,在浏览器中输入 IP 地址即可对设备进行配置。为此,我使用 Linux 内核提供的 f_rndis USB gadget 来连接到主机。在配置 RNDIS gadget 的过程中遇到了一些问题,记录如下。

配置 RNDIS 的步骤与配置普通 USB gadget 的步骤无异,在 gadget 的 function 目录中创建好 f_rndis 开头的目录即可。将设备插入 Windows PC 后,Windows 并不会自动为其安装驱动,而需要在设备管理器中手动选择安装驱动。

接下来需要在设备上运行一个 DHCP 服务器。在这里我直接选用了 systemd-networkd 内建的 DHCP 服务器,使用起来非常简单,只需要建立一个 network 文件,然后在里面写上 DHCPServer=yes 即可。不过,在这一步却遇到了一个坑:在上述默认 rndis 配置下,Windows 并不会将设备的连接类型识别为以太网,导致 DHCP 请求的 Hardware Type 字段被设置为 ARCNET(普通以太网环境下,该字段应为 ETHERNET):

截屏2022-01-22 下午10 51 15
Hardware type: ARCNET (0x07)

我使用的 systemd-networkd 版本 (v249) 中有一条判断语句,如果硬件类型不是 ETHERNET,就会将包直接丢掉,导致 DHCP 服务器不响应请求。为此我给 systemd-networkd 提交了一个 issue #22217。本来是想能不能添加一个针对 ARCNET 的 Workaround,不过没想到的是,维护者直接增加了任意硬件类型的支持代码,将这个限制去掉了(PR #22222),从根本上解决了问题。猜测也许是 IPoIB 也对这个 DHCP Server 有需求,这么解决问题就一劳永逸了。

到目前为止,RNDIS 算是能用了,不过每次都需要点击安装驱动还是比较麻烦。在 这篇文章 中提到了一个方法:

echo 0xEF > bDeviceClass
echo 0x02 > bDeviceSubClass
echo 0x01 > bDeviceProtocol

如此可以直接更改设备的 class、subclass 和 protocol,让 Windows 能够自动识别并安装驱动。用这种方法还有一个额外的好处:Windows 自动识别的驱动还可以让请求包中的类型直接是 ETHERNET,而不是 ARCNET,从而上面的 systemd 的修正也可以不需要了。至此,问题就完美解决了。

CC BY-SA 4.0 本作品使用基于以下许可授权:Creative Commons Attribution-ShareAlike 4.0 International License.