Skip to content

[BUG] USB 枚举路径漂移导致生成重复接口 3_1_2,并持续刷屏 "sim card is ready" #280

Open

Description

@sassalana

描述问题

型号:MangoPi M28C
目标平台:rockchip/armv8
固件版本:LEDE R26.02.20 / LuCI openwrt-23.05 branch git-26.249.11976-dd742f5
安装方式:自行编译
内核版本:6.12.80
Qmodem版本:qmodem - 3.4.0_rc3-104
调制解调器名称:FM650-CN
制造商:Fibocom Wireless Inc.
AT 端口:/dev/ttyUSB0
正常接口:4_1_2,物理路径 /sys/bus/usb/devices/4-1.2/
异常接口:3_1_2

QModem 原本正常使用 4_1_2 接口拨号,运行约两天后,网络配置中额外出现了 3_1_2 接口。

4_1_2 可以正常拨号并获得 IP:10.74.127.106。

但 3_1_2 无法正常拨号,并且日志持续每 5 秒左右刷屏:

[2026-09-23 12:23:55] modem_dial:info sim card is ready
[2026-09-23 12:24:00] modem_dial:info sim card is ready
[2026-09-23 12:24:05] modem_dial:info sim card is ready
[2026-09-23 12:24:11] modem_dial:info sim card is ready
...

疑似 USB 枚举路径发生漂移后,QModem 将同一个物理模组识别成了新的设备,从而创建了重复接口 3_1_2,但没有正确清理或去重。


复现方法
Steps to Reproduce

  1. 正常配置并启用 QModem,接口为 4_1_2
  2. 使用一段时间,约两天。
  3. 期间发生过重启、断电重新启动
  4. 之后 QModem 网络配置中多出 3_1_2
  5. 3_1_2 持续打印 sim card is ready,无法正常拨号

期望行为
描述正常情况下应该是什么行为

同一个物理模组不应因为 USB 路径变化而生成重复接口
自动探测失败时不应无限刷屏日志。
3_1_2 这种异常接口不应反复尝试拨号


日志信息

异常接口 3_1_2 日志片段:

[2026-09-23 12:23:55] modem_dial:info sim card is ready
[2026-09-23 12:24:00] modem_dial:info sim card is ready
[2026-09-23 12:24:05] modem_dial:info sim card is ready
[2026-09-23 12:24:11] modem_dial:info sim card is ready
...

正常接口 4_1_2 日志片段:

[2026-04-04 06:32:16] modem_dial:modem_path=/sys/bus/usb/devices/4-1.2/,driver=ecm,interface=4_1_2,at_port=/dev/ttyUSB0,using_sim_slot:1,dns_list:,bridge_enabled:0,bridge_ports:,bridge_management_ip: 
[2026-04-04 06:32:21] modem_dial:info sim card is miss 
[2026-04-04 14:32:26] modem_dial:info sim card is miss 
[2026-04-04 14:32:32] modem_dial:info sim card is miss 
[2026-04-04 14:32:37] modem_dial:info sim card is miss 
[2026-04-04 14:32:42] modem_dial:info sim card is ready 
[2026-04-04 14:32:42] modem_dial:create interface 4_1_2 with proto dhcp and metric 11 
[2026-04-04 14:32:42] modem_dial:create interface 4_1_2v6 with proto dhcpv6 and metric 11 
[2026-04-04 14:32:42] modem_dial:set interface 4_1_2 to usb0 
[2026-04-04 14:32:43] modem_dial:network reload 
[2026-04-04 14:32:43] modem_dial:firewall reload 
[2026-04-04 14:32:43] modem_dial:dialing /sys/bus/usb/devices/4-1.2/ driver ecm 
[2026-04-04 14:32:43] modem_dial:dialing: vendor:fibocom; platform:unisoc; driver:ecm; apn:; command:AT+GTRNDIS=1,1 pdp_index:1 
[2026-04-04 14:32:43] modem_dial:dial_cmd: AT+GTRNDIS=1,1; cgdcont_cmd: AT+CGDCONT=1,"IPV4V6"; ppp_auth_cmd:  
[2026-09-23 12:51:04] modem_dial:ip changed from , to ,10.251.229.7 

