Skip to content

wwand: add cellular connection manager - #30185

Open
ddimension wants to merge 6 commits into
openwrt:masterfrom
ddimension:net-wwand
Open

wwand: add cellular connection manager#30185
ddimension wants to merge 6 commits into
openwrt:masterfrom
ddimension:net-wwand

Conversation

@ddimension

@ddimension ddimension commented Aug 7, 2026

Copy link
Copy Markdown

Adds wwand, an event-driven cellular connection manager written in ucode: native QMI, MBIM and NCM/AT control (no uqmi/qmicli/libqmi/glib), direct netifd integration (the daemon owns the context lifecycle — no per-interface monitor process; transient loss renews in place so IPv6-PD/VRF survive), multi-modem + multi-PDP-context via QMAP multiplexing, SIM/eSIM management (SGP.22 via lpac), SMS (send + receive), telemetry, a recovery ladder, board profiles and zero-config autosetup. A wwandctl CLI and a LuCI app (openwrt/luci#8917) sit on top.

Upstream repo: https://github.com/ddimension/wwand (GPL-2.0-only). Current release: v1.6.4 — the release this Makefile pins (4089 host-side checks run without hardware).

One source package, six binary packages:

  • wwand — backend-neutral base (daemon, codec, netifd proto shim, SIM/APDU layer, wwandctl CLI). It also ships the small native C transport module wwand_io.so (message-oriented cdc-wdm/tty I/O + rmnet netlink helper) — wwand-private and always version-locked to the ucode side, so it lives inside the base package (PROVIDES ucode-mod-wwand-io for older configs).
  • wwand-qmi / wwand-mbim / wwand-ncm — per-protocol control backends; install only what the modems need (wwand-qmi pulls in wwand; a typical QMI router needs just that).
  • wwand-mhi — PCIe/MHI transport bundle (MHI bus/PCI/control/data kmods + the kernel-wwan-subsystem hotplug) for modems whose control port appears under /sys/class/wwan instead of usbmisc. Backend-neutral: pair with wwand-qmi or wwand-mbim.
  • wwand-esim — optional SGP.22 profile management + SM-DP+ download (depends on lpac >= 2.3.0).

Since v1.6.0 the QMI mux datapath is an interface rather than a hard-coded branch: rmnet, qmimux and the MBIM session mux are entries in it, and wwand-qmi additionally carries two plug-ins for the out-of-tree vendor QMAP drivers (qmi_wwan_q, pcie_mhi). Neither driver exists in the kernel tree, so on an OpenWrt kernel both plug-ins are inert — their probe finds none of the children those drivers would have registered and declines, leaving the built-in datapaths in charge. 1.6.0 also fixes the QMAP data-aggregation constant: QMAPV5 was 8, which is libqmi's QMAPv4, so modems declined it and every QMI link silently fell back to plain QMAP.

Packaging. The ucode tree is flat; each package installs an explicit per-file list — no glob-then-rm, so every module is owned by exactly one package and a new backend file can never silently ship in the base too. The ucode tree ships as source. Bytecode precompilation is available via CONFIG_WWAND_UCODE_PRECOMPILE but stays opt-in: bytecode carries a format version (UCODE_BYTECODE_VERSION) that an interpreter upgraded past it refuses to load, and that version is independent of libucode's PKG_ABI_VERSION/SONAME, so no package relation expresses the coupling. It is only sound when ucode and wwand are built in the same tree — which a self-built image is and a feed is not.

Good-citizen coexistence (no stock stack replaced). The packages do not CONFLICTS uqmi/umbim/comgt-ncm — they install alongside them. The netifd shim registers proto wwand and nothing else: the qmi proto name stays uqmi's, so netifd's handler load order never decides who owns an interface, and there is no switch that changes this. wwand manages only proto wwand interfaces and never adopts a bare proto qmi/mbim/ncm one, so exactly one dialer owns a given interface and the control device behind it. Handing one over is always user-triggered and rewrites it in place to proto wwand: a "Migratable interfaces" list in the LuCI modem page, the migrate ubus method / CLI, or an example uci-defaults script shipped inert under /usr/share/wwand/examples/. Nothing is installed under /etc/uci-defaults, so installing or upgrading wwand cannot rewrite an existing configuration. Inclusion is additive and opt-in per interface, not a second implementation that displaces the existing handlers.

Hardware-tested on MikroTik Chateau 5G R17 ax (Quectel RG650E, 5G NSA), Zyxel NR7101 (RG502Q), Zyxel LTE3301-Plus (EG06) and Cudy LT300 v3 (MeiG SLM770A-R), plus a GL.iNet GL-X3000 (RM520N-GL); the PCIe/MHI path (wwand-mhi) is under active validation with community testers on Foxconn T99W175 hardware. Maintained and shipped from an external feed (github.com/ddimension/openwrt-repo) while it broadens coverage and gathers field reports.

🤖 Generated with Claude Code

@BKPepe BKPepe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. I can see the motivation behind having a lightweight, event-driven WWAN manager tightly integrated with netifd, and some of the functionality here is certainly interesting.

However, I don't think this is ready to be merged into the OpenWrt packages feed in its current form.

My main concern is the scope and the amount of functionality being reimplemented. This is not merely another frontend or connection manager using the existing OpenWrt WWAN stack. wwand implements QMI, MBIM and NCM/AT itself and the corresponding packages explicitly conflict with and replace uqmi, umbim and comgt-ncm.

That effectively introduces a second implementation of a significant part of the OpenWrt WWAN stack which we would then need to maintain and review in parallel with the existing implementations.

The scope is also very large for a newly introduced project: QMI, MBIM, NCM/AT, QMAP/multiple PDP contexts, SIM/APDU handling, eSIM, SMS, telemetry, recovery, board profiles, netifd integration and automatic migration of existing configurations are all being introduced at once.

Host-side tests are useful, but they cannot replace real-world modem interoperability testing for protocols such as QMI and MBIM. The PR currently mentions production testing on four devices/modems. Considering the number of modem vendors, firmware versions, protocol quirks and failure/recovery scenarios encountered in the OpenWrt ecosystem, I don't think this provides enough coverage yet to justify replacing the established handlers.

Another concern is project maturity. This is a relatively new implementation of protocol parsers and fairly complex asynchronous state machines, and a substantial part of the implementation was AI-generated. I don't consider the use of AI itself a reason to reject code, but for this kind of low-level protocol and state-machine implementation it makes independent review and real-world validation especially important. At the moment there does not appear to be enough independent review or deployment history to establish that confidence.

There is also a broader architectural question here.

Since this project is specifically designed around OpenWrt (ucode, uloop, ubus, UCI and netifd) and aims to replace several existing OpenWrt WWAN components, I think the architecture should first be discussed with the maintainers of the existing WWAN/netifd components. In particular, it should be considered whether the missing functionality could be implemented by improving the existing stack instead of introducing another complete QMI/MBIM/NCM implementation.

Features such as better recovery, persistent context handling, QMAP support or improved netifd integration may indeed solve real shortcomings. If so, contributing those improvements to the existing components could benefit all existing users without creating two competing OpenWrt-specific WWAN stacks.

I would therefore prefer to see wwand mature as an external feed first, gain broader hardware coverage and users, accumulate real-world bug reports and fixes, and receive independent review of the protocol/state-machine implementation.

Once that has happened, and if there is consensus that maintaining a separate WWAN implementation is preferable to improving the existing stack, inclusion in the official packages feed could be reconsidered.

So for now, I would be against merging this PR. This is not because the project has no value, but because replacing several established OpenWrt WWAN components with a young and very broad implementation creates a substantial long-term maintenance and review burden that I don't think has been justified yet.

@ddimension

ddimension commented Aug 7, 2026

Copy link
Copy Markdown
Author

Thanks for taking a deep look. This code is based on my personal QMI dial-in handler which I developed since 2014. All of my knowledge about quirks with modems is in this project.

I can understand you to not support inclusion, but is not the package feed exactly for this? Optional packages, which the user selects if he want's it. The user may use old style stack with all of it's stability problems or may use wwand instead.

So this is not about replacing, it is about giving a stable alternative with features which are needed in the field (plmn lock i.e.), that nothing else provides.
I'm also willing to provide support in future, also my company (M2M focused) stands behind this.

André

@4920441

4920441 commented Aug 7, 2026

Copy link
Copy Markdown

Since this project is specifically designed around OpenWrt (ucode, uloop, ubus, UCI and netifd) and aims to replace several
existing OpenWrt WWAN components, I think the architecture should first be discussed with the maintainers of the existing
WWAN/netifd components. In particular, it should be considered whether the missing functionality could be implemented by
improving the existing stack instead of introducing another complete QMI/MBIM/NCM implementation.

Shouldn't that only be a showstopper if wwand is set to the default install for wwan interfaces? Since there are already so much packages for manageing WWAN stuff, why is this section important for adding another package? The options you get with wwand are mostly missing on ALL other packages...

Cheers,

4920441

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Packaging-level review of net/wwand/Makefile only — the inclusion/scope discussion in the existing review is a maintainer call and I'm not restating it.

Nothing here blocks a merge on its own. The two worth acting on regardless of how the scope question lands are the unresolvable CONFLICTS entry and the glob-then-rm split in Package/wwand/install, which can silently produce two packages owning the same path. The rest are small.

Metadata otherwise checks out: PKG_RELEASE:=1 is correct for a new package, PKG_MAINTAINER is set, the define blocks follow the 2-spaces-for-metadata / tabs-for-recipes convention, all ucode-mod-* and kmod-* dependencies resolve against openwrt main, lpac in this feed is at 2.3.0 so the >= 2.3.0 note holds, and the codeload.github.com/.../refs/tags/ source URL matches what 243 other Makefiles in this feed do. I could not verify PKG_HASH or the v1.0.0 tag — this session's GitHub access is scoped to openwrt/packages.


Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile
Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile Outdated
@ddimension

ddimension commented Aug 8, 2026

Copy link
Copy Markdown
Author

Thanks for the very thorough and fair review — the scope and maintenance-burden concerns are legitimate, and I've reworked the most load-bearing part in response.

The biggest change: wwand no longer replaces the stock WWAN stack. I've removed all CONFLICTS (uqmi/umbim/comgt-ncm) — the packages now install alongside them. By default wwand is a good citizen:

  • it manages only proto wwand interfaces and does not touch existing proto qmi/mbim/ncm interfaces;
  • adopting the stock stack (registering the qmi proto alias, managing bare proto qmi, auto-migrating on upgrade) is gated behind a single global option takeover, default off;
  • moving one specific interface to wwand is user-triggered (a "Migratable interfaces" list in the LuCI modem page, which converts it in place to proto wwand).

So it's no longer "a second implementation that replaces the existing handlers" — it's additive and opt-in per interface. That directly targets the "two competing OpenWrt-specific WWAN stacks" and "replacing established handlers" concerns: nothing is replaced unless the operator explicitly opts in, and the stock stack keeps owning proto qmi/mbim/ncm otherwise. I also dropped the LuCI qmi.js alias for the same reason (it collided with luci-proto-qmi), and fixed the packaging nits from the bot review (+ucode not +libucode, SUBMENU:=WWAN on wwand-esim, $(CMAKE_BINARY_DIR), the dead conflict entry).

On maturity and independent review — I fully agree these matter for low-level protocol/state-machine code. It's being maintained and shipped from an external feed (github.com/ddimension/openwrt-repo), runs on production hardware here (QMI/MBIM/NCM across several modems), and I'm actively hardening it. I'd like to keep improving it in the open rather than sit on it.

Given the coexistence rework removes the "replaces the existing stack" objection, would you be open to leaving this open for another ~2 weeks while I continue to mature it — broaden hardware coverage, gather field bug reports, and address review feedback? I'll keep the PR updated regularly as that happens. If after that you still feel the scope is too broad for the feed, I completely understand keeping it external for now.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of the one new commit since my last pass (d802b81, "wwand: 1.1.0 — coexist with the stock WWAN stack"). Packaging-level only; the inclusion/scope discussion is a maintainer call and I'm not restating it.

The three packaging points from the previous round are all addressed: ucode-mod-wwand-io now depends on +ucode, wwand-esim gained SUBMENU:=WWAN, and the install step uses $(CMAKE_BINARY_DIR) — which expands to $(PKG_BUILD_DIR)/build given CMAKE_BINARY_SUBDIR:=build, so the path is unchanged and now tracks L29. The dead qmi-advanced CONFLICTS entry went away with the rest of the CONFLICTS lines. The version bump keeps PKG_RELEASE:=1, which is correct for a PKG_VERSION change. Commit message matches the diff.

Nothing new blocks a merge. The one worth an answer before this lands is device ownership under the new coexistence model: CONFLICTS is what previously guaranteed only one stack could touch a given /dev/cdc-wdmX, and the replacement guarantee is a runtime property of the daemon that the packaging can't show. The takeover / proto qmi alias question is the same theme from the netifd side. The other two are nits.

Two earlier threads are still open and I haven't repeated them: the glob-then-rm split in Package/wwand/install, and the missing test-version.sh for the generic CI version check. Only the FormalityCheck jobs have reported on this head (all green), so the build/test CI hasn't exercised the latter yet.

I still can't verify PKG_HASH or the v1.1.0 tag — this session's GitHub access is scoped to openwrt/packages, so ddimension/wwand is unreachable to both the API and a plain fetch. Treat those as unchecked rather than checked-and-fine.


Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile
Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile Outdated
ddimension pushed a commit to ddimension/wwand that referenced this pull request Aug 9, 2026
Package-G artefacts for the openwrt/packages#30185 + openwrt/luci#8917 push:
- upstream/dossier-packages-30185.md — maturity/coexistence dossier to post as a
  PR comment (ModemManager precedent, independent-verification story, HW/test
  matrix, audit changelog, device-ownership answer, re-review request).
- upstream/rfc-openwrt-devel.md — the architecture RFC (improve-existing-stack
  vs. a separate opt-in proto) for openwrt-devel.
- upstream/checklist.md — the push/tag/PR/feed action sequence.

Drafts for author review; sending/posting is manual.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ddimension

Copy link
Copy Markdown
Author

Updated to wwand 1.2.0 (tag v1.2.0, PKG_HASH refreshed; the base package now also installs /usr/bin/wwandctl).

Since 1.1.0:

  • modem_reattach (network re-registration without a modem reset), the wwandctl CLI, end-to-end PUK entry, SMS send, SIM slots on MBIM, PCIe/MHI (kernel wwan subsystem) discovery, stable L3 device names, FCC RF unlock, eSIM switch via lpac.
  • QMI/MBIM/NCM backend parity: unified telemetry, PLMN/FPLMN lists, recovery ladder, live IP-settings refresh, last_error.
  • Correctness: LTE attach-APN programmed before registration; registration reject causes surfaced; native-module hardening (OOB netlink read, missed-ACK-as-success, spawn exit-status race).
  • A five-round maintainability audit: module decomposition, CI (host suite + shellcheck), ~1050 host-side checks green.

LuCI side is updated in openwrt/luci#8917.

@ddimension
ddimension requested a review from BKPepe August 14, 2026 04:18

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of the one new commit since my last pass (345c8b1, "wwand: 1.2.0"). Packaging-level only; the inclusion/scope discussion in the maintainer review above is a maintainer call and I'm not restating it.

The bump itself is clean: PKG_RELEASE stays at 1, which is correct for a PKG_VERSION change, and the new /usr/bin/wwandctl install is properly paired with a wwandctl.uc entry in the base package's strip list, so it doesn't also leak into $(UCDIR). The commit message matches the diff. I confirmed the v1.2.0 tag exists in ddimension/wwand (resolves to commit 1d75ae8); PKG_HASH I still can't verify — codeload.github.com is not reachable from this session — so treat that one as unchecked rather than checked-and-fine.

One finding is worth acting on before merge: 1.2.0 also adds files/wwand.hotplug.wwan, a fourth hotplug script that this Makefile never installs, which leaves the "PCIe/MHI (kernel wwan subsystem) discovery" listed in the commit message working only for modems already present when the daemon starts. The other two comments are nits.

Earlier threads are still open and I haven't repeated them: the glob-then-rm split in Package/wwand/install, the missing test-version.sh (one new comment does extend that one, since 1.2.0 adds a second executable that definitely fails the generic check), the proto qmi alias ownership question under takeover, the cdc-wdm device-ownership question, and the PR body still describing the pre-1.1.0 CONFLICTS / auto-migrate model. Only the three FormalityCheck jobs have reported on this head, all green, so the build/test CI still hasn't exercised any of this.


Generated by Claude Code

Comment thread net/wwand/Makefile
Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile Outdated

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of the one new commit since my last pass. 345c8b1 was amended into fc0388e (same subject, wwand: 1.2.0); the only delta against what I reviewed last time is the four-line wwan hotplug hunk in Package/wwand/install. Packaging-level only; the inclusion/scope discussion in the maintainer review above is a maintainer call and I'm not restating it.

That hunk resolves the one finding I flagged as worth acting on last round: files/wwand.hotplug.wwan is now installed to /etc/hotplug.d/wwan/20-wwand, and the paired $(INSTALL_DIR) is what arms the dispatch — procd only calls hotplug-call for a subsystem whose directory exists (hotplug.json:83-86). INSTALL_DATA matches the three sibling hotplug installs above it and the in-tree precedent for this same subsystem (modemmanager Makefile:158-160), and the filename doesn't collide with modemmanager's 25-modemmanager-wwan, so both can be installed. Commit message matches the diff, PKG_RELEASE stays at 1, which is correct for the PKG_VERSION change.

Nothing new to flag on this head. Earlier threads are still open and I haven't repeated them: the glob-then-rm split in Package/wwand/install, the missing test-version.sh (three installed executables now), the proto qmi alias ownership question under takeover, the cdc-wdm device-ownership question, the MHI kmod hint in Package/wwand-qmi/description, the bare wwand: 1.2.0 commit subject, and the PR body still describing the pre-1.1.0 CONFLICTS / auto-migrate model.

Two things I could verify last round but cannot on this one: PKG_HASH and the v1.2.0 tag. This session's GitHub access is scoped to openwrt/packages, and codeload.github.com is unreachable, so ddimension/wwand is out of reach to both the API and a plain fetch. PKG_HASH is unchanged by this amend, so nothing new rests on it — but treat it as unchecked here rather than checked-and-fine.

Only the three FormalityCheck jobs have reported on this head, all green, so the build/test CI still hasn't exercised any of this.


Generated by Claude Code

@ddimension

Copy link
Copy Markdown
Author

Pushed a squashed head (8ffb9e3) that folds the 1.1.0/1.2.0 bumps back into the single wwand: add cellular connection manager commit, plus:

  • net/wwand/test-version.sh — the three installed executables (wwand, wwandctl, migrate) don't print PKG_VERSION, so all six packages opt out of the generic runtime version check (no grep -q, per the feed convention).
  • MHI kmodsPackage/wwand-qmi/description now points PCIe/MHI users at kmod-mhi-wwan-ctrl (+ kmod-mhi-net / kmod-mhi-pci-generic); no hard dep, since most users are on USB.

Answering the two open questions, since they're the ones that can't be read off the packaging:

proto qmi ownership under takeover. netifd sources /lib/netifd/proto/*.sh in sorted glob order, and wwand.sh sorts after qmi.sh, so when option takeover '1' makes both call add_protocol qmi, wwand's handler registers last and deterministically owns proto qmi. With takeover off (default) wwand.sh never emits add_protocol qmi at all, so uqmi keeps it — that's the intended coexistence. takeover is meant for a box being switched to wwand.

cdc-wdm device ownership. wwand opens a control device only when a wwand_modem section references it (then start_modem runs) or zero-config autosetup creates one. A device that no wwand config references is never opened — no MBIM OPEN, no QMI client, nothing. Autosetup only fires on an unconfigured box, and I just tightened its occupancy gate (ddimension/wwand@abeb0bd) so an existing proto mbim/ncm interface counts as "configured" too (it previously keyed off proto wwand/qmi + a wwan0 section, which caught the common case by interface name but not a stock umbim/comgt-ncm interface under another name). So with umbim/uqmi/comgt-ncm owning a cdc-wdm for their own interface, wwand leaves it untouched until that interface is explicitly migrated to proto wwand. That fix will ride the next point release the PKG pin tracks; happy to bump the pin here once tagged if you'd prefer it in-tree first.

glob-then-rm in Package/wwand/install. Agreed this is the least tidy part. Explicit enumeration was the first thing I tried, but the base package is ~54 .uc files (38 in src-ucode/, 16 under codec/), so listing them just moves the hand-synced list to the other side — a new base file would then be the thing silently dropped. The clean fix is the one you suggested: lay src-ucode/ out in per-backend subdirectories so each package globs its own directory and the base can't leak a backend file. That's an upstream reorg (it touches every import path), so I've queued it rather than trade one sync hazard for another; the backend packages already enumerate explicitly, so the split fails loudly at install (duplicate path) rather than shipping wrong-but-working.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review against the new head. The branch was squashed since my last pass — the four commits I had reviewed (fc0388e and its ancestors) are now the single commit 8ffb9e3, "wwand: add cellular connection manager". Diffing fc0388e..8ffb9e3 on net/wwand/, the only content delta is two things, both closing threads from earlier rounds:

  • net/wwand/test-version.sh (new) — opts all six binary packages out of the generic version check. It follows the in-tree $PKG_NAME case/*)-fallback shape (e.g. libs/expat/test-version.sh), has no grep -q, and lists every package the Makefile builds, so the *) branch can't fire.
  • Package/wwand-qmi/description (L130-134) — the MHI kmod hint. All three names check out against openwrt main: kmod-mhi-wwan-ctrl, kmod-mhi-net, kmod-mhi-pci-generic.

The squash also resolved the bare-wwand: 1.2.0 subject nit on its own. The single commit's message matches its diff, and PKG_RELEASE:=1 is correct for a new package. Nothing new blocks a merge; the one comment below is a nit.

Worth noting because it changes what is actually verified: the full build CI has now run on this head and is green on all ten architectures, so test-version.sh is confirmed working rather than assumed — the x86_64 runtime job logs wwand-qmi: Version test override script found and [pass] Version check override for each package, then All tests passed. (The * Failed to connect to ubus lines around the wwand post-install/pre-deinstall in that log are just default_postinst's "$i" start on a procd init script in a container with no ubus — not a defect here.) lpac in this feed is still at 2.3.0, so the >= 2.3.0 note in Package/wwand-esim/description continues to hold.

Earlier threads are still open and I'm not repeating them: the glob-then-rm split in Package/wwand/install, the proto qmi alias ownership question under takeover, the cdc-wdm device-ownership question, the qmi-advanced mention that survives in the L121 prose, the ucode-mod-io reuse question, and the PR body still describing the pre-1.1.0 CONFLICTS / auto-migrate model. The scope and inclusion discussion in the maintainer review above is a maintainer call and I'm not restating it.

PKG_HASH and the v1.2.0 tag I still cannot check — this session's GitHub access is scoped to openwrt/packages, so ddimension/wwand is unreachable to both the API and a plain fetch. Neither changed in this delta, but treat them as unchecked rather than checked-and-fine.


Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
@ddimension

ddimension commented Aug 18, 2026

Copy link
Copy Markdown
Author

Updated to wwand 1.3.0 (tag v1.3.0, PKG_HASH refreshed), which resolves the open packaging threads — most of them by the source-tree reorg that was queued last round:

  • glob-then-rm in Package/wwand/install → gone. src-ucode/ is now laid out so each package installs an explicit per-file list (WWAND_BASE_UC / _CODEC / _SCHEMA for the base; the backends enumerate their own modules). Every module is owned by exactly one package, so a new backend file can never silently land in the base. This is the reorg suggested in that thread.
  • A second native I/O module vs. the stock ucode-mod-io. wwand_io.so is message-framed cdc-wdm/tty transport plus an rmnet/QMAP netlink helper — not the byte-stream file I/O the stock module offers — so it can't be replaced by it. To stop it looking like a general-purpose module, it's no longer a separate package: it ships inside the wwand base (wwand-private, version-locked to the ucode side), with PROVIDES:=ucode-mod-wwand-io so older configs keep resolving.
  • PCIe/MHI drivers. New wwand-mhi package carries the MHI bus/PCI/control/data kmods as DEPENDS and ships the kernel-wwan-subsystem hotplug (/etc/hotplug.d/wwan/20-wwand) — the fourth hotplug script that the base install was missing. It is transport-only/backend-neutral; pair it with wwand-qmi or wwand-mbim. The USB backends keep their USB-only kmod deps.
  • wwand-esim SUBMENU:=WWAN added, so it no longer lands directly under Network.
  • removed a leftover internal project-name reference from the description and PR text (it was never a package).
  • Coexistence vs. device ownership. The base hotplug opens a control device only when a wwand_modem section references it (or zero-config autosetup creates one on an otherwise-unconfigured box); a device owned by umbim/uqmi/comgt-ncm for their own interface is left untouched until that interface is explicitly migrated to proto wwand.
  • test-version.sh covers the new package set (the three installed executables — wwand, wwandctl, migrate — don't print PKG_VERSION).

New in 1.3.0 as well: the ucode tree ships precompiled to bytecode by default (repo-root CMakeLists, built next to wwand_io.so), with a configure-time capability probe that falls back to shipping source when the host ucode can't emit bytecode — so the build never fails on an older toolchain; CONFIG_WWAND_UCODE_SOURCE forces source.

On the broader architecture question: I'd still welcome a discussion with the WWAN/netifd maintainers. wwand is deliberately additive here (opt-in per interface, nothing replaced by default), and I'm happy to feed back any of the recovery / persistent-context / QMAP / netifd-integration work into the existing stack where that's the better home.

@liaohongxing

Copy link
Copy Markdown

I very much welcome and look forward to this component, because the existing proto_qmi, proto_mbim, and proto_ncm only implement basic connection functionality, lacking a GUI interface and advanced features such as band locking, SMS reading, signal strength, etc. This component can provide unified management and reduce the learning cost for users. As for the possibility that the author might stop maintaining it in the future, we can simply remove this package then.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review against the new head. The branch was squashed again — 8ffb9e3 is now the single commit 8e33265 with the same subject, so I diffed 8ffb9e3..8e33265. The delta is the 1.3.0 bump plus four structural changes: the ucode tree is now precompiled to bytecode by a repo-root cmake build (PKG_BUILD_DEPENDS:=ucode/host, UCODE_COMPILER/UCODE_PRECOMPILE, the new CONFIG_WWAND_UCODE_SOURCE opt-out), the base install switched from glob-then-rm to explicit WWAND_BASE_UC/_CODEC/_SCHEMA lists, ucode-mod-wwand-io was folded into the base package (PROVIDES:=ucode-mod-wwand-io) and replaced in the package set by the new wwand-mhi transport bundle, which is also where the wwan hotplug now lives. Packaging-level only; the inclusion/scope discussion in the maintainer review above is a maintainer call and I'm not restating it.

Three earlier threads close with this head, and the replacements check out: the base package no longer installs anything a backend owns; wwand-mhi's DEPENDS names four kmods that all exist in openwrt main, including kmod-mhi-wwan-mbim, which answers the MBIM-over-MHI question I raised last round; and test-version.sh was updated in step with the package set (wwand-mhi in, ucode-mod-wwand-io out), so the *) fallback still cannot fire. The single commit's message matches its diff and PKG_RELEASE:=1 is correct for a new package, so no commit checks.

What is new is that the default build path changed shape. Three of the comments below are questions about that path — bytecode/interpreter skew, whether the SDK's host ucode can compile modules that import ubus/uci/uloop/rtnl, and whether a precompiled main.uc is still directly executable as /usr/sbin/wwand. None is a defect I can demonstrate from the packaging alone, and each has a one-line answer if the upstream build already handles it; I raise them because bytecode is the default while every build and runtime test this PR has accumulated so far exercised the source path, and only the three FormalityCheck jobs have reported on this head. The other two comments are nits.

Earlier threads I'm not repeating: the proto qmi alias ownership under takeover and the cdc-wdm device-ownership question (both answered in the PR conversation but the threads are still open), and the PR body still describing the pre-1.1.0 CONFLICTS / auto-migrate model.

PKG_HASH and the v1.3.0 tag remain unchecked — this session's GitHub access is scoped to openwrt/packages, so ddimension/wwand is unreachable to both the API and a plain fetch. Treat them as unverified rather than verified-fine.


Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile
Comment thread net/wwand/Makefile
Comment thread net/wwand/Makefile Outdated
Comment thread net/wwand/Makefile
wwand is an event-driven cellular connection manager written in ucode. It
drives netifd over ubus with no_proto_task, so the daemon owns the modem and
context lifecycle while netifd keeps ownership of all addressing and routing.

Six packages: a backend-neutral base (daemon, netifd shim, codec, the native
wwand_io.so) plus wwand-qmi, wwand-mbim, wwand-ncm, wwand-mhi and wwand-esim.
A backend is loaded lazily, so a missing backend package surfaces as a status
note instead of a failure.

It coexists with the stock stack rather than replacing it. There is no
CONFLICTS on uqmi/umbim/comgt-ncm, and the shim registers `proto wwand` and
nothing else — the `qmi` proto name stays uqmi's, so netifd's handler load
order never decides who owns an interface. Handing one over is always an
explicit act that rewrites it in place to `proto wwand`: the LuCI modem list,
/usr/libexec/wwand/migrate, or the example uci-defaults script shipped inert
under /usr/share/wwand/examples/. Nothing is installed under /etc/uci-defaults,
so installing or upgrading cannot rewrite an existing configuration.

The ucode tree ships as source. Bytecode precompilation is available via
CONFIG_WWAND_UCODE_PRECOMPILE but stays opt-in: bytecode carries a format
version (UCODE_BYTECODE_VERSION) that an interpreter upgraded past it refuses
to load, and that version is independent of libucode's PKG_ABI_VERSION/SONAME,
so no package relation expresses the coupling. It is only sound when ucode and
wwand are built in the same tree, which a self-built image is and a feed is not.

Signed-off-by: André Valentin <avalentin@marcant.net>
ddimension pushed a commit to ddimension/luci that referenced this pull request Aug 30, 2026
Netifd protocol handler for `proto wwand`, the cellular connection manager
proposed in openwrt/packages#30185. It renders the connection options the
daemon consumes — APN, PDP type, authentication, MUX id, MTU handling — and
resolves the modem an interface is bound to.

wwand registers `proto wwand` only; the historical `qmi` proto name stays
uqmi's, so this handler never competes with the stock one for an interface.

Signed-off-by: André Valentin <avalentin@marcant.net>
ddimension pushed a commit to ddimension/luci that referenced this pull request Aug 30, 2026
Status and management UI for the wwand cellular connection manager proposed in
openwrt/packages#30185: modem overview, per-modem tools (radio technologies,
band selection, network selection and scan, cell lock), SIM and eSIM profile
management, SMS, and the per-interface migration entry point that converts a
stock cellular interface to `proto wwand` in place.

Everything is driven over the daemon's ubus API; the ACL file lists exactly the
methods the pages call.

Signed-off-by: André Valentin <avalentin@marcant.net>

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 1 new commit; one question below.

The branch was squashed again — my last pass was 881679d (v1.5.2) and the delta is the single commit 6f5d357, same subject. Diffing 881679d..6f5d357 on net/wwand/, the whole change is the 1.5.2 → 1.6.0 bump (PKG_VERSION, PKG_HASH), the datapath_qmi.ucmodem_datapath_qmi.uc rename in WWAND_BASE_UC, two new wwand-qmi install entries, USB_SUPPORT-conditional driver dependencies on all three backends (+kmod-usb-net-rndis added to wwand-ncm), and a rewritten paragraph in Package/wwand-mhi/description. PKG_RELEASE:=1 is correct for a new package and the commit message matches its diff, so no commit checks. Packaging-level only; the scope and inclusion discussion in the maintainer review above is a maintainer call and I'm not restating it.

Nothing here blocks a merge. The one comment below is a question about whether wwand-ncm belonged in the USB_SUPPORT sweep, since it is the one backend with no non-USB transport.

Verified against the release this pins. github.com/ddimension/wwand is reachable over plain git from this session, so this is a check against the tree rather than an inference. Tag v1.6.0 exists (annotated 11ed391 → commit efbc360), and against it:

  • Module ownership is exact. All 84 .uc files in src-ucode/ are installed by exactly one package — no orphans, no duplicates, and nothing the Makefile names is missing from the release. v1.5.2..v1.6.0 changes exactly three packaged files (datapath_qmi.uc removed, modem_datapath_qmi.uc + datapath_rmnet_nss.uc + datapath_rmnet_nss_mhi.uc added) and the install lists moved with all three. That is the failure mode the explicit-per-file lists exist to expose, and this is the second bump in a row where it was caught rather than missed.
  • The rename is load-bearing, not cosmetic. daemon.uc globs $(UCDIR)/datapath_*.uc and require()s each match, so datapath_<name>.uc is the add-on namespace; keeping the old datapath_qmi.uc in the base list would have registered the QMI bring-up module as a selectable mux plug-in. The base list follows upstream's rename correctly, and the plug-in name is regex-restricted (/^[a-z][a-z0-9_]*$/) before it reaches require().
  • The two new plug-ins are genuinely inert on a stock kernel, as the install comment claims — datapath_rmnet_nss.uc probes on qmap_mode sitting directly on the netdev, which only the vendor qmi_wwan_q attribute group (no .name, hence no qmi/ subgroup) produces; mainline qmi_wwan has no such node. Shipping them in wwand-qmi rather than in packages of their own matches how the daemon finds them.
  • No new dependency is owed. The tree's native imports are still fs, struct, ubus, uci, uloop, rtnl and wwand_io — all covered by the base package's DEPENDS. All eight $(PKG_BUILD_DIR)/files/... paths resolve, including files/examples/99-wwand-migrate (#!/bin/sh); files/wwand-proto.sh contains a single add_protocol wwand and no takeover, matching the commit message; main.uc and wwandctl.uc still start with #!/usr/bin/env ucode, so the source-default path installs them directly executable.
  • The +SYMBOL:pkg dependency form is right and has in-tree precedent in this feed — bluez uses +USB_SUPPORT:kmod-bluetooth. kmod-usb-net-rndis exists in openwrt main (usb.mk:1541), and kmod-rmnet carries no dependency of its own, so leaving it unconditional costs a non-USB target nothing.
  • test-version.sh is unchanged and still names all six packages, so the *) branch cannot fire; lpac in this feed is still 2.3.0, so the &gt;= 2.3.0 note in Package/wwand-esim/description continues to hold; the PR body says "Current release: v1.6.0 — the release this Makefile pins", which matches L27.

What I could not verify. PKG_HASHcodeload.github.com and github.com/.../archive/... both answer this session with an access-denied JSON body rather than a tarball, even though the git endpoint for the same repo is reachable, so the archive bytes are out of reach. Treat it as unverified rather than verified-fine.

Only the three FormalityCheck jobs have reported on this head, all green. The full build/runtime CI has not run since 8ffb9e3 (the 1.3.0 head), so the current default build path — ucode source, precompile off, no host ucode staged — and the current install lists remain unexercised by this repo's CI.

Earlier threads still open and not repeated here: the cdc-wdm device-ownership question, the ucode-mod-io reuse question, the deferred backend/transport split, and — for the opt-in precompile path only — the host-ucode capability and bytecode/interpreter-skew questions.


Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
Comment on lines +284 to +285
DEPENDS:=+wwand +USB_SUPPORT:kmod-usb-net-cdc-ncm \
+USB_SUPPORT:kmod-usb-net-cdc-ether +USB_SUPPORT:kmod-usb-net-rndis

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was wwand-ncm meant to be part of the USB_SUPPORT sweep? Unlike wwand-qmi (which keeps +kmod-rmnet unconditional and reaches a modem over MHI) and wwand-mbim (kmod-mhi-wwan-mbim via wwand-mhi), this backend has no non-USB transport at all: context_ncm.uc drives a single cdc_ncm/cdc_ether netdev and the only variant it recognises is rndis_host (self.modem.datapath?.backend != 'rndis_host'), and you noted yourself on the earlier thread that there is no cdc_ncm/cdc_ether/rndis_host netdev on the MHI bus — wwand-mhi's datapath kmods are kmod-mhi-net and kmod-mhi-wwan-mbim.

So the gate that used to come free with the hard +kmod-usb-net-cdc-ncm is gone: on a !USB_SUPPORT target this package was previously unselectable, and is now selectable while pulling no datapath driver whatsoever. Package/wwand-mhi/description L332-335 states the intent as "on a PCIe-only target the backends are selectable and pull no USB stack", which is the desired outcome for QMI/MBIM but means installable-and-inert for NCM.

Keeping the three NCM kmods unconditional restores the gate and changes nothing on a USB target:

Suggested change
DEPENDS:=+wwand +USB_SUPPORT:kmod-usb-net-cdc-ncm \
+USB_SUPPORT:kmod-usb-net-cdc-ether +USB_SUPPORT:kmod-usb-net-rndis
DEPENDS:=+wwand +kmod-usb-net-cdc-ncm +kmod-usb-net-cdc-ether \
+kmod-usb-net-rndis

(@USB_SUPPORT on the package would express the same thing more explicitly, if you prefer that shape.) Unrelated to the gating question: kmod-usb-net-rndis already pulls kmod-usb-net-cdc-ether itself — usb.mk:1541-1547 — so the middle entry is redundant either way, and listing it explicitly is fine.


Generated by Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, and thank you for catching it — wwand-ncm should not have been in that sweep.

The sweep holds for the other two because each has a non-USB transport behind it. wwand-qmi keeps +kmod-rmnet unconditional and reaches a modem over MHI; wwand-mbim gets kmod-mhi-wwan-mbim through wwand-mhi. On a PCIe-only target both stay selectable and functional, which is what Package/wwand-mhi/description promises.

NCM has no such path, exactly as you describe. The backend drives a single cdc_ncm/cdc_ether netdev and the only variant it recognises is rndis_host (context_ncm.uc, modem_ncm.uc); there is no MHI NCM netdev, and wwand-mhi ships kmod-mhi-net and kmod-mhi-wwan-mbim, neither of which NCM can drive. So gating the three kmods on USB_SUPPORT removed the implicit gate the hard dependency used to provide: on a !USB_SUPPORT target the package went from unselectable to selectable-while-pulling-no-datapath-driver — installable and inert, as you put it.

Reverted to unconditional, with a comment at the site recording why NCM is the exception rather than an oversight, so a later sweep does not re-do it. Unselectable on a target that cannot run it is the honest result.

Review point on the USB_SUPPORT sweep, and it is right. wwand-qmi and
wwand-mbim can afford a conditional USB kmod because each has a non-USB
transport behind it: QMI keeps +kmod-rmnet unconditional and reaches a modem
over MHI, MBIM gets kmod-mhi-wwan-mbim through wwand-mhi. So on a PCIe-only
target those two are selectable AND functional, which was the point of the
sweep.

NCM has no such path. The backend drives a single cdc_ncm/cdc_ether netdev and
the only variant it recognises is rndis_host (context_ncm.uc) — all USB. Gating
its three kmods on USB_SUPPORT therefore removed the implicit gate that the hard
dependency used to provide: on a !USB_SUPPORT target the package went from
unselectable to selectable-while-pulling-no-datapath-driver, i.e. installable
and inert.

Reverting these three to unconditional restores that gate. Unselectable on a
target that cannot run it is the honest result.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Signed-off-by: André Valentin <avalentin@marcant.net>
Correctness work since 1.6.0, most of it found in review:

- A destroyed QMI client now refuses further requests and detaches from the hub
  before running its cancellation callbacks. A callback that reads an error as
  "carry on" used to issue its next request from inside that loop: the frame
  went out, a timeout timer was armed, and the pending entry it created was
  wiped by the very loop that had called it — so the reply could never be
  dispatched while the timer still charged a protocol timeout to the recovery
  counter, for a client that no longer existed.
- The QMUX decoder is bounded by the frame its header declares rather than by
  however many bytes the read returned, so a message length claiming more than
  the frame can no longer take its TLVs from whatever followed it.
- SMS: a truncated PDU is refused instead of decoding into a plausible message
  with a sender built from zero bytes; UCS2 and 8-bit honour the declared
  user-data length; multipart reassembly keys on sender and store, so two
  senders sharing a concatenation reference no longer merge into one message.
- A modem bound by `option serial` or `option imei` is no longer dropped at
  parse time, and invalid modems are removed before their interfaces are
  validated against them.
- Datapath setup fails when a requested mux channel was not created, instead of
  reporting success and leaving the control backend to dial into a netifd
  device that does not exist.
- A GPIO write that fails is reported as a failure, so the recovery ladder
  falls through to the next rung instead of consuming a hardware rung that
  touched no hardware.
- A hub port and the modem behind it are no longer treated as the same device,
  which had let a foreign claim on either blocklist the other.

New in this release: carrier configuration over QMI PDC, distinct attach-bearer
credentials, `option lowpower` with a parked lifecycle the registration
supervisor knows about, `option gnss` plus the modem's NMEA port reported over
ubus for gpsd to be pointed at, and a startup banner naming the build, the
installed backends and the available datapaths.

The five modules new since 1.6.0 (carrier_config, version, and the CAT, PDC and
TMD schemas) are added to the install lists in the same commit — the file lists
and the version have to move together, since none of them exist in the 1.6.0
tarball.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Signed-off-by: André Valentin <avalentin@marcant.net>

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of the two new commits since my last pass (6f5d357..a81b1d8). The branch was not squashed this time. The whole delta is 20 lines in net/wwand/Makefile: f503296 reverts wwand-ncm's three USB kmods to unconditional, and a81b1d8 bumps 1.6.0 → 1.6.1 and adds the five new modules to the install lists. PKG_RELEASE:=1 is correct for a new package. Both commit messages match their diffs, so no commit checks. Packaging-level only; the scope and inclusion discussion in the maintainer review above is a maintainer call and I'm not restating it.

Nothing here blocks a build. The first comment below is a packaging gap worth closing before merge; the second is a nit that f503296 created.

f503296 is right, and the reasoning checks out against the tree. wwand-ncm really is the one backend with no non-USB transport: neither modem_ncm.uc nor context_ncm.uc has any MHI or /sys/class/wwan path, and the only variants the backend recognises are cdc_ncm / cdc_ether / rndis_host. So gating those three on USB_SUPPORT did turn an unselectable package into a selectable-but-inert one on a !USB_SUPPORT target, which is what the comment says. wwand-qmi (+kmod-rmnet unconditional, MHI transport) and wwand-mbim (kmod-mhi-wwan-mbim via wwand-mhi) keep their conditional form correctly — that asymmetry is now spelled out at L286-296.

Verified against the release this pins. github.com/ddimension/wwand is reachable over plain git from this session. Tag v1.6.1 exists (68a3f84), and against that tree:

  • Module ownership is exact. All 89 .uc files in src-ucode/ are installed by exactly one package — no orphans, no duplicates, and nothing the Makefile names is missing from the release. v1.6.0..v1.6.1 adds exactly five packaged modules (carrier_config.uc, version.uc, codec/schema/{cat,pdc,tmd}.uc) and removes/renames none; the install lists moved with all five, which is what the commit message claims. Running upstream's own tools/check-packaging.py --makefile against this head agrees: "owns every .uc exactly once".
  • No new dependency is owed. The tree's native imports are still fs, struct, ubus, uci, uloop, rtnl (via require() in netlink.uc) and wwand_io — all covered by the base package's DEPENDS. version.uc reads the apk/opkg package database at runtime and needs no build-time generated constant, so nothing new is owed on the Makefile side either. The only system() calls are date -u -s and the netlink helper's own argv; no new external binary is spawned, so the gnss work adds no gpsd relation.
  • The AT-over-MBIM lazy load is still guarded, which matters more now that carrier_config.uc and friends widened modem_common.uc: atcmd_mbim.uc / atcmd_mbim_lazy.uc are reached only through the try/require() in load_at_mbim(), so a wwand + wwand-qmi + wwand-mhi install with no wwand-mbim reports the capability absent rather than throwing.
  • main.uc and wwandctl.uc still start with #!/usr/bin/env ucode, so the source-default path installs them directly executable as /usr/sbin/wwand and /usr/bin/wwandctl. test-version.sh is untouched by this delta and still names all six packages, so the *) branch cannot fire. The PR body says "Current release: v1.6.0", which now lags L27 by one — the same drift that closed a few rounds back.

What I could not verify. PKG_HASH: codeload.github.com answers the archive URL with an access-denied JSON body rather than a tarball for this session, even though the git endpoint for the same repo is reachable, so the archive bytes stay out of reach. Treat it as unverified rather than verified-fine.

Only the three FormalityCheck jobs have reported on this head, all green. The full build/runtime CI has not run since 8ffb9e3 (the 1.3.0 head), so the current default build path — ucode source, precompile off, no host ucode staged — and the current install lists remain unexercised by this repo's CI, which is why the packaging gap in the first comment is only visible from a read of the release tree.

Earlier threads still open and not repeated here: the cdc-wdm device-ownership question, the ucode-mod-io reuse question, the deferred backend/transport split, and — for the opt-in precompile path only — the host-ucode capability and bytecode/interpreter-skew questions.


Generated by Claude Code

Comment thread net/wwand/Makefile
# tty hotplug: AT ports appearing after the datapath netdev (vendor-serial
# new_id bind / late kmodloader) re-kick a modem parked in no_at_port backoff
$(INSTALL_DIR) $(1)/etc/hotplug.d/tty
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/wwand.hotplug.tty $(1)/etc/hotplug.d/tty/20-wwand

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.6.1 adds a fifth hotplug script upstream, files/wwand.hotplug.e1820, and no package installs it — it ships in the tarball and lands nowhere. v1.6.0..v1.6.1 adds exactly one new files/ entry, and while the five new .uc modules moved into the install lists in this commit, this one did not.

The script is not cosmetic for the hardware it targets: its own header says it is meant to be /etc/hotplug.d/usb/21-wwand-e1820, and it re-creates a volatile qmi_wwan new_id entry for the Huawei E1820 (12d1:14ac) on every enumeration — without it that modem's control channel never appears at all, because cdc_ether blacklists the device and qmi_wwan's static table entry does not match its class-02 layout.

This is precisely the blind spot in the invariant checks: upstream's own tools/check-packaging.py only asserts that every $(PKG_BUILD_DIR)/files/... path the Makefile names resolves, not that every files/ entry is named by something. Running it against this head reports all 8 files/ paths resolve out of 10 present — the two it cannot see are files/wwand.config (deliberate, documented at L169-171) and this one.

INSTALL_DATA and the paired $(INSTALL_DIR) match the three sibling hotplug installs, and the directory is what arms dispatch — procd only runs hotplug-call for a subsystem whose directory exists (hotplug.json:83-86). Worth knowing before applying: usb is a high-traffic subsystem, so creating /etc/hotplug.d/usb makes procd fork hotplug-call for every USB uevent on the box, not just this modem's.

Suggested change
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/wwand.hotplug.tty $(1)/etc/hotplug.d/tty/20-wwand
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/wwand.hotplug.tty $(1)/etc/hotplug.d/tty/20-wwand
# usb hotplug: the Huawei E1820 (12d1:14ac) needs a volatile qmi_wwan new_id
# entry re-created on every enumeration, or its control channel never appears
$(INSTALL_DIR) $(1)/etc/hotplug.d/usb
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/wwand.hotplug.e1820 $(1)/etc/hotplug.d/usb/21-wwand-e1820

The suggestion puts it in the base package alongside the other three, which is where the sibling hotplugs live — but the script binds qmi_wwan specifically, so wwand-qmi is arguably the better owner by the same reasoning that moved the wwan hotplug into wwand-mhi. Your call; either placement closes the gap. If it is deliberately left out for now, a NOTE: next to the one at L181-184 would say so, the way the wwand hotplug's omission does.


Generated by Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a temporary not-yet-validated debugging script for my hardware. And when copied to a box containing this modem, it does not actually work after a reboot, for reasons yet unknown.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thank you — it landed nowhere, exactly as you say.

files/wwand.hotplug.e1820 is the whole mechanism for that modem: the kernel defers the E1820 to qmi_wwan (cdc_ether blacklists it, and qmi_wwan's own table entry wants a vendor-specific class this 2009-era stack does not carry), so the control channel only appears once a scoped dynamic new_id binds interface 1 — and that binding is volatile, so it has to be re-created on every replug. Shipping the script without installing it means the modem simply never comes up, with nothing failing to say why.

Installed to /etc/hotplug.d/usb/21-wwand-e1820 in the base package now, matching the path the daemon expects.

The reason it got past me is worth stating, because it is fixable: tools/check-packaging.py in the wwand tree verifies that every path the Makefile NAMES exists in the source, and never asked the other direction — whether every shipped file is named by some package. It printed "ok" while telling me "10 files/ entries" against "8 files/ paths resolve", and I read past the difference. The check now asks both directions and fails by name on an uninstalled file; the two deliberate exceptions (wwand.config, which this Makefile documents as an example that is never installed, and directory entries) are listed with their reason. Removing the install line again makes it fail, which is how I verified it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@patrakov Your assessment was right, and the cause turned out to be findable —
so I want to put it back to you, because you own the only E1820 I know of.

The script never bound anything, on any event. Two independent faults, both in
the idempotency guard:

[ -e "/sys/bus/usb/devices/${DEVPATH#/devices/}:1.1/driver" ] && \
	return 0 2>/dev/null || exit 0
  1. /sys/bus/usb/devices holds flat kobject names (3-1, 3-1:1.1), never
    a $DEVPATH-shaped path, so that test could not match anything. Measured on
    a MikroTik Chateau 5G against a live modem: the expression resolves to
    /sys/bus/usb/devices/platform/soc@0/.../usb3/3-1:1.1/driver, which does not
    exist.
  2. Worse, the line does the opposite of what it reads like. When the path is
    absent — the case we want to continue past — [ -e ] fails, && is
    skipped, and || fires exit 0. The binder was unreachable in exactly the
    situation it exists for.

So new_id was never written from hotplug. Setting it by hand worked, and after
a reboot nothing did — which is precisely what you described, and why the cause
was "yet unknown": the script looked like it ran, and did nothing.

Fixed upstream after 1.6.1 (b7222e6), with the path corrected to the child
form (/sys$DEVPATH/${DEVPATH##*/}:1.1/driver — an interface is a child of its
device, not a sibling; the sibling form that was suggested in review does not
exist either) and a DEVTYPE=usb_device gate, since usb_uevent() emits
PRODUCT for interfaces too. There is a test that runs the real script against
a sysfs miniature and asserts the path shapes separately from the behaviour.

