| 0/0 |
2026/08/10 00:28 |
flow |
assessment-security |
1h14m
Results: map[DenialOfService:false Explanation:The bug report describes a `WARN_ONCE` triggered in `drv_unassign_vif_chanctx`
within the mac80211 subsystem.
### Root Cause Analysis
The warning is triggered by the `check_sdata_in_driver(sdata)` macro, which
checks if the `IEEE80211_SDATA_IN_DRIVER` flag is set on the sub-interface data
(`sdata`). If the flag is missing, it emits a warning and returns false, causing
`drv_unassign_vif_chanctx` to return early without calling the driver's
`unassign_vif_chanctx` callback.
This happens during the teardown of a wireless interface (e.g., an AP or a fully
associated STATION) when the underlying hardware is removed or unregistered. The
teardown sequence is as follows:
1. `cfg80211_shutdown_all_interfaces` calls `dev_close`, which eventually calls
`ieee80211_do_stop`.
2. `ieee80211_do_stop` calls `drv_remove_interface`, which clears the
`IEEE80211_SDATA_IN_DRIVER` flag, effectively removing the interface from the
driver's perspective.
3. Later in the teardown process, `cfg80211_unregister_wdev` calls
`unregister_netdevice_many`, which invokes the `ndo_uninit` callback
(`ieee80211_uninit`).
4. `ieee80211_uninit` calls `ieee80211_teardown_sdata`, which calls
`ieee80211_link_stop` and then `ieee80211_link_release_channel`.
5. `ieee80211_link_release_channel` attempts to unassign the channel context by
calling `drv_unassign_vif_chanctx`.
6. Since `IEEE80211_SDATA_IN_DRIVER` was already cleared in step 2, the
`check_sdata_in_driver` macro triggers the warning.
### Security Impact
**Exploitable:** No.
This is a harmless warning caused by a slightly out-of-order teardown sequence.
Returning early from `drv_unassign_vif_chanctx` is actually the correct and safe
behavior here, as calling the driver's `unassign_vif_chanctx` callback on an
interface that has already been removed (`drv_remove_interface`) could lead to a
crash or use-after-free in the driver. The channel context is still properly
unassigned and freed on the mac80211 side, so there are no resource leaks,
memory corruptions, or use-after-free vulnerabilities.
**Denial of Service:** No.
The bug is a `WARN_ONCE` and does not halt the kernel or cause any deadlocks. It
will not cause a denial of service in production builds (unless `panic_on_warn`
is explicitly enabled by the administrator).
**Trigger Vectors:**
- **Peripheral Trigger:** Yes. An attacker with physical access can trigger this
by physically unplugging a USB Wi-Fi dongle while an Access Point (AP) or a
connected STATION interface is running on it.
- **User Namespace:** Yes. An unprivileged user can trigger this by creating a
new user namespace and network namespace, acquiring `CAP_NET_ADMIN`, and using
the `mac80211_hwsim` module (via `HWSIM_CMD_NEW_RADIO`) to create a virtual
radio. They can then start an AP interface on it and destroy the network
namespace, which unregisters the virtual hardware and triggers the warning. Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
|
| 1/1 |
2026/08/10 00:28 |
action |
syz-repro-to-c-repro |
0m
Results:
|
| 2/1 |
2026/08/10 00:28 |
action |
kernel-checkouter |
0m
Results: map[KernelSrc:/app/workdir/cache/src/cdeee7f73771964691f0c27cfb0938e4c7688540]
|
| 3/1 |
2026/08/10 00:28 |
action |
kernel-builder |
17m
Results: map[KernelObj:/app/workdir/cache/build/aaae06e67a1f2a237720213b42030e4d3d77a670]
|
| 4/1 |
2026/08/10 00:46 |
action |
codesearch-prepare |
23m
Results: map[Index:codesearch-index]
|
| 5/1 |
2026/08/10 01:09 |
agent |
expert |
33m
Model:
Results: map[DenialOfService:false Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
Instruction: You are an experienced Linux kernel security engineer. Your task is to analyze given kernel bug report
and determine its security impact based on the following dimensions.
Use the provided tools to examine the source code, check for capability checks (e.g., capable(), ns_capable()),
and understand the nature of the bug. Analyze the given kernel build and configuration.
You can check the kernel config by grepping ".config" file; you can check kernel cmdline by grepping
".config" file for "CONFIG_CMDLINE=". Assume sysctl parameters have default values.
But analyze for the corresponding production build w/o debugging tools enabled (like KASAN, KMSAN, UBSAN).
Try different strategies when analyzing the bug:
- think of ways in which the vulnerable code is unreachable
- or the other way around: try to come up with different ideas of how an unprivileged user can reach the bug
If still unsure err on the side of the bug being non-exploitable/not-accessible.
In the final reply, provide a reasoning for your assessment.
Analysis dimensions:
* Exploitable:
Determine if the bug can result in memory corruption, elevated privileges, or an information leak.
Memory safety issues are almost always exploitable (KASAN or UBSAN reports for use-after-free, out-of-bounds;
refcounting issues, corrupted lists, etc). When kernel is crashing on a completely wild pointer access
(e.g. user-space address, or non-canonical address, but not on NULL or address corresponding to KASAN shadow
for NULL address), including both data accesses and control transfers, that also usually implies possibility
of exploitation. Such reports usually say "unable to handle kernel paging request".
Uses of uninitialized values detected by KMSAN may be exploitable b/c attacker frequently can affect uninit
values with spraying techniques. However, for these exploitability depends on how exactly the uninit value
is used in the code, and what it affects.
Information leaks are exploitable on their own and should be classified as such. A bug that copies kernel
memory contents to userspace (e.g. an out-of-bounds read whose result is returned to the caller, or
uninitialized stack/heap bytes written to a user buffer) is exploitable: it can reveal kernel pointer
values and defeat KASLR, expose sensitive data such as cryptographic keys or other processes' memory, and
serves as a necessary building block in most modern kernel privilege-escalation exploit chains. Do not classify
an information leak as non-exploitable solely because it does not directly cause a memory write or control-flow
hijack; the leak itself is the exploit primitive.
Think of what happens after the bug is triggered. Some bugs cause kernel panic and halt execution,
they are harder to exploit. For example, BUG reports halts the kernel. However, WARNING reports don't halt
execution in production builds. Debug bug detection tools (like KASAN, KMSAN, KCSAN, UBSAN) are also not enabled
in production builds, so attacker can freely exploit these bugs w/o being detected by these tools.
If you see an integer overflow, think how the overflowed value used later (if it's used as allocation size,
or an array index). If you see an out-of-bounds read, think if it's followed by an out-of-bounds write as well.
Some KCSAN data-races may be exploitable by skilled attackers as well. Think what data structures got corrupted
as the result of data races and how. However, note that kernel has lots of "benign" data races that don't lead
to any runtime misbehavior at all.
* Denial Of Service:
Determine if the bug can result in denial-of-service. Most bugs can, since they cause system crash,
hangs, deadlocks, or resource leaks. This is mostly applicable to WARNING bugs that won't cause system crash
in production. For these think what will be consequences of the violation of the kernel assumptions flagged
by the WARNING. In some cases the unexpected condition is also properly handled by the normal control flow
(e.g. with "if (WARN_ON(...))"), these won't cause denial-of-service. If the condition is not handled,
then it may or may not cause denial-of-service.
* Accessible From Unprivileged Processes:
Determine if the bug can be reached from a typical (non-root) user process that does NOT have any special capabilities
(like CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON) or access to device nodes restricted to root.
Assume that unprivileged_bpf_disabled=1, that is eBPF loading is not accessible. However, cBPF (classical BPF)
is still accessible to non-root processes.
Assume that user namespaces are not accessible, that is, the process cannot get the mentioned capabilities even
within a new user namespace (checked by ns_capable() function in the kernel sources).
* Accessible From User Namespaces:
Determine if the bug can be reached within a user-namespace where the process has all capabilities
(including CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON). Such capabilities are checked with ns_capable()
function in the kernel sources.
* VM Guest Trigger:
Determine if the bug can be triggered from the context of a typical KVM guest (e.g., set up by a QEMU VMM).
Consider accesses to standard Linux host paravirtualized features (virtio-blk, virtio-net, etc.),
and handling of VM exits in the KVM code.
* VM Host Trigger in The Confidential Computing Context:
Determine if the bug can be triggered in a confidential computing guest kernel from the context of a KVM host.
Consider access to standard Linux guest paravirtualized features (virtio-blk, virtio-net, etc.).
* Ethernet Network Trigger:
Determine if the bug can be triggered by processing ingress network Ethernet traffic, either directly (network stack)
or via drivers exposed to network data.
* Other Remote Trigger:
Determine if the bug can be triggered by processing remote traffic other than Ethernet (Wifi, Bluetooth, NFC, etc).
* Peripheral Trigger:
Determine if the bug can be triggered via an untrusted peripheral device that can be physically plugged
into a system, such as a USB device or a niche hardware driver handling external hardware inputs.
This is particularly important for mobile and desktop environments where users can plug in unknown devices.
* Malicious Filesystem Trigger:
Determine if the bug can be triggered by the kernel mounting and parsing a malicious filesystem image.
This is highly critical for Desktop and Mobile environments where external media or downloaded images
might be auto-mounted.
Don't make assumptions about the kernel source code (it may be different from what you assume it is).
Extensively use the provided code access tools (codesearch-*, git-*, grepper, etc)
to examine the actual source code, and confirm any assumptions.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt:
The kernel bug report is:
------------[ cut here ]------------
wlan0: Failed check-sdata-in-driver check, flags: 0x0
WARNING: net/mac80211/driver-ops.c:366 at drv_unassign_vif_chanctx+0x498/0x7d0 net/mac80211/driver-ops.c:366, CPU#1: kworker/u8:33/10061
Modules linked in:
CPU: 1 UID: 0 PID: 10061 Comm: kworker/u8:33 Tainted: G L syzkaller #0 PREEMPT(full)
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/24/2026
Workqueue: netns cleanup_net
RIP: 0010:drv_unassign_vif_chanctx+0x4e5/0x7d0 net/mac80211/driver-ops.c:366
Code: 8d 78 0a 00 00 48 8b 02 48 8d b0 20 01 00 00 48 85 c0 48 0f 44 f1 42 0f b6 44 3d 00 84 c0 0f 85 95 01 00 00 41 8b 16 48 89 df <67> 48 0f b9 3a e9 04 fd ff ff e8 6c 20 8d f6 90 0f 0b 90 e9 3d fe
RSP: 0018:ffffc9000d7ff090 EFLAGS: 00010246
RAX: 0000000000000000 RBX: ffffffff90695800 RCX: ffff888037171938
RDX: 0000000000000000 RSI: ffff888037170120 RDI: ffffffff90695800
RBP: 1ffff11006e2e325 R08: ffffffff90574637 R09: 1ffffffff20ae8c6
R10: dffffc0000000000 R11: fffffbfff20ae8c7 R12: ffff888037172c70
R13: ffff888037170ec0 R14: ffff888037171928 R15: dffffc0000000000
FS: 0000000000000000(0000) GS:ffff888125055000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000557e0c475950 CR3: 0000000051358000 CR4: 00000000003526f0
Call Trace:
<TASK>
ieee80211_assign_link_chanctx+0x234/0xcd0 net/mac80211/chan.c:1199
__ieee80211_link_release_channel+0x3c6/0x610 net/mac80211/chan.c:2176
ieee80211_teardown_sdata+0xc1/0x240 net/mac80211/iface.c:916
unregister_netdevice_many_notify+0x1acd/0x2140 net/core/dev.c:12467
unregister_netdevice_many net/core/dev.c:12509 [inline]
unregister_netdevice_queue+0x2f5/0x340 net/core/dev.c:12320
unregister_netdevice include/linux/netdevice.h:3474 [inline]
_cfg80211_unregister_wdev+0x156/0x5a0 net/wireless/core.c:1422
ieee80211_remove_interfaces+0x49c/0x6a0 net/mac80211/iface.c:2492
ieee80211_unregister_hw+0x5d/0x2c0 net/mac80211/main.c:1718
mac80211_hwsim_del_radio+0x28a/0x4a0 drivers/net/wireless/virtual/mac80211_hwsim_main.c:6226
hwsim_exit_net+0xe8e/0xf50 drivers/net/wireless/virtual/mac80211_hwsim_main.c:7207
ops_exit_list net/core/net_namespace.c:199 [inline]
ops_undo_list+0x43d/0x8d0 net/core/net_namespace.c:252
cleanup_net+0x572/0x810 net/core/net_namespace.c:702
process_one_work kernel/workqueue.c:3322 [inline]
process_scheduled_works+0xa8e/0x14e0 kernel/workqueue.c:3405
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3486
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
----------------
Code disassembly (best guess):
0: 8d 78 0a lea 0xa(%rax),%edi
3: 00 00 add %al,(%rax)
5: 48 8b 02 mov (%rdx),%rax
8: 48 8d b0 20 01 00 00 lea 0x120(%rax),%rsi
f: 48 85 c0 test %rax,%rax
12: 48 0f 44 f1 cmove %rcx,%rsi
16: 42 0f b6 44 3d 00 movzbl 0x0(%rbp,%r15,1),%eax
1c: 84 c0 test %al,%al
1e: 0f 85 95 01 00 00 jne 0x1b9
24: 41 8b 16 mov (%r14),%edx
27: 48 89 df mov %rbx,%rdi
* 2a: 67 48 0f b9 3a ud1 (%edx),%rdi <-- trapping instruction
2f: e9 04 fd ff ff jmp 0xfffffd38
34: e8 6c 20 8d f6 call 0xf68d20a5
39: 90 nop
3a: 0f 0b ud2
3c: 90 nop
3d: e9 .byte 0xe9
3e: 3d .byte 0x3d
3f: fe .byte 0xfe
Reply: The bug report describes a `WARN_ONCE` triggered in `drv_unassign_vif_chanctx` within the mac80211 subsystem.
### Root Cause Analysis
The warning is triggered by the `check_sdata_in_driver(sdata)` macro, which checks if the `IEEE80211_SDATA_IN_DRIVER` flag is set on the sub-interface data (`sdata`). If the flag is missing, it emits a warning and returns false, causing `drv_unassign_vif_chanctx` to return early without calling the driver's `unassign_vif_chanctx` callback.
This happens during the teardown of a wireless interface (e.g., an AP or a fully associated STATION) when the underlying hardware is removed or unregistered. The teardown sequence is as follows:
1. `cfg80211_shutdown_all_interfaces` calls `dev_close`, which eventually calls `ieee80211_do_stop`.
2. `ieee80211_do_stop` calls `drv_remove_interface`, which clears the `IEEE80211_SDATA_IN_DRIVER` flag, effectively removing the interface from the driver's perspective.
3. Later in the teardown process, `cfg80211_unregister_wdev` calls `unregister_netdevice_many`, which invokes the `ndo_uninit` callback (`ieee80211_uninit`).
4. `ieee80211_uninit` calls `ieee80211_teardown_sdata`, which calls `ieee80211_link_stop` and then `ieee80211_link_release_channel`.
5. `ieee80211_link_release_channel` attempts to unassign the channel context by calling `drv_unassign_vif_chanctx`.
6. Since `IEEE80211_SDATA_IN_DRIVER` was already cleared in step 2, the `check_sdata_in_driver` macro triggers the warning.
### Security Impact
**Exploitable:** No.
This is a harmless warning caused by a slightly out-of-order teardown sequence. Returning early from `drv_unassign_vif_chanctx` is actually the correct and safe behavior here, as calling the driver's `unassign_vif_chanctx` callback on an interface that has already been removed (`drv_remove_interface`) could lead to a crash or use-after-free in the driver. The channel context is still properly unassigned and freed on the mac80211 side, so there are no resource leaks, memory corruptions, or use-after-free vulnerabilities.
**Denial of Service:** No.
The bug is a `WARN_ONCE` and does not halt the kernel or cause any deadlocks. It will not cause a denial of service in production builds (unless `panic_on_warn` is explicitly enabled by the administrator).
**Trigger Vectors:**
- **Peripheral Trigger:** Yes. An attacker with physical access can trigger this by physically unplugging a USB Wi-Fi dongle while an Access Point (AP) or a connected STATION interface is running on it.
- **User Namespace:** Yes. An unprivileged user can trigger this by creating a new user namespace and network namespace, acquiring `CAP_NET_ADMIN`, and using the `mac80211_hwsim` module (via `HWSIM_CMD_NEW_RADIO`) to create a virtual radio. They can then start an AP interface on it and destroy the network namespace, which unregisters the virtual hardware and triggers the warning.
|
| 6/2 |
2026/08/10 01:09 |
llm |
expert |
0m
Model:
Tokens:
input: 7811
output: 48
thoughts: 74
Thoughts: Here's my analysis of that warning:
**Analyzing a mac80211 Driver Warning**
Okay, I've got a `WARNING` popping up, specifically within `drv_unassign_vif_chanctx` on line 366 of `net/mac80211/driver-ops.c`. The message itself, "wlan0: Failed check-sdata-in-driver check, flags: 0x0," immediately flags a potential issue with the way the driver is handling scheduled data (sdata) and its interaction with channel context, for interface 'wlan0'. The "flags: 0x0" part is crucial; it's telling me the specific flags related to the problem are currently empty, which likely means some state wasn't set when the check was performed or the problem lies elsewhere.
My immediate next step is to examine that section of code around line 366. I need to understand the exact conditions that trigger this `check-sdata-in-driver` verification. I'll need to trace the execution path leading into `drv_unassign_vif_chanctx` to see what's happening just before this warning is issued. Specifically, I'll be looking for possible race conditions, memory corruption, or incorrect assumptions about the sdata state. Given my experience, I suspect a timing issue or possibly an incorrect state being propagated between the driver and the mac80211 core. A common cause for these warnings is a situation where the driver thinks that there is sdata in flight that has not been properly handled by the mac80211 core.
I expect this is not a common event and may be related to more complex operational scenarios, and I need to identify the exact trigger condition to see if this is an error or simply a warning.
|
| 7/2 |
2026/08/10 01:09 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/driver-ops.c Name:drv_unassign_vif_chanctx]
Results: map[SourceCode: 353: void drv_unassign_vif_chanctx(struct ieee80211_local *local,
354: struct ieee80211_sub_if_data *sdata,
355: struct ieee80211_bss_conf *link_conf,
356: struct ieee80211_chanctx *ctx)
357: {
358: might_sleep();
359: lockdep_assert_wiphy(local->hw.wiphy);
360:
361: if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
362: local->emulate_chanctx &&
363: !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
364: return;
365:
366: if (!check_sdata_in_driver(sdata))
367: return;
368:
369: if (!ieee80211_vif_link_active(&sdata->vif, link_conf->link_id))
370: return;
371:
372: trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
373: if (local->ops->unassign_vif_chanctx) {
374: WARN_ON_ONCE(!ctx->driver_present);
375: local->ops->unassign_vif_chanctx(&local->hw,
376: &sdata->vif,
377: link_conf,
378: &ctx->conf);
379: }
380: trace_drv_return_void(local);
381: }
SourceFile:net/mac80211/driver-ops.c]
|
| 8/2 |
2026/08/10 01:09 |
llm |
expert |
0m
Model:
Tokens:
input: 8866
output: 46
thoughts: 33
Thoughts: Here's my analysis of this situation:
**Investigating the Warning Location**
Okay, so the warning I'm dealing with is originating from within the `check_sdata_in_driver(sdata)` function. That's my starting point. The crucial next step is obviously to dive directly into the definition of `check_sdata_in_driver` and dissect the logic within. That's where the root cause of this warning will be revealed, I'm sure. I need to understand what conditions trigger it and what `sdata` represents in this context. Time to get down to the nitty gritty.
|
| 9/2 |
2026/08/10 01:09 |
tool |
codesearch-definition-source |
0m
Error:
Args: map[ContextFile:net/mac80211/driver-ops.c Name:check_sdata_in_driver]
Results: map[SourceCode: SourceFile:]
|
| 10/2 |
2026/08/10 01:09 |
llm |
expert |
0m
Model:
Tokens:
input: 9099
output: 43
thoughts: 35
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm deep in the weeds with wireless driver development:
**Thinking Through a Possible MACRO**
Alright, the problem I'm looking at⦠could be a macro. That's a classic. To figure this out quickly, I'm going to jump straight into `net/mac80211/driver-ops.c`. Specifically, I'm going to zero in around line 366. That's usually a good area to start looking for common MAC80211 driver operations and associated definitions. With my experience, I can often spot a macro definition or usage pattern quickly within that context. From there, I'll be able to infer the root cause.
|
| 11/2 |
2026/08/10 01:10 |
tool |
read-file |
0m
Args: map[File:net/mac80211/driver-ops.c FirstLine:300 LineCount:100]
Results: map[Contents: 300: might_sleep();
301: lockdep_assert_wiphy(local->hw.wiphy);
302:
303: if (!check_sdata_in_driver(sdata))
304: return;
305:
306: trace_drv_reset_tsf(local, sdata);
307: if (local->ops->reset_tsf)
308: local->ops->reset_tsf(&local->hw, &sdata->vif);
309: trace_drv_return_void(local);
310: }
311:
312: int drv_assign_vif_chanctx(struct ieee80211_local *local,
313: struct ieee80211_sub_if_data *sdata,
314: struct ieee80211_bss_conf *link_conf,
315: struct ieee80211_chanctx *ctx)
316: {
317: int ret = 0;
318:
319: might_sleep();
320: lockdep_assert_wiphy(local->hw.wiphy);
321:
322: /*
323: * We should perhaps push emulate chanctx down and only
324: * make it call ->config() when the chanctx is actually
325: * assigned here (and unassigned below), but that's yet
326: * another change to all drivers to add assign/unassign
327: * emulation callbacks. Maybe later.
328: */
329: if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
330: local->emulate_chanctx &&
331: !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
332: return 0;
333:
334: if (!check_sdata_in_driver(sdata))
335: return -EIO;
336:
337: if (!ieee80211_vif_link_active(&sdata->vif, link_conf->link_id))
338: return 0;
339:
340: trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx);
341: if (local->ops->assign_vif_chanctx) {
342: WARN_ON_ONCE(!ctx->driver_present);
343: ret = local->ops->assign_vif_chanctx(&local->hw,
344: &sdata->vif,
345: link_conf,
346: &ctx->conf);
347: }
348: trace_drv_return_int(local, ret);
349:
350: return ret;
351: }
352:
353: void drv_unassign_vif_chanctx(struct ieee80211_local *local,
354: struct ieee80211_sub_if_data *sdata,
355: struct ieee80211_bss_conf *link_conf,
356: struct ieee80211_chanctx *ctx)
357: {
358: might_sleep();
359: lockdep_assert_wiphy(local->hw.wiphy);
360:
361: if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
362: local->emulate_chanctx &&
363: !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
364: return;
365:
366: if (!check_sdata_in_driver(sdata))
367: return;
368:
369: if (!ieee80211_vif_link_active(&sdata->vif, link_conf->link_id))
370: return;
371:
372: trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
373: if (local->ops->unassign_vif_chanctx) {
374: WARN_ON_ONCE(!ctx->driver_present);
375: local->ops->unassign_vif_chanctx(&local->hw,
376: &sdata->vif,
377: link_conf,
378: &ctx->conf);
379: }
380: trace_drv_return_void(local);
381: }
382:
383: int drv_switch_vif_chanctx(struct ieee80211_local *local,
384: struct ieee80211_vif_chanctx_switch *vifs,
385: int n_vifs, enum ieee80211_chanctx_switch_mode mode)
386: {
387: int ret = 0;
388: int i;
389:
390: might_sleep();
391: lockdep_assert_wiphy(local->hw.wiphy);
392:
393: if (!local->ops->switch_vif_chanctx)
394: return -EOPNOTSUPP;
395:
396: for (i = 0; i < n_vifs; i++) {
397: struct ieee80211_chanctx *new_ctx =
398: container_of(vifs[i].new_ctx,
399: struct ieee80211_chanctx,
]
|
| 12/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 11009
output: 24
thoughts: 21
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Analyzing Potential Macro Usage in Driver Code**
Okay, so `check_sdata_in_driver` is popping up in this driver code. My initial hunch is that it's likely a macro. The name has that classic macro-esque feel to it β concise and hinting at a repetitive code snippet. Given the context, it's probably being used for some data validation or pre-check within the driver logic. Now I need to track down where this macro is defined. Time to go hunting for its definition. Let's see if I can find it in an included header or maybe within the driver file itself, probably in a header file if it is declared.
|
| 13/2 |
2026/08/10 01:10 |
tool |
grepper |
0m
Args: map[Expression:#define check_sdata_in_driver]
Results: map[Output:net/mac80211/driver-ops.h-15-
net/mac80211/driver-ops.h:16:#define check_sdata_in_driver(sdata) ({ \
net/mac80211/driver-ops.h-17- WARN_ONCE(!sdata->local->reconfig_failure && \
]
|
| 14/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 11315
output: 40
thoughts: 26
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Diving into the MAC80211 Driver Operations**
Okay, let's get down to brass tacks. I'm going to pull up `net/mac80211/driver-ops.h` and specifically focus on the code around line 16. I want to quickly review the driver operation structures. Line 16 is probably where the core function pointers or the start of a key data structure definition lie. I need to refresh my understanding of how the mac80211 core interfaces with the specific driver implementation. I suspect there will be some basic function defintions for things like frame transmit and receive here. Understanding the driver ops structure is crucial to tracing any particular issue. This is likely the best place to start.
|
| 15/2 |
2026/08/10 01:10 |
tool |
read-file |
0m
Args: map[File:net/mac80211/driver-ops.h FirstLine:1 LineCount:50]
Results: map[Contents: 1: /* SPDX-License-Identifier: GPL-2.0 */
2: /*
3: * Portions of this file
4: * Copyright(c) 2016 Intel Deutschland GmbH
5: * Copyright (C) 2018-2019, 2021-2025 Intel Corporation
6: */
7:
8: #ifndef __MAC80211_DRIVER_OPS
9: #define __MAC80211_DRIVER_OPS
10:
11: #include <linux/fips.h>
12: #include <net/mac80211.h>
13: #include "ieee80211_i.h"
14: #include "trace.h"
15:
16: #define check_sdata_in_driver(sdata) ({ \
17: WARN_ONCE(!sdata->local->reconfig_failure && \
18: !(sdata->flags & IEEE80211_SDATA_IN_DRIVER), \
19: "%s: Failed check-sdata-in-driver check, flags: 0x%x\n", \
20: sdata->dev ? sdata->dev->name : sdata->name, sdata->flags); \
21: !!(sdata->flags & IEEE80211_SDATA_IN_DRIVER); \
22: })
23:
24: static inline struct ieee80211_sub_if_data *
25: get_bss_sdata(struct ieee80211_sub_if_data *sdata)
26: {
27: if (sdata && sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
28: sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
29: u.ap);
30:
31: return sdata;
32: }
33:
34: static inline void drv_tx(struct ieee80211_local *local,
35: struct ieee80211_tx_control *control,
36: struct sk_buff *skb)
37: {
38: local->ops->tx(&local->hw, control, skb);
39: }
40:
41: static inline void drv_sync_rx_queues(struct ieee80211_local *local,
42: struct sta_info *sta)
43: {
44: might_sleep();
45: lockdep_assert_wiphy(local->hw.wiphy);
46:
47: if (local->ops->sync_rx_queues) {
48: trace_drv_sync_rx_queues(local, sta->sdata, &sta->sta);
49: local->ops->sync_rx_queues(&local->hw);
50: trace_drv_return_void(local);
]
|
| 16/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 12418
output: 48
thoughts: 896
Thoughts: **Analyzing a Mac80211 Warning During Network Namespace Cleanup**
Okay, so I've got this warning that pops up during the cleanup of a network namespace, specifically when `hwsim_exit_net` is called, which is when the hwsim radios are being deleted. The warning itself is: `WARN_ONCE(!sdata->local->reconfig_failure && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER), "%s: Failed check-sdata-in-driver check, flags: 0x%x\n", sdata->dev ? sdata->dev->name : sdata->name, sdata->flags);`
Essentially, it's saying the `IEEE80211_SDATA_IN_DRIVER` flag isn't set when it probably *should* be. The stack trace points to `ieee80211_assign_link_chanctx`, `__ieee80211_link_release_channel`, and finally into `hwsim_exit_net`. That makes sense; we're in the process of tearing down interfaces and devices.
My initial thought is, this is likely a bug. `sdata->flags` doesn't have the expected flag set. But let's see how the code handles it. A quick look at the code reveals that `check_sdata_in_driver` *returns* `!!(sdata->flags & IEEE80211_SDATA_IN_DRIVER)`. The important thing is that `drv_unassign_vif_chanctx` is called, but that function has a check - it returns if the flag isn't set. So the warning is just a warning, it's expected and the code handles it by returning early.
Now, the obvious question is, is this exploitable? No, not directly. It's just a warning. This isn't a kernel panic. Unless `panic_on_warn` is set, which is not default, it won't crash the kernel.
But the next level question is, could this cause a resource leak or a deadlock? If `drv_unassign_vif_chanctx` returns early, does it skip some important cleanup? I need to dig into `drv_unassign_vif_chanctx` itself to understand what it actually *does*. I need to see if the early return could lead to a situation where resources are not properly released, or where some important state isn't reset, which could lead to instability down the line. That's the real potential issue here. So, I need to see what's skipped when this condition occurs, and what that might mean in terms of long-term system stability.
|
| 17/2 |
2026/08/10 01:10 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/driver-ops.c Name:drv_unassign_vif_chanctx]
Results: map[SourceCode: 353: void drv_unassign_vif_chanctx(struct ieee80211_local *local,
354: struct ieee80211_sub_if_data *sdata,
355: struct ieee80211_bss_conf *link_conf,
356: struct ieee80211_chanctx *ctx)
357: {
358: might_sleep();
359: lockdep_assert_wiphy(local->hw.wiphy);
360:
361: if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
362: local->emulate_chanctx &&
363: !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
364: return;
365:
366: if (!check_sdata_in_driver(sdata))
367: return;
368:
369: if (!ieee80211_vif_link_active(&sdata->vif, link_conf->link_id))
370: return;
371:
372: trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
373: if (local->ops->unassign_vif_chanctx) {
374: WARN_ON_ONCE(!ctx->driver_present);
375: local->ops->unassign_vif_chanctx(&local->hw,
376: &sdata->vif,
377: link_conf,
378: &ctx->conf);
379: }
380: trace_drv_return_void(local);
381: }
SourceFile:net/mac80211/driver-ops.c]
|
| 18/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 14498
output: 50
thoughts: 161
Thoughts: **Analyzing the Conditional Unassignment**
Okay, so I'm looking at this code and trying to understand this conditional skip of `local->ops->unassign_vif_chanctx`. It seems straightforward at first: if the function returns early, then `unassign_vif_chanctx` doesn't get called. That makes sense on the surface. But, the real question is why the early return.
The comment about `sdata` not being in the driver and `IEEE80211_SDATA_IN_DRIVER` not being set is the key. That implies that if this flag isn't set, then the context probably *wasn't* assigned to the driver in the first place, or it's already been removed. Skipping the unassignment is the correct behavior in that scenario β it's a defensive measure. The warning message is just a sanity check to flag unexpected attempts to unassign something that the driver isn't actually managing.
But that still begs the question... *why* is it trying to unassign something that isn't under driver control in the first place? Something upstream is likely misbehaving. I need to trace this back. Let's look at `ieee80211_assign_link_chanctx` in `net/mac80211/chan.c:1199`. That's where this context assignment is likely happening, and where the root cause probably lies. I need to see what conditions lead to that assignment to fully understand the context of the unassignment.
|
| 19/2 |
2026/08/10 01:10 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/chan.c Name:ieee80211_assign_link_chanctx]
Results: map[SourceCode:1179: static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
1180: struct ieee80211_chanctx *new_ctx,
1181: bool assign_on_failure)
1182: {
1183: struct ieee80211_sub_if_data *sdata = link->sdata;
1184: struct ieee80211_local *local = sdata->local;
1185: struct ieee80211_chanctx_conf *conf;
1186: struct ieee80211_chanctx *curr_ctx = NULL;
1187: bool new_idle;
1188: int ret;
1189:
1190: if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
1191: return -EOPNOTSUPP;
1192:
1193: conf = rcu_dereference_protected(link->conf->chanctx_conf,
1194: lockdep_is_held(&local->hw.wiphy->mtx));
1195:
1196: if (conf && !local->in_reconfig) {
1197: curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
1198:
1199: drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
1200: conf = NULL;
1201: }
1202:
1203: if (new_ctx) {
1204: /* recalc considering the link we'll use it for now */
1205: _ieee80211_recalc_chanctx_min_def(local, new_ctx, link, false);
1206:
1207: ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
1208: if (assign_on_failure || !ret) {
1209: /* Need to continue, see _ieee80211_set_active_links */
1210: WARN_ON_ONCE(ret && !local->in_reconfig);
1211: ret = 0;
1212:
1213: /* succeeded, so commit it to the data structures */
1214: conf = &new_ctx->conf;
1215: }
1216: } else {
1217: ret = 0;
1218: }
1219:
1220: rcu_assign_pointer(link->conf->chanctx_conf, conf);
1221:
1222: if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
1223: ieee80211_recalc_chanctx_chantype(local, curr_ctx);
1224: ieee80211_recalc_smps_chanctx(local, curr_ctx);
1225: ieee80211_recalc_radar_chanctx(local, curr_ctx);
1226: ieee80211_recalc_chanctx_min_def(local, curr_ctx);
1227: }
1228:
1229: if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
1230: ieee80211_recalc_txpower(link, false);
1231: ieee80211_recalc_chanctx_min_def(local, new_ctx);
1232: }
1233:
1234: if (conf) {
1235: new_idle = false;
1236: } else {
1237: struct ieee80211_link_data *tmp;
1238:
1239: new_idle = true;
1240: for_each_sdata_link(local, tmp) {
1241: if (rcu_access_pointer(tmp->conf->chanctx_conf)) {
1242: new_idle = false;
1243: break;
1244: }
1245: }
1246: }
1247:
1248: if (new_idle != sdata->vif.cfg.idle) {
1249: sdata->vif.cfg.idle = new_idle;
1250:
1251: if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
1252: sdata->vif.type != NL80211_IFTYPE_MONITOR)
1253: ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_IDLE);
1254: }
1255:
1256: ieee80211_check_fast_xmit_iface(sdata);
1257:
1258: return ret;
1259: }
SourceFile:net/mac80211/chan.c]
|
| 20/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 16507
output: 51
thoughts: 180
Thoughts: **Analyzing the MAC80211 Interface Teardown**
Okay, so I'm looking at this stack trace and it immediately suggests a potential resource release issue during interface removal in the mac80211 wireless stack. Specifically, `__ieee80211_link_release_channel` is being called, which then invokes `ieee80211_assign_link_chanctx` with a null `chanctx` and `false` for the force flag. That's interesting, but not the root cause. We've got `ieee80211_teardown_sdata` calling that `__ieee80211_link_release_channel`, then `ieee80211_remove_interfaces` calls `ieee80211_teardown_sdata`, and finally, at the top, `ieee80211_unregister_hw` triggers it all by calling `ieee80211_remove_interfaces`. The pattern here is, as expected, interface teardown cascades up to hardware unregistration.
My next step is to examine the `ieee80211_teardown_sdata` function, specifically in `net/mac80211/iface.c`, line 916. That's the key function. It's the point where the channel context release is triggered when an interface is being torn down. I'll need to see how the soft device is handled there, what other resources are being released, and whether there's a race condition or a missed edge case in that flow that might be causing this issue. I suspect the way channel context is handled in `ieee80211_teardown_sdata` may be related to the problem, or a related function within that context.
|
| 21/2 |
2026/08/10 01:10 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/iface.c Name:ieee80211_teardown_sdata]
Results: map[SourceCode: 896: /*
897: * Called when the netdev is removed or, by the code below, before
898: * the interface type changes.
899: */
900: static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
901: {
902: if (WARN_ON(!list_empty(&sdata->work.entry)))
903: wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
904:
905: /* free extra data */
906: ieee80211_free_keys(sdata, false);
907:
908: ieee80211_debugfs_remove_netdev(sdata);
909:
910: ieee80211_destroy_frag_cache(&sdata->frags);
911:
912: if (ieee80211_vif_is_mesh(&sdata->vif))
913: ieee80211_mesh_teardown_sdata(sdata);
914:
915: ieee80211_vif_clear_links(sdata);
916: ieee80211_link_stop(&sdata->deflink);
917:
918: if (sdata->vif.type == NL80211_IFTYPE_NAN) {
919: struct ieee80211_nan_sched_cfg *nan_sched =
920: &sdata->vif.cfg.nan_sched;
921:
922: for (int i = 0; i < ARRAY_SIZE(nan_sched->channels); i++)
923: WARN_ON(nan_sched->channels[i].chanreq.oper.chan);
924: }
925: }
SourceFile:net/mac80211/iface.c]
|
| 22/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 17725
output: 48
thoughts: 51
Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective:
**Diving into IEEE 802.11 Link Management**
Alright, that's a bit unexpected. I was just reviewing some 802.11 code, and it hit me: `ieee80211_link_stop`... shouldn't it be primarily about *stopping* a link? Why would it call `__ieee80211_link_release_channel`? That function is typically involved in channel release, which usually happens when the link is *released* entirely, or when there's a channel switch involved. Hmm, I need to understand that. This calls for a closer look. Let's see how `ieee80211_link_stop` is actually implemented; let's see what's happening there. I need to understand the control flow, the data structures that are accessed, and, crucially, *why* channel release is being triggered during a link *stop*. It could be part of a graceful shutdown process, maybe a mechanism for properly relinquishing channel resources when a link is being deactivated, but I have to verify that. It could also point to a subtle bug! Time to break out the source code.
|
| 23/2 |
2026/08/10 01:10 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/iface.c Name:ieee80211_link_stop]
Results: map[SourceCode: 162: void ieee80211_link_stop(struct ieee80211_link_data *link)
163: {
164: if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
165: ieee80211_mgd_stop_link(link);
166:
167: wiphy_delayed_work_cancel(link->sdata->local->hw.wiphy,
168: &link->color_collision_detect_work);
169: wiphy_work_cancel(link->sdata->local->hw.wiphy,
170: &link->color_change_finalize_work);
171: wiphy_work_cancel(link->sdata->local->hw.wiphy,
172: &link->csa.finalize_work);
173:
174: if (link->sdata->wdev.links[link->link_id].cac_started) {
175: wiphy_hrtimer_work_cancel(link->sdata->local->hw.wiphy,
176: &link->dfs_cac_timer_work);
177: cfg80211_cac_event(link->sdata->dev,
178: &link->conf->chanreq.oper,
179: NL80211_RADAR_CAC_ABORTED,
180: GFP_KERNEL, link->link_id);
181: }
182:
183: ieee80211_link_release_channel(link);
184: }
SourceFile:net/mac80211/link.c]
|
| 24/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 18591
output: 31
thoughts: 290
Thoughts: **Investigating a Potential Channel Context Leak**
Okay, so `ieee80211_link_release_channel` is calling `__ieee80211_link_release_channel`, and that's generating a warning. The warning specifically flags that the `IEEE80211_SDATA_IN_DRIVER` flag isn't set in `sdata->flags`. Hmm, that's not ideal. Why isn't that flag set? The code suggests two possibilities: the flag was either explicitly removed from the driver, or it was never added in the first place.
If it was never added, then `ieee80211_link_release_channel` *shouldn't* have been called in the first place, or at the very least it needs to handle this situation gracefully. Now, let's see, within `ieee80211_assign_link_chanctx` there is a check for `conf` and if it exists, it's unassigned.
If `conf` exists, then a channel context *was* assigned to the link. Could the interface be removed from the driver before the channel context is unassigned? That would explain the warning and potentially lead to a resource leak. Let's dig deeper and trace where this `IEEE80211_SDATA_IN_DRIVER` flag is being set and cleared. I need to understand the lifecycle of that flag to determine the root cause.
|
| 25/2 |
2026/08/10 01:10 |
tool |
codesearch-find-references |
0m
Error:
Args: map[Name:IEEE80211_SDATA_IN_DRIVER]
Results: map[References:<nil> TruncatedOutput:false]
|
| 26/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 19250
output: 27
thoughts: 15
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience:
**Identifying and Investigating a Suspected Macro**
Right, that's a macro. The immediate reaction is to move beyond simple assumptions and get concrete. Let's not waste time speculating about its function; instead, let's reach for the tools. My gut says "grep," and specifically, "grep" in its most effective form. I'm thinking I'll aim for a precise search, targeting the macro's name or a unique component within it. I know it's a good starting point to hunt for the definition or uses across the relevant codebase. Gotta determine its scope and impact. This could be a quick win or the start of a deep dive. Time to get to work.
|
| 27/2 |
2026/08/10 01:10 |
tool |
grepper |
0m
Args: map[Expression:IEEE80211_SDATA_IN_DRIVER]
Results: map[Output:net/mac80211/cfg.c=50=static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata,
--
net/mac80211/cfg.c-90- if (sdata->vif.bss_conf.mu_mimo_owner &&
net/mac80211/cfg.c:91: sdata->flags & IEEE80211_SDATA_IN_DRIVER)
net/mac80211/cfg.c-92- ieee80211_link_info_change_notify(sdata, &sdata->deflink,
--
net/mac80211/cfg.c=3835=static int ieee80211_get_tx_power(struct wiphy *wiphy,
--
net/mac80211/cfg.c-3845- if (local->ops->get_txpower &&
net/mac80211/cfg.c:3846: (sdata->flags & IEEE80211_SDATA_IN_DRIVER))
net/mac80211/cfg.c-3847- return drv_get_txpower(local, sdata, link_id, dbm);
--
net/mac80211/cfg.c=3875=static int ieee80211_testmode_cmd(struct wiphy *wiphy,
--
net/mac80211/cfg.c-3888- sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
net/mac80211/cfg.c:3889: if (sdata->flags & IEEE80211_SDATA_IN_DRIVER)
net/mac80211/cfg.c-3890- vif = &sdata->vif;
--
net/mac80211/debugfs_netdev.c=1030=void ieee80211_debugfs_recreate_netdev(struct ieee80211_sub_if_data *sdata,
--
net/mac80211/debugfs_netdev.c-1035-
net/mac80211/debugfs_netdev.c:1036: if (sdata->flags & IEEE80211_SDATA_IN_DRIVER) {
net/mac80211/debugfs_netdev.c-1037- drv_vif_add_debugfs(sdata->local, sdata);
--
net/mac80211/driver-ops.c=57=int drv_add_interface(struct ieee80211_local *local,
--
net/mac80211/driver-ops.c-78-
net/mac80211/driver-ops.c:79: if (!(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) {
net/mac80211/driver-ops.c:80: sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
net/mac80211/driver-ops.c-81-
--
net/mac80211/driver-ops.c=108=void drv_remove_interface(struct ieee80211_local *local,
--
net/mac80211/driver-ops.c-116-
net/mac80211/driver-ops.c:117: sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
net/mac80211/driver-ops.c-118-
--
net/mac80211/driver-ops.h-17- WARN_ONCE(!sdata->local->reconfig_failure && \
net/mac80211/driver-ops.h:18: !(sdata->flags & IEEE80211_SDATA_IN_DRIVER), \
net/mac80211/driver-ops.h-19- "%s: Failed check-sdata-in-driver check, flags: 0x%x\n", \
net/mac80211/driver-ops.h-20- sdata->dev ? sdata->dev->name : sdata->name, sdata->flags); \
net/mac80211/driver-ops.h:21: !!(sdata->flags & IEEE80211_SDATA_IN_DRIVER); \
net/mac80211/driver-ops.h-22-})
--
net/mac80211/ieee80211_i.h=770=struct ieee80211_if_mesh {
--
net/mac80211/ieee80211_i.h-866- * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
net/mac80211/ieee80211_i.h:867: * @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver
net/mac80211/ieee80211_i.h-868- * @IEEE80211_SDATA_DISCONNECT_HW_RESTART: Disconnect after hardware restart
--
net/mac80211/ieee80211_i.h=871=enum ieee80211_sub_if_data_flags {
--
net/mac80211/ieee80211_i.h-874- IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4),
net/mac80211/ieee80211_i.h:875: IEEE80211_SDATA_IN_DRIVER = BIT(5),
net/mac80211/ieee80211_i.h-876- IEEE80211_SDATA_DISCONNECT_HW_RESTART = BIT(6),
--
net/mac80211/util.c=745=static void __iterate_interfaces(struct ieee80211_local *local,
--
net/mac80211/util.c-768- if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
net/mac80211/util.c:769: active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
net/mac80211/util.c-770- continue;
net/mac80211/util.c-771- if ((iter_flags & IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) &&
net/mac80211/util.c:772: !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
net/mac80211/util.c-773- continue;
--
net/mac80211/util.c-783- (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
net/mac80211/util.c:784: sdata->flags & IEEE80211_SDATA_IN_DRIVER))
net/mac80211/util.c-785- iterator(data, sdata->vif.addr, &sdata->vif);
--
net/mac80211/util.c=818=__ieee80211_iterate_interfaces(struct ieee80211_hw *hw,
--
net/mac80211/util.c-849- if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
net/mac80211/util.c:850: active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
net/mac80211/util.c-851- continue;
net/mac80211/util.c-852- if ((iter_flags & IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) &&
net/mac80211/util.c:853: !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
net/mac80211/util.c-854- continue;
--
net/mac80211/util.c-860- (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
net/mac80211/util.c:861: monitor->flags & IEEE80211_SDATA_IN_DRIVER))
net/mac80211/util.c-862- return &monitor->vif;
--
net/mac80211/util.c=921=struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
--
net/mac80211/util.c-925- if (!ieee80211_sdata_running(sdata) ||
net/mac80211/util.c:926: !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
net/mac80211/util.c-927- return NULL;
--
net/mac80211/util.c=1673=static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
--
net/mac80211/util.c-1702- list_for_each_entry(sdata, &local->interfaces, list)
net/mac80211/util.c:1703: sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
net/mac80211/util.c-1704-
]
|
| 28/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 22112
output: 43
thoughts: 56
Thoughts: Okay, let's see, my mental gears are turning...
**Analyzing the Interface Removal Process**
Right, so `drv_remove_interface` is responsible for clearing `IEEE80211_SDATA_IN_DRIVER`. My immediate thought is, "Okay, let's dive deeper and understand the actual mechanics of this operation." I need to verify the implementation within `net/mac80211/driver-ops.c`, specifically line 108. I'm going to quickly pull up that file and go straight to that line. I need to understand what else is going on in that function, the surrounding context, any potential side effects, and of course, what's *actually* clearing that flag. This likely is part of the clean-up when an interface is being removed. I need to ensure the action is safe and does what I expect.
|
| 29/2 |
2026/08/10 01:10 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/driver-ops.c Name:drv_remove_interface]
Results: map[SourceCode: 108: void drv_remove_interface(struct ieee80211_local *local,
109: struct ieee80211_sub_if_data *sdata)
110: {
111: might_sleep();
112: lockdep_assert_wiphy(local->hw.wiphy);
113:
114: if (!check_sdata_in_driver(sdata))
115: return;
116:
117: sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
118:
119: /*
120: * Remove driver debugfs entries.
121: * The virtual monitor interface doesn't get a debugfs
122: * entry, so it's exempt here.
123: */
124: if (sdata != rcu_access_pointer(local->monitor_sdata))
125: ieee80211_debugfs_recreate_netdev(sdata,
126: sdata->vif.valid_links);
127:
128: trace_drv_remove_interface(local, sdata);
129: local->ops->remove_interface(&local->hw, &sdata->vif);
130: trace_drv_return_void(local);
131: }
SourceFile:net/mac80211/driver-ops.c]
|
| 30/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 22825
output: 23
thoughts: 15
Thoughts: Here's my thought process, as if I were analyzing that code:
**Diving into `drv_remove_interface`**
Okay, so I need to understand the implications of this `drv_remove_interface` function. My first instinct is always to understand its *context*. Where is it *actually* used? I'll need to trace its calls to get a complete picture. Let's start with a code search. I'll need to identify all the places in the codebase where `drv_remove_interface` is invoked. Understanding the calling contexts will give me essential insight into the purpose and impact of removing the interface. I'm thinking, are we talking about a clean shutdown, a hot-swap scenario, or something else entirely? The call sites will be key to unlocking that.
|
| 31/2 |
2026/08/10 01:10 |
tool |
codesearch-find-references |
0m
Args: map[Name:drv_remove_interface]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:__ieee80211_suspend SourceFile:net/mac80211/pm.c SourceLine:164] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:_ieee80211_change_mac SourceFile:net/mac80211/iface.c SourceLine:294] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_add_virtual_monitor SourceFile:net/mac80211/iface.c SourceLine:1288] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_del_virtual_monitor SourceFile:net/mac80211/iface.c SourceLine:1350] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_do_open SourceFile:net/mac80211/iface.c SourceLine:1604] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_do_stop SourceFile:net/mac80211/iface.c SourceLine:762] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_reconfig SourceFile:net/mac80211/util.c SourceLine:2030]] TruncatedOutput:false]
|
| 32/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 23484
output: 48
thoughts: 59
Thoughts: Here's my understanding of the situation, given my expertise:
**Diving into the Interface Shutdown Sequence**
Okay, so I'm looking at how a Wi-Fi interface is shut down, specifically using the mac80211 framework. The key function here seems to be `ieee80211_do_stop`. The interesting bit, as I see it, is that `ieee80211_do_stop` is responsible for calling `drv_remove_interface`. That makes immediate sense; the mac80211 layer needs to tell the driver to tear down its representation of the interface. I want to pinpoint the exact location of `ieee80211_do_stop` so I'm navigating to `net/mac80211/iface.c:762`. This is where the core logic of the interface stopping operation should reside, and I need to examine its inner workings. I'll need to see how the interface shutdown is coordinated, and how the driver gets involved.
|
| 33/2 |
2026/08/10 01:10 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/iface.c Name:ieee80211_do_stop]
Results: map[SourceCode: 479: static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down)
480: {
481: struct ieee80211_local *local = sdata->local;
482: struct ieee80211_sub_if_data *iter;
483: unsigned long flags;
484: struct sk_buff_head freeq;
485: struct sk_buff *skb, *tmp;
486: u32 hw_reconf_flags = 0;
487: int i, flushed;
488: struct ps_data *ps;
489: struct cfg80211_chan_def chandef;
490: bool cancel_scan;
491: struct cfg80211_nan_func *func;
492:
493: lockdep_assert_wiphy(local->hw.wiphy);
494:
495: clear_bit(SDATA_STATE_RUNNING, &sdata->state);
496: synchronize_rcu(); /* flush _ieee80211_wake_txqs() */
497:
498: cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
499: if (cancel_scan)
500: ieee80211_scan_cancel(local);
501:
502: ieee80211_roc_purge(local, sdata);
503:
504: switch (sdata->vif.type) {
505: case NL80211_IFTYPE_STATION:
506: ieee80211_mgd_stop(sdata);
507: break;
508: case NL80211_IFTYPE_ADHOC:
509: ieee80211_ibss_stop(sdata);
510: break;
511: case NL80211_IFTYPE_MONITOR:
512: list_del_rcu(&sdata->u.mntr.list);
513: break;
514: case NL80211_IFTYPE_AP_VLAN:
515: ieee80211_apvlan_link_clear(sdata);
516: break;
517: default:
518: break;
519: }
520:
521: /*
522: * Remove all stations associated with this interface.
523: *
524: * This must be done before calling ops->remove_interface()
525: * because otherwise we can later invoke ops->sta_notify()
526: * whenever the STAs are removed, and that invalidates driver
527: * assumptions about always getting a vif pointer that is valid
528: * (because if we remove a STA after ops->remove_interface()
529: * the driver will have removed the vif info already!)
530: *
531: * For AP_VLANs, NAN and NAN_DATA stations may exist since there's
532: * nothing else that would have removed them, but in other modes there
533: * shouldn't be any stations.
534: */
535: flushed = sta_info_flush(sdata, -1);
536: WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
537: sdata->vif.type != NL80211_IFTYPE_NAN &&
538: sdata->vif.type != NL80211_IFTYPE_NAN_DATA && flushed > 0);
539:
540: /* don't count this interface for allmulti while it is down */
541: if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
542: atomic_dec(&local->iff_allmultis);
543:
544: if (sdata->vif.type == NL80211_IFTYPE_AP) {
545: local->fif_pspoll--;
546: local->fif_probe_req--;
547: } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
548: local->fif_probe_req--;
549: }
550:
551: if (sdata->dev) {
552: netif_addr_lock_bh(sdata->dev);
553: spin_lock_bh(&local->filter_lock);
554: __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
555: sdata->dev->addr_len);
556: spin_unlock_bh(&local->filter_lock);
557: netif_addr_unlock_bh(sdata->dev);
558: }
559:
560: timer_delete_sync(&local->dynamic_ps_timer);
561: wiphy_work_cancel(local->hw.wiphy, &local->dynamic_ps_enable_work);
562:
563: WARN(ieee80211_vif_is_mld(&sdata->vif),
564: "destroying interface with valid links 0x%04x\n",
565: sdata->vif.valid_links);
566:
567: sdata->vif.bss_conf.csa_active = false;
568: if (sdata->vif.type == NL80211_IFTYPE_STATION)
569: sdata->deflink.u.mgd.csa.waiting_bcn = false;
570: ieee80211_vif_unblock_queues_csa(sdata);
571:
572: wiphy_work_cancel(local->hw.wiphy, &sdata->deflink.csa.finalize_work);
573: wiphy_work_cancel(local->hw.wiphy,
574: &sdata->deflink.color_change_finalize_work);
575: wiphy_hrtimer_work_cancel(local->hw.wiphy,
576: &sdata->deflink.dfs_cac_timer_work);
577:
578: if (sdata->wdev.links[0].cac_started) {
579: chandef = sdata->vif.bss_conf.chanreq.oper;
580: WARN_ON(local->suspended);
581: ieee80211_link_release_channel(&sdata->deflink);
582: cfg80211_cac_event(sdata->dev, &chandef,
583: NL80211_RADAR_CAC_ABORTED,
584: GFP_KERNEL, 0);
585: }
586:
587: if (sdata->vif.type == NL80211_IFTYPE_AP) {
588: WARN_ON(!list_empty(&sdata->u.ap.vlans));
589: } else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
590: /* remove all packets in parent bc_buf pointing to this dev */
591: __skb_queue_head_init(&freeq);
592: ps = &sdata->bss->ps;
593:
594: spin_lock_irqsave(&ps->bc_buf.lock, flags);
595: skb_queue_walk_safe(&ps->bc_buf, skb, tmp) {
596: if (skb->dev == sdata->dev) {
597: __skb_unlink(skb, &ps->bc_buf);
598: local->total_ps_buffered--;
599: __skb_queue_tail(&freeq, skb);
600: }
601: }
602: spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
603:
604: skb_queue_walk_safe(&freeq, skb, tmp) {
605: __skb_unlink(skb, &freeq);
606: ieee80211_free_txskb(&local->hw, skb);
607: }
608: }
609:
610: if (going_down)
611: local->open_count--;
612:
613: switch (sdata->vif.type) {
614: case NL80211_IFTYPE_AP_VLAN:
615: list_del(&sdata->u.vlan.list);
616: RCU_INIT_POINTER(sdata->vif.bss_conf.chanctx_conf, NULL);
617: /* see comment in the default case below */
618: ieee80211_free_keys(sdata, true);
619: /* no need to tell driver */
620: break;
621: case NL80211_IFTYPE_MONITOR:
622: local->monitors--;
623:
624: if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
625: !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
626:
627: local->virt_monitors--;
628: if (local->virt_monitors == 0) {
629: local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
630: hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
631: }
632:
633: ieee80211_adjust_monitor_flags(sdata, -1);
634: }
635: break;
636: case NL80211_IFTYPE_NAN:
637: /* Check if any open NAN_DATA interfaces */
638: list_for_each_entry(iter, &local->interfaces, list) {
639: WARN_ON(iter->vif.type == NL80211_IFTYPE_NAN_DATA &&
640: ieee80211_sdata_running(iter));
641: }
642:
643: /* clean all the functions */
644: if (!(local->hw.wiphy->nan_capa.flags &
645: WIPHY_NAN_FLAGS_USERSPACE_DE)) {
646: spin_lock_bh(&sdata->u.nan.de.func_lock);
647:
648: idr_for_each_entry(&sdata->u.nan.de.function_inst_ids,
649: func, i) {
650: idr_remove(&sdata->u.nan.de.function_inst_ids, i);
651: cfg80211_free_nan_func(func);
652: }
653: idr_destroy(&sdata->u.nan.de.function_inst_ids);
654:
655: spin_unlock_bh(&sdata->u.nan.de.func_lock);
656: }
657:
658: /*
659: * Free the remaining keys that might be associated with the
660: * NAN interface, e.g., IGTK and BIGTK used for Tx.
661: */
662: ieee80211_free_keys(sdata, true);
663: break;
664: case NL80211_IFTYPE_NAN_DATA:
665: RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
666: fallthrough;
667: default:
668: wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
669: /*
670: * When we get here, the interface is marked down.
671: * Free the remaining keys, if there are any
672: * (which can happen in AP mode if userspace sets
673: * keys before the interface is operating)
674: *
675: * Force the key freeing to always synchronize_net()
676: * to wait for the RX path in case it is using this
677: * interface enqueuing frames at this very time on
678: * another CPU.
679: */
680: ieee80211_free_keys(sdata, true);
681: skb_queue_purge(&sdata->skb_queue);
682: skb_queue_purge(&sdata->status_queue);
683: }
684:
685: /*
686: * Since ieee80211_free_txskb() may issue __dev_queue_xmit()
687: * which should be called with interrupts enabled, reclamation
688: * is done in two phases:
689: */
690: __skb_queue_head_init(&freeq);
691:
692: /* unlink from local queues... */
693: spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
694: for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
695: skb_queue_walk_safe(&local->pending[i], skb, tmp) {
696: struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
697: if (info->control.vif == &sdata->vif) {
698: __skb_unlink(skb, &local->pending[i]);
699: __skb_queue_tail(&freeq, skb);
700: }
701: }
702: }
703: spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
704:
705: /* ... and perform actual reclamation with interrupts enabled. */
706: skb_queue_walk_safe(&freeq, skb, tmp) {
707: __skb_unlink(skb, &freeq);
708: ieee80211_free_txskb(&local->hw, skb);
709: }
710:
711: if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
712: ieee80211_txq_remove_vlan(local, sdata);
713:
714: if (sdata->vif.txq)
715: ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq));
716:
717: if (sdata->vif.txq_mgmt)
718: ieee80211_txq_purge(sdata->local,
719: to_txq_info(sdata->vif.txq_mgmt));
720:
721: sdata->bss = NULL;
722:
723: if (local->open_count == 0)
724: ieee80211_clear_tx_pending(local);
725:
726: sdata->vif.bss_conf.beacon_int = 0;
727:
728: /*
729: * If the interface goes down while suspended, presumably because
730: * the device was unplugged and that happens before our resume,
731: * then the driver is already unconfigured and the remainder of
732: * this function isn't needed.
733: * XXX: what about WoWLAN? If the device has software state, e.g.
734: * memory allocated, it might expect teardown commands from
735: * mac80211 here?
736: */
737: if (local->suspended) {
738: WARN_ON(local->wowlan);
739: WARN_ON(rcu_access_pointer(local->monitor_sdata));
740: return;
741: }
742:
743: switch (sdata->vif.type) {
744: case NL80211_IFTYPE_AP_VLAN:
745: break;
746: case NL80211_IFTYPE_MONITOR:
747: if (local->virt_monitors == 0)
748: ieee80211_del_virtual_monitor(local);
749:
750: ieee80211_recalc_idle(local);
751: ieee80211_recalc_offload(local);
752:
753: if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
754: !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
755: break;
756:
757: ieee80211_link_release_channel(&sdata->deflink);
758: fallthrough;
759: default:
760: if (!going_down)
761: break;
762: drv_remove_interface(local, sdata);
763:
764: /* Clear private driver data to prevent reuse */
765: memset(sdata->vif.drv_priv, 0, local->hw.vif_data_size);
766: }
767:
768: ieee80211_recalc_ps(local);
769:
770: if (cancel_scan)
771: wiphy_delayed_work_flush(local->hw.wiphy, &local->scan_work);
772:
773: if (local->open_count == 0) {
774: ieee80211_stop_device(local, false);
775:
776: /* no reconfiguring after stop! */
777: return;
778: }
779:
780: /* do after stop to avoid reconfiguring when we stop anyway */
781: ieee80211_configure_filter(local);
782: ieee80211_hw_config(local, -1, hw_reconf_flags);
783:
784: /* Passing NULL means an interface is picked for configuration */
785: if (local->virt_monitors == local->open_count)
786: ieee80211_add_virtual_monitor(local, NULL);
787: }
SourceFile:net/mac80211/iface.c]
|
| 34/2 |
2026/08/10 01:10 |
llm |
expert |
0m
Model:
Tokens:
input: 29294
output: 48
thoughts: 102
Thoughts: **Analyzing the IEEE 802.11 Interface Shutdown Sequence**
Okay, so I'm digging into this `ieee80211` code, specifically the shutdown path. It looks like `ieee80211_do_stop` is the key function here. Now, if `going_down` is set to true, it calls `drv_remove_interface`. Hold on a second, that rings a bell! Wasn't there something about `ieee80211_remove_interfaces` in the picture too? Yeah, I'm pretty sure that function calls `ieee80211_teardown_sdata`. I need to confirm the relationship here, to be absolutely sure. Right, let's take a look at the code for `ieee80211_remove_interfaces` β specifically line 2492 in `net/mac80211/iface.c`. Let's see what that code block is all about. This flow needs to make sense...
|
| 35/2 |
2026/08/10 01:11 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/iface.c Name:ieee80211_remove_interfaces]
Results: map[SourceCode:2447: void ieee80211_remove_interfaces(struct ieee80211_local *local)
2448: {
2449: struct ieee80211_sub_if_data *sdata, *tmp;
2450: LIST_HEAD(unreg_list);
2451:
2452: ASSERT_RTNL();
2453:
2454: /* Before destroying the interfaces, make sure they're all stopped so
2455: * that the hardware is stopped. Otherwise, the driver might still be
2456: * iterating the interfaces during the shutdown, e.g. from a worker
2457: * or from RX processing or similar, and if it does so (using atomic
2458: * iteration) while we're manipulating the list, the iteration will
2459: * crash.
2460: *
2461: * After this, the hardware should be stopped and the driver should
2462: * have stopped all of its activities, so that we can do RCU-unaware
2463: * manipulations of the interface list below.
2464: */
2465: cfg80211_shutdown_all_interfaces(local->hw.wiphy);
2466:
2467: guard(wiphy)(local->hw.wiphy);
2468:
2469: WARN(local->open_count, "%s: open count remains %d\n",
2470: wiphy_name(local->hw.wiphy), local->open_count);
2471:
2472: mutex_lock(&local->iflist_mtx);
2473: list_splice_init(&local->interfaces, &unreg_list);
2474: mutex_unlock(&local->iflist_mtx);
2475:
2476: list_for_each_entry_safe(sdata, tmp, &unreg_list, list) {
2477: bool netdev = sdata->dev;
2478:
2479: /*
2480: * Remove IP addresses explicitly, since the notifier will
2481: * skip the callbacks if wdev->registered is false, since
2482: * we can't acquire the wiphy_lock() again there if already
2483: * inside this locked section.
2484: */
2485: sdata->vif.cfg.arp_addr_cnt = 0;
2486: if (sdata->vif.type == NL80211_IFTYPE_STATION &&
2487: sdata->u.mgd.associated)
2488: ieee80211_vif_cfg_change_notify(sdata,
2489: BSS_CHANGED_ARP_FILTER);
2490:
2491: list_del(&sdata->list);
2492: cfg80211_unregister_wdev(&sdata->wdev);
2493:
2494: if (!netdev)
2495: kfree(sdata);
2496: }
2497: }
SourceFile:net/mac80211/iface.c]
|
| 36/2 |
2026/08/10 01:11 |
llm |
expert |
0m
Model:
Tokens:
input: 30553
output: 33
thoughts: 501
Thoughts: **Dissecting the Mac80211 Interface Teardown**
Okay, let's break this down. My initial thought was that `cfg80211_unregister_wdev` directly triggered `unregister_netdevice_many`. But hold on, the trail then leads to `ieee80211_teardown_sdata` via `unregister_netdevice_many`? No, that's not quite right. It seems `unregister_netdevice_many_notify` is the key, and *it* calls `ndev->priv_destructor` β my intuition is there. So where does `ieee80211_teardown_sdata` fit?
Right, the stack trace confirms it. `unregister_netdevice_many_notify` handles this through `dev->netdev_ops->ndo_uninit`. That makes sense; the notification is the crucial part. So, `ieee80211_teardown_sdata` is definitely reached through the `ndo_uninit` path in this whole process. Now, I need to check `net/mac80211/iface.c` for any direct references to `ndo_uninit` for complete clarity.
|
| 37/2 |
2026/08/10 01:11 |
tool |
grepper |
0m
Args: map[Expression:ndo_uninit PathPrefix:net/mac80211/]
Results: map[Output:net/mac80211/iface.c=941=static const struct net_device_ops ieee80211_dataif_ops = {
--
net/mac80211/iface.c-943- .ndo_stop = ieee80211_stop,
net/mac80211/iface.c:944: .ndo_uninit = ieee80211_uninit,
net/mac80211/iface.c-945- .ndo_start_xmit = ieee80211_subif_start_xmit,
--
net/mac80211/iface.c=979=static const struct net_device_ops ieee80211_monitorif_ops = {
--
net/mac80211/iface.c-981- .ndo_stop = ieee80211_stop,
net/mac80211/iface.c:982: .ndo_uninit = ieee80211_uninit,
net/mac80211/iface.c-983- .ndo_start_xmit = ieee80211_monitor_start_xmit,
--
net/mac80211/iface.c=1047=static const struct net_device_ops ieee80211_dataif_8023_ops = {
--
net/mac80211/iface.c-1049- .ndo_stop = ieee80211_stop,
net/mac80211/iface.c:1050: .ndo_uninit = ieee80211_uninit,
net/mac80211/iface.c-1051- .ndo_start_xmit = ieee80211_subif_start_xmit_8023,
]
|
| 38/2 |
2026/08/10 01:11 |
llm |
expert |
0m
Model:
Tokens:
input: 31875
output: 47
thoughts: 32
Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective:
**Diving into the 802.11 Deinitialization**
Alright, I'm thinking about the teardown process for a wireless interface, specifically within the mac80211 framework. The mental journey begins with: where does this thing actually get uninitialized? I remember the rough structure of the code, so the immediate question is: let's go straight to `ieee80211_uninit`. It should be in `net/mac80211/iface.c`. That function will be key to understanding how a wireless interface is properly shut down when the user or system wants it gone. What's the complete resource release and state transition logic within? I need to check how it deals with pending operations, locks, and any hardware-specific cleanup. Gotta make sure we're handling all the edge cases correctly there. Itβs important because improper initialization/deinitialization is a common source of stability problems in these sorts of systems.
|
| 39/2 |
2026/08/10 01:11 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/iface.c Name:ieee80211_uninit]
Results: map[SourceCode: 927: static void ieee80211_uninit(struct net_device *dev)
928: {
929: ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
930: }
SourceFile:net/mac80211/iface.c]
|
| 40/2 |
2026/08/10 01:11 |
llm |
expert |
0m
Model:
Tokens:
input: 32299
output: 43
thoughts: 56
Thoughts: Okay, let's break this down.
**Diving into the Interface Shutdown**
Right, so `ieee80211_remove_interfaces` β that's the function that's responsible for, well, removing the interfaces. And it looks like the crucial step here is that it calls `cfg80211_shutdown_all_interfaces` with `local->hw.wiphy` as the argument. Okay, that makes sense; we're using the cfg80211 regulatory/configuration system. Now, let me see what's happening *inside* `cfg80211_shutdown_all_interfaces`. I need to understand the specifics of how it's orchestrating the shutdown. Where does that go next?
|
| 41/2 |
2026/08/10 01:11 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/wireless/core.c Name:cfg80211_shutdown_all_interfaces]
Results: map[SourceCode: 347: void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
348: {
349: struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
350: struct wireless_dev *wdev;
351:
352: ASSERT_RTNL();
353:
354: /*
355: * Some netdev interfaces need to be closed before some non-netdev
356: * ones, i.e. NAN_DATA interfaces need to be closed before the NAN
357: * interface
358: */
359: list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
360: if (wdev->netdev) {
361: dev_close(wdev->netdev);
362: continue;
363: }
364: }
365:
366: guard(wiphy)(wiphy);
367:
368: list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
369: switch (wdev->iftype) {
370: case NL80211_IFTYPE_P2P_DEVICE:
371: cfg80211_stop_p2p_device(rdev, wdev);
372: break;
373: case NL80211_IFTYPE_NAN:
374: cfg80211_stop_nan(rdev, wdev);
375: break;
376: case NL80211_IFTYPE_PD:
377: cfg80211_stop_pd(rdev, wdev);
378: break;
379: default:
380: break;
381: }
382: }
383: }
SourceFile:net/wireless/core.c]
|
| 42/2 |
2026/08/10 01:11 |
llm |
expert |
0m
Model:
Tokens:
input: 33151
output: 46
thoughts: 84
Thoughts: Here's my thought process, as I delve into this code:
**Analyzing the Interface Shutdown Sequence in cfg80211**
Okay, so `cfg80211_shutdown_all_interfaces` is the starting point. It seems pretty clear it's going to shut down all the wireless interfaces. The first thing that jumps out is the call to `dev_close(wdev->netdev)`. This suggests a standard device closure mechanism is being used, likely through the kernel's network device infrastructure.
Now, `dev_close` is the key. Let's see what *it* does... Ah, it calls `ndo_stop`. And based on the context, `ndo_stop` appears to be aliased to `ieee80211_stop`. That's a strong clue β it's definitely tied to the 802.11 stack. We are in the right place.
So, `ieee80211_stop` is the function that's doing the heavy lifting to stop the wireless interface, likely in `net/mac80211/iface.c`. My next step is to examine that function, `ieee80211_stop`, in detail. I'll be looking for resource deallocation, state transitions, and any potential locking issues related to stopping the 802.11 interface cleanly. I want to see how the driver specifically handles the stop operation, especially in the context of the mac80211 framework. I will be very interested in what that function does to the network device.
|
| 43/2 |
2026/08/10 01:11 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/iface.c Name:ieee80211_stop]
Results: map[SourceCode: 845: static int ieee80211_stop(struct net_device *dev)
846: {
847: struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
848:
849: /* close dependent VLAN interfaces before locking wiphy */
850: if (sdata->vif.type == NL80211_IFTYPE_AP) {
851: struct ieee80211_sub_if_data *vlan, *tmpsdata;
852:
853: list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
854: u.vlan.list)
855: dev_close(vlan->dev);
856: }
857:
858: guard(wiphy)(sdata->local->hw.wiphy);
859:
860: wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->activate_links_work);
861:
862: /* Close the dependent MBSSID interfaces with wiphy lock as we may be
863: * terminating its partner links too in case of MLD.
864: */
865: if (sdata->vif.type == NL80211_IFTYPE_AP)
866: ieee80211_stop_mbssid(sdata);
867:
868: ieee80211_do_stop(sdata, true);
869:
870: return 0;
871: }
SourceFile:net/mac80211/iface.c]
|
| 44/2 |
2026/08/10 01:11 |
llm |
expert |
0m
Model:
Tokens:
input: 34138
output: 48
thoughts: 1034
Thoughts: **Analyzing the Wireless Interface Shutdown Sequence**
Okay, so I'm tracing the shutdown process of a wireless interface, starting with `ieee80211_stop`. It kicks off a series of calls: `ieee80211_do_stop`, `drv_remove_interface`, `ieee80211_remove_interfaces`, `cfg80211_unregister_wdev`, eventually leading to `ieee80211_uninit` and `ieee80211_teardown_sdata`. Within `ieee80211_teardown_sdata`, we hit `ieee80211_link_stop` and then `ieee80211_link_release_channel`, all of which look like they're aimed at cleanly unassigning channel context.
The critical point is `drv_unassign_vif_chanctx`, called within the channel release sequence. This, in turn, calls `check_sdata_in_driver`, which checks `IEEE80211_SDATA_IN_DRIVER`. Now, here's where things get interesting. We know that `drv_remove_interface`, which is called *before* `drv_unassign_vif_chanctx`, clears that very flag. So, `check_sdata_in_driver` *should* always warn if `curr_ctx` is not NULL which is strange.
Wait, if `curr_ctx` is NOT NULL, it means the channel context wasn't properly unassigned during the initial `ieee80211_do_stop` call. Is this a bug? Should it have been?
I need to revisit `ieee80211_do_stop` and see if the channel context is unconditionally released there. I see a conditional release based on `cac_started`. If CAC is active, the channel is released. And there's also an explicit release for monitor interfaces. I'm seeing if it's AP, but it doesn't look like an unconditional release happens for all interface types. This is the crux of it. For APs, or other interface types, there's a potential that the channel context remains assigned, even though we're supposedly shutting down the interface. That's a definite problem, and it's likely the cause of the `check_sdata_in_driver` warning. This warrants a deeper look into the logic within `ieee80211_do_stop` to ensure channel contexts are released in all the relevant scenarios during interface shutdown.
|
| 45/2 |
2026/08/10 01:11 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/iface.c Name:ieee80211_do_stop]
Results: map[SourceCode: 479: static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down)
480: {
481: struct ieee80211_local *local = sdata->local;
482: struct ieee80211_sub_if_data *iter;
483: unsigned long flags;
484: struct sk_buff_head freeq;
485: struct sk_buff *skb, *tmp;
486: u32 hw_reconf_flags = 0;
487: int i, flushed;
488: struct ps_data *ps;
489: struct cfg80211_chan_def chandef;
490: bool cancel_scan;
491: struct cfg80211_nan_func *func;
492:
493: lockdep_assert_wiphy(local->hw.wiphy);
494:
495: clear_bit(SDATA_STATE_RUNNING, &sdata->state);
496: synchronize_rcu(); /* flush _ieee80211_wake_txqs() */
497:
498: cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
499: if (cancel_scan)
500: ieee80211_scan_cancel(local);
501:
502: ieee80211_roc_purge(local, sdata);
503:
504: switch (sdata->vif.type) {
505: case NL80211_IFTYPE_STATION:
506: ieee80211_mgd_stop(sdata);
507: break;
508: case NL80211_IFTYPE_ADHOC:
509: ieee80211_ibss_stop(sdata);
510: break;
511: case NL80211_IFTYPE_MONITOR:
512: list_del_rcu(&sdata->u.mntr.list);
513: break;
514: case NL80211_IFTYPE_AP_VLAN:
515: ieee80211_apvlan_link_clear(sdata);
516: break;
517: default:
518: break;
519: }
520:
521: /*
522: * Remove all stations associated with this interface.
523: *
524: * This must be done before calling ops->remove_interface()
525: * because otherwise we can later invoke ops->sta_notify()
526: * whenever the STAs are removed, and that invalidates driver
527: * assumptions about always getting a vif pointer that is valid
528: * (because if we remove a STA after ops->remove_interface()
529: * the driver will have removed the vif info already!)
530: *
531: * For AP_VLANs, NAN and NAN_DATA stations may exist since there's
532: * nothing else that would have removed them, but in other modes there
533: * shouldn't be any stations.
534: */
535: flushed = sta_info_flush(sdata, -1);
536: WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
537: sdata->vif.type != NL80211_IFTYPE_NAN &&
538: sdata->vif.type != NL80211_IFTYPE_NAN_DATA && flushed > 0);
539:
540: /* don't count this interface for allmulti while it is down */
541: if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
542: atomic_dec(&local->iff_allmultis);
543:
544: if (sdata->vif.type == NL80211_IFTYPE_AP) {
545: local->fif_pspoll--;
546: local->fif_probe_req--;
547: } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
548: local->fif_probe_req--;
549: }
550:
551: if (sdata->dev) {
552: netif_addr_lock_bh(sdata->dev);
553: spin_lock_bh(&local->filter_lock);
554: __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
555: sdata->dev->addr_len);
556: spin_unlock_bh(&local->filter_lock);
557: netif_addr_unlock_bh(sdata->dev);
558: }
559:
560: timer_delete_sync(&local->dynamic_ps_timer);
561: wiphy_work_cancel(local->hw.wiphy, &local->dynamic_ps_enable_work);
562:
563: WARN(ieee80211_vif_is_mld(&sdata->vif),
564: "destroying interface with valid links 0x%04x\n",
565: sdata->vif.valid_links);
566:
567: sdata->vif.bss_conf.csa_active = false;
568: if (sdata->vif.type == NL80211_IFTYPE_STATION)
569: sdata->deflink.u.mgd.csa.waiting_bcn = false;
570: ieee80211_vif_unblock_queues_csa(sdata);
571:
572: wiphy_work_cancel(local->hw.wiphy, &sdata->deflink.csa.finalize_work);
573: wiphy_work_cancel(local->hw.wiphy,
574: &sdata->deflink.color_change_finalize_work);
575: wiphy_hrtimer_work_cancel(local->hw.wiphy,
576: &sdata->deflink.dfs_cac_timer_work);
577:
578: if (sdata->wdev.links[0].cac_started) {
579: chandef = sdata->vif.bss_conf.chanreq.oper;
580: WARN_ON(local->suspended);
581: ieee80211_link_release_channel(&sdata->deflink);
582: cfg80211_cac_event(sdata->dev, &chandef,
583: NL80211_RADAR_CAC_ABORTED,
584: GFP_KERNEL, 0);
585: }
586:
587: if (sdata->vif.type == NL80211_IFTYPE_AP) {
588: WARN_ON(!list_empty(&sdata->u.ap.vlans));
589: } else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
590: /* remove all packets in parent bc_buf pointing to this dev */
591: __skb_queue_head_init(&freeq);
592: ps = &sdata->bss->ps;
593:
594: spin_lock_irqsave(&ps->bc_buf.lock, flags);
595: skb_queue_walk_safe(&ps->bc_buf, skb, tmp) {
596: if (skb->dev == sdata->dev) {
597: __skb_unlink(skb, &ps->bc_buf);
598: local->total_ps_buffered--;
599: __skb_queue_tail(&freeq, skb);
600: }
601: }
602: spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
603:
604: skb_queue_walk_safe(&freeq, skb, tmp) {
605: __skb_unlink(skb, &freeq);
606: ieee80211_free_txskb(&local->hw, skb);
607: }
608: }
609:
610: if (going_down)
611: local->open_count--;
612:
613: switch (sdata->vif.type) {
614: case NL80211_IFTYPE_AP_VLAN:
615: list_del(&sdata->u.vlan.list);
616: RCU_INIT_POINTER(sdata->vif.bss_conf.chanctx_conf, NULL);
617: /* see comment in the default case below */
618: ieee80211_free_keys(sdata, true);
619: /* no need to tell driver */
620: break;
621: case NL80211_IFTYPE_MONITOR:
622: local->monitors--;
623:
624: if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
625: !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
626:
627: local->virt_monitors--;
628: if (local->virt_monitors == 0) {
629: local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
630: hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
631: }
632:
633: ieee80211_adjust_monitor_flags(sdata, -1);
634: }
635: break;
636: case NL80211_IFTYPE_NAN:
637: /* Check if any open NAN_DATA interfaces */
638: list_for_each_entry(iter, &local->interfaces, list) {
639: WARN_ON(iter->vif.type == NL80211_IFTYPE_NAN_DATA &&
640: ieee80211_sdata_running(iter));
641: }
642:
643: /* clean all the functions */
644: if (!(local->hw.wiphy->nan_capa.flags &
645: WIPHY_NAN_FLAGS_USERSPACE_DE)) {
646: spin_lock_bh(&sdata->u.nan.de.func_lock);
647:
648: idr_for_each_entry(&sdata->u.nan.de.function_inst_ids,
649: func, i) {
650: idr_remove(&sdata->u.nan.de.function_inst_ids, i);
651: cfg80211_free_nan_func(func);
652: }
653: idr_destroy(&sdata->u.nan.de.function_inst_ids);
654:
655: spin_unlock_bh(&sdata->u.nan.de.func_lock);
656: }
657:
658: /*
659: * Free the remaining keys that might be associated with the
660: * NAN interface, e.g., IGTK and BIGTK used for Tx.
661: */
662: ieee80211_free_keys(sdata, true);
663: break;
664: case NL80211_IFTYPE_NAN_DATA:
665: RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
666: fallthrough;
667: default:
668: wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
669: /*
670: * When we get here, the interface is marked down.
671: * Free the remaining keys, if there are any
672: * (which can happen in AP mode if userspace sets
673: * keys before the interface is operating)
674: *
675: * Force the key freeing to always synchronize_net()
676: * to wait for the RX path in case it is using this
677: * interface enqueuing frames at this very time on
678: * another CPU.
679: */
680: ieee80211_free_keys(sdata, true);
681: skb_queue_purge(&sdata->skb_queue);
682: skb_queue_purge(&sdata->status_queue);
683: }
684:
685: /*
686: * Since ieee80211_free_txskb() may issue __dev_queue_xmit()
687: * which should be called with interrupts enabled, reclamation
688: * is done in two phases:
689: */
690: __skb_queue_head_init(&freeq);
691:
692: /* unlink from local queues... */
693: spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
694: for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
695: skb_queue_walk_safe(&local->pending[i], skb, tmp) {
696: struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
697: if (info->control.vif == &sdata->vif) {
698: __skb_unlink(skb, &local->pending[i]);
699: __skb_queue_tail(&freeq, skb);
700: }
701: }
702: }
703: spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
704:
705: /* ... and perform actual reclamation with interrupts enabled. */
706: skb_queue_walk_safe(&freeq, skb, tmp) {
707: __skb_unlink(skb, &freeq);
708: ieee80211_free_txskb(&local->hw, skb);
709: }
710:
711: if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
712: ieee80211_txq_remove_vlan(local, sdata);
713:
714: if (sdata->vif.txq)
715: ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq));
716:
717: if (sdata->vif.txq_mgmt)
718: ieee80211_txq_purge(sdata->local,
719: to_txq_info(sdata->vif.txq_mgmt));
720:
721: sdata->bss = NULL;
722:
723: if (local->open_count == 0)
724: ieee80211_clear_tx_pending(local);
725:
726: sdata->vif.bss_conf.beacon_int = 0;
727:
728: /*
729: * If the interface goes down while suspended, presumably because
730: * the device was unplugged and that happens before our resume,
731: * then the driver is already unconfigured and the remainder of
732: * this function isn't needed.
733: * XXX: what about WoWLAN? If the device has software state, e.g.
734: * memory allocated, it might expect teardown commands from
735: * mac80211 here?
736: */
737: if (local->suspended) {
738: WARN_ON(local->wowlan);
739: WARN_ON(rcu_access_pointer(local->monitor_sdata));
740: return;
741: }
742:
743: switch (sdata->vif.type) {
744: case NL80211_IFTYPE_AP_VLAN:
745: break;
746: case NL80211_IFTYPE_MONITOR:
747: if (local->virt_monitors == 0)
748: ieee80211_del_virtual_monitor(local);
749:
750: ieee80211_recalc_idle(local);
751: ieee80211_recalc_offload(local);
752:
753: if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
754: !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
755: break;
756:
757: ieee80211_link_release_channel(&sdata->deflink);
758: fallthrough;
759: default:
760: if (!going_down)
761: break;
762: drv_remove_interface(local, sdata);
763:
764: /* Clear private driver data to prevent reuse */
765: memset(sdata->vif.drv_priv, 0, local->hw.vif_data_size);
766: }
767:
768: ieee80211_recalc_ps(local);
769:
770: if (cancel_scan)
771: wiphy_delayed_work_flush(local->hw.wiphy, &local->scan_work);
772:
773: if (local->open_count == 0) {
774: ieee80211_stop_device(local, false);
775:
776: /* no reconfiguring after stop! */
777: return;
778: }
779:
780: /* do after stop to avoid reconfiguring when we stop anyway */
781: ieee80211_configure_filter(local);
782: ieee80211_hw_config(local, -1, hw_reconf_flags);
783:
784: /* Passing NULL means an interface is picked for configuration */
785: if (local->virt_monitors == local->open_count)
786: ieee80211_add_virtual_monitor(local, NULL);
787: }
SourceFile:net/mac80211/iface.c]
|
| 46/2 |
2026/08/10 01:11 |
llm |
expert |
0m
Model:
Tokens:
input: 41263
output: 31
thoughts: 2090
Thoughts: **Analysis of a Mac80211 Channel Context Release Warning**
Okay, so here's what I've figured out after digging into this code. It seems like the function `ieee80211_link_release_channel` isn't always called in the right order, specifically when dealing with interfaces other than monitor interfaces. The issue arises during the unregistration process of a wireless device.
Essentially, the process goes like this: `ieee80211_do_stop` removes the driver's interface, clearing `IEEE80211_SDATA_IN_DRIVER`. Later, during teardown, `ieee80211_teardown_sdata` is called, which then calls a chain of functions ending in `drv_unassign_vif_chanctx`. This last function checks `IEEE80211_SDATA_IN_DRIVER`, and since it was already cleared, we get a warning.
The core of the problem seems to be that the channel context isn't being unassigned *before* `drv_remove_interface` is called for non-monitor interfaces. I'm trying to figure out if it's a matter of incorrect order in the function calls, or if the logic is missing a critical step for these other interface types.
The important point is that this warning itself doesn't cause a crash, memory leak, or any serious security risk directly. `drv_unassign_vif_chanctx` just returns if `check_sdata_in_driver` fails, so it's a no-op at that point.
However, the warning can be triggered when a network namespace containing a wireless device is destroyed, or when a USB Wi-Fi dongle is unplugged. This means it's not specific to the `mac80211_hwsim` driver, but it could happen with any Mac80211 driver if the interface is up during hardware unregistration. It appears that `ieee80211_link_release_channel` is supposed to be called earlier in the process but isn't. I'm now checking the code to confirm all where it is called and if this is a general case. It could be possible it's only called in a very specific flow. I'm checking if this happened for a long time without being noticed, and if so, what causes this?
So, this is a warning, not a critical bug, but something should be fixed to prevent it. There is nothing to leak or cause use-after-free, and it doesn't represent a vulnerability.
|
| 47/2 |
2026/08/10 01:11 |
tool |
codesearch-find-references |
0m
Args: map[Name:ieee80211_link_release_channel]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:__ieee80211_sta_join_ibss SourceFile:net/mac80211/ibss.c SourceLine:357] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_del_virtual_monitor SourceFile:net/mac80211/iface.c SourceLine:1347] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_destroy_assoc_data SourceFile:net/mac80211/mlme.c SourceLine:5342] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_destroy_auth_data SourceFile:net/mac80211/mlme.c SourceLine:5285] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_dfs_cac_cancel SourceFile:net/mac80211/util.c SourceLine:3694] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_dfs_cac_timer_work SourceFile:net/mac80211/mlme.c SourceLine:3991] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_do_stop SourceFile:net/mac80211/iface.c SourceLine:581] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_do_stop SourceFile:net/mac80211/iface.c SourceLine:757] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_end_cac SourceFile:net/mac80211/cfg.c SourceLine:4263] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_ibss_disconnect SourceFile:net/mac80211/ibss.c SourceLine:702] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_leave_mesh SourceFile:net/mac80211/cfg.c SourceLine:3333] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_stop SourceFile:net/mac80211/link.c SourceLine:183] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_mgd_auth SourceFile:net/mac80211/mlme.c SourceLine:10049] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_ocb_leave SourceFile:net/mac80211/ocb.c SourceLine:235] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_prep_connection SourceFile:net/mac80211/mlme.c SourceLine:9752] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_set_disassoc SourceFile:net/mac80211/mlme.c SourceLine:4711] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_set_monitor_channel SourceFile:net/mac80211/cfg.c SourceLine:1087] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_start_ap SourceFile:net/mac80211/cfg.c SourceLine:1932] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_stop_ap SourceFile:net/mac80211/cfg.c SourceLine:2125]] TruncatedOutput:false]
|
| 48/2 |
2026/08/10 01:11 |
llm |
expert |
0m
Model:
Tokens:
input: 45153
output: 47
thoughts: 50
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Analyzing the IEEE 802.11 Access Point Shutdown Sequence**
Right, so `ieee80211_stop_ap` is the crucial function here, and I've seen it before. The key point of focus now is that it calls `ieee80211_link_release_channel`. I immediately need to understand the relationship and implications of that call. Why is channel release directly tied into stopping an AP? Is it a graceful shutdown, a forced termination, or a cleanup step? Is it releasing the hardware, or just marking the channel as unused in the software? I should also quickly check if `ieee80211_stop_ap` itself has any other calls that are also relevant. Now, I need to look into `ieee80211_stop_ap`. Time to dig in and see what's really happening during the AP's shutdown.
|
| 49/2 |
2026/08/10 01:11 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/cfg.c Name:ieee80211_stop_ap]
Results: map[SourceCode:2011: static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
2012: unsigned int link_id)
2013: {
2014: struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2015: struct ieee80211_sub_if_data *vlan;
2016: struct ieee80211_local *local = sdata->local;
2017: struct beacon_data *old_beacon;
2018: struct probe_resp *old_probe_resp;
2019: struct fils_discovery_data *old_fils_discovery;
2020: struct unsol_bcast_probe_resp_data *old_unsol_bcast_probe_resp;
2021: struct s1g_short_beacon_data *old_s1g_short_beacon;
2022: struct cfg80211_chan_def chandef;
2023: struct ieee80211_link_data *link =
2024: sdata_dereference(sdata->link[link_id], sdata);
2025: struct ieee80211_bss_conf *link_conf = link->conf;
2026: u64 changes = BSS_CHANGED_BEACON_ENABLED;
2027: LIST_HEAD(keys);
2028:
2029: lockdep_assert_wiphy(local->hw.wiphy);
2030:
2031: old_beacon = sdata_dereference(link->u.ap.beacon, sdata);
2032: if (!old_beacon)
2033: return -ENOENT;
2034: old_probe_resp = sdata_dereference(link->u.ap.probe_resp,
2035: sdata);
2036: old_fils_discovery = sdata_dereference(link->u.ap.fils_discovery,
2037: sdata);
2038: old_unsol_bcast_probe_resp =
2039: sdata_dereference(link->u.ap.unsol_bcast_probe_resp,
2040: sdata);
2041: old_s1g_short_beacon =
2042: sdata_dereference(link->u.ap.s1g_short_beacon, sdata);
2043:
2044: /* abort any running channel switch or color change */
2045: link_conf->csa_active = false;
2046: link_conf->color_change_active = false;
2047: ieee80211_vif_unblock_queues_csa(sdata);
2048:
2049: ieee80211_free_next_beacon(link);
2050:
2051: /* turn off carrier for this interface and dependent VLANs */
2052: list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
2053: netif_carrier_off(vlan->dev);
2054:
2055: if (ieee80211_num_beaconing_links(sdata) <= 1) {
2056: netif_carrier_off(dev);
2057: sdata->u.ap.active = false;
2058: }
2059:
2060: /* remove beacon and probe response */
2061: RCU_INIT_POINTER(link->u.ap.beacon, NULL);
2062: RCU_INIT_POINTER(link->u.ap.probe_resp, NULL);
2063: RCU_INIT_POINTER(link->u.ap.fils_discovery, NULL);
2064: RCU_INIT_POINTER(link->u.ap.unsol_bcast_probe_resp, NULL);
2065: RCU_INIT_POINTER(link->u.ap.s1g_short_beacon, NULL);
2066: kfree_rcu(old_beacon, rcu_head);
2067: if (old_probe_resp)
2068: kfree_rcu(old_probe_resp, rcu_head);
2069: if (old_fils_discovery)
2070: kfree_rcu(old_fils_discovery, rcu_head);
2071: if (old_unsol_bcast_probe_resp)
2072: kfree_rcu(old_unsol_bcast_probe_resp, rcu_head);
2073: if (old_s1g_short_beacon)
2074: kfree_rcu(old_s1g_short_beacon, rcu_head);
2075:
2076: if (link_conf->ftm_responder) {
2077: link_conf->ftm_responder = false;
2078: changes |= BSS_CHANGED_FTM_RESPONDER;
2079: }
2080:
2081: kfree(link_conf->ftmr_params);
2082: link_conf->ftmr_params = NULL;
2083:
2084: link_conf->bssid_index = 0;
2085: link_conf->nontransmitted = false;
2086: link_conf->ema_ap = false;
2087: link_conf->bssid_indicator = 0;
2088: link_conf->fils_discovery.min_interval = 0;
2089: link_conf->fils_discovery.max_interval = 0;
2090: link_conf->unsol_bcast_probe_resp_interval = 0;
2091:
2092: __sta_info_flush(sdata, true, link_id, NULL);
2093:
2094: ieee80211_stop_mbssid(sdata);
2095: RCU_INIT_POINTER(link_conf->tx_bss_conf, NULL);
2096:
2097: link_conf->enable_beacon = false;
2098: sdata->beacon_rate_set = false;
2099: sdata->vif.cfg.ssid_len = 0;
2100: sdata->vif.cfg.s1g = false;
2101: clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
2102: ieee80211_link_info_change_notify(sdata, link, changes);
2103:
2104: ieee80211_remove_link_keys(link, &keys);
2105: if (!list_empty(&keys)) {
2106: synchronize_net();
2107: ieee80211_free_key_list(local, &keys);
2108: }
2109:
2110: if (sdata->wdev.links[link_id].cac_started) {
2111: chandef = link_conf->chanreq.oper;
2112: wiphy_hrtimer_work_cancel(wiphy, &link->dfs_cac_timer_work);
2113: cfg80211_cac_event(sdata->dev, &chandef,
2114: NL80211_RADAR_CAC_ABORTED,
2115: GFP_KERNEL, link_id);
2116: }
2117:
2118: drv_stop_ap(sdata->local, sdata, link_conf);
2119:
2120: /* free all potentially still buffered bcast frames */
2121: local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
2122: ieee80211_purge_tx_queue(&local->hw, &sdata->u.ap.ps.bc_buf);
2123:
2124: ieee80211_link_copy_chanctx_to_vlans(link, true);
2125: ieee80211_link_release_channel(link);
2126:
2127: return 0;
2128: }
SourceFile:net/mac80211/cfg.c]
|
| 50/2 |
2026/08/10 01:11 |
llm |
expert |
0m
Model:
Tokens:
input: 47791
output: 30
thoughts: 855
Thoughts: **Channel Context Release in AP Interface Shutdown**
Okay, let's break this down. My initial thought was triggered by seeing `ieee80211_stop_ap` call `ieee80211_link_release_channel(link)`. I know `ieee80211_stop_ap` is specifically for AP interfaces, which is clear. Then I see that `cfg80211_shutdown_all_interfaces` eventually calls `ieee80211_stop` which itself calls `ieee80211_do_stop`. The alarm bells start ringing immediately because `ieee80211_do_stop` *doesn't* directly call `ieee80211_stop_ap`.
Looking closer, I see the switch statement within `ieee80211_do_stop` and realize that for `NL80211_IFTYPE_AP`, it's basically a no-op! It doesn't trigger `ieee80211_stop_ap`. This makes sense because `ieee80211_stop_ap` is the function called when userspace explicitly stops the AP. (e.g. via `NL80211_CMD_STOP_AP`). If I manually stop the AP, this is triggered. But when an interface is *closed* (e.g., `ifconfig wlan0 down`), `ieee80211_stop` is called.
Here's the problem: when `ifconfig wlan0 down` is called, is the AP stopped correctly? The answer seems to be yes, `ieee80211_do_stop` does indeed stop the interface. BUT, it doesn't call `ieee80211_link_release_channel` for AP interfaces! This is the critical point. If it doesn't release the channel context directly, that suggests the channel context isn't released when the interface goes down.
Okay, let's step through it, when is the context released? I dig a little further. When `ieee80211_teardown_sdata` is eventually called, it does call `ieee80211_link_stop` which then, finally, calls `ieee80211_link_release_channel`. But, that's AFTER `drv_remove_interface` has already been called within `ieee80211_do_stop`!
This means `IEEE80211_SDATA_IN_DRIVER` has already been cleared. And, when it does call `ieee80211_link_release_channel` it calls `drv_unassign_vif_chanctx` which *warns*! So I can confidently say this warning happens EVERY SINGLE TIME an AP interface is removed while it's still up and has an active channel context. That's a huge code smell!
But if it happens every time, why is this even being reported as a bug? Is this a recent regression then? I need to check the git log for `net/mac80211/driver-ops.h` and `net/mac80211/chan.c`. This might be a clue.
|
| 51/2 |
2026/08/10 01:12 |
tool |
git-log |
8m
Args: map[CodeRegexp:check_sdata_in_driver Count:10]
Results: map[Output:840492bf333b wifi: mac80211: add NAN peer schedule support
4cb1ce7e254a wifi: mac80211: add link_sta_statistics ops to fill link station statistics
8f500fbc6c65 wifi: mac80211: process and save negotiated TID to Link mapping request
e993af2ed288 wifi: mac80211: add a driver callback to check active_links
a1f5dcb1c0c1 wifi: mac80211: add a driver callback to add vif debugfs
5549b0885d6f wifi: mac80211: add more ops assertions
d00800a289c9 wifi: mac80211: add flush_sta method
170cd6a66d9a wifi: mac80211: add netdev per-link debugfs data and driver hook
81202305f7c2 wifi: mac80211: add support for set_hw_timestamp command
d2caad527c19 wifi: mac80211: add API to show the link STAs in debugfs
]
|
| 52/2 |
2026/08/10 01:20 |
llm |
expert |
0m
Model:
Tokens:
input: 49709
output: 27
thoughts: 31
Thoughts: Here's a summary of my thinking, expressed in the first person:
**Analyzing a Kernel Patch**
Okay, let's dive into this patch titled "mac80211: add more ops assertions" with the ID `5549b0885d6f`. My initial instinct is that this likely concerns the Wi-Fi subsystem, specifically the mac80211 framework. The title itself suggests they're adding assertions, which points towards improving code reliability and potentially catching bugs earlier during development or runtime. Assertions are a crucial aspect of robust code, acting as guardrails to ensure certain invariants hold true.
Given my understanding of mac80211, I expect this patch is touching the operational functions β the "ops" β that define how specific Wi-Fi drivers interact with the core mac80211 layer. These "ops" are essentially the bridge between the generic mac80211 code and the hardware-specific details of different Wi-Fi chips. Adding assertions in this area is a smart move; any unexpected behavior from the driver within these "ops" can lead to serious system instability.
I'll be looking for where these assertions are being introduced. Is it related to parameter validation, return value checking, state transitions, or perhaps some interaction with concurrency primitives? I'm curious to see the specific conditions the developers thought were crucial to verify. The level of detail and precision in these assertions will be a good indicator of the patch author's understanding of the system's subtleties. I anticipate this will improve the overall code quality and maintainability of the mac80211 framework. This is the kind of change that, while seemingly minor, can have a profound impact on the long-term health of the kernel's Wi-Fi functionality.
|
| 53/2 |
2026/08/10 01:21 |
tool |
git-show |
0m
Args:
Results: map[Output:commit 5549b0885d6fbad79e0e471a9a863bd2f45af0c5
Author: Johannes Berg <johannes.berg@intel.com>
Date: Mon Aug 28 13:59:36 2023 +0200
wifi: mac80211: add more ops assertions
Add more might_sleep() checks and check sdata-in-driver
for one additional place.
type=feature
ticket=jira:WIFI-314309
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c
index 30cd0c905a24..376dae58b5a6 100644
--- a/net/mac80211/driver-ops.c
+++ b/net/mac80211/driver-ops.c
@@ -285,6 +285,8 @@ int drv_assign_vif_chanctx(struct ieee80211_local *local,
{
int ret = 0;
+ might_sleep();
+
drv_verify_link_exists(sdata, link_conf);
if (!check_sdata_in_driver(sdata))
return -EIO;
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index c4505593ba7a..d95ff2282f54 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -40,6 +40,8 @@ static inline void drv_tx(struct ieee80211_local *local,
static inline void drv_sync_rx_queues(struct ieee80211_local *local,
struct sta_info *sta)
{
+ might_sleep();
+
if (local->ops->sync_rx_queues) {
trace_drv_sync_rx_queues(local, sta->sdata, &sta->sta);
local->ops->sync_rx_queues(&local->hw);
@@ -569,6 +571,8 @@ static inline void drv_sta_statistics(struct ieee80211_local *local,
struct ieee80211_sta *sta,
struct station_info *sinfo)
{
+ might_sleep();
+
sdata = get_bss_sdata(sdata);
if (!check_sdata_in_driver(sdata))
return;
@@ -616,6 +620,8 @@ static inline int drv_get_survey(struct ieee80211_local *local, int idx,
{
int ret = -EOPNOTSUPP;
+ might_sleep();
+
trace_drv_get_survey(local, idx, survey);
if (local->ops->get_survey)
@@ -797,6 +803,8 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct cfg80211_gtk_rekey_data *data)
{
+ might_sleep();
+
if (!check_sdata_in_driver(sdata))
return;
@@ -987,6 +995,8 @@ static inline void drv_stop_ap(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *link_conf)
{
+ might_sleep();
+
/* make sure link_conf is protected */
drv_verify_link_exists(sdata, link_conf);
@@ -1016,6 +1026,8 @@ drv_set_default_unicast_key(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
int key_idx)
{
+ might_sleep();
+
if (!check_sdata_in_driver(sdata))
return;
@@ -1046,6 +1058,8 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
+ might_sleep();
+
if (local->ops->channel_switch_beacon) {
trace_drv_channel_switch_beacon(local, sdata, chandef);
local->ops->channel_switch_beacon(&local->hw, &sdata->vif,
@@ -1060,6 +1074,8 @@ drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
int ret = 0;
+ might_sleep();
+
if (!check_sdata_in_driver(sdata))
return -EIO;
@@ -1077,6 +1093,8 @@ drv_post_channel_switch(struct ieee80211_sub_if_data *sdata)
struct ieee80211_local *local = sdata->local;
int ret = 0;
+ might_sleep();
+
if (!check_sdata_in_driver(sdata))
return -EIO;
@@ -1092,6 +1110,8 @@ drv_abort_channel_switch(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
+ might_sleep();
+
if (!check_sdata_in_driver(sdata))
return;
@@ -1107,6 +1127,8 @@ drv_channel_switch_rx_beacon(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_local *local = sdata->local;
+ might_sleep();
+
if (!check_sdata_in_driver(sdata))
return;
@@ -1163,6 +1185,8 @@ static inline int drv_get_txpower(struct ieee80211_local *local,
{
int ret;
+ might_sleep();
+
if (!local->ops->get_txpower)
return -EOPNOTSUPP;
@@ -1267,6 +1291,10 @@ drv_get_ftm_responder_stats(struct ieee80211_local *local,
{
u32 ret = -EOPNOTSUPP;
+ might_sleep();
+ if (!check_sdata_in_driver(sdata))
+ return -EIO;
+
if (local->ops->get_ftm_responder_stats)
ret = local->ops->get_ftm_responder_stats(&local->hw,
&sdata->vif,
@@ -1436,6 +1464,8 @@ static inline void drv_sta_set_4addr(struct ieee80211_local *local,
struct ieee80211_sta *sta, bool enabled)
{
sdata = get_bss_sdata(sdata);
+
+ might_sleep();
if (!check_sdata_in_driver(sdata))
return;
@@ -1451,6 +1481,8 @@ static inline void drv_sta_set_decap_offload(struct ieee80211_local *local,
bool enabled)
{
sdata = get_bss_sdata(sdata);
+
+ might_sleep();
if (!check_sdata_in_driver(sdata))
return;
@@ -1526,6 +1558,8 @@ static inline int drv_net_setup_tc(struct ieee80211_local *local,
{
int ret = -EOPNOTSUPP;
+ might_sleep();
+
sdata = get_bss_sdata(sdata);
trace_drv_net_setup_tc(local, sdata, type);
if (local->ops->net_setup_tc)
]
|
| 54/2 |
2026/08/10 01:21 |
llm |
expert |
0m
Model:
Tokens:
input: 52511
output: 34
thoughts: 68
Thoughts: Here's my take on the thought process:
**Tracing Down a Code Change**
Okay, hold on a second. I need to make sure I have my facts straight. Did `check_sdata_in_driver` *really* get added in commit `5549b0885d6f`? Something feels off, like I recall seeing it earlier. It's easy to get lost in the commit history, especially when you're dealing with a codebase this complex. I should verify exactly *when* that function was introduced, particularly in relation to `drv_unassign_vif_chanctx`. Let's just double-check that timing and avoid making assumptions. Gotta be precise. The exact introduction point for that function is what I need to establish.
|
| 55/2 |
2026/08/10 01:21 |
tool |
git-log |
9m
Args: map[CodeRegexp:check_sdata_in_driver\(sdata\) Count:10]
Results: map[Output:840492bf333b wifi: mac80211: add NAN peer schedule support
4cb1ce7e254a wifi: mac80211: add link_sta_statistics ops to fill link station statistics
8f500fbc6c65 wifi: mac80211: process and save negotiated TID to Link mapping request
e993af2ed288 wifi: mac80211: add a driver callback to check active_links
a1f5dcb1c0c1 wifi: mac80211: add a driver callback to add vif debugfs
5549b0885d6f wifi: mac80211: add more ops assertions
d00800a289c9 wifi: mac80211: add flush_sta method
170cd6a66d9a wifi: mac80211: add netdev per-link debugfs data and driver hook
81202305f7c2 wifi: mac80211: add support for set_hw_timestamp command
d2caad527c19 wifi: mac80211: add API to show the link STAs in debugfs
]
|
| 56/2 |
2026/08/10 01:30 |
llm |
expert |
0m
Model:
Tokens:
input: 53087
output: 32
thoughts: 18
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Investigating `drv_unassign_vif_chanctx`**
Alright, time to dive into this. The task at hand is to understand the implications of `drv_unassign_vif_chanctx`. My first thought is to immediately go digging through its history. I need to understand when it was introduced, why, and what changes have been made to it over time. I'm looking for the context of its initial implementation β the problem it was designed to solve. Then I'll scan for any bug fixes, optimizations, or significant refactorings. This historical perspective will provide the foundation I need to properly assess its current state and any potential issues. I'll be particularly interested in identifying any interactions or dependencies this function has with other channel assignment or virtual interface management routines. From there, I'll be in a better position to determine its relevance to whatever current problem I'm trying to diagnose or feature I'm trying to implement.
|
| 57/2 |
2026/08/10 01:30 |
tool |
git-log |
10m
Error:
Args: map[CodeRegexp:drv_unassign_vif_chanctx Count:10]
Results:
|
| 58/2 |
2026/08/10 01:40 |
llm |
expert |
0m
Model:
Tokens:
input: 53389
output: 52
thoughts: 22
Thoughts: Here's my take on the thought process, as if I were the one thinking it:
**Diving into the net/mac80211/driver-ops.c History**
Okay, time to get my hands dirty. I need to understand the evolution of this particular driver operations file. The specific file I'm targeting, `net/mac80211/driver-ops.c`, is critical for interfacing the mac80211 stack with the underlying hardware, so understanding its history is paramount. I need to see how the interface has changed over time, what additions or removals have occurred, and what the motivations were behind those modifications. Understanding the context of those changes will shed light on why things are the way they are now. This will likely provide vital context for my current task, whatever it may be. Let's see what the commit history has to tell us.
|
| 59/2 |
2026/08/10 01:40 |
tool |
git-log |
0m
Args: map[CodeRegexp:drv_unassign_vif_chanctx Count:10 PathPrefix:net/mac80211/driver-ops.c]
Results: map[Output:efe9c2bfd1a8 wifi: mac80211: isolate driver from inactive links
]
|
| 60/2 |
2026/08/10 01:40 |
llm |
expert |
0m
Model:
Tokens:
input: 53689
output: 24
thoughts: 15
Thoughts: Okay, here's my interpretation of that seemingly random string, presented as a first-person thought process, keeping in mind that the user is an expert.
**Initial Assessment: Decoding the Enigma**
Hmm, `efe9c2bfd1a8`. That looks like a hexadecimal string, doesn't it? My immediate instinct is to treat this as some kind of encoded representation. Given the context (implied, of course, because I have no external information), it's probably data of some kind. Given that the user is an expert, I'm already mentally running through the likely candidates. Is it a hash? A UUID? Part of a larger identifier? The structure suggests a moderately long sequence, making it potentially a key, an ID, or a representation of some digital content. My background leans toward digital data representation: how would this data likely have been structured? What is its most probable meaning in relation to data science? We should consider its context: is it referring to a dataset, a model, a transaction, or a file? Further information would make the interpretation more meaningful.
|
| 61/2 |
2026/08/10 01:40 |
tool |
git-show |
0m
Args:
Results: map[Output:commit efe9c2bfd1a82894e455514a68dc794556fbd463
Author: Johannes Berg <johannes.berg@intel.com>
Date: Fri Sep 2 16:12:42 2022 +0200
wifi: mac80211: isolate driver from inactive links
In order to let the driver select active links and properly
make multi-link connections, as a first step isolate the
driver from inactive links, and set the active links to be
only the association link for client-side interfaces. For
AP side nothing changes since APs always have to have all
their links active.
To simplify things, update the for_each_sta_active_link()
API to include the appropriate vif pointer.
This also implies not allocating a chanctx for an inactive
link, which requires a few more changes.
Since we now no longer try to program multiple links to the
driver, remove the check in the MLME code.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d4e1d73d88cc..20a2f25a38fa 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1799,6 +1799,9 @@ struct ieee80211_vif_cfg {
* @link_conf: in case of MLD, the per-link BSS configuration,
* indexed by link ID
* @valid_links: bitmap of valid links, or 0 for non-MLO.
+ * @active_links: The bitmap of active links, or 0 for non-MLO.
+ * The driver shouldn't change this directly, but use the
+ * API calls meant for that purpose.
* @addr: address of this interface
* @p2p: indicates whether this AP or STA interface is a p2p
* interface, i.e. a GO or p2p-sta respectively
@@ -1834,7 +1837,7 @@ struct ieee80211_vif {
struct ieee80211_vif_cfg cfg;
struct ieee80211_bss_conf bss_conf;
struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS];
- u16 valid_links;
+ u16 valid_links, active_links;
u8 addr[ETH_ALEN] __aligned(2);
bool p2p;
@@ -1861,12 +1864,11 @@ struct ieee80211_vif {
u8 drv_priv[] __aligned(sizeof(void *));
};
-/* FIXME: for now loop over all the available links; later will be changed
- * to loop only over the active links.
- */
-#define for_each_vif_active_link(vif, link, link_id) \
- for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \
- if ((link = rcu_dereference((vif)->link_conf[link_id])))
+#define for_each_vif_active_link(vif, link, link_id) \
+ for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \
+ if ((!(vif)->active_links || \
+ (vif)->active_links & BIT(link_id)) && \
+ (link = rcu_dereference((vif)->link_conf[link_id])))
static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
{
@@ -2264,13 +2266,13 @@ struct ieee80211_sta {
u8 drv_priv[] __aligned(sizeof(void *));
};
-/* FIXME: need to loop only over links which are active and check the actual
- * lock
- */
-#define for_each_sta_active_link(sta, link_sta, link_id) \
- for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) \
- if (((link_sta) = rcu_dereference_protected((sta)->link[link_id],\
- 1))) \
+/* FIXME: check the locking correctly */
+#define for_each_sta_active_link(vif, sta, link_sta, link_id) \
+ for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) \
+ if ((!(vif)->active_links || \
+ (vif)->active_links & BIT(link_id)) && \
+ ((link_sta) = rcu_dereference_protected((sta)->link[link_id],\
+ 1)))
/**
* enum sta_notify_cmd - sta notify command
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index f247daa41563..e72cf0749d49 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -1799,6 +1799,12 @@ int ieee80211_link_use_channel(struct ieee80211_link_data *link,
lockdep_assert_held(&local->mtx);
+ if (sdata->vif.active_links &&
+ !(sdata->vif.active_links & BIT(link->link_id))) {
+ ieee80211_link_update_chandef(link, chandef);
+ return 0;
+ }
+
mutex_lock(&local->chanctx_mtx);
ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c
index 9b61dc7889c2..5392ffa18270 100644
--- a/net/mac80211/driver-ops.c
+++ b/net/mac80211/driver-ops.c
@@ -192,6 +192,10 @@ int drv_conf_tx(struct ieee80211_local *local,
if (!check_sdata_in_driver(sdata))
return -EIO;
+ if (sdata->vif.active_links &&
+ !(sdata->vif.active_links & BIT(link->link_id)))
+ return 0;
+
if (params->cw_min == 0 || params->cw_min > params->cw_max) {
/*
* If we can't configure hardware anyway, don't warn. We may
@@ -272,6 +276,60 @@ void drv_reset_tsf(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+int drv_assign_vif_chanctx(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx *ctx)
+{
+ int ret = 0;
+
+ drv_verify_link_exists(sdata, link_conf);
+ if (!check_sdata_in_driver(sdata))
+ return -EIO;
+
+ if (sdata->vif.active_links &&
+ !(sdata->vif.active_links & BIT(link_conf->link_id)))
+ return 0;
+
+ trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx);
+ if (local->ops->assign_vif_chanctx) {
+ WARN_ON_ONCE(!ctx->driver_present);
+ ret = local->ops->assign_vif_chanctx(&local->hw,
+ &sdata->vif,
+ link_conf,
+ &ctx->conf);
+ }
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
+void drv_unassign_vif_chanctx(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx *ctx)
+{
+ might_sleep();
+
+ drv_verify_link_exists(sdata, link_conf);
+ if (!check_sdata_in_driver(sdata))
+ return;
+
+ if (sdata->vif.active_links &&
+ !(sdata->vif.active_links & BIT(link_conf->link_id)))
+ return;
+
+ trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
+ if (local->ops->unassign_vif_chanctx) {
+ WARN_ON_ONCE(!ctx->driver_present);
+ local->ops->unassign_vif_chanctx(&local->hw,
+ &sdata->vif,
+ link_conf,
+ &ctx->conf);
+ }
+ trace_drv_return_void(local);
+}
+
int drv_switch_vif_chanctx(struct ieee80211_local *local,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs, enum ieee80211_chanctx_switch_mode mode)
@@ -346,3 +404,117 @@ int drv_ampdu_action(struct ieee80211_local *local,
return ret;
}
+
+void drv_link_info_changed(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *info,
+ int link_id, u64 changed)
+{
+ might_sleep();
+
+ if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_ENABLED) &&
+ sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+ sdata->vif.type != NL80211_IFTYPE_OCB))
+ return;
+
+ if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
+ sdata->vif.type == NL80211_IFTYPE_NAN ||
+ (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+ !sdata->vif.bss_conf.mu_mimo_owner &&
+ !(changed & BSS_CHANGED_TXPOWER))))
+ return;
+
+ if (!check_sdata_in_driver(sdata))
+ return;
+
+ if (sdata->vif.active_links &&
+ !(sdata->vif.active_links & BIT(link_id)))
+ return;
+
+ trace_drv_link_info_changed(local, sdata, info, changed);
+ if (local->ops->link_info_changed)
+ local->ops->link_info_changed(&local->hw, &sdata->vif,
+ info, changed);
+ else if (local->ops->bss_info_changed)
+ local->ops->bss_info_changed(&local->hw, &sdata->vif,
+ info, changed);
+ trace_drv_return_void(local);
+}
+
+int drv_set_key(struct ieee80211_local *local,
+ enum set_key_cmd cmd,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ int ret;
+
+ might_sleep();
+
+ sdata = get_bss_sdata(sdata);
+ if (!check_sdata_in_driver(sdata))
+ return -EIO;
+
+ if (WARN_ON(key->link_id >= 0 && sdata->vif.active_links &&
+ !(sdata->vif.active_links & BIT(key->link_id))))
+ return -ENOLINK;
+
+ trace_drv_set_key(local, cmd, sdata, sta, key);
+ ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
+int drv_change_vif_links(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ u16 old_links, u16 new_links,
+ struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
+{
+ int ret = -EOPNOTSUPP;
+
+ might_sleep();
+
+ if (!check_sdata_in_driver(sdata))
+ return -EIO;
+
+ if (old_links == new_links)
+ return 0;
+
+ trace_drv_change_vif_links(local, sdata, old_links, new_links);
+ if (local->ops->change_vif_links)
+ ret = local->ops->change_vif_links(&local->hw, &sdata->vif,
+ old_links, new_links, old);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
+int drv_change_sta_links(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ u16 old_links, u16 new_links)
+{
+ int ret = -EOPNOTSUPP;
+
+ might_sleep();
+
+ if (!check_sdata_in_driver(sdata))
+ return -EIO;
+
+ old_links &= sdata->vif.active_links;
+ new_links &= sdata->vif.active_links;
+
+ if (old_links == new_links)
+ return 0;
+
+ trace_drv_change_sta_links(local, sdata, sta, old_links, new_links);
+ if (local->ops->change_sta_links)
+ ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta,
+ old_links, new_links);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 482f5c97a72b..81e40b0a3b16 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -165,40 +165,10 @@ static inline void drv_vif_cfg_changed(struct ieee80211_local *local,
trace_drv_return_void(local);
}
-static inline void drv_link_info_changed(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct ieee80211_bss_conf *info,
- int link_id, u64 changed)
-{
- might_sleep();
-
- if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON |
- BSS_CHANGED_BEACON_ENABLED) &&
- sdata->vif.type != NL80211_IFTYPE_AP &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
- sdata->vif.type != NL80211_IFTYPE_OCB))
- return;
-
- if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
- sdata->vif.type == NL80211_IFTYPE_NAN ||
- (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
- !sdata->vif.bss_conf.mu_mimo_owner &&
- !(changed & BSS_CHANGED_TXPOWER))))
- return;
-
- if (!check_sdata_in_driver(sdata))
- return;
-
- trace_drv_link_info_changed(local, sdata, info, changed);
- if (local->ops->link_info_changed)
- local->ops->link_info_changed(&local->hw, &sdata->vif,
- info, changed);
- else if (local->ops->bss_info_changed)
- local->ops->bss_info_changed(&local->hw, &sdata->vif,
- info, changed);
- trace_drv_return_void(local);
-}
+void drv_link_info_changed(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *info,
+ int link_id, u64 changed);
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
struct netdev_hw_addr_list *mc_list)
@@ -256,25 +226,11 @@ static inline int drv_set_tim(struct ieee80211_local *local,
return ret;
}
-static inline int drv_set_key(struct ieee80211_local *local,
- enum set_key_cmd cmd,
- struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- int ret;
-
- might_sleep();
-
- sdata = get_bss_sdata(sdata);
- if (!check_sdata_in_driver(sdata))
- return -EIO;
-
- trace_drv_set_key(local, cmd, sdata, sta, key);
- ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
- trace_drv_return_int(local, ret);
- return ret;
-}
+int drv_set_key(struct ieee80211_local *local,
+ enum set_key_cmd cmd,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key);
static inline void drv_update_tkip_key(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
@@ -945,52 +901,14 @@ static inline void drv_verify_link_exists(struct ieee80211_sub_if_data *sdata,
sdata_assert_lock(sdata);
}
-static inline int drv_assign_vif_chanctx(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct ieee80211_bss_conf *link_conf,
- struct ieee80211_chanctx *ctx)
-{
- int ret = 0;
-
- drv_verify_link_exists(sdata, link_conf);
- if (!check_sdata_in_driver(sdata))
- return -EIO;
-
- trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx);
- if (local->ops->assign_vif_chanctx) {
- WARN_ON_ONCE(!ctx->driver_present);
- ret = local->ops->assign_vif_chanctx(&local->hw,
- &sdata->vif,
- link_conf,
- &ctx->conf);
- }
- trace_drv_return_int(local, ret);
-
- return ret;
-}
-
-static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct ieee80211_bss_conf *link_conf,
- struct ieee80211_chanctx *ctx)
-{
- might_sleep();
-
- drv_verify_link_exists(sdata, link_conf);
- if (!check_sdata_in_driver(sdata))
- return;
-
- trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx);
- if (local->ops->unassign_vif_chanctx) {
- WARN_ON_ONCE(!ctx->driver_present);
- local->ops->unassign_vif_chanctx(&local->hw,
- &sdata->vif,
- link_conf,
- &ctx->conf);
- }
- trace_drv_return_void(local);
-}
-
+int drv_assign_vif_chanctx(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx *ctx);
+void drv_unassign_vif_chanctx(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_chanctx *ctx);
int drv_switch_vif_chanctx(struct ieee80211_local *local,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs, enum ieee80211_chanctx_switch_mode mode);
@@ -1552,46 +1470,13 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
return ret;
}
-static inline int drv_change_vif_links(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- u16 old_links, u16 new_links,
- struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
-{
- int ret = -EOPNOTSUPP;
-
- might_sleep();
-
- if (!check_sdata_in_driver(sdata))
- return -EIO;
-
- trace_drv_change_vif_links(local, sdata, old_links, new_links);
- if (local->ops->change_vif_links)
- ret = local->ops->change_vif_links(&local->hw, &sdata->vif,
- old_links, new_links, old);
- trace_drv_return_int(local, ret);
-
- return ret;
-}
-
-static inline int drv_change_sta_links(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct ieee80211_sta *sta,
- u16 old_links, u16 new_links)
-{
- int ret = -EOPNOTSUPP;
-
- might_sleep();
-
- if (!check_sdata_in_driver(sdata))
- return -EIO;
-
- trace_drv_change_sta_links(local, sdata, sta, old_links, new_links);
- if (local->ops->change_sta_links)
- ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta,
- old_links, new_links);
- trace_drv_return_int(local, ret);
-
- return ret;
-}
+int drv_change_vif_links(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ u16 old_links, u16 new_links,
+ struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]);
+int drv_change_sta_links(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ u16 old_links, u16 new_links);
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index d89ec93b243b..f6f0f65fb255 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -177,6 +177,10 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
}
}
+ if (key->conf.link_id >= 0 && sdata->vif.active_links &&
+ !(sdata->vif.active_links & BIT(key->conf.link_id)))
+ return 0;
+
ret = drv_set_key(key->local, SET_KEY, sdata,
sta ? &sta->sta : NULL, &key->conf);
@@ -246,6 +250,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
sta = key->sta;
sdata = key->sdata;
+ if (key->conf.link_id >= 0 && sdata->vif.active_links &&
+ !(sdata->vif.active_links & BIT(key->conf.link_id)))
+ return;
+
if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
diff --git a/net/mac80211/link.c b/net/mac80211/link.c
index 096f313c2a6e..8df348a5edce 100644
--- a/net/mac80211/link.c
+++ b/net/mac80211/link.c
@@ -73,28 +73,37 @@ struct link_container {
struct ieee80211_bss_conf conf;
};
-static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata,
- struct link_container **links)
+static void ieee80211_tear_down_links(struct ieee80211_sub_if_data *sdata,
+ struct link_container **links, u16 mask)
{
+ struct ieee80211_link_data *link;
LIST_HEAD(keys);
unsigned int link_id;
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
- if (!links[link_id])
+ if (!(mask & BIT(link_id)))
+ continue;
+ link = &links[link_id]->data;
+ if (link_id == 0 && !link)
+ link = &sdata->deflink;
+ if (WARN_ON(!link))
continue;
- ieee80211_remove_link_keys(&links[link_id]->data, &keys);
+ ieee80211_remove_link_keys(link, &keys);
+ ieee80211_link_stop(link);
}
synchronize_rcu();
ieee80211_free_key_list(sdata->local, &keys);
+}
- for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
- if (!links[link_id])
- continue;
- ieee80211_link_stop(&links[link_id]->data);
+static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata,
+ struct link_container **links)
+{
+ unsigned int link_id;
+
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
kfree(links[link_id]);
- }
}
static int ieee80211_check_dup_link_addrs(struct ieee80211_sub_if_data *sdata)
@@ -123,11 +132,38 @@ static int ieee80211_check_dup_link_addrs(struct ieee80211_sub_if_data *sdata)
return 0;
}
+static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
+ u16 links)
+{
+ sdata->vif.valid_links = links;
+
+ if (!links) {
+ sdata->vif.active_links = 0;
+ return;
+ }
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ /* in an AP all links are always active */
+ sdata->vif.active_links = links;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (sdata->vif.active_links)
+ break;
+ WARN_ON(hweight16(links) > 1);
+ sdata->vif.active_links = links;
+ break;
+ default:
+ WARN_ON(1);
+ }
+}
+
static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
struct link_container **to_free,
u16 new_links)
{
u16 old_links = sdata->vif.valid_links;
+ u16 old_active = sdata->vif.active_links;
unsigned long add = new_links & ~old_links;
unsigned long rem = old_links & ~new_links;
unsigned int link_id;
@@ -195,13 +231,17 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
ieee80211_link_init(sdata, -1, &sdata->deflink,
&sdata->vif.bss_conf);
- sdata->vif.valid_links = new_links;
-
ret = ieee80211_check_dup_link_addrs(sdata);
if (!ret) {
+ /* for keys we will not be able to undo this */
+ ieee80211_tear_down_links(sdata, to_free, rem);
+
+ ieee80211_set_vif_links_bitmaps(sdata, new_links);
+
/* tell the driver */
ret = drv_change_vif_links(sdata->local, sdata,
- old_links, new_links,
+ old_links & old_active,
+ new_links & sdata->vif.active_links,
old);
}
@@ -209,7 +249,7 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
/* restore config */
memcpy(sdata->link, old_data, sizeof(old_data));
memcpy(sdata->vif.link_conf, old, sizeof(old));
- sdata->vif.valid_links = old_links;
+ ieee80211_set_vif_links_bitmaps(sdata, old_links);
/* and free (only) the newly allocated links */
memset(to_free, 0, sizeof(links));
goto free;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 699e409ef45a..609584493ce0 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4056,11 +4056,11 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
goto out;
}
- sband = ieee80211_get_link_sband(link);
- if (!sband) {
+ if (WARN_ON(!link->conf->chandef.chan)) {
ret = false;
goto out;
}
+ sband = local->hw.wiphy->bands[link->conf->chandef.chan->band];
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
(!elems->he_cap || !elems->he_operation)) {
@@ -4884,8 +4884,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
err = ieee80211_prep_channel(sdata, link,
assoc_data->link[link_id].bss,
&link->u.mgd.conn_flags);
- if (err)
+ if (err) {
+ link_info(link, "prep_channel failed\n");
goto out_err;
+ }
}
err = ieee80211_mgd_setup_link_sta(link, sta, link_sta,
@@ -6889,23 +6891,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
size += req->links[i].elems_len;
- if (req->ap_mld_addr) {
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
- if (!req->links[i].bss)
- continue;
- if (i == assoc_link_id)
- continue;
- /*
- * For now, support only a single link in MLO, we
- * don't have the necessary parsing of the multi-
- * link element in the association response, etc.
- */
- sdata_info(sdata,
- "refusing MLO association with >1 links\n");
- return -EINVAL;
- }
- }
-
/* FIXME: no support for 4-addr MLO yet */
if (sdata->u.mgd.use_4addr && req->link_id >= 0)
return -EOPNOTSUPP;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3359ab332d7d..0ea5d50091dc 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2900,7 +2900,7 @@ void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata,
*/
rcu_read_unlock();
- if (WARN_ON_ONCE(!chanctx_conf))
+ if (!chanctx_conf)
goto unlock;
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx,
]
|
| 62/2 |
2026/08/10 01:40 |
llm |
expert |
0m
Model:
Tokens:
input: 64221
output: 52
thoughts: 341
Thoughts: **Analyzing a Driver Bug**
Okay, so `efe9c2bfd1a8` cleanly isolated the driver from inactive links. It added `sdata->vif.active_links`, which is good. Now, in `drv_unassign_vif_chanctx`, it's checking `sdata->vif.active_links` and returning if the link isn't active.
But hold on, `check_sdata_in_driver` was already there! That's been around for a while. Why are we getting a warning *now*?
The pieces are starting to fit... `ieee80211_do_stop` clears `IEEE80211_SDATA_IN_DRIVER`. And then, `ieee80211_teardown_sdata` calls `ieee80211_link_stop`. *That* calls `ieee80211_link_release_channel`, which ultimately calls `drv_unassign_vif_chanctx`.
Aha! It seems like if `ieee80211_link_release_channel` is called *after* `drv_remove_interface`, that's when the warning appears. This makes sense.
The critical question is, was `ieee80211_link_release_channel` *always* called in `ieee80211_teardown_sdata`? I need to check the history of when `ieee80211_link_stop` was added to `ieee80211_teardown_sdata` to pinpoint the introduction of this behavior. I'll check that next.
|
| 63/2 |
2026/08/10 01:41 |
tool |
git-log |
0m
Args: map[CodeRegexp:ieee80211_link_stop Count:10 PathPrefix:net/mac80211/iface.c]
Results: map[Output:e73b5e51a05d wifi: mac80211: move link code to a new file
b2e8434f1829 wifi: mac80211: set up/tear down client vif links properly
]
|
| 64/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 65062
output: 27
thoughts: 18
Thoughts: Okay, here's my interpretation of that.
**Analyzing the Query: `b2e8434f1829`**
Alright, that identifier... it's a bit cryptic, isn't it? Just a string of hexadecimal characters. My immediate thought is, what is this referring to? It could be anything: a commit hash in version control, a unique identifier for a database record, a cryptographic key, a file hash, or even just a random string used for testing. The lack of context is frustrating. My instinct as an expert is to start mentally cataloging possibilities and the tools I would use to investigate. I'd need to know the origin of this string to even begin to know how to interpret it effectively. Is it from a log file, a database output, a code repository, an email? Without context, this could be anything.
|
| 65/2 |
2026/08/10 01:41 |
tool |
git-show |
0m
Args:
Results: map[Output:commit b2e8434f1829bb500f79b1adb80ffed2316811cf
Author: Johannes Berg <johannes.berg@intel.com>
Date: Fri Jun 24 10:57:41 2022 +0200
wifi: mac80211: set up/tear down client vif links properly
In station/client mode, the link data needs a bit more
initialization and destruction than just zero-init and
kfree() respectively, implement that.
This required some shuffling of the link data handling
in general, as we should set it up in setup and do the
teardown in teardown, otherwise we're asymmetric in
case of interface type changes.
Also stop using kfree_rcu(), we cannot guarantee that
nothing is scheduling things that live within the link
(e.g. the u.mgd.request_smps_work) until we're sure it
cannot be referenced anymore, therefore synchronize
instead. This isn't very efficient, but we can always
optimize it later.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8c14274c9aaf..05996df627ea 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1772,6 +1772,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
u8 reason, bool tx);
+void ieee80211_mgd_setup_link(struct ieee80211_link_data *link);
+void ieee80211_mgd_stop_link(struct ieee80211_link_data *link);
/* IBSS code */
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 55b0a1fa92ab..fbb9c9c291b9 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -368,6 +368,208 @@ static int ieee80211_open(struct net_device *dev)
return err;
}
+static void ieee80211_link_setup(struct ieee80211_link_data *link)
+{
+ if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
+ ieee80211_mgd_setup_link(link);
+}
+
+static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
+ int link_id,
+ struct ieee80211_link_data *link,
+ struct ieee80211_bss_conf *link_conf)
+{
+ bool deflink = link_id < 0;
+
+ if (link_id < 0)
+ link_id = 0;
+
+ rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf);
+ rcu_assign_pointer(sdata->link[link_id], link);
+
+ link->sdata = sdata;
+ link->link_id = link_id;
+ link->conf = link_conf;
+
+ INIT_WORK(&link->csa_finalize_work,
+ ieee80211_csa_finalize_work);
+ INIT_WORK(&link->color_change_finalize_work,
+ ieee80211_color_change_finalize_work);
+ INIT_LIST_HEAD(&link->assigned_chanctx_list);
+ INIT_LIST_HEAD(&link->reserved_chanctx_list);
+ INIT_DELAYED_WORK(&link->dfs_cac_timer_work,
+ ieee80211_dfs_cac_timer_work);
+
+ if (!deflink) {
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP:
+ ether_addr_copy(link_conf->addr,
+ sdata->wdev.links[link_id].addr);
+ WARN_ON(!(sdata->wdev.valid_links & BIT(link_id)));
+ break;
+ case NL80211_IFTYPE_STATION:
+ eth_random_addr(link_conf->addr);
+ ether_addr_copy(sdata->wdev.links[link_id].addr,
+ link_conf->addr);
+ break;
+ default:
+ WARN_ON(1);
+ }
+ }
+}
+
+static void ieee80211_link_stop(struct ieee80211_link_data *link)
+{
+ if (link->sdata->vif.type == NL80211_IFTYPE_STATION)
+ ieee80211_mgd_stop_link(link);
+}
+
+struct link_container {
+ struct ieee80211_link_data data;
+ struct ieee80211_bss_conf conf;
+};
+
+static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata,
+ struct link_container **links)
+{
+ unsigned int link_id;
+
+ synchronize_rcu();
+
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
+ if (!links[link_id])
+ continue;
+ ieee80211_link_stop(&links[link_id]->data);
+ kfree(links[link_id]);
+ }
+}
+
+static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
+ struct link_container **to_free,
+ u16 new_links)
+{
+ u16 old_links = sdata->vif.valid_links;
+ unsigned long add = new_links & ~old_links;
+ unsigned long rem = old_links & ~new_links;
+ unsigned int link_id;
+ int ret;
+ struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link;
+ struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS];
+ bool use_deflink = old_links == 0; /* set for error case */
+
+ sdata_assert_lock(sdata);
+
+ memset(to_free, 0, sizeof(links));
+
+ if (old_links == new_links)
+ return 0;
+
+ /* allocate new link structures first */
+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (!link) {
+ ret = -ENOMEM;
+ goto free;
+ }
+ links[link_id] = link;
+ }
+
+ /* keep track of the old pointers for the driver */
+ BUILD_BUG_ON(sizeof(old) != sizeof(sdata->vif.link_conf));
+ memcpy(old, sdata->vif.link_conf, sizeof(old));
+ /* and for us in error cases */
+ BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
+ memcpy(old_data, sdata->link, sizeof(old_data));
+
+ /* link them into data structures */
+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+ WARN_ON(!use_deflink &&
+ rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink);
+
+ link = links[link_id];
+ ieee80211_link_init(sdata, link_id, &link->data, &link->conf);
+ ieee80211_link_setup(&link->data);
+ }
+
+ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
+ RCU_INIT_POINTER(sdata->link[link_id], NULL);
+ RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
+ }
+
+ sdata->vif.valid_links = new_links;
+
+ /* tell the driver */
+ ret = drv_change_vif_links(sdata->local, sdata,
+ old_links, new_links,
+ old);
+ if (ret) {
+ /* restore config */
+ memcpy(sdata->link, old_data, sizeof(old_data));
+ memcpy(sdata->vif.link_conf, old, sizeof(old));
+ sdata->vif.valid_links = old_links;
+ /* and free the newly allocated links */
+ goto deinit;
+ }
+
+ /* use deflink/bss_conf again if and only if there are no more links */
+ use_deflink = new_links == 0;
+
+ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
+ if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
+ continue;
+ /*
+ * we must have allocated the data through this path so
+ * we know we can free both at the same time
+ */
+ to_free[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
+ typeof(*links[link_id]),
+ data);
+ }
+
+ goto deinit;
+free:
+ /* if we failed during allocation, only free all */
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
+ kfree(links[link_id]);
+ links[link_id] = NULL;
+ }
+deinit:
+ if (use_deflink)
+ ieee80211_link_init(sdata, -1, &sdata->deflink,
+ &sdata->vif.bss_conf);
+ return ret;
+}
+
+int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
+ u16 new_links)
+{
+ struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS];
+ int ret;
+
+ ret = ieee80211_vif_update_links(sdata, links, new_links);
+ ieee80211_free_links(sdata, links);
+
+ return ret;
+}
+
+static void ieee80211_vif_clear_links(struct ieee80211_sub_if_data *sdata)
+{
+ struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS];
+
+ /*
+ * The locking here is different because when we free links
+ * in the station case we need to be able to cancel_work_sync()
+ * something that also takes the lock.
+ */
+
+ sdata_lock(sdata);
+ ieee80211_vif_update_links(sdata, links, 0);
+ sdata_unlock(sdata);
+
+ ieee80211_free_links(sdata, links);
+}
+
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down)
{
struct ieee80211_local *local = sdata->local;
@@ -729,6 +931,9 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
if (ieee80211_vif_is_mesh(&sdata->vif))
ieee80211_mesh_teardown_sdata(sdata);
+
+ ieee80211_vif_clear_links(sdata);
+ ieee80211_link_stop(&sdata->deflink);
}
static void ieee80211_uninit(struct net_device *dev)
@@ -1021,50 +1226,6 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
}
-static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
- int link_id,
- struct ieee80211_link_data *link,
- struct ieee80211_bss_conf *link_conf)
-{
- bool deflink = link_id < 0;
-
- if (link_id < 0)
- link_id = 0;
-
- rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf);
- rcu_assign_pointer(sdata->link[link_id], link);
-
- link->sdata = sdata;
- link->link_id = link_id;
- link->conf = link_conf;
-
- INIT_WORK(&link->csa_finalize_work,
- ieee80211_csa_finalize_work);
- INIT_WORK(&link->color_change_finalize_work,
- ieee80211_color_change_finalize_work);
- INIT_LIST_HEAD(&link->assigned_chanctx_list);
- INIT_LIST_HEAD(&link->reserved_chanctx_list);
- INIT_DELAYED_WORK(&link->dfs_cac_timer_work,
- ieee80211_dfs_cac_timer_work);
-
- if (!deflink) {
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_AP:
- ether_addr_copy(link_conf->addr,
- sdata->wdev.links[link_id].addr);
- WARN_ON(!(sdata->wdev.valid_links & BIT(link_id)));
- break;
- case NL80211_IFTYPE_STATION:
- eth_random_addr(link_conf->addr);
- ether_addr_copy(sdata->wdev.links[link_id].addr,
- link_conf->addr);
- break;
- default:
- WARN_ON(1);
- }
- }
-}
-
static void ieee80211_sdata_init(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
@@ -1787,6 +1948,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
break;
}
+ /* need to do this after the switch so vif.type is correct */
+ ieee80211_link_setup(&sdata->deflink);
+
ieee80211_debugfs_add_netdev(sdata);
}
@@ -2355,97 +2519,3 @@ void ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata)
else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
atomic_dec(&sdata->u.vlan.num_mcast_sta);
}
-
-int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata,
- u16 new_links)
-{
- u16 old_links = sdata->vif.valid_links;
- unsigned long add = new_links & ~old_links;
- unsigned long rem = old_links & ~new_links;
- unsigned int link_id;
- int ret;
- struct {
- struct ieee80211_link_data data;
- struct ieee80211_bss_conf conf;
- struct rcu_head rcu_head;
- } *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link;
- struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS];
- struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS];
- bool use_deflink = old_links == 0; /* set for error case */
-
- sdata_assert_lock(sdata);
-
- if (old_links == new_links)
- return 0;
-
- /* allocate new link structures first */
- for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
- link = kzalloc(sizeof(*link), GFP_KERNEL);
- if (!link) {
- ret = -ENOMEM;
- goto free;
- }
- links[link_id] = link;
- }
-
- /* keep track of the old pointers for the driver */
- BUILD_BUG_ON(sizeof(old) != sizeof(sdata->vif.link_conf));
- memcpy(old, sdata->vif.link_conf, sizeof(old));
- /* and for us in error cases */
- BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link));
- memcpy(old_data, sdata->link, sizeof(old_data));
-
- /* link them into data structures */
- for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
- WARN_ON(!use_deflink &&
- rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink);
-
- link = links[link_id];
- ieee80211_link_init(sdata, link_id, &link->data, &link->conf);
- }
-
- for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- RCU_INIT_POINTER(sdata->link[link_id], NULL);
- RCU_INIT_POINTER(sdata->vif.link_conf[link_id], NULL);
- }
-
- sdata->vif.valid_links = new_links;
-
- /* tell the driver */
- ret = drv_change_vif_links(sdata->local, sdata,
- old_links, new_links,
- old);
- if (ret) {
- /* restore config */
- memcpy(sdata->link, old_data, sizeof(old_data));
- memcpy(sdata->vif.link_conf, old, sizeof(old));
- sdata->vif.valid_links = old_links;
- /* and free the newly allocated links */
- goto free;
- }
-
- /* use deflink/bss_conf again if and only if there are no more links */
- use_deflink = new_links == 0;
-
- /* now use this to free the old links */
- memset(links, 0, sizeof(links));
- for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- if (rcu_access_pointer(sdata->link[link_id]) == &sdata->deflink)
- continue;
- /*
- * we must have allocated the data through this path so
- * we know we can free both at the same time
- */
- links[link_id] = container_of(rcu_access_pointer(sdata->link[link_id]),
- typeof(*links[link_id]),
- data);
- }
-
-free:
- for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
- kfree_rcu(links[link_id], rcu_head);
- if (use_deflink)
- ieee80211_link_init(sdata, -1, &sdata->deflink,
- &sdata->vif.bss_conf);
- return ret;
-}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d4d226436e8d..299381d19760 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5033,17 +5033,14 @@ static void ieee80211_request_smps_mgd_work(struct work_struct *work)
/* interface setup */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_if_managed *ifmgd;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- ifmgd = &sdata->u.mgd;
INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
INIT_WORK(&ifmgd->beacon_connection_loss_work,
ieee80211_beacon_connection_loss_work);
INIT_WORK(&ifmgd->csa_connection_drop_work,
ieee80211_csa_connection_drop_work);
- INIT_WORK(&sdata->deflink.u.mgd.request_smps_work,
- ieee80211_request_smps_mgd_work);
INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work,
ieee80211_tdls_peer_del_work);
timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0);
@@ -5057,20 +5054,28 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ifmgd->powersave = sdata->wdev.ps;
ifmgd->uapsd_queues = sdata->local->hw.uapsd_queues;
ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len;
- sdata->deflink.u.mgd.p2p_noa_index = -1;
- sdata->deflink.u.mgd.conn_flags = 0;
-
- if (sdata->local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS)
- sdata->deflink.u.mgd.req_smps = IEEE80211_SMPS_AUTOMATIC;
- else
- sdata->deflink.u.mgd.req_smps = IEEE80211_SMPS_OFF;
-
/* Setup TDLS data */
spin_lock_init(&ifmgd->teardown_lock);
ifmgd->teardown_skb = NULL;
ifmgd->orig_teardown_skb = NULL;
}
+void ieee80211_mgd_setup_link(struct ieee80211_link_data *link)
+{
+ struct ieee80211_local *local = link->sdata->local;
+
+ link->u.mgd.p2p_noa_index = -1;
+ link->u.mgd.conn_flags = 0;
+ link->conf->bssid = link->u.mgd.bssid;
+
+ INIT_WORK(&link->u.mgd.request_smps_work,
+ ieee80211_request_smps_mgd_work);
+ if (local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS)
+ link->u.mgd.req_smps = IEEE80211_SMPS_AUTOMATIC;
+ else
+ link->u.mgd.req_smps = IEEE80211_SMPS_OFF;
+}
+
/* scan finished notification */
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
{
@@ -6383,6 +6388,11 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
return 0;
}
+void ieee80211_mgd_stop_link(struct ieee80211_link_data *link)
+{
+ cancel_work_sync(&link->u.mgd.request_smps_work);
+}
+
void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -6394,7 +6404,6 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
*/
cancel_work_sync(&ifmgd->monitor_work);
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
- cancel_work_sync(&sdata->deflink.u.mgd.request_smps_work);
cancel_work_sync(&ifmgd->csa_connection_drop_work);
cancel_work_sync(&ifmgd->chswitch_work);
cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work);
]
|
| 66/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 72675
output: 51
thoughts: 1340
Thoughts: **Analyzing the IEEE 802.11 Link Release Channel Issue**
Okay, let's break this down. My initial thought is about the sequence. `ieee80211_link_stop` was introduced, and `ieee80211_link_release_channel` was moved into it. That's fine. Then, I see `ieee80211_link_release_channel` is indeed called from `ieee80211_link_stop`. And `ieee80211_link_stop` itself is called from `ieee80211_teardown_sdata`, which is called from `ieee80211_uninit`, which is, in turn, called from `unregister_netdevice_many`, eventually stemming from `ieee80211_unregister_hw`. Standard unregistering flow.
However, `ieee80211_do_stop` clears `IEEE80211_SDATA_IN_DRIVER`, and `ieee80211_do_stop` is called within the unregistering flow from `dev_close`. Now here's the crucial point: `ieee80211_do_stop` is *before* `ieee80211_link_release_channel`. So, `IEEE80211_SDATA_IN_DRIVER` should *always* be cleared before `ieee80211_link_release_channel` is called. So, why are we seeing warnings?
The warning stems from the condition within `ieee80211_link_release_channel`: it only calls `drv_unassign_vif_chanctx` if `conf` isn't NULL. `conf` references `link->conf->chanctx_conf`. Let's clarify how the `chanctx_conf` is set and cleared.
`chanctx_conf` is set by `ieee80211_assign_link_chanctx` when `new_ctx != NULL` and cleared when `new_ctx == NULL`. Importantly, `__ieee80211_link_release_channel` calls `ieee80211_assign_link_chanctx(link, NULL, false)`. This function is effectively the same as `ieee80211_link_release_channel`.
So, if `ieee80211_link_release_channel` *hasn't* been called before `ieee80211_teardown_sdata`, `chanctx_conf` will still be set, causing the warning. The question is, when does `ieee80211_link_release_channel` not get called beforehand? For an AP, `ieee80211_stop_ap` calls `ieee80211_link_release_channel`, but `ieee80211_stop_ap` is only called if the userspace *explicitly* stops the AP via `NL80211_CMD_STOP_AP`.
If userspace just deletes the interface, or, crucially, if the hardware is unplugged, `ieee80211_stop_ap` *isn't* called. Let me re-iterate: `cfg80211_shutdown_all_interfaces` *doesn't* call `ieee80211_stop_ap`. It calls `dev_close`. `dev_close` calls `ieee80211_stop`, then `ieee80211_do_stop`. `ieee80211_do_stop` *doesn't* call `ieee80211_stop_ap`.
So, in the AP scenario, when the hardware is unplugged *while* the AP is running, `ieee80211_link_release_channel` isn't called until `ieee80211_teardown_sdata`. *That's* when the warning occurs!
Now, does this align with the syzbot report? Yes! The stack trace in the report involves `mac80211_hwsim_del_radio`, followed by `hwsim_exit_net`. `hwsim_exit_net` deleting the radio is equivalent to unplugging the hardware. If an AP or another mode was active, the warning will be triggered.
The final question: Can an unprivileged user trigger this? `hwsim_exit_net` is called when a network namespace is destroyed
|
| 67/2 |
2026/08/10 01:41 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/wireless/virtual/mac80211_hwsim_main.c Name:hwsim_exit_net]
Results: map[SourceCode:7184: static void __net_exit hwsim_exit_net(struct net *net)
7185: {
7186: struct mac80211_hwsim_data *data, *tmp;
7187: LIST_HEAD(list);
7188:
7189: spin_lock_bh(&hwsim_radio_lock);
7190: list_for_each_entry_safe(data, tmp, &hwsim_radios, list) {
7191: if (!net_eq(wiphy_net(data->hw->wiphy), net))
7192: continue;
7193:
7194: /* Radios created in init_net are returned to init_net. */
7195: if (data->netgroup == hwsim_net_get_netgroup(&init_net))
7196: continue;
7197:
7198: list_move(&data->list, &list);
7199: rhashtable_remove_fast(&hwsim_radios_rht, &data->rht,
7200: hwsim_rht_params);
7201: hwsim_radios_generation++;
7202: }
7203: spin_unlock_bh(&hwsim_radio_lock);
7204:
7205: list_for_each_entry_safe(data, tmp, &list, list) {
7206: list_del(&data->list);
7207: mac80211_hwsim_del_radio(data,
7208: wiphy_name(data->hw->wiphy),
7209: NULL);
7210: }
7211:
7212: ida_free(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net));
7213: }
SourceFile:drivers/net/wireless/virtual/mac80211_hwsim_main.c]
|
| 68/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 75635
output: 53
thoughts: 107
Thoughts: **Delving into HWSIM Radio Lifecycle**
Okay, so `hwsim_exit_net` is the function that cleans up radios when a network namespace gets nuked. The interesting bit is that it skips radios if they were created within `init_net`. That immediately sparks a question in my mind: how *can* a radio even exist outside of `init_net`'s context to begin with? I mean, I know how the kernel operates, but I need to be sure.
Aha! It's most likely through netlink, specifically using the `HWSIM_CMD_NEW_RADIO` command. That makes sense; netlink is the standard way to interact with the kernel.
Now, the next logical question arises: Does the user need the required `CAP_NET_ADMIN` capability in the `init_net` namespace to successfully execute that netlink command to create a radio? I need to clarify the permission model. Let me examine `hwsim_new_radio_nl` more closely. I need to understand the function responsible for handling the creation of these radios and the permission requirements it enforces. Let's see what's what.
|
| 69/2 |
2026/08/10 01:41 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/wireless/virtual/mac80211_hwsim_main.c Name:hwsim_new_radio_nl]
Results: map[SourceCode:6752: static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
6753: {
6754: struct hwsim_new_radio_params param = { 0 };
6755: const char *hwname = NULL;
6756: int ret;
6757:
6758: param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
6759: param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
6760: param.nan_device = info->attrs[HWSIM_ATTR_SUPPORT_NAN_DEVICE];
6761: param.channels = channels;
6762: param.destroy_on_close =
6763: info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE];
6764:
6765: if (info->attrs[HWSIM_ATTR_CHANNELS])
6766: param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
6767:
6768: if (param.channels < 1) {
6769: GENL_SET_ERR_MSG(info, "must have at least one channel");
6770: return -EINVAL;
6771: }
6772:
6773: if (info->attrs[HWSIM_ATTR_NO_VIF])
6774: param.no_vif = true;
6775:
6776: if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
6777: param.use_chanctx = true;
6778: else
6779: param.use_chanctx = (param.channels > 1);
6780:
6781: if (info->attrs[HWSIM_ATTR_MULTI_RADIO])
6782: param.multi_radio = true;
6783:
6784: if (info->attrs[HWSIM_ATTR_SUPPORT_BACKGROUND_RADAR])
6785: param.background_radar = true;
6786:
6787: if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
6788: param.reg_alpha2 =
6789: nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
6790:
6791: if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) {
6792: u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]);
6793:
6794: if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom))
6795: return -EINVAL;
6796:
6797: idx = array_index_nospec(idx,
6798: ARRAY_SIZE(hwsim_world_regdom_custom));
6799: param.regd = hwsim_world_regdom_custom[idx];
6800: }
6801:
6802: if (info->attrs[HWSIM_ATTR_PERM_ADDR]) {
6803: if (!is_valid_ether_addr(
6804: nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]))) {
6805: GENL_SET_ERR_MSG(info,"MAC is no valid source addr");
6806: NL_SET_BAD_ATTR(info->extack,
6807: info->attrs[HWSIM_ATTR_PERM_ADDR]);
6808: return -EINVAL;
6809: }
6810:
6811: param.perm_addr = nla_data(info->attrs[HWSIM_ATTR_PERM_ADDR]);
6812: }
6813:
6814: if (info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]) {
6815: param.iftypes =
6816: nla_get_u32(info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT]);
6817:
6818: if (param.iftypes & ~HWSIM_IFTYPE_SUPPORT_MASK) {
6819: NL_SET_ERR_MSG_ATTR(info->extack,
6820: info->attrs[HWSIM_ATTR_IFTYPE_SUPPORT],
6821: "cannot support more iftypes than kernel");
6822: return -EINVAL;
6823: }
6824: } else {
6825: param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK;
6826: }
6827:
6828: /* ensure both flag and iftype support is honored */
6829: if (param.p2p_device ||
6830: param.iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) {
6831: param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
6832: param.p2p_device = true;
6833: }
6834:
6835: if (param.nan_device) {
6836: if (param.multi_radio) {
6837: NL_SET_ERR_MSG(info->extack,
6838: "NAN is not supported on multi-radio wiphys");
6839: return -EINVAL;
6840: }
6841: param.iftypes |= BIT(NL80211_IFTYPE_NAN) |
6842: BIT(NL80211_IFTYPE_NAN_DATA);
6843: }
6844:
6845: if (info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]) {
6846: u32 len = nla_len(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]);
6847:
6848: param.ciphers =
6849: nla_data(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]);
6850:
6851: if (len % sizeof(u32)) {
6852: NL_SET_ERR_MSG_ATTR(info->extack,
6853: info->attrs[HWSIM_ATTR_CIPHER_SUPPORT],
6854: "bad cipher list length");
6855: return -EINVAL;
6856: }
6857:
6858: param.n_ciphers = len / sizeof(u32);
6859:
6860: if (param.n_ciphers > ARRAY_SIZE(hwsim_ciphers)) {
6861: NL_SET_ERR_MSG_ATTR(info->extack,
6862: info->attrs[HWSIM_ATTR_CIPHER_SUPPORT],
6863: "too many ciphers specified");
6864: return -EINVAL;
6865: }
6866:
6867: if (!hwsim_known_ciphers(param.ciphers, param.n_ciphers)) {
6868: NL_SET_ERR_MSG_ATTR(info->extack,
6869: info->attrs[HWSIM_ATTR_CIPHER_SUPPORT],
6870: "unsupported ciphers specified");
6871: return -EINVAL;
6872: }
6873: }
6874:
6875: param.mlo = info->attrs[HWSIM_ATTR_MLO_SUPPORT];
6876:
6877: if (param.mlo || param.multi_radio)
6878: param.use_chanctx = true;
6879:
6880: if (info->attrs[HWSIM_ATTR_RADIO_NAME]) {
6881: hwname = kstrndup((char *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]),
6882: nla_len(info->attrs[HWSIM_ATTR_RADIO_NAME]),
6883: GFP_KERNEL);
6884: if (!hwname)
6885: return -ENOMEM;
6886: param.hwname = hwname;
6887: }
6888:
6889: if (info->attrs[HWSIM_ATTR_PMSR_SUPPORT]) {
6890: struct cfg80211_pmsr_capabilities *pmsr_capa;
6891:
6892: pmsr_capa = kzalloc_obj(*pmsr_capa);
6893: if (!pmsr_capa) {
6894: ret = -ENOMEM;
6895: goto out_free;
6896: }
6897: param.pmsr_capa = pmsr_capa;
6898:
6899: ret = parse_pmsr_capa(info->attrs[HWSIM_ATTR_PMSR_SUPPORT], pmsr_capa, info);
6900: if (ret)
6901: goto out_free;
6902: }
6903:
6904: ret = mac80211_hwsim_new_radio(info, ¶m);
6905:
6906: out_free:
6907: kfree(hwname);
6908: kfree(param.pmsr_capa);
6909: return ret;
6910: }
SourceFile:drivers/net/wireless/virtual/mac80211_hwsim_main.c]
|
| 70/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 78749
output: 52
thoughts: 33
Thoughts: Here's my summary, as though I'm thinking through this process:
**Diving into `hwsim_new_radio_nl`**
Okay, so `hwsim_new_radio_nl`. That's a Genl callback, isn't it? Right, it's pretty clear from the name. Time to trace this through the system. I need to see exactly what this thing is *doing*. The obvious place to start is the definition within `hwsim_genl_ops`. Let's dig into that structure and see what we can find. I want to see the details of this callback. What actions does it trigger? What arguments does it expect? Let's get to the bottom of this.
|
| 71/2 |
2026/08/10 01:41 |
tool |
codesearch-definition-source |
0m
Error:
Args: map[ContextFile:drivers/net/wireless/virtual/mac80211_hwsim_main.c Name:hwsim_genl_ops]
Results: map[SourceCode: SourceFile:]
|
| 72/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 79010
output: 49
thoughts: 15
Thoughts: Here's my thought process, summarized as you requested:
**Digging into the Radio Abstraction Layer**
Okay, so I need to find where this `hwsim_new_radio_nl` function is being used. This smells like it's connected to the hardware simulation layer, potentially within the Netlink interface. It's likely a critical function for setting up a simulated radio interface within the hardware simulation environment. I need to understand its role in creating or initializing a new simulated radio device that communicates through the Netlink protocol. My immediate goal is to figure out where this function is called, what it's passed, and what it does. `grep` seems like the perfect tool for quickly identifying all instances of its usage within the codebase. I expect it's going to be a key element in the radio simulation framework. From there, I'll be able to better understand the simulation's structure and behavior. Let's see what `grep` uncovers.
|
| 73/2 |
2026/08/10 01:41 |
tool |
grepper |
0m
Args: map[Expression:hwsim_new_radio_nl PathPrefix:drivers/net/wireless/virtual/mac80211_hwsim_main.c]
Results: map[Output:drivers/net/wireless/virtual/mac80211_hwsim_main.c=6713=static int parse_pmsr_capa(const struct nlattr *pmsr_capa, struct cfg80211_pmsr_capabilities *out,
--
drivers/net/wireless/virtual/mac80211_hwsim_main.c-6751-
drivers/net/wireless/virtual/mac80211_hwsim_main.c:6752:static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
drivers/net/wireless/virtual/mac80211_hwsim_main.c-6753-{
--
drivers/net/wireless/virtual/mac80211_hwsim_main.c=7052=static const struct genl_small_ops hwsim_ops[] = {
--
drivers/net/wireless/virtual/mac80211_hwsim_main.c-7071- .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
drivers/net/wireless/virtual/mac80211_hwsim_main.c:7072: .doit = hwsim_new_radio_nl,
drivers/net/wireless/virtual/mac80211_hwsim_main.c-7073- .flags = GENL_UNS_ADMIN_PERM,
]
|
| 74/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 79655
output: 28
thoughts: 866
Thoughts: **Bug Analysis: mac80211 WARN_ONCE**
Okay, so `.flags = GENL_UNS_ADMIN_PERM` on this thing... that immediately tells me this requires `CAP_NET_ADMIN` within the user namespace. Interesting. That means an unprivileged user can create a user namespace, snag that capability, and then use something like `hwsim` to create a virtual radio. They can spin up an AP interface on it, start it, and then blow away the network namespace (or delete the radio). Boom β warning triggered. So, yeah, definitely accessible from user namespaces.
Now, can an *unprivileged* user trigger this *without* user namespaces? Nope, `CAP_NET_ADMIN` is the gatekeeper. But wait... Could an unprivileged user trigger this on a real USB Wi-Fi dongle? If they *physically unplug* the dongle while an AP is running. But, ah, unprivileged users can't start an AP interface in the first place without `CAP_NET_ADMIN`, so it's a moot point. Wait a minute... if an *administrator* started the AP, and *then* an unprivileged user yanks the USB dongle, then it would trigger the warning. So this is vulnerable to a peripheral triggerβspecifically, unplugging a USB device. This can also be triggered from user namespaces through tools like `mac80211_hwsim`.
Let me just confirm that `GENL_UNS_ADMIN_PERM` means it's kosher in user namespaces. Yup, it checks `ns_capable(net->user_ns, CAP_NET_ADMIN)`, so a user namespace is sufficient.
Okay, let's summarize the root cause here. When an interface (specifically, an AP) is removed while it's up and has a channel context assigned, `ieee80211_do_stop` clears `IEEE80211_SDATA_IN_DRIVER`, but it *doesn't* release the channel context right away. Later, `ieee80211_teardown_sdata` calls `ieee80211_link_stop`, which calls `ieee80211_link_release_channel`. That then calls `drv_unassign_vif_chanctx`, and *that* checks `check_sdata_in_driver`. Since `IEEE80211_SDATA_IN_DRIVER` has already been cleared, it trips a `WARN_ONCE`.
The good news is that this warning is apparently harmless. It just prints a message and then returns. No memory corruption, no use-after-free, no resource leak (the channel context is properly unassigned from the mac80211 side, and the driver is already being removed so it doesn't care). It's not exploitable, and it doesn't cause a denial of service (unless `panic_on_warn` is set, of course, which would cause a panic).
Let me just double-check for any potential resource leak, just to be thorough. In `ieee80211_assign_link_chanctx`... I see this:
```c
if (conf && !local->in_reconfig) {
curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
conf = NULL;
}
```
It sets `conf = NULL` and then `rcu_assign_pointer(link->conf->chanctx_conf, conf)`. So that pointer is cleared. But what about `curr_ctx`? Is *that* freed? `curr_ctx` is a `struct ieee80211_chanctx`. These contexts are managed by `mac80211/chan.c`. Hmm, I should verify if `ieee80211_assign_link_chanctx` frees it. Nope, it just unassigns it from the link. Ah, the actual `chanctx` is freed when its reference count drops to zero? Right. Gotta see where those reference counts are managed.
|
| 75/2 |
2026/08/10 01:41 |
tool |
codesearch-find-references |
0m
Args: map[Name:ieee80211_chanctx]
Results: map[References:[map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__bpf_trace_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__bpf_trace_local_chanctx SourceFile:net/mac80211/trace.h SourceLine:1668] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__bpf_trace_local_sdata_chanctx SourceFile:net/mac80211/trace.h SourceLine:1823] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__do_trace_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__do_trace_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__do_trace_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__do_trace_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__do_trace_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__ieee80211_channel_switch SourceFile:net/mac80211/cfg.c SourceLine:4717] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__ieee80211_channel_switch SourceFile:net/mac80211/cfg.c SourceLine:4766] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__ieee80211_channel_switch SourceFile:net/mac80211/cfg.c SourceLine:4766] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__ieee80211_channel_switch SourceFile:net/mac80211/cfg.c SourceLine:4766] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__ieee80211_link_release_channel SourceFile:net/mac80211/chan.c SourceLine:2156] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__ieee80211_link_release_channel SourceFile:net/mac80211/chan.c SourceLine:2166] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__ieee80211_link_release_channel SourceFile:net/mac80211/chan.c SourceLine:2166] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__ieee80211_link_release_channel SourceFile:net/mac80211/chan.c SourceLine:2166] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__ieee80211_recalc_chanctx_min_def SourceFile:net/mac80211/chan.c SourceLine:635] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__probestub_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__probestub_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__probestub_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__probestub_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__probestub_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:__traceiter_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:_ieee80211_chanctx_compatible SourceFile:net/mac80211/chan.c SourceLine:336] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:_ieee80211_change_chanctx SourceFile:net/mac80211/chan.c SourceLine:810] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:_ieee80211_change_chanctx SourceFile:net/mac80211/chan.c SourceLine:811] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:_ieee80211_link_use_channel SourceFile:net/mac80211/chan.c SourceLine:2282] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:_ieee80211_recalc_chanctx_min_def SourceFile:net/mac80211/chan.c SourceLine:748] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:check_trace_callback_type_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:check_trace_callback_type_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:check_trace_callback_type_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:check_trace_callback_type_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:check_trace_callback_type_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:do_perf_trace_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:do_perf_trace_local_chanctx SourceFile:net/mac80211/trace.h SourceLine:1668] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:do_perf_trace_local_sdata_chanctx SourceFile:net/mac80211/trace.h SourceLine:1823] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:do_trace_event_raw_event_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:do_trace_event_raw_event_local_chanctx SourceFile:net/mac80211/trace.h SourceLine:1668] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:do_trace_event_raw_event_local_sdata_chanctx SourceFile:net/mac80211/trace.h SourceLine:1823] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_add_chanctx SourceFile:net/mac80211/driver-ops.h SourceLine:1015] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_assign_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:315] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_change_chanctx SourceFile:net/mac80211/driver-ops.h SourceLine:1049] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_remove_chanctx SourceFile:net/mac80211/driver-ops.h SourceLine:1033] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:397] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:398] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:398] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:398] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:401] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:402] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:402] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:402] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:420] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:421] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:421] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:421] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:424] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:425] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:425] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_switch_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:425] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:drv_unassign_vif_chanctx SourceFile:net/mac80211/driver-ops.c SourceLine:356] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:iee80211_tdls_recalc_chanctx SourceFile:net/mac80211/tdls.c SourceLine:1321] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:iee80211_tdls_recalc_chanctx SourceFile:net/mac80211/tdls.c SourceLine:1332] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:iee80211_tdls_recalc_chanctx SourceFile:net/mac80211/tdls.c SourceLine:1332] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:iee80211_tdls_recalc_chanctx SourceFile:net/mac80211/tdls.c SourceLine:1332] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_add_chanctx SourceFile:net/mac80211/chan.c SourceLine:1024] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_alloc_chanctx SourceFile:net/mac80211/chan.c SourceLine:1002] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_assign_chanctx SourceFile:net/mac80211/util.c SourceLine:1717] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_assign_chanctx SourceFile:net/mac80211/util.c SourceLine:1724] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_assign_chanctx SourceFile:net/mac80211/util.c SourceLine:1724] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_assign_chanctx SourceFile:net/mac80211/util.c SourceLine:1724] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_assign_link_chanctx SourceFile:net/mac80211/chan.c SourceLine:1180] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_assign_link_chanctx SourceFile:net/mac80211/chan.c SourceLine:1186] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_assign_link_chanctx SourceFile:net/mac80211/chan.c SourceLine:1197] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_assign_link_chanctx SourceFile:net/mac80211/chan.c SourceLine:1197] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_assign_link_chanctx SourceFile:net/mac80211/chan.c SourceLine:1197] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chan_bw_change SourceFile:net/mac80211/chan.c SourceLine:674] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_can_reserve SourceFile:net/mac80211/chan.c SourceLine:415] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_compatible SourceFile:net/mac80211/chan.c SourceLine:360] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_non_reserved_chandef SourceFile:net/mac80211/chan.c SourceLine:391] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_num_assigned SourceFile:net/mac80211/chan.c SourceLine:192] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_num_reserved SourceFile:net/mac80211/chan.c SourceLine:204] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_radar_detect SourceFile:net/mac80211/util.c SourceLine:4164] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_radar_required SourceFile:net/mac80211/chan.c SourceLine:982] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_refcount SourceFile:net/mac80211/chan.c SourceLine:216] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_reserved_chanreq SourceFile:net/mac80211/chan.c SourceLine:369] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_update_npca_links SourceFile:net/mac80211/chan.c SourceLine:779] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_user_iter_next SourceFile:net/mac80211/chan.c SourceLine:113] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_user_iter_next_link SourceFile:net/mac80211/chan.c SourceLine:64] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chanctx_user_iter_next_nan_channel SourceFile:net/mac80211/chan.c SourceLine:37] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_change_chanctx SourceFile:net/mac80211/chan.c SourceLine:897] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_change_chanctx SourceFile:net/mac80211/chan.c SourceLine:898] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chsw_switch_ctxs SourceFile:net/mac80211/chan.c SourceLine:1847] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chsw_switch_vifs SourceFile:net/mac80211/chan.c SourceLine:1802] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_chsw_switch_vifs SourceFile:net/mac80211/chan.c SourceLine:1802] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_del_chanctx SourceFile:net/mac80211/chan.c SourceLine:1079] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_dfs_cac_cancel SourceFile:net/mac80211/util.c SourceLine:3664] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_dfs_radar_detected_work SourceFile:net/mac80211/util.c SourceLine:3708] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_dfs_radar_detected_work SourceFile:net/mac80211/util.c SourceLine:3708] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_fill_ifcomb_params SourceFile:net/mac80211/util.c SourceLine:4260] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_fill_ifcomb_params SourceFile:net/mac80211/util.c SourceLine:4265] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_finalize_rx_omi_bw SourceFile:net/mac80211/he.c SourceLine:330] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_find_chanctx SourceFile:net/mac80211/chan.c SourceLine:911] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_find_or_create_chanctx SourceFile:net/mac80211/chan.c SourceLine:2195] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_find_reservation_chanctx SourceFile:net/mac80211/chan.c SourceLine:440] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_free_chanctx SourceFile:net/mac80211/chan.c SourceLine:1093] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_get_chanctx_max_required_bw SourceFile:net/mac80211/chan.c SourceLine:583] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_handle_reconfig_failure SourceFile:net/mac80211/util.c SourceLine:1676] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_hw_conf_chan SourceFile:net/mac80211/main.c SourceLine:244] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_hw_conf_chan SourceFile:net/mac80211/main.c SourceLine:246] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_hw_conf_chan SourceFile:net/mac80211/main.c SourceLine:246] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_hw_conf_chan SourceFile:net/mac80211/main.c SourceLine:246] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_hw_conf_init SourceFile:net/mac80211/main.c SourceLine:263] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_hw_conf_init SourceFile:net/mac80211/main.c SourceLine:265] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_hw_conf_init SourceFile:net/mac80211/main.c SourceLine:265] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_hw_conf_init SourceFile:net/mac80211/main.c SourceLine:265] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_iter_chan_contexts_atomic SourceFile:net/mac80211/chan.c SourceLine:2527] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_iter_chan_contexts_mtx SourceFile:net/mac80211/chan.c SourceLine:2545] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_change_chanreq SourceFile:net/mac80211/chan.c SourceLine:2424] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_change_chanreq SourceFile:net/mac80211/chan.c SourceLine:2450] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_change_chanreq SourceFile:net/mac80211/chan.c SourceLine:2450] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_change_chanreq SourceFile:net/mac80211/chan.c SourceLine:2450] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_get_chanctx SourceFile:net/mac80211/chan.c SourceLine:270] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_get_chanctx SourceFile:net/mac80211/chan.c SourceLine:270] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_get_chanctx SourceFile:net/mac80211/chan.c SourceLine:270] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_has_in_place_reservation SourceFile:net/mac80211/chan.c SourceLine:1776] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_has_in_place_reservation SourceFile:net/mac80211/chan.c SourceLine:1776] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_reserve_chanctx SourceFile:net/mac80211/chan.c SourceLine:1546] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_reserve_chanctx SourceFile:net/mac80211/chan.c SourceLine:1546] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_unreserve_chanctx SourceFile:net/mac80211/chan.c SourceLine:1405] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_use_reserved_assign SourceFile:net/mac80211/chan.c SourceLine:1728] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_use_reserved_assign SourceFile:net/mac80211/chan.c SourceLine:1728] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_use_reserved_context SourceFile:net/mac80211/chan.c SourceLine:2359] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_use_reserved_context SourceFile:net/mac80211/chan.c SourceLine:2360] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_use_reserved_reassign SourceFile:net/mac80211/chan.c SourceLine:1647] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_use_reserved_reassign SourceFile:net/mac80211/chan.c SourceLine:1647] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_monitor_start_xmit SourceFile:net/mac80211/tx.c SourceLine:2413] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_evac_chanctx_filter SourceFile:net/mac80211/chan.c SourceLine:2218] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_evacuate_channel SourceFile:net/mac80211/nan.c SourceLine:723] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_evacuate_channel SourceFile:net/mac80211/nan.c SourceLine:748] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_evacuate_channel SourceFile:net/mac80211/nan.c SourceLine:748] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_evacuate_channel SourceFile:net/mac80211/nan.c SourceLine:748] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_find_evac_chan SourceFile:net/mac80211/nan.c SourceLine:763] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_find_evac_chan SourceFile:net/mac80211/nan.c SourceLine:781] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_find_evac_chan SourceFile:net/mac80211/nan.c SourceLine:789] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_find_evac_chan SourceFile:net/mac80211/nan.c SourceLine:789] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_find_evac_chan SourceFile:net/mac80211/nan.c SourceLine:789] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_remove_channel SourceFile:net/mac80211/nan.c SourceLine:181] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_remove_channel SourceFile:net/mac80211/nan.c SourceLine:211] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_remove_channel SourceFile:net/mac80211/nan.c SourceLine:211] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_remove_channel SourceFile:net/mac80211/nan.c SourceLine:211] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_sched_update_done SourceFile:net/mac80211/nan.c SourceLine:477] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_sched_update_done SourceFile:net/mac80211/nan.c SourceLine:477] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_sched_update_done SourceFile:net/mac80211/nan.c SourceLine:477] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_set_local_sched SourceFile:net/mac80211/nan.c SourceLine:421] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_set_local_sched SourceFile:net/mac80211/nan.c SourceLine:421] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_set_local_sched SourceFile:net/mac80211/nan.c SourceLine:421] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_try_evacuate SourceFile:net/mac80211/nan.c SourceLine:832] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_try_evacuate SourceFile:net/mac80211/nan.c SourceLine:840] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_try_evacuate SourceFile:net/mac80211/nan.c SourceLine:840] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_try_evacuate SourceFile:net/mac80211/nan.c SourceLine:840] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_update_channel SourceFile:net/mac80211/nan.c SourceLine:57] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_update_channel SourceFile:net/mac80211/nan.c SourceLine:57] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_update_channel SourceFile:net/mac80211/nan.c SourceLine:57] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_use_chanctx SourceFile:net/mac80211/nan.c SourceLine:67] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_new_chanctx SourceFile:net/mac80211/chan.c SourceLine:1054] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_num_chanctx SourceFile:net/mac80211/chan.c SourceLine:236] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_prepare_rx_omi_bw SourceFile:net/mac80211/he.c SourceLine:277] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_radar_mark_chan_ctx_iterator SourceFile:net/mac80211/util.c SourceLine:3733] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_radar_mark_chan_ctx_iterator SourceFile:net/mac80211/util.c SourceLine:3734] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_radar_mark_chan_ctx_iterator SourceFile:net/mac80211/util.c SourceLine:3734] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_radar_mark_chan_ctx_iterator SourceFile:net/mac80211/util.c SourceLine:3734] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_chanctx_chantype SourceFile:net/mac80211/chan.c SourceLine:1106] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_chanctx_min_def SourceFile:net/mac80211/chan.c SourceLine:772] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_min_chandef SourceFile:net/mac80211/util.c SourceLine:2465] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_min_chandef SourceFile:net/mac80211/util.c SourceLine:2498] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_min_chandef SourceFile:net/mac80211/util.c SourceLine:2498] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_min_chandef SourceFile:net/mac80211/util.c SourceLine:2498] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_radar_chanctx SourceFile:net/mac80211/chan.c SourceLine:1163] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_smps SourceFile:net/mac80211/util.c SourceLine:2440] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_smps SourceFile:net/mac80211/util.c SourceLine:2456] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_smps SourceFile:net/mac80211/util.c SourceLine:2456] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_smps SourceFile:net/mac80211/util.c SourceLine:2456] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_recalc_smps_chanctx SourceFile:net/mac80211/chan.c SourceLine:1262] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_reconfig SourceFile:net/mac80211/util.c SourceLine:1889] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_replace_chanctx SourceFile:net/mac80211/chan.c SourceLine:1439] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_replace_chanctx SourceFile:net/mac80211/chan.c SourceLine:1441] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_replace_chanctx SourceFile:net/mac80211/chan.c SourceLine:1441] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_rx_uhr_link_reconfig_req SourceFile:net/mac80211/ap.c SourceLine:224] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_rx_uhr_link_reconfig_req SourceFile:net/mac80211/ap.c SourceLine:252] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_rx_uhr_link_reconfig_req SourceFile:net/mac80211/ap.c SourceLine:252] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_rx_uhr_link_reconfig_req SourceFile:net/mac80211/ap.c SourceLine:252] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_sta_process_chanswitch SourceFile:net/mac80211/mlme.c SourceLine:3237] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_sta_process_chanswitch SourceFile:net/mac80211/mlme.c SourceLine:3432] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_sta_process_chanswitch SourceFile:net/mac80211/mlme.c SourceLine:3432] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_sta_process_chanswitch SourceFile:net/mac80211/mlme.c SourceLine:3432] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_try_nan_chan_evacuation SourceFile:net/mac80211/chan.c SourceLine:2240] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_try_nan_chan_evacuation SourceFile:net/mac80211/chan.c SourceLine:2251] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_try_nan_chan_evacuation SourceFile:net/mac80211/chan.c SourceLine:2251] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_try_nan_chan_evacuation SourceFile:net/mac80211/chan.c SourceLine:2251] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_uhr_disable_dbe_all_stas SourceFile:net/mac80211/ap.c SourceLine:329] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_uhr_disable_dbe_all_stas SourceFile:net/mac80211/ap.c SourceLine:336] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_uhr_disable_dbe_all_stas SourceFile:net/mac80211/ap.c SourceLine:336] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_uhr_disable_dbe_all_stas SourceFile:net/mac80211/ap.c SourceLine:336] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_update_ap_bandwidth SourceFile:net/mac80211/cfg.c SourceLine:1430] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_update_ap_bandwidth SourceFile:net/mac80211/cfg.c SourceLine:1453] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_update_ap_bandwidth SourceFile:net/mac80211/cfg.c SourceLine:1453] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_update_ap_bandwidth SourceFile:net/mac80211/cfg.c SourceLine:1453] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_vif_use_reserved_switch SourceFile:net/mac80211/chan.c SourceLine:1885] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_vif_use_reserved_switch SourceFile:net/mac80211/chan.c SourceLine:1885] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:ieee80211_vif_use_reserved_switch SourceFile:net/mac80211/chan.c SourceLine:1885] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:perf_trace_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:perf_trace_local_chanctx SourceFile:net/mac80211/trace.h SourceLine:1668] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:perf_trace_local_sdata_chanctx SourceFile:net/mac80211/trace.h SourceLine:1823] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_prio_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_prio_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_prio_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_prio_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:register_trace_prio_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_call__drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_call__drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_call__drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_call__drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_call__drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_event_get_offsets_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_event_get_offsets_local_chanctx SourceFile:net/mac80211/trace.h SourceLine:1668] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_event_get_offsets_local_sdata_chanctx SourceFile:net/mac80211/trace.h SourceLine:1823] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_event_raw_event_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_event_raw_event_local_chanctx SourceFile:net/mac80211/trace.h SourceLine:1668] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:trace_event_raw_event_local_sdata_chanctx SourceFile:net/mac80211/trace.h SourceLine:1823] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:unregister_trace_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:unregister_trace_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:unregister_trace_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:unregister_trace_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:function ReferencingEntityName:unregister_trace_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859] map[ReferenceKind:uses ReferencingEntityKind:struct ReferencingEntityName:ieee80211_check_combinations_data SourceFile:net/mac80211/ieee80211_i.h SourceLine:2873] map[ReferenceKind:uses ReferencingEntityKind:typedef ReferencingEntityName:btf_trace_drv_add_chanctx SourceFile:net/mac80211/trace.h SourceLine:1690] map[ReferenceKind:uses ReferencingEntityKind:typedef ReferencingEntityName:btf_trace_drv_assign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1851] map[ReferenceKind:uses ReferencingEntityKind:typedef ReferencingEntityName:btf_trace_drv_change_chanctx SourceFile:net/mac80211/trace.h SourceLine:1702] map[ReferenceKind:uses ReferencingEntityKind:typedef ReferencingEntityName:btf_trace_drv_remove_chanctx SourceFile:net/mac80211/trace.h SourceLine:1696] map[ReferenceKind:uses ReferencingEntityKind:typedef ReferencingEntityName:btf_trace_drv_unassign_vif_chanctx SourceFile:net/mac80211/trace.h SourceLine:1859]] TruncatedOutput:false]
|
| 76/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 97890
output: 48
thoughts: 36
Thoughts: Here's my take on the thought process, from an expert's perspective:
**Diving into Channel Context Management**
Okay, so we're looking at freeing a channel context. The code snippet mentions `ieee80211_free_chanctx`, which is exactly what I'd expect. Let's dig into that function directly. It's the lynchpin for ensuring clean and efficient resource management. I want to see how it handles all the associated data structures, making sure we don't leak anything, especially with the complexities we've had with dynamic frequency and channel allocation. I'm hoping it's robust; I've had to debug enough memory management issues in the past! Let's see how it works under the hood.
|
| 77/2 |
2026/08/10 01:41 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/chan.c Name:ieee80211_free_chanctx]
Results: map[SourceCode:1092: void ieee80211_free_chanctx(struct ieee80211_local *local,
1093: struct ieee80211_chanctx *ctx,
1094: bool skip_idle_recalc)
1095: {
1096: lockdep_assert_wiphy(local->hw.wiphy);
1097:
1098: WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
1099:
1100: list_del_rcu(&ctx->list);
1101: ieee80211_del_chanctx(local, ctx, skip_idle_recalc);
1102: kfree_rcu(ctx, rcu_head);
1103: }
SourceFile:net/mac80211/chan.c]
|
| 78/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 98401
output: 30
thoughts: 60
Thoughts: Okay, let's see, I'm thinking about the channel context management in this 802.11 code. So, the question is, **Channel Context Liberation and Reference Counting**. Right, so `ieee80211_free_chanctx` is the function that actually releases the resources associated with a channel context. The critical trigger for that release is when the reference count, `ieee80211_chanctx_refcount`, hits zero, indicating that nobody is using it anymore. Now, I need to trace the call paths to `ieee80211_free_chanctx`. Where *exactly* are the points in the code that decrement that reference count and where are all the points this function is invoked? I need to analyze the calls to that function to understand how the memory is managed.
|
| 79/2 |
2026/08/10 01:41 |
tool |
codesearch-find-references |
0m
Args: map[Name:ieee80211_free_chanctx]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:__ieee80211_link_release_channel SourceFile:net/mac80211/chan.c SourceLine:2178] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:_ieee80211_link_use_channel SourceFile:net/mac80211/chan.c SourceLine:2342] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_unreserve_chanctx SourceFile:net/mac80211/chan.c SourceLine:1430] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_use_reserved_assign SourceFile:net/mac80211/chan.c SourceLine:1762] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_use_reserved_reassign SourceFile:net/mac80211/chan.c SourceLine:1695] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_link_use_reserved_reassign SourceFile:net/mac80211/chan.c SourceLine:1709] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_evacuate_channel SourceFile:net/mac80211/nan.c SourceLine:757] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:ieee80211_nan_remove_channel SourceFile:net/mac80211/nan.c SourceLine:220]] TruncatedOutput:false]
|
| 80/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 99205
output: 50
thoughts: 52
Thoughts: Okay, here's my take on those thoughts, framed as my own:
**Digging into Channel Release in 802.11**
Alright, so `__ieee80211_link_release_channel` is the function we're concerned with here. It looks like its main purpose is to clean up a channel context, since the code mentions `ieee80211_free_chanctx`. Let's dive into the internals of `__ieee80211_link_release_channel`. It's pretty likely we are going to see a deallocation. I'm hoping it's handling reference counts correctly and doesn't have any obvious memory management issues. Time to trace the execution and see if there are any subtle race conditions or potential leaks. I'll focus on the data structures it manipulates.
|
| 81/2 |
2026/08/10 01:41 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/chan.c Name:__ieee80211_link_release_channel]
Results: map[SourceCode:2149: void __ieee80211_link_release_channel(struct ieee80211_link_data *link,
2150: bool skip_idle_recalc)
2151: {
2152: struct ieee80211_sub_if_data *sdata = link->sdata;
2153: struct ieee80211_bss_conf *link_conf = link->conf;
2154: struct ieee80211_local *local = sdata->local;
2155: struct ieee80211_chanctx_conf *conf;
2156: struct ieee80211_chanctx *ctx;
2157: bool use_reserved_switch = false;
2158:
2159: lockdep_assert_wiphy(local->hw.wiphy);
2160:
2161: conf = rcu_dereference_protected(link_conf->chanctx_conf,
2162: lockdep_is_held(&local->hw.wiphy->mtx));
2163: if (!conf)
2164: return;
2165:
2166: ctx = container_of(conf, struct ieee80211_chanctx, conf);
2167:
2168: if (link->reserved_chanctx) {
2169: if (link->reserved_chanctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
2170: ieee80211_chanctx_num_reserved(local, link->reserved_chanctx) > 1)
2171: use_reserved_switch = true;
2172:
2173: ieee80211_link_unreserve_chanctx(link);
2174: }
2175:
2176: ieee80211_assign_link_chanctx(link, NULL, false);
2177: if (ieee80211_chanctx_refcount(local, ctx) == 0)
2178: ieee80211_free_chanctx(local, ctx, skip_idle_recalc);
2179:
2180: link->radar_required = false;
2181:
2182: /* Unreserving may ready an in-place reservation. */
2183: if (use_reserved_switch)
2184: ieee80211_vif_use_reserved_switch(local);
2185: }
SourceFile:net/mac80211/chan.c]
|
| 82/2 |
2026/08/10 01:41 |
llm |
expert |
0m
Model:
Tokens:
input: 100219
output: 49
thoughts: 1308
Thoughts: **Analysis of the IEEE 802.11 Channel Context Release**
Okay, so `ieee80211_link_release_channel` *does* call `ieee80211_assign_link_chanctx(link, NULL, false)`. That part is fine; it unassigns the context. And the refcount check and subsequent freeing of the context confirms there's no resource leak. Good. So, the only thing that's concerning is that `WARN_ONCE`. Let me pull up that macro:
```c
#define check_sdata_in_driver(sdata) ({ \
WARN_ONCE(!sdata->local->reconfig_failure && \
!(sdata->flags & IEEE80211_SDATA_IN_DRIVER), \
"%s: Failed check-sdata-in-driver check, flags: 0x%x\n", \
sdata->dev ? sdata->dev->name : sdata->name, sdata->flags); \
!!(sdata->flags & IEEE80211_SDATA_IN_DRIVER); \
})
```
It returns `false`. Then `drv_unassign_vif_chanctx` returns early:
```c
if (!check_sdata_in_driver(sdata))
return;
```
This means `local->ops->unassign_vif_chanctx` isn't called. Is that a problem? No, wait! `drv_remove_interface` has already been called! The driver has already removed the interface entirely. Asking it to unassign the channel context from an interface that's already gone... that could lead to driver crashes! So returning early is actually *correct* in this case. The warning is just a sanity check that's failing because the teardown order is a bit... unusual: interface removal before channel context unassignment. But the order is probably intentional, or at least harmless. The warning is just noise.
So, let's break down the security impact:
* **Exploitable:** No.
* **Denial of Service:** No, unless you have `panic_on_warn` set.
* **Privilege escalation:** No.
* **User namespace:** Yes, through mac80211_hwsim, but that's a special case.
* **VM Trigger:** No.
* **Ethernet Network:** No.
* **Remote:** No.
* **Peripheral:** Yes! Unplugging a USB Wi-Fi dongle when an AP is running.
* **Malicious Filesystem:** No.
But can an unprivileged user actually trigger this via that peripheral trigger? Yes, but they need an AP running on it. Can an unprivileged user start an AP? No, they'd need `CAP_NET_ADMIN`. However, if the admin started the AP, and a regular user unplugs the dongle, it triggers the warning. So it *is* a peripheral trigger.
Okay, let me double-check how `ieee80211_do_stop` clears `IEEE80211_SDATA_IN_DRIVER` across all interface types. Right, `drv_remove_interface` is called in the `default` case:
```c
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
break;
case NL80211_IFTYPE_MONITOR:
if (local->virt_monitors == 0)
ieee80211_del_virtual_monitor(local);
ieee80211_recalc_idle(local);
ieee80211_recalc_offload(local);
if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
break;
ieee80211_link_release_channel(&sdata->deflink);
fallthrough;
default:
if (!going_down)
break;
drv_remove_interface(local, sdata);
/* Clear private driver data to prevent reuse */
memset(sdata->vif.drv_priv, 0, local->hw.vif_data_size);
}
```
For `NL8021
|
| 83/2 |
2026/08/10 01:42 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/mlme.c Name:ieee80211_mgd_stop]
Results: map[SourceCode:10771: void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
10772: {
10773: struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
10774:
10775: /*
10776: * Make sure some work items will not run after this,
10777: * they will not do anything but might not have been
10778: * cancelled when disconnecting.
10779: */
10780: wiphy_work_cancel(sdata->local->hw.wiphy,
10781: &ifmgd->monitor_work);
10782: wiphy_work_cancel(sdata->local->hw.wiphy,
10783: &ifmgd->beacon_connection_loss_work);
10784: wiphy_work_cancel(sdata->local->hw.wiphy,
10785: &ifmgd->csa_connection_drop_work);
10786: wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
10787: &ifmgd->tdls_peer_del_work);
10788: wiphy_hrtimer_work_cancel(sdata->local->hw.wiphy,
10789: &ifmgd->uhr_omp.status_work);
10790:
10791: if (ifmgd->assoc_data)
10792: ieee80211_destroy_assoc_data(sdata, ASSOC_TIMEOUT);
10793: if (ifmgd->auth_data)
10794: ieee80211_destroy_auth_data(sdata, false);
10795: spin_lock_bh(&ifmgd->teardown_lock);
10796: if (ifmgd->teardown_skb) {
10797: kfree_skb(ifmgd->teardown_skb);
10798: ifmgd->teardown_skb = NULL;
10799: ifmgd->orig_teardown_skb = NULL;
10800: }
10801: kfree(ifmgd->assoc_req_ies);
10802: ifmgd->assoc_req_ies = NULL;
10803: ifmgd->assoc_req_ies_len = 0;
10804: spin_unlock_bh(&ifmgd->teardown_lock);
10805: timer_delete_sync(&ifmgd->timer);
10806: }
SourceFile:net/mac80211/mlme.c]
|
| 84/2 |
2026/08/10 01:42 |
llm |
expert |
0m
Model:
Tokens:
input: 103379
output: 50
thoughts: 50
Thoughts: Here's my analysis of that function call, broken down as I would think through it:
**Deconstructing `ieee80211_mgd_stop` and `ieee80211_destroy_assoc_data`**
Okay, so `ieee80211_mgd_stop` is telling us something has happened in the management domain, specifically, likely a de-association or disconnection event. I need to understand the implications of this, particularly how the system handles the cleanup. The fact that `ieee80211_mgd_stop` calls `ieee80211_destroy_assoc_data` is the key. It looks like the system's choice to call that function is a signal to begin the important step of handling resources that are linked to an association.
Therefore, the next logical step is to dive right into what `ieee80211_destroy_assoc_data` does. I need to understand what specific data structures, buffers, or states it's responsible for clearing and freeing. What resources are tied to a given association, and how does the system ensure they're properly reclaimed? Is this a full teardown, or are there steps that may not occur in this process?
Ultimately, my goal here is to grasp the full lifecycle of an association and ensure that any potential memory leaks or resource-related bugs are prevented.
|
| 85/2 |
2026/08/10 01:42 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/mlme.c Name:ieee80211_destroy_assoc_data]
Results: map[SourceCode:5300: static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
5301: enum assoc_status status)
5302: {
5303: struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
5304:
5305: lockdep_assert_wiphy(sdata->local->hw.wiphy);
5306:
5307: sdata->u.mgd.assoc_data = NULL;
5308:
5309: if (status != ASSOC_SUCCESS) {
5310: /*
5311: * we are not associated yet, the only timer that could be
5312: * running is the timeout for the association response which
5313: * which is not relevant anymore.
5314: */
5315: timer_delete_sync(&sdata->u.mgd.timer);
5316: sta_info_destroy_addr(sdata, assoc_data->ap_addr);
5317:
5318: eth_zero_addr(sdata->deflink.u.mgd.bssid);
5319: ieee80211_link_info_change_notify(sdata, &sdata->deflink,
5320: BSS_CHANGED_BSSID);
5321: sdata->u.mgd.flags = 0;
5322: sdata->vif.bss_conf.mu_mimo_owner = false;
5323:
5324: if (status != ASSOC_REJECTED) {
5325: struct cfg80211_assoc_failure data = {
5326: .timeout = status == ASSOC_TIMEOUT,
5327: };
5328: int i;
5329:
5330: BUILD_BUG_ON(ARRAY_SIZE(data.bss) !=
5331: ARRAY_SIZE(assoc_data->link));
5332:
5333: for (i = 0; i < ARRAY_SIZE(data.bss); i++)
5334: data.bss[i] = assoc_data->link[i].bss;
5335:
5336: if (ieee80211_vif_is_mld(&sdata->vif))
5337: data.ap_mld_addr = assoc_data->ap_addr;
5338:
5339: cfg80211_assoc_failure(sdata->dev, &data);
5340: }
5341:
5342: ieee80211_link_release_channel(&sdata->deflink);
5343: ieee80211_vif_set_links(sdata, 0, 0);
5344: }
5345:
5346: kfree(assoc_data);
5347: }
SourceFile:net/mac80211/mlme.c]
|
| 86/2 |
2026/08/10 01:42 |
llm |
expert |
0m
Model:
Tokens:
input: 104638
output: 49
thoughts: 595
Thoughts: **Analyzing the Channel Release Flow in IEEE 802.11 Interface Teardown**
Okay, let's break this down. My initial concern was about the potential for a race condition in the channel release during interface teardown, specifically looking at how `ieee80211_link_release_channel` is called. The original code snippet highlighted a potentially missed call.
My first observation was that `ieee80211_destroy_assoc_data` calls `ieee80211_link_release_channel` if the association `status` isn't `ASSOC_SUCCESS`. But, wait, if the device *is* associated, this function *won't* call the channel release, right? That's the baseline.
Then, I see `ieee80211_mgd_stop` calls `ieee80211_destroy_assoc_data` with a timeout, `ASSOC_TIMEOUT`. This means the `status` will be *not* `ASSOC_SUCCESS`, so it *will* call the channel release. Okay, that looks correct.
Now, if `ieee80211_link_release_channel` is called *within* `ieee80211_mgd_stop`, then for a `NL80211_IFTYPE_STATION` interface, it *should* be called before `drv_remove_interface`. This is important. Let me re-examine `ieee80211_do_stop` to confirm:
```c
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
ieee80211_mgd_stop(sdata);
break;
```
Yes, for a STATION interface, `ieee80211_mgd_stop` *is* called. But, does `ieee80211_mgd_stop` always call `ieee80211_destroy_assoc_data`? It *only* does so if `ifmgd->assoc_data` isn't NULL. But that pointer is *only* not NULL during the association process! Once association *succeeds*, `assoc_data` is freed in `ieee80211_assoc_success`. So, when the station is *fully* associated, `ifmgd->assoc_data` is NULL!
Which means, `ieee80211_mgd_stop` *won't* call `ieee80211_link_release_channel` if the device is fully associated. Now, where is `ieee80211_link_release_channel` called in this scenario? Nowhere! Not until `ieee80211_teardown_sdata` is called.
**Therefore, for a STATION interface, if the device is fully associated, the channel will not be released before the driver removal, which could lead to the warning!**
Now, I also need to consider IBSS (Ad-hoc) interfaces. Here, `ieee80211_ibss_stop` is called. That's a different path, which needs a similar analysis, as I may have only identified the root cause for STA mode.
|
| 87/2 |
2026/08/10 01:42 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:net/mac80211/ibss.c Name:ieee80211_ibss_stop]
Results: map[SourceCode: 530: void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata)
531: {
532: struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
533:
534: wiphy_work_cancel(sdata->local->hw.wiphy,
535: &ifibss->csa_connection_drop_work);
536: }
SourceFile:net/mac80211/ibss.c]
|
| 88/2 |
2026/08/10 01:42 |
llm |
expert |
0m
Model:
Tokens:
input: 106192
output: 58
thoughts: 470
Thoughts: **Analyzing a Harmless Warning in the Wi-Fi Driver**
Okay, so I've been looking into this `ieee80211_link_release_channel` warning. It seems like `ieee80211_ibss_stop` doesn't call that function, which is the root cause. This means the warning pops up for Access Points, Stations (when associated), and IBSS modes when the interface is removed while it's active. That's actually pretty commonβthink about just unplugging a USB Wi-Fi dongle.
The good news is, it's completely benign. It's a `WARN_ONCE`, so it only shows up once per boot and doesnβt lead to any crashes or memory corruption. Essentially a nuisance, but not a bug.
So, how do we classify this?
* **Exploitable:** Nope.
* **Denial of Service:** Nah.
* **Unprivileged Access:** No.
* **User Namespaces:** Yes (through `mac80211_hwsim`).
* **VM/Network Triggers:** None.
* **Peripheral Trigger:** Yes, via unplugging a USB Wi-Fi dongle.
* **Malicious Filesystem Trigger:** No.
Now, let's make sure an unprivileged user can't exploit this in some other way. Physical access to unplug the dongle is straightforward. Can they trigger this through `mac80211_hwsim` without user namespaces? No, because `HWSIM_CMD_NEW_RADIO` needs `CAP_NET_ADMIN`.
However, what if they use a net namespace? If user namespaces are enabled, a user can create a namespace, map their UID to root, get `CAP_NET_ADMIN` within that namespace, create a new network namespace, then use `HWSIM_CMD_NEW_RADIO` to spawn a new radio. After that, they can create an AP or Station interface, bring it up, and finally destroy the network namespace to trigger the warning.
Hold on, I need to verify something. Does `HWSIM_CMD_NEW_RADIO` even work in a non-init network namespace? Gotta check `mac80211_hwsim_new_radio` for confirmation.
|
| 89/2 |
2026/08/10 01:42 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/net/wireless/virtual/mac80211_hwsim_main.c Name:mac80211_hwsim_new_radio]
Results: map[SourceCode:5650: static int mac80211_hwsim_new_radio(struct genl_info *info,
5651: struct hwsim_new_radio_params *param)
5652: {
5653: int err;
5654: u8 addr[ETH_ALEN];
5655: struct mac80211_hwsim_data *data;
5656: struct ieee80211_hw *hw;
5657: enum nl80211_band band;
5658: const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
5659: struct net *net;
5660: int idx, i;
5661: int n_limits = 0;
5662: int n_bands = 0;
5663:
5664: if (WARN_ON(param->channels > 1 && !param->use_chanctx))
5665: return -EINVAL;
5666:
5667: spin_lock_bh(&hwsim_radio_lock);
5668: idx = hwsim_radio_idx++;
5669: spin_unlock_bh(&hwsim_radio_lock);
5670:
5671: if (param->mlo)
5672: ops = &mac80211_hwsim_mlo_ops;
5673: else if (param->use_chanctx)
5674: ops = &mac80211_hwsim_mchan_ops;
5675: hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname);
5676: if (!hw) {
5677: pr_debug("mac80211_hwsim: ieee80211_alloc_hw failed\n");
5678: err = -ENOMEM;
5679: goto failed;
5680: }
5681:
5682: /* ieee80211_alloc_hw_nm may have used a default name */
5683: param->hwname = wiphy_name(hw->wiphy);
5684:
5685: if (info)
5686: net = genl_info_net(info);
5687: else
5688: net = &init_net;
5689: wiphy_net_set(hw->wiphy, net);
5690:
5691: data = hw->priv;
5692: data->hw = hw;
5693:
5694: data->dev = device_create(&hwsim_class, NULL, 0, hw, "hwsim%d", idx);
5695: if (IS_ERR(data->dev)) {
5696: printk(KERN_DEBUG
5697: "mac80211_hwsim: device_create failed (%ld)\n",
5698: PTR_ERR(data->dev));
5699: err = -ENOMEM;
5700: goto failed_drvdata;
5701: }
5702: data->dev->driver = &mac80211_hwsim_driver.driver;
5703: err = device_bind_driver(data->dev);
5704: if (err != 0) {
5705: pr_debug("mac80211_hwsim: device_bind_driver failed (%d)\n",
5706: err);
5707: goto failed_bind;
5708: }
5709:
5710: skb_queue_head_init(&data->pending);
5711:
5712: SET_IEEE80211_DEV(hw, data->dev);
5713: if (!param->perm_addr) {
5714: eth_zero_addr(addr);
5715: addr[0] = 0x02;
5716: addr[3] = idx >> 8;
5717: addr[4] = idx;
5718: memcpy(data->addresses[0].addr, addr, ETH_ALEN);
5719: /* Why need here second address ? */
5720: memcpy(data->addresses[1].addr, addr, ETH_ALEN);
5721: data->addresses[1].addr[0] |= 0x40;
5722: memcpy(data->addresses[2].addr, addr, ETH_ALEN);
5723: data->addresses[2].addr[0] |= 0x50;
5724:
5725: hw->wiphy->n_addresses = 3;
5726: hw->wiphy->addresses = data->addresses;
5727: /* possible address clash is checked at hash table insertion */
5728: } else {
5729: memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN);
5730: /* compatibility with automatically generated mac addr */
5731: memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN);
5732: memcpy(data->addresses[2].addr, param->perm_addr, ETH_ALEN);
5733: hw->wiphy->n_addresses = 3;
5734: hw->wiphy->addresses = data->addresses;
5735: }
5736:
5737: data->channels = param->channels;
5738: data->use_chanctx = param->use_chanctx;
5739: data->idx = idx;
5740: data->destroy_on_close = param->destroy_on_close;
5741: if (info)
5742: data->portid = info->snd_portid;
5743:
5744: /* setup interface limits, only on interface types we support */
5745: if (param->iftypes & BIT(NL80211_IFTYPE_ADHOC)) {
5746: data->if_limits[n_limits].max = 1;
5747: data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_ADHOC);
5748: n_limits++;
5749: }
5750:
5751: if (param->iftypes & HWSIM_DEFAULT_IF_LIMIT) {
5752: data->if_limits[n_limits].max = 2048;
5753: /*
5754: * For this case, we may only support a subset of
5755: * HWSIM_DEFAULT_IF_LIMIT, therefore we only want to add the
5756: * bits that both param->iftype & HWSIM_DEFAULT_IF_LIMIT have.
5757: */
5758: data->if_limits[n_limits].types =
5759: HWSIM_DEFAULT_IF_LIMIT & param->iftypes;
5760: n_limits++;
5761: }
5762:
5763: if (param->iftypes & BIT(NL80211_IFTYPE_P2P_DEVICE)) {
5764: data->if_limits[n_limits].max = 1;
5765: data->if_limits[n_limits].types =
5766: BIT(NL80211_IFTYPE_P2P_DEVICE);
5767: n_limits++;
5768: }
5769:
5770: if (param->iftypes & BIT(NL80211_IFTYPE_NAN)) {
5771: data->if_limits[n_limits].max = 1;
5772: data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_NAN);
5773: n_limits++;
5774:
5775: hw->wiphy->nan_supported_bands = BIT(NL80211_BAND_2GHZ) |
5776: BIT(NL80211_BAND_5GHZ);
5777:
5778: hw->wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC |
5779: WIPHY_NAN_FLAGS_USERSPACE_DE;
5780: hw->wiphy->nan_capa.op_mode = NAN_OP_MODE_PHY_MODE_MASK |
5781: NAN_OP_MODE_80P80MHZ |
5782: NAN_OP_MODE_160MHZ;
5783:
5784: hw->wiphy->nan_capa.n_antennas = 0x22;
5785: hw->wiphy->nan_capa.max_channel_switch_time = 0;
5786:
5787: wiphy_ext_feature_set(hw->wiphy,
5788: NL80211_EXT_FEATURE_SECURE_NAN);
5789:
5790: hrtimer_setup(&data->nan.slot_timer,
5791: mac80211_hwsim_nan_slot_timer,
5792: CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT);
5793: hrtimer_setup(&data->nan.resume_txqs_timer,
5794: mac80211_hwsim_nan_resume_txqs_timer,
5795: CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT);
5796: hrtimer_setup(&data->nan.discovery_beacon_timer,
5797: mac80211_hwsim_nan_discovery_beacon_timer,
5798: CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT);
5799:
5800: spin_lock_init(&data->nan.state_lock);
5801: }
5802:
5803: if (param->iftypes & BIT(NL80211_IFTYPE_NAN_DATA)) {
5804: data->if_limits[n_limits].max = 2;
5805: data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_NAN_DATA);
5806: n_limits++;
5807:
5808: hw->wiphy->nan_capa.phy.ht = hwsim_nan_ht_cap;
5809: hw->wiphy->nan_capa.phy.vht = hwsim_nan_vht_cap;
5810: hw->wiphy->nan_capa.phy.he = hwsim_nan_he_cap;
5811:
5812: /*
5813: * NAN switches between bands/channels per its schedule,
5814: * so mac80211 rate control can't work here.
5815: */
5816: ieee80211_hw_set(hw, HAS_RATE_CONTROL);
5817: }
5818:
5819: data->if_combination.radar_detect_widths =
5820: BIT(NL80211_CHAN_WIDTH_5) |
5821: BIT(NL80211_CHAN_WIDTH_10) |
5822: BIT(NL80211_CHAN_WIDTH_20_NOHT) |
5823: BIT(NL80211_CHAN_WIDTH_20) |
5824: BIT(NL80211_CHAN_WIDTH_40) |
5825: BIT(NL80211_CHAN_WIDTH_80) |
5826: BIT(NL80211_CHAN_WIDTH_160);
5827:
5828: if (data->use_chanctx) {
5829: hw->wiphy->max_scan_ssids = 255;
5830: hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
5831: hw->wiphy->max_remain_on_channel_duration = 1000;
5832: data->if_combination.num_different_channels = data->channels;
5833: } else {
5834: data->if_combination.num_different_channels = 1;
5835: }
5836:
5837: if (!n_limits) {
5838: err = -EINVAL;
5839: goto failed_hw;
5840: }
5841:
5842: data->if_combination.max_interfaces = 0;
5843: for (i = 0; i < n_limits; i++)
5844: data->if_combination.max_interfaces +=
5845: data->if_limits[i].max;
5846:
5847: data->if_combination.n_limits = n_limits;
5848: data->if_combination.limits = data->if_limits;
5849:
5850: /*
5851: * If we actually were asked to support combinations,
5852: * advertise them - if there's only a single thing like
5853: * only IBSS then don't advertise it as combinations.
5854: */
5855: if (data->if_combination.max_interfaces > 1) {
5856: hw->wiphy->iface_combinations = &data->if_combination;
5857: hw->wiphy->n_iface_combinations = 1;
5858: }
5859:
5860: if (param->ciphers) {
5861: memcpy(data->ciphers, param->ciphers,
5862: param->n_ciphers * sizeof(u32));
5863: hw->wiphy->cipher_suites = data->ciphers;
5864: hw->wiphy->n_cipher_suites = param->n_ciphers;
5865: }
5866:
5867: hw->wiphy->mbssid_max_interfaces = 8;
5868: hw->wiphy->ema_max_profile_periodicity = 3;
5869:
5870: spin_lock_init(&data->tsf_offset_lock);
5871:
5872: data->rx_rssi = DEFAULT_RX_RSSI;
5873:
5874: INIT_DELAYED_WORK(&data->roc_start, hw_roc_start);
5875: INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
5876: INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work);
5877:
5878: hw->queues = 5;
5879: hw->offchannel_tx_hw_queue = 4;
5880:
5881: ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
5882: ieee80211_hw_set(hw, CHANCTX_STA_CSA);
5883: ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
5884: ieee80211_hw_set(hw, QUEUE_CONTROL);
5885: ieee80211_hw_set(hw, WANT_MONITOR_VIF);
5886: ieee80211_hw_set(hw, AMPDU_AGGREGATION);
5887: ieee80211_hw_set(hw, MFP_CAPABLE);
5888: ieee80211_hw_set(hw, SIGNAL_DBM);
5889: ieee80211_hw_set(hw, SUPPORTS_PS);
5890: ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
5891: ieee80211_hw_set(hw, TDLS_WIDER_BW);
5892: ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
5893: ieee80211_hw_set(hw, STRICT);
5894: ieee80211_hw_set(hw, BUFF_MMPDU_TXQ);
5895: ieee80211_hw_set(hw, STA_MMPDU_TXQ);
5896:
5897: if (param->mlo) {
5898: hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;
5899: ieee80211_hw_set(hw, HAS_RATE_CONTROL);
5900: ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
5901: ieee80211_hw_set(hw, CONNECTION_MONITOR);
5902: ieee80211_hw_set(hw, AP_LINK_PS);
5903:
5904: hw->wiphy->iftype_ext_capab = mac80211_hwsim_iftypes_ext_capa;
5905: hw->wiphy->num_iftype_ext_capab =
5906: ARRAY_SIZE(mac80211_hwsim_iftypes_ext_capa);
5907: } else {
5908: ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
5909: ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
5910: if (rctbl)
5911: ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
5912: }
5913:
5914: hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
5915: hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
5916: WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
5917: WIPHY_FLAG_AP_UAPSD |
5918: WIPHY_FLAG_HAS_CHANNEL_SWITCH;
5919: hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5920: hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
5921: NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
5922: NL80211_FEATURE_STATIC_SMPS |
5923: NL80211_FEATURE_DYNAMIC_SMPS |
5924: NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
5925: NL80211_FEATURE_AP_SCAN;
5926: wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
5927: wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
5928: wiphy_ext_feature_set(hw->wiphy,
5929: NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
5930: wiphy_ext_feature_set(hw->wiphy,
5931: NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
5932: wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);
5933:
5934: wiphy_ext_feature_set(hw->wiphy,
5935: NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT);
5936: wiphy_ext_feature_set(hw->wiphy,
5937: NL80211_EXT_FEATURE_BSS_COLOR);
5938: wiphy_ext_feature_set(hw->wiphy,
5939: NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT);
5940: wiphy_ext_feature_set(hw->wiphy,
5941: NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
5942: wiphy_ext_feature_set(hw->wiphy,
5943: NL80211_EXT_FEATURE_EXT_KEY_ID);
5944: wiphy_ext_feature_set(hw->wiphy,
5945: NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION);
5946:
5947: hw->wiphy->interface_modes = param->iftypes;
5948:
5949: /* ask mac80211 to reserve space for magic */
5950: hw->vif_data_size = sizeof(struct hwsim_vif_priv);
5951: hw->sta_data_size = sizeof(struct hwsim_sta_priv);
5952: hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv);
5953: hw->txq_data_size = 0;
5954:
5955: memcpy(data->channels_2ghz, hwsim_channels_2ghz,
5956: sizeof(hwsim_channels_2ghz));
5957: memcpy(data->channels_5ghz, hwsim_channels_5ghz,
5958: sizeof(hwsim_channels_5ghz));
5959: memcpy(data->channels_6ghz, hwsim_channels_6ghz,
5960: sizeof(hwsim_channels_6ghz));
5961: memcpy(data->channels_s1g, hwsim_channels_s1g,
5962: sizeof(hwsim_channels_s1g));
5963: memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
5964:
5965: for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
5966: struct ieee80211_supported_band *sband = &data->bands[band];
5967: struct wiphy_radio_freq_range *radio_range;
5968: const struct ieee80211_channel *c;
5969: struct wiphy_radio *radio;
5970:
5971: sband->band = band;
5972:
5973: switch (band) {
5974: case NL80211_BAND_2GHZ:
5975: sband->channels = data->channels_2ghz;
5976: sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz);
5977: sband->bitrates = data->rates;
5978: sband->n_bitrates = ARRAY_SIZE(hwsim_rates);
5979: break;
5980: case NL80211_BAND_5GHZ:
5981: sband->channels = data->channels_5ghz;
5982: sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz);
5983: sband->bitrates = data->rates + 4;
5984: sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
5985:
5986: sband->vht_cap.vht_supported = true;
5987: sband->vht_cap.cap =
5988: IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
5989: IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
5990: IEEE80211_VHT_CAP_RXLDPC |
5991: IEEE80211_VHT_CAP_SHORT_GI_80 |
5992: IEEE80211_VHT_CAP_SHORT_GI_160 |
5993: IEEE80211_VHT_CAP_TXSTBC |
5994: IEEE80211_VHT_CAP_RXSTBC_4 |
5995: IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
5996: sband->vht_cap.vht_mcs.rx_mcs_map =
5997: cpu_to_le16(HWSIM_VHT_MCS_MAP);
5998: sband->vht_cap.vht_mcs.tx_mcs_map =
5999: sband->vht_cap.vht_mcs.rx_mcs_map;
6000: break;
6001: case NL80211_BAND_6GHZ:
6002: sband->channels = data->channels_6ghz;
6003: sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz);
6004: sband->bitrates = data->rates + 4;
6005: sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
6006: break;
6007: case NL80211_BAND_S1GHZ:
6008: memcpy(&sband->s1g_cap, &hwsim_s1g_cap,
6009: sizeof(sband->s1g_cap));
6010: sband->channels = data->channels_s1g;
6011: sband->n_channels = ARRAY_SIZE(hwsim_channels_s1g);
6012: break;
6013: default:
6014: continue;
6015: }
6016:
6017: if (band != NL80211_BAND_6GHZ){
6018: sband->ht_cap.ht_supported = true;
6019: sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
6020: IEEE80211_HT_CAP_GRN_FLD |
6021: IEEE80211_HT_CAP_SGI_20 |
6022: IEEE80211_HT_CAP_SGI_40 |
6023: IEEE80211_HT_CAP_DSSSCCK40 |
6024: IEEE80211_HT_CAP_TX_STBC |
6025: IEEE80211_HT_CAP_RX_STBC;
6026: sband->ht_cap.ampdu_factor = 0x3;
6027: sband->ht_cap.ampdu_density = 0x6;
6028: memset(&sband->ht_cap.mcs, 0,
6029: sizeof(sband->ht_cap.mcs));
6030: sband->ht_cap.mcs.rx_mask[0] = 0xff;
6031: sband->ht_cap.mcs.rx_mask[1] = 0xff;
6032: sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
6033: }
6034:
6035: mac80211_hwsim_sband_capab(sband);
6036:
6037: hw->wiphy->bands[band] = sband;
6038:
6039: if (!param->multi_radio)
6040: continue;
6041:
6042: c = sband->channels;
6043: radio_range = &data->radio_range[n_bands];
6044: radio_range->start_freq = ieee80211_channel_to_khz(c) - 10000;
6045:
6046: c += sband->n_channels - 1;
6047: radio_range->end_freq = ieee80211_channel_to_khz(c) + 10000;
6048:
6049: radio = &data->radio[n_bands++];
6050: radio->freq_range = radio_range;
6051: radio->n_freq_range = 1;
6052: radio->iface_combinations = &data->if_combination_radio;
6053: radio->n_iface_combinations = 1;
6054: }
6055:
6056: if (param->multi_radio) {
6057: hw->wiphy->radio = data->radio;
6058: hw->wiphy->n_radio = n_bands;
6059:
6060: memcpy(&data->if_combination_radio, &data->if_combination,
6061: sizeof(data->if_combination));
6062: data->if_combination.num_different_channels *= n_bands;
6063: }
6064:
6065: if (data->use_chanctx)
6066: data->if_combination.radar_detect_widths = 0;
6067:
6068: /* By default all radios belong to the first group */
6069: data->group = 1;
6070: mutex_init(&data->mutex);
6071:
6072: data->netgroup = hwsim_net_get_netgroup(net);
6073: data->wmediumd = hwsim_net_get_wmediumd(net);
6074:
6075: /* Enable frame retransmissions for lossy channels */
6076: hw->max_rates = 4;
6077: hw->max_rate_tries = 11;
6078:
6079: hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands;
6080: hw->wiphy->n_vendor_commands =
6081: ARRAY_SIZE(mac80211_hwsim_vendor_commands);
6082: hw->wiphy->vendor_events = mac80211_hwsim_vendor_events;
6083: hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events);
6084:
6085: if (param->reg_strict)
6086: hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
6087: if (param->regd) {
6088: data->regd = param->regd;
6089: hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
6090: wiphy_apply_custom_regulatory(hw->wiphy, param->regd);
6091: /* give the regulatory workqueue a chance to run */
6092: schedule_timeout_interruptible(1);
6093: }
6094:
6095: wiphy_ext_feature_set(hw->wiphy,
6096: NL80211_EXT_FEATURE_DFS_CONCURRENT);
6097: if (param->background_radar)
6098: wiphy_ext_feature_set(hw->wiphy,
6099: NL80211_EXT_FEATURE_RADAR_BACKGROUND);
6100:
6101: if (param->no_vif)
6102: ieee80211_hw_set(hw, NO_AUTO_VIF);
6103:
6104: wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
6105: wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PUNCT);
6106:
6107: for (i = 0; i < ARRAY_SIZE(data->link_data); i++) {
6108: hrtimer_setup(&data->link_data[i].beacon_timer, mac80211_hwsim_beacon,
6109: CLOCK_MONOTONIC, HRTIMER_MODE_ABS_SOFT);
6110: data->link_data[i].link_id = i;
6111: }
6112:
6113: err = ieee80211_register_hw(hw);
6114: if (err < 0) {
6115: pr_debug("mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
6116: err);
6117: goto failed_hw;
6118: }
6119:
6120: wiphy_dbg(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr);
6121:
6122: if (param->reg_alpha2) {
6123: data->alpha2[0] = param->reg_alpha2[0];
6124: data->alpha2[1] = param->reg_alpha2[1];
6125: regulatory_hint(hw->wiphy, param->reg_alpha2);
6126: }
6127:
6128: data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir);
6129: debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
6130: debugfs_create_file("group", 0666, data->debugfs, data,
6131: &hwsim_fops_group);
6132: debugfs_create_file("rx_rssi", 0666, data->debugfs, data,
6133: &hwsim_fops_rx_rssi);
6134: if (!data->use_chanctx)
6135: debugfs_create_file("dfs_simulate_radar", 0222,
6136: data->debugfs,
6137: data, &hwsim_simulate_radar);
6138: if (param->background_radar)
6139: debugfs_create_file("dfs_background_cac", 0200,
6140: data->debugfs,
6141: data, &hwsim_background_cac_ops);
6142: debugfs_create_file("simulate_incumbent_signal_interference", 0200,
6143: data->debugfs,
6144: data, &hwsim_simulate_incumbent_signal_fops);
6145:
6146: if (param->pmsr_capa) {
6147: data->pmsr_capa = *param->pmsr_capa;
6148: hw->wiphy->pmsr_capa = &data->pmsr_capa;
6149: }
6150:
6151: spin_lock_bh(&hwsim_radio_lock);
6152: err = rhashtable_insert_fast(&hwsim_radios_rht, &data->rht,
6153: hwsim_rht_params);
6154: if (err < 0) {
6155: if (info) {
6156: GENL_SET_ERR_MSG(info, "perm addr already present");
6157: NL_SET_BAD_ATTR(info->extack,
6158: info->attrs[HWSIM_ATTR_PERM_ADDR]);
6159: }
6160: spin_unlock_bh(&hwsim_radio_lock);
6161: goto failed_final_insert;
6162: }
6163:
6164: list_add_tail(&data->list, &hwsim_radios);
6165: hwsim_radios_generation++;
6166: spin_unlock_bh(&hwsim_radio_lock);
6167:
6168: hwsim_mcast_new_radio(idx, info, param);
6169:
6170: return idx;
6171:
6172: failed_final_insert:
6173: debugfs_remove_recursive(data->debugfs);
6174: ieee80211_unregister_hw(data->hw);
6175: failed_hw:
6176: device_release_driver(data->dev);
6177: failed_bind:
6178: device_unregister(data->dev);
6179: failed_drvdata:
6180: ieee80211_free_hw(hw);
6181: failed:
6182: return err;
6183: }
SourceFile:drivers/net/wireless/virtual/mac80211_hwsim_main.c]
|
| 90/2 |
2026/08/10 01:42 |
llm |
expert |
0m
Model:
Tokens:
input: 117437
output: 66
thoughts: 391
Thoughts: **My Assessment of the `mac80211_hwsim` Vulnerability**
Okay, so here's what I've figured out. `mac80211_hwsim_new_radio` is using `genl_info_net(info)` if `info` exists, and this is crucial. Along with `wiphy_net_set(hw->wiphy, net)`, it means the new radio is created directly within the user's network namespace. This has some interesting implications.
When that user's network namespace is destroyed, `hwsim_exit_net` gets called, which, as expected, deletes the radio. So, an unprivileged user can trigger a `WARN_ONCE` with the following sequence:
1. Create a user namespace and a network namespace.
2. Send `HWSIM_CMD_NEW_RADIO` to get a new radio.
3. Set up an AP interface on that radio.
4. Start the AP interface.
5. Exit the process, which removes the user's network namespace.
6. `hwsim_exit_net` clears the radio
7. `ieee80211_unregister_hw` removes the interfaces
8. `ieee80211_do_stop` clears `IEEE80211_SDATA_IN_DRIVER`
9. `ieee80211_teardown_sdata` calls `ieee80211_link_release_channel`
10. `drv_unassign_vif_chanctx` causes a `WARN_ONCE` warning.
The key here is that an unprivileged user can indeed trigger this. However, it's just a `WARN_ONCE`. It doesn't seem to have any demonstrable impact beyond that. Therefore, it's not exploitable for privilege escalation or denial of service, *unless* `panic_on_warn` is set, which, as we know, is highly unlikely in a production environment. So, I will classify this as a low-severity issue, and proceed to set the results based on this analysis.
|
| 91/2 |
2026/08/10 01:42 |
tool |
set-results |
0m
Args: map[DenialOfService:false Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
Results: map[DenialOfService:false Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:true RemoteTrigger:false Unprivileged:false UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
|
| 92/2 |
2026/08/10 01:42 |
llm |
expert |
0m
Model:
Tokens:
input: 118432
output: 819
thoughts: 298
Thoughts: **My Assessment of the `WARN_ONCE` Bug**
Okay, the results are in, and now it's time to craft the final response. My analysis shows a harmless, though potentially concerning, `WARN_ONCE` within the `drv_unassign_vif_chanctx` function. The core of the problem lies in a failed `check_sdata_in_driver` check.
It seems the issue stems from how `IEEE80211_SDATA_IN_DRIVER` is handled. The flag is cleared during interface teardown via `ieee80211_do_stop`, but then we call `ieee80211_link_release_channel` *later* during `ieee80211_teardown_sdata`. This leads to a mismatch: when `ieee80211_link_release_channel` attempts to unassign the channel context, it finds the interface is *no longer* considered active within the driver. That triggers the warning.
However, I've confirmed that this is just a false positive, so to speak. The channel context is properly unassigned from the mac80211 side of things. Since the driver is already undergoing removal, it's not strictly necessary for it to be notified. The warning is essentially noise.
Crucially, there are *no* real security issues here. My assessment indicates no memory corruption, no use-after-free conditions, and no resource leaks. I've also found that this can be triggered by either unplugging a USB Wi-Fi dongle while an AP is running (peripheral trigger) or, in a more controlled environment, using `mac80211_hwsim` within an unprivileged user namespace (user namespace trigger). Importantly, there is no exploitable vulnerability, and it does not allow for a denial of service.
|
| 93/1 |
2026/08/10 01:42 |
action |
format-explanation |
0m
Results: map[Explanation:The bug report describes a `WARN_ONCE` triggered in `drv_unassign_vif_chanctx`
within the mac80211 subsystem.
### Root Cause Analysis
The warning is triggered by the `check_sdata_in_driver(sdata)` macro, which
checks if the `IEEE80211_SDATA_IN_DRIVER` flag is set on the sub-interface data
(`sdata`). If the flag is missing, it emits a warning and returns false, causing
`drv_unassign_vif_chanctx` to return early without calling the driver's
`unassign_vif_chanctx` callback.
This happens during the teardown of a wireless interface (e.g., an AP or a fully
associated STATION) when the underlying hardware is removed or unregistered. The
teardown sequence is as follows:
1. `cfg80211_shutdown_all_interfaces` calls `dev_close`, which eventually calls
`ieee80211_do_stop`.
2. `ieee80211_do_stop` calls `drv_remove_interface`, which clears the
`IEEE80211_SDATA_IN_DRIVER` flag, effectively removing the interface from the
driver's perspective.
3. Later in the teardown process, `cfg80211_unregister_wdev` calls
`unregister_netdevice_many`, which invokes the `ndo_uninit` callback
(`ieee80211_uninit`).
4. `ieee80211_uninit` calls `ieee80211_teardown_sdata`, which calls
`ieee80211_link_stop` and then `ieee80211_link_release_channel`.
5. `ieee80211_link_release_channel` attempts to unassign the channel context by
calling `drv_unassign_vif_chanctx`.
6. Since `IEEE80211_SDATA_IN_DRIVER` was already cleared in step 2, the
`check_sdata_in_driver` macro triggers the warning.
### Security Impact
**Exploitable:** No.
This is a harmless warning caused by a slightly out-of-order teardown sequence.
Returning early from `drv_unassign_vif_chanctx` is actually the correct and safe
behavior here, as calling the driver's `unassign_vif_chanctx` callback on an
interface that has already been removed (`drv_remove_interface`) could lead to a
crash or use-after-free in the driver. The channel context is still properly
unassigned and freed on the mac80211 side, so there are no resource leaks,
memory corruptions, or use-after-free vulnerabilities.
**Denial of Service:** No.
The bug is a `WARN_ONCE` and does not halt the kernel or cause any deadlocks. It
will not cause a denial of service in production builds (unless `panic_on_warn`
is explicitly enabled by the administrator).
**Trigger Vectors:**
- **Peripheral Trigger:** Yes. An attacker with physical access can trigger this
by physically unplugging a USB Wi-Fi dongle while an Access Point (AP) or a
connected STATION interface is running on it.
- **User Namespace:** Yes. An unprivileged user can trigger this by creating a
new user namespace and network namespace, acquiring `CAP_NET_ADMIN`, and using
the `mac80211_hwsim` module (via `HWSIM_CMD_NEW_RADIO`) to create a virtual
radio. They can then start an AP interface on it and destroy the network
namespace, which unregisters the virtual hardware and triggers the warning.]
|