cdc_mbim - 用于 CDC MBIM 移动宽带调制解调器的驱动程序

cdc_mbim 驱动程序支持符合“移动宽带接口模型的通用串行总线通信类子类规范”[1] 的 USB 设备,该规范是对“网络控制模型设备的通用串行总线通信类子类规范”[2] 的进一步发展,针对移动宽带设备(也称为“3G/LTE 调制解调器”)进行了优化。

命令行参数

cdc_mbim 驱动程序没有自己的参数。但是,对于 NCM 1.0 向后兼容的 MBIM 功能([1] 的第 3.2 节中定义的“NCM/MBIM 功能”)的探测行为,受 cdc_ncm 驱动程序参数的影响

prefer_mbim

类型:

布尔

有效范围:

N/Y (0-1)

默认值:

Y(首选 MBIM)

此参数设置 NCM/MBIM 功能的系统策略。此类功能将由 cdc_ncm 驱动程序或 cdc_mbim 驱动程序处理,具体取决于 prefer_mbim 设置。设置 prefer_mbim=N 会使 cdc_mbim 驱动程序忽略这些功能,而让 cdc_ncm 驱动程序来处理它们。

该参数是可写的,并且可以随时更改。需要手动取消绑定/绑定,才能使更改对绑定到“错误”驱动程序的 NCM/MBIM 功能生效

基本用法

MBIM 功能在未管理时处于非活动状态。cdc_mbim 驱动程序仅提供到 MBIM 控制通道的用户空间接口,并且不会参与该功能的管理。这意味着始终需要用户空间 MBIM 管理应用程序来启用 MBIM 功能。

此类用户空间应用程序包括但不限于

  • mbimcli(包含在 libmbim [3] 库中),以及

  • ModemManager [4]

建立 MBIM IP 会话至少需要管理应用程序执行以下操作

  • 打开控制通道

  • 配置网络连接设置

  • 连接到网络

  • 配置 IP 接口

管理应用程序开发

驱动程序 <-> 用户空间接口如下所述。MBIM 控制通道协议在 [1] 中进行了描述。

MBIM 控制通道用户空间 ABI

/dev/cdc-wdmX 字符设备

该驱动程序使用 cdc-wdm 驱动程序作为子驱动程序,创建到 MBIM 功能控制通道的双向管道。控制通道管道的用户空间端是 /dev/cdc-wdmX 字符设备。

cdc_mbim 驱动程序不处理或管理控制通道上的消息。该通道完全委托给用户空间管理应用程序。因此,此应用程序有责任确保它符合 [1] 中的所有控制通道要求。

cdc-wdmX 设备创建为 MBIM 控制接口 USB 设备的子设备。可以使用 sysfs 查找与特定 MBIM 功能关联的字符设备。例如

bjorn@nemi:~$ ls /sys/bus/usb/drivers/cdc_mbim/2-4:2.12/usbmisc
cdc-wdm0

bjorn@nemi:~$ grep . /sys/bus/usb/drivers/cdc_mbim/2-4:2.12/usbmisc/cdc-wdm0/dev
180:0

USB 配置描述符

CDC MBIM 功能描述符的 wMaxControlMessage 字段限制了最大控制消息大小。管理应用程序负责协商符合 [1] 的第 9.3.1 节要求的控制消息大小,同时考虑此描述符字段。

用户空间应用程序可以使用 [6] 或 [7] 中描述的两个 USB 配置描述符内核接口中的任何一个来访问 MBIM 功能的 CDC MBIM 功能描述符。

另请参阅下面的 ioctl 文档。

分片

用户空间应用程序负责所有控制消息的分片和去分片,如 [1] 的第 9.5 节中所述。

/dev/cdc-wdmX write()

来自管理应用程序的 MBIM 控制消息不得超过协商的控制消息大小。

/dev/cdc-wdmX read()

管理应用程序必须接受最大为协商的控制消息大小的控制消息。

/dev/cdc-wdmX ioctl()

IOCTL_WDM_MAX_COMMAND:获取最大命令大小 此 ioctl 返回 MBIM 设备的 CDC MBIM 功能描述符的 wMaxControlMessage 字段。这旨在提供方便,从而无需从用户空间解析 USB 描述符。

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/usb/cdc-wdm.h>
int main()
{
        __u16 max;
        int fd = open("/dev/cdc-wdm0", O_RDWR);
        if (!ioctl(fd, IOCTL_WDM_MAX_COMMAND, &max))
                printf("wMaxControlMessage is %d\n", max);
}

自定义设备服务

MBIM 规范允许供应商自由定义其他服务。cdc_mbim 驱动程序完全支持这一点。

对新 MBIM 服务(包括供应商指定的服务)的支持完全在用户空间中实现,就像 MBIM 控制协议的其余部分一样

新服务应在 MBIM 注册表 [5] 中注册。

MBIM 数据通道用户空间 ABI

wwanY 网络设备

cdc_mbim 驱动程序将 MBIM 数据通道表示为“wwan”类型的单个网络设备。此网络设备最初映射到 MBIM IP 会话 0。

多路复用 IP 会话 (IPS)

MBIM 允许在单个 USB 数据通道上多路复用最多 256 个 IP 会话。cdc_mbim 驱动程序将此类 IP 会话建模为主 wwanY 设备的 802.1q VLAN 子设备,将 MBIM IP 会话 Z 映射到 VLAN ID Z,对于所有大于 0 的 Z 值。

设备最大 Z 值在 [1] 的第 10.5.1 节中描述的 MBIM_DEVICE_CAPS_INFO 结构中给出。

用户空间管理应用程序负责在建立 SessionId 大于 0 的 MBIM IP 会话之前添加新的 VLAN 链接。可以使用常规 VLAN 内核接口(ioctl 或 netlink)添加这些链接。

例如,为 SessionId 为 3 的 MBIM IP 会话添加链接

ip link add link wwan0 name wwan0.3 type vlan id 3

驱动程序会自动将“wwan0.3”网络设备映射到 MBIM IP 会话 3。

设备服务流 (DSS)

MBIM 还允许在同一共享 USB 数据通道上多路复用最多 256 个非 IP 数据流。cdc_mbim 驱动程序将这些会话建模为主 wwanY 设备的另一组 802.1q VLAN 子设备,将 MBIM DSS 会话 A 映射到 VLAN ID (256 + A),对于所有 A 值。

设备最大 A 值在 [1] 的第 10.5.29 节中描述的 MBIM_DEVICE_SERVICES_INFO 结构中给出。

DSS VLAN 子设备用作共享 MBIM 数据通道和支持 MBIM DSS 的用户空间应用程序之间的实用接口。它不打算直接呈现给最终用户。假设启动 DSS 会话的用户空间应用程序还会负责对 DSS 数据进行必要的成帧,以适合流类型的方式向最终用户呈现流。

网络设备 ABI 要求为每个正在传输的 DSS 数据帧提供一个虚拟以太网头。此头的内容是任意的,但以下情况例外

  • 使用 IP 协议(0x0800 或 0x86dd)的 TX 帧将被丢弃

  • RX 帧的协议字段将设置为 ETH_P_802_3(但不会是正确格式化的 802.3 帧)

  • RX 帧的目的地址将设置为主设备的硬件地址

支持 DSS 的用户空间管理应用程序负责在 TX 上添加虚拟以太网头并在 RX 上剥离它。

这是一个使用常用工具的简单示例,将 DssSessionId 5 导出为 /dev/nmea 符号链接指向的 pty 字符设备

ip link add link wwan0 name wwan0.dss5 type vlan id 261
ip link set dev wwan0.dss5 up
socat INTERFACE:wwan0.dss5,type=2 PTY:,echo=0,link=/dev/nmea

这只是一个示例,最适合用于测试 DSS 服务。支持特定 MBIM DSS 服务用户空间应用程序应使用该服务所需的工具和编程接口。

请注意,为 DSS 会话添加 VLAN 链接是完全可选的。管理应用程序可以选择直接将数据包套接字绑定到主网络设备,使用收到的 VLAN 标签将帧映射到正确的 DSS 会话,并在 TX 上添加带有适当标签的 18 字节 VLAN 以太网头。在这种情况下,建议使用套接字过滤器,仅匹配 DSS VLAN 子集。这样可以避免不必要地将不相关的 IP 会话数据复制到用户空间。例如

static struct sock_filter dssfilter[] = {
      /* use special negative offsets to get VLAN tag */
      BPF_STMT(BPF_LD|BPF_B|BPF_ABS, SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT),
      BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 1, 0, 6), /* true */

      /* verify DSS VLAN range */
      BPF_STMT(BPF_LD|BPF_H|BPF_ABS, SKF_AD_OFF + SKF_AD_VLAN_TAG),
      BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 0, 4),     /* 256 is first DSS VLAN */
      BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 512, 3, 0),     /* 511 is last DSS VLAN */

      /* verify ethertype */
      BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 2 * ETH_ALEN),
      BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ETH_P_802_3, 0, 1),

      BPF_STMT(BPF_RET|BPF_K, (u_int)-1),     /* accept */
      BPF_STMT(BPF_RET|BPF_K, 0),             /* ignore */
};

标记的 IP 会话 0 VLAN

如上所述,MBIM IP 会话 0 被驱动程序视为特殊会话。它最初映射到 wwanY 网络设备上的未标记帧。

此映射对多路复用 IPS 和 DSS 会话有一些限制,这些限制可能并不总是实用

  • 没有 IPS 或 DSS 会话可以使用大于 IP 会话 0 上的 MTU 的帧大小

  • 除非表示 IP 会话 0 的网络设备也处于启动状态,否则没有 IPS 或 DSS 会话可以处于启动状态

可以通过选择使驱动程序将 IP 会话 0 映射到 VLAN 子设备(类似于所有其他 IP 会话)来避免这些问题。可以通过为魔术 VLAN ID 4094 添加 VLAN 链接来触发此行为。然后,驱动程序将立即开始将 MBIM IP 会话 0 映射到此 VLAN,并将丢弃主 wwanY 设备上的未标记帧。

提示:将此 VLAN 子设备命名为 MBIM SessionID 而不是 VLAN ID 可能对最终用户来说更不容易混淆。例如

ip link add link wwan0 name wwan0.0 type vlan id 4094

VLAN 映射

总结上述 cdc_mbim 驱动程序映射,我们在 wwanY 网络设备上的 VLAN 标签和共享 USB 数据通道上的 MBIM 会话之间有以下关系

VLAN ID       MBIM type   MBIM SessionID           Notes
---------------------------------------------------------
untagged      IPS         0                        a)
1 - 255       IPS         1 - 255 <VLANID>
256 - 511     DSS         0 - 255 <VLANID - 256>
512 - 4093                                         b)
4094          IPS         0                        c)

  a) if no VLAN ID 4094 link exists, else dropped
  b) unsupported VLAN range, unconditionally dropped
  c) if a VLAN ID 4094 link exists, else dropped

参考文献

  1. USB Implementers Forum, Inc. - “移动宽带接口模型的通用串行总线通信类子类规范”,修订版 1.0(勘误表 1),2013 年 5 月 1 日

  2. USB Implementers Forum, Inc. - “网络控制模型设备的通用串行总线通信类子类规范”,修订版 1.0(勘误表 1),2010 年 11 月 24 日

  3. libmbim - “一个基于 glib 的库,用于与使用移动接口宽带模型 (MBIM) 协议的 WWAN 调制解调器和设备通信”

  4. ModemManager - “一个 DBus 激活的守护程序,用于控制移动宽带 (2G/3G/4G) 设备和连接”

  5. “MBIM(移动宽带接口模型)注册表”

  6. “/sys/kernel/debug/usb/devices 输出格式”

  7. “/sys/bus/usb/devices/.../descriptors”

    • Documentation/ABI/stable/sysfs-bus-usb