The boot-time modprobe qmi_wwan race was a different fix and it is already
in the 1.6.1 this PR pins — so on your build that half was fine and the guard
was the whole problem.

Would you retest when you have a moment? The corrected script is in the
wwand tree at files/wwand.hotplug.e1820; dropping it in as
/etc/hotplug.d/usb/21-wwand-e1820 and replugging (or rebooting) is the whole
test. If it still does not bind, I would rather hear that than assume the fix
landed — I have never had this hardware and everything above is measured on
other modems plus a sysfs fixture.

Independently of the answer, the script stays out of the base package here. The
reason is no longer your report but the dispatch cost: installing it creates
/etc/hotplug.d/usb, and procd then forks hotplug-call for every USB uevent
on every wwand install. The note in the Makefile now says that instead
(09a56ad).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I can retest tomorrow. But I would also like to highlight that wwand is supposed to support PPP-only modems, which my modem without the hotplug script is. And it fails to support my E182e (naming it as it self-identifies via ATI) as a PPP-only stick.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, this E3372 issue is not a weak-signal issue. The LED is on, but the interface is down:

4: wwand1: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 00:1e:10:1f:00:00 brd ff:ff:ff:ff:ff:ff

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After update to latest version the Huawei E182E conns come up fine. Connection over Huawei E3372 also comes up, but sending does not work. I tried several things, but it seems to be "without charge", no volume left. Perhaps you could swap cards between E182E and E3372 to finally verify it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have enough money on the SIM that is in the e3372 and 65 GB remaining out of the package. Unfortunately, swapping the SIM cards between the modems is not possible: the SIM in the E3372 belongs to an operator that does not have 2G/3G coverage at all, while E182E only supports 2G and 3G.

