[PATCH AUTOSEL 6.18-6.6] wifi: ath12k: fix scan command endianness on big endian

Sasha Levin sashal at kernel.org
Mon Oct 19 06:48:45 PDT 2026


From: Alexander Wilhelm <alexander.wilhelm at westermo.com>

[ Upstream commit 6c90f68f97de591e0413f7d2de59449a0388bbab ]

ath12k_wmi_scan_req_arg stores scan parameters in CPU-native byte order,
while ath12k_wmi_send_scan_start_cmd() writes them into a WMI command
buffer whose contents must be in little-endian format. The existing code
copies the channel list and writes s_ssid and hint_bssid related values to
the command buffer without endian conversion. As a result, scan requests
contain invalid parameters on big-endian systems and fail.

Convert the channel list as well as the s_ssid and hint_bssid related
values to little-endian before writing them to the WMI command buffer. This
preserves the existing behaviour on little-endian systems while fixing scan
requests on big-endian architectures.

Signed-off-by: Alexander Wilhelm <alexander.wilhelm at westermo.com>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram at oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang at oss.qualcomm.com>
Link: https://patch.msgid.link/20260703-fix-channel-list-copy-v2-1-372c39306d79@westermo.com
Signed-off-by: Jeff Johnson <jeff.johnson at oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---

LLM Generated explanations, may be completely bogus:

The local tree is **v7.3-rc4** (mainline). The buggy ath12k scan path is
present here, and this is a small, real endianness fix for scan commands
on big-endian hosts.

---

## PHASE 1: COMMIT MESSAGE FORENSICS

**Step 1.1: PARSE THE SUBJECT LINE**
- Record: **[ath12k / wifi] [fix] [scan WMI command missing little-
  endian conversion on big-endian]**

**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
- Record:
  - No `Fixes:` tag (expected for this review)
  - No `Reported-by:` / `Tested-by:` / `Cc: stable`
  - `Reviewed-by: Rameshkumar Sundaram
    <rameshkumar.sundaram at oss.qualcomm.com>` (Qualcomm ath12k)
  - `Reviewed-by: Baochen Qiang <baochen.qiang at oss.qualcomm.com>`
    (Qualcomm ath12k)
  - `Link: https://patch.msgid.link/20260703-fix-channel-list-
    copy-v2-1-372c39306d79 at westermo.com`
  - `Signed-off-by: Alexander Wilhelm <alexander.wilhelm at westermo.com>`
    (author; Westermo)
  - `Signed-off-by: Jeff Johnson <jeff.johnson at oss.qualcomm.com>`
    (ath12k maintainer; applied)
  - Ignore pipeline-added Sasha Levin SOB if present (not on this
    commit)

**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
- Record:
  - **Bug:** `ath12k_wmi_scan_req_arg` is CPU-endian; the WMI start-scan
    buffer must be little-endian. Channel list is `memcpy`'d; `s_ssid` /
    `hint_bssid` integers are assigned without `cpu_to_le32`.
  - **Symptom:** scan start commands carry invalid channel/hint values
    on big-endian; scans fail.
  - **Root cause:** missing endian conversion on those TLV payloads
    (other scalar fields in the same function already use
    `cpu_to_le32`).
  - **Version info:** none in the message. Buggy code dates to the
    original ath12k driver.

**Step 1.4: DETECT HIDDEN BUG FIXES**
- Record: **Not a hidden fix.** Subject and body state an endianness
  correctness bug. Not cleanup/refactor.

---

## PHASE 2: DIFF ANALYSIS

**Step 2.1: INVENTORY THE CHANGES**
- Record:
  - `drivers/net/wireless/ath/ath12k/wmi.c`: 20 insertions / 8 deletions
  - `drivers/net/wireless/ath/ath12k/wmi.h`: 10 insertions
  - **Net:** +22 / −8, two files
  - **Function:** `ath12k_wmi_send_scan_start_cmd()`
  - **Scope:** single-function surgical fix plus two local wire-format
    structs

**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
- Record:
  - **Channel list:** `memcpy` of host `u32` channel frequencies → per-
    element `cpu_to_le32` into `__le32 *`.
  - **Hint short SSID:** raw `u32` assigns → `cpu_to_le32` into
    `ath12k_wmi_hint_short_ssid_params` (`__le32` fields).
  - **Hint BSSID:** `freq_flags` raw assign → `cpu_to_le32` into
    `ath12k_wmi_hint_bssid_params`.
  - **Normal path** (every scan start), not an error-only path. LE
    behavior unchanged (`cpu_to_le32` is identity on LE).

