diff --git a/UPSTREAM.md b/UPSTREAM.md index 2a6ac6cfd..58ef576d8 100644 --- a/UPSTREAM.md +++ b/UPSTREAM.md @@ -1,11 +1,17 @@ -# BES2600 driver — upstream submission prep +# BES2600 driver -- upstream submission prep ## Status -Six patches, all checkpatch-clean, all deployed and verified on a PineTab2 -(BES2600WM + Rockchip RK3566) running linux-pinetab2 6.19.10-danctnix1. -Ready for Mobian DKMS merge requests and as the basis for a future -`drivers/staging/bes2600/` submission to linux-wireless. +Seven patches, all checkpatch `--strict` clean, all deployed and verified +on a PineTab2 (BES2600WM + Rockchip RK3566) running linux-pinetab2 +6.19.10-danctnix1. Ready for Mobian DKMS merge requests and as the basis +for a future `drivers/staging/bes2600/` submission to linux-wireless. + +The 7th patch (`tx-sdio-dma-oob`) fixes a KFENCE-detected SDIO DMA +out-of-bounds read on every TX burst -- a real memory-safety bug that +also leaks adjacent kernel memory onto the air. This upgrades the series +from "cleanup" to "cleanup + live bug fix" and should precede any +linux-wireless RFC. ## The series @@ -13,14 +19,15 @@ Recommended submission order (dependency-clean, bisectable): | # | Branch | Commit | Intent | |---|--------|--------|--------| -| 01 | `bes2600/factory-request-firmware` | `1a5d54a` | c1 — Replace `filp_open` + `kernel_read` in the factory-read path with `request_firmware()`. Repoint `FACTORY_PATH` macro to the firmware-class name. Kills a kernel-mainline anti-pattern and the `(NULL device *)` `read and check /lib/firmware/bes2600_factory.txt error` boot spam on PineTab2. | -| 02 | `bes2600/factory-no-efuse-flag` | `82ba594` | c5 — Default `STANDARD_FACTORY_EFUSE_FLAG` from y to n. The shipped `bes2600_factory.txt` has 30 calibration fields; the driver was expecting 31 (incl. a `##select_efuse_flag` section this firmware doesn't ship). Also drops an inconsistent `#if defined(STANDARD_FACTORY_EFUSE_FLAG)` wrapper around the `wsm_save_factory_txt_to_mcu()` prototype — the definition and call site are always ungated, so the gate broke the build once EFUSE_FLAG=n. | -| 03 | `bes2600/factory-thread-dev` | `8732881` | c1.1 — Thread `struct device *` through `factory_section_read_file()` via a module-local setter invoked at SDIO probe, so `request_firmware()` gets proper per-device context instead of NULL. Removes the `(NULL device *)` log prefix from factory-related diagnostics. | -| 04 | `bes2600/pm-gate-on-handshake` | `80178ec` | c2 — Gate the device-end of the LP transition on successful per-VIF firmware handshake. Before: `bes2600_pwr_device_enter_lp_mode()` was called unconditionally even when `wait_for_completion_timeout()` returned 0 (firmware never ack'd). On PineTab2 this produced `bes2600_pwr_enter_lp_mode, wait pm ind timeout` every 5-10s and cascaded into `sdio_tx_work` WARN splats. After: `-ETIMEDOUT` returned cleanly, dmesg silent, SDIO stable. | -| 05 | `bes2600/remove-chardev-user-interface` | `f43bcc5` | c3 — Remove the custom `/dev/bes2600` character-device interface (fops, command dispatcher, `bes2600_op_*` handlers, `bes2600_load_uevent`, `alloc_chrdev_region`/`class_create`/`device_create` registration, cdev fields in struct bes_cdev). 519-line deletion. Keeps all in-kernel accessor functions (13 callers) and the `fw_type` module parameter as the user-facing replacement. | -| 06 | `bes2600/enable-testmode` | `9398d30` | c4 — Flip `CONFIG_BES2600_TESTMODE` default from n to y, exposing the driver's mac80211 testmode_cmd surface (dispatches to the firmware's `patch_wifi_testMode` path) through the standard nl80211 testmode interface. Also fixes accumulated bit-rot revealed by enabling the flag: adds compat shim macros in `bes_log.h` for the legacy `bes2600_info()` / `bes2600_err()` / `bes2600_warn()` / `bes2600_dbg()` / `bes2600_err_with_cond()` family (which had no definition anywhere, despite ~41 call sites in testmode code), defines `BES2600_DBG_*` subsystem ids as 0 constants, and marks 3 TSM/roam-delay helpers in sta.c as `static` for `-Werror=missing-prototypes`. | +| 01 | `bes2600/factory-request-firmware` | `1a5d54a` | c1 -- Replace `filp_open` + `kernel_read` in the factory-read path with `request_firmware()`. Repoint `FACTORY_PATH` macro to the firmware-class name. Kills a kernel-mainline anti-pattern and the `(NULL device *)` `read and check /lib/firmware/bes2600_factory.txt error` boot spam on PineTab2. | +| 02 | `bes2600/factory-no-efuse-flag` | `82ba594` | c5 -- Default `STANDARD_FACTORY_EFUSE_FLAG` from y to n. The shipped `bes2600_factory.txt` has 30 calibration fields; the driver was expecting 31 (incl. a `##select_efuse_flag` section this firmware doesn't ship). Also drops an inconsistent `#if defined(STANDARD_FACTORY_EFUSE_FLAG)` wrapper around the `wsm_save_factory_txt_to_mcu()` prototype -- the definition and call site are always ungated, so the gate broke the build once EFUSE_FLAG=n. | +| 03 | `bes2600/factory-thread-dev` | `8732881` | c1.1 -- Thread `struct device *` through `factory_section_read_file()` via a module-local setter invoked at SDIO probe, so `request_firmware()` gets proper per-device context instead of NULL. Removes the `(NULL device *)` log prefix from factory-related diagnostics. | +| 04 | `bes2600/pm-gate-on-handshake` | `80178ec` | c2 -- Gate the device-end of the LP transition on successful per-VIF firmware handshake. Before: `bes2600_pwr_device_enter_lp_mode()` was called unconditionally even when `wait_for_completion_timeout()` returned 0 (firmware never ack'd). On PineTab2 this produced `bes2600_pwr_enter_lp_mode, wait pm ind timeout` every 5-10s and cascaded into `sdio_tx_work` WARN splats. After: `-ETIMEDOUT` returned cleanly, dmesg silent, SDIO stable. | +| 05 | `bes2600/remove-chardev-user-interface` | `f43bcc5` | c3 -- Remove the custom `/dev/bes2600` character-device interface (fops, command dispatcher, `bes2600_op_*` handlers, `bes2600_load_uevent`, `alloc_chrdev_region`/`class_create`/`device_create` registration, cdev fields in struct bes_cdev). 519-line deletion. Keeps all in-kernel accessor functions (13 callers) and the `fw_type` module parameter as the user-facing replacement. | +| 06 | `bes2600/enable-testmode` | `9398d30` | c4 -- Flip `CONFIG_BES2600_TESTMODE` default from n to y, exposing the driver's mac80211 testmode_cmd surface (dispatches to the firmware's `patch_wifi_testMode` path) through the standard nl80211 testmode interface. Also fixes accumulated bit-rot revealed by enabling the flag: adds compat shim macros in `bes_log.h` for the legacy `bes2600_info()` / `bes2600_err()` / `bes2600_warn()` / `bes2600_dbg()` / `bes2600_err_with_cond()` family (which had no definition anywhere, despite ~41 call sites in testmode code), defines `BES2600_DBG_*` subsystem ids as 0 constants, and marks 3 TSM/roam-delay helpers in sta.c as `static` for `-Werror=missing-prototypes`. | +| 07 | `bes2600/tx-sdio-dma-oob` | `10a05d2` | tx-bounce -- Fix a KFENCE OOB read in the SDIO TX path. `sdio_tx_work()` handed dma_map_sg a block-aligned length (`blks * cur_blksize`, or 1632) but `tx_buffer->buf` is only `tx_buffer->len` bytes long (aliases into an skb linear head sized by `pskb_expand_head` / TCP). DMA read up to one block past the skb -- KFENCE fires `out-of-bounds read in __pi_memcpy_generic` / `sdio_tx_work+0x2b4` / `bes_sdio_memcpy_to_io_helper+0x18c`, and the padding bytes are transmitted to the peer (kernel-memory leak to air). Allocate a driver-owned DMA-pages bounce buffer of `MAX_SDIO_TRANSFER_LEN`, memcpy each TX buffer into its slot, zero-pad, and point SG entries at the bounce. Separate from `single_gathered_buffer` (that one is bus-serialised via `sdio_claim_host` but `sdio_tx_work` accumulates SG entries before claiming). | -Total: +45 / −576 lines excluding commit messages. +Total: +117 / -550 lines excluding commit messages. ## Driver lineage (for the cover letter) @@ -32,9 +39,9 @@ already in mainline at `drivers/net/wireless/st/cw1200/`. Evidence: commit history). - Kconfig option names carry the ancestry: `CONFIG_BES2600_USE_STE_EXTENSIONS` (STE = ST-Ericsson), `CONFIG_BES2600_WSM_DEBUG` (WSM = CW1200's host - ↔ firmware Wireless Sensor Module protocol). + <-> firmware Wireless Sensor Module protocol). - File-layout parallel: `bh.c`, `hwio.c`, `fwio.c`, `queue.c`, `scan.c`, - `sta.c`, `txrx.c`, `wsm.c`, `pm.c`, `main.c` — same spine as CW1200, + `sta.c`, `txrx.c`, `wsm.c`, `pm.c`, `main.c` -- same spine as CW1200, plus BES-specific additions (ePTA coexistence, `bes2600_btuart`, 5 GHz support, `bes_pwr`, `bes2600_factory`, `itp`, `bes_chardev`). @@ -47,17 +54,17 @@ BES2600 driver upstream. Upstream today for BES2600 is fragmented: -- **`salsa.debian.org/Mobian-team/devices/bes2600-dkms`** — Mobian DKMS +- **`salsa.debian.org/Mobian-team/devices/bes2600-dkms`** -- Mobian DKMS package, actively maintained (last commit 2025-12). Primary PR target. -- **`codeberg.org/DanctNIX/linux-pinetab2`** — danctnix kernel fork; ships +- **`codeberg.org/DanctNIX/linux-pinetab2`** -- danctnix kernel fork; ships the driver in-tree at `drivers/staging/bes2600/` at tag `v6.19.10-danctnix1`. -- **`gitlab.com/arjanvlek/bes2600`** — original community fork; master was +- **`gitlab.com/arjanvlek/bes2600`** -- original community fork; master was sanitized in 2024-10 (`e5055a3 "Removed sources from main branch"`). `gitlab.com/TuxThePenguin0/bes2600` preserves the pre-sanitization snapshot. -The Mobian DKMS tree and the danctnix in-kernel tree have converged — 0- +The Mobian DKMS tree and the danctnix in-kernel tree have converged -- 0- hunk diff on `bes_pwr.c`, `bes2600_factory.c`, `wsm.c` between them. This series lands on Mobian first (branches already pushed to `git.reauktion.de/marfrit/bes2600-dkms`). @@ -79,14 +86,16 @@ Per-patch: - **c1.1**: factory-related log lines no longer carry the `(NULL device *):` prefix. - **c2**: pre-patch dmesg carried ~20-30 `wait pm ind timeout` messages - per 5 min and 2+ `sdio_tx_work` WARN splats; post-patch both counts are - 0 in the same window. `[RX] Receive failure: 4.` disappears too. + per 5 min and 2+ `sdio_tx_work` WARN splats; post-patch `wait pm ind + timeout` is 0 in the same window and `[RX] Receive failure: 4.` + disappears. A residual `sdio_tx_work+0x2b4` splat (~1 per reboot) still + recurred with c1..c6 alone; see c7 below for its root cause and fix. - **c3**: `/dev/bes2600` character device node is absent post-reboot; `lsmod | grep bes2600` still shows both `bes2600` and `bes2600_btuart` loaded and associated; WiFi continues to function. - **c4**: `iw phy0` now lists `testmode` under *Supported commands*; nl80211 testmode interface reachable via `iw phy0 testmode cmd ` - (not exercised end-to-end yet — depends on userspace tooling). + (not exercised end-to-end yet -- depends on userspace tooling). Full stack c1+c5+c1.1+c2+c3+c4: WiFi associates and passes traffic across 3+ reboots. @@ -114,18 +123,18 @@ Full stack c1+c5+c1.1+c2+c3+c4: WiFi associates and passes traffic across family still reads/writes a `bes_cdev` singleton. Threading `struct bes2600_common *` through those call sites (13 files) requires first replacing the `fw_type` module_param with a per-phy debugfs knob - or nl80211 testmode command — a migration that overlaps with c4's + or nl80211 testmode command -- a migration that overlaps with c4's testmode plumbing. Tracked as c3.1 (deferred). - One residual dmesg notice after the full stack: `bes2600_wlan mmc2:0001:1: PS Mode Error, Reason:1` at T+40s on fresh boot. Distinct - from the pre-c2 `wait pm ind timeout` cascade — benign, driver + from the pre-c2 `wait pm ind timeout` cascade -- benign, driver recovers, WiFi stays up. Root cause not investigated; candidate for a future c2.1 or firmware-RE follow-up. - Firmware RE (task d) was pursued briefly. The shipped firmware keeps many format-string literals (e.g. `patch_HI_Set_Coex_Params, hw_epta_ - enable:0x%x, new_run_flag:0x%x, gEptaBypass: %d`) as dead data — the + enable:0x%x, new_run_flag:0x%x, gEptaBypass: %d`) as dead data -- the string is in the blob but no code references it in any encoding. The compiler kept the literal while dead-stripping the `TRACE()` / `patch_*()` callers that would have used it. Takeaway: strings-mining @@ -136,7 +145,7 @@ Full stack c1+c5+c1.1+c2+c3+c4: WiFi associates and passes traffic across ### Near-term: Mobian DKMS merge request -All 6 branches are pushed to `git.reauktion.de/marfrit/bes2600-dkms` with +All 7 branches are pushed to `git.reauktion.de/marfrit/bes2600-dkms` with upstream set to `salsa.debian.org/Mobian-team/devices/bes2600-dkms`. To open an MR against Mobian: @@ -150,14 +159,15 @@ open an MR against Mobian: bes2600/factory-thread-dev \ bes2600/pm-gate-on-handshake \ bes2600/remove-chardev-user-interface \ - bes2600/enable-testmode; do + bes2600/enable-testmode \ + bes2600/tx-sdio-dma-oob; do git push salsa $br done ``` 3. For each branch open an MR against `Mobian-team/devices/bes2600-dkms:mobian`. Use the commit message as the MR description (it already reads as a standalone rationale). -4. Consider bundling into a single MR with all 6 commits if the Mobian +4. Consider bundling into a single MR with all 7 commits if the Mobian reviewer prefers series review. ### Near-term alt: danctnix linux-pinetab2 (codeberg) @@ -173,7 +183,7 @@ apply cleanly against tag `v6.19.10-danctnix1` and checkpatch-clean. Submission route: 1. Create a codeberg.org account + add your SSH key. -2. Fork `DanctNIX/linux-pinetab2` on codeberg; push the 6 commits as a +2. Fork `DanctNIX/linux-pinetab2` on codeberg; push the 7 commits as a branch `bes2600/staging-prep-series`. 3. Open a codeberg PR against `DanctNIX/linux-pinetab2:master` with the cover-letter content as PR description. @@ -181,14 +191,14 @@ Submission route: `@danctnix@social.treehouse.systems`). Their merge workflow may be more casual than formal PR review. -Mobian and danctnix share the bes2600 source — `bes_pwr.c`, +Mobian and danctnix share the bes2600 source -- `bes_pwr.c`, `bes2600_factory.c`, `wsm.c` all 0-hunk diff at the patched files. Landing in either benefits users of both. ### Longer-term: linux-wireless RFC for drivers/staging/bes2600/ This series cleans up the Mobian DKMS tree. A proper mainline staging -submission is bigger work — new Kconfig + Makefile integration under +submission is bigger work -- new Kconfig + Makefile integration under `drivers/staging/`, a MAINTAINERS entry for Markus Fritsche + CC Dmitry Tarnyagin for CW1200 lineage ack, cover-letter framing the driver as a new staging submission with the CW1200 ancestry cited so reviewers can @@ -196,7 +206,7 @@ contextualise the structural parallels. Gate: the `kernel_write()` / `filp_open()` leftovers (factory write-back, DPD-to-file, observe_file debug path) must all go before staging will -accept it — drivers/staging still has a nominal filter against direct +accept it -- drivers/staging still has a nominal filter against direct filesystem manipulation. Plan those as follow-up patches (c1.2, c1.3, c1.4) and include them in the staging series. diff --git a/patches/staging-prep-series-danctnix/0000-cover-letter.patch b/patches/staging-prep-series-danctnix/0000-cover-letter.patch index 51bdf119a..870126af1 100644 --- a/patches/staging-prep-series-danctnix/0000-cover-letter.patch +++ b/patches/staging-prep-series-danctnix/0000-cover-letter.patch @@ -1,134 +1,185 @@ -From 6f13e008d21d453db486f707f47340a0a17e650b Mon Sep 17 00:00:00 2001 +From 10a05d21bfe4563f963e16d65228fd7a713c143d Mon Sep 17 00:00:00 2001 +Message-ID: From: Markus Fritsche -Date: Wed, 22 Apr 2026 14:27:00 +0200 -Subject: [PATCH 0/6] bes2600: staging-prep cleanup for PineTab2 (BES2600WM) +Date: Thu, 23 Apr 2026 12:35:28 +0200 +Subject: [PATCH 0/7] bes2600: staging-prep cleanup for PineTab2 (BES2600WM) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit -This is the danctnix-layout variant of the bes2600 staging-prep series. -All six patches target `drivers/staging/bes2600/` in -`codeberg.org/DanctNIX/linux-pinetab2` at tag `v6.19.10-danctnix1`. Apply -cleanly, `checkpatch.pl --no-tree --strict` clean. +This series is a staging-prep cleanup for the out-of-tree Bestechnic +BES2600WM Wi-Fi/BT combo-chip driver as shipped by Mobian's bes2600-dkms +package (and in-tree at drivers/staging/bes2600/ in the danctnix +linux-pinetab2 fork). Target hardware is the Pine64 PineTab2 (RK3566 ++ BES2600WM, SDIO vendor 0xBE57 / device 0x2002). -The Mobian `bes2600-dkms` variant of this series (same content, paths -rooted at `bes2600/` rather than `drivers/staging/bes2600/`) lives at -`git.reauktion.de/marfrit/bes2600-dkms` branch -`bes2600/staging-prep-series`. If you maintain both trees, you may -prefer to apply there and propagate to the danctnix in-tree copy. +The driver descends from the ST-Ericsson CW1200 (drivers/net/wireless/ +st/cw1200/) -- same author, Dmitry Tarnyagin, shared WSM host<->firmware +protocol, shared SDIO bus backend. Kconfig ancestry markers survive in +this tree today: CONFIG_BES2600_USE_STE_EXTENSIONS (STE = ST-Ericsson), +CONFIG_BES2600_WSM_DEBUG (WSM). ST-Ericsson wound down in 2013; +Bestechnic (founded 2015) appears to have inherited or licensed the +CW1200 IP. No linux-wireless RFC has ever linked the two chips. -## Background - -The BES2600 Linux driver descends from the ST-Ericsson CW1200 driver in -mainline (`drivers/net/wireless/st/cw1200/`). Same author -- Dmitry -Tarnyagin; shared WSM host<->firmware protocol plumbing; shared SDIO bus -backend. Kconfig ancestry markers survive: `CONFIG_BES2600_USE_STE_EXTENSIONS` -(STE = ST-Ericsson), `CONFIG_BES2600_WSM_DEBUG` (WSM). ST-Ericsson was -wound down in 2013; Bestechnic (founded 2015) appears to have inherited -or licensed the CW1200 IP. No linux-wireless RFC has ever linked the two -chips. - -The series fixes observable defects on a PineTab2 running the danctnix -kernel 6.19.10-danctnix1-1 and removes two upstream blockers. Each -patch is independently testable and bisectable; the order below -preserves dependencies. +The series fixes observable defects on a PineTab2 running linux-pinetab2 +6.19.10-danctnix1-1 and removes two upstream blockers. Each patch is +independently testable and bisectable; the order below preserves +dependencies. ## What the series does -* 1/6 -- Replace `filp_open()` + `kernel_read()` in the factory- - calibration read path with `request_firmware()`. Repoint the - FACTORY_PATH macro to the firmware-class name - (`bes2600/bes2600_factory.txt`). Kills a kernel-mainline anti-pattern - and the `(NULL device *): read and check /lib/firmware/bes2600_factory.txt - error` boot spam. +* 1/7 -- Replace filp_open() + kernel_read() in the factory-calibration + read path with request_firmware(). Repoint the FACTORY_PATH macro to + the firmware-class name (bes2600/bes2600_factory.txt, matching the + /lib/firmware/ layout). Kills a kernel-mainline anti-pattern and the + '(NULL device *): read and check /lib/firmware/bes2600_factory.txt + error' boot spam on PineTab2. -* 2/6 -- Default `STANDARD_FACTORY_EFUSE_FLAG` from y to n. The shipped - `bes2600_factory.txt` on PineTab2 contains 30 calibration fields; the - driver was expecting 31 (including a `##select_efuse_flag` section +* 2/7 -- Default STANDARD_FACTORY_EFUSE_FLAG from y to n. The shipped + bes2600_factory.txt on PineTab2 contains 30 calibration fields; the + driver was expecting 31 (including a ##select_efuse_flag section absent from this firmware). Also unguards the - `wsm_save_factory_txt_to_mcu()` prototype in `wsm.h` which was - inconsistently wrapped in `#if defined(STANDARD_FACTORY_EFUSE_FLAG)` - while its definition in `wsm.c` and its call site in `sta.c` were - ungated. + wsm_save_factory_txt_to_mcu() prototype in wsm.h which was + inconsistently wrapped in '#if defined(STANDARD_FACTORY_EFUSE_FLAG)' + while its definition in wsm.c and its call site in sta.c were + ungated -- gcc -Werror=missing-prototypes broke the build with the + new default until this is fixed. -* 3/6 -- Thread `struct device *` through `factory_section_read_file()` - via a module-local setter invoked at SDIO probe. `request_firmware()` - now receives a real device pointer; `(NULL device *):` no longer - prefixes factory-related diagnostics. +* 3/7 -- Thread struct device * through factory_section_read_file() via + a module-local setter invoked at SDIO probe. request_firmware() now + receives a real device pointer; '(NULL device *):' no longer prefixes + factory-related diagnostics. -* 4/6 -- Gate the device-end of the low-power transition on successful - per-VIF firmware handshake. Pre-patch: `bes2600_pwr_enter_lp_mode()` - called `bes2600_pwr_device_enter_lp_mode()` unconditionally even when - `wait_for_completion_timeout()` returned 0. On PineTab2 this recurred - every 5-10 s in idle-associated state, flooded dmesg, and cascaded - into `sdio_tx_work` WARN splats. Post-patch: `-ETIMEDOUT` returned - cleanly, dmesg silent, SDIO stable. +* 4/7 -- Gate the device-end of the low-power transition on successful + per-VIF firmware handshake. Pre-patch bes2600_pwr_enter_lp_mode() + called bes2600_pwr_device_enter_lp_mode() unconditionally even when + wait_for_completion_timeout() returned 0 (firmware never posted the + PM-change indication). On PineTab2 this recurred every 5-10 s + whenever the interface was associated and idle, flooded dmesg, and + cascaded into sdio_tx_work WARN splats / [RX] Receive failure + messages. Post-patch: -ETIMEDOUT returned cleanly, dmesg silent, + SDIO stable. -* 5/6 -- Remove the custom `/dev/bes2600` character-device interface. - `file_operations`, open/read/write/release, `bes2600_op_*` command- - dispatch table, `bes2600_load_uevent`, cdev registration in the init - path -- 519 lines deleted. In-kernel accessors (`is_signal_mode`, - `get_fw_type`, etc., 13 call sites) and the `fw_type` module - parameter are preserved. +* 5/7 -- Remove the custom /dev/bes2600 character-device interface. + file_operations, open/read/write/release, bes2600_op_* + command-dispatch table, bes2600_load_uevent, alloc_chrdev_region / + cdev_init / cdev_add / class_create / device_create in the init + path, and the matching teardown in bes2600_chrdev_free -- 519 lines + deleted. The in-kernel accessor functions (is_signal_mode, + get_fw_type, etc., 13 call sites) and the fw_type module parameter + are preserved; the userspace interface becomes rfkill + module_param + + (with 6/7) nl80211 testmode. -* 6/6 -- Flip `CONFIG_BES2600_TESTMODE` default from n to y. Also fixes - accumulated bit-rot revealed by enabling the flag: shim macros in - `bes_log.h` for the legacy `bes2600_info/err/warn/dbg/err_with_cond` - family, `BES2600_DBG_*` constants defined as 0, 3 TSM/roam-delay - helpers marked `static`. +* 6/7 -- Flip CONFIG_BES2600_TESTMODE default from n to y. The driver + already implements a mac80211 testmode_cmd dispatcher (routing to + the firmware's patch_wifi_testMode path), already gated on the flag; + CONFIG_NL80211_TESTMODE=y is common on target kernels. Enabling the + flag also exposes accumulated bit-rot -- ~41 calls to undefined + bes2600_info/err/warn/dbg/err_with_cond macros, and 3 TSM/roam-delay + helpers with external linkage but no prototype. Add shim macros to + bes_log.h rewiring the legacy calls onto the existing bes_info / + bes_err / bes_warn / bes_devel family, define BES2600_DBG_* subsystem + ids as 0 constants, and mark the 3 helpers static. + +* 7/7 -- Bounce SDIO TX buffers to avoid DMA out-of-bounds reads. + sdio_tx_work() rounded the transfer length up to the SDIO block size + (align = blks * cur_blksize, or 1632) and handed that length to + dma_map_sg() via sg_set_buf(..., tx_buffer->buf, align); tx_buffer->buf + typically aliases into an skb linear head allocated to tx_buffer->len, + not the block-aligned length. The DMA engine therefore read up to one + block past the end of the skb -- KFENCE on PineTab2 fires as + 'out-of-bounds read in __pi_memcpy_generic ... 704B right of + kfence-#...' with sdio_tx_work+0x2b4 / bes_sdio_memcpy_to_io_helper in + the stack and pskb_expand_head / validate_xmit_skb / tcp_write_xmit in + the allocator stack. Besides being undefined behavior, the padding + bytes are transmitted to the peer, leaking adjacent kernel memory on + the air. Allocate a driver-owned DMA-pages bounce buffer of + MAX_SDIO_TRANSFER_LEN, memcpy each TX buffer into its slot, zero the + padding tail, and point the SG entries at the bounce. Mirrors the + pattern already used for single_gathered_buffer; kept as a separate + allocation because sdio_tx_work accumulates SG entries before claiming + the bus. ## Testing Reference hardware: Pine64 PineTab2 (BES2600WM + Rockchip RK3566, -MAC `8a:2e:77:1f:ec:05`). Host kernel: linux-pinetab2 -6.19.10-danctnix1-1 with `CONFIG_NL80211_TESTMODE=y`. Full stack -applied, verified over 3+ reboots: WiFi associates and passes traffic -on both 2.4 GHz (newton / ch11) and 5 GHz (TelekomHotspot@ERGO / ch36). +8a:2e:77:1f:ec:05, LAN AP newton @ 2.4 GHz ch11, tested also on +TelekomHotspot@ERGO @ 5 GHz ch36). -Per-patch outcomes in post-reboot dmesg: -- 1/6: `read and check /lib/firmware/bes2600_factory.txt error` -- gone -- 2/6: `bes2600_factory.txt parse fail` / `factory cali data get failed.` -- gone -- 3/6: `(NULL device *):` prefix on factory lines -- gone -- 4/6: `wait pm ind timeout` (pre-patch 20-30 msgs / 5 min) -- 0 per 5 min; - `sdio_tx_work` WARN splat (pre-patch 2+ / 5 min) -- 0 per 5 min; - `[RX] Receive failure: 4.` -- gone -- 5/6: `/dev/bes2600` -- absent; driver continues to associate -- 6/6: `iw phy0` lists `testmode` under *Supported commands* +Host kernel: linux-pinetab2 6.19.10-danctnix1-1-pinetab2 with +CONFIG_NL80211_TESTMODE=y and CONFIG_KFENCE=y (for 7/7 verification). +Driver installed via /lib/modules//extra/ and verified loaded via +modinfo srcversion. + +Per-patch outcomes in post-reboot dmesg (full-stack applied, 11+ min +soak, 245k RX packets / 365 MB traffic): + +- 1/7: 'read and check /lib/firmware/bes2600_factory.txt error' -- gone +- 2/7: 'bes2600_factory.txt parse fail' / 'factory cali data get + failed.' -- gone +- 3/7: '(NULL device *):' prefix on factory lines -- gone +- 4/7: 'bes2600_pwr_enter_lp_mode, wait pm ind timeout' (pre-patch 20-30 + msgs / 5 min window) -- 0 per 5 min; '[RX] Receive failure: 4.' -- + gone +- 5/7: /dev/bes2600 -- absent; driver continues to associate +- 6/7: 'iw phy0' lists 'testmode' under Supported commands; module + builds cleanly +- 7/7: 'BUG: KFENCE: out-of-bounds read in __pi_memcpy_generic' + (pre-patch ~65 splats per 4 h of real traffic, always via + sdio_tx_work+0x2b4 / bes_sdio_memcpy_to_io_helper+0x18c) -- 0; + 'sdio_tx_work+0x2b4' WARN splat residual from 4/7's cascade -- 0 + (previously recurred ~1 per reboot even with 4/7 applied); + 'PS Mode Error, Reason:1' benign handshake notice at T+40s -- + also gone, apparently a downstream effect of no longer DMAing + uninitialised padding bytes into firmware + +Full stack: wifi associates and passes traffic across 3+ reboots. ## Known limitations / out of scope -- `factory_section_write_file()` still uses `kernel_write()` + `filp_open()` - for calibration persistence. Conversion to debugfs/nl80211 is a +- factory_section_write_file() in bes2600_factory.c still uses + kernel_write() + filp_open(O_CREAT) to persist per-channel + calibration updates back to /lib/firmware/bes2600_factory.txt. + Converting the write-back path to debugfs or nl80211 testmode is a follow-up. -- `bes_chardev.c` still contains DPD-to-file read/write paths (gated by - `BES2600_WRITE_DPD_TO_FILE`, off by default -- dead code in default - builds). Same treatment needed. -- `bes_fw.c:587` unconditionally creates - `/lib/firmware/bes2002_fw_write.bin` via `filp_open()` for debug - observation. Must go before a future drivers/net/wireless/st/ - promotion. -- `bes_cdev` singleton still holds `sig_mode`/`fw_type`. Migrating - fw_type from module_param to per-phy debugfs knob or nl80211 testmode - is the next architectural step. -- Residual benign dmesg: `bes2600_wlan mmc2:0001:1: PS Mode Error, - Reason:1` at T+40 s on fresh boot. Distinct from the pre-4/6 timeout - cascade; driver recovers, WiFi stays up. -Markus Fritsche (6): +- bes_chardev.c still carries DPD file-read/write paths gated by + BES2600_WRITE_DPD_TO_FILE (off by default, so dead code in the + default build). Same treatment needed. + +- bes_fw.c:587 unconditionally creates + /lib/firmware/bes2002_fw_write.bin via filp_open() for debug + observation. Needs to go before drivers/staging/ accepts the driver. + +- bes_cdev global singleton still holds sig_mode and fw_type. Moving + those to per-hw_priv state is blocked by fw_type being a module + parameter (inherently singleton). Migrating fw_type to a per-phy + debugfs knob or nl80211 testmode command is the next step; overlaps + with 6/7's testmode plumbing. + +Markus Fritsche (7): bes2600: use request_firmware() for factory.txt read - bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2 factory.txt format - bes2600: thread struct device * through factory request_firmware() call - bes2600: gate device LP-mode entry on successful per-VIF firmware handshake + bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2 + factory.txt format + bes2600: thread struct device * through factory request_firmware() + call + bes2600: gate device LP-mode entry on successful per-VIF firmware + handshake bes2600: remove userspace /dev/bes2600 character device interface - bes2600: enable CONFIG_BES2600_TESTMODE by default + fix bit-rotted testmode plumbing + bes2600: enable CONFIG_BES2600_TESTMODE by default + fix bit-rotted + testmode plumbing + bes2600: bounce SDIO TX buffers to avoid DMA OOB read drivers/staging/bes2600/Makefile | 6 +- - drivers/staging/bes2600/bes2600_factory.c | 45 +-- + drivers/staging/bes2600/bes2600_factory.c | 45 ++-- drivers/staging/bes2600/bes2600_factory.h | 3 + - drivers/staging/bes2600/bes2600_sdio.c | 4 + - drivers/staging/bes2600/bes_chardev.c | 519 -------------------------------- + drivers/staging/bes2600/bes2600_sdio.c | 43 +++- + drivers/staging/bes2600/bes_chardev.c | 519 -------------------------------------- drivers/staging/bes2600/bes_log.h | 23 ++ drivers/staging/bes2600/bes_pwr.c | 20 +- drivers/staging/bes2600/sta.c | 6 +- drivers/staging/bes2600/wsm.h | 2 - - 9 files changed, 79 insertions(+), 549 deletions(-) + 9 files changed, 117 insertions(+), 550 deletions(-) -- 2.53.0 diff --git a/patches/staging-prep-series-danctnix/0001-bes2600-use-request_firmware-for-factory.txt-read.patch b/patches/staging-prep-series-danctnix/0001-bes2600-use-request_firmware-for-factory.txt-read.patch index 0b13769c5..34031bf8c 100644 --- a/patches/staging-prep-series-danctnix/0001-bes2600-use-request_firmware-for-factory.txt-read.patch +++ b/patches/staging-prep-series-danctnix/0001-bes2600-use-request_firmware-for-factory.txt-read.patch @@ -1,7 +1,10 @@ -From 30a51afef7db9c4ce964cfbb2ffd15ed9eeadab0 Mon Sep 17 00:00:00 2001 +From d18aa6a9bc03a03e455434f83577892aa1a60ffe Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 10:09:44 +0200 -Subject: [PATCH 1/6] bes2600: use request_firmware() for factory.txt read +Subject: [PATCH 1/7] bes2600: use request_firmware() for factory.txt read The BES2600 factory calibration file (bes2600_factory.txt) was being read via filp_open() + kernel_read() from a hard-coded absolute path baked in @@ -59,11 +62,11 @@ exposed and tracked separately). Signed-off-by: Markus Fritsche --- drivers/staging/bes2600/Makefile | 2 +- - drivers/staging/bes2600/bes2600_factory.c | 33 ++++++++++------------- + drivers/staging/bes2600/bes2600_factory.c | 33 ++++++++++++++------------------- 2 files changed, 15 insertions(+), 20 deletions(-) -diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile -index df5e55d..95b07fa 100644 +diff --git a/drivers/staging/bes2600/Makefile b/bes2600/Makefile +index 300912b..788aee2 100644 --- a/drivers/staging/bes2600/Makefile +++ b/drivers/staging/bes2600/Makefile @@ -66,7 +66,7 @@ BES2600_DRV_VERSION := bes2600_0.3.5_2024.0116 @@ -71,11 +74,11 @@ index df5e55d..95b07fa 100644 FACTORY_CRC_CHECK ?= n STANDARD_FACTORY_EFUSE_FLAG ?= y -FACTORY_PATH ?= /lib/firmware/bes2600_factory.txt -+FACTORY_PATH ?= bes2600/bes2600_factory.txt ++FACTORY_PATH ?= drivers/staging/bes2600/bes2600_factory.txt endif # basic function -diff --git a/drivers/staging/bes2600/bes2600_factory.c b/drivers/staging/bes2600/bes2600_factory.c +diff --git a/drivers/staging/bes2600/bes2600_factory.c b/bes2600/bes2600_factory.c index dc5d3da..8d60b7c 100644 --- a/drivers/staging/bes2600/bes2600_factory.c +++ b/drivers/staging/bes2600/bes2600_factory.c diff --git a/patches/staging-prep-series-danctnix/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch b/patches/staging-prep-series-danctnix/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch index d59ac0029..2af11a2f3 100644 --- a/patches/staging-prep-series-danctnix/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch +++ b/patches/staging-prep-series-danctnix/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch @@ -1,7 +1,10 @@ -From 6cc2efd4dfbb6358e2d458398afcebda4e05ffe6 Mon Sep 17 00:00:00 2001 +From a826f4db7d97a3a872d92079db37dbdaf9a0cdec Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 12:17:56 +0200 -Subject: [PATCH 2/6] bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for +Subject: [PATCH 2/7] bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2 factory.txt format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -23,7 +26,7 @@ The PineTab2 factory.txt has no select_efuse_flag section, so sscanf stops after field 30 and factory_parse() returns -1 with: bes2600_factory.txt parse fail - read and check bes2600/bes2600_factory.txt error + read and check drivers/staging/bes2600/bes2600_factory.txt error factory cali data get failed. This was latent until the preceding patch (use request_firmware() for @@ -53,8 +56,8 @@ Signed-off-by: Markus Fritsche drivers/staging/bes2600/wsm.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) -diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile -index 95b07fa..4ea2424 100644 +diff --git a/drivers/staging/bes2600/Makefile b/bes2600/Makefile +index 788aee2..2dcba09 100644 --- a/drivers/staging/bes2600/Makefile +++ b/drivers/staging/bes2600/Makefile @@ -65,7 +65,7 @@ BES2600_DRV_VERSION := bes2600_0.3.5_2024.0116 @@ -63,10 +66,10 @@ index 95b07fa..4ea2424 100644 FACTORY_CRC_CHECK ?= n -STANDARD_FACTORY_EFUSE_FLAG ?= y +STANDARD_FACTORY_EFUSE_FLAG ?= n - FACTORY_PATH ?= bes2600/bes2600_factory.txt + FACTORY_PATH ?= drivers/staging/bes2600/bes2600_factory.txt endif -diff --git a/drivers/staging/bes2600/wsm.h b/drivers/staging/bes2600/wsm.h +diff --git a/drivers/staging/bes2600/wsm.h b/bes2600/wsm.h index 0673131..22845ac 100644 --- a/drivers/staging/bes2600/wsm.h +++ b/drivers/staging/bes2600/wsm.h diff --git a/patches/staging-prep-series-danctnix/0003-bes2600-thread-struct-device-through-factory-request.patch b/patches/staging-prep-series-danctnix/0003-bes2600-thread-struct-device-through-factory-request.patch index 7344eb435..28966a2f6 100644 --- a/patches/staging-prep-series-danctnix/0003-bes2600-thread-struct-device-through-factory-request.patch +++ b/patches/staging-prep-series-danctnix/0003-bes2600-thread-struct-device-through-factory-request.patch @@ -1,7 +1,10 @@ -From cfbbf5d5430925e2175f53f153c482cb17520d6d Mon Sep 17 00:00:00 2001 +From c7ba2044b78cc3778763737daea60c9912b710c6 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 13:18:38 +0200 -Subject: [PATCH 3/6] bes2600: thread struct device * through factory +Subject: [PATCH 3/7] bes2600: thread struct device * through factory request_firmware() call Follow-up to \"bes2600: use request_firmware() for factory.txt read\". @@ -43,7 +46,7 @@ Signed-off-by: Markus Fritsche drivers/staging/bes2600/bes2600_sdio.c | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) -diff --git a/drivers/staging/bes2600/bes2600_factory.c b/drivers/staging/bes2600/bes2600_factory.c +diff --git a/drivers/staging/bes2600/bes2600_factory.c b/bes2600/bes2600_factory.c index 8d60b7c..1cda447 100644 --- a/drivers/staging/bes2600/bes2600_factory.c +++ b/drivers/staging/bes2600/bes2600_factory.c @@ -75,7 +78,7 @@ index 8d60b7c..1cda447 100644 if (ret) { bes_devel("BES2600: request_firmware(%s) failed: %d\n", path, ret); return -1; -diff --git a/drivers/staging/bes2600/bes2600_factory.h b/drivers/staging/bes2600/bes2600_factory.h +diff --git a/drivers/staging/bes2600/bes2600_factory.h b/bes2600/bes2600_factory.h index 3835b0d..7dbe9f8 100644 --- a/drivers/staging/bes2600/bes2600_factory.h +++ b/drivers/staging/bes2600/bes2600_factory.h @@ -89,8 +92,8 @@ index 3835b0d..7dbe9f8 100644 /* read wifi & bt factory cali value*/ u8* bes2600_get_factory_cali_data(u8 *file_buffer, u32 *data_len, char *path); void factory_little_endian_cvrt(u8 *data); -diff --git a/drivers/staging/bes2600/bes2600_sdio.c b/drivers/staging/bes2600/bes2600_sdio.c -index 13d4ff1..f172d53 100644 +diff --git a/drivers/staging/bes2600/bes2600_sdio.c b/bes2600/bes2600_sdio.c +index b595365..371ef4f 100644 --- a/drivers/staging/bes2600/bes2600_sdio.c +++ b/drivers/staging/bes2600/bes2600_sdio.c @@ -30,6 +30,7 @@ diff --git a/patches/staging-prep-series-danctnix/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch b/patches/staging-prep-series-danctnix/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch index c93fe6063..965f0eeed 100644 --- a/patches/staging-prep-series-danctnix/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch +++ b/patches/staging-prep-series-danctnix/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch @@ -1,7 +1,10 @@ -From 28a5de5303e72ff0670ee2e3509088c228270829 Mon Sep 17 00:00:00 2001 +From 108d3967eac4ba3a6e0f508d865a5f221b49079d Mon Sep 17 00:00:00 2001 +Message-ID: <108d3967eac4ba3a6e0f508d865a5f221b49079d.1776940528.git.fritsche.markus@gmail.com> +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 12:37:45 +0200 -Subject: [PATCH 4/6] bes2600: gate device LP-mode entry on successful per-VIF +Subject: [PATCH 4/7] bes2600: gate device LP-mode entry on successful per-VIF firmware handshake bes2600_pwr_enter_lp_mode() drives the transition to low-power for each @@ -49,7 +52,7 @@ Signed-off-by: Markus Fritsche drivers/staging/bes2600/bes_pwr.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) -diff --git a/drivers/staging/bes2600/bes_pwr.c b/drivers/staging/bes2600/bes_pwr.c +diff --git a/drivers/staging/bes2600/bes_pwr.c b/bes2600/bes_pwr.c index e7a1045..f62ae22 100644 --- a/drivers/staging/bes2600/bes_pwr.c +++ b/drivers/staging/bes2600/bes_pwr.c diff --git a/patches/staging-prep-series-danctnix/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch b/patches/staging-prep-series-danctnix/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch index e9be73374..c32880575 100644 --- a/patches/staging-prep-series-danctnix/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch +++ b/patches/staging-prep-series-danctnix/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch @@ -1,7 +1,10 @@ -From adb2cb22a8189ee6d2de5521e65aed63aebf1d09 Mon Sep 17 00:00:00 2001 +From 3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f Mon Sep 17 00:00:00 2001 +Message-ID: <3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f.1776940528.git.fritsche.markus@gmail.com> +In-Reply-To: +References: From: Markus Fritsche -Date: Wed, 22 Apr 2026 13:04:27 +0200 -Subject: [PATCH 5/6] bes2600: remove userspace /dev/bes2600 character device +Date: Wed, 22 Apr 2026 12:55:18 +0200 +Subject: [PATCH 5/7] bes2600: remove userspace /dev/bes2600 character device interface bes_chardev.c implemented a custom character device at /dev/bes2600 with @@ -73,11 +76,11 @@ Follow-ups: Signed-off-by: Markus Fritsche --- - drivers/staging/bes2600/bes_chardev.c | 519 -------------------------- + drivers/staging/bes2600/bes_chardev.c | 519 ------------------------------------------ 1 file changed, 519 deletions(-) -diff --git a/drivers/staging/bes2600/bes_chardev.c b/drivers/staging/bes2600/bes_chardev.c -index f89dcb8..455108a 100644 +diff --git a/drivers/staging/bes2600/bes_chardev.c b/bes2600/bes_chardev.c +index 9038e48..e2e4f1b 100644 --- a/drivers/staging/bes2600/bes_chardev.c +++ b/drivers/staging/bes2600/bes_chardev.c @@ -43,12 +43,6 @@ enum bus_probe_state { @@ -93,9 +96,9 @@ index f89dcb8..455108a 100644 atomic_t num_proc; wait_queue_head_t open_wq; spinlock_t status_lock; -@@ -290,351 +284,18 @@ int bes2600_chrdev_switch_subsys_glb(int wifi, int bt) +@@ -249,351 +243,18 @@ int bes2600_switch_bt(bool on) + return ret; } - EXPORT_SYMBOL_GPL(bes2600_chrdev_switch_subsys_glb); -static int bes2600_get_cmd_and_ifname(const char *str, char **result) -{ @@ -119,7 +122,7 @@ index f89dcb8..455108a 100644 - if (!tmp_ptr) { - return -2; - } - +- - strncpy(tmp_ptr, str+7, ifname_len); - tmp_ptr[ifname_len] = '\0'; - result[0] = tmp_ptr; @@ -150,33 +153,33 @@ index f89dcb8..455108a 100644 - - return 0; -} - +- -static void bes2600_recyle_cmd_and_ifname_mem(char **info) -{ - if (info[0]) { - kfree(info[0]); - info[0] = NULL; - } - +- - if (info[1]) { - kfree(info[1]); - info[1] = NULL; - } - +- -} - +- -static int bes2600_op_default_handler(const char *str) -{ - char *info[2] = {0}; - +- - if (bes2600_get_cmd_and_ifname(str, info) == 0) { - bes_devel("cmd(%s) on %s not handled\n", info[1], info[0]); - } else { - bes_err("%s get command fail, the origin string is %s\n", __func__, str); - } - +- - bes2600_recyle_cmd_and_ifname_mem(info); - +- - return 0; -} - @@ -344,8 +347,8 @@ index f89dcb8..455108a 100644 - WARN_ON(status <= 0); - - ret = (status <= 0 || bes2600_chrdev_is_bus_error()) ? -1 : 0; -- -- + + - return ret; -} - @@ -360,7 +363,7 @@ index f89dcb8..455108a 100644 - return -EFAULT; - } - spin_unlock(&bes2600_cdev.status_lock); -- + - /* wait probe done event */ - status = wait_event_timeout(bes2600_cdev.probe_done_wq, - bes2600_bootup_end(), HZ * 8); @@ -384,26 +387,26 @@ index f89dcb8..455108a 100644 - return -EFAULT; - } - spin_unlock(&bes2600_cdev.status_lock); -- + - /* wait probe done event */ - status = wait_event_timeout(bes2600_cdev.probe_done_wq, - bes2600_bootup_end(), HZ * 8); - if (status <= 0 || bes2600_chrdev_is_bus_error()) - return -EFAULT; -- + - bes_devel("bes2600 allow bt sleep.\n"); - ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_LP_OFF, SUBSYSTEM_BT_LP, false); -- + - return ret; -} -- + -static int bes2600_op_set_wakeup_read_flag(const char *str) -{ - bes_devel("%s is called, arg:%s\n", __func__, str); - spin_lock(&bes2600_cdev.status_lock); - bes2600_cdev.read_flag = BES_CDEV_READ_WAKEUP_STATE; - spin_unlock(&bes2600_cdev.status_lock); -- + - return 0; -} @@ -445,7 +448,7 @@ index f89dcb8..455108a 100644 static int bes2600_chrdev_check_system_close_internal(void) { -@@ -644,123 +305,10 @@ static int bes2600_chrdev_check_system_close_internal(void) +@@ -603,123 +264,10 @@ static int bes2600_chrdev_check_system_close_internal(void) && (bes2600_cdev.wifi_opened == false); } @@ -456,20 +459,20 @@ index f89dcb8..455108a 100644 - (atomic_read(&bes2600_cdev.num_proc) == 0), - MAX_SCHEDULE_TIMEOUT); - } -- + - bes_devel("bes2600 char device is opened\n"); - atomic_inc(&bes2600_cdev.num_proc); -- + - return 0; -} -- + -static ssize_t bes2600_chrdev_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - char buf[64] = {0}; - unsigned int len; - long status = 0; -- + - switch (bes2600_cdev.read_flag) { - case BES_CDEV_READ_WAKEUP_STATE: - if (bes2600_chrdev_wakeup_by_event_get() > WAKEUP_EVENT_NONE) { @@ -546,18 +549,18 @@ index f89dcb8..455108a 100644 - - return (ret == 0) ? count : ret; -} - +- -static int bes2600_chrdev_release (struct inode *inode, struct file *file) -{ - if (atomic_dec_and_test(&bes2600_cdev.num_proc)) { - wake_up(&bes2600_cdev.open_wq); - } - +- - bes_devel("bes2600 char device is closed\n"); - +- - return 0; -} - +- -static struct file_operations bes2600_chardev_fops = -{ - .owner = THIS_MODULE, @@ -569,7 +572,7 @@ index f89dcb8..455108a 100644 #ifdef BES2600_WRITE_DPD_TO_FILE static int bes2600_chrdev_write_dpd_data_to_file(const char *path, void *buffer, int size) -@@ -1167,12 +715,6 @@ void bes2600_chrdev_update_signal_mode(void) +@@ -1124,12 +672,6 @@ void bes2600_chrdev_update_signal_mode(void) static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work) { @@ -582,7 +585,7 @@ index f89dcb8..455108a 100644 if (bes2600_chrdev_is_wifi_opened()) { bes_devel("system exeception, force wifi down\n"); -@@ -1189,14 +731,6 @@ static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work) +@@ -1146,14 +688,6 @@ static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work) bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops, bes2600_cdev.sbus_priv); } @@ -597,7 +600,7 @@ index f89dcb8..455108a 100644 } } -@@ -1290,46 +824,6 @@ int bes2600_chrdev_wakeup_by_event_get(void) +@@ -1247,46 +781,6 @@ int bes2600_chrdev_wakeup_by_event_get(void) int bes2600_chrdev_init(struct sbus_ops *ops) { @@ -644,7 +647,7 @@ index f89dcb8..455108a 100644 /* initialise global variable */ atomic_set(&bes2600_cdev.num_proc, 0); init_waitqueue_head(&bes2600_cdev.open_wq); -@@ -1361,15 +855,6 @@ int bes2600_chrdev_init(struct sbus_ops *ops) +@@ -1318,15 +812,6 @@ int bes2600_chrdev_init(struct sbus_ops *ops) bes_devel("%s done\n", __func__); return 0; @@ -660,7 +663,7 @@ index f89dcb8..455108a 100644 } void bes2600_chrdev_free(void) -@@ -1379,9 +864,5 @@ void bes2600_chrdev_free(void) +@@ -1336,9 +821,5 @@ void bes2600_chrdev_free(void) bes2600_free_dpd_log_buffer(); #endif bes2600_chrdev_free_dpd_data(); diff --git a/patches/staging-prep-series-danctnix/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch b/patches/staging-prep-series-danctnix/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch index 34a3699a4..c20de2663 100644 --- a/patches/staging-prep-series-danctnix/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch +++ b/patches/staging-prep-series-danctnix/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch @@ -1,7 +1,10 @@ -From f1d22ab91dbc0d12064f672300fec5ec0ff220e3 Mon Sep 17 00:00:00 2001 +From 6f13e008d21d453db486f707f47340a0a17e650b Mon Sep 17 00:00:00 2001 +Message-ID: <6f13e008d21d453db486f707f47340a0a17e650b.1776940528.git.fritsche.markus@gmail.com> +In-Reply-To: +References: From: Markus Fritsche -Date: Wed, 22 Apr 2026 14:26:43 +0200 -Subject: [PATCH 6/6] bes2600: enable CONFIG_BES2600_TESTMODE by default + fix +Date: Wed, 22 Apr 2026 13:04:27 +0200 +Subject: [PATCH 6/7] bes2600: enable CONFIG_BES2600_TESTMODE by default + fix bit-rotted testmode plumbing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -63,11 +66,11 @@ Signed-off-by: Markus Fritsche drivers/staging/bes2600/sta.c | 6 +++--- 3 files changed, 27 insertions(+), 4 deletions(-) -diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile -index 4ea2424..aecb302 100644 +diff --git a/drivers/staging/bes2600/Makefile b/bes2600/Makefile +index 2dcba09..2c1a850 100644 --- a/drivers/staging/bes2600/Makefile +++ b/drivers/staging/bes2600/Makefile -@@ -2,7 +2,7 @@ KERN_DIR = /lib/modules/$(shell uname -r)/build +@@ -2,7 +2,7 @@ KERN_DIR = /lib/modules/$(KERNELRELEASE)/build # feature option BES2600 ?= m @@ -76,7 +79,7 @@ index 4ea2424..aecb302 100644 CONFIG_BES2600_ENABLE_DEVEL_LOGS ?= n -diff --git a/drivers/staging/bes2600/bes_log.h b/drivers/staging/bes2600/bes_log.h +diff --git a/drivers/staging/bes2600/bes_log.h b/bes2600/bes_log.h index 605cea8..65cf703 100644 --- a/drivers/staging/bes2600/bes_log.h +++ b/drivers/staging/bes2600/bes_log.h @@ -107,11 +110,11 @@ index 605cea8..65cf703 100644 + if (_cond) \ + bes_err(fmt, ##__VA_ARGS__); \ + } while (0) -diff --git a/drivers/staging/bes2600/sta.c b/drivers/staging/bes2600/sta.c -index ca1c77c..bc6d483 100644 +diff --git a/drivers/staging/bes2600/sta.c b/bes2600/sta.c +index aa69eb8..5f1a456 100644 --- a/drivers/staging/bes2600/sta.c +++ b/drivers/staging/bes2600/sta.c -@@ -3654,7 +3654,7 @@ static int bes2600_set_power_save(struct ieee80211_hw *hw, +@@ -3633,7 +3633,7 @@ static int bes2600_set_power_save(struct ieee80211_hw *hw, * * Returns: 0 on success or non zero value on failure */ @@ -120,7 +123,7 @@ index ca1c77c..bc6d483 100644 { struct bes_msg_start_stop_tsm *start_stop_tsm = (struct bes_msg_start_stop_tsm *) data; -@@ -3684,7 +3684,7 @@ int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data) +@@ -3663,7 +3663,7 @@ int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data) * * Returns: TSM parameters collected */ @@ -129,7 +132,7 @@ index ca1c77c..bc6d483 100644 { struct bes2600_common *hw_priv = hw->priv; struct bes_tsm_stats tsm_stats; -@@ -3724,7 +3724,7 @@ int bes2600_get_tsm_params(struct ieee80211_hw *hw) +@@ -3703,7 +3703,7 @@ int bes2600_get_tsm_params(struct ieee80211_hw *hw) * * Returns: Returns the last measured roam delay */ diff --git a/patches/staging-prep-series-danctnix/0007-bes2600-bounce-SDIO-TX-buffers-to-avoid-DMA-OOB-read.patch b/patches/staging-prep-series-danctnix/0007-bes2600-bounce-SDIO-TX-buffers-to-avoid-DMA-OOB-read.patch new file mode 100644 index 000000000..eb045c402 --- /dev/null +++ b/patches/staging-prep-series-danctnix/0007-bes2600-bounce-SDIO-TX-buffers-to-avoid-DMA-OOB-read.patch @@ -0,0 +1,126 @@ +From 10a05d21bfe4563f963e16d65228fd7a713c143d Mon Sep 17 00:00:00 2001 +Message-ID: <10a05d21bfe4563f963e16d65228fd7a713c143d.1776940528.git.fritsche.markus@gmail.com> +In-Reply-To: +References: +From: Markus Fritsche +Date: Thu, 23 Apr 2026 11:58:31 +0200 +Subject: [PATCH 7/7] bes2600: bounce SDIO TX buffers to avoid DMA OOB read + +The SDIO TX path rounds the DMA transfer length up to the host's +current block size and hands that length to dma_map_sg() via +sg_set_buf(&sg[scatters], tx_buffer->buf, align) in sdio_tx_work(). +tx_buffer->buf typically aliases into an skb linear head whose +allocated size matches tx_buffer->len, not the block-aligned +align. The DMA engine (swiotlb / dw_mci IDMAC) therefore reads up +to one block past the end of the skb. On a PineTab2 with KFENCE +enabled this fires as: + + BUG: KFENCE: out-of-bounds read in __pi_memcpy_generic + Out-of-bounds read at ... (704B right of kfence-#...): + __pi_memcpy_generic + swiotlb_tbl_map_single + swiotlb_map + dma_direct_map_sg + __dma_map_sg_attrs + dma_map_sg_attrs + dw_mci_pre_dma_transfer + __dw_mci_start_request + ... + bes_sdio_memcpy_to_io_helper+0x18c/0x288 [bes2600] + sdio_tx_work+0x2b4/0x4a0 [bes2600] + +allocated by ... pskb_expand_head / validate_xmit_skb / tcp_* + +In addition to being undefined behavior, the padding bytes (which +come from whatever memory follows the skb) are transmitted to the +peer, leaking kernel memory on the air. + +Allocate a driver-owned DMA-page bounce buffer sized to +MAX_SDIO_TRANSFER_LEN and use it as the scatter-gather backing for +sdio_tx_work. Each TX buffer is copied into its bounce slot and the +tail (align - tx_buffer->len bytes) is zeroed. This mirrors the +existing bounce pattern already used by bes2600_sdio_memcpy_toio() +via single_gathered_buffer; a separate allocation is used for the +TX path because single_gathered_buffer is only serialised via +sdio_claim_host and sdio_tx_work accumulates scatter entries before +claiming the bus. + +Signed-off-by: Markus Fritsche +--- + drivers/staging/bes2600/bes2600_sdio.c | 39 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 38 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/bes2600/bes2600_sdio.c b/bes2600/bes2600_sdio.c +index 371ef4f..3e04e8c 100644 +--- a/drivers/staging/bes2600/bes2600_sdio.c ++++ b/drivers/staging/bes2600/bes2600_sdio.c +@@ -95,6 +95,7 @@ struct sbus_priv { + struct work_struct tx_work; + struct scatterlist tx_sg[BES_SDIO_TX_MULTIPLE_NUM + 1]; + struct scatterlist tx_sg_nosignal[BES_SDIO_TX_MULTIPLE_NUM_NOSIGNAL + 1]; ++ u8 *tx_bounce; + u32 tx_data_cnt; + u32 tx_xfer_cnt; + u32 tx_proc_cnt; +@@ -1136,7 +1137,26 @@ static void sdio_tx_work(struct work_struct *work) + } + } + +- sg_set_buf(&sg[scatters], tx_buffer->buf, align); ++ /* ++ * The transfer length is rounded up to the SDIO block ++ * size, but tx_buffer->buf is only tx_buffer->len bytes ++ * long (it usually aliases into an skb linear head). ++ * Copy into a driver-owned bounce buffer and zero-pad ++ * to the aligned size; otherwise DMA reads past the ++ * skb and leaks adjacent kernel memory on the wire -- ++ * observed as KFENCE OOB reads from ++ * bes_sdio_memcpy_to_io_helper via dma_map_sg. ++ */ ++ if (WARN_ON_ONCE(total_len + align > MAX_SDIO_TRANSFER_LEN)) ++ goto flush_previous; ++ memcpy(self->tx_bounce + total_len, ++ tx_buffer->buf, tx_buffer->len); ++ if (align > tx_buffer->len) ++ memset(self->tx_bounce + total_len + ++ tx_buffer->len, 0, ++ align - tx_buffer->len); ++ sg_set_buf(&sg[scatters], ++ self->tx_bounce + total_len, align); + total_len += align; + ++scatters; + /*del_node:*/ +@@ -1857,6 +1877,17 @@ static int bes2600_sdio_probe(struct sdio_func *func, + if (!self->single_gathered_buffer) + return -ENOMEM; + #endif ++#ifdef BES_SDIO_TX_MULTIPLE_ENABLE ++ self->tx_bounce = (u8 *)__get_dma_pages(GFP_KERNEL, ++ get_order(MAX_SDIO_TRANSFER_LEN)); ++ if (!self->tx_bounce) { ++#ifndef SDIO_HOST_ADMA_SUPPORT ++ free_pages((unsigned long)self->single_gathered_buffer, ++ get_order(MAX_SDIO_TRANSFER_LEN)); ++#endif ++ return -ENOMEM; ++ } ++#endif + #ifdef BES_SDIO_RXTX_TOGGLE + self->fw_started = false; + #endif +@@ -1985,6 +2016,12 @@ static void bes2600_sdio_remove(struct sdio_func *func) + if (self->single_gathered_buffer) { + free_pages((unsigned long)self->single_gathered_buffer, get_order(MAX_SDIO_TRANSFER_LEN)); + } ++#endif ++#ifdef BES_SDIO_TX_MULTIPLE_ENABLE ++ if (self->tx_bounce) { ++ free_pages((unsigned long)self->tx_bounce, ++ get_order(MAX_SDIO_TRANSFER_LEN)); ++ } + #endif + kfree(self); + } +-- +2.53.0 + diff --git a/patches/staging-prep-series/0000-cover-letter.patch b/patches/staging-prep-series/0000-cover-letter.patch index a9f5fd24e..d219a8467 100644 --- a/patches/staging-prep-series/0000-cover-letter.patch +++ b/patches/staging-prep-series/0000-cover-letter.patch @@ -1,7 +1,11 @@ -From 6f13e008d21d453db486f707f47340a0a17e650b Mon Sep 17 00:00:00 2001 +From 10a05d21bfe4563f963e16d65228fd7a713c143d Mon Sep 17 00:00:00 2001 +Message-ID: From: Markus Fritsche -Date: Wed, 22 Apr 2026 14:15:56 +0200 -Subject: [PATCH 0/6] bes2600: staging-prep cleanup for PineTab2 (BES2600WM) +Date: Thu, 23 Apr 2026 12:35:28 +0200 +Subject: [PATCH 0/7] bes2600: staging-prep cleanup for PineTab2 (BES2600WM) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit This series is a staging-prep cleanup for the out-of-tree Bestechnic BES2600WM Wi-Fi/BT combo-chip driver as shipped by Mobian's bes2600-dkms @@ -24,14 +28,14 @@ dependencies. ## What the series does -* 1/6 -- Replace filp_open() + kernel_read() in the factory-calibration +* 1/7 -- Replace filp_open() + kernel_read() in the factory-calibration read path with request_firmware(). Repoint the FACTORY_PATH macro to the firmware-class name (bes2600/bes2600_factory.txt, matching the /lib/firmware/ layout). Kills a kernel-mainline anti-pattern and the '(NULL device *): read and check /lib/firmware/bes2600_factory.txt error' boot spam on PineTab2. -* 2/6 -- Default STANDARD_FACTORY_EFUSE_FLAG from y to n. The shipped +* 2/7 -- Default STANDARD_FACTORY_EFUSE_FLAG from y to n. The shipped bes2600_factory.txt on PineTab2 contains 30 calibration fields; the driver was expecting 31 (including a ##select_efuse_flag section absent from this firmware). Also unguards the @@ -41,12 +45,12 @@ dependencies. ungated -- gcc -Werror=missing-prototypes broke the build with the new default until this is fixed. -* 3/6 -- Thread struct device * through factory_section_read_file() via +* 3/7 -- Thread struct device * through factory_section_read_file() via a module-local setter invoked at SDIO probe. request_firmware() now receives a real device pointer; '(NULL device *):' no longer prefixes factory-related diagnostics. -* 4/6 -- Gate the device-end of the low-power transition on successful +* 4/7 -- Gate the device-end of the low-power transition on successful per-VIF firmware handshake. Pre-patch bes2600_pwr_enter_lp_mode() called bes2600_pwr_device_enter_lp_mode() unconditionally even when wait_for_completion_timeout() returned 0 (firmware never posted the @@ -56,7 +60,7 @@ dependencies. messages. Post-patch: -ETIMEDOUT returned cleanly, dmesg silent, SDIO stable. -* 5/6 -- Remove the custom /dev/bes2600 character-device interface. +* 5/7 -- Remove the custom /dev/bes2600 character-device interface. file_operations, open/read/write/release, bes2600_op_* command-dispatch table, bes2600_load_uevent, alloc_chrdev_region / cdev_init / cdev_add / class_create / device_create in the init @@ -64,9 +68,9 @@ dependencies. deleted. The in-kernel accessor functions (is_signal_mode, get_fw_type, etc., 13 call sites) and the fw_type module parameter are preserved; the userspace interface becomes rfkill + module_param - + (with 6/6) nl80211 testmode. + + (with 6/7) nl80211 testmode. -* 6/6 -- Flip CONFIG_BES2600_TESTMODE default from n to y. The driver +* 6/7 -- Flip CONFIG_BES2600_TESTMODE default from n to y. The driver already implements a mac80211 testmode_cmd dispatcher (routing to the firmware's patch_wifi_testMode path), already gated on the flag; CONFIG_NL80211_TESTMODE=y is common on target kernels. Enabling the @@ -77,6 +81,25 @@ dependencies. bes_err / bes_warn / bes_devel family, define BES2600_DBG_* subsystem ids as 0 constants, and mark the 3 helpers static. +* 7/7 -- Bounce SDIO TX buffers to avoid DMA out-of-bounds reads. + sdio_tx_work() rounded the transfer length up to the SDIO block size + (align = blks * cur_blksize, or 1632) and handed that length to + dma_map_sg() via sg_set_buf(..., tx_buffer->buf, align); tx_buffer->buf + typically aliases into an skb linear head allocated to tx_buffer->len, + not the block-aligned length. The DMA engine therefore read up to one + block past the end of the skb -- KFENCE on PineTab2 fires as + 'out-of-bounds read in __pi_memcpy_generic ... 704B right of + kfence-#...' with sdio_tx_work+0x2b4 / bes_sdio_memcpy_to_io_helper in + the stack and pskb_expand_head / validate_xmit_skb / tcp_write_xmit in + the allocator stack. Besides being undefined behavior, the padding + bytes are transmitted to the peer, leaking adjacent kernel memory on + the air. Allocate a driver-owned DMA-pages bounce buffer of + MAX_SDIO_TRANSFER_LEN, memcpy each TX buffer into its slot, zero the + padding tail, and point the SG entries at the bounce. Mirrors the + pattern already used for single_gathered_buffer; kept as a separate + allocation because sdio_tx_work accumulates SG entries before claiming + the bus. + ## Testing Reference hardware: Pine64 PineTab2 (BES2600WM + Rockchip RK3566, @@ -84,21 +107,31 @@ Reference hardware: Pine64 PineTab2 (BES2600WM + Rockchip RK3566, TelekomHotspot@ERGO @ 5 GHz ch36). Host kernel: linux-pinetab2 6.19.10-danctnix1-1-pinetab2 with -CONFIG_NL80211_TESTMODE=y. Driver installed via -/lib/modules//extra/ and verified loaded via modinfo srcversion. +CONFIG_NL80211_TESTMODE=y and CONFIG_KFENCE=y (for 7/7 verification). +Driver installed via /lib/modules//extra/ and verified loaded via +modinfo srcversion. -Per-patch outcomes in post-reboot dmesg (full-stack applied): -- 1/6: 'read and check /lib/firmware/bes2600_factory.txt error' -- gone -- 2/6: 'bes2600_factory.txt parse fail' / 'factory cali data get +Per-patch outcomes in post-reboot dmesg (full-stack applied, 11+ min +soak, 245k RX packets / 365 MB traffic): + +- 1/7: 'read and check /lib/firmware/bes2600_factory.txt error' -- gone +- 2/7: 'bes2600_factory.txt parse fail' / 'factory cali data get failed.' -- gone -- 3/6: '(NULL device *):' prefix on factory lines -- gone -- 4/6: 'bes2600_pwr_enter_lp_mode, wait pm ind timeout' (pre-patch 20-30 - msgs / 5 min window) -- 0 per 5 min; 'sdio_tx_work' WARN splat - (pre-patch 2+ / 5 min) -- 0 per 5 min; '[RX] Receive failure: 4.' -- +- 3/7: '(NULL device *):' prefix on factory lines -- gone +- 4/7: 'bes2600_pwr_enter_lp_mode, wait pm ind timeout' (pre-patch 20-30 + msgs / 5 min window) -- 0 per 5 min; '[RX] Receive failure: 4.' -- gone -- 5/6: /dev/bes2600 -- absent; driver continues to associate -- 6/6: 'iw phy0' lists 'testmode' under Supported commands; module +- 5/7: /dev/bes2600 -- absent; driver continues to associate +- 6/7: 'iw phy0' lists 'testmode' under Supported commands; module builds cleanly +- 7/7: 'BUG: KFENCE: out-of-bounds read in __pi_memcpy_generic' + (pre-patch ~65 splats per 4 h of real traffic, always via + sdio_tx_work+0x2b4 / bes_sdio_memcpy_to_io_helper+0x18c) -- 0; + 'sdio_tx_work+0x2b4' WARN splat residual from 4/7's cascade -- 0 + (previously recurred ~1 per reboot even with 4/7 applied); + 'PS Mode Error, Reason:1' benign handshake notice at T+40s -- + also gone, apparently a downstream effect of no longer DMAing + uninitialised padding bytes into firmware Full stack: wifi associates and passes traffic across 3+ reboots. @@ -122,14 +155,9 @@ Full stack: wifi associates and passes traffic across 3+ reboots. those to per-hw_priv state is blocked by fw_type being a module parameter (inherently singleton). Migrating fw_type to a per-phy debugfs knob or nl80211 testmode command is the next step; overlaps - with 6/6's testmode plumbing. + with 6/7's testmode plumbing. -- One residual benign notice after the full stack: 'bes2600_wlan - mmc2:0001:1: PS Mode Error, Reason:1' at T+40s on fresh boot. - Distinct from the pre-4/6 timeout cascade; driver recovers, WiFi - stays up. Root cause not investigated. - -Markus Fritsche (6): +Markus Fritsche (7): bes2600: use request_firmware() for factory.txt read bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2 factory.txt format @@ -140,17 +168,18 @@ Markus Fritsche (6): bes2600: remove userspace /dev/bes2600 character device interface bes2600: enable CONFIG_BES2600_TESTMODE by default + fix bit-rotted testmode plumbing + bes2600: bounce SDIO TX buffers to avoid DMA OOB read bes2600/Makefile | 6 +- bes2600/bes2600_factory.c | 45 ++-- bes2600/bes2600_factory.h | 3 + - bes2600/bes2600_sdio.c | 4 + + bes2600/bes2600_sdio.c | 43 +++- bes2600/bes_chardev.c | 519 -------------------------------------- bes2600/bes_log.h | 23 ++ bes2600/bes_pwr.c | 20 +- bes2600/sta.c | 6 +- bes2600/wsm.h | 2 - - 9 files changed, 79 insertions(+), 549 deletions(-) + 9 files changed, 117 insertions(+), 550 deletions(-) -- 2.53.0 diff --git a/patches/staging-prep-series/0001-bes2600-use-request_firmware-for-factory.txt-read.patch b/patches/staging-prep-series/0001-bes2600-use-request_firmware-for-factory.txt-read.patch index bc5dd3957..5f65b9c54 100644 --- a/patches/staging-prep-series/0001-bes2600-use-request_firmware-for-factory.txt-read.patch +++ b/patches/staging-prep-series/0001-bes2600-use-request_firmware-for-factory.txt-read.patch @@ -1,7 +1,10 @@ From d18aa6a9bc03a03e455434f83577892aa1a60ffe Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 10:09:44 +0200 -Subject: [PATCH 1/6] bes2600: use request_firmware() for factory.txt read +Subject: [PATCH 1/7] bes2600: use request_firmware() for factory.txt read The BES2600 factory calibration file (bes2600_factory.txt) was being read via filp_open() + kernel_read() from a hard-coded absolute path baked in diff --git a/patches/staging-prep-series/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch b/patches/staging-prep-series/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch index b53f9d364..187277deb 100644 --- a/patches/staging-prep-series/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch +++ b/patches/staging-prep-series/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch @@ -1,7 +1,10 @@ From a826f4db7d97a3a872d92079db37dbdaf9a0cdec Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 12:17:56 +0200 -Subject: [PATCH 2/6] bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for +Subject: [PATCH 2/7] bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2 factory.txt format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 diff --git a/patches/staging-prep-series/0003-bes2600-thread-struct-device-through-factory-request.patch b/patches/staging-prep-series/0003-bes2600-thread-struct-device-through-factory-request.patch index e697bd5ba..68fcea166 100644 --- a/patches/staging-prep-series/0003-bes2600-thread-struct-device-through-factory-request.patch +++ b/patches/staging-prep-series/0003-bes2600-thread-struct-device-through-factory-request.patch @@ -1,7 +1,10 @@ From c7ba2044b78cc3778763737daea60c9912b710c6 Mon Sep 17 00:00:00 2001 +Message-ID: +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 13:18:38 +0200 -Subject: [PATCH 3/6] bes2600: thread struct device * through factory +Subject: [PATCH 3/7] bes2600: thread struct device * through factory request_firmware() call Follow-up to \"bes2600: use request_firmware() for factory.txt read\". diff --git a/patches/staging-prep-series/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch b/patches/staging-prep-series/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch index e4617c406..cb99f2b01 100644 --- a/patches/staging-prep-series/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch +++ b/patches/staging-prep-series/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch @@ -1,7 +1,10 @@ From 108d3967eac4ba3a6e0f508d865a5f221b49079d Mon Sep 17 00:00:00 2001 +Message-ID: <108d3967eac4ba3a6e0f508d865a5f221b49079d.1776940528.git.fritsche.markus@gmail.com> +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 12:37:45 +0200 -Subject: [PATCH 4/6] bes2600: gate device LP-mode entry on successful per-VIF +Subject: [PATCH 4/7] bes2600: gate device LP-mode entry on successful per-VIF firmware handshake bes2600_pwr_enter_lp_mode() drives the transition to low-power for each diff --git a/patches/staging-prep-series/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch b/patches/staging-prep-series/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch index 64a54d2f0..28ab2957a 100644 --- a/patches/staging-prep-series/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch +++ b/patches/staging-prep-series/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch @@ -1,7 +1,10 @@ From 3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f Mon Sep 17 00:00:00 2001 +Message-ID: <3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f.1776940528.git.fritsche.markus@gmail.com> +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 12:55:18 +0200 -Subject: [PATCH 5/6] bes2600: remove userspace /dev/bes2600 character device +Subject: [PATCH 5/7] bes2600: remove userspace /dev/bes2600 character device interface bes_chardev.c implemented a custom character device at /dev/bes2600 with diff --git a/patches/staging-prep-series/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch b/patches/staging-prep-series/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch index aec6a59c2..8df3e44ed 100644 --- a/patches/staging-prep-series/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch +++ b/patches/staging-prep-series/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch @@ -1,7 +1,10 @@ From 6f13e008d21d453db486f707f47340a0a17e650b Mon Sep 17 00:00:00 2001 +Message-ID: <6f13e008d21d453db486f707f47340a0a17e650b.1776940528.git.fritsche.markus@gmail.com> +In-Reply-To: +References: From: Markus Fritsche Date: Wed, 22 Apr 2026 13:04:27 +0200 -Subject: [PATCH 6/6] bes2600: enable CONFIG_BES2600_TESTMODE by default + fix +Subject: [PATCH 6/7] bes2600: enable CONFIG_BES2600_TESTMODE by default + fix bit-rotted testmode plumbing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 diff --git a/patches/staging-prep-series/0007-bes2600-bounce-SDIO-TX-buffers-to-avoid-DMA-OOB-read.patch b/patches/staging-prep-series/0007-bes2600-bounce-SDIO-TX-buffers-to-avoid-DMA-OOB-read.patch new file mode 100644 index 000000000..b876ad851 --- /dev/null +++ b/patches/staging-prep-series/0007-bes2600-bounce-SDIO-TX-buffers-to-avoid-DMA-OOB-read.patch @@ -0,0 +1,126 @@ +From 10a05d21bfe4563f963e16d65228fd7a713c143d Mon Sep 17 00:00:00 2001 +Message-ID: <10a05d21bfe4563f963e16d65228fd7a713c143d.1776940528.git.fritsche.markus@gmail.com> +In-Reply-To: +References: +From: Markus Fritsche +Date: Thu, 23 Apr 2026 11:58:31 +0200 +Subject: [PATCH 7/7] bes2600: bounce SDIO TX buffers to avoid DMA OOB read + +The SDIO TX path rounds the DMA transfer length up to the host's +current block size and hands that length to dma_map_sg() via +sg_set_buf(&sg[scatters], tx_buffer->buf, align) in sdio_tx_work(). +tx_buffer->buf typically aliases into an skb linear head whose +allocated size matches tx_buffer->len, not the block-aligned +align. The DMA engine (swiotlb / dw_mci IDMAC) therefore reads up +to one block past the end of the skb. On a PineTab2 with KFENCE +enabled this fires as: + + BUG: KFENCE: out-of-bounds read in __pi_memcpy_generic + Out-of-bounds read at ... (704B right of kfence-#...): + __pi_memcpy_generic + swiotlb_tbl_map_single + swiotlb_map + dma_direct_map_sg + __dma_map_sg_attrs + dma_map_sg_attrs + dw_mci_pre_dma_transfer + __dw_mci_start_request + ... + bes_sdio_memcpy_to_io_helper+0x18c/0x288 [bes2600] + sdio_tx_work+0x2b4/0x4a0 [bes2600] + +allocated by ... pskb_expand_head / validate_xmit_skb / tcp_* + +In addition to being undefined behavior, the padding bytes (which +come from whatever memory follows the skb) are transmitted to the +peer, leaking kernel memory on the air. + +Allocate a driver-owned DMA-page bounce buffer sized to +MAX_SDIO_TRANSFER_LEN and use it as the scatter-gather backing for +sdio_tx_work. Each TX buffer is copied into its bounce slot and the +tail (align - tx_buffer->len bytes) is zeroed. This mirrors the +existing bounce pattern already used by bes2600_sdio_memcpy_toio() +via single_gathered_buffer; a separate allocation is used for the +TX path because single_gathered_buffer is only serialised via +sdio_claim_host and sdio_tx_work accumulates scatter entries before +claiming the bus. + +Signed-off-by: Markus Fritsche +--- + bes2600/bes2600_sdio.c | 39 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 38 insertions(+), 1 deletion(-) + +diff --git a/bes2600/bes2600_sdio.c b/bes2600/bes2600_sdio.c +index 371ef4f..3e04e8c 100644 +--- a/bes2600/bes2600_sdio.c ++++ b/bes2600/bes2600_sdio.c +@@ -95,6 +95,7 @@ struct sbus_priv { + struct work_struct tx_work; + struct scatterlist tx_sg[BES_SDIO_TX_MULTIPLE_NUM + 1]; + struct scatterlist tx_sg_nosignal[BES_SDIO_TX_MULTIPLE_NUM_NOSIGNAL + 1]; ++ u8 *tx_bounce; + u32 tx_data_cnt; + u32 tx_xfer_cnt; + u32 tx_proc_cnt; +@@ -1136,7 +1137,26 @@ static void sdio_tx_work(struct work_struct *work) + } + } + +- sg_set_buf(&sg[scatters], tx_buffer->buf, align); ++ /* ++ * The transfer length is rounded up to the SDIO block ++ * size, but tx_buffer->buf is only tx_buffer->len bytes ++ * long (it usually aliases into an skb linear head). ++ * Copy into a driver-owned bounce buffer and zero-pad ++ * to the aligned size; otherwise DMA reads past the ++ * skb and leaks adjacent kernel memory on the wire -- ++ * observed as KFENCE OOB reads from ++ * bes_sdio_memcpy_to_io_helper via dma_map_sg. ++ */ ++ if (WARN_ON_ONCE(total_len + align > MAX_SDIO_TRANSFER_LEN)) ++ goto flush_previous; ++ memcpy(self->tx_bounce + total_len, ++ tx_buffer->buf, tx_buffer->len); ++ if (align > tx_buffer->len) ++ memset(self->tx_bounce + total_len + ++ tx_buffer->len, 0, ++ align - tx_buffer->len); ++ sg_set_buf(&sg[scatters], ++ self->tx_bounce + total_len, align); + total_len += align; + ++scatters; + /*del_node:*/ +@@ -1857,6 +1877,17 @@ static int bes2600_sdio_probe(struct sdio_func *func, + if (!self->single_gathered_buffer) + return -ENOMEM; + #endif ++#ifdef BES_SDIO_TX_MULTIPLE_ENABLE ++ self->tx_bounce = (u8 *)__get_dma_pages(GFP_KERNEL, ++ get_order(MAX_SDIO_TRANSFER_LEN)); ++ if (!self->tx_bounce) { ++#ifndef SDIO_HOST_ADMA_SUPPORT ++ free_pages((unsigned long)self->single_gathered_buffer, ++ get_order(MAX_SDIO_TRANSFER_LEN)); ++#endif ++ return -ENOMEM; ++ } ++#endif + #ifdef BES_SDIO_RXTX_TOGGLE + self->fw_started = false; + #endif +@@ -1985,6 +2016,12 @@ static void bes2600_sdio_remove(struct sdio_func *func) + if (self->single_gathered_buffer) { + free_pages((unsigned long)self->single_gathered_buffer, get_order(MAX_SDIO_TRANSFER_LEN)); + } ++#endif ++#ifdef BES_SDIO_TX_MULTIPLE_ENABLE ++ if (self->tx_bounce) { ++ free_pages((unsigned long)self->tx_bounce, ++ get_order(MAX_SDIO_TRANSFER_LEN)); ++ } + #endif + kfree(self); + } +-- +2.53.0 +