Let me also try fixing the connectivity. Maybe it's just bad signal indeed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it came up, but the route is still wrong:

default dev wwand1 proto static scope link metric 90 

it needs to be via the gateway, not via the device.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, and it is in the release this Makefile pins.

You were right twice over: the device route was wrong on that link, and my first answer to it was wrong too. The shape now depends on whether the link can actually resolve a neighbour, instead of being one rule for every modem:

default via <gw> dev X      # ARP/ND link: a nexthop the kernel can resolve
default dev X scope link    # IFF_NOARP p2p link: no nexthop to resolve

default dev X scope link has no nexthop at all, so the kernel ARPs the destination. That only works on a NOARP point-to-point link — which is what the raw-IP modems give you, and why it went unnoticed. Your E3372 hands out an 802.3 link with ARP, and there it is simply broken.

Current state on your box, all three modems:

default dev wwand0 proto static scope link metric 55
default via 100.77.95.133 dev wwand1 proto static metric 90

and the flag the code keys off:

wwand0 flags=0x1083     <- 0x80 = IFF_NOARP  -> scope link, no gateway
wwand1 flags=0x1003     <- no 0x80           -> via 100.77.95.133

So wwand1 is exactly the line you quoted, now with the nexthop; wwand0 keeps the device form because on that link it is the correct one. wwand2 (the E182E) reads 0x1003 as well and gets the gateway form when it is up.