Activity

  1. FUjr commented on Sep 24, 2026

    @FUjr
    Owner

    关于重复接口 3_1_2 的修复(可测试分支)

    感谢反馈。根因已定位并实现了修复,欢迎帮忙实机验证。

    根因:modem_scand 把 UCI 段名直接绑定到 sysfs 槽位名(4-1.2 → 4_1_2),既没有记录「这个段属于哪个物理模组」,也不会回收已经失效的旧段。模组换端口重新枚举后就会多出一个段;而一个网卡(usb0)只能属于一条 sysfs 路径,旧段永远等不到网卡,于是 modem_dial.sh 的 5 秒轮询就一直刷 sim card is ready。

    修复内容(分支 fix/modem-scand-device-dedup-280,commit 6fe6851):

    • 扫描时为每个模组记录物理身份:USB 用 usb:<vid>:<pid>@<物理端口> 加设备序列号(0123456789ABCDEF 之类的厂商占位串会被拒绝),PCIe 用 pcie:<slot>;
    • 同一物理模组换端口后改为迁移已有段,只刷新扫描派生字段,alias/apn/pincode/metric/enable_dial 全部保留,并把 state 重新置为 enabled(否则重插后不会拨号);
    • 能证明是同一模组的重复段会被回收,回收前先停掉它的拨号实例;
    • 设备仍在其它端口存在的段、序列号明确冲突的段,绝不会被合并或删除。

    如何把 feeds 切到这个分支

    把 feeds.conf.default 里的

    src-git qmodem https://github.com/FUjr/QModem.git;main
    

    改成

    src-git qmodem https://github.com/FUjr/QModem.git;fix/modem-scand-device-dedup-280
    

    然后:

    ./scripts/feeds update qmodem
    ./scripts/feeds install -a -p qmodem
    
    # 确认拿到的是修复分支(应显示 6fe6851 modem_scan: merge ...)
    git -C feeds/qmodem log --oneline -1
    
    # 只重编受影响的包
    make package/feeds/qmodem/modem_scan/compile V=s

    产物在 bin/packages/<arch>/qmodem/modem_scan-*.ipk(apk 系统是 *.apk),传到设备后:

    opkg install --force-reinstall /tmp/modem_scan-*.ipk
    /etc/init.d/qmodem_network restart

    如果 ./scripts/feeds update 不接受带 / 的分支名,可以改成手动克隆 + src-link:

    git clone -b fix/modem-scand-device-dedup-280 https://github.com/FUjr/QModem.git ~/QModem-dedup
    echo "src-link qmodem $HOME/QModem-dedup" >> feeds.conf.default

    验证方法

    # 1. 看现有段以及它们记录的物理身份
    uci show qmodem | grep -E 'scan_id|scan_serial|path'
    
    # 2. 触发一次全量扫描(或直接把模组换到另一个 USB 口)
    /usr/share/qmodem/modem_scan.sh scan
    
    # 3. 看日志
    logread | grep -E 'migrate modem|retired duplicate|stopped leftover'

    预期:只保留一个 modem-device 段,path 指向当前端口,alias/apn 不变,重复段被停掉,之后不再刷 sim card is ready。

    已知限制(请知悉)

    • 你现有的 3_1_2 是旧版本创建的,没有 scan_id/scan_serial。新代码无法证明它是重复段,因此只会把它停用(state=disabled),不会自动删除。如果 uci show qmodem.3_1_2 里的 network 仍指向 usb0,停用会自动生效;否则请在 LuCI 里手动删掉这一个段即可,删除后不会再产生新的。
    • 该修复目前只在宿主机上完成编译和静态回归测试(application/qmodem/tests/test_modem_scan_device_dedup.sh,46 条断言,CI 的 Vendor fixture tests 已通过),尚未在真机上验证,所以非常需要你的实机反馈。
    • 分支名带 /,而仓库的 SDK 自动编译工作流用的是 branches: ['*'](* 不匹配 /),因此不会为这个分支产出固件包,需要按上面的步骤本地编译。
    • issue 里提到的「探测失败时无限刷屏」是另一个独立问题(modem_dial.sh 的 5 秒轮询没有退避),本次没有一并改动,以免和正在进行的 PR 冲突。

    如果验证有问题,请把 logread | grep qmodem 和 uci show qmodem 贴出来,我继续跟进。

  2. sassalana commented on Sep 24, 2026

    @sassalana
    Author

    感谢作者的修复和详细指导

    我已经编译并安装了modem_scan_3.4.0_rc3-1_aarch64_generic.ipk。

    当前进展

    • 旧的重复接口 3_1_2 已清理,sim card is ready 刷屏已停止。
    • 新包安装后,配置中成功出现了物理身份标识:
      qmodem.4_1_2.path='/sys/bus/usb/devices/4-1.2/'
      qmodem.4_1_2.scan_id='usb:2cb7:0a04@4-1.2'
      qmodem.4_1_2.scan_serial='MD6JQY007Z'

    我的模组是 PCIe 接口但走 USB 线路,主板只有一个 PCIe 插槽,无法物理拔插换 USB 口。因此我准备通过日常使用来继续尝试触发USB 路径漂移

    再次感谢!有结果我会及时反馈。

  3. sassalana commented on Sep 24, 2026

    @sassalana
    Author

    再次感谢作者的修复!有一个非常好的测试结果:

    我把模组从 ECM 拨号模式切换到 NCM 模式,这正好触发了一次 USB 路径漂移:

    项目 切换前 (ECM) 切换后 (NCM)
    path /sys/bus/usb/devices/4-1.2/ /sys/bus/usb/devices/2-1.2/
    scan_id usb:2cb7:0a04@4-1.2 usb:2cb7:0a05@2-1.2
    scan_serial MD6JQY007Z MD6JQY007Z

    结果:

    • 路径和 PID 都变了(ECM/NCM 是不同 USB 配置),但代码通过 scan_serial 正确识别为同一物理模组。
    • 没有生成重复段,段名仍是 4_1_2,sim card is ready 刷屏没有复现。
    • 拨号自动重建,成功获取 IP 10.41.3.161。

    一些补充说明:
    这次是主动切换拨号模式触发的路径变化,不是自然漂移,我会继续观察几天确认自然环境下是否也会正常。

    主板上似乎只有 4-1.2 是高速 USB,切换到 NCM 后路径变成了 2-1.2,可能是低速端口,这或许会影响网络性能

    切换过程中出现了 6 次 sim card is miss 的轮询(间隔 5 秒),最终恢复,期待后续修复。

    切换后的拨号日志:

    [2026-09-25 01:12:10] modem_dial:modem_path=/sys/bus/usb/devices/2-1.2/,driver=ncm,interface=4_1_2,at_port=/dev/ttyUSB0,using_sim_slot:1,dns_list:,bridge_enabled:0,bridge_ports:,bridge_management_ip: 
    [2026-09-25 01:12:15] modem_dial:info sim card is miss 
    [2026-09-25 01:12:21] modem_dial:info sim card is miss 
    [2026-09-25 01:12:26] modem_dial:info sim card is miss 
    [2026-09-25 01:12:31] modem_dial:info sim card is miss 
    [2026-09-25 01:12:36] modem_dial:info sim card is miss 
    [2026-09-25 01:12:41] modem_dial:info sim card is miss 
    [2026-09-25 01:12:46] modem_dial:info sim card is ready 
    [2026-09-25 01:12:46] modem_dial:create interface 4_1_2 with proto dhcp and metric 11 
    [2026-09-25 01:12:46] modem_dial:create interface 4_1_2v6 with proto dhcpv6 and metric 11 
    [2026-09-25 01:12:47] modem_dial:set interface 4_1_2 to usb0 
    [2026-09-25 01:12:47] modem_dial:network reload 
    [2026-09-25 01:12:47] modem_dial:firewall reload 
    [2026-09-25 01:12:47] modem_dial:dialing /sys/bus/usb/devices/2-1.2/ driver ncm 
    [2026-09-25 01:12:47] modem_dial:dialing: vendor:fibocom; platform:unisoc; driver:ncm; apn:; command:AT+GTRNDIS=1,1 pdp_index:1 
    [2026-09-25 01:12:47] modem_dial:dial_cmd: AT+GTRNDIS=1,1; cgdcont_cmd: AT+CGDCONT=1,"IPV4V6"; ppp_auth_cmd:  
    [2026-09-25 01:14:11] modem_dial:ip changed from , to ,10.41.3.161 
    

    从结果看,修复逻辑在真机上验证通过了。感谢!

  4. FUjr commented on Sep 25, 2026

    @FUjr
    Owner

    太好了,感谢实机验证 🙏 这个结果很有价值——它同时验证了序列号匹配这条路径确实生效(pid 从 0a04 变成 0a05、端口从 4-1.2 变成 2-1.2,仍然被认成同一个模组,段名保持 4_1_2,没有产生第二个段)。

    你的日志暴露了一个我还漏掉的场景,已修复

    你这次是 ECM → NCM,也就是同一个槽位重新枚举,所以段名恰好还是 4_1_2,没有触发那个漏洞。

    但如果是同一个模组换到另一个端口(4_1_2 → 3_1_2),会走另一条分支,而那条分支里我犯了个错:

    /* 旧代码:段名和本次扫描的槽位名相同时,直接跳过 */
    if (!strcmp(s->name, section) || s->fixed || ...)
        continue;

    这个跳过本意是「不要删掉马上要重写的那一段」,但段名撞车时它会把真正的持有者跳过:老段 4_1_2 里带着 scan_id/scan_serial(它就是同一模组),代码却因为它叫 4_1_2 而不回收它,然后在 3_1_2 上又建一个新段——正好又变成重复段。

    现在改成:只有「就是本次正在写入的那一段」才跳过;名字被别的槽位占用时,带同一身份的旧段照常回收。 同时补了一条保护——如果某个段记录的设备此刻仍然存在于别的路径,那它就不是残留,绝不回收。

    需要你再验证一次

    因为这是你报告里最接近原始场景(3_1_2 那种漂移)的路径,麻烦把 feeds 分支重新拉一下(同一个分支名,新 commit 8f48aa9):

    ./scripts/feeds update qmodem
    git -C feeds/qmodem log --oneline -1      # 应显示 8f48aa9
    make package/feeds/qmodem/modem_scan/compile V=s

    然后再用 ECM/NCM 切换一次(这次段名会保持 4_1_2,只是确认没有回归),并且如果条件允许,把模组换到主板上另一个 USB/PCIe 口——那才是原始 issue 的场景。切换后看:

    uci show qmodem | grep -E '^qmodem\.[0-9_]+=' # 应该只有一个 modem-device 段
    logread | grep -E 'migrate modem|retired duplicate|stopped leftover'

    关于你提到的另外两点

    1. sim card is miss 轮询 6 次(约 30 秒)

    这个属于探测阶段的正常重试,不是 bug:dial() 在拨号前要等 SIM 就绪和网卡出现,超时后每 5 秒重试一次。ECM→NCM 切换时模组要重新初始化 USB 配置,30 秒属于合理范围。

    真正的问题是 issue 里说的无限刷屏——那需要「准备阶段永远无法满足」才会发生(比如旧代码那种幽灵段,网卡被别的段占着)。现在段不会再重复,这条路径已经堵住了。

    另外提醒一句:拨号日志(/var/run/qmodem/<段名>_dir/dial_log)是超过 300 行才清空,logread 里的记录不受这个限制。如果你看到 logread 里持续刷同一条,那才是需要处理的;dial_log 本身不会无限增长。

    2. NCM 后路径变成 2-1.2、担心低速端口影响网速

    路径编号(2-1.2 vs 4-1.2)是 USB 控制器/总线编号,不是速率等级——它取决于模组以哪个 USB 配置枚举、挂在哪个 root hub 下,不代表链路变慢了。真正决定速率的是协商出来的 USB 速度,可以直接看:

    cat /sys/bus/usb/devices/2-1.2/speed     # 480 = USB2 High-Speed, 5000 = USB3 SuperSpeed
    cat /sys/bus/usb/devices/4-1.2/speed     # 对比切换前
    lsusb -t                                  # 看整棵树的速率

    如果 NCM 下 speed 仍是 480(甚至 5000),那就没有性能损失;如果掉到 12/1.5,才需要担心。方便的话把这两个值和 lsusb -t 的输出贴一下,我帮你看。

    当前分支状态

    • fix/modem-scand-device-dedup-280 → 8f48aa9(在 6fe6851 之上加了这个修复)
    • 回归测试同步更新到 57 条断言,CI 的 Vendor fixture tests 已通过

    感谢配合,等你换端口的结果。

  5. sassalana commented on Sep 26, 2026

    @sassalana
    Author

    太棒了,我成功通过拔掉天线完美复现了路径从 4-1.2 变成 3-1.2 的场景,并且验证了你的 8f48aa9 补丁完美生效!

    拔掉天线后,模组的网络模式从NR5G-SA Mode变为了FDD LTE并经历了重启短暂的断电重新枚举,USB 控制器编号发生变动,路径发生了漂移。以下是抓取的完整数据:

    1. 模组段状态(只保留了一个段,没有产生重复)

    root@LEDE:~# uci show qmodem | grep -E '^qmodem\.[0-9_]+='
    qmodem.4_1_2=modem-device
    

    2.物理身份与路径(路径变了,但 scan_serial 保留,APN 保留)

    root@LEDE:~# uci show qmodem | grep -E 'scan_id|scan_serial|path|alias|apn'
    qmodem.4_1_2.scan_serial='MD6JQY007Z'
    qmodem.4_1_2.alias='-'
    qmodem.4_1_2.force_set_apn='0'
    qmodem.4_1_2.apn='ctnet'
    qmodem.4_1_2.path='/sys/bus/usb/devices/3-1.2/'
    qmodem.4_1_2.scan_id='usb:2cb7:0a05@3-1.2'
    

    3.迁移日志(明确打印了 migrate modem,没有触发回收残留段)

    root@LEDE:~# logread | grep -E 'migrate modem|retired duplicate|stopped leftover'
    Sat Sep 26 13:04:35 2026 daemon.info modem_scand[959]: migrate modem section=4_1_2 slot=3-1.2 type=usb
    Sat Sep 26 13:05:06 2026 daemon.info modem_scand[959]: migrate modem section=4_1_2 slot=3-1.2 type=usb
    

    4. 拨号日志(没有刷屏,自动重建并成功拨号)

    [2026-09-26 13:04:36] modem_dial:modem_path=/sys/bus/usb/devices/3-1.2/,driver=ncm,interface=4_1_2,at_port=/dev/ttyUSB0,using_sim_slot:1,...
    [2026-09-26 13:04:41] modem_dial:info sim card is miss 
    ... (略去 5 次 normal miss 轮询)
    [2026-09-26 13:05:33] modem_dial:info sim card is ready 
    [2026-09-26 13:05:33] modem_dial:create interface 4_1_2 with proto dhcp and metric 11 
    [2026-09-26 13:05:33] modem_dial:create interface 4_1_2v6 with proto dhcpv6 and metric 11 
    [2026-09-26 13:05:33] modem_dial:set interface 4_1_2 to usb0 
    [2026-09-26 13:05:34] modem_dial:dialing /sys/bus/usb/devices/3-1.2/ driver ncm 
    [2026-09-26 13:05:34] modem_dial:dialing: vendor:fibocom; platform:unisoc; driver:ncm; apn:ctnet; command:AT+GTRNDIS=1,1 pdp_index:1 
    [2026-09-26 13:05:58] modem_dial:ip changed from , to ,10.113.198.64 
    

    5. 速度验证(未降速,依然是 5000M)

    root@LEDE:~# cat /sys/bus/usb/devices/3-1.2/speed
    5000
    root@LEDE:~# lsusb -t
    /:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=ehci-platform/1p, 480M
    /:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci-hcd/1p, 5000M
        |__ Port 1: Dev 2, If 0, Class=, Driver=hub/4p, 5000M
            |__ Port 2: Dev 3, If 0, Class=, Driver=cdc_ncm, 5000M
            |__ Port 2: Dev 3, If 1, Class=, Driver=cdc_ncm, 5000M
            |__ Port 2: Dev 3, If 2, Class=, Driver=option, 5000M
            ...
    /:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ohci-platform/1p, 12M
    /:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci-hcd/1p, 480M
        |__ Port 1: Dev 2, If 0, Class=, Driver=hub/4p, 480M
    

    6. 重启后的再次漂移验证(路径变回 4-1.2)

    为了进一步确认稳定性,我重启了一次路由器,发现 USB 枚举具有随机性,路径又从3-1.2漂移回了4-1.2。以下是重启后的拨号日志,依然没有产生重复段,且自动拨号成功:

    [2026-09-26 13:23:41] modem_dial:modem_path=/sys/bus/usb/devices/4-1.2/,driver=ncm,interface=4_1_2,at_port=/dev/ttyUSB0,using_sim_slot:1,...
    [2026-09-26 13:23:46] modem_dial:info sim card is miss 
    ... (略去 6 次 normal miss 轮询)
    [2026-09-26 13:24:23] modem_dial:info sim card is ready 
    [2026-09-26 13:24:23] modem_dial:create interface 4_1_2 with proto dhcp and metric 11 
    [2026-09-26 13:24:23] modem_dial:set interface 4_1_2 to usb0 
    [2026-09-26 13:24:23] modem_dial:dialing /sys/bus/usb/devices/4-1.2/ driver ncm 
    [2026-09-26 13:24:23] modem_dial:dial_cmd: AT+GTRNDIS=1,1; cgdcont_cmd: AT+CGDCONT=1,"IPV4V6","ctnet"; ppp_auth_cmd:  
    [2026-09-26 13:24:48] modem_dial:ip changed from , to ,10.96.165.135 
    

    结论:新补丁成功处理了跨端口漂移(无论4-1.2还是3-1.2),旧段被正确迁移到新槽位,配置完整保留,没有产生重复段,也没有出现刷屏。由于xhci-hcd在枚举时随机分配了总线号,路径会随机变化,但速度始终保持在 5000M 高速。非常感谢作者的修复!这个困扰我很久的接口问题终于彻底解决了!

  6. Medvedolog commented on Oct 22, 2026

    @Medvedolog

    Hi @FUjr, thanks for the fix on fix/modem-scand-device-dedup-280.
    We hit the same bug on an Orange Pi Zero 3 (OpenWrt 25.12, several USB modems: Fibocom FM350, Foxconn T99W175, Dell DW5821e). This board renumbers the USB buses on reboot, so the same FM350 appeared as 1-1.3, 3-1.3 and 6-1.3 on different boots. QModem kept a section for each slot name (1_1_3, 3_1_3, 6_1_3), and each one brought its own set of network interfaces. What followed:
    An old section stayed enabled with the AT port of an earlier boot. After renumbering, that tty belonged to another modem: 3_1_3 kept at_port /dev/ttyUSB5 while the FM350 had come back as cdc_acm (ttyACM0-2), and ttyUSB5 was now the T99's (3-1.4:1.1). QModem then sent its AT commands to the wrong modem (tom_modem ... AT+QSIMDET? every minute), and tom_modem got stuck in D state.
    The leftover interfaces were brought up by netifd on the live netdev, and 6_1_3v6 looped (125 times in one log).
    To be fair: we run with block_auto_probe=1, so _try_device and the hotplug remove handler, which would disable a section whose path is gone, are skipped on our side. But renumbering on reboot makes duplicates anyway, which is the case your fix handles with the vid:pid + serial identity. For now we remove the leftover sections downstream ourselves, and a proper fix in QModem would be much better.
    @sassalana confirmed 8f48aa9 on hardware on 2026-09-26: after drifting from 4-1.2 to 3-1.2, one section was left, migrate modem was in the log, and dialing worked again after a reboot. Could you merge it into main and backport it to stable?
    We build QModem from stable (3c44579, 2026-10-19). The branch is based on main at c49654e and doesn't apply to stable: git apply --3way gives five conflicts in modem_scand.c. All five are where stable added config_lock() / g.queue_lock / event_current() around the same section writes that the fix now does under uci_lock: in add_modem, the remove path and disable_slot. Merging the two locking schemes is better done by you than downstream.
    We can test a stable build with the fix on this Orange Pi Zero 3 and report back.

    中文简述:我们在 Orange Pi Zero 3(OpenWrt 25.12,多个 USB 模块)上遇到了同样的问题:每次重启 USB 总线编号都会变化,同一个 FM350 生成了 1_1_3、3_1_3、6_1_3 三个配置段;旧配置段保留的 AT 口在重新编号后属于另一个模块(T99),tom_modem 卡在 D 状态,残留的 v6 接口循环启动。#280 的修复已在硬件上确认有效,希望合并到 main 并移植到 stable。该分支基于 main(c49654e),在 stable(3c44579)上有 5 处冲突,都在加锁部分。我们可以在这块板子上测试 stable 版本。

  7. FUjr commented on Oct 22, 2026

    @FUjr
    Owner

    @Medvedolog @sassalana

    中文

    感谢补充多模组场景的反馈。我重新考虑了这个问题的处理边界:我倾向于认为 USB 总线编号在重启后变化是 board/platform 层面的问题;我不希望在 QModem 中引入额外的身份判定机制来合并不同 slot 的配置。 这还不是对具体板级根因的最终确认。不过,旧配置继续拨号、向已经属于另一模组的 AT 口发送命令,确实是 QModem 应该处理的生命周期问题。

    因此,我实现了一个新的方案,供大家测试:PR #288,分支 fix-modem-presence-280,提交 f644cfa。这次实现的目标是保证扫描与拨号的时序:

    • 启动和全量扫描时检查已有模组配置;确认设备路径、AT 口和网卡实际归属后,才允许创建拨号进程。不会直接信任上次启动留下的 state=enabled。
    • 拨号脚本在读取配置及发送 AT 命令前再次检查。旧 tty 被另一模组复用、或同一路径重新枚举后,旧的运行期确认会失效。
    • 掉线后立即撤销就绪状态,停用旧段、停止拨号进程并清理它拥有的网络接口。掉线清理不通过旧 AT 口发送挂断命令,失败会有限重试;旧扫描结果也不能重新放行已掉线的设备。
    • 即使设置 block_auto_probe=1,已有配置的存在性检查和掉线处理仍然执行;自动发现和配置探测仍被禁止。固定配置也需要通过存在性检查。

    与之前 #285 的方案不同,这次不会合并、迁移或自动删除历史模组配置,也不会把 APN 自动迁移到新 slot。 路径发生变化后,旧段应保留但停用;自动模式可以独立发现新 slot,手动模式需要修正配置后重新检查。验收重点是“失效段不运行、不误用其他模组的端口”,不是“UCI 中永远只有一个段”。

    宿主机编译和回归测试已通过,这一版尚未经过实机验证,之前对 8f48aa9 的硬件结果不能代替对本实现的验证。目前 PR 基于 main,尚未移植到 stable。

    方便的话,请在 Orange Pi Zero 3 多模组环境测试这一版,尤其是保留 block_auto_probe=1 后重启、USB 总线重新编号、旧 tty 被另一模组复用,以及拔插/重新枚举。请检查旧段是否变为 disabled、对应 procd 实例和残留 IPv4/IPv6 接口是否被清理,以及当前有效模组能否正常拨号。也欢迎复测 ECM/NCM 模式切换。

    English

    Thanks for the additional multi-modem report. After reconsidering the scope, I tend to view USB bus renumbering across reboots as a board/platform issue, and I do not want to introduce extra identity heuristics in QModem to merge configurations across slots. This is not a final diagnosis of the board-specific cause. However, allowing a stale configuration to keep dialing or send AT commands to a port now owned by another modem is a lifecycle problem QModem should address.

    I have implemented a new approach in PR #288, branch fix-modem-presence-280, commit f644cfa:

    • Validate saved configurations at startup and during full scans. Start dialing only after confirming the current device path, AT endpoint and data interface ownership; a persisted state=enabled is insufficient.
    • Recheck presence before reading dial configuration and sending AT commands. Port reuse and re-enumeration at the same path invalidate the old runtime confirmation.
    • Revoke readiness on removal, disable the old section, stop its dial processes and clean up its owned network interfaces. Offline cleanup does not send hangup commands through the stale AT port. Failed cleanup receives bounded retries, and stale scan events cannot re-enable the removed device.
    • Keep presence checks and removal handling active with block_auto_probe=1, while automatic discovery/configuration probing remains blocked. Fixed configurations also require presence validation.

    This approach does not merge, migrate or automatically delete historical modem sections, and does not transfer APN settings to a new slot. An old section may remain in UCI, but it should be disabled and inactive. Automatic mode can discover the new slot independently; manual mode requires correcting the configuration and checking it again. The acceptance criterion is that stale sections stop running and cannot use another modem's port, not that only one section remains.

    Host compilation and regression tests pass, but this implementation has not been tested on hardware. The earlier hardware results for 8f48aa9 do not validate this new approach. This PR targets main; a stable backport is not included yet.

    Could you test this on the Orange Pi Zero 3 multi-modem setup, particularly reboot/bus renumbering with block_auto_probe=1, tty reuse by another modem, and unplug/re-enumeration? Please check whether stale sections become disabled, their procd instances and leftover IPv4/IPv6 interfaces disappear, and correctly configured present modems can dial. ECM/NCM switching feedback is also welcome.

    测试分支 / Test branch

    请将现有 qmodem feed 切换到以下分支,然后同时编译、安装 qmodem 和 modem_scan,安装后重启路由器。仅更新扫描包不够。

    Change the existing qmodem feed entry to this branch, then build and install both qmodem and modem_scan, and reboot the router. Updating only the scanner package is insufficient.

    src-git qmodem https://github.com/FUjr/QModem.git;fix-modem-presence-280
    
    ./scripts/feeds update qmodem
    ./scripts/feeds install -a -p qmodem
    git -C feeds/qmodem log -1 --oneline
    make package/feeds/qmodem/qmodem/compile package/feeds/qmodem/modem_scan/compile V=s

    请反馈测试提交、场景和以下输出 / Please include the tested commit, scenario and these outputs:

    uci show qmodem | grep -E '=modem-device$|\.(path|at_port|state|enable_dial|block_auto_probe)='
    ubus call service list '{"name":"qmodem_network"}'
    ubus call network.interface dump
    logread | grep -E 'modem_scand|qmodem_network|modem_hotplug'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions