本文是系列第5篇。SD-WAN终端的典型形态是”有线宽带 + 4G蜂窝”双链路。本文详细记录将移远(Quectel)EC200T/EC20F 4G模块集成到OpenWrt系统的完整过程——从内核USB驱动修改,到AT指令测试,再到开机自动拨号的实现。

一、4G模块在路由器中的工作方式

4G模块通过USB接口连接到路由器的主控芯片。从软件角度看,4G模块接入后,Linux内核会将其识别为一系列USB设备:

  • 串口设备(ttyUSB0、ttyUSB1…):用于发送AT指令控制模块
  • 网络设备(usb0、wwan0…):用于数据传输,作为WAN接口

要让路由器通过4G上网,需要解决两个层面的问题:

  1. 内核层面:让Linux正确识别4G模块的USB设备,创建串口和网络接口
  2. 用户空间层面:通过串口发送拨号指令,建立数据连接,配置网络路由

二、内核驱动修改

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模块不识别

排查步骤:

  1. lsusb确认USB设备是否存在
  2. 确认VID/PID与驱动中的定义一致
  3. dmesg | grep usb查看内核是否有错误信息
  4. 确认USB主机控制器驱动已加载(ohci/uhci/xhci)

7.2 拨号成功但无法上网

排查步骤:

  1. AT+CSQ检查信号强度(低于10可能不稳定)
  2. 确认APN设置正确(不同运营商APN不同)
  3. AT+CREG?确认已注册到运营商网络
  4. ping 8.8.8.8测试连通性
  5. 检查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的核心技术——虚拟专线的流量分流实现。这是”让指定流量走隧道,其余流量走本地”的关键机制。