Landed in 6d91d2c, contained in v1.6.3PKG_VERSION:=1.6.3 in this PR, so nothing further is needed here. The shell guard reads /sys/class/net/$netdev/flags defensively: a missing or non-hex value falls back to the plain default route rather than aborting the handler, since $(( )) on a non-number kills an ash script outright.

Comment thread net/wwand/Makefile Outdated
Comment on lines +345 to +347
nothing on this path any more: the USB glue of every backend is now a
USB_SUPPORT-conditional dependency, so on a PCIe-only target the backends are
selectable and pull no USB stack, while a USB target gets exactly what it did

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: f503296 makes this sentence false as written. "the USB glue of every backend is now a USB_SUPPORT-conditional dependency" was accurate at 6f5d357, but that commit reverted wwand-ncm's three kmods to unconditional (L297-298) on purpose, so "every backend" is now two of the three. The paragraph is only ever talking about the QMI/MBIM pair on an MHI box, where the claim still holds — it is the generalisation that no longer does.

Suggested change
nothing on this path any more: the USB glue of every backend is now a
USB_SUPPORT-conditional dependency, so on a PCIe-only target the backends are
selectable and pull no USB stack, while a USB target gets exactly what it did
nothing on this path any more: the USB glue of wwand-qmi and wwand-mbim is a
USB_SUPPORT-conditional dependency, so on a PCIe-only target those two are
selectable and pull no USB stack, while a USB target gets exactly what it did