**Step 2.3: IDENTIFY THE BUG MECHANISM**
- Record: **[Type / endianness]** Host-endian `u32`s were placed in a LE
  WMI buffer. Firmware then sees swapped channel numbers (e.g. 2412 /
  `0x0000096c` becomes `0x6c090000`) and rejects or mis-handles the
  scan.

**Step 2.4: ASSESS THE FIX QUALITY**
- Record: **Obviously correct.** Same function already converts
  `num_chan`, dwell times, SSID length, etc. with `cpu_to_le32`. New
  `*_params` structs match existing `ath12k_wmi_ssid_params` (`__le32
  ssid_len`). **Regression risk: very low** on LE; no
  API/locking/refcount change. Review found a pre-existing swapped
  `ether_addr_copy` on hint BSSID; that was **not** mixed into this
  patch (separate commit `7b0bd40e97a00`).

---

## PHASE 3: GIT HISTORY INVESTIGATION

**Step 3.1: BLAME THE CHANGED LINES**
- Record: Buggy `memcpy(tmp_ptr, arg->chan_list, ...)` and hint field
  copies come from **`d889913205cf7` (“wifi: ath12k: driver for Qualcomm
  Wi-Fi 7 devices”)**, Kalle Valo, 2022-11-28. First appeared in
  **v6.3-rc1**. Long-lived, not recent churn.

**Step 3.2: FOLLOW THE FIXES: TAG**
- Record: **No `Fixes:` tag.** Introduction commit is `d889913205cf7`,
  ancestor of this HEAD (`git merge-base --is-ancestor` of the fix
  itself is true). This tree contains both the original driver and the
  fix.

**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
- Record:
  - Immediate predecessor on this function: `7b0bd40e97a00` “Correctly
    copy the hint BSSID in WMI scan request” (same day in the ath tree).
    Independent bug (copy direction).
  - Later `wmi.c` commits (`c42b27336eeff`, TLV/overread fixes) do
    **not** revert or rework this endian conversion.
  - Same author earlier: `9eb6f553026e1` “enforce CPU endian format for
    all QMI data” — same BE enablement effort.
  - **Standalone** for the endian bug; not patch N/M of a series (v2 of
    a single patch).

**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
- Record: Alexander Wilhelm (Westermo) has ath12k BE work; not the
  subsystem maintainer. Applied by **Jeff Johnson** (Qualcomm ath12k
  maintainer) after Qualcomm reviews.

**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
- Record: No new helpers. Uses existing `cpu_to_le32`. Hint `*_params`
  structs are added in this patch. `7b0bd40e97a00` is **not** a semantic
  prerequisite for channel-list conversion; it only changes
  `ether_addr_copy` argument order. **Can apply standalone** (possible
  one-hunk context mismatch on trees that still have the swapped copy).

---

## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH

**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
- Record:
  - Lore/msgid: `https://patch.msgid.link/20260703-fix-channel-list-
    copy-v2-1-372c39306d79 at westermo.com`
  - **v1:** 2026-03-17? (msgid dated 2026-06-29) “fix channel list copy
    on big endian”
  - **v2:** 2026-07-03 “fix scan command endianness on big endian” —
    rebase; also convert `s_ssid` / `hint_bssid`; reworded message
  - Applied version is **v2** (latest).
  - **No NAK.** Baochen asked whether to also fix swapped
    `ether_addr_copy`; Jeff: **separate patch**. Rameshkumar and Baochen
    `Reviewed-by`. Jeff: “Applied, thanks!”
  - **No reviewer `Cc: stable`.**

**Step 4.2: CHECK WHO REVIEWED THE PATCH**
- Record: Recipients: Jeff Johnson, Baochen Qiang, `linux-wireless`,
  `ath12k at lists.infradead.org`, `linux-kernel`. Right maintainers/lists.
  Two Qualcomm `Reviewed-by`s; maintainer applied it.

**Step 4.3: SEARCH FOR THE BUG REPORT**
- Record: No syzbot/bugzilla. Author is a vendor using BE + ath12k
  (consistent with their prior QMI endian patch). Failure mode described
  as scan failure, not a crash dump.

**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
- Record: Single-patch series. Related: `7b0bd40e97a00` (hint BSSID copy
  direction), prompted by Baochen on this thread. Not required for the
  channel-list endian fix.

**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
- Record: No stable-list discussion found for this subject. WebSearch on
  `lore.kernel.org/stable` did not return this patch. **UNVERIFIED**
  beyond that search (lore.kernel.org HTTP 403 from this environment).

---

## PHASE 5: CODE SEMANTIC ANALYSIS

**Step 5.1: IDENTIFY KEY FUNCTIONS**
- Record: `ath12k_wmi_send_scan_start_cmd()` only. New structs:
  `ath12k_wmi_hint_short_ssid_params`, `ath12k_wmi_hint_bssid_params`.

**Step 5.2: TRACE CALLERS**
- Record:
  - `ath12k_wmi_send_scan_start_cmd` ← `ath12k_start_scan`
    (`mac.c:5407`)
  - `ath12k_start_scan` ← hw scan (`mac.c:5727`, fills `chan_list[i] =
    chan_list[i]->center_freq`)
  - `ath12k_start_scan` ← remain-on-channel (`mac.c:14062`,
    `chan_list[0] = chan->center_freq`)
  - **Userspace-reachable** via nl80211 scan / ROC. Not IRQ.

**Step 5.3: TRACE CALLEES**
- Record: Builds a WMI skb (`ath12k_wmi_alloc_skb`), fills TLVs,
  `ath12k_wmi_cmd_send(..., WMI_START_SCAN_CMDID)`. Firmware then runs
  the scan.

**Step 5.4: FOLLOW THE CALL CHAIN**
- Record: cfg80211/mac80211 scan or ROC → `ath12k_mac` → WMI start-scan.
  **Yes, userspace-triggerable.** Channel list is always filled on those
  paths. `num_hint_s_ssid` / `num_hint_bssid` are **never assigned** in
  this tree (stay 0 from `kzalloc`); hint conversions are still correct
  but not the live bug. **The live bug is the channel list on every
  scan/ROC.**

**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
- Record: Other fields in the same command already use `cpu_to_le32`.
  `ath12k_wmi_ssid_params` already has `__le32 ssid_len`. Sibling ath11k
  `ath11k_wmi_send_scan_start_cmd` still copies `chan_list` as host
  `u32` without `cpu_to_le32` (ath11k WMI structs are less consistently
  `__le32`). Other ath12k endian fixes exist (`2adcddd8a316e` vdev
  create, `8f1a078842d4a` WMI service bits, `1cfa6d4e5bd9b` HAL TLV).

---

## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE

**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
- Record: **Yes.** Tree is **v7.3-rc4** (`7.3.0-rc4`, HEAD
  `f0100363d8c37`). ath12k and `ath12k_wmi_send_scan_start_cmd` exist.
  Bug introduced **v6.3**; not after this branch. The fix commit
  `6c90f68f97de5` is already an ancestor of HEAD; current `wmi.c`
  already has the `cpu_to_le32` channel loop. Evaluating technical merit
  for this codebase, not “already queued.”

**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
- Record: **Clean apply here** (already present). New structs are
  additive. On older stables without `7b0bd40e97a00`, one
  `ether_addr_copy` context hunk may need a trivial refresh; channel-
  list hunk is independent.

**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
- Record: This exact fix is in the tree. No alternate/earlier endian fix
  for this memcpy. No revert.

---

## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT

**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
- Record: **wifi / ath12k (Qualcomm Wi-Fi 7)** — **IMPORTANT** (not
  mm/core; real devices and scan/ROC depend on it).

**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
- Record: **Active** (frequent `wmi.c` fixes). This particular memcpy
  has been wrong since the driver landed in v6.3.

---

## PHASE 8: IMPACT AND RISK ASSESSMENT

**Step 8.1: DETERMINE WHO IS AFFECTED**
- Record: **Driver-specific + endian-specific:** `CONFIG_ATH12K` on big-
  endian CPUs. LE ath12k (typical x86/ARM) unchanged. Author affiliation
  indicates real BE industrial use.

**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
- Record: **Any scan or remain-on-channel.** Common for Wi-Fi (network
  manager, `iw scan`, P2P/ROC). Unprivileged users can trigger scans
  depending on policy; not a UAF/crash primitive. Not a race.

**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
- Record: **Scan/ROC commands invalid on BE → scan fails / association
  cannot find APs.** Not oops/deadlock/corruption. **Severity: HIGH**
  for BE ath12k (driver largely unusable for STA), **LOW** for LE
  majority.

**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
- Record:
  - **Benefit:** Restores scanning on BE ath12k; no-op on LE.
  - **Risk:** Very low (~22 lines, `cpu_to_le32` only, internal
    structs).
  - **Ratio:** Favorable. Classic endianness driver fix.

---

## PHASE 9: FINAL SYNTHESIS

**Step 9.1: COMPILE THE EVIDENCE**

**FOR backporting:**
- Real, user-visible bug: WMI scan channel list (and hint integers) not
  converted to LE.
- Hits every hw scan and ROC on BE; firmware gets garbage channel
  numbers.
- Small, matches existing conversions in the same function.
- Present since v6.3; this tree has the driver.
- Reviewed and applied by Qualcomm ath12k maintainers; v2 addressed
  review (hints + rebase).
- `cpu_to_le32` is identity on LE → negligible regression risk.
- Endianness/type bugs are a documented stable category.

**AGAINST:**
- Not crash/UAF/security/deadlock.
- BE + ath12k is a smaller population than x86/ARM LE.
- No `Fixes:` / `Cc: stable` / syzbot (absence expected; not a
  negative).
- Hint paths appear unused in this tree (still correct to convert).

**UNRESOLVED:**
- Full lore.kernel.org HTML was 403; thread recovered via `b4 dig -m`.
- No stable-list thread found.
- No in-tree test proving a specific BE board besides the author’s
  description.

**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — same conversion pattern as
   the rest of the command; Qualcomm review + maintainer apply. Author
   exercised BE.
2. Fixes a real bug that affects users? **PASS** — scans fail on BE.
3. Important issue? **PASS** — Wi-Fi scan/ROC broken on affected systems
   (endianness correctness), not a style tweak.
4. Small and contained? **PASS** — two files, +22/−8, one function.
5. No new features or APIs? **PASS** — internal `__le32` wire structs
   only.
6. Can apply to the local tree? **PASS** — ath12k WMI scan path exists
   here; hunks match.

**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
- Record: Not a device-ID/quirk/DT/build/docs exception. Standard
  correctness fix.

**Step 9.4: MAKE YOUR DECISION**
This tree has the ath12k scan WMI path introduced in v6.3. Missing
`cpu_to_le32` on the channel list makes scanning fail on big-endian; the
patch is small, matches existing WMI encoding, and is a no-op on little-
endian. It meets stable rules for this checkout.

---

## What the commit solves and why it matters

`ath12k_wmi_send_scan_start_cmd()` already converted scalar WMI fields
with `cpu_to_le32`, but copied `chan_list` with `memcpy` and assigned
hint integers in CPU order. On big-endian, firmware sees swapped
frequencies, so scan/ROC fail. Stable users of ath12k on BE cannot scan
or remain-on-channel without this. LE users see no behavior change.

## Risk vs benefit

Benefit is restoring a core Wi-Fi operation on BE. Risk is very low:
surgical conversions, no locking/API change, identity transform on LE.

## Concerns

No functional dependency on other patches for the channel-list fix. Hint
BSSID `ether_addr_copy` direction is a separate commit already in this
tree. Backport to older stables may need a one-line context tweak if
that copy-direction fix is absent.

---

## Verification
- [Phase 1] Parsed tags: two Qualcomm `Reviewed-by`; maintainer SOB;
  msgid.link; no Fixes/stable/syzbot
- [Phase 2] Diff: `wmi.c` + `wmi.h`, +22/−8; `memcpy` → `cpu_to_le32`
  loop; hint fields converted; two `__le32` structs added
- [Phase 3] `git describe HEAD`: `v7.3-rc4-27-gf0100363d8c37`; `make
  kernelversion`: `7.3.0-rc4`
- [Phase 3] `git merge-base --is-ancestor 6c90f68f97de5 HEAD`: yes (exit
  0)
- [Phase 3] `git blame` on parent: buggy memcpy/assigns from
  `d889913205cf7` (v6.3-rc1)
- [Phase 3] Related: `7b0bd40e97a00` hint BSSID copy; `9eb6f553026e1`
  QMI endian; no revert after this fix
- [Phase 4] `b4 dig -c 6c90f68f97de5`: v2 msgid `20260703-fix-channel-
  list-copy-v2-1-372c39306d79 at westermo.com`
- [Phase 4] `b4 dig -a`: v1 channel-list-only → v2 also converts hints
- [Phase 4] `b4 dig -w`: Jeff Johnson, Baochen Qiang, linux-wireless,
  ath12k list
- [Phase 4] mbox: Baochen/Rameshkumar R-b; Jeff applied; swapped
  `ether_addr_copy` deferred to separate patch (no NAK of endian fix)
- [Phase 4] lore.kernel.org fetch: 403; used b4 mbox + mirrors
- [Phase 4] stable list search: no discussion found
- [Phase 5] Callers: `ath12k_start_scan` ← hw scan (`mac.c:5727`) and
  ROC (`mac.c:14062`); both write `chan_list` as `center_freq`
- [Phase 5] `num_hint_*` never assigned in ath12k (remain 0)
- [Phase 6] Current tree already contains the converted loop at
  `wmi.c:2739-2740`
- [Phase 8] Failure: invalid WMI scan params on BE → scan failure; not
  oops
- UNVERIFIED: specific BE board log beyond commit text; full lore HTML

**YES**

 drivers/net/wireless/ath/ath12k/wmi.c | 20 ++++++++++++--------
 drivers/net/wireless/ath/ath12k/wmi.h | 10 ++++++++++
 2 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 39d5110eca901..91f293ab70137 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -2666,9 +2666,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 	struct wmi_tlv *tlv;
 	void *ptr;
 	int i, ret, len;
-	u32 *tmp_ptr, extraie_len_with_pad = 0;
-	struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL;
-	struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL;
+	__le32 *tmp_ptr;
+	u32 extraie_len_with_pad = 0;
+	struct ath12k_wmi_hint_short_ssid_params *s_ssid = NULL;
+	struct ath12k_wmi_hint_bssid_params *hint_bssid = NULL;
 
 	len = sizeof(*cmd);
 
@@ -2751,9 +2752,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 	tlv = ptr;
 	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, len);
 	ptr += TLV_HDR_SIZE;
-	tmp_ptr = (u32 *)ptr;
+	tmp_ptr = (__le32 *)ptr;
 
-	memcpy(tmp_ptr, arg->chan_list, arg->num_chan * 4);
+	for (i = 0; i < arg->num_chan; i++)
+		tmp_ptr[i] = cpu_to_le32(arg->chan_list[i]);
 
 	ptr += len;
 
@@ -2809,8 +2811,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 		ptr += TLV_HDR_SIZE;
 		s_ssid = ptr;
 		for (i = 0; i < arg->num_hint_s_ssid; ++i) {
-			s_ssid->freq_flags = arg->hint_s_ssid[i].freq_flags;
-			s_ssid->short_ssid = arg->hint_s_ssid[i].short_ssid;
+			s_ssid->freq_flags =
+				cpu_to_le32(arg->hint_s_ssid[i].freq_flags);
+			s_ssid->short_ssid =
+				cpu_to_le32(arg->hint_s_ssid[i].short_ssid);
 			s_ssid++;
 		}
 		ptr += len;
@@ -2824,7 +2828,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 		hint_bssid = ptr;
 		for (i = 0; i < arg->num_hint_bssid; ++i) {
 			hint_bssid->freq_flags =
-				arg->hint_bssid[i].freq_flags;
+				cpu_to_le32(arg->hint_bssid[i].freq_flags);
 			ether_addr_copy(&hint_bssid->bssid.addr[0],
 					&arg->hint_bssid[i].bssid.addr[0]);
 			hint_bssid++;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 6d9c645e3d5d0..6468d9738639e 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -3504,6 +3504,16 @@ struct ath12k_wmi_hint_bssid_arg {
 	struct ath12k_wmi_mac_addr_params bssid;
 };
 
+struct ath12k_wmi_hint_short_ssid_params {
+	__le32 freq_flags;
+	__le32 short_ssid;
+};
+
+struct ath12k_wmi_hint_bssid_params {
+	__le32 freq_flags;
+	struct ath12k_wmi_mac_addr_params bssid;
+};
+
 struct ath12k_wmi_scan_req_arg {
 	u32 scan_id;
 	u32 scan_req_id;
-- 
2.53.0




More information about the ath12k mailing list