SD-WAN终端研发系列05 在OpenWrt上集成4G模块:从内核驱动到自动拨号
本文是系列第5篇。SD-WAN终端的典型形态是”有线宽带 + 4G蜂窝”双链路。本文详细记录将移远(Quectel)EC200T/EC20F 4G模块集成到OpenWrt系统的完整过程——从内核USB驱动修改,到AT指令测试,再到开机自动拨号的实现。
一、4G模块在路由器中的工作方式
4G模块通过USB接口连接到路由器的主控芯片。从软件角度看,4G模块接入后,Linux内核会将其识别为一系列USB设备:
- 串口设备(ttyUSB0、ttyUSB1…):用于发送AT指令控制模块
- 网络设备(usb0、wwan0…):用于数据传输,作为WAN接口
要让路由器通过4G上网,需要解决两个层面的问题:
- 内核层面:让Linux正确识别4G模块的USB设备,创建串口和网络接口
- 用户空间层面:通过串口发送拨号指令,建立数据连接,配置网络路由
二、内核驱动修改
OpenWrt 17.01及以上版本已经内置了大部分4G模块的驱动支持,但某些较新或特定型号的模块可能需要手动添加。以移远EC200T-CN(VID: 0x2C7C, PID: 0x6026)为例,需要修改三个内核驱动源文件。
2.1 修改option.c:注册USB设备ID
option.c是Linux USB串口驱动的核心文件,负责将USB设备映射为ttyUSB串口设备。
文件路径:drivers/usb/serial/option.c
第一步:添加设备ID
// 在文件头部的宏定义区域添加
#define QUECTEL_VENDOR_ID 0x2c7c
#define QUECTEL_PRODUCT_EC200T 0x6026
第二步:注册设备ID
在option_ids数组中添加设备匹配项:
static const struct usb_device_id option_ids[] = {
// ... 已有项 ...
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T) },
{ USB_DEVICE(0x05C6, 0x9215) }, // Quectel EC20
// ... 已有项 ...
};
第三步:添加探测函数
4G模块通常有多个USB接口(串口、网络等),option.c需要知道哪些接口应该作为串口设备注册,哪些应该留给网络驱动。通过option_probe函数控制:
static int option_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
// ... 已有代码 ...
// 为移远模块添加接口过滤
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2c7c) &&
serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) {
return -ENODEV; // 接口号>=4的不作为串口设备
}
// 为EC20添加同样的过滤
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) &&
serial->dev->descriptor.idProduct == cpu_to_le16(0x9215) &&
serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) {
return -ENODEV;
}
}
这里的逻辑是:4G模块的USB接口0-3作为串口设备(用于AT指令和PPP拨号),接口4及以上作为网络数据接口,由qmi_wwan驱动接管。
2.2 修改usb_wwan.c:添加零包反馈
根据USB协议要求,在批量输出传输时需要处理零数据包(Zero Packet)。如果不添加,某些4G模块会出现通信异常。
文件路径:drivers/usb/serial/usb_wwan.c
// 在usb_fill_bulk_urb调用后添加
#if 1 //Added by Quectel for Zero Packet
if (dir == USB_DIR_OUT) {
struct usb_device_descriptor *desc = &serial->dev->descriptor;
if (desc->idVendor == cpu_to_le16(0x2c7c))
urb->transfer_flags |= URB_ZERO_PACKET;
// 也可以为其他已知模块添加
}
#endif
2.3 修改qmi_wwan.c:注册QMI网络设备
QMI(Qualcomm Messaging Interface)是一种网络通信协议,4G模块通过QMI接口提供移动数据连接。
文件路径:drivers/net/usb/qmi_wwan.c
static const struct usb_device_id products[] = {
// ... 已有项 ...
#if 1 //Added by Quectel
{QMI_FIXED_INTF(0x2C7C, 0x6026, 4)}, /* Quectel EC200T */
{QMI_FIXED_INTF(0x05C6, 0x9215, 4)}, /* Quectel EC20 */
#endif
};
QMI_FIXED_INTF(vid, pid, intf)宏表示:将指定VID/PID设备的第intf号接口注册为QMI网络设备。
2.4 处理驱动冲突
如果系统中已经安装了qcserial驱动(高通的串口驱动),它可能与option驱动产生冲突——两者都试图注册同一个USB设备。需要检查qcserial.c中的设备ID列表,移除与option.c重复的ID。
2.5 制作内核补丁
直接在build_dir中修改的源码在make clean后会丢失。需要将修改保存为内核补丁(Patch),这样每次编译都会自动应用。
补丁制作步骤:
# 1. 备份原始文件
cp option.c option_old.c
# 2. 修改文件(已完成上述步骤)
# 3. 生成补丁
diff -ruN option_old.c option.c > 999-kernel-option-add-ec200t.patch
# 4. 修改补丁中的路径前缀
# 将 a/drivers/usb/serial/option.c 改为内核源码的绝对路径
# 将 b/drivers/usb/serial/option.c 改为内核源码的绝对路径
将补丁文件放入target/linux/ramips/patches-4.14/目录(4.14为内核版本号)。编译时,内核构建系统会自动应用该目录下的所有补丁。
2.6 通过menuconfig启用相关模块
Kernel modules
└── USB Support
├── kmod-usb-core # USB核心
├── kmod-usb-net # USB网络设备框架
├── kmod-usb-net-qmi-wwan # QMI网络驱动
├── kmod-usb-serial # USB串口框架
├── kmod-usb-serial-option # option串口驱动
├── kmod-usb-serial-wwan # USB WAN串口驱动
├── kmod-usb-ohci / uhci # USB主机控制器
└── kmod-usb2 / usb3 # USB 2.0/3.0支持
三、验证驱动加载
编译完成后刷入设备,插入4G模块(含SIM卡),检查驱动是否加载成功:
# 检查USB设备是否被识别
lsusb
# 应能看到 Quectel 的设备
# 检查串口设备是否创建
ls /dev/ttyUSB*
# 应能看到 ttyUSB0, ttyUSB1, ttyUSB2 等
# 检查串口设备的用途
# ttyUSB0: DM port(诊断端口)
# ttyUSB1: AT Port(AT指令端口)
# ttyUSB2: PPP/AT Port(拨号和AT指令)
如果看不到ttyUSB设备,需要排查:USB接口是否启用、VID/PID是否匹配、驱动模块是否加载。
四、AT指令测试
通过串口向4G模块发送AT指令,可以验证模块是否正常工作、SIM卡是否识别、网络是否注册。
使用microcom工具进行AT指令交互:
opkg install microcom # 如果未安装
microcom /dev/ttyUSB1 # 连接到AT端口
4.1 基础检查
AT # 测试通信是否正常
OK
AT+CPIN? # 检查SIM卡状态
+CPIN: READY # READY表示SIM卡正常识别
OK
AT+CSQ # 检查信号质量
+CSQ: 22,99 # 22为信号强度(0-31,越大越好),99为未知
OK
AT+COPS? # 查询运营商
+COPS: 0,0,"CHINA MOBILE",7 # 已注册中国移动网络
OK
AT+CGMI # 模块厂商
Quectel
AT+CGSN # IMEI号(国际移动设备标识)
868123456789012
4.2 数据连接设置
# 设置APN(接入点名称)
AT+QICSGP=1,1,"cmnet" # cmnet=移动, 3gnet/uninet=联通, ctnet=电信
OK
# EC200T需要手动触发拨号
AT+QNETDEVCTL=1,1,1
OK
按Ctrl+X退出microcom。
4.3 模式切换
移远模块支持多种USB网络模式:
- RNDIS模式:模拟以太网卡,兼容性好
- ECM模式:另一种以太网模拟模式
- MBIM模式:较新的协议
# 查询当前模式
AT+QCFG="usbnet"
+QCFG: "usbnet",1 # 1=ECM, 0=RNDIS
# 切换模式(需要重启模块生效)
AT+QCFG="usbnet",0 # 切换为RNDIS
AT+CFUN=1,1 # 重启模块
五、自动拨号实现
手动AT指令测试通过后,需要实现开机自动拨号。拨号脚本需要处理以下流程:
系统启动
↓
检测4G模块是否插入(lsusb或检查ttyUSB设备)
↓
检查SIM卡状态(AT+CPIN?)
↓
设置APN(AT+QICSGP)
↓
发起拨号连接
↓
等待网络接口就绪(usb0/wwan0 UP)
↓
配置网络接口(IP地址、路由、DNS)
5.1 网络接口配置
在OpenWrt的网络配置中添加4G接口:
- 手动方式:LuCI → 网络 → 接口 → 添加新接口 → 物理设置选中usb0 → 防火墙选择WAN
- 自动方式:在
02_network脚本中添加4G接口的UCI配置
5.2 Hotplug事件驱动
OpenWrt的hotplug机制可以在网络接口状态变化时自动触发脚本。当4G网络接口UP时,执行拨号和路由配置;当接口DOWN时,执行清理操作。
# /etc/hotplug.d/iface/10-l2tp(示例)
case "$ACTION" in
ifup)
# 接口上线时的操作
;;
ifdown)
# 接口断开时的操作
;;
esac
5.3 SIM卡热插拔检测
在工业环境中,SIM卡可能被意外拔出或更换。移远模块支持通过AT指令检测SIM卡状态:
AT+QSIMSTAT=1 # 开启SIM卡插拔状态报告
AT+QSIMDET=1,1 # 开启SIM卡检测功能(模式1)
# AT+QSIMDET=1,0 为模式0
当SIM卡状态变化时,模块会通过串口发送URC(非请求结果码):
+QSIMSTAT:1,0→ SIM卡拔出+QSIMSTAT:1,1→ SIM卡插入+CPIN: NOT READY→ SIM卡不可用Call Ready→ SIM卡就绪,可以拨号
拨号脚本需要监听这些事件,在SIM卡插入时自动发起拨号。
5.4 网络连通性检测
4G拨号成功不代表网络可用(信号弱、APN错误、欠费等都可能导致有连接但无网络)。需要通过ping检测来确认:
opkg install pingcheck # 安装网络检测工具
pingcheck工具定期ping指定的地址(如8.8.8.8),如果连续失败,触发重新拨号流程。
六、WAN与4G的切换
SD-WAN终端通常有有线WAN和4G两条链路。当有线网络断开时,需要自动切换到4G;当有线网络恢复时,切换回有线。有几种实现方式:
6.1 mwan3方案
mwan3是OpenWrt的多WAN管理工具,支持基于策略的链路选择和自动故障切换。
opkg install mwan3 luci-app-mwan3
配置要点:
- 为WAN和4G分别创建mwan3成员(member)
- 创建故障检测规则(ping目标地址)
- 创建策略(policy),定义链路优先级
- 将策略绑定到具体的流量规则
6.2 路由表方案
如果不需要复杂的策略路由,可以使用简单的路由表切换:
- 创建两张路由表(如table 100和table 101)
- 默认使用WAN的路由表
- 当WAN断开时,通过hotplug事件切换到4G的路由表
- 当WAN恢复时,切换回WAN的路由表
七、实际部署中的问题与解决
7.1 4G模块不识别
排查步骤:
lsusb确认USB设备是否存在- 确认VID/PID与驱动中的定义一致
dmesg | grep usb查看内核是否有错误信息- 确认USB主机控制器驱动已加载(ohci/uhci/xhci)
7.2 拨号成功但无法上网
排查步骤:
AT+CSQ检查信号强度(低于10可能不稳定)- 确认APN设置正确(不同运营商APN不同)
AT+CREG?确认已注册到运营商网络ping 8.8.8.8测试连通性- 检查DNS配置(
cat /etc/resolv.conf)
7.3 4G性能基准
在MT7621双核设备上,未启用硬件加密的L2TP隧道测试结果:
[ 4] 0.00-30.00 sec 408 MBytes 114 Mbits/sec sender
[ 4] 0.00-30.00 sec 408 MBytes 114 Mbits/sec receiver
这个吞吐量受限于CPU加密运算能力。如果需要更高性能,需要选择支持硬件加密的芯片平台。
下一篇将深入SD-WAN的核心技术——虚拟专线的流量分流实现。这是”让指定流量走隧道,其余流量走本地”的关键机制。