Generated by Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right — f503296 made that sentence false, and I did not go back to the prose that described the sweep.

Reworded to say what the paragraph is actually about: the two backends that can serve an MHI modem, wwand-qmi and wwand-mbim, are the ones whose USB kmods are USB_SUPPORT-conditional, so on a PCIe-only target they stay selectable and pull no USB stack. The NCM exception is now stated there rather than left for a reader to discover in the DEPENDS line — it drives a cdc_ncm/cdc_ether or rndis_host netdev, has no non-USB transport, and its hard kmod dependencies are what keep it unselectable where it could not work anyway.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 1 new commit.


Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
# dynamic new_id is what makes the control channel appear at all. It is
# volatile: every replug needs it re-created.
$(INSTALL_DIR) $(1)/etc/hotplug.d/usb
$(INSTALL_DATA) $(PKG_BUILD_DIR)/files/wwand.hotplug.e1820 $(1)/etc/hotplug.d/usb/21-wwand-e1820

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idempotency guard in the script this installs can never match: /sys/bus/usb/devices/ holds flat kobject names (1-1, 1-1:1.1), not the pci0000:00/…/usb1/1-1 path that ${DEVPATH#/devices/} yields, so wwand.hotplug.e1820:29 always falls through and new_id is written on every matching add event — each write appends another dynid to qmi_wwan rather than being a no-op. It also runs for the interface uevents, not just the device one, since PRODUCT is exported on those too. Upstream wants /sys$DEVPATH:1.1/driver and a DEVTYPE=usb_device gate.


Generated by Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed, all three parts — and the suggested path does not work either, which
is the useful part of checking it.

The guard never matched. /sys/bus/usb/devices/ holds flat kobject names
(3-1, 3-1:1.1), so ${DEVPATH#/devices/} produced a path that directory
never contains. Evaluated on a MikroTik Chateau 5G (2026-09-05) against a live
modem, that expression resolves to
/sys/bus/usb/devices/platform/soc@0/.../usb3/3-1:1.1/driver and does not
exist.

new_id is not idempotent. usb_store_new_id() kzallocs a usb_dynid and
list_add_tail()s it with no lookup (drivers/usb/core/driver.c, 6.18.41), so
each run really did append another entry.

PRODUCT is on interface events. usb_uevent() in that same file handles
is_usb_interface(dev) explicitly and emits PRODUCT from the parent device's
descriptor. Confirmed on hardware: /sys/bus/usb/devices/3-1:1.1/uevent carries
DEVTYPE=usb_interface alongside PRODUCT=2c7c/122/515.

Where the proposal needs correcting: /sys$DEVPATH:1.1/driver does not exist
either.
An interface is not a sibling of its device, it is a child of it —
/sys/bus/usb/devices/3-1:1.1 resolves to .../usb3/3-1/3-1:1.1. On the same
box the sibling form misses and /sys$DEVPATH/${DEVPATH##*/}:1.1/driver hits,
reporting option as the bound driver.

Fixed upstream of this tarball with that path plus the DEVTYPE=usb_device
gate you asked for, and covered by a test that runs the real script against a
sysfs miniature — it asserts the path shapes separately from the behaviour, so
a future kernel layout change reports which property moved rather than only
that binding broke. Reverting either half of the fix turns exactly one check
red.

For this PR the question is moot in the other direction: the script is no
longer installed at all, per the thread above.

Comment thread net/wwand/Makefile Outdated
Comment on lines +181 to +186
# usb hotplug: bind qmi_wwan to the Huawei E1820's ethernet function (USB
# 12d1:14ac, interface 1, class 02/06). The kernel defers the device to
# qmi_wwan — cdc_ether blacklists it, and qmi_wwan's own table entry wants a
# vendor-specific class this old stack does not carry — so the scoped
# dynamic new_id is what makes the control channel appear at all. It is
# volatile: every replug needs it re-created.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The owner of the E1820 hardware describes this script as "a temporary not-yet-validated debugging script" that "does not actually work after a reboot, for reasons yet unknown" — which conflicts with the commit message calling it "the whole mechanism" for that modem. Installing it in the base package puts it on every wwand install and arms /etc/hotplug.d/usb dispatch for all USB events; is it ready for that, or should it stay unpackaged until it is confirmed working?


Generated by Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, and so is the hardware owner. Removed from the install.

The conflict you spotted is real: the commit message described it as the whole
mechanism for that modem while the person who owns the modem calls it an
unvalidated debugging script that does not survive a reboot. Installing it from
the base package put it on every wwand install and armed /etc/hotplug.d/usb
dispatch for all USB events, which is not a trade worth making on that
evidence.

It stays in the source tree and the maintainer's own feed installs it, so the
people actually testing that modem still get it. The Makefile now records the
omission explicitly rather than leaving it looking like an oversight — the
packaging check this repo's contributor tooling runs would otherwise flag a
shipped-but-uninstalled file, which is exactly how the missing install was found
in the first place.

Separately, the script was broken in two ways; see the thread below for the
evidence and the fix.

Comment thread net/wwand/Makefile Outdated
stack, while a USB target gets exactly what it did before. (wwand-ncm is
deliberately not in that sweep: it drives a cdc_ncm/cdc_ether or rndis_host
netdev and has no non-USB transport, so its kmods stay hard dependencies and
keep it unselectable where it could not work anyway.) Without wwand-mbim the capability is simply absent — vendor AT

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: 120 chars, while the rest of this description block wraps at ~80.

Suggested change
keep it unselectable where it could not work anyway.) Without wwand-mbim the capability is simply absent — vendor AT
keep it unselectable where it could not work anyway.) Without wwand-mbim the
capability is simply absent — vendor AT

Generated by Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied, thanks.

For the record, two other lines in this file exceed 100 characters (67 and 146),
but both are make code — a variable assignment and an $(INSTALL_DATA) — where
the prose wrap does not apply and a continuation would cost more readability
than it buys. You flagged the one that was actually prose.

ddimension pushed a commit to ddimension/wwand that referenced this pull request Sep 5, 2026
Two independent mistakes in the same three lines, both silent.

The unbound check was built from /sys/bus/usb/devices/${DEVPATH#/devices/} —
but that directory holds only flat kobject names (`3-1`, `3-1:1.1`), never a
$DEVPATH-shaped one, so it matched nothing and the binder ran on every event.
The obvious repair is wrong too: an interface is not a sibling of its device,
so /sys$DEVPATH:1.1 does not exist either. It is a child, hence
/sys$DEVPATH/${DEVPATH##*/}:1.1 (HW-checked on a Chateau 5G, 2026-09-05).

And there was no device/interface gate. usb_uevent() handles is_usb_interface()
and emits PRODUCT from the parent's descriptor (drivers/usb/core/driver.c,
6.18.41), so a plug fired the body once per interface as well as once for the
device. That is not cosmetic: usb_store_new_id() (same file) kzallocs and
list_add_tail()s without a duplicate check, so each run appended another dynid
to qmi_wwan, every plug, forever.

test_hotplug_e1820 runs the real script against a sysfs miniature and asserts
the path shapes separately from the behaviour, so a future kernel layout change
reports which property moved instead of only that binding broke. Reverting
either half of the fix turns exactly one check red.

Reported by openwrt-ai on openwrt/packages#30185; the diagnosis was right and
the suggested path was not.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ddimension pushed a commit to ddimension/luci that referenced this pull request Sep 5, 2026
Netifd protocol handler for `proto wwand`, the cellular connection manager
proposed in openwrt/packages#30185. It renders the connection options the
daemon consumes — APN, PDP type, authentication, MUX id, MTU handling — and
resolves the modem an interface is bound to.

wwand registers `proto wwand` only; the historical `qmi` proto name stays
uqmi's, so this handler never competes with the stock one for an interface.

Signed-off-by: André Valentin <avalentin@marcant.net>
ddimension pushed a commit to ddimension/luci that referenced this pull request Sep 5, 2026
Status and management UI for the wwand cellular connection manager proposed in
openwrt/packages#30185: modem overview, per-modem tools (radio technologies,
band selection, network selection and scan, cell lock), SIM and eSIM profile
management, SMS, and the per-interface migration entry point that converts a
stock cellular interface to `proto wwand` in place.

Everything is driven over the daemon's ubus API; the ACL file lists exactly the
methods the pages call.

Signed-off-by: André Valentin <avalentin@marcant.net>

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 1 new commit.


Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
Comment on lines +358 to +361
keep it unselectable where it could not work anyway.) Without wwand-mbim the
capability is simply absent — vendor AT
commands, the protocol switch and AT telemetry are unavailable, which is a
limitation rather than a failure.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rewrap left vendor AT as a 40-char orphan mid-sentence — my earlier suggestion was anchored too narrowly and only covered the first two lines, so the rest of the sentence never got reflowed. Reflowing the whole sentence fixes it:

Suggested change
keep it unselectable where it could not work anyway.) Without wwand-mbim the
capability is simply absent — vendor AT
commands, the protocol switch and AT telemetry are unavailable, which is a
limitation rather than a failure.
keep it unselectable where it could not work anyway.) Without wwand-mbim the
capability is simply absent — vendor AT commands, the protocol switch and AT
telemetry are unavailable, which is a limitation rather than a failure.

Generated by Claude Code

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, thanks


Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
Comment on lines +137 to +142
# The E1820 usb binder (files/wwand.hotplug.e1820) ships in the tarball but is
# deliberately NOT installed here: the only known E1820 owner reports it as an
# unvalidated debugging script that does not survive a reboot, so it has no
# business arming /etc/hotplug.d/usb on every install of the base package. The
# feed package installs it for the people testing that hardware.
# check-packaging: not-installed files/wwand.hotplug.e1820

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: b030d93 adds the E1820 hotplug install and 8ec4574 removes it again, so the pair is net-zero in the series. Dropping the E1820 half of b030d93 (keeping its MHI-note correction, which survives) would leave the history without the round trip.


Generated by Claude Code

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, thanks — solved by dropping both commits in the rewrite, so the round trip is gone from the series.


Generated by Claude Code

@simsasss

simsasss commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Hi, I tried to play with RUTC50 and RG520N modem.
Initial connection was fine, I tried enable multiplexing, not working as before:

root@OpenWrt:~# /etc/init.d/wwand restart
root@OpenWrt:~# Mon Sep  7 11:18:31 2026 daemon.notice wwand[7923]: wwand 2026.09.07~24d173de-r66; backends: qmi
Mon Sep  7 11:18:31 2026 daemon.warn wwand[7923]: config: modem wwmodem_auto: no device/netdev/path/serial/imei, ignoring
Mon Sep  7 11:18:31 2026 daemon.warn wwand[7923]: config: interface wwan0: unknown modem 'wwmodem_auto', ignoring
Mon Sep  7 11:18:31 2026 daemon.warn wwand[7923]: config: interface wwan1: unknown modem 'wwmodem_auto', ignoring
Mon Sep  7 11:18:31 2026 daemon.notice wwand[7923]: device blocklist: br-lan (interface lan, proto static), lo (interface loopback, proto static), wan (interface wan, proto dhcp) — owned by a non-wwand interface, wwand will not touch them
Mon Sep  7 11:18:31 2026 daemon.info wwand[7923]: hotplug add cdc-wdm0
Mon Sep  7 11:18:31 2026 daemon.notice wwand[7923]: datapath: built-in auto, raw_ip, ethernet, rmnet, qmimux, vlan (no add-on datapath installed)
Mon Sep  7 11:18:31 2026 daemon.notice wwand[7923]: wwand started, 0 modem(s), 0 context(s)

wwand-2026.09.07~24d173de-r66
DISTRIB_TARGET='mediatek/filogic'
DISTRIB_ARCH='aarch64_cortex-a53'
DISTRIB_DESCRIPTION='OpenWrt SNAPSHOT r36072-f1a3f07139'

config wwand_modem 'wwmodem_auto'

config interface 'wwan0'
	option proto 'wwand'
	option device 'wwand0'
	option modem 'wwmodem_auto'
	option autosetup '1'
	option mux_id '1'
	option metric '10'

config interface 'wwan1'
	option proto 'wwand'
	option modem 'wwmodem_auto'
	option apn 'internet'
	option pdp_type 'ipv4'
	option mux_id '2'

Right after configuration change wwand drop modem:
image

@simsasss

simsasss commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Another one:
RUT240 with EC25-E fails to connect.
BUILD_ID="r36077-fe4bb13256"
OPENWRT_BOARD="ath79/generic"
OPENWRT_ARCH="mips_24kc"
wwand-2026.09.07~24d173de-r66

config wwand_modem 'wwmodem_auto'
	option path 'platform/ahb/1b000000.usb/ci_hdrc.0/usb1/1-1'

config interface 'wwan0'
	option proto 'wwand'
	option device 'wwand0'
	option modem 'wwmodem_auto'
	option autosetup '1'

Logs:

Mon Sep  7 11:43:33 2026 daemon.info wwand[1567]: hotplug add ttyUSB1
Mon Sep  7 11:43:34 2026 daemon.info wwand[1567]: hotplug add ttyUSB2
Mon Sep  7 11:43:35 2026 daemon.info wwand[1567]: modem wwmodem_auto: qmi control channel answered — hardware recovery armed
Mon Sep  7 11:43:35 2026 daemon.info wwand[1567]: modem wwmodem_auto: state INIT_TRANSPORT -> INIT_SERVICES
Mon Sep  7 11:43:35 2026 daemon.info wwand[1567]: modem wwmodem_auto: services: 0(1.5) 1(1.67) 2(1.0) 3(1.25) 4(1.12) 5(1.10) 7(1.3) 8(1.2) 9(2.1) 10(2.24) 11(1.46) 12(1.4) 15(1.0) 16(2.0) 17(1.0) 23(1.0) 24(1.0) 26(1.16) 29(1.1) 34(1.0) 36(1.0) 41(1.0) 42(1.0) 45(1.0) 48(1.0) 50(1.0) 54(1.0)
Mon Sep  7 11:43:36 2026 daemon.info wwand[1567]: modem wwmodem_auto: thermal mitigation devices: pa (0..3), modem (0..3), cpuv_restriction_cold (0..1), cx_vdd_limit (0..3)
Mon Sep  7 11:43:36 2026 daemon.info wwand[1567]: hotplug add ttyUSB3
Mon Sep  7 11:43:36 2026 daemon.info wwand[1567]: modem wwmodem_auto: capabilities: max tx 50000000 rx 100000000 kbps, radio ifs [4 5 8]
Mon Sep  7 11:43:36 2026 daemon.notice wwand[1567]: modem wwmodem_auto: QUALCOMM INCORPORATED QUECTEL Mobile Broadband Module, revision EC25ECGAR06A16M1G, imei xxxxx
Mon Sep  7 11:43:37 2026 daemon.notice wwand[1567]: modem wwmodem_auto: AT port: /dev/ttyUSB2
Mon Sep  7 11:43:37 2026 daemon.notice wwand[1567]: modem wwmodem_auto: NMEA port /dev/ttyUSB1 available (wwand does not open it; see `gps_port` in ubus status)
Mon Sep  7 11:43:37 2026 daemon.notice wwand[1567]: modem wwmodem_auto: AT telemetry channel: /dev/ttyUSB3
Mon Sep  7 11:43:37 2026 daemon.info wwand[1567]: modem wwmodem_auto: state INIT_SERVICES -> INIT_DATAPATH
Mon Sep  7 11:43:37 2026 daemon.info wwand[1567]: modem wwmodem_auto: wda format negotiated: QMAP v5 (proto 0) ul/dl, llp 2, dl max 10 x 4096 bytes, ul max 16 x 4096 bytes (requested v5 / proto 9, 4096 bytes)
Mon Sep  7 11:43:37 2026 daemon.notice wwand[1567]: modem wwmodem_auto: modem rejected aggregation protocol 9, trying qmap v4
Mon Sep  7 11:43:37 2026 daemon.info wwand[1567]: modem wwmodem_auto: wda format negotiated: QMAP v4 (proto 0) ul/dl, llp 2, dl max 10 x 4096 bytes, ul max 16 x 4096 bytes (requested v4 / proto 8, 4096 bytes)
Mon Sep  7 11:43:37 2026 daemon.notice wwand[1567]: modem wwmodem_auto: modem rejected aggregation protocol 8, trying qmap v1
Mon Sep  7 11:43:37 2026 daemon.info wwand[1567]: modem wwmodem_auto: wda format negotiated: QMAP v1 (proto 5) ul/dl, llp 2, dl max 10 x 4096 bytes, ul max 16 x 4096 bytes (requested v1 / proto 5, 4096 bytes)
Mon Sep  7 11:43:37 2026 daemon.err wwand[1567]: modem wwmodem_auto: failed in datapath: { "ok": false, "error": "datapath rmnet negotiated QMAP v1 but the interface configures no mux channel — add `option mux_id` (a plain raw-IP parent cannot carry QMAP frames)" }
Mon Sep  7 11:43:37 2026 daemon.info wwand[1567]: modem wwmodem_auto: connection attempt 1 failed
Mon Sep  7 11:43:37 2026 daemon.info wwand[1567]: modem wwmodem_auto: state INIT_DATAPATH -> ABSENT
Mon Sep  7 11:43:38 2026 daemon.info wwand[1567]: hotplug add cdc-wdm0
Mon Sep  7 11:43:38 2026 daemon.info wwand[1567]: modem wwmodem_auto: state ABSENT -> INIT_TRANSPORT
Mon Sep  7 11:43:38 2026 daemon.info wwand[1567]: hotplug add wwan0
Mon Sep  7 11:43:38 2026 user.notice firewall: Reloading firewall due to ifup of wan (eth1)
Mon Sep  7 11:43:39 2026 daemon.info wwand[1567]: hotplug move wwand0
Mon Sep  7 11:44:21 2026 daemon.warn wwand[1567]: modem wwmodem_auto: control SYNC unanswered (timeout) — continuing, the version query is the real gate
Mon Sep  7 11:44:21 2026 daemon.info wwand[1567]: modem wwmodem_auto: state INIT_TRANSPORT -> INIT_SERVICES
Mon Sep  7 11:44:31 2026 daemon.err wwand[1567]: modem wwmodem_auto: failed in version_info: { "error": "timeout" }
Mon Sep  7 11:44:31 2026 daemon.info wwand[1567]: modem wwmodem_auto: connection attempt 2 failed
Mon Sep  7 11:44:31 2026 daemon.info wwand[1567]: modem wwmodem_auto: state INIT_SERVICES -> ABSENT
Mon Sep  7 11:44:41 2026 daemon.info wwand[1567]: modem wwmodem_auto: state ABSENT -> INIT_TRANSPORT
Mon Sep  7 11:45:24 2026 daemon.warn wwand[1567]: modem wwmodem_auto: control SYNC unanswered (timeout) — continuing, the version query is the real gate
Mon Sep  7 11:45:24 2026 daemon.info wwand[1567]: modem wwmodem_auto: state INIT_TRANSPORT -> INIT_SERVICES

root@OpenWrt:~# Mon Sep  7 11:45:34 2026 daemon.err wwand[1567]: modem wwmodem_auto: failed in version_info: { "error": "timeout" }
Mon Sep  7 11:45:34 2026 daemon.info wwand[1567]: modem wwmodem_auto: connection attempt 3 failed
Mon Sep  7 11:45:34 2026 daemon.info wwand[1567]: modem wwmodem_auto: state INIT_SERVICES -> ABSENT
Mon Sep  7 11:45:49 2026 daemon.info wwand[1567]: modem wwmodem_auto: state ABSENT -> INIT_TRANSPORT
Mon Sep  7 11:46:32 2026 daemon.warn wwand[1567]: modem wwmodem_auto: control SYNC unanswered (timeout) — continuing, the version query is the real gate
Mon Sep  7 11:46:32 2026 daemon.info wwand[1567]: modem wwmodem_auto: state INIT_TRANSPORT -> INIT_SERVICES
Mon Sep  7 11:46:42 2026 daemon.err wwand[1567]: modem wwmodem_auto: failed in version_info: { "error": "timeout" }
Mon Sep  7 11:46:42 2026 daemon.info wwand[1567]: modem wwmodem_auto: connection attempt 4 failed
Mon Sep  7 11:46:42 2026 daemon.info wwand[1567]: modem wwmodem_auto: state INIT_SERVICES -> ABSENT
Mon Sep  7 11:47:02 2026 daemon.info wwand[1567]: modem wwmodem_auto: state ABSENT -> INIT_TRANSPORT
image

Also segfault on restart:

/etc/init.d/wwand restart
Mon Sep  7 11:49:44 2026 kern.info kernel: [  461.289513] do_page_fault(): sending SIGSEGV to ucode for invalid read access from 77acdc30
Mon Sep  7 11:49:44 2026 kern.info kernel: [  461.296464] epc = 77d8dae9 in libucode.so.20230711[19ae9,77d74000+22000]
Mon Sep  7 11:49:44 2026 kern.info kernel: [  461.303257] ra  = 77d8d8ef in libucode.so.20230711[198ef,77d74000+22000]

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are consistency/packaging issues to address (PR description vs pinned version mismatch, and a wildcard install that conflicts with the stated explicit per-file ownership approach).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds a new OpenWrt package definition for wwand, splitting it into multiple installable binary packages (base + protocol backends + MHI transport + optional eSIM support) and adding a runtime version-test override script for the package set.

Changes:

  • Introduces net/wwand/Makefile defining the source package and six binary packages (wwand, wwand-qmi, wwand-mbim, wwand-ncm, wwand-mhi, wwand-esim) with explicit install logic.
  • Adds net/wwand/test-version.sh to opt these packages out of the generic runtime version check since the installed executables do not print PKG_VERSION.
File summaries
File Description
net/wwand/Makefile Adds the OpenWrt packaging for wwand, including package splits, dependencies, and install steps.
net/wwand/test-version.sh Adds a package-specific version-test override to bypass the generic runtime version check for wwand packages.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread net/wwand/Makefile Outdated
Comment on lines +26 to +32
PKG_NAME:=wwand
PKG_VERSION:=1.6.1
PKG_RELEASE:=1

PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/ddimension/wwand/tar.gz/refs/tags/v$(PKG_VERSION)?
PKG_HASH:=c7d85b1d6c7f8b524b7eab3f1381b34961e6e22810852b122dcd00b890289d0c

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overtaken by the series since — both halves now read 1.6.3: the body says "Current release: v1.6.3 — the release this Makefile pins" and the Makefile sets PKG_VERSION:=1.6.3, so the description and the pin agree.

