前言
我是远程桌面应用的重度使用者。最近,我经常需要远程到公司电脑进行办公。公司的电脑已经接入到我的分布式局域网当中,使用内部 IP 地址就能直接访问。——听起来非常美好。然而,公司的网络是对称式 NAT,且有 电信—联通 双线负载均衡,这就导致了公司网络出口一会是电信,一会是联通。我的网络大量应用了 Zerotier 二层虚拟化技术,P2P 穿透对这种场景非常敏感。为了优化线路质量,提高线路冗余度,我决定为公司路由器增加第二条互联网接入方式,这次我选择了通过蜂窝移动网络模块。
模块在网上商店可以以非常实惠的价格购入,这里我选择了 ME909s-821A 模块与 USB 转接板(含 SIM 卡槽)套餐,拿到手后,直接插入 Windows PC,可以直接使用并连接 Internet。
模块的工作模式
通过查阅资料,我发现,此类模块为了兼容多种用途,往往具有多种工作模式。如:串口,Modem,NDIS,MBIM 等等。
其中,Modem 接口是过去最常用的方法,模块本身工作为 Serial Modem,由客户端计算机执行 AT 指令,并建立 PPP 会话。
NDIS/ECM/NCM 是在 MBIM 出现之前的最优做法,模块表现为一块 USB 网卡,由模块完成网络拨号,过程对客户端计算机透明,只需让客户端计算机按照输入的 APN 等信息进行 AT(NDIS) 指令,连接成功后很快就能看到这块网卡取得 IP 地址。
MBIM 是较新的接口工作方式,是由 USB 组织官方所提供的解决方案,是完全针对上网卡环境所设计的,当我们将模块插入计算机后,Windows 10 甚至能够零配置,直接初始化使用,并能识别出 SIM 卡 ID,IMEI,以及信号强度信息。
Modem 的速度最慢,它的速度受限于串口通信,NDIS 方式 与 MBIM 方式则更加适合高速网络,尤其是 4G 网络。
尝试
首先,我尝试了 NDIS/ECM/NCM 模式。OpenWRT 有针对此模式的图形界面操作。我使用的是 OpenWRT 19.07。
opkg update opkg install usbutils kmod-usb-net-huawei-cdc-ncm comgt-ncm luci-proto-3g luci-proto-ncm luci-proto-qmi kmod-usb-net-huawei-cdc-ncm usb-modeswitch
安装完成后,我们可以使用 lsusb, dmesg 来查看模块是否被正确识别,使用 ls -l /dev/ 看看是否存在 /dev/ttyUSB# (# 为数字)。我发现,模块已经正常驱动,但是并不存在网上资料所介绍的 wwan0 或 usb0 接口。经过测试发现,usb-modeswitch 包不应该安装,且还需要额外安装另一个包。
opkg remove usb-modeswitch opkg install kmod-usb-net-cdc-ether
现在,我们使用 ifconfig -a 可以看到 wwan0 接口了。接下来在 Web 界面中创建接口,输入网络信息就可以了。
一切似乎非常美好,wwan0 获取了到了地址,设置好默认网关与跃点信息后,可以通过路由器使用蜂窝移动网络接入互联网。但是…有些不对劲。IPv6 地址去哪里了?在 Windows 系统下,我可以清楚地看到,IPv6 是正常工作的。
去年,我尝试过将 ME909s-821 模块接入到 Ubuntu 18.04 LTS 下,使用 Network Manager 接入网络,同样无法获得 IPv6 地址。查阅了很久的资料,我发现此模块似乎无法在 NCM(NDIS) 模式下使用 IPv6——即便你选择了双栈网络。通过抓包我发现,路由器在 wwan0 接口发送的 IPv6 邻居发现数据包无任何应答,也许这是一个固件 BUG?
查阅华为的模块接口手册,我们可以得知,在 Windows 8 及以上系统下,模块以 MBIM 模式工作,并且在实际尝试中能够获得 IPv6 地址。于是我决定继续尝试 MBIM 模式。
opkg remove kmod-usb-net-cdc-ether opkg install umbim kmod-usb-net-cdc-mbim
不过,此时模块被内核默认识别为 NDIS(NCM) 模式,我们需要让内核识别为 MBIM 模式。
echo 0 > /sys/bus/usb/devices/1-2/bConfigurationValue /bin/sleep 5 echo 3 > /sys/bus/usb/devices/1-2/bConfigurationValue
注意,上文中的 “1-2” 是模块在 USB 总线中的位置,可参考 lsusb 中的信息更改,每台设备都可能不太一样。另外,不可以直接将配置信息设置为 3,必须先置 0 以禁用设备然后再赋值,否则,后续的 umbim 将无法与模块正确通信。
然后,我们可以通过以下命令,上线 wwan0,并接入移动网络:
/sbin/ifconfig wwan0 up /bin/sleep 5 /sbin/umbim -d /dev/cdc-wdm0 -n -t 2 subscriber /bin/sleep 2 /sbin/umbim -d /dev/cdc-wdm0 -n -t 2 attach /bin/sleep 2 /sbin/umbim -d /dev/cdc-wdm0 -n -t 2 connect ctnet ipv4v6
最后,在 OpenWRT 的 Web 界面中,我们创建两个 WAN,选择 wwan0 接口,协议分别是 DHCP 与 DHCPv6,就能成功地获取到双栈 IP 地址了:
上述脚本我们可以加入 /etc/rc.local,让设备开机自动执行,如果可以深入研究,可以写成脚本,与 OpenWRT 集成,这样会显得更加优雅。每次插拔模块都需要切换工作模式(可以参考 OpenWRT 热插拔事件制作脚本以自动化),而每次切换都会产生不同的设备 MAC 地址,如果有相关应用依赖 wwan0 的 MAC 地址,还需要特别注意。
参考资料
Huawei Module, USB Interface Descriptor Guide Issue 02(2015-09-09): http://download-c1.huawei.com/download/downloadCenter?downloadId=60305&version=200311&siteCode=worldwide&view=true
Huawei ME906s-158 (a.k.a. HP lt4132): Linux and IPv6 support (or lack thereof): https://toreanderson.github.io/2017/07/31/huawei-me906s-hp-lt4132-linux-ipv6.html
How to use 4G LTE modems like the MC7455 on both Debian/Ubuntu and OpenWRT using MBIM: https://gist.github.com/Juul/e42c5b6ec71ce11923526b36d3f1cb2c