Comment thread net/wwand/Makefile
Comment on lines +276 to +280
$(INSTALL_DATA) $(WWAND_UCODE)/mbim_lazy.uc $(1)$(UCDIR)/
$(INSTALL_DATA) $(WWAND_UCODE)/atcmd_mbim.uc $(1)$(UCDIR)/
$(INSTALL_DATA) $(WWAND_UCODE)/atcmd_mbim_lazy.uc $(1)$(UCDIR)/
$(INSTALL_DATA) $(WWAND_UCODE)/codec/mbim.uc $(1)$(UCDIR)/codec/
$(INSTALL_DATA) $(WWAND_UCODE)/codec/mbim_schema/*.uc $(1)$(UCDIR)/codec/mbim_schema/

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct on the facts — it is the only wildcard in the file; every other .uc is
installed by name. But I think the trade runs the other way here, so let me put
the reasoning up rather than just change it.

What an explicit list would buy, and what it would cost. The failure mode is
not symmetric:

  • With the glob, a new schema file that upstream adds lands in wwand-mbim
    without a Makefile change. The risk is shipping a file nobody re-reviewed
    here.
  • With an explicit list, that same file is silently not installed. It is
    loaded by name at runtime (wwand.codec.mbim_schema.<service>), so the result
    is an import failure on a live modem — MBIM breaks, and the Makefile that
    caused it looks perfectly fine.

I would rather fail towards "a file shipped that nobody asked about" than
towards "a backend broken on hardware", and that is the whole of my preference.

Three things bound the risk the glob carries:

  1. The directory has exactly one owner. codec/mbim_schema/ is installed by
    wwand-mbim and by nothing else, and everything under it is an MBIM service
    schema by construction — the only importers are modem_mbim.uc,
    context_mbim.uc, mbim_backend.uc, telemetry_mbim.uc and
    qmi_over_mbim.uc. There is no plausible file that could appear there and
    belong to a different package.
  2. A new file is not unreviewed upstream. The wwand tree's CMakeLists
    carries explicit source lists and fails the configure on drift in either
    direction — an unlisted .uc, or a listed one that does not exist. So a
    schema file cannot appear without a deliberate change there.
  3. The version bump is the review point either way. Any new file arrives
    with a new tarball and a new PKG_HASH; a reviewer who wants to know what
    changed reads that diff, not the install list.

The contributor tooling knows about this one exception and is explicit about
it.
tools/check-packaging.py asserts every .uc is installed by exactly one
package, and handles the glob by claiming direct children only — it
deliberately does not descend, because claiming every descendant would report a
nested file as installed when the shell glob would silently omit it. That is a
false negative against the one invariant the tool exists for.

So the "explicit per-file list" claim in the description is about package
ownership — which files belong to which of the six packages — and that property
still holds exactly: the glob covers one single-owner directory.

That said, this is your project's convention to set. If you would rather have
the six names spelled out, say so and I will do it — it is a small change, and I
would add a check that fails when the list and the directory disagree, so the
silent-omission failure above cannot happen.

@ddimension

Copy link
Copy Markdown
Author

@simsasss Thank you — the second one is a regression I caused, and you caught it
within a day of it shipping.

RUT240 / EC25-E: my bug, fixed

wda format negotiated: QMAP v5 ... modem rejected aggregation protocol 9, trying qmap v4
wda format negotiated: QMAP v4 ... modem rejected aggregation protocol 8, trying qmap v1
failed in datapath: "datapath rmnet negotiated QMAP v1 but the interface
configures no mux channel — add `option mux_id`"

option mux_id is optional and must stay optional. What went wrong: the
datapath probe claims the box for rmnet whether or not channels are
configured — that part is deliberate, an accelerated datapath has to be able to
identify itself before anyone writes option mux. But the "no channel
configured" check then sat in netlink.setup(), after the WDA ladder had
already run. So your unmuxed EC25 walked the whole QMAP ladder and died on a
config whose only sin was having no mux_id.

The refusal was not wrong, it was in the wrong layer. Negotiating a format we
then have nothing to unwrap with is the bug; your config is ordinary. Fixed in
cc8b942: with no channels configured, a channel-building datapath now settles
on a plain raw-IP parent before the WDA gate, so no aggregation is ever
requested — which is what an unmuxed modem got before any of this existed.

The one case where that error is correct is kept and now says what it means: a
datapath that adopts channels its driver created at module load
(rmnet_nss) has a modem already in QMAP whatever wwand negotiates, so an
unmuxed config genuinely cannot work there.

There is a regression test that fails on the first assertion — the modem does
not come up — when the fix is reverted.

The version_info: timeout loop after it is downstream of the same event: the
failed datapath step drops the modem to ABSENT mid-init and the EC25 needs a
re-enumeration to answer QMI again. I expect it to go with the fix. If it does
not, that is a separate bug and I want to know.

RUTC50 / RG520N: I need one more thing from you

This one I cannot pin from the log, and I do not want to guess:

config: modem wwmodem_auto: no device/netdev/path/serial/imei, ignoring
config: interface wwan0: unknown modem 'wwmodem_auto', ignoring

Your config wwand_modem 'wwmodem_auto' has no binding at all — no
device, no path, no serial, no imei. wwand drops such a section (it
names no hardware), and with it every interface pointing at it, which is your
"0 modem(s), 0 context(s)".

What I cannot explain is how it got that way. autosetup always writes one or
the other (path when the sysfs path resolves, device otherwise), and the
learn-back that converts device to path sets the new value before removing
the old. So: did that section have a path or device line before you
enabled multiplexing?
If yes, the exact steps that removed it are the bug and
I will chase it. If it was written by hand, that is just a missing binding.

Either way it is stuck now rather than self-healing, and that part is worth
fixing on its own: autosetup sees an existing wwand_modem section, decides
the box is configured, and never repairs it — so it stays dead with the reason
only in a boot-time warning. Your option autosetup '1' is still sitting on
wwan0 for the same reason.

To get going immediately:

uci set network.wwmodem_auto.path='<the sysfs path of your modem>'   # see `ubus call wwand modem_probe`
uci commit network && /etc/init.d/wwand restart

The segfault

sending SIGSEGV to ucode for invalid read access from 77acdc30
epc = 77d8dae9 in libucode.so.20230711

Please open that as its own issue at ddimension/wwand with the wwand version,
the exact command, and whether it reproduces. It is on /etc/init.d/wwand restart, i.e. most likely during shutdown, and a crash inside libucode is
either a ucode bug or wwand handing it something it should not — neither is
diagnosable from this line alone. If you can get ulimit -c unlimited and a
core, or even just say "every restart" vs "once", that narrows it a lot.

Both fixes are in the wwand repo; this PR's pinned version will pick them up at
the next bump.

@ddimension

Copy link
Copy Markdown
Author

@simsasss The mux_id regression is fixed and published —
wwand-2026.09.07~2961940a-r68 in the ddimension feed.

Your RUT240 / EC25-E should connect again without option mux_id: an unmuxed
config no longer negotiates QMAP at all, so there is nothing left for the
datapath step to refuse. I expect the version_info: timeout loop that followed
to go with it, since the EC25 only needed a re-enumeration after the failed
datapath step dropped it mid-init. If that loop persists after the fix, it is a
separate fault and I want to see it.

Note r67 never reached the feed — it was superseded before publishing — so r68
is the first build carrying this.

Still open from your reports, and neither is forgotten:

  • RUTC50 / RG520N, the bare config wwand_modem 'wwmodem_auto'. I still
    cannot explain how the binding was lost, and I would rather ask than guess:
    did that section have a path or device line before you enabled
    multiplexing? If it did, the steps that removed it are a bug I want to chase.
  • The libucode SIGSEGV on restart. Please open that at ddimension/wwand
    with the wwand version and whether it reproduces on every restart or happened
    once — a crash inside libucode is either a ucode bug or wwand handing it
    something it should not, and that one line cannot tell them apart.

Thank you for testing against the tip; this one was reported and fixed inside a
day because of it.

@simsasss

simsasss commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Info:

root@OpenWrt:~# wwandctl status
MODEM wwmodem_auto  (Quectel RG520N-EB, qmi, /dev/cdc-wdm0)
  state       READY
  SIM         imsi   iccid 
  network     Telia LT (246/01), LTE
  signal      LTE rsrp -108 dBm rsrq -11 dB
  temp        35 °C
  datapath    rmnet · QMAP v5 · urb 4100
INTERFACE wwan0  (netdev wwand0)
  state       CONNECTED
  data        down 0 bytes  up 748 bytes
BOARD       teltonika,rutc50
root@OpenWrt:~# wwandctl modems
wwmodem_auto     READY      qmi    RG520N-EB                Telia LT (246/01), LTE
config wwand_modem 'wwmodem_auto'
	option path 'platform/soc/11200000.usb/usb2/2-1/2-1.1'

config interface 'wwan0'
	option proto 'wwand'
	option device 'wwand0'
	option modem 'wwmodem_auto'
	option autosetup '1'
	option mux_id '1'

Step by step multiplexing:

  1. Create new interface over WebUI
  2. Change "Mux channel" to 2
  3. Save and apply
image

This generates:

# /etc/config/network
uci set network.wwan1=interface
uci set network.wwan1.proto='wwand'
uci del network.wwmodem_auto.path
uci set network.wwan1.modem='wwmodem_auto'
uci set network.wwan1.mux_id='2'

@ddimension

Copy link
Copy Markdown
Author

@simsasss That capture is the whole bug — thank you for reproducing it step by
step and pasting the generated uci. This is the RUTC50 mystery from the earlier
thread, and it is a LuCI bug of ours, not a missing binding on your side.

The line that does the damage:

uci del network.wwmodem_auto.path

Adding a second interface on an existing modem deletes that modem's
hardware binding. After it the wwand_modem section names no hardware at all,
so the daemon drops it and every interface referencing it — exactly the
0 modem(s), 0 context(s) you saw. It does not self-heal, because autosetup
finds an existing wwand_modem section and leaves it alone. That is why your
box stayed dead until you put the binding back.

Cause is an ordering asymmetry between rendering and saving. option modem
lives on the General tab (wwand.js:423); the modem-bound fields (path, imei,
serial, reset_gpio…) are declared much later (:555), and LuCI saves in
declaration order. So on a new interface:

  • at render time option modem is not set yet, modemSid() returns null, and
    every bound field reads the interface section and comes up blank;
  • at save time modem has just been written, so modemSid() now resolves —
    and LuCI calls remove() for each blank field, which cleared them on the
    shared modem section.

The user never sees those values and never touches them. Only path appears in
your capture because it was the only modem-level option that had a value; the
others were already empty, so there was nothing to delete.

Fixed in ddimension/luci-app-wwand@98a83ab: an empty field clears the modem
section only when the form actually read that section when it loaded.
Deliberately clearing a value the form did show still works.

I verified it by replaying both orders against the real bindModem semantics
rather than by eye — unguarded reproduces your two lines exactly and loses
path; guarded emits only the modem set and keeps the binding.

Two notes:

  • Your wwandctl status looks healthy otherwise — RG520N-EB on rmnet/QMAP v5,
    urb 4100, CONNECTED. Note down 0 bytes, which is just a fresh session.
  • This is in luci-app-wwand, so it does not affect this PR's Makefile. It
    will reach you in the next luci-app build; until then, adding a second
    interface is worth doing with uci directly, or check
    uci show network.wwmodem_auto afterwards.

marcant-oss and others added 2 commits September 8, 2026 20:34
"the USB glue of every backend is now a USB_SUPPORT-conditional dependency" was
true when written and stopped being true one commit later, when wwand-ncm's
kmods went back to unconditional on purpose. The paragraph only ever describes
the QMI/MBIM pair on an MHI box, where the claim still holds — it is the
generalisation that no longer does.

Says two of the three, and states the NCM exception where a reader meets it
rather than leaving it to be discovered in a DEPENDS line: that backend drives a
cdc_ncm/cdc_ether or rndis_host netdev, has no non-USB transport, and its hard
kmod dependencies are what keep it unselectable where it could not work anyway.

Signed-off-by: André Valentin <avalentin@marcant.net>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
files/wwand.hotplug.e182e ships in the tarball and no package here installs it.
That is deliberate, and the packaging check this project's contributor tooling
runs flags a shipped-but-uninstalled file, so the reason belongs in the Makefile
rather than in a reviewer's memory.

Installing it from the BASE package would create /etc/hotplug.d/usb on every
wwand install, and procd dispatches hotplug-call for a subsystem whose directory
exists — so every USB uevent on the box would fork a script, for one 2009 Huawei
stick almost nobody has. The maintainer's own feed installs it for the people
testing that hardware.

The note also records what the script is and what was wrong with it, because the
review thread that found this rests on a report ("unvalidated, does not survive
a reboot") whose cause is now known and fixed upstream: the idempotency guard
tested a path /sys/bus/usb/devices never holds, and was written so that it
exited in exactly the case the binder exists for.

Signed-off-by: André Valentin <avalentin@marcant.net>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit checks

  • 7551787 "wwand: say why the E182E usb binder is not installed" — the body names files/wwand.hotplug.e182e, but the file this release ships (and the path the commit's own check-packaging line uses) is files/wwand.hotplug.e1820.

Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
Comment on lines +138 to +140
# here. (The file is `files/wwand.hotplug.e1820` in 1.6.2 — the stick is an
# E182E and upstream renamed the file after this tag; the path below is the one
# this release actually contains.) Installing it from the BASE package would

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: 7551787 sits one commit before the 1.6.2 bump, so where this lands the Makefile still pins 1.6.1 and the parenthetical describes a release the tree does not build yet. Ordering it after wwand: update to 1.6.2 makes it true at the commit that introduces it.


Generated by Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gone with the rewrite — that intermediate commit is no longer in the series, and the Makefile now pins 1.6.3 in a single bump rather than passing through 1.6.1/1.6.2 on the way.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 1 new commit.


Generated by Claude Code

Comment thread net/wwand/Makefile Outdated
include $(TOPDIR)/rules.mk

PKG_NAME:=wwand
PKG_VERSION:=1.6.3

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the PR body still reads "Current release: v1.6.2 — the release this Makefile pins". Bring the description to 1.6.3 so it and the pin agree.


Generated by Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, thanks — the body reads "Current release: v1.6.3 — the release this Makefile pins", matching PKG_VERSION:=1.6.3.

I also re-checked the check count in that same sentence rather than carrying it forward: a worktree at v1.6.3 runs 52 suites, 3917 checks, 0 failures, so "3917 host-side checks" describes the pinned release accurately.

Routing, an old-stack dial path, and PPP scope — all three measured on hardware.

The IPv4 default route carries a nexthop where the link resolves neighbours. A
device route has no nexthop, so the kernel resolves the DESTINATION on that
link: right on a NOARP point-to-point link, wrong on an ethernet-framed one,
where it silently requires the modem to proxy-ARP the whole internet. On a
Huawei E3372, alternating only the route shape three times: 100% loss on the
device route, 0% via the gateway. NOARP links — every RNDIS and raw-IP
deployment — keep exactly the routes they had.

Old QMI stacks dial again: no invented profile index is sent to a modem that
answered INVALID_PROFILE, and the IP family rides in START_NETWORK where
SET_IP_FAMILY is refused. A Huawei E182E answers both with errors and never
completed a dial before.

PPP-only devices are out of scope by decision, and now say so: a serial-only
modem still gets one usbnet mode switch, and every dead end of it names
OpenWrt's `proto 3g` rather than "leaving unmanaged". Migration never converted
a `proto 3g` interface; there is now a test so a later widening cannot take it
silently. `ppp` is gone from the documented values of `option protocol`.

1.6.4 adds a unit conversion the release notes should not have to explain twice:
WCDMA Ec/Io arrives over QMI as a raw gint16 in -0.5 dB units but over AT
already in dB, so one documented key meant two different things depending on
which path answered. It is normalised at every point that stores a raw signal
reply — the polled read, the indication and the QMI-over-MBIM passthrough.

Also: a firmware protocol switch clears an `option protocol` pin it has just
invalidated, and the vanish escalation says why it had nothing to pulse on a
multi-modem box.

deps.uc and wwandctl_fmt.uc join the installed module list. They were extracted
from main.uc and wwandctl in this release and would otherwise ship nowhere,
which tools/check-packaging.py in the source tree catches when run against the
release tarball.

Signed-off-by: André Valentin <avalentin@marcant.net>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants