| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/23 18:40 | flow | patch-triage |
3mArgs:null Results: {
"EnableConfigs": [
"CFG80211",
"MAC80211",
"MAC80211_HWSIM"
],
"FocusSymbols": [
"nl80211_nan_set_non_evac_channels",
"nl80211_parse_non_evac_channel",
"cfg80211_nan_set_non_evac_channels",
"ieee80211_set_nan_non_evac_channels",
"ieee80211_nan_set_non_evac_channels",
"ieee80211_nan_find_evac_chan"
],
"KMSANReasoning": "The patch introduces a new nl80211 command `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS` along with mac80211/cfg80211 handling to configure channels that must not be evacuated.\n\n1. Memory Initialization: All newly allocated heap structures (`channels` and `channel_parsed`) are allocated using `kzalloc` and `kcalloc`, respectively. Furthermore, `nl80211_parse_chandef()` explicitly zeroes the destination `cfg80211_chan_def` using `memset()`. The struct `ieee80211_nan_channel` containing the new `no_evacuate` boolean is already zeroed via `memset()` during channel init and removal.\n2. Kernel-to-User Information Leaks: The command is a setter (`doit` only) and does not copy any kernel structures or Netlink attributes back to user space.\n3. KMSAN vs. KASAN applicability: Any theoretical issues introduced by the patch (such as integer truncation on `n_channels`, channel index lookups, or NULL pointer dereferencing) fall under bounds checks, memory corruption, or locking issues, which are comprehensively caught by KASAN, UBSAN, and LOCKDEP. No uninitialized memory usage or info-leak vectors are introduced. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false,
"Reasoning": "The patch adds a new userspace-facing nl80211 Generic Netlink command NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS to configure NAN local schedule channels that must not be evacuated for concurrent operations. The implementation includes nested attribute parsing in nl80211, validation and state checks in cfg80211, driver callback plumbing, and evacuation filtering in mac80211. This code is fully reachable in virtualized environments using mac80211_hwsim and netlink. Moreover, user-controlled channel counts parsed into a u8 variable with __counted_by annotations warrant fuzzing against truncation, bounds violations, and state consistency issues.",
"WorthFuzzing": true
} |
| 1/1 | 2026/09/23 18:40 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 2bd9eba0b7bea163a2099d7071fa60052175ccac\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Sep 23 18:40:41 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/include/net/cfg80211.h b/include/net/cfg80211.h\nindex 9aa7d2d4a1841..43551dd4328ef 100644\n--- a/include/net/cfg80211.h\n+++ b/include/net/cfg80211.h\n@@ -4258,6 +4258,21 @@ struct cfg80211_nan_local_sched {\n \tstruct cfg80211_nan_channel nan_channels[] __counted_by(n_channels);\n };\n \n+/**\n+ * struct cfg80211_nan_non_evac_channels - NAN non-evacuable channels\n+ *\n+ * This struct defines the set of NAN local schedule channels that must not\n+ * be evacuated for concurrent operations.\n+ *\n+ * @n_channels: number of channel definitions in %chandefs.\n+ * @chandefs: array of channel definitions that must not be evacuated. Each\n+ *\tmust match a channel of the current local schedule.\n+ */\n+struct cfg80211_nan_non_evac_channels {\n+\tu8 n_channels;\n+\tstruct cfg80211_chan_def chandefs[] __counted_by(n_channels);\n+};\n+\n /**\n * struct cfg80211_nan_peer_map - NAN peer schedule map\n *\n@@ -5206,6 +5221,12 @@ struct mgmt_frame_regs {\n *\tschedule, the full new schedule is provided - partial updates are not\n *\tsupported, and the new schedule completely replaces the previous one.\n *\n+ * @nan_set_non_evac_channels: set the list of local schedule channels that\n+ *\tmust not be evacuated for concurrent operations. The provided list\n+ *\treplaces the previous set; channels of the current schedule that are\n+ *\tnot included become evacuable again. All provided channels are\n+ *\tguaranteed by cfg80211 to belong to the current local schedule.\n+ *\n * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS\n *\n * @get_txq_stats: Get TXQ stats for interface or phy. If wdev is %NULL, this\n@@ -5592,6 +5613,9 @@ struct cfg80211_ops {\n \tint\t(*nan_set_peer_sched)(struct wiphy *wiphy,\n \t\t\t\t struct wireless_dev *wdev,\n \t\t\t\t struct cfg80211_nan_peer_sched *sched);\n+\tint\t(*nan_set_non_evac_channels)(struct wiphy *wiphy,\n+\t\t\t\t\t struct wireless_dev *wdev,\n+\t\t\t\t\t struct cfg80211_nan_non_evac_channels *channels);\n \tint\t(*set_multicast_to_unicast)(struct wiphy *wiphy,\n \t\t\t\t\t struct net_device *dev,\n \t\t\t\t\t const bool enabled);\ndiff --git a/include/net/mac80211.h b/include/net/mac80211.h\nindex 1172d7b83ed18..46ae2aa6e4e75 100644\n--- a/include/net/mac80211.h\n+++ b/include/net/mac80211.h\n@@ -923,12 +923,14 @@ struct ieee80211_bss_conf {\n * @channel_entry: the Channel Entry blob as defined in Wi-Fi Aware\n *\t(TM) 4.0 specification Table 100 (Channel Entry format for the NAN\n *\tAvailability attribute).\n+ * @no_evacuate: if set, this channel must not be evacuated\n */\n struct ieee80211_nan_channel {\n \tstruct ieee80211_chan_req chanreq;\n \tu8 needed_rx_chains;\n \tstruct ieee80211_chanctx_conf *chanctx_conf;\n \tu8 channel_entry[6];\n+\tbool no_evacuate;\n };\n \n /**\ndiff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h\nindex 9a2ccb8d66b86..ff7b5157e8cf8 100644\n--- a/include/uapi/linux/nl80211.h\n+++ b/include/uapi/linux/nl80211.h\n@@ -1383,6 +1383,13 @@\n *\tfrom the device to perform an announced schedule update. See\n *\t%NL80211_ATTR_NAN_SCHED_DEFERRED for more details.\n *\tIf not set, the schedule should be applied immediately.\n+ *\tSetting a new schedule is always allowed and is never treated as an\n+ *\tevacuation, even if it removes channels that were previously marked as\n+ *\tnon-evacuable with %NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS. The\n+ *\tnon-evacuable marking is a per-channel property of the schedule:\n+ *\tchannels that remain in the new schedule keep their marking, channels\n+ *\tthat are removed simply lose it, and newly added channels are\n+ *\tevacuable by default.\n * @NL80211_CMD_NAN_SCHED_UPDATE_DONE: Event sent to user space to notify that\n *\ta deferred local NAN schedule update (requested with\n *\t%NL80211_CMD_NAN_SET_LOCAL_SCHED and %NL80211_ATTR_NAN_SCHED_DEFERRED)\n@@ -1427,6 +1434,28 @@\n * @NL80211_CMD_STOP_PD: Stop the PD operation, identified by\n *\tits %NL80211_ATTR_WDEV interface.\n *\n+ * @NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS: Set the list of NAN local schedule\n+ *\tchannels that must not be evacuated. NAN must be operational\n+ *\t(%NL80211_CMD_START_NAN was executed) and a local schedule must have\n+ *\tbeen set (%NL80211_CMD_NAN_SET_LOCAL_SCHED). The command carries zero\n+ *\tor more nested %NL80211_ATTR_NAN_CHANNEL attributes, each identifying a\n+ *\tchannel (by its channel definition) of the current local schedule that\n+ *\tmust not be evacuated for concurrent operations. The provided list\n+ *\treplaces the previous set of non-evacuable channels; channels of the\n+ *\tcurrent schedule that are not included become evacuable again. All\n+ *\tprovided channels must exist in the current local schedule, otherwise\n+ *\tthe command fails. This is used to protect channels carrying NDC or\n+ *\timmutable schedules, whose evacuation would break existing NDP\n+ *\tconnections.\n+ *\tThe non-evacuable marking is a per-channel property of the current\n+ *\tlocal schedule and only affects evacuation for concurrent operations;\n+ *\tit does not prevent the schedule itself from being changed. Removing a\n+ *\tchannel from the schedule with %NL80211_CMD_NAN_SET_LOCAL_SCHED is a\n+ *\tuser-initiated change, not an evacuation, and is allowed even for a\n+ *\tnon-evacuable channel. Across a schedule update, channels that remain\n+ *\tkeep their non-evacuable marking, removed channels lose it, and newly\n+ *\tadded channels are evacuable by default; issue this command again to\n+ *\tchange the non-evacuable set.\n * @NL80211_CMD_MAX: highest used command number\n * @__NL80211_CMD_AFTER_LAST: internal use\n */\n@@ -1705,6 +1734,8 @@ enum nl80211_commands {\n \tNL80211_CMD_START_PD,\n \tNL80211_CMD_STOP_PD,\n \n+\tNL80211_CMD_NAN_SET_NON_EVAC_CHANNELS,\n+\n \t/* add new commands above here */\n \n \t/* used to define NL80211_CMD_MAX below */\ndiff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c\nindex 23f4f9ec86d0a..cdcf1f0577077 100644\n--- a/net/mac80211/cfg.c\n+++ b/net/mac80211/cfg.c\n@@ -5973,6 +5973,18 @@ ieee80211_set_peer_nan_sched(struct wiphy *wiphy,\n \treturn ieee80211_nan_set_peer_sched(sdata, sched);\n }\n \n+static int\n+ieee80211_set_nan_non_evac_channels(struct wiphy *wiphy,\n+\t\t\t\t struct wireless_dev *wdev,\n+\t\t\t\t struct cfg80211_nan_non_evac_channels *channels)\n+{\n+\tstruct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);\n+\n+\tlockdep_assert_wiphy(wiphy);\n+\n+\treturn ieee80211_nan_set_non_evac_channels(sdata, channels);\n+}\n+\n const struct cfg80211_ops mac80211_config_ops = {\n \t.add_virtual_intf = ieee80211_add_iface,\n \t.del_virtual_intf = ieee80211_del_iface,\n@@ -6091,4 +6103,5 @@ const struct cfg80211_ops mac80211_config_ops = {\n \t.set_epcs = ieee80211_set_epcs,\n \t.nan_set_local_sched = ieee80211_set_local_nan_sched,\n \t.nan_set_peer_sched = ieee80211_set_peer_nan_sched,\n+\t.nan_set_non_evac_channels = ieee80211_set_nan_non_evac_channels,\n };\ndiff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h\nindex 9514f01778beb..eaaffb80a422c 100644\n--- a/net/mac80211/ieee80211_i.h\n+++ b/net/mac80211/ieee80211_i.h\n@@ -2088,6 +2088,8 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,\n \t\t\t\t struct cfg80211_nan_local_sched *sched);\n int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata,\n \t\t\t\t struct cfg80211_nan_peer_sched *sched);\n+int ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata,\n+\t\t\t\t\tstruct cfg80211_nan_non_evac_channels *channels);\n void ieee80211_nan_free_peer_sched(struct ieee80211_nan_peer_sched *sched);\n void ieee80211_nan_update_ndi_carrier(struct ieee80211_sub_if_data *ndi_sdata);\n struct ieee80211_nan_channel *\ndiff --git a/net/mac80211/nan.c b/net/mac80211/nan.c\nindex 19e08661be43a..38bd105121acf 100644\n--- a/net/mac80211/nan.c\n+++ b/net/mac80211/nan.c\n@@ -248,6 +248,35 @@ ieee80211_nan_find_free_channel(struct ieee80211_nan_sched_cfg *sched_cfg)\n \treturn NULL;\n }\n \n+int\n+ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata,\n+\t\t\t\t struct cfg80211_nan_non_evac_channels *channels)\n+{\n+\tstruct ieee80211_nan_sched_cfg *sched_cfg = \u0026sdata-\u003evif.cfg.nan_sched;\n+\n+\t/*\n+\t * cfg80211 already validated that all provided channels belong to the\n+\t * current schedule, so just clear all non-evacuable flags and set the\n+\t * ones in the list.\n+\t */\n+\tfor (int j = 0; j \u003c ARRAY_SIZE(sched_cfg-\u003echannels); j++)\n+\t\tsched_cfg-\u003echannels[j].no_evacuate = false;\n+\n+\tfor (int i = 0; i \u003c channels-\u003en_channels; i++) {\n+\t\tfor (int j = 0; j \u003c ARRAY_SIZE(sched_cfg-\u003echannels); j++) {\n+\t\t\tif (!sched_cfg-\u003echannels[j].chanreq.oper.chan)\n+\t\t\t\tcontinue;\n+\t\t\tif (cfg80211_chandef_identical(\u0026sched_cfg-\u003echannels[j].chanreq.oper,\n+\t\t\t\t\t\t \u0026channels-\u003echandefs[i])) {\n+\t\t\t\tsched_cfg-\u003echannels[j].no_evacuate = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,\n \t\t\t\t struct cfg80211_nan_local_sched *sched)\n {\n@@ -786,6 +815,10 @@ ieee80211_nan_find_evac_chan(struct ieee80211_local *local,\n \n \t\tusable_channels++;\n \n+\t\t/* No-evacuate channel is usable but cannot be evacuated */\n+\t\tif (chan-\u003eno_evacuate)\n+\t\t\tcontinue;\n+\n \t\tchan_ctx = container_of(chan-\u003echanctx_conf,\n \t\t\t\t\tstruct ieee80211_chanctx, conf);\n \ndiff --git a/net/wireless/core.c b/net/wireless/core.c\nindex d13310fef691a..2f46243773f94 100644\n--- a/net/wireless/core.c\n+++ b/net/wireless/core.c\n@@ -325,6 +325,41 @@ int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,\n \treturn 0;\n }\n \n+int cfg80211_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,\n+\t\t\t\t struct wireless_dev *wdev,\n+\t\t\t\t struct cfg80211_nan_non_evac_channels *channels)\n+{\n+\tlockdep_assert_held(\u0026rdev-\u003ewiphy.mtx);\n+\n+\tif (wdev-\u003eiftype != NL80211_IFTYPE_NAN || !wdev_running(wdev))\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * Don't allow updating the non-evacuable channels while a deferred\n+\t * schedule update is pending, as the set of channels may still change.\n+\t */\n+\tif (wdev-\u003eu.nan.sched_update_pending)\n+\t\treturn -EBUSY;\n+\n+\t/* All provided channels must belong to the current local schedule. */\n+\tfor (int i = 0; i \u003c channels-\u003en_channels; i++) {\n+\t\tbool found = false;\n+\n+\t\tfor (int j = 0; j \u003c wdev-\u003eu.nan.n_channels; j++) {\n+\t\t\tif (cfg80211_chandef_identical(\u0026wdev-\u003eu.nan.chandefs[j],\n+\t\t\t\t\t\t \u0026channels-\u003echandefs[i])) {\n+\t\t\t\tfound = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (!found)\n+\t\t\treturn -ENOENT;\n+\t}\n+\n+\treturn rdev_nan_set_non_evac_channels(rdev, wdev, channels);\n+}\n+\n void cfg80211_stop_pd(struct cfg80211_registered_device *rdev,\n \t\t struct wireless_dev *wdev)\n {\ndiff --git a/net/wireless/core.h b/net/wireless/core.h\nindex b4610f6685dcb..4ee48b9370800 100644\n--- a/net/wireless/core.h\n+++ b/net/wireless/core.h\n@@ -565,6 +565,10 @@ int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,\n \t\t\t\t struct wireless_dev *wdev,\n \t\t\t\t struct cfg80211_nan_local_sched *sched);\n \n+int cfg80211_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,\n+\t\t\t\t struct wireless_dev *wdev,\n+\t\t\t\t struct cfg80211_nan_non_evac_channels *channels);\n+\n struct cfg80211_internal_bss *\n cfg80211_bss_update(struct cfg80211_registered_device *rdev,\n \t\t struct cfg80211_internal_bss *tmp,\ndiff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c\nindex ab5a14f5fe283..bb1abc9d18e27 100644\n--- a/net/wireless/nl80211.c\n+++ b/net/wireless/nl80211.c\n@@ -17767,6 +17767,69 @@ static int nl80211_nan_set_local_sched(struct sk_buff *skb,\n \treturn cfg80211_nan_set_local_schedule(rdev, wdev, sched);\n }\n \n+static int\n+nl80211_parse_non_evac_channel(struct cfg80211_registered_device *rdev,\n+\t\t\t struct nlattr *channel, struct genl_info *info,\n+\t\t\t struct cfg80211_chan_def *chandef)\n+{\n+\tstruct nlattr **channel_parsed __free(kfree) =\n+\t\tkcalloc(NL80211_ATTR_MAX + 1, sizeof(*channel_parsed),\n+\t\t\tGFP_KERNEL);\n+\tint ret;\n+\n+\tif (!channel_parsed)\n+\t\treturn -ENOMEM;\n+\n+\tret = nla_parse_nested(channel_parsed, NL80211_ATTR_MAX, channel, NULL,\n+\t\t\t info-\u003eextack);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn nl80211_parse_chandef(rdev, info-\u003eextack, channel_parsed,\n+\t\t\t\t chandef, false);\n+}\n+\n+static int nl80211_nan_set_non_evac_channels(struct sk_buff *skb,\n+\t\t\t\t\t struct genl_info *info)\n+{\n+\tstruct cfg80211_registered_device *rdev = info-\u003euser_ptr[0];\n+\tstruct wireless_dev *wdev = info-\u003euser_ptr[1];\n+\tint rem, i = 0, n_channels = 0;\n+\tstruct nlattr *channel;\n+\n+\tif (wdev-\u003eiftype != NL80211_IFTYPE_NAN)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tif (!wdev_running(wdev))\n+\t\treturn -ENOTCONN;\n+\n+\t/* Count how many channel attributes we got */\n+\tnlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL,\n+\t\t\t\t info-\u003enlhdr, GENL_HDRLEN, rem)\n+\t\tn_channels++;\n+\n+\tstruct cfg80211_nan_non_evac_channels *channels __free(kfree) =\n+\t\tkzalloc(struct_size(channels, chandefs, n_channels),\n+\t\t\tGFP_KERNEL);\n+\tif (!channels)\n+\t\treturn -ENOMEM;\n+\n+\tchannels-\u003en_channels = n_channels;\n+\n+\tnlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL,\n+\t\t\t\t info-\u003enlhdr, GENL_HDRLEN, rem) {\n+\t\tint ret;\n+\n+\t\tret = nl80211_parse_non_evac_channel(rdev, channel, info,\n+\t\t\t\t\t\t \u0026channels-\u003echandefs[i]);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t\ti++;\n+\t}\n+\n+\treturn cfg80211_nan_set_non_evac_channels(rdev, wdev, channels);\n+}\n+\n static int nl80211_get_protocol_features(struct sk_buff *skb,\n \t\t\t\t\t struct genl_info *info)\n {\n@@ -20629,6 +20692,12 @@ static const struct genl_small_ops nl80211_small_ops[] = {\n \t\t.flags = GENL_ADMIN_PERM,\n \t\t.internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP),\n \t},\n+\t{\n+\t\t.cmd = NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS,\n+\t\t.doit = nl80211_nan_set_non_evac_channels,\n+\t\t.flags = GENL_ADMIN_PERM,\n+\t\t.internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP),\n+\t},\n };\n \n static struct genl_family nl80211_fam __ro_after_init = {\ndiff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h\nindex 46849fe8d0b39..269258c94a42a 100644\n--- a/net/wireless/rdev-ops.h\n+++ b/net/wireless/rdev-ops.h\n@@ -1093,6 +1093,23 @@ rdev_nan_set_peer_sched(struct cfg80211_registered_device *rdev,\n \treturn ret;\n }\n \n+static inline int\n+rdev_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,\n+\t\t\t struct wireless_dev *wdev,\n+\t\t\t struct cfg80211_nan_non_evac_channels *channels)\n+{\n+\tint ret;\n+\n+\ttrace_rdev_nan_set_non_evac_channels(\u0026rdev-\u003ewiphy, wdev, channels);\n+\tif (rdev-\u003eops-\u003enan_set_non_evac_channels)\n+\t\tret = rdev-\u003eops-\u003enan_set_non_evac_channels(\u0026rdev-\u003ewiphy, wdev,\n+\t\t\t\t\t\t\t channels);\n+\telse\n+\t\tret = -EOPNOTSUPP;\n+\ttrace_rdev_return_int(\u0026rdev-\u003ewiphy, ret);\n+\treturn ret;\n+}\n+\n static inline int rdev_start_pd(struct cfg80211_registered_device *rdev,\n \t\t\t\tstruct wireless_dev *wdev)\n {\ndiff --git a/net/wireless/trace.h b/net/wireless/trace.h\nindex 8c2a91b85c396..435dc58cafbed 100644\n--- a/net/wireless/trace.h\n+++ b/net/wireless/trace.h\n@@ -2483,6 +2483,31 @@ TRACE_EVENT(rdev_nan_set_peer_sched,\n \t)\n );\n \n+TRACE_EVENT(rdev_nan_set_non_evac_channels,\n+\tTP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,\n+\t\t struct cfg80211_nan_non_evac_channels *channels),\n+\tTP_ARGS(wiphy, wdev, channels),\n+\tTP_STRUCT__entry(\n+\t\tWIPHY_ENTRY\n+\t\tWDEV_ENTRY\n+\t\t__field(u8, n_channels)\n+\t\t__dynamic_array(u32, freqs, channels-\u003en_channels)\n+\t),\n+\tTP_fast_assign(\n+\t\tu32 *freqs = __get_dynamic_array(freqs);\n+\n+\t\tWIPHY_ASSIGN;\n+\t\tWDEV_ASSIGN;\n+\t\t__entry-\u003en_channels = channels-\u003en_channels;\n+\t\tfor (int i = 0; i \u003c channels-\u003en_channels; i++)\n+\t\t\tfreqs[i] = channels-\u003echandefs[i].chan-\u003ecenter_freq;\n+\t),\n+\tTP_printk(WIPHY_PR_FMT \", \" WDEV_PR_FMT \", n_channels: %u, freqs: %s\",\n+\t\t WIPHY_PR_ARG, WDEV_PR_ARG, __entry-\u003en_channels,\n+\t\t __print_array(__get_dynamic_array(freqs),\n+\t\t\t\t__entry-\u003en_channels, sizeof(u32)))\n+);\n+\n TRACE_EVENT(rdev_set_mac_acl,\n \tTP_PROTO(struct wiphy *wiphy, struct net_device *netdev,\n \t\t struct cfg80211_acl_data *params),\n"
} |
| 2/1 | 2026/09/23 18:40 | agent | patch-evaluator |
2mModel:core Args: null Results: {
"EnableConfigs": [
"CFG80211",
"MAC80211",
"MAC80211_HWSIM"
],
"FocusSymbols": [
"nl80211_nan_set_non_evac_channels",
"nl80211_parse_non_evac_channel",
"cfg80211_nan_set_non_evac_channels",
"ieee80211_set_nan_non_evac_channels",
"ieee80211_nan_set_non_evac_channels",
"ieee80211_nan_find_evac_chan"
],
"Reasoning": "The patch adds a new userspace-facing nl80211 Generic Netlink command NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS to configure NAN local schedule channels that must not be evacuated for concurrent operations. The implementation includes nested attribute parsing in nl80211, validation and state checks in cfg80211, driver callback plumbing, and evacuation filtering in mac80211. This code is fully reachable in virtualized environments using mac80211_hwsim and netlink. Moreover, user-controlled channel counts parsed into a u8 variable with __counted_by annotations warrant fuzzing against truncation, bounds violations, and state consistency issues.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
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: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 2bd9eba0b7bea163a2099d7071fa60052175ccac
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Sep 23 18:40:41 2026 +0000
syz-cluster: applied patch under review
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9aa7d2d4a1841..43551dd4328ef 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4258,6 +4258,21 @@ struct cfg80211_nan_local_sched {
struct cfg80211_nan_channel nan_channels[] __counted_by(n_channels);
};
+/**
+ * struct cfg80211_nan_non_evac_channels - NAN non-evacuable channels
+ *
+ * This struct defines the set of NAN local schedule channels that must not
+ * be evacuated for concurrent operations.
+ *
+ * @n_channels: number of channel definitions in %chandefs.
+ * @chandefs: array of channel definitions that must not be evacuated. Each
+ * must match a channel of the current local schedule.
+ */
+struct cfg80211_nan_non_evac_channels {
+ u8 n_channels;
+ struct cfg80211_chan_def chandefs[] __counted_by(n_channels);
+};
+
/**
* struct cfg80211_nan_peer_map - NAN peer schedule map
*
@@ -5206,6 +5221,12 @@ struct mgmt_frame_regs {
* schedule, the full new schedule is provided - partial updates are not
* supported, and the new schedule completely replaces the previous one.
*
+ * @nan_set_non_evac_channels: set the list of local schedule channels that
+ * must not be evacuated for concurrent operations. The provided list
+ * replaces the previous set; channels of the current schedule that are
+ * not included become evacuable again. All provided channels are
+ * guaranteed by cfg80211 to belong to the current local schedule.
+ *
* @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
*
* @get_txq_stats: Get TXQ stats for interface or phy. If wdev is %NULL, this
@@ -5592,6 +5613,9 @@ struct cfg80211_ops {
int (*nan_set_peer_sched)(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct cfg80211_nan_peer_sched *sched);
+ int (*nan_set_non_evac_channels)(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels);
int (*set_multicast_to_unicast)(struct wiphy *wiphy,
struct net_device *dev,
const bool enabled);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1172d7b83ed18..46ae2aa6e4e75 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -923,12 +923,14 @@ struct ieee80211_bss_conf {
* @channel_entry: the Channel Entry blob as defined in Wi-Fi Aware
* (TM) 4.0 specification Table 100 (Channel Entry format for the NAN
* Availability attribute).
+ * @no_evacuate: if set, this channel must not be evacuated
*/
struct ieee80211_nan_channel {
struct ieee80211_chan_req chanreq;
u8 needed_rx_chains;
struct ieee80211_chanctx_conf *chanctx_conf;
u8 channel_entry[6];
+ bool no_evacuate;
};
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9a2ccb8d66b86..ff7b5157e8cf8 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1383,6 +1383,13 @@
* from the device to perform an announced schedule update. See
* %NL80211_ATTR_NAN_SCHED_DEFERRED for more details.
* If not set, the schedule should be applied immediately.
+ * Setting a new schedule is always allowed and is never treated as an
+ * evacuation, even if it removes channels that were previously marked as
+ * non-evacuable with %NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS. The
+ * non-evacuable marking is a per-channel property of the schedule:
+ * channels that remain in the new schedule keep their marking, channels
+ * that are removed simply lose it, and newly added channels are
+ * evacuable by default.
* @NL80211_CMD_NAN_SCHED_UPDATE_DONE: Event sent to user space to notify that
* a deferred local NAN schedule update (requested with
* %NL80211_CMD_NAN_SET_LOCAL_SCHED and %NL80211_ATTR_NAN_SCHED_DEFERRED)
@@ -1427,6 +1434,28 @@
* @NL80211_CMD_STOP_PD: Stop the PD operation, identified by
* its %NL80211_ATTR_WDEV interface.
*
+ * @NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS: Set the list of NAN local schedule
+ * channels that must not be evacuated. NAN must be operational
+ * (%NL80211_CMD_START_NAN was executed) and a local schedule must have
+ * been set (%NL80211_CMD_NAN_SET_LOCAL_SCHED). The command carries zero
+ * or more nested %NL80211_ATTR_NAN_CHANNEL attributes, each identifying a
+ * channel (by its channel definition) of the current local schedule that
+ * must not be evacuated for concurrent operations. The provided list
+ * replaces the previous set of non-evacuable channels; channels of the
+ * current schedule that are not included become evacuable again. All
+ * provided channels must exist in the current local schedule, otherwise
+ * the command fails. This is used to protect channels carrying NDC or
+ * immutable schedules, whose evacuation would break existing NDP
+ * connections.
+ * The non-evacuable marking is a per-channel property of the current
+ * local schedule and only affects evacuation for concurrent operations;
+ * it does not prevent the schedule itself from being changed. Removing a
+ * channel from the schedule with %NL80211_CMD_NAN_SET_LOCAL_SCHED is a
+ * user-initiated change, not an evacuation, and is allowed even for a
+ * non-evacuable channel. Across a schedule update, channels that remain
+ * keep their non-evacuable marking, removed channels lose it, and newly
+ * added channels are evacuable by default; issue this command again to
+ * change the non-evacuable set.
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1705,6 +1734,8 @@ enum nl80211_commands {
NL80211_CMD_START_PD,
NL80211_CMD_STOP_PD,
+ NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 23f4f9ec86d0a..cdcf1f0577077 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -5973,6 +5973,18 @@ ieee80211_set_peer_nan_sched(struct wiphy *wiphy,
return ieee80211_nan_set_peer_sched(sdata, sched);
}
+static int
+ieee80211_set_nan_non_evac_channels(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+ lockdep_assert_wiphy(wiphy);
+
+ return ieee80211_nan_set_non_evac_channels(sdata, channels);
+}
+
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -6091,4 +6103,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.set_epcs = ieee80211_set_epcs,
.nan_set_local_sched = ieee80211_set_local_nan_sched,
.nan_set_peer_sched = ieee80211_set_peer_nan_sched,
+ .nan_set_non_evac_channels = ieee80211_set_nan_non_evac_channels,
};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9514f01778beb..eaaffb80a422c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2088,6 +2088,8 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
struct cfg80211_nan_local_sched *sched);
int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata,
struct cfg80211_nan_peer_sched *sched);
+int ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_nan_non_evac_channels *channels);
void ieee80211_nan_free_peer_sched(struct ieee80211_nan_peer_sched *sched);
void ieee80211_nan_update_ndi_carrier(struct ieee80211_sub_if_data *ndi_sdata);
struct ieee80211_nan_channel *
diff --git a/net/mac80211/nan.c b/net/mac80211/nan.c
index 19e08661be43a..38bd105121acf 100644
--- a/net/mac80211/nan.c
+++ b/net/mac80211/nan.c
@@ -248,6 +248,35 @@ ieee80211_nan_find_free_channel(struct ieee80211_nan_sched_cfg *sched_cfg)
return NULL;
}
+int
+ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_nan_non_evac_channels *channels)
+{
+ struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
+
+ /*
+ * cfg80211 already validated that all provided channels belong to the
+ * current schedule, so just clear all non-evacuable flags and set the
+ * ones in the list.
+ */
+ for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++)
+ sched_cfg->channels[j].no_evacuate = false;
+
+ for (int i = 0; i < channels->n_channels; i++) {
+ for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++) {
+ if (!sched_cfg->channels[j].chanreq.oper.chan)
+ continue;
+ if (cfg80211_chandef_identical(&sched_cfg->channels[j].chanreq.oper,
+ &channels->chandefs[i])) {
+ sched_cfg->channels[j].no_evacuate = true;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
struct cfg80211_nan_local_sched *sched)
{
@@ -786,6 +815,10 @@ ieee80211_nan_find_evac_chan(struct ieee80211_local *local,
usable_channels++;
+ /* No-evacuate channel is usable but cannot be evacuated */
+ if (chan->no_evacuate)
+ continue;
+
chan_ctx = container_of(chan->chanctx_conf,
struct ieee80211_chanctx, conf);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d13310fef691a..2f46243773f94 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -325,6 +325,41 @@ int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,
return 0;
}
+int cfg80211_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels)
+{
+ lockdep_assert_held(&rdev->wiphy.mtx);
+
+ if (wdev->iftype != NL80211_IFTYPE_NAN || !wdev_running(wdev))
+ return -EINVAL;
+
+ /*
+ * Don't allow updating the non-evacuable channels while a deferred
+ * schedule update is pending, as the set of channels may still change.
+ */
+ if (wdev->u.nan.sched_update_pending)
+ return -EBUSY;
+
+ /* All provided channels must belong to the current local schedule. */
+ for (int i = 0; i < channels->n_channels; i++) {
+ bool found = false;
+
+ for (int j = 0; j < wdev->u.nan.n_channels; j++) {
+ if (cfg80211_chandef_identical(&wdev->u.nan.chandefs[j],
+ &channels->chandefs[i])) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return -ENOENT;
+ }
+
+ return rdev_nan_set_non_evac_channels(rdev, wdev, channels);
+}
+
void cfg80211_stop_pd(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b4610f6685dcb..4ee48b9370800 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -565,6 +565,10 @@ int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct cfg80211_nan_local_sched *sched);
+int cfg80211_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels);
+
struct cfg80211_internal_bss *
cfg80211_bss_update(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *tmp,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ab5a14f5fe283..bb1abc9d18e27 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -17767,6 +17767,69 @@ static int nl80211_nan_set_local_sched(struct sk_buff *skb,
return cfg80211_nan_set_local_schedule(rdev, wdev, sched);
}
+static int
+nl80211_parse_non_evac_channel(struct cfg80211_registered_device *rdev,
+ struct nlattr *channel, struct genl_info *info,
+ struct cfg80211_chan_def *chandef)
+{
+ struct nlattr **channel_parsed __free(kfree) =
+ kcalloc(NL80211_ATTR_MAX + 1, sizeof(*channel_parsed),
+ GFP_KERNEL);
+ int ret;
+
+ if (!channel_parsed)
+ return -ENOMEM;
+
+ ret = nla_parse_nested(channel_parsed, NL80211_ATTR_MAX, channel, NULL,
+ info->extack);
+ if (ret)
+ return ret;
+
+ return nl80211_parse_chandef(rdev, info->extack, channel_parsed,
+ chandef, false);
+}
+
+static int nl80211_nan_set_non_evac_channels(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+ int rem, i = 0, n_channels = 0;
+ struct nlattr *channel;
+
+ if (wdev->iftype != NL80211_IFTYPE_NAN)
+ return -EOPNOTSUPP;
+
+ if (!wdev_running(wdev))
+ return -ENOTCONN;
+
+ /* Count how many channel attributes we got */
+ nlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL,
+ info->nlhdr, GENL_HDRLEN, rem)
+ n_channels++;
+
+ struct cfg80211_nan_non_evac_channels *channels __free(kfree) =
+ kzalloc(struct_size(channels, chandefs, n_channels),
+ GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ channels->n_channels = n_channels;
+
+ nlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL,
+ info->nlhdr, GENL_HDRLEN, rem) {
+ int ret;
+
+ ret = nl80211_parse_non_evac_channel(rdev, channel, info,
+ &channels->chandefs[i]);
+ if (ret)
+ return ret;
+ i++;
+ }
+
+ return cfg80211_nan_set_non_evac_channels(rdev, wdev, channels);
+}
+
static int nl80211_get_protocol_features(struct sk_buff *skb,
struct genl_info *info)
{
@@ -20629,6 +20692,12 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.flags = GENL_ADMIN_PERM,
.internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP),
},
+ {
+ .cmd = NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS,
+ .doit = nl80211_nan_set_non_evac_channels,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP),
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 46849fe8d0b39..269258c94a42a 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1093,6 +1093,23 @@ rdev_nan_set_peer_sched(struct cfg80211_registered_device *rdev,
return ret;
}
+static inline int
+rdev_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels)
+{
+ int ret;
+
+ trace_rdev_nan_set_non_evac_channels(&rdev->wiphy, wdev, channels);
+ if (rdev->ops->nan_set_non_evac_channels)
+ ret = rdev->ops->nan_set_non_evac_channels(&rdev->wiphy, wdev,
+ channels);
+ else
+ ret = -EOPNOTSUPP;
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
static inline int rdev_start_pd(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 8c2a91b85c396..435dc58cafbed 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2483,6 +2483,31 @@ TRACE_EVENT(rdev_nan_set_peer_sched,
)
);
+TRACE_EVENT(rdev_nan_set_non_evac_channels,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels),
+ TP_ARGS(wiphy, wdev, channels),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ __field(u8, n_channels)
+ __dynamic_array(u32, freqs, channels->n_channels)
+ ),
+ TP_fast_assign(
+ u32 *freqs = __get_dynamic_array(freqs);
+
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ __entry->n_channels = channels->n_channels;
+ for (int i = 0; i < channels->n_channels; i++)
+ freqs[i] = channels->chandefs[i].chan->center_freq;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", n_channels: %u, freqs: %s",
+ WIPHY_PR_ARG, WDEV_PR_ARG, __entry->n_channels,
+ __print_array(__get_dynamic_array(freqs),
+ __entry->n_channels, sizeof(u32)))
+);
+
TRACE_EVENT(rdev_set_mac_acl,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_acl_data *params),
|
| 3/2 | 2026/09/23 18:40 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 9372 output: 29 thoughts: 512 Thoughts: **Analyzing the NAN Non-Evacuation Channel Patch** Okay, so this patch introduces `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS` into `nl80211` and requires handling within `cfg80211` and `mac80211`. My initial thought is to quickly understand the scope of the modifications. Let's see... the diff spans `include/net/cfg80211.h`, `include/net/mac80211.h`, `include/uapi/linux/nl80211.h`, `net/mac80211/cfg.c`, `net/mac80211/ieee80211_i.h`, `net/mac80211/nan.c`, `net/wireless/core.c`, `net/wireless/core.h`, `net/wireless/nl80211.c`, `net/wireless/rdev-ops.h`, and `net/wireless/trace.h`. Now, the real test. I need to understand the impact and reachability of this change, so I'm thinking about how to test it thoroughly. My first question is, can I reach this code through standard testing environments like QEMU or with syzkaller? It looks like syzkaller is a good bet for finding any subtle issues. Ah, yes! `mac80211_hwsim` is heavily fuzzed by syzkaller. Let me think... does `mac80211_hwsim` actually use `mac80211`'s operations? Yes, of course. `mac80211_hwsim` is a software driver based on `mac80211`, so it should be perfect. I'll need to double-check that `mac80211_config_ops` in `net/mac80211/cfg.c` is used. Yep, it is. `mac80211` registers to `cfg80211` through that. Okay, next question: does `mac80211` even *support* NAN? I'll need to confirm that. Time to use `grepper`. I'll look for uses of `nan_set_non_evac_channels`, `nan_set_local_sched`, and `mac80211_config_ops` within `mac80211` and `mac80211_hwsim`. Let's see what turns up. |
| 4/2 | 2026/09/23 18:40 | tool | grepper |
0mArgs:{
"Expression": "nan_set_local_sched",
"PathPrefix": "net/"
}Results: {
"Output": "net/mac80211/cfg.c=5953=ieee80211_set_local_nan_sched(struct wiphy *wiphy,\n--\nnet/mac80211/cfg.c-5960-\nnet/mac80211/cfg.c:5961:\treturn ieee80211_nan_set_local_sched(sdata, sched);\nnet/mac80211/cfg.c-5962-}\n--\nnet/mac80211/cfg.c=5988=const struct cfg80211_ops mac80211_config_ops = {\n--\nnet/mac80211/cfg.c-6103-\t.set_epcs = ieee80211_set_epcs,\nnet/mac80211/cfg.c:6104:\t.nan_set_local_sched = ieee80211_set_local_nan_sched,\nnet/mac80211/cfg.c-6105-\t.nan_set_peer_sched = ieee80211_set_peer_nan_sched,\n--\nnet/mac80211/chan.c=1050=ieee80211_new_chanctx(struct ieee80211_local *local,\n--\nnet/mac80211/chan.c-1071-\t * We ignored a driver error, see _ieee80211_set_active_links and/or\nnet/mac80211/chan.c:1072:\t * ieee80211_nan_set_local_sched\nnet/mac80211/chan.c-1073-\t */\n--\nnet/mac80211/ieee80211_i.h=2083=int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/ieee80211_i.h-2086-/* NAN code */\nnet/mac80211/ieee80211_i.h:2087:int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,\nnet/mac80211/ieee80211_i.h-2088-\t\t\t\t struct cfg80211_nan_local_sched *sched);\n--\nnet/mac80211/nan.c=252=ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/nan.c-279-\nnet/mac80211/nan.c:280:int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,\nnet/mac80211/nan.c-281-\t\t\t\t struct cfg80211_nan_local_sched *sched)\n--\nnet/wireless/core.c=255=void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/core.c-276-\t/* Unschedule all */\nnet/wireless/core.c:277:\tcfg80211_nan_set_local_schedule(rdev, wdev, \u0026empty_sched);\nnet/wireless/core.c-278-\n--\nnet/wireless/core.c-286-\nnet/wireless/core.c:287:int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,\nnet/wireless/core.c-288-\t\t\t\t struct wireless_dev *wdev,\n--\nnet/wireless/core.c-300-\nnet/wireless/core.c:301:\tret = rdev_nan_set_local_sched(rdev, wdev, sched);\nnet/wireless/core.c-302-\tif (ret)\n--\nnet/wireless/core.h=561=void cfg80211_stop_pd(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/core.h-563-\nnet/wireless/core.h:564:int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,\nnet/wireless/core.h-565-\t\t\t\t struct wireless_dev *wdev,\n--\nnet/wireless/nl80211.c=17676=static bool nl80211_nan_is_sched_empty(struct cfg80211_nan_local_sched *sched)\n--\nnet/wireless/nl80211.c-17688-\nnet/wireless/nl80211.c:17689:static int nl80211_nan_set_local_sched(struct sk_buff *skb,\nnet/wireless/nl80211.c-17690-\t\t\t\t struct genl_info *info)\n--\nnet/wireless/nl80211.c-17766-\nnet/wireless/nl80211.c:17767:\treturn cfg80211_nan_set_local_schedule(rdev, wdev, sched);\nnet/wireless/nl80211.c-17768-}\n--\nnet/wireless/nl80211.c=19819=static const struct genl_small_ops nl80211_small_ops[] = {\n--\nnet/wireless/nl80211.c-20684-\t\t.cmd = NL80211_CMD_NAN_SET_LOCAL_SCHED,\nnet/wireless/nl80211.c:20685:\t\t.doit = nl80211_nan_set_local_sched,\nnet/wireless/nl80211.c-20686-\t\t.flags = GENL_ADMIN_PERM,\n--\nnet/wireless/rdev-ops.h=1064=static inline int\nnet/wireless/rdev-ops.h:1065:rdev_nan_set_local_sched(struct cfg80211_registered_device *rdev,\nnet/wireless/rdev-ops.h-1066-\t\t\t struct wireless_dev *wdev,\n--\nnet/wireless/rdev-ops.h-1070-\nnet/wireless/rdev-ops.h:1071:\ttrace_rdev_nan_set_local_sched(\u0026rdev-\u003ewiphy, wdev, sched);\nnet/wireless/rdev-ops.h:1072:\tif (rdev-\u003eops-\u003enan_set_local_sched)\nnet/wireless/rdev-ops.h:1073:\t\tret = rdev-\u003eops-\u003enan_set_local_sched(\u0026rdev-\u003ewiphy, wdev, sched);\nnet/wireless/rdev-ops.h-1074-\telse\n--\nnet/wireless/trace.h=2419=TRACE_EVENT(rdev_del_nan_func,\n--\nnet/wireless/trace.h-2436-\nnet/wireless/trace.h:2437:TRACE_EVENT(rdev_nan_set_local_sched,\nnet/wireless/trace.h-2438-\tTP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,\n"
} |
| 5/2 | 2026/09/23 18:40 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 12465 output: 37 thoughts: 400 Thoughts: **My Analysis of NAN Non-Evacuation Channel Configuration** Okay, so I'm digging into how the non-evacuation channels are set up for NAN (Neighbor Awareness Networking) in this kernel code. It looks like the `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS` command is registered within `nl80211_small_ops`. When this netlink command is triggered—which uses the generic netlink family `nl80211`—the execution path is pretty clear. It's a chain: `nl80211_nan_set_non_evac_channels` calls `cfg80211_nan_set_non_evac_channels`, which in turn calls `rdev_nan_set_non_evac_channels`, which ultimately calls the `nan_set_non_evac_channels` function pointer within the `mac80211_config_ops` structure. This function pointer is assigned to `ieee80211_set_nan_non_evac_channels`, ultimately leading to `ieee80211_nan_set_non_evac_channels`. And as a side note, `ieee80211_nan_find_evac_chan` is now checking for `chan->no_evacuate`. Now, let's see, I need to check the netlink parsing and the associated handler functions to get a clearer picture of the data and any potential vulnerabilities. I should investigate `nl80211_parse_non_evac_channel` and `nl80211_nan_set_non_evac_channels` in `net/wireless/nl80211.c`. Wait... what permissions are required to call this command? Ah, the `.flags` field is set to `GENL_ADMIN_PERM`, meaning it requires `CAP_NET_ADMIN`. That could be interesting in fuzzing contexts... Hang on, syzkaller grants `CAP_NET_ADMIN` within unprivileged user namespaces. And I'm pretty sure syzkaller does a lot of fuzzing on nl80211 via netlink sockets, possibly using hwsim or other interfaces. This might be a relevant area to focus on. So, for my next step, I need to verify that `mac80211_hwsim` actually supports the NAN interface type (`NL80211_IFTYPE_NAN`). If it does, that provides a key piece of the puzzle. |
| 6/2 | 2026/09/23 18:40 | tool | grepper |
0mArgs:{
"Expression": "NL80211_IFTYPE_NAN",
"PathPrefix": "drivers/net/wireless/"
}Results: {
"Output": "drivers/net/wireless/intel/iwlwifi/mld/iface.c=20=void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-58-\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:59:\tif (vif-\u003etype == NL80211_IFTYPE_NAN) {\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-60-\t\tmld_vif-\u003enan.mac_added = false;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-72-\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:73:\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA \u0026\u0026\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-74-\t mld_vif-\u003enan.mcast_data_sta.sta_id != IWL_INVALID_STA)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c=103=static int iwl_mld_mac80211_iftype_to_fw(const struct ieee80211_vif *vif)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-115-\t\treturn FW_MAC_TYPE_IBSS;\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:116:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-117-\t\treturn FW_MAC_TYPE_NAN;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c=386=static int iwl_mld_fill_mac_cmd_nan(struct iwl_mld *mld,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-406-\tfor_each_active_interface(iter, mld-\u003ehw) {\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:407:\t\tif (iter-\u003etype != NL80211_IFTYPE_NAN_DATA)\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-408-\t\t\tcontinue;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c=435=__iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-443-\t/* NAN_DATA interface type is not known to FW */\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:444:\tif (WARN_ON(vif-\u003etype == NL80211_IFTYPE_NAN_DATA))\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-445-\t\treturn -EINVAL;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-448-\tif (WARN_ON(ndi_being_added \u0026\u0026\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:449:\t\t (vif-\u003etype != NL80211_IFTYPE_NAN || action != FW_CTXT_ACTION_MODIFY)))\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-450-\t\treturn -EINVAL;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-477-\t\tbreak;\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:478:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-479-\t\tret = iwl_mld_fill_mac_cmd_nan(mld, vif, ndi_being_added, \u0026cmd);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c=512=iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-534-\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:535:\tif (vif-\u003etype == NL80211_IFTYPE_NAN) {\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-536-\t\tfor (int i = 0; i \u003c ARRAY_SIZE(mld_vif-\u003enan.links); i++) {\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-542-\t\tiwl_mld_init_internal_sta(\u0026mld_vif-\u003enan.mgmt_sta);\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:543:\t} else if (vif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-544-\t\tiwl_mld_init_internal_sta(\u0026mld_vif-\u003enan.mcast_data_sta);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c=568=int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-577-\t/* NAN MACs are added to FW only when a schedule is set */\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:578:\tif (vif-\u003etype == NL80211_IFTYPE_NAN)\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-579-\t\treturn 0;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-581-\t/* NAN_DATA interface type is not known to FW, but we need to update NAN MAC */\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:582:\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA)\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-583-\t\treturn iwl_mld_update_nan_mac(mld, vif);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c=596=int iwl_mld_add_nan_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-602-\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:603:\tif (WARN_ON(vif-\u003etype != NL80211_IFTYPE_NAN))\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-604-\t\treturn -EINVAL;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c=621=void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-626-\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:627:\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-628-\t\tiwl_mld_update_nan_mac(mld, NULL);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-638-\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c:639:\tif (vif-\u003etype == NL80211_IFTYPE_NAN)\ndrivers/net/wireless/intel/iwlwifi/mld/iface.c-640-\t\tmld_vif-\u003enan.mac_added = false;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.h=226=static inline bool iwl_mld_vif_fw_id_valid(struct iwl_mld_vif *mld_vif)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/iface.h-230-\tswitch (vif-\u003etype) {\ndrivers/net/wireless/intel/iwlwifi/mld/iface.h:231:\tcase NL80211_IFTYPE_NAN_DATA:\ndrivers/net/wireless/intel/iwlwifi/mld/iface.h-232-\t\treturn false;\ndrivers/net/wireless/intel/iwlwifi/mld/iface.h:233:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/intel/iwlwifi/mld/iface.h-234-\t\tif (!mld_vif-\u003enan.mac_added)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/key.c=61=static u32 iwl_mld_get_key_sta_mask(struct iwl_mld *mld,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/key.c-71-\ndrivers/net/wireless/intel/iwlwifi/mld/key.c:72:\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA \u0026\u0026 !sta) {\ndrivers/net/wireless/intel/iwlwifi/mld/key.c-73-\t\t/* Older firmware versions do not support transmission of\n--\ndrivers/net/wireless/intel/iwlwifi/mld/key.c-85-\ndrivers/net/wireless/intel/iwlwifi/mld/key.c:86:\tif (vif-\u003etype == NL80211_IFTYPE_NAN \u0026\u0026 !sta) {\ndrivers/net/wireless/intel/iwlwifi/mld/key.c-87-\t\t/* Older firmware versions do not support installation of\n--\ndrivers/net/wireless/intel/iwlwifi/mld/key.c=214=iwl_mld_get_igtk_ptr(struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/key.c-239-\t\treturn \u0026mld_ap_link_sta-\u003erx_igtk;\ndrivers/net/wireless/intel/iwlwifi/mld/key.c:240:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/intel/iwlwifi/mld/key.c-241-\t\tif (sta) {\n--\ndrivers/net/wireless/intel/iwlwifi/mld/key.c=285=int iwl_mld_add_key(struct iwl_mld *mld,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/key.c-298-\t\t/* for NAN (GTK) indicate SW-only, it's not used at all */\ndrivers/net/wireless/intel/iwlwifi/mld/key.c:299:\t\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA \u0026\u0026 !sta \u0026\u0026\ndrivers/net/wireless/intel/iwlwifi/mld/key.c-300-\t\t !iwl_mld_nan_use_nan_stations(mld))\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c=63=static const struct ieee80211_iface_limit iwl_mld_limits_nan[] = {\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-69-\t\t.max = 1,\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:70:\t\t.types = BIT(NL80211_IFTYPE_NAN),\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-71-\t},\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-73-\t\t.max = 2,\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:74:\t\t.types = BIT(NL80211_IFTYPE_NAN_DATA),\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-75-\t},\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c=268=static void iwl_mld_hw_set_nan(struct iwl_mld *mld)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-271-\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:272:\thw-\u003ewiphy-\u003einterface_modes |= BIT(NL80211_IFTYPE_NAN);\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:273:\thw-\u003ewiphy-\u003einterface_modes |= BIT(NL80211_IFTYPE_NAN_DATA);\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-274-\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c=659=int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-671-\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:672:\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-673-\t\tif (WARN_ON(!mld-\u003enan_device_vif)) {\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-697-\t */\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:698:\tif (vif-\u003etype != NL80211_IFTYPE_NAN \u0026\u0026 !ieee80211_vif_is_mld(vif)) {\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-699-\t\tret = iwl_mld_add_link(mld, \u0026vif-\u003ebss_conf);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-729-\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:730:\tif (vif-\u003etype == NL80211_IFTYPE_NAN)\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-731-\t\tmld-\u003enan_device_vif = vif;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c=741=void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-759-\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:760:\tif (vif-\u003etype == NL80211_IFTYPE_NAN) {\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-761-\t\tmld-\u003enan_device_vif = NULL;\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:762:\t} else if (vif-\u003etype != NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-763-\t\tiwl_mld_remove_link(mld, \u0026vif-\u003ebss_conf);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c=1390=iwl_mld_mac80211_link_info_changed(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-1413-\t\tbreak;\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:1414:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:1415:\tcase NL80211_IFTYPE_NAN_DATA:\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-1416-\t\t/* NAN has no links */\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c=1434=void iwl_mld_mac80211_vif_cfg_changed(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-1442-\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:1443:\tif (vif-\u003etype == NL80211_IFTYPE_NAN) {\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-1444-\t\tiwl_mld_nan_vif_cfg_changed(mld, vif, changes);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c=1630=iwl_mld_mac80211_conf_tx(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-1640-\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c:1641:\tif (vif-\u003etype == NL80211_IFTYPE_NAN || vif-\u003etype == NL80211_IFTYPE_NAN_DATA)\ndrivers/net/wireless/intel/iwlwifi/mld/mac80211.c-1642-\t\treturn 0;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/nan.c=654=static void iwl_mld_nan_set_mcast_data_links(struct ieee80211_vif *vif)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/nan.c-657-\ndrivers/net/wireless/intel/iwlwifi/mld/nan.c:658:\tif (vif-\u003etype != NL80211_IFTYPE_NAN_DATA)\ndrivers/net/wireless/intel/iwlwifi/mld/nan.c-659-\t\treturn;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c=461=int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c-540-\t/* In NAN, there is no association request so no initial SMPS info */\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c:541:\tif (mld_sta-\u003evif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c-542-\t\tcmd.mimo = cpu_to_le32(1);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c=820=int iwl_mld_add_sta(struct iwl_mld *mld, struct ieee80211_sta *sta,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c-829-\tswitch (vif-\u003etype) {\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c:830:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c-831-\t\ttype = STATION_TYPE_NAN_PEER_NMI;\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c-832-\t\tbreak;\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c:833:\tcase NL80211_IFTYPE_NAN_DATA:\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c-834-\t\ttype = STATION_TYPE_NAN_PEER_NDI;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c=1281=void iwl_mld_remove_aux_sta(struct iwl_mld *mld,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c-1287-\t\t vif-\u003etype != NL80211_IFTYPE_STATION \u0026\u0026\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c:1288:\t\t vif-\u003etype != NL80211_IFTYPE_NAN))\ndrivers/net/wireless/intel/iwlwifi/mld/sta.c-1289-\t\treturn;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/stats.c=314=static void iwl_mld_sta_stats_fill_beacon_signal_avg(struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/stats.c-324-\t/* TODO: support statistics for NAN */\ndrivers/net/wireless/intel/iwlwifi/mld/stats.c:325:\tif (vif-\u003etype == NL80211_IFTYPE_NAN ||\ndrivers/net/wireless/intel/iwlwifi/mld/stats.c:326:\t vif-\u003etype == NL80211_IFTYPE_NAN_DATA)\ndrivers/net/wireless/intel/iwlwifi/mld/stats.c-327-\t\treturn;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tlc.c=721=void iwl_mld_config_tlc_link(struct iwl_mld *mld,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tlc.c-736-\ndrivers/net/wireless/intel/iwlwifi/mld/tlc.c:737:\tif (vif-\u003etype == NL80211_IFTYPE_NAN)\ndrivers/net/wireless/intel/iwlwifi/mld/tlc.c-738-\t\treturn;\ndrivers/net/wireless/intel/iwlwifi/mld/tlc.c-739-\ndrivers/net/wireless/intel/iwlwifi/mld/tlc.c:740:\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/intel/iwlwifi/mld/tlc.c-741-\t\tiwl_mld_config_tlc_nan(mld, vif, link_sta, fw_sta_id);\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c=70=static int iwl_mld_allocate_txq(struct iwl_mld *mld, struct ieee80211_txq *txq)\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-78-\tcase NL80211_IFTYPE_AP:\t\t/* STA might go to PS */\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c:79:\tcase NL80211_IFTYPE_NAN_DATA:\t/* peer might ULW/break schedule */\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-80-\t\twatchdog_timeout = IWL_WATCHDOG_DISABLED;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c=341=u8 iwl_mld_get_lowest_rate(struct iwl_mld *mld,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-353-\tif (band \u003e= NUM_NL80211_BANDS) {\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c:354:\t\tWARN_ON(vif-\u003etype != NL80211_IFTYPE_NAN \u0026\u0026\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c:355:\t\t\tvif-\u003etype != NL80211_IFTYPE_NAN_DATA);\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-356-\t\treturn IWL_FIRST_OFDM_RATE;\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c=540=iwl_mld_fill_tx_cmd(struct iwl_mld *mld, struct sk_buff *skb,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-566-\tif (unlikely(!sta ||\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c:567:\t\t (mld_sta \u0026\u0026 mld_sta-\u003evif-\u003etype == NL80211_IFTYPE_NAN) ||\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-568-\t\t info-\u003econtrol.flags \u0026 IEEE80211_TX_CTRL_RATE_INJECT)) {\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c=613=iwl_mld_get_tx_queue_id(struct iwl_mld *mld, struct ieee80211_txq *txq,\n--\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-683-\t\treturn mld_vif-\u003eaux_sta.queue_id;\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c:684:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-685-\t\tWARN_ON(!ieee80211_is_mgmt(fc));\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-686-\t\treturn iwl_mld_nan_get_mgmt_queue(mld, info-\u003econtrol.vif);\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c:687:\tcase NL80211_IFTYPE_NAN_DATA:\ndrivers/net/wireless/intel/iwlwifi/mld/tx.c-688-\t\tWARN_ON(!ieee80211_is_data(fc));\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=414=void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-467-\t\tbreak;\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:468:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:469:\tcase NL80211_IFTYPE_NAN_DATA:\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-470-\t\tbasic-\u003econn_type = cpu_to_le32(CONNECTION_NAN);\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=1194=int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1266-\t\tbreak;\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1267:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1268:\tcase NL80211_IFTYPE_NAN_DATA:\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1269-\t\tbasic_req.basic.conn_type = cpu_to_le32(CONNECTION_NAN);\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c=1612=int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,\n--\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1681-\t\tbreak;\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1682:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:1683:\tcase NL80211_IFTYPE_NAN_DATA:\ndrivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c-1684-\t\tbasic_req.basic.conn_type = cpu_to_le32(CONNECTION_NAN);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c=163=static int mt7925_init_nan_cap(struct mt76_dev *mdev)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-181-\tsband = wiphy-\u003ebands[NL80211_BAND_2GHZ];\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c:182:\the_cap = sband ? ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_NAN)\ndrivers/net/wireless/mediatek/mt76/mt7925/init.c-183-\t\t : NULL;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=455=mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-480-\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:481:\tif (vif-\u003etype == NL80211_IFTYPE_NAN)\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-482-\t\tdev-\u003enan_vif = vif;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=1241=int mt7925_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-1260-\tcase MT76_STA_EVENT_AUTHORIZE:\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:1261:\t\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-1262-\t\t\tint ret;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=1394=void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-1401-\t/* Release NAN peer record before tearing down the STA. */\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:1402:\tif (vif-\u003etype == NL80211_IFTYPE_NAN ||\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:1403:\t vif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-1404-\t\tint ret = mt792x_nan_set_peer_rec(mdev, sta);\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-1412-\t/* Release NDP context ID for NAN_DATA sta. */\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:1413:\tif (vif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-1414-\t\tstruct ieee80211_sta *nmi_sta;\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=2095=static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-2143-\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:2144:\tif (vif-\u003etype == NL80211_IFTYPE_NAN \u0026\u0026\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-2145-\t changed \u0026 BSS_CHANGED_NAN_LOCAL_SCHED) {\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=16=static bool mt7925_vif_is_nan(struct ieee80211_vif *vif)\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-17-{\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:18:\treturn vif-\u003etype == NL80211_IFTYPE_NAN ||\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:19:\t vif-\u003etype == NL80211_IFTYPE_NAN_DATA;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-20-}\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2694=mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2770-\t\tbreak;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2771:\tcase NL80211_IFTYPE_NAN:\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2772:\tcase NL80211_IFTYPE_NAN_DATA:\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2773-\t\tbasic_req-\u003econn_type = cpu_to_le32(CONNECTION_NAN);\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c=64=static const struct ieee80211_iface_limit if_limits_nan_mcc[] = {\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-70-\t\t.max = 1,\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c:71:\t\t.types = BIT(NL80211_IFTYPE_NAN),\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-72-\t},\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-74-\t\t.max = 2,\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c:75:\t\t.types = BIT(NL80211_IFTYPE_NAN_DATA),\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-76-\t},\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c=79=static const struct ieee80211_iface_limit if_limits_nan_scc[] = {\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-85-\t\t.max = 1,\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c:86:\t\t.types = BIT(NL80211_IFTYPE_NAN),\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-87-\t},\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-89-\t\t.max = 2,\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c:90:\t\t.types = BIT(NL80211_IFTYPE_NAN_DATA),\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-91-\t},\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c=750=int mt792x_init_wiphy(struct ieee80211_hw *hw)\n--\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-796-\t (dev-\u003efw_features \u0026 MT792x_FW_CAP_NAN)) {\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c:797:\t\twiphy-\u003einterface_modes |= BIT(NL80211_IFTYPE_NAN) |\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c:798:\t\t\t\t\t BIT(NL80211_IFTYPE_NAN_DATA);\ndrivers/net/wireless/mediatek/mt76/mt792x_core.c-799-\t\twiphy-\u003enan_supported_bands = BIT(NL80211_BAND_2GHZ) |\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c=1781=static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-1786-\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:1787:\tif (vif-\u003etype == NL80211_IFTYPE_NAN ||\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:1788:\t vif-\u003etype == NL80211_IFTYPE_NAN_DATA) {\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-1789-\t\tdata-\u003ereceive = mac80211_hwsim_nan_receive(data-\u003ehw,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c=2104=static void mac80211_hwsim_tx(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-2135-\tif (vif \u0026\u0026 !data-\u003etmp_chan \u0026\u0026\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:2136:\t (vif-\u003etype == NL80211_IFTYPE_NAN ||\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:2137:\t vif-\u003etype == NL80211_IFTYPE_NAN_DATA)) {\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-2138-\t\tstruct cfg80211_chan_def chandef;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c=2298=void ieee80211_hwsim_wake_tx_queue(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-2305-\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:2306:\tif ((txq-\u003evif-\u003etype == NL80211_IFTYPE_NAN ||\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:2307:\t txq-\u003evif-\u003etype == NL80211_IFTYPE_NAN_DATA) \u0026\u0026\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-2308-\t !mac80211_hwsim_nan_txq_transmitting(hw, txq))\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c=2796=mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-2805-\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:2806:\tif (vif-\u003etype == NL80211_IFTYPE_NAN ||\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:2807:\t vif-\u003etype == NL80211_IFTYPE_NAN_DATA)\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-2808-\t\treturn;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c=5675=static int mac80211_hwsim_new_radio(struct genl_info *info,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5794-\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5795:\tif (param-\u003eiftypes \u0026 BIT(NL80211_IFTYPE_NAN)) {\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5796-\t\tdata-\u003eif_limits[n_limits].max = 1;\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5797:\t\tdata-\u003eif_limits[n_limits].types = BIT(NL80211_IFTYPE_NAN);\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5798-\t\tn_limits++;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5827-\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5828:\tif (param-\u003eiftypes \u0026 BIT(NL80211_IFTYPE_NAN_DATA)) {\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5829-\t\tdata-\u003eif_limits[n_limits].max = 2;\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5830:\t\tdata-\u003eif_limits[n_limits].types = BIT(NL80211_IFTYPE_NAN_DATA);\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5831-\t\tn_limits++;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c=6258=static int mac80211_hwsim_get_radio(struct sk_buff *skb,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-6282-\tparam.nan_device = !!(data-\u003ehw-\u003ewiphy-\u003einterface_modes \u0026\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:6283:\t\t\t\t\tBIT(NL80211_IFTYPE_NAN));\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-6284-\tparam.use_chanctx = data-\u003euse_chanctx;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c=6855=static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-6943-\t\t}\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:6944:\t\tparam.iftypes |= BIT(NL80211_IFTYPE_NAN) |\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:6945:\t\t\t\t BIT(NL80211_IFTYPE_NAN_DATA);\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-6946-\t}\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c=909=int mac80211_hwsim_nan_start(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-914-\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:915:\tif (vif-\u003etype != NL80211_IFTYPE_NAN)\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-916-\t\treturn -EINVAL;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c=951=int mac80211_hwsim_nan_stop(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-955-\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:956:\tif (vif-\u003etype != NL80211_IFTYPE_NAN || !data-\u003enan.device_vif ||\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-957-\t data-\u003enan.device_vif != vif)\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c=968=int mac80211_hwsim_nan_change_config(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-974-\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:975:\tif (vif-\u003etype != NL80211_IFTYPE_NAN)\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-976-\t\treturn -EINVAL;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c=998=static void hwsim_nan_can_sta_transmit(void *_ctx, struct ieee80211_sta *sta)\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1010-\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:1011:\t\tif (txq-\u003evif-\u003etype != NL80211_IFTYPE_NAN \u0026\u0026\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:1012:\t\t txq-\u003evif-\u003etype != NL80211_IFTYPE_NAN_DATA)\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1013-\t\t\treturn;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c=1070=static void hwsim_nan_wake_sta_iter(void *_data, struct ieee80211_sta *sta)\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1080-\t\t/* exit early if non-NAN */\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:1081:\t\tif (txq-\u003evif-\u003etype != NL80211_IFTYPE_NAN \u0026\u0026\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:1082:\t\t txq-\u003evif-\u003etype != NL80211_IFTYPE_NAN_DATA)\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1083-\t\t\treturn;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c=1149=bool mac80211_hwsim_nan_txq_transmitting(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1172-\t\t/* Non-STA TXQ: allow management frames during DW */\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:1173:\t\tif (txq-\u003evif-\u003etype == NL80211_IFTYPE_NAN)\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1174-\t\t\treturn is_dw_slot;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1189-\tif (is_dw_slot) {\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:1190:\t\tif (txq-\u003evif-\u003etype == NL80211_IFTYPE_NAN_DATA)\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1191-\t\t\treturn false;\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c=1268=void mac80211_hwsim_nan_local_sched_changed(struct ieee80211_hw *hw,\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1273-\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c:1274:\tif (WARN_ON(vif-\u003etype != NL80211_IFTYPE_NAN))\ndrivers/net/wireless/virtual/mac80211_hwsim_nan.c-1275-\t\treturn;\n"
} |
| 7/2 | 2026/09/23 18:40 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 27111 output: 32 thoughts: 148 Thoughts: **NAN Support in mac80211_hwsim and Syzkaller Integration** Okay, so `mac80211_hwsim` has full NAN support, that's excellent. And syzkaller is already set up to work with `netlink nl80211`, which includes `mac80211_hwsim` – that's a huge advantage for testing. This patch introduces a new netlink command, `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS`. Now, let's dig into this. I need to understand this implementation thoroughly. My immediate focus is on a few key areas: 1. What specific configurations are *required* to enable this functionality? I'll need to check the Kconfig files for both CFG80211 and MAC80211 to see what dependencies exist and what options need to be set. 2. What are the *core* symbols and data structures involved in this `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS` command? I need to identify the key functions, structures, and variables that are central to the implementation. 3. Are there any potential areas of concern, subtle bugs, or nuanced details that might be overlooked at first glance? I'll be looking for any potential race conditions, boundary conditions, or assumptions that could lead to problems down the line. I'll need to think about error handling, security implications, and how this new command integrates with the existing NAN implementation. Time to dive deep. |
| 8/2 | 2026/09/23 18:40 | tool | grepper |
0mArgs:{
"Expression": "config CFG80211",
"PathPrefix": "net/wireless/"
}Results: {
"Output": "net/wireless/Kconfig=14=config WEXT_PRIV\n--\nnet/wireless/Kconfig-16-\nnet/wireless/Kconfig:17:config CFG80211\nnet/wireless/Kconfig-18-\ttristate \"cfg80211 - wireless configuration API\"\n--\nnet/wireless/Kconfig=38=config NL80211_TESTMODE\n--\nnet/wireless/Kconfig-51-\nnet/wireless/Kconfig:52:config CFG80211_DEVELOPER_WARNINGS\nnet/wireless/Kconfig-53-\tbool \"enable developer warnings\"\n--\nnet/wireless/Kconfig-67-\nnet/wireless/Kconfig:68:config CFG80211_CERTIFICATION_ONUS\nnet/wireless/Kconfig-69-\tbool \"cfg80211 certification onus\"\n--\nnet/wireless/Kconfig-88-\nnet/wireless/Kconfig:89:config CFG80211_REQUIRE_SIGNED_REGDB\nnet/wireless/Kconfig-90-\tbool \"require regdb signature\" if CFG80211_CERTIFICATION_ONUS\n--\nnet/wireless/Kconfig-98-\nnet/wireless/Kconfig:99:config CFG80211_USE_KERNEL_REGDB_KEYS\nnet/wireless/Kconfig-100-\tbool \"allow regdb keys shipped with the kernel\" if CFG80211_CERTIFICATION_ONUS\n--\nnet/wireless/Kconfig-110-\nnet/wireless/Kconfig:111:config CFG80211_EXTRA_REGDB_KEYDIR\nnet/wireless/Kconfig-112-\tstring \"additional regdb key directory\" if CFG80211_CERTIFICATION_ONUS\n--\nnet/wireless/Kconfig-121-\nnet/wireless/Kconfig:122:config CFG80211_REG_CELLULAR_HINTS\nnet/wireless/Kconfig-123-\tbool \"cfg80211 regulatory support for cellular base station hints\"\n--\nnet/wireless/Kconfig-134-\nnet/wireless/Kconfig:135:config CFG80211_REG_RELAX_NO_IR\nnet/wireless/Kconfig-136-\tbool \"cfg80211 support for NO_IR relaxation\"\n--\nnet/wireless/Kconfig-158-\nnet/wireless/Kconfig:159:config CFG80211_DEFAULT_PS\nnet/wireless/Kconfig-160-\tbool \"enable powersave by default\"\n--\nnet/wireless/Kconfig-168-\nnet/wireless/Kconfig:169:config CFG80211_DEBUGFS\nnet/wireless/Kconfig-170-\tbool \"cfg80211 DebugFS entries\"\n--\nnet/wireless/Kconfig-176-\nnet/wireless/Kconfig:177:config CFG80211_CRDA_SUPPORT\nnet/wireless/Kconfig-178-\tbool \"support CRDA\" if EXPERT\n--\nnet/wireless/Kconfig-186-\nnet/wireless/Kconfig:187:config CFG80211_WEXT\nnet/wireless/Kconfig-188-\tbool \"cfg80211 wireless extensions compatibility\"\n--\nnet/wireless/Kconfig-193-\nnet/wireless/Kconfig:194:config CFG80211_KUNIT_TEST\nnet/wireless/Kconfig-195-\ttristate \"KUnit tests for cfg80211\" if !KUNIT_ALL_TESTS\n"
} |
| 9/2 | 2026/09/23 18:40 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 28554 output: 36 thoughts: 17 Thoughts: Here's a summary of my thought process, as requested: **Diving into `net/mac80211/Kconfig`** Okay, time to get started. My first instinct is to dive into the `net/mac80211/Kconfig` file. Given my expertise, I know this is where the core configuration options related to the mac80211 subsystem are defined. I expect to find the settings that govern driver inclusion, feature enable/disable switches, and potentially some default values for parameters related to wireless networking. My hope is to quickly identify the relevant configuration option(s) that are causing me issues. From experience, this is usually the best first step in understanding and potentially troubleshooting the current setup. I'll need to remember to pay close attention to any dependencies and default values declared there. This gives me a high level starting point from which to work. |
| 10/2 | 2026/09/23 18:41 | tool | grepper |
0mArgs:{
"Expression": "config MAC80211",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/Kconfig-1-# SPDX-License-Identifier: GPL-2.0-only\nnet/mac80211/Kconfig:2:config MAC80211\nnet/mac80211/Kconfig-3-\ttristate \"Generic IEEE 802.11 Networking Stack (mac80211)\"\n--\nnet/mac80211/Kconfig=19=if MAC80211 != n\nnet/mac80211/Kconfig-20-\nnet/mac80211/Kconfig:21:config MAC80211_HAS_RC\nnet/mac80211/Kconfig-22-\tbool\nnet/mac80211/Kconfig-23-\nnet/mac80211/Kconfig:24:config MAC80211_RC_MINSTREL\nnet/mac80211/Kconfig-25-\tbool \"Minstrel\" if EXPERT\n--\nnet/mac80211/Kconfig=31=choice\n--\nnet/mac80211/Kconfig-40-\nnet/mac80211/Kconfig:41:config MAC80211_RC_DEFAULT_MINSTREL\nnet/mac80211/Kconfig-42-\tbool \"Minstrel\"\n--\nnet/mac80211/Kconfig=48=endchoice\nnet/mac80211/Kconfig-49-\nnet/mac80211/Kconfig:50:config MAC80211_RC_DEFAULT\nnet/mac80211/Kconfig-51-\tstring\n--\nnet/mac80211/Kconfig=57=comment \"Some wireless drivers require a rate control algorithm\"\n--\nnet/mac80211/Kconfig-59-\nnet/mac80211/Kconfig:60:config MAC80211_KUNIT_TEST\nnet/mac80211/Kconfig-61-\ttristate \"KUnit tests for mac80211\" if !KUNIT_ALL_TESTS\n--\nnet/mac80211/Kconfig-69-\nnet/mac80211/Kconfig:70:config MAC80211_MESH\nnet/mac80211/Kconfig-71-\tbool \"Enable mac80211 mesh networking support\"\n--\nnet/mac80211/Kconfig-78-\nnet/mac80211/Kconfig:79:config MAC80211_LEDS\nnet/mac80211/Kconfig-80-\tbool \"Enable LED triggers\"\n--\nnet/mac80211/Kconfig-87-\nnet/mac80211/Kconfig:88:config MAC80211_DEBUGFS\nnet/mac80211/Kconfig-89-\tbool \"Export mac80211 internals in DebugFS\"\n--\nnet/mac80211/Kconfig-96-\nnet/mac80211/Kconfig:97:config MAC80211_MESSAGE_TRACING\nnet/mac80211/Kconfig-98-\tbool \"Trace all mac80211 debug messages\"\n--\nnet/mac80211/Kconfig-109-\nnet/mac80211/Kconfig:110:menuconfig MAC80211_DEBUG_MENU\nnet/mac80211/Kconfig-111-\tbool \"Select mac80211 debugging features\"\n--\nnet/mac80211/Kconfig-115-\nnet/mac80211/Kconfig:116:config MAC80211_NOINLINE\nnet/mac80211/Kconfig-117-\tbool \"Do not inline TX/RX handlers\"\n--\nnet/mac80211/Kconfig-131-\nnet/mac80211/Kconfig:132:config MAC80211_VERBOSE_DEBUG\nnet/mac80211/Kconfig-133-\tbool \"Verbose debugging output\"\n--\nnet/mac80211/Kconfig-142-\nnet/mac80211/Kconfig:143:config MAC80211_MLME_DEBUG\nnet/mac80211/Kconfig-144-\tbool \"Verbose managed MLME output\"\n--\nnet/mac80211/Kconfig-153-\nnet/mac80211/Kconfig:154:config MAC80211_STA_DEBUG\nnet/mac80211/Kconfig-155-\tbool \"Verbose station debugging\"\n--\nnet/mac80211/Kconfig-162-\nnet/mac80211/Kconfig:163:config MAC80211_HT_DEBUG\nnet/mac80211/Kconfig-164-\tbool \"Verbose HT debugging\"\n--\nnet/mac80211/Kconfig-174-\nnet/mac80211/Kconfig:175:config MAC80211_OCB_DEBUG\nnet/mac80211/Kconfig-176-\tbool \"Verbose OCB debugging\"\n--\nnet/mac80211/Kconfig-185-\nnet/mac80211/Kconfig:186:config MAC80211_IBSS_DEBUG\nnet/mac80211/Kconfig-187-\tbool \"Verbose IBSS debugging\"\n--\nnet/mac80211/Kconfig-196-\nnet/mac80211/Kconfig:197:config MAC80211_PS_DEBUG\nnet/mac80211/Kconfig-198-\tbool \"Verbose powersave mode debugging\"\n--\nnet/mac80211/Kconfig-208-\nnet/mac80211/Kconfig:209:config MAC80211_MPL_DEBUG\nnet/mac80211/Kconfig-210-\tbool \"Verbose mesh peer link debugging\"\n--\nnet/mac80211/Kconfig-221-\nnet/mac80211/Kconfig:222:config MAC80211_MPATH_DEBUG\nnet/mac80211/Kconfig-223-\tbool \"Verbose mesh path debugging\"\n--\nnet/mac80211/Kconfig-234-\nnet/mac80211/Kconfig:235:config MAC80211_MHWMP_DEBUG\nnet/mac80211/Kconfig-236-\tbool \"Verbose mesh HWMP routing debugging\"\n--\nnet/mac80211/Kconfig-247-\nnet/mac80211/Kconfig:248:config MAC80211_MESH_SYNC_DEBUG\nnet/mac80211/Kconfig-249-\tbool \"Verbose mesh synchronization debugging\"\n--\nnet/mac80211/Kconfig-258-\nnet/mac80211/Kconfig:259:config MAC80211_MESH_CSA_DEBUG\nnet/mac80211/Kconfig-260-\tbool \"Verbose mesh channel switch debugging\"\n--\nnet/mac80211/Kconfig-269-\nnet/mac80211/Kconfig:270:config MAC80211_MESH_PS_DEBUG\nnet/mac80211/Kconfig-271-\tbool \"Verbose mesh powersave debugging\"\n--\nnet/mac80211/Kconfig-280-\nnet/mac80211/Kconfig:281:config MAC80211_TDLS_DEBUG\nnet/mac80211/Kconfig-282-\tbool \"Verbose TDLS debugging\"\n--\nnet/mac80211/Kconfig-292-\nnet/mac80211/Kconfig:293:config MAC80211_DEBUG_COUNTERS\nnet/mac80211/Kconfig-294-\tbool \"Extra statistics for TX/RX debugging\"\n--\nnet/mac80211/Kconfig-307-\nnet/mac80211/Kconfig:308:config MAC80211_STA_HASH_MAX_SIZE\nnet/mac80211/Kconfig-309-\tint \"Station hash table maximum size\" if MAC80211_DEBUG_MENU\n"
} |
| 11/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 30977 output: 25 thoughts: 27 Thoughts: Here's my take on the process, crafted as a first-person account suitable for a networking expert: **Diving into the Makefile Maze** Alright, time to get my hands dirty. I'm going to take a look at the build configuration. I suspect some dependencies or build flags are playing a role here. Let's start with a deep dive into the Makefiles. Specifically, I need to examine the `net/mac80211/Makefile` and the `net/wireless/Makefile` files. These are the usual suspects when dealing with wireless networking components within the kernel. It’s likely the configuration specific to mac80211 is where my problem lies, but I don't want to exclude `net/wireless` too quickly. I'll meticulously compare any relevant variables, includes, and conditional statements in those two files. I’m thinking there might be a flag defined there, or perhaps missing that impacts the inclusion, compilation, or linking of the relevant modules or features I'm working with. This will be the starting point to understand how they are being built and how they relate. |
| 12/2 | 2026/09/23 18:41 | tool | grepper |
0mArgs:{
"Expression": "nan\\.o",
"PathPrefix": "net/"
}Results: {
"Output": "net/mac80211/Makefile=5=mac80211-y := \\\n--\nnet/mac80211/Makefile-37-\tairtime.o \\\nnet/mac80211/Makefile:38:\teht.o uhr.o nan.o\nnet/mac80211/Makefile-39-\n"
} |
| 13/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 31364 output: 39 thoughts: 83 Thoughts: Okay, let's see, my thinking goes like this: **Investigating the Dependencies of `nan.o` within mac80211** Right, so `nan.o` is always built into mac80211 when `CONFIG_MAC80211` is set. That's straightforward enough. And, obviously, `cfg80211` is governed by its own config option, `CONFIG_CFG80211`. But what about `CONFIG_MAC80211_HWSIM`? Does the hardware simulation require any other dependencies that might influence how `nan.o` gets included? I need to quickly check if hwsim introduces any further conditions to the build process. Best to be sure. |
| 14/2 | 2026/09/23 18:41 | tool | grepper |
0mArgs:{
"Expression": "config MAC80211_HWSIM",
"PathPrefix": "drivers/net/wireless/virtual/"
}Results: {
"Output": "drivers/net/wireless/virtual/Kconfig:1:config MAC80211_HWSIM\ndrivers/net/wireless/virtual/Kconfig-2-\ttristate \"Simulated radio testing tool for mac80211\"\n"
} |
| 15/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 31719 output: 32 thoughts: 23 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Diving into the `CFG80211` Landscape** Right, let's start with a systematic approach. I need to get a clear picture of the current state of `CFG80211` within the kernel's network stack. To do that, the logical first step is to scrutinize its dependencies, which means I should be looking closely at `net/wireless/Kconfig`. This is the single source of truth, if you will. I need to quickly assess how it links with other wireless subsystems, and identify any external dependencies that should inform my understanding of the system, maybe there is something of note. From here I can start making my mental map of how it fits into the broader picture. |
| 16/2 | 2026/09/23 18:41 | tool | read-file |
0mArgs:{
"File": "net/wireless/Kconfig",
"FirstLine": 1,
"LineCount": 40
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\tconfig WIRELESS_EXT\n 3:\t\tbool\n 4:\t\n 5:\tconfig WEXT_CORE\n 6:\t\tdef_bool y\n 7:\t\tdepends on CFG80211_WEXT || WIRELESS_EXT\n 8:\t\n 9:\tconfig WEXT_PROC\n 10:\t\tdef_bool y\n 11:\t\tdepends on PROC_FS\n 12:\t\tdepends on WEXT_CORE\n 13:\t\n 14:\tconfig WEXT_PRIV\n 15:\t\tbool\n 16:\t\n 17:\tconfig CFG80211\n 18:\t\ttristate \"cfg80211 - wireless configuration API\"\n 19:\t\tdepends on RFKILL || !RFKILL\n 20:\t\tselect FW_LOADER\n 21:\t\tselect CRC32\n 22:\t\t# may need to update this when certificates are changed and are\n 23:\t\t# using a different algorithm, though right now they shouldn't\n 24:\t\t# (this is here rather than below to allow it to be a module)\n 25:\t\tselect CRYPTO_SHA256 if CFG80211_USE_KERNEL_REGDB_KEYS\n 26:\t\thelp\n 27:\t\t cfg80211 is the Linux wireless LAN (802.11) configuration API.\n 28:\t\t Enable this if you have a wireless device.\n 29:\t\n 30:\t\t For more information refer to documentation on the wireless wiki:\n 31:\t\n 32:\t\t https://wireless.wiki.kernel.org/en/developers/Documentation/cfg80211\n 33:\t\n 34:\t\t When built as a module it will be called cfg80211.\n 35:\t\n 36:\tif CFG80211\n 37:\t\n 38:\tconfig NL80211_TESTMODE\n 39:\t\tbool \"nl80211 testmode command\"\n 40:\t\thelp\n"
} |
| 17/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 32485 output: 37 thoughts: 18 Thoughts: Okay, let's dive into this. Here's my take on those thoughts, as if they're my own: **Analyzing the Kconfig in net/mac80211** Right, time to get to the heart of the matter. My mental gears are already whirring. Let's see what we're working with in `net/mac80211/Kconfig`. This is the configuration file, the blueprint, the very DNA of how this wireless subsystem is built and enabled within the kernel. I'm mentally parsing through the options, dependencies, and default settings. This Kconfig file will reveal the features, the build dependencies, and the knobs and dials that control the behavior of the entire mac80211 subsystem. Time to dig in and see what configuration options are available and what they control. |
| 18/2 | 2026/09/23 18:41 | tool | read-file |
0mArgs:{
"File": "net/mac80211/Kconfig",
"FirstLine": 1,
"LineCount": 30
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0-only\n 2:\tconfig MAC80211\n 3:\t\ttristate \"Generic IEEE 802.11 Networking Stack (mac80211)\"\n 4:\t\tdepends on CFG80211\n 5:\t\tselect CRYPTO\n 6:\t\tselect CRYPTO_LIB_AES_CBC_MACS\n 7:\t\tselect CRYPTO_LIB_ARC4\n 8:\t\tselect CRYPTO_AES\n 9:\t\tselect CRYPTO_CCM\n 10:\t\tselect CRYPTO_GCM\n 11:\t\tselect CRC32\n 12:\t\thelp\n 13:\t\t This option enables the hardware independent IEEE 802.11\n 14:\t\t networking stack.\n 15:\t\n 16:\tcomment \"CFG80211 needs to be enabled for MAC80211\"\n 17:\t\tdepends on CFG80211=n\n 18:\t\n 19:\tif MAC80211 != n\n 20:\t\n 21:\tconfig MAC80211_HAS_RC\n 22:\t\tbool\n 23:\t\n 24:\tconfig MAC80211_RC_MINSTREL\n 25:\t\tbool \"Minstrel\" if EXPERT\n 26:\t\tselect MAC80211_HAS_RC\n 27:\t\tdefault y\n 28:\t\thelp\n 29:\t\t This option enables the 'minstrel' TX rate control algorithm\n 30:\t\n"
} |
| 19/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 33121 output: 35 thoughts: 1917 Thoughts: **Vulnerability Analysis of `nl80211_nan_set_non_evac_channels`** Okay, let's dissect this code with a fine-tooth comb. I'm focusing on `nl80211_nan_set_non_evac_channels` and its interactions. My primary concern here is data integrity, potential overflows, and safety. I'm seeing a potential critical vulnerability related to how the number of channels is handled and a secondary potential for a NULL-pointer dereference. First, I observe that the number of channel attributes (`n_channels`) is counted using `nlmsg_for_each_attr_type` and is an `int`. This count then determines memory allocation for `channels->chandefs` using `kzalloc`. Critically, however, the count `n_channels` is then assigned to `channels->n_channels`, which is a *`u8`*. *Bingo*! This means any value of `n_channels` greater than 255 (U8_MAX) will be truncated, leading to an incorrect value stored in `channels->n_channels`. This sounds *very* problematic! If `n_channels` is 256 or more, the memory is allocated correctly, but `channels->n_channels` becomes 0 (or 1 in the case of 257). The problem is that the code *continues* to process the attributes in the netlink message, regardless of this truncation. Specifically, the second `nlmsg_for_each_attr_type` loop in `nl80211_nan_set_non_evac_channels` will iterate through all channel attributes, *writing beyond the bounds* of the allocated `channels->chandefs` if `n_channels > 255`, which might cause an out-of-bounds write. The code then passes the corrupted `channels` struct to `cfg80211_nan_set_non_evac_channels`. I then note that the code accesses `channels->chandefs[i]` without explicit bounds checking within the loop using the truncated `channels->n_channels` within the function `nl80211_parse_non_evac_channel`. The use of `__counted_by(n_channels)` in the `cfg80211_nan_non_evac_channels` structure definition *should* have been a safeguard, but in the first `nlmsg_for_each_attr_type` loop `n_channels` can be arbitrarily large, leading to out-of-bounds writes into the allocated buffer. In practice with Clang's `-fsanitize=bounds`, accessing `channels->chandefs[i]` when `channels->n_channels` is 0 will trigger an immediate bounds-sanitizer trap/kernel panic! Even without the UBSAN bounds, if `n_channels > 255`, elements will be left out of sync! I am starting to smell a classic buffer overflow. I need to confirm if Netlink messages can be crafted to include more than 255 channel attributes. A quick sanity check suggests this is definitely possible: a netlink message's size is not limited to that small number. It can easily accommodate hundreds, perhaps thousands, of these attributes. *There's no check* to ensure `n_channels` doesn't exceed `U8_MAX` (255) prior to the assignment to `channels->n_channels`. I predict this is a critical vulnerability. Finally, I also see that, inside `trace_rdev_nan_set_non_evac_channels`, the code accesses `channels->chandefs[i].chan->center_freq`. I need to ensure that `channels->chandefs[i].chan` can never be NULL. If it *can* be NULL, this will cause a null-pointer dereference. I need to review how the `chandef` struct is populated to verify this assumption. In summary, I believe I have identified a critical buffer overflow vulnerability and a potential NULL-pointer dereference with `nl80211_nan_set_non_evac_channels`. The overflow is caused by the integer truncation when the number of channels exceeds `U8_MAX`. I'll need to develop a proof-of-concept exploit that triggers this vulnerability and generates a kernel panic, or a controlled buffer overflow. The next step is a code review of the functions called within this code block. I suspect there may be more issues here. |
| 20/2 | 2026/09/23 18:41 | tool | grepper |
0mArgs:{
"Expression": "nl80211_parse_chandef",
"PathPrefix": "net/wireless/"
}Results: {
"Output": "net/wireless/nl80211.c=3904=static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)\n--\nnet/wireless/nl80211.c-3927-\nnet/wireless/nl80211.c:3928:static int _nl80211_parse_chandef(struct cfg80211_registered_device *rdev,\nnet/wireless/nl80211.c-3929-\t\t\t\t struct netlink_ext_ack *extack,\n--\nnet/wireless/nl80211.c-4096-\nnet/wireless/nl80211.c:4097:int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,\nnet/wireless/nl80211.c-4098-\t\t\t struct netlink_ext_ack *extack,\n--\nnet/wireless/nl80211.c-4102-{\nnet/wireless/nl80211.c:4103:\treturn _nl80211_parse_chandef(rdev, extack, attrs, false, chandef,\nnet/wireless/nl80211.c-4104-\t\t\t\t permit_npca);\n--\nnet/wireless/nl80211.c=4107=static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/nl80211.c-4135-\nnet/wireless/nl80211.c:4136:\tresult = _nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs,\nnet/wireless/nl80211.c-4137-\t\t\t\t\tiftype == NL80211_IFTYPE_MONITOR,\n--\nnet/wireless/nl80211.c=7211=static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-7348-\tif (info-\u003eattrs[NL80211_ATTR_WIPHY_FREQ]) {\nnet/wireless/nl80211.c:7349:\t\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs,\nnet/wireless/nl80211.c-7350-\t\t\t\t\t \u0026params-\u003echandef, true);\n--\nnet/wireless/nl80211.c=12045=static int nl80211_start_radar_detection(struct sk_buff *skb,\n--\nnet/wireless/nl80211.c-12076-\nnet/wireless/nl80211.c:12077:\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs, \u0026chandef,\nnet/wireless/nl80211.c-12078-\t\t\t\t false);\n--\nnet/wireless/nl80211.c=12149=static int nl80211_notify_radar_detection(struct sk_buff *skb,\n--\nnet/wireless/nl80211.c-12166-\nnet/wireless/nl80211.c:12167:\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs, \u0026chandef,\nnet/wireless/nl80211.c-12168-\t\t\t\t false);\n--\nnet/wireless/nl80211.c=12240=static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-12306-\nnet/wireless/nl80211.c:12307:\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs,\nnet/wireless/nl80211.c-12308-\t\t\t\t \u0026params.chandef, permit_npca);\n--\nnet/wireless/nl80211.c=13545=static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-13592-\nnet/wireless/nl80211.c:13593:\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs,\nnet/wireless/nl80211.c-13594-\t\t\t\t \u0026ibss.chandef, false);\n--\nnet/wireless/nl80211.c=14584=static int nl80211_remain_on_channel(struct sk_buff *skb,\n--\nnet/wireless/nl80211.c-14623-\nnet/wireless/nl80211.c:14624:\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs, \u0026chandef,\nnet/wireless/nl80211.c-14625-\t\t\t\t false);\n--\nnet/wireless/nl80211.c=14778=static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-14853-\tif (info-\u003eattrs[NL80211_ATTR_WIPHY_FREQ]) {\nnet/wireless/nl80211.c:14854:\t\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs,\nnet/wireless/nl80211.c-14855-\t\t\t\t\t \u0026chandef, false);\n--\nnet/wireless/nl80211.c=15259=static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-15265-\nnet/wireless/nl80211.c:15266:\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs,\nnet/wireless/nl80211.c-15267-\t\t\t\t \u0026setup.chandef, false);\n--\nnet/wireless/nl80211.c=15282=static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-15341-\tif (info-\u003eattrs[NL80211_ATTR_WIPHY_FREQ]) {\nnet/wireless/nl80211.c:15342:\t\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs,\nnet/wireless/nl80211.c-15343-\t\t\t\t\t \u0026setup.chandef, false);\n--\nnet/wireless/nl80211.c=17339=static int nl80211_parse_nan_channel(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/nl80211.c-17359-\nnet/wireless/nl80211.c:17360:\tret = nl80211_parse_chandef(rdev, info-\u003eextack, channel_parsed,\nnet/wireless/nl80211.c-17361-\t\t\t\t \u0026chandef, false);\n--\nnet/wireless/nl80211.c=17771=nl80211_parse_non_evac_channel(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/nl80211.c-17787-\nnet/wireless/nl80211.c:17788:\treturn nl80211_parse_chandef(rdev, info-\u003eextack, channel_parsed,\nnet/wireless/nl80211.c-17789-\t\t\t\t chandef, false);\n--\nnet/wireless/nl80211.c=18405=static int nl80211_tdls_channel_switch(struct sk_buff *skb,\n--\nnet/wireless/nl80211.c-18431-\nnet/wireless/nl80211.c:18432:\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs, \u0026chandef,\nnet/wireless/nl80211.c-18433-\t\t\t\t false);\n--\nnet/wireless/nl80211.h=19=static inline u64 wdev_id(struct wireless_dev *wdev)\n--\nnet/wireless/nl80211.h-24-\nnet/wireless/nl80211.h:25:int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,\nnet/wireless/nl80211.h-26-\t\t\t struct netlink_ext_ack *extack,\n--\nnet/wireless/pmsr.c=309=static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/pmsr.c-354-\nnet/wireless/pmsr.c:355:\terr = nl80211_parse_chandef(rdev, info-\u003eextack, info-\u003eattrs,\nnet/wireless/pmsr.c-356-\t\t\t\t \u0026out-\u003echandef, false);\n"
} |
| 21/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 38653 output: 36 thoughts: 46 Thoughts: Here's a summary of my thought process: **Diving into NAN Channel Scheduling** Okay, I need to understand how the `nl80211_nan_set_local_sched` function deals with channel counts within the context of NAN (Neighbor Awareness Networking) channel parsing. My immediate focus is on the `nl80211_parse_nan_channel` function and how it feeds into the scheduling mechanism. Specifically, I need to see exactly how `n_channels` is handled and if there are any potential edge cases or subtleties in how it's interpreted and used by `nl80211_nan_set_local_sched`. Time to dig in and verify my understanding. Let's start with `nl80211_parse_nan_channel` and go from there. |
| 22/2 | 2026/09/23 18:41 | tool | grepper |
0mArgs:{
"Expression": "nl80211_parse_nan_channel",
"PathPrefix": "net/wireless/"
}Results: {
"Output": "net/wireless/nl80211.c=17337=EXPORT_SYMBOL(cfg80211_nan_sched_update_done);\nnet/wireless/nl80211.c-17338-\nnet/wireless/nl80211.c:17339:static int nl80211_parse_nan_channel(struct cfg80211_registered_device *rdev,\nnet/wireless/nl80211.c-17340-\t\t\t\t struct nlattr *channel,\n--\nnet/wireless/nl80211.c=17527=static int nl80211_nan_set_peer_sched(struct sk_buff *skb,\n--\nnet/wireless/nl80211.c-17584-\nnet/wireless/nl80211.c:17585:\t\tret = nl80211_parse_nan_channel(rdev, channel, info,\nnet/wireless/nl80211.c-17586-\t\t\t\t\t\tnan_channels, i, false);\n--\nnet/wireless/nl80211.c=17689=static int nl80211_nan_set_local_sched(struct sk_buff *skb,\n--\nnet/wireless/nl80211.c-17721-\t\t\t\t info-\u003enlhdr, GENL_HDRLEN, rem) {\nnet/wireless/nl80211.c:17722:\t\tret = nl80211_parse_nan_channel(rdev, channel, info,\nnet/wireless/nl80211.c-17723-\t\t\t\t\t\tsched-\u003enan_channels, i, true);\n"
} |
| 23/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 39359 output: 42 thoughts: 44 Thoughts: Okay, let's dive into this. **Examining the Implementation of `nl80211_nan_set_local_sched`** Right, so I need to get a clear picture of how this `nl80211_nan_set_local_sched` function is actually working. The obvious starting point is the source code itself, specifically the `net/wireless/nl80211.c` file. I'll need to go and read through that section to see exactly how this NAN local scheduling is handled from the kernel's perspective. It's the most efficient way to understand the specifics of its implementation. Let's see what we can find. |
| 24/2 | 2026/09/23 18:41 | tool | read-file |
0mArgs:{
"File": "net/wireless/nl80211.c",
"FirstLine": 17688,
"LineCount": 55
}Results: {
"Contents": "17688:\t\n17689:\tstatic int nl80211_nan_set_local_sched(struct sk_buff *skb,\n17690:\t\t\t\t\t struct genl_info *info)\n17691:\t{\n17692:\t\tstruct cfg80211_registered_device *rdev = info-\u003euser_ptr[0];\n17693:\t\tstruct cfg80211_nan_local_sched *sched __free(kfree) = NULL;\n17694:\t\tstruct wireless_dev *wdev = info-\u003euser_ptr[1];\n17695:\t\tint rem, i = 0, n_channels = 0, ret;\n17696:\t\tstruct nlattr *channel;\n17697:\t\tbool sched_empty;\n17698:\t\n17699:\t\tif (wdev-\u003eiftype != NL80211_IFTYPE_NAN)\n17700:\t\t\treturn -EOPNOTSUPP;\n17701:\t\n17702:\t\tif (!wdev_running(wdev))\n17703:\t\t\treturn -ENOTCONN;\n17704:\t\n17705:\t\tif (!info-\u003eattrs[NL80211_ATTR_NAN_TIME_SLOTS])\n17706:\t\t\treturn -EINVAL;\n17707:\t\n17708:\t\t/* First count how many channel attributes we got */\n17709:\t\tnlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL,\n17710:\t\t\t\t\t info-\u003enlhdr, GENL_HDRLEN, rem)\n17711:\t\t\tn_channels++;\n17712:\t\n17713:\t\tsched = kzalloc(struct_size(sched, nan_channels, n_channels),\n17714:\t\t\t\tGFP_KERNEL);\n17715:\t\tif (!sched)\n17716:\t\t\treturn -ENOMEM;\n17717:\t\n17718:\t\tsched-\u003en_channels = n_channels;\n17719:\t\n17720:\t\tnlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL,\n17721:\t\t\t\t\t info-\u003enlhdr, GENL_HDRLEN, rem) {\n17722:\t\t\tret = nl80211_parse_nan_channel(rdev, channel, info,\n17723:\t\t\t\t\t\t\tsched-\u003enan_channels, i, true);\n17724:\t\n17725:\t\t\tif (ret)\n17726:\t\t\t\treturn ret;\n17727:\t\t\ti++;\n17728:\t\t}\n17729:\t\n17730:\t\t/* Parse and validate schedule */\n17731:\t\tret = nl80211_parse_nan_schedule(info,\n17732:\t\t\t\t\t\t info-\u003eattrs[NL80211_ATTR_NAN_TIME_SLOTS],\n17733:\t\t\t\t\t\t sched-\u003eschedule, sched-\u003en_channels);\n17734:\t\tif (ret)\n17735:\t\t\treturn ret;\n17736:\t\n17737:\t\tsched_empty = nl80211_nan_is_sched_empty(sched);\n17738:\t\n17739:\t\tsched-\u003edeferred =\n17740:\t\t\tnla_get_flag(info-\u003eattrs[NL80211_ATTR_NAN_SCHED_DEFERRED]);\n17741:\t\n17742:\t\tif (sched_empty) {\n"
} |
| 25/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 40542 output: 35 thoughts: 44 Thoughts: Here's my summary, as the expert: **Investigating the cfg80211_nan_local_sched Structure** Okay, let's dive into this `struct cfg80211_nan_local_sched`. I'm immediately curious about what `n_channels` actually represents in this context. It's not immediately obvious from the name. Time to go digging through the headers. I'll need to consult `include/net/cfg80211.h` to see how this is defined and get the full context around this `n_channels` field. Hopefully, the comments within the header are clear enough to shed some light on its meaning and purpose within the NAN (Neighbor Awareness Networking) scheduling framework. Let's see if we can get a clearer understanding of how this impacts overall operation. |
| 26/2 | 2026/09/23 18:41 | tool | grepper |
0mArgs:{
"Expression": "struct cfg80211_nan_local_sched",
"PathPrefix": "include/"
}Results: {
"Output": "include/net/cfg80211.h=4226=struct cfg80211_nan_channel {\n--\ninclude/net/cfg80211.h-4232-/**\ninclude/net/cfg80211.h:4233: * struct cfg80211_nan_local_sched - NAN local schedule\ninclude/net/cfg80211.h-4234- *\n--\ninclude/net/cfg80211.h-4251- */\ninclude/net/cfg80211.h:4252:struct cfg80211_nan_local_sched {\ninclude/net/cfg80211.h-4253-\tu8 schedule[CFG80211_NAN_SCHED_NUM_TIME_SLOTS];\n--\ninclude/net/cfg80211.h=5303=struct cfg80211_ops {\n--\ninclude/net/cfg80211.h-5611-\t\t\t\t struct wireless_dev *wdev,\ninclude/net/cfg80211.h:5612:\t\t\t\t struct cfg80211_nan_local_sched *sched);\ninclude/net/cfg80211.h-5613-\tint\t(*nan_set_peer_sched)(struct wiphy *wiphy,\n"
} |
| 27/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 41157 output: 41 thoughts: 22 Thoughts: Here's my understanding of the thought process, summarized as you requested: **Deconstructing `struct cfg80211_nan_local_sched`** Okay, so I'm looking at `struct cfg80211_nan_local_sched`. This is likely something related to WiFi, specifically the NAN (Neighbor Awareness Networking) standard, within the cfg80211 framework. Given my expertise, I immediately expect this struct to deal with local scheduling aspects. It will probably contain information related to how the local device manages and schedules NAN operations, perhaps managing resources, timing, or contention within the NAN context. I'll need to dig into the definition to see the specific fields. I'm keen to understand how this structure interacts with the broader cfg80211 API and how it's employed in practice within the driver architecture. My initial assumptions point towards resource management, possibly power control, and maybe some kind of prioritization scheme for NAN communications on this particular local device. I'll be looking for things like timers, queues, state flags related to the scheduling process for different NAN services. The details will, of course, clarify what's really happening. |
| 28/2 | 2026/09/23 18:41 | tool | read-file |
0mArgs:{
"File": "include/net/cfg80211.h",
"FirstLine": 4250,
"LineCount": 20
}Results: {
"Contents": "4250:\t * @nan_channels: array of NAN channel definitions that can be scheduled.\n4251:\t */\n4252:\tstruct cfg80211_nan_local_sched {\n4253:\t\tu8 schedule[CFG80211_NAN_SCHED_NUM_TIME_SLOTS];\n4254:\t\tu8 n_channels;\n4255:\t\tconst u8 *nan_avail_blob;\n4256:\t\tu16 nan_avail_blob_len;\n4257:\t\tbool deferred;\n4258:\t\tstruct cfg80211_nan_channel nan_channels[] __counted_by(n_channels);\n4259:\t};\n4260:\t\n4261:\t/**\n4262:\t * struct cfg80211_nan_non_evac_channels - NAN non-evacuable channels\n4263:\t *\n4264:\t * This struct defines the set of NAN local schedule channels that must not\n4265:\t * be evacuated for concurrent operations.\n4266:\t *\n4267:\t * @n_channels: number of channel definitions in %chandefs.\n4268:\t * @chandefs: array of channel definitions that must not be evacuated. Each\n4269:\t *\tmust match a channel of the current local schedule.\n"
} |
| 29/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 41825 output: 41 thoughts: 922 Thoughts: **Analyzing Non-Evacuable NAN Channel Configuration** Okay, so I'm looking into how non-evacuable channels are handled in the cfg80211 NAN code, specifically in the context of setting these channels. Let's start with the obvious, `struct cfg80211_nan_non_evac_channels`. It's pretty straightforward: we have a count, `n_channels`, and then an array of channel definitions, `chandefs`, sized by that count. Now, I'm checking the `cfg80211_nan_set_non_evac_channels` function in `net/wireless/core.c`. I see the checks for interface type (must be NAN) and that the wireless device is running. It also guards against setting these channels if a deferred schedule update is pending – makes sense, as the channel set could be in flux. The core of it is the loop that iterates through the provided channels and makes sure they actually exist in the current local schedule. If any of them aren't, it returns `-ENOENT`. Then we call `rdev_nan_set_non_evac_channels`. I'm now checking the tracepoint `trace_rdev_nan_set_non_evac_channels` because I want to understand what data is logged. Okay, I see that this tracepoint logs the wiphy, wdev, number of channels and the frequencies. The frequencies are derived from the `chandefs` using `channels->chandefs[i].chan->center_freq`. So, this gives me a good insight into the debug data that's being captured. A thought just crossed my mind: the code accesses `channels->chandefs[i].chan`. Could `channels->chandefs[i].chan` *ever* be a NULL pointer here? I'm not immediately seeing a check. I need to check the channel definition parsing. Let's see... the `nl80211_parse_non_evac_channel` function calls `nl80211_parse_chandef(...)`. I should examine what `_nl80211_parse_chandef` does, as this is where the channel definition is ultimately populated, to ensure that the pointer isn't inadvertently null. I'll need to double-check that this function is correctly validating and setting the channel definition. |
| 30/2 | 2026/09/23 18:41 | tool | read-file |
0mArgs:{
"File": "net/wireless/nl80211.c",
"FirstLine": 3928,
"LineCount": 50
}Results: {
"Contents": "3928:\tstatic int _nl80211_parse_chandef(struct cfg80211_registered_device *rdev,\n3929:\t\t\t\t\t struct netlink_ext_ack *extack,\n3930:\t\t\t\t\t struct nlattr **attrs, bool monitor,\n3931:\t\t\t\t\t struct cfg80211_chan_def *chandef,\n3932:\t\t\t\t\t bool permit_npca)\n3933:\t{\n3934:\t\tu32 control_freq;\n3935:\t\n3936:\t\tif (!attrs[NL80211_ATTR_WIPHY_FREQ]) {\n3937:\t\t\tNL_SET_ERR_MSG_ATTR(extack, attrs[NL80211_ATTR_WIPHY_FREQ],\n3938:\t\t\t\t\t \"Frequency is missing\");\n3939:\t\t\treturn -EINVAL;\n3940:\t\t}\n3941:\t\n3942:\t\tcontrol_freq = MHZ_TO_KHZ(\n3943:\t\t\t\tnla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ]));\n3944:\t\tif (attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])\n3945:\t\t\tcontrol_freq +=\n3946:\t\t\t nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);\n3947:\t\n3948:\t\tmemset(chandef, 0, sizeof(*chandef));\n3949:\t\tchandef-\u003echan = ieee80211_get_channel_khz(\u0026rdev-\u003ewiphy, control_freq);\n3950:\t\tchandef-\u003ewidth = NL80211_CHAN_WIDTH_20_NOHT;\n3951:\t\tchandef-\u003ecenter_freq1 = KHZ_TO_MHZ(control_freq);\n3952:\t\tchandef-\u003efreq1_offset = control_freq % 1000;\n3953:\t\tchandef-\u003ecenter_freq2 = 0;\n3954:\t\tchandef-\u003es1g_primary_2mhz = false;\n3955:\t\n3956:\t\tif (!chandef-\u003echan) {\n3957:\t\t\tNL_SET_ERR_MSG_ATTR(extack, attrs[NL80211_ATTR_WIPHY_FREQ],\n3958:\t\t\t\t\t \"Unknown channel\");\n3959:\t\t\treturn -EINVAL;\n3960:\t\t}\n3961:\t\n3962:\t\tif (cfg80211_chandef_is_s1g(chandef))\n3963:\t\t\tchandef-\u003ewidth = NL80211_CHAN_WIDTH_1;\n3964:\t\n3965:\t\tif (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {\n3966:\t\t\tenum nl80211_channel_type chantype;\n3967:\t\n3968:\t\t\tchantype = nla_get_u32(attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);\n3969:\t\n3970:\t\t\tswitch (chantype) {\n3971:\t\t\tcase NL80211_CHAN_NO_HT:\n3972:\t\t\tcase NL80211_CHAN_HT20:\n3973:\t\t\tcase NL80211_CHAN_HT40PLUS:\n3974:\t\t\tcase NL80211_CHAN_HT40MINUS:\n3975:\t\t\t\tif (chandef-\u003echan-\u003eband == NL80211_BAND_60GHZ ||\n3976:\t\t\t\t chandef-\u003echan-\u003eband == NL80211_BAND_S1GHZ)\n3977:\t\t\t\t\treturn -EINVAL;\n"
} |
| 31/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 44312 output: 40 thoughts: 491 Thoughts: **Analyzing Channel Evacuation in the NAN Schedule** Okay, so I'm diving into this `ieee80211_nan_set_non_evac_channels` function. The key assumption here is that `chandef->chan` is guaranteed to be non-NULL when `nl80211_parse_chandef` returns 0. That’s fundamental to how this works, so I'll keep that in mind. Now, looking at the code, it seems like we're dealing with a schedule of channels, and the goal is to mark specific channels as "non-evacuable." The comment confirms that `cfg80211` has already done the heavy lifting of validating that these channels are actually part of the current schedule – so we don't need to re-verify the channel set. The first loop in `ieee80211_nan_set_non_evac_channels` clears the `no_evacuate` flag for all channels in `sched_cfg->channels`. Then, a nested loop iterates through the provided non-evacuable channel definitions and checks if each channel matches a channel in the schedule. If it does, the `no_evacuate` flag for that schedule channel is set to `true`. This approach makes sense; it's a direct, efficient way to update the schedule. Wait a second. I need to understand how `sdata->vif.cfg.nan_sched` gets populated in the first place, or this whole process is meaningless. It looks like `ieee80211_nan_set_local_sched` sets the values. Need to circle back and check that as well. And if we have channels we *can* evacuate, how does that work? Where does that logic live? I need to check `ieee80211_nan_find_evac_chan` for that. Time to go dig in `net/mac80211/nan.c` and figure out how all these pieces fit together. |
| 32/2 | 2026/09/23 18:41 | tool | read-file |
0mArgs:{
"File": "net/mac80211/nan.c",
"FirstLine": 800,
"LineCount": 40
}Results: {
"Contents": " 800:\t\n 801:\t\tif (WARN_ON(sdata-\u003evif.type != NL80211_IFTYPE_NAN))\n 802:\t\t\treturn NULL;\n 803:\t\n 804:\t\tsched_cfg = \u0026sdata-\u003evif.cfg.nan_sched;\n 805:\t\n 806:\t\t/* Find the channel to evacuate and count usable channels */\n 807:\t\tfor (int i = 0; i \u003c IEEE80211_NAN_MAX_CHANNELS; i++) {\n 808:\t\t\tstruct ieee80211_nan_channel *chan =\n 809:\t\t\t\t\u0026sched_cfg-\u003echannels[i];\n 810:\t\t\tstruct ieee80211_chanctx *chan_ctx;\n 811:\t\t\tint slot_count = 0;\n 812:\t\n 813:\t\t\tif (!chan-\u003echanreq.oper.chan || !chan-\u003echanctx_conf)\n 814:\t\t\t\tcontinue;\n 815:\t\n 816:\t\t\tusable_channels++;\n 817:\t\n 818:\t\t\t/* No-evacuate channel is usable but cannot be evacuated */\n 819:\t\t\tif (chan-\u003eno_evacuate)\n 820:\t\t\t\tcontinue;\n 821:\t\n 822:\t\t\tchan_ctx = container_of(chan-\u003echanctx_conf,\n 823:\t\t\t\t\t\tstruct ieee80211_chanctx, conf);\n 824:\t\n 825:\t\t\t/* If ctx specified, only consider that specific chanctx */\n 826:\t\t\tif (ctx) {\n 827:\t\t\t\tif (chan_ctx == ctx)\n 828:\t\t\t\t\tevac_chan = chan;\n 829:\t\t\t\tcontinue;\n 830:\t\t\t}\n 831:\t\n 832:\t\t\t/* Can only evacuate channels whose chanctx is NAN-only */\n 833:\t\t\tif (ieee80211_chanctx_refcount(local, chan_ctx) \u003e 1)\n 834:\t\t\t\tcontinue;\n 835:\t\n 836:\t\t\t/* Count how many time slots use this channel */\n 837:\t\t\tfor (int s = 0; s \u003c CFG80211_NAN_SCHED_NUM_TIME_SLOTS; s++)\n 838:\t\t\t\tif (sched_cfg-\u003eschedule[s] == chan)\n 839:\t\t\t\t\tslot_count++;\n"
} |
| 33/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 45925 output: 40 thoughts: 810 Thoughts: **Analyzing NAN Schedule Updates** Okay, let's dive into this `ieee80211_nan_set_local_sched` function. I need to understand how it handles the `no_evacuate` flag when the local schedule changes. The commit log mentioned preserving this flag across schedule updates, but I have a nagging feeling that's not explicitly implemented here. Is it forgotten or handled elsewhere? Right, time to re-examine the code. I'll need to confirm if the `ieee80211_nan_set_local_sched` function actually preserves the non-evacuable marking, as the commit implies, or if some other function does the heavy lifting. The key is to find where the `no_evacuate` attribute is either set or cleared on channel changes. Let me check the diff in `net/mac80211/nan.c`. Ah, here's a related function, `ieee80211_nan_set_non_evac_channels`. It iterates through the existing schedule channels and sets the `no_evacuate` flag for channels matching those provided in the `channels` struct. The existing schedule's `no_evacuate` flags are cleared and then set from the provided channel list. Now, I have to be sure this is connected to what I'm looking at, let me look at `ieee80211_nan_set_local_sched`. |
| 34/2 | 2026/09/23 18:41 | tool | read-file |
0mArgs:{
"File": "net/mac80211/nan.c",
"FirstLine": 280,
"LineCount": 50
}Results: {
"Contents": " 280:\tint ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,\n 281:\t\t\t\t\t struct cfg80211_nan_local_sched *sched)\n 282:\t{\n 283:\t\tstruct ieee80211_nan_channel *sched_idx_to_chan[IEEE80211_NAN_MAX_CHANNELS] = {};\n 284:\t\tstruct ieee80211_nan_sched_cfg *sched_cfg = \u0026sdata-\u003evif.cfg.nan_sched;\n 285:\t\tstruct ieee80211_nan_sched_cfg *backup_sched __free(kfree) = kmalloc_obj(*backup_sched);\n 286:\t\tint ret;\n 287:\t\n 288:\t\tif (!backup_sched)\n 289:\t\t\treturn -ENOMEM;\n 290:\t\n 291:\t\tif (sched-\u003en_channels \u003e IEEE80211_NAN_MAX_CHANNELS)\n 292:\t\t\treturn -EOPNOTSUPP;\n 293:\t\n 294:\t\tif (sched-\u003enan_avail_blob_len \u003e IEEE80211_NAN_AVAIL_BLOB_MAX_LEN)\n 295:\t\t\treturn -EINVAL;\n 296:\t\n 297:\t\t/*\n 298:\t\t * If a deferred schedule update is pending completion, new updates are\n 299:\t\t * not allowed. Only allow to configure an empty schedule so NAN can be\n 300:\t\t * stopped in the middle of a deferred update. This is fine because\n 301:\t\t * empty schedule means the local NAN device will not be available for\n 302:\t\t * peers anymore so there is no need to update peers about a new\n 303:\t\t * schedule.\n 304:\t\t */\n 305:\t\tif (WARN_ON(sched_cfg-\u003edeferred \u0026\u0026 sched-\u003en_channels))\n 306:\t\t\treturn -EBUSY;\n 307:\t\n 308:\t\tbitmap_zero(sdata-\u003eu.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);\n 309:\t\n 310:\t\tmemcpy(backup_sched-\u003eschedule, sched_cfg-\u003eschedule,\n 311:\t\t sizeof(backup_sched-\u003eschedule));\n 312:\t\tmemcpy(backup_sched-\u003echannels, sched_cfg-\u003echannels,\n 313:\t\t sizeof(backup_sched-\u003echannels));\n 314:\t\tmemcpy(backup_sched-\u003eavail_blob, sched_cfg-\u003eavail_blob,\n 315:\t\t sizeof(backup_sched-\u003eavail_blob));\n 316:\t\tbackup_sched-\u003eavail_blob_len = sched_cfg-\u003eavail_blob_len;\n 317:\t\n 318:\t\tmemcpy(sched_cfg-\u003eavail_blob, sched-\u003enan_avail_blob,\n 319:\t\t sched-\u003enan_avail_blob_len);\n 320:\t\tsched_cfg-\u003eavail_blob_len = sched-\u003enan_avail_blob_len;\n 321:\t\n 322:\t\t/*\n 323:\t\t * Remove channels that are no longer in the new schedule to free up\n 324:\t\t * resources before adding new channels. For deferred schedule, channels\n 325:\t\t * will be removed when the schedule is applied.\n 326:\t\t * Create a mapping from sched index to sched_cfg channel\n 327:\t\t */\n 328:\t\tfor (int i = 0; i \u003c ARRAY_SIZE(sched_cfg-\u003echannels); i++) {\n 329:\t\t\tbool still_needed = false;\n"
} |
| 35/2 | 2026/09/23 18:41 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 48046 output: 40 thoughts: 34 Thoughts: Okay, here's my interpretation of what's going on in that code section, focusing on how I'd approach understanding it: **Deconstructing `ieee80211_nan_set_local_sched` (Lines 330-420)** Alright, diving into this section of `ieee80211_nan_set_local_sched`. I need to get a handle on how this scheduler is working for NAN. From the function name, I'm expecting this to be the core logic for setting the local schedule. Let's see what they're doing. First, I'm looking for the primary data structures being manipulated here. Are we dealing with queues, lists, timers? What are the key variables that define the scheduler's state? I'm anticipating elements related to discovery window management, channel selection, or perhaps service announcement intervals. I'm keen to spot if this function interacts with any hardware registers directly. It will be interesting to observe how the scheduling interacts with any power management mechanisms, to see if there are any tradeoffs they made. Then, I'll be looking for any critical sections, locks, or atomic operations. Concurrency is a real concern in this kind of driver, and any potential race conditions will be top of mind. I expect there to be careful handling of mutexes or spinlocks given that this is a core scheduling function. I also want to see how the code handles different NAN configurations or operating modes. Are there conditional branches based on the network profile, or the role of the device (initiator/responder)? Any place in the code where this scheduling behavior is dependent on the firmware version, or hardware revision. Finally, I'll be watching for error handling. What happens if something goes wrong – invalid parameters, resource exhaustion, hardware failures? How are errors reported or handled? Is there a fallback mechanism? It's usually a good indicator of overall quality and robustness. I'll want to see how this section integrates with the broader NAN stack and the mac80211 framework. I have an intuition that this set_local_sched may just provide an interface for the mac80211 to interface with, and that'll be my assumption until I can prove otherwise. I'm keeping my eye out for any interactions with the regulatory domain to see how these schedules are governed by it. |
| 36/2 | 2026/09/23 18:42 | tool | read-file |
0mArgs:{
"File": "net/mac80211/nan.c",
"FirstLine": 330,
"LineCount": 80
}Results: {
"Contents": " 330:\t\n 331:\t\t\tif (!sched_cfg-\u003echannels[i].chanreq.oper.chan)\n 332:\t\t\t\tcontinue;\n 333:\t\n 334:\t\t\tfor (int j = 0; j \u003c sched-\u003en_channels; j++) {\n 335:\t\t\t\tif (cfg80211_chandef_identical(\u0026sched_cfg-\u003echannels[i].chanreq.oper,\n 336:\t\t\t\t\t\t\t \u0026sched-\u003enan_channels[j].chandef)) {\n 337:\t\t\t\t\tsched_idx_to_chan[j] =\n 338:\t\t\t\t\t\t\u0026sched_cfg-\u003echannels[i];\n 339:\t\t\t\t\tstill_needed = true;\n 340:\t\t\t\t\tbreak;\n 341:\t\t\t\t}\n 342:\t\t\t}\n 343:\t\n 344:\t\t\tif (!still_needed) {\n 345:\t\t\t\t__set_bit(i, sdata-\u003eu.nan.removed_channels);\n 346:\t\t\t\tif (!sched-\u003edeferred)\n 347:\t\t\t\t\tieee80211_nan_remove_channel(sdata,\n 348:\t\t\t\t\t\t\t\t \u0026sched_cfg-\u003echannels[i]);\n 349:\t\t\t}\n 350:\t\t}\n 351:\t\n 352:\t\tfor (int i = 0; i \u003c sched-\u003en_channels; i++) {\n 353:\t\t\tstruct ieee80211_nan_channel *chan = sched_idx_to_chan[i];\n 354:\t\n 355:\t\t\tif (chan) {\n 356:\t\t\t\tieee80211_nan_update_channel(sdata-\u003elocal, chan,\n 357:\t\t\t\t\t\t\t \u0026sched-\u003enan_channels[i],\n 358:\t\t\t\t\t\t\t sched-\u003edeferred);\n 359:\t\t\t} else {\n 360:\t\t\t\tchan = ieee80211_nan_find_free_channel(sched_cfg);\n 361:\t\t\t\tif (WARN_ON(!chan)) {\n 362:\t\t\t\t\tret = -EINVAL;\n 363:\t\t\t\t\tgoto err;\n 364:\t\t\t\t}\n 365:\t\n 366:\t\t\t\tsched_idx_to_chan[i] = chan;\n 367:\t\t\t\tieee80211_nan_init_channel(chan,\n 368:\t\t\t\t\t\t\t \u0026sched-\u003enan_channels[i]);\n 369:\t\t\t}\n 370:\t\n 371:\t\t\t/* Also a pre-existing channel might have been ULWed, so no chanctx */\n 372:\t\t\tif (!chan-\u003echanctx_conf) {\n 373:\t\t\t\tret = ieee80211_nan_use_chanctx(sdata, chan, false);\n 374:\t\t\t\tif (ret) {\n 375:\t\t\t\t\tmemset(chan, 0, sizeof(*chan));\n 376:\t\t\t\t\tgoto err;\n 377:\t\t\t\t}\n 378:\t\t\t}\n 379:\t\t}\n 380:\t\n 381:\t\tfor (int s = 0; s \u003c ARRAY_SIZE(sched_cfg-\u003eschedule); s++) {\n 382:\t\t\tif (sched-\u003eschedule[s] \u003c ARRAY_SIZE(sched_idx_to_chan))\n 383:\t\t\t\tsched_cfg-\u003eschedule[s] =\n 384:\t\t\t\t\tsched_idx_to_chan[sched-\u003eschedule[s]];\n 385:\t\t\telse\n 386:\t\t\t\tsched_cfg-\u003eschedule[s] = NULL;\n 387:\t\t}\n 388:\t\n 389:\t\tsched_cfg-\u003edeferred = sched-\u003edeferred;\n 390:\t\n 391:\t\tdrv_vif_cfg_changed(sdata-\u003elocal, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);\n 392:\t\n 393:\t\t/*\n 394:\t\t * For deferred update, don't update NDI carriers yet as the new\n 395:\t\t * schedule is not yet applied so common slots don't change. The NDI\n 396:\t\t * carrier will be updated once the driver notifies the new schedule is\n 397:\t\t * applied.\n 398:\t\t */\n 399:\t\tif (sched_cfg-\u003edeferred)\n 400:\t\t\treturn 0;\n 401:\t\n 402:\t\tieee80211_nan_update_all_ndi_carriers(sdata-\u003elocal);\n 403:\t\tbitmap_zero(sdata-\u003eu.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);\n 404:\t\n 405:\t\treturn 0;\n 406:\terr:\n 407:\t\t/* Remove newly added channels */\n 408:\t\tfor (int i = 0; i \u003c ARRAY_SIZE(sched_cfg-\u003echannels); i++) {\n 409:\t\t\tstruct cfg80211_chan_def *chan_def =\n"
} |
| 37/2 | 2026/09/23 18:42 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 49904 output: 42 thoughts: 130 Thoughts: **Analyzing Channel Updates in the NAN Scheduler** Okay, here's what I'm seeing: there's this situation where a channel, let's call it `chan`, is already present within the `sched_cfg->channels` structure. And then, there are these two key operations that seem important. Firstly, it sets `sched_idx_to_chan[j]` to point to the address of `sched_cfg->channels[i]`. So `sched_idx_to_chan[j]` is now a pointer to the channel already in the config, and the other index maps to the same channel. Secondly, the code calls `ieee80211_nan_update_channel` with the channel, a local structure and some scheduling data. I need to be sure the update doesn't have an adverse affect on the channel. My immediate question is, does this `ieee80211_nan_update_channel` function potentially overwrite some critical channel flags? Specifically, I'm thinking about the `no_evacuate` flag. It seems important to know if the scheduler updates something it shouldn't. I'm going to dig into the implementation of `ieee80211_nan_update_channel` now to understand exactly what it does, and whether this overwrite is a possibility. This is where the devil's in the details with this kind of scheduler code. |
| 38/2 | 2026/09/23 18:42 | tool | grepper |
0mArgs:{
"Expression": "ieee80211_nan_update_channel",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/nan.c=24=static void\nnet/mac80211/nan.c:25:ieee80211_nan_update_channel(struct ieee80211_local *local,\nnet/mac80211/nan.c-26-\t\t\t struct ieee80211_nan_channel *nan_channel,\n--\nnet/mac80211/nan.c=280=int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/nan.c-355-\t\tif (chan) {\nnet/mac80211/nan.c:356:\t\t\tieee80211_nan_update_channel(sdata-\u003elocal, chan,\nnet/mac80211/nan.c-357-\t\t\t\t\t\t \u0026sched-\u003enan_channels[i],\n"
} |
| 39/2 | 2026/09/23 18:42 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 50639 output: 39 thoughts: 35 Thoughts: Okay, let's dive into these functions, `ieee80211_nan_update_channel` and `ieee80211_nan_init_channel`. I want to quickly grasp the core logic of channel management in the NAN context. I'm already familiar with 802.11 standards, so I expect these functions to be fairly specific to NAN extensions, likely dealing with discovery window management, preferred channel selection, and potentially power save related logic. I need to understand how the system dynamically updates channel parameters or initializes them. The initial channel setup is critical for device discoverability and connection, I anticipate `ieee80211_nan_init_channel` to handle that part. The 'update' function suggests there’s state management, probably in response to beacons, external events, or policy changes. I'll be looking for things like frequency agility, regulatory domain considerations, and how the channel parameters are communicated or negotiated. Let's see how they handle the complexities of NAN operation and potential channel conflicts with traditional Wi-Fi networks. |
| 40/2 | 2026/09/23 18:42 | tool | read-file |
0mArgs:{
"File": "net/mac80211/nan.c",
"FirstLine": 15,
"LineCount": 40
}Results: {
"Contents": " 15:\t{\n 16:\t\tmemset(nan_channel, 0, sizeof(*nan_channel));\n 17:\t\n 18:\t\tnan_channel-\u003echanreq.oper = cfg_nan_channel-\u003echandef;\n 19:\t\tmemcpy(nan_channel-\u003echannel_entry, cfg_nan_channel-\u003echannel_entry,\n 20:\t\t sizeof(nan_channel-\u003echannel_entry));\n 21:\t\tnan_channel-\u003eneeded_rx_chains = cfg_nan_channel-\u003erx_nss;\n 22:\t}\n 23:\t\n 24:\tstatic void\n 25:\tieee80211_nan_update_channel(struct ieee80211_local *local,\n 26:\t\t\t\t struct ieee80211_nan_channel *nan_channel,\n 27:\t\t\t\t struct cfg80211_nan_channel *cfg_nan_channel,\n 28:\t\t\t\t bool deferred)\n 29:\t{\n 30:\t\tstruct ieee80211_chanctx_conf *conf;\n 31:\t\tbool reducing_nss;\n 32:\t\n 33:\t\tif (WARN_ON(!cfg80211_chandef_identical(\u0026nan_channel-\u003echanreq.oper,\n 34:\t\t\t\t\t\t\t\u0026cfg_nan_channel-\u003echandef)))\n 35:\t\t\treturn;\n 36:\t\n 37:\t\tif (WARN_ON(memcmp(nan_channel-\u003echannel_entry,\n 38:\t\t\t\t cfg_nan_channel-\u003echannel_entry,\n 39:\t\t\t\t sizeof(nan_channel-\u003echannel_entry))))\n 40:\t\t\treturn;\n 41:\t\n 42:\t\tif (nan_channel-\u003eneeded_rx_chains == cfg_nan_channel-\u003erx_nss)\n 43:\t\t\treturn;\n 44:\t\n 45:\t\treducing_nss = nan_channel-\u003eneeded_rx_chains \u003e cfg_nan_channel-\u003erx_nss;\n 46:\t\tnan_channel-\u003eneeded_rx_chains = cfg_nan_channel-\u003erx_nss;\n 47:\t\n 48:\t\tconf = nan_channel-\u003echanctx_conf;\n 49:\t\n 50:\t\t/*\n 51:\t\t * If we are adding NSSs, we need to be ready before notifying the peer,\n 52:\t\t * if we are reducing NSSs, we need to wait until the peer is notified.\n 53:\t\t */\n 54:\t\tif (!conf || (deferred \u0026\u0026 reducing_nss))\n"
} |
| 41/2 | 2026/09/23 18:42 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 51586 output: 41 thoughts: 2955 Thoughts: **Vulnerability Deep Dive: NAN Channel Evacuation in mac80211 - A Fuzzing Goldmine** Okay, so I've been digging into this NAN channel evacuation logic, and there's some seriously interesting stuff here. My initial assessment was solid: the channel state management seems correct on the surface, with new channels evacuable by default, existing channels retaining their non-evacuable status, and removed channels being cleaned up. That initial check confirmed the behavior matched the description. However, the `nl80211_nan_set_non_evac_channels` function is where things get... problematic. The critical vulnerability centers around a classic integer overflow and type mismatch. Specifically, `n_channels` (an `int`) representing the number of channels sent from userspace, is used to allocate space and set the count, but ultimately it's truncated down to a `u8` (`channels->n_channels`). If a user space program sends more than 255 channels, we get a value of zero written into `n_channels`. This truncation is a major issue. The code then uses this `channels->n_channels` (now 0) in two key places. First, the bounds sanitizer will report an out of bounds error in more modern kernels because `channels->chandefs[0]` is accessed, when it's supposed to be an array sized by a zero value. Second, the code will loop zero times even though the user passed data for many channels. Even if the bounds sanitizer doesn't trigger, the loop condition `i < channels->n_channels` becomes `i < 0`. This completely bypasses the intended processing, which validates the contents of these channels, and sets the number of channels correctly. If the user passed 256 or 257 channels, then `channels->n_channels` will incorrectly be set to 0 or 1, and the sanitizers will trip. The vulnerability occurs within the `nlmsg_for_each_attr_type` block, when accessing a flexible array member (`chandefs`) which can lead to out-of-bounds reads/writes if `n_channels` is larger than the type's maximum size. Then, the check in `cfg80211_nan_set_non_evac_channels`, which tries to validate all the provided channels against the current local schedule, is bypassed as a result of the integer overflow. Additionally, even if `channels->n_channels` is nonzero, the validation loop uses the smaller `wdev->u.nan.n_channels` (also a `u8`), which means there's a possibility of bypassing validation too. Furthermore, looking at `nl80211_nan_set_local_sched`, we see a similar pattern with `sched->n_channels` as a `u8`, which could lead to further issues with out-of-bounds access. This is textbook syzkaller fodder. This setup has the perfect conditions. - Integer truncation (int -> u8). - Netlink message attribute count mismatches. - Reachable code paths within standard configurations, with a lot of new runtime assertions. - Good coverage from syzkaller, which already understands the `nl80211` netlink family and the virtual `mac80211_hwsim` driver. I've verified that all the necessary kernel configurations (`CFG80211`, `MAC80211`, etc.) are standard and readily available. This bug meets all the positive criteria: It's reachable via netlink (a core part of kernel interaction with user space), involves well-established drivers and protocols, and presents opportunities for runtime assertions and fuzzing. It's a prime target for syzkaller, which can easily craft malformed netlink messages to trigger this vulnerability and crash the kernel. |
| 42/2 | 2026/09/23 18:42 | tool | grepper |
0mArgs:{
"Expression": "config MAC80211_HWSIM",
"PathPrefix": "drivers/net/wireless/virtual/Kconfig"
}Results: {
"Output": "drivers/net/wireless/virtual/Kconfig:1:config MAC80211_HWSIM\ndrivers/net/wireless/virtual/Kconfig-2-\ttristate \"Simulated radio testing tool for mac80211\"\n"
} |
| 43/2 | 2026/09/23 18:42 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 55486 output: 36 thoughts: 16 Thoughts: Here's a summary of my thought process, as if I were considering that Kconfig file: **Analyzing the Virtual Wireless Network Driver Kconfig** Okay, let's dive into the `drivers/net/wireless/virtual/Kconfig` file. I immediately know this is going to be about configuring features and options for a virtual network driver, specifically one designed for wireless networks. My expertise tells me that this file will be crucial in determining how the kernel builds this driver, and what features will be included or excluded based on the end-user's configuration. I'm expecting to see dependencies on other kernel features, possible hardware configurations, and perhaps different levels of support for various virtual wireless capabilities like virtual access points, virtual clients, and bridging scenarios. I'll be looking for things like: * **`config` options:** These will define the individual features that users can enable or disable, like enabling a specific mode or protocol. * **`depends on` clauses:** These are the key. They show me which other kernel components or dependencies need to be enabled before this virtual driver can even be considered. This helps me understand the architecture and how this driver fits into the larger kernel context. * **`select` statements:** These indicate the automatic inclusion of other symbols when a certain configuration is selected. It's important to understand these to see which features are automatically enabled. * **`help` text:** This section is vital. I'll be using this information to understand what each configuration option *does*, the trade-offs of enabling or disabling it, and which situations it is intended for. This also gives me insight into the author's intent and how they view the feature. * **Likely some conditionals based on CPU arch:** With this being a virtual driver, I would expect it to be largely architecture-agnostic. But, there might be architectural considerations in specific drivers. My goal is to thoroughly grasp the design decisions and potential implications of each configuration option to see how it can be used within its context. I can then use this to debug, tweak, or extend it to meet my particular needs and to give me insight on the design rationale. |
| 44/2 | 2026/09/23 18:42 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/virtual/Kconfig",
"FirstLine": 1,
"LineCount": 25
}Results: {
"Contents": " 1:\tconfig MAC80211_HWSIM\n 2:\t\ttristate \"Simulated radio testing tool for mac80211\"\n 3:\t\tdepends on MAC80211\n 4:\t\thelp\n 5:\t\t This driver is a developer testing tool that can be used to test\n 6:\t\t IEEE 802.11 networking stack (mac80211) functionality. This is not\n 7:\t\t needed for normal wireless LAN usage and is only for testing. See\n 8:\t\t Documentation/networking/mac80211_hwsim for more information on how\n 9:\t\t to use this tool.\n 10:\t\n 11:\t\t To compile this driver as a module, choose M here: the module will be\n 12:\t\t called mac80211_hwsim. If unsure, say N.\n 13:\t\n 14:\tconfig VIRT_WIFI\n 15:\t\ttristate \"Wifi wrapper for ethernet drivers\"\n 16:\t\tdepends on CFG80211\n 17:\t\thelp\n 18:\t\t This option adds support for ethernet connections to appear as if they\n 19:\t\t are wifi connections through a special rtnetlink device.\n 20:\t\n"
} |
| 45/2 | 2026/09/23 18:42 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 56317 output: 31 thoughts: 94 Thoughts: **My Initial Thoughts on Building Wireless Networking Components** Okay, so I'm diving into this build process. It's clear that both `CFG80211` and `MAC80211` are fundamental prerequisites for compiling `net/wireless` and `net/mac80211`. That makes perfect sense; `MAC80211` is the core of the wireless MAC layer, and `CFG80211` is its userspace interface, right? Then I remember `MAC80211_HWSIM`. Ah, yes, that's the one. It enables the software-emulated radio device. That's fantastic for testing and development in a virtualized setting, which is pretty common these days. That gives me a way to actually *exercise* mac80211 without needing physical hardware. It's great to have a standardized method. But I'm wondering... are those the *only* significant configurations I need to worry about? I know there are usually more fine-grained options. Better to be sure. Time to double-check. I'm going to take a look at `net/wireless/Makefile`. I'm sure I'll find the answer there. |
| 46/2 | 2026/09/23 18:42 | tool | read-file |
0mArgs:{
"File": "net/wireless/Makefile",
"FirstLine": 1,
"LineCount": 35
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0\n 2:\tobj-$(CONFIG_CFG80211) += cfg80211.o\n 3:\tobj-y += tests/\n 4:\t\n 5:\tobj-$(CONFIG_WEXT_CORE) += wext-core.o\n 6:\tobj-$(CONFIG_WEXT_PROC) += wext-proc.o\n 7:\tobj-$(CONFIG_WEXT_PRIV) += wext-priv.o\n 8:\t\n 9:\tcfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o\n 10:\tcfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o\n 11:\tcfg80211-y += michael-mic.o pmsr.o\n 12:\tcfg80211-$(CONFIG_OF) += of.o\n 13:\tcfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o\n 14:\tcfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o\n 15:\t\n 16:\tCFLAGS_trace.o := -I$(src)\n 17:\t\n 18:\tcfg80211-$(CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS) += shipped-certs.o\n 19:\tifneq ($(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR),)\n 20:\tcfg80211-y += extra-certs.o\n 21:\tendif\n 22:\t\n 23:\t$(obj)/shipped-certs.c: $(sort $(wildcard $(src)/certs/*.hex))\n 24:\t\t@$(kecho) \" GEN $@\"\n 25:\t\t$(Q)(echo '#include \"reg.h\"'; \\\n 26:\t\t echo 'const u8 shipped_regdb_certs[] = {'; \\\n 27:\t\t echo | cat - $^ ; \\\n 28:\t\t echo '};'; \\\n 29:\t\t echo 'unsigned int shipped_regdb_certs_len = sizeof(shipped_regdb_certs);'; \\\n 30:\t\t ) \u003e $@\n 31:\t\n 32:\t$(obj)/extra-certs.c: $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR) \\\n 33:\t\t\t $(sort $(wildcard $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR)/*.x509))\n 34:\t\t@$(kecho) \" GEN $@\"\n 35:\t\t$(Q)(set -e; \\\n"
} |
| 47/2 | 2026/09/23 18:42 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 57456 output: 332 thoughts: 1082 Thoughts: **Analysis of NAN Non-Evacuable Channel Feature for Fuzzing** Okay, let's break this down. From a configuration perspective, I see that `cfg80211` and `mac80211` are being modified, with specific attention to the NAN (Neighbor Awareness Networking) non-evacuable channel feature. Specifically, I'm noting the compilation units involved: `cfg80211.o`, `core.o`, `nl80211.o` for `cfg80211` and `mac80211.o`, `cfg.o`, and `nan.o` for `mac80211`. The relevant kernel config options are `CONFIG_CFG80211`, `CONFIG_MAC80211`, and `CONFIG_MAC80211_HWSIM`. Now, the critical part: identifying the *new* or *altered* symbols. I've pinpointed the following: * `nl80211.c`: `nl80211_nan_set_non_evac_channels`, `nl80211_parse_non_evac_channel` * `core.c`: `cfg80211_nan_set_non_evac_channels` * `cfg.c`: `ieee80211_set_nan_non_evac_channels` * `nan.c`: `ieee80211_nan_set_non_evac_channels`, `ieee80211_nan_find_evac_chan` (with a modification to check `chan->no_evacuate`). I've verified their visibility. Importantly, `nl80211_nan_set_non_evac_channels` is a static handler for `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS`. Now, I'm discounting the static inline `rdev_nan_set_non_evac_channels` in `rdev-ops.h` as per the established guidelines; focus on .c files. Given that information, I'm assessing the fuzzing potential. These functions are highly specific to the NAN non-evacuable channel functionality and evacuation logic. Crucially, they aren't core, ubiquitous hot-paths that I'd normally avoid. With that in mind, my assessment is: * **WorthFuzzing**: True. * **Reasoning**: I'm seeing the introduction of the `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS` netlink command and associated parsing of nested attributes. This data propagates through `cfg80211` to `mac80211`, which impacts channel evacuation logic. This whole chain is reachable in virtualized environments via `mac80211_hwsim` and unprivileged netlink. There's also a potential for integer truncation and bounds check issues when processing the channel array. * **EnableConfigs**: `CFG80211`, `MAC80211`, `MAC80211_HWSIM` * **FocusSymbols**: (the list of symbols from above) Everything looks solid. The analysis is thorough, and the conclusions are well-supported. I'm satisfied. Now, let's call `set-results`. |
| 48/2 | 2026/09/23 18:42 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"CFG80211",
"MAC80211",
"MAC80211_HWSIM"
],
"FocusSymbols": [
"nl80211_nan_set_non_evac_channels",
"nl80211_parse_non_evac_channel",
"cfg80211_nan_set_non_evac_channels",
"ieee80211_set_nan_non_evac_channels",
"ieee80211_nan_set_non_evac_channels",
"ieee80211_nan_find_evac_chan"
],
"Reasoning": "The patch adds a new userspace-facing nl80211 Generic Netlink command NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS to configure NAN local schedule channels that must not be evacuated for concurrent operations. The implementation includes nested attribute parsing in nl80211, validation and state checks in cfg80211, driver callback plumbing, and evacuation filtering in mac80211. This code is fully reachable in virtualized environments using mac80211_hwsim and netlink. Moreover, user-controlled channel counts parsed into a u8 variable with __counted_by annotations warrant fuzzing against truncation, bounds violations, and state consistency issues.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"CFG80211",
"MAC80211",
"MAC80211_HWSIM"
],
"FocusSymbols": [
"nl80211_nan_set_non_evac_channels",
"nl80211_parse_non_evac_channel",
"cfg80211_nan_set_non_evac_channels",
"ieee80211_set_nan_non_evac_channels",
"ieee80211_nan_set_non_evac_channels",
"ieee80211_nan_find_evac_chan"
],
"Reasoning": "The patch adds a new userspace-facing nl80211 Generic Netlink command NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS to configure NAN local schedule channels that must not be evacuated for concurrent operations. The implementation includes nested attribute parsing in nl80211, validation and state checks in cfg80211, driver callback plumbing, and evacuation filtering in mac80211. This code is fully reachable in virtualized environments using mac80211_hwsim and netlink. Moreover, user-controlled channel counts parsed into a u8 variable with __counted_by annotations warrant fuzzing against truncation, bounds violations, and state consistency issues.",
"WorthFuzzing": true
} |
| 49/1 | 2026/09/23 18:42 | action | If |
1mArgs:{
"WorthFuzzing": true
}Results: null |
| 50/2 | 2026/09/23 18:42 | agent | kmsan-evaluator |
1mModel:core Args: null Results: {
"KMSANReasoning": "The patch introduces a new nl80211 command `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS` along with mac80211/cfg80211 handling to configure channels that must not be evacuated.\n\n1. Memory Initialization: All newly allocated heap structures (`channels` and `channel_parsed`) are allocated using `kzalloc` and `kcalloc`, respectively. Furthermore, `nl80211_parse_chandef()` explicitly zeroes the destination `cfg80211_chan_def` using `memset()`. The struct `ieee80211_nan_channel` containing the new `no_evacuate` boolean is already zeroed via `memset()` during channel init and removal.\n2. Kernel-to-User Information Leaks: The command is a setter (`doit` only) and does not copy any kernel structures or Netlink attributes back to user space.\n3. KMSAN vs. KASAN applicability: Any theoretical issues introduced by the patch (such as integer truncation on `n_channels`, channel index lookups, or NULL pointer dereferencing) fall under bounds checks, memory corruption, or locking issues, which are comprehensively caught by KASAN, UBSAN, and LOCKDEP. No uninitialized memory usage or info-leak vectors are introduced. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
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: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 2bd9eba0b7bea163a2099d7071fa60052175ccac
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Sep 23 18:40:41 2026 +0000
syz-cluster: applied patch under review
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9aa7d2d4a1841..43551dd4328ef 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4258,6 +4258,21 @@ struct cfg80211_nan_local_sched {
struct cfg80211_nan_channel nan_channels[] __counted_by(n_channels);
};
+/**
+ * struct cfg80211_nan_non_evac_channels - NAN non-evacuable channels
+ *
+ * This struct defines the set of NAN local schedule channels that must not
+ * be evacuated for concurrent operations.
+ *
+ * @n_channels: number of channel definitions in %chandefs.
+ * @chandefs: array of channel definitions that must not be evacuated. Each
+ * must match a channel of the current local schedule.
+ */
+struct cfg80211_nan_non_evac_channels {
+ u8 n_channels;
+ struct cfg80211_chan_def chandefs[] __counted_by(n_channels);
+};
+
/**
* struct cfg80211_nan_peer_map - NAN peer schedule map
*
@@ -5206,6 +5221,12 @@ struct mgmt_frame_regs {
* schedule, the full new schedule is provided - partial updates are not
* supported, and the new schedule completely replaces the previous one.
*
+ * @nan_set_non_evac_channels: set the list of local schedule channels that
+ * must not be evacuated for concurrent operations. The provided list
+ * replaces the previous set; channels of the current schedule that are
+ * not included become evacuable again. All provided channels are
+ * guaranteed by cfg80211 to belong to the current local schedule.
+ *
* @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
*
* @get_txq_stats: Get TXQ stats for interface or phy. If wdev is %NULL, this
@@ -5592,6 +5613,9 @@ struct cfg80211_ops {
int (*nan_set_peer_sched)(struct wiphy *wiphy,
struct wireless_dev *wdev,
struct cfg80211_nan_peer_sched *sched);
+ int (*nan_set_non_evac_channels)(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels);
int (*set_multicast_to_unicast)(struct wiphy *wiphy,
struct net_device *dev,
const bool enabled);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1172d7b83ed18..46ae2aa6e4e75 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -923,12 +923,14 @@ struct ieee80211_bss_conf {
* @channel_entry: the Channel Entry blob as defined in Wi-Fi Aware
* (TM) 4.0 specification Table 100 (Channel Entry format for the NAN
* Availability attribute).
+ * @no_evacuate: if set, this channel must not be evacuated
*/
struct ieee80211_nan_channel {
struct ieee80211_chan_req chanreq;
u8 needed_rx_chains;
struct ieee80211_chanctx_conf *chanctx_conf;
u8 channel_entry[6];
+ bool no_evacuate;
};
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9a2ccb8d66b86..ff7b5157e8cf8 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1383,6 +1383,13 @@
* from the device to perform an announced schedule update. See
* %NL80211_ATTR_NAN_SCHED_DEFERRED for more details.
* If not set, the schedule should be applied immediately.
+ * Setting a new schedule is always allowed and is never treated as an
+ * evacuation, even if it removes channels that were previously marked as
+ * non-evacuable with %NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS. The
+ * non-evacuable marking is a per-channel property of the schedule:
+ * channels that remain in the new schedule keep their marking, channels
+ * that are removed simply lose it, and newly added channels are
+ * evacuable by default.
* @NL80211_CMD_NAN_SCHED_UPDATE_DONE: Event sent to user space to notify that
* a deferred local NAN schedule update (requested with
* %NL80211_CMD_NAN_SET_LOCAL_SCHED and %NL80211_ATTR_NAN_SCHED_DEFERRED)
@@ -1427,6 +1434,28 @@
* @NL80211_CMD_STOP_PD: Stop the PD operation, identified by
* its %NL80211_ATTR_WDEV interface.
*
+ * @NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS: Set the list of NAN local schedule
+ * channels that must not be evacuated. NAN must be operational
+ * (%NL80211_CMD_START_NAN was executed) and a local schedule must have
+ * been set (%NL80211_CMD_NAN_SET_LOCAL_SCHED). The command carries zero
+ * or more nested %NL80211_ATTR_NAN_CHANNEL attributes, each identifying a
+ * channel (by its channel definition) of the current local schedule that
+ * must not be evacuated for concurrent operations. The provided list
+ * replaces the previous set of non-evacuable channels; channels of the
+ * current schedule that are not included become evacuable again. All
+ * provided channels must exist in the current local schedule, otherwise
+ * the command fails. This is used to protect channels carrying NDC or
+ * immutable schedules, whose evacuation would break existing NDP
+ * connections.
+ * The non-evacuable marking is a per-channel property of the current
+ * local schedule and only affects evacuation for concurrent operations;
+ * it does not prevent the schedule itself from being changed. Removing a
+ * channel from the schedule with %NL80211_CMD_NAN_SET_LOCAL_SCHED is a
+ * user-initiated change, not an evacuation, and is allowed even for a
+ * non-evacuable channel. Across a schedule update, channels that remain
+ * keep their non-evacuable marking, removed channels lose it, and newly
+ * added channels are evacuable by default; issue this command again to
+ * change the non-evacuable set.
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1705,6 +1734,8 @@ enum nl80211_commands {
NL80211_CMD_START_PD,
NL80211_CMD_STOP_PD,
+ NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 23f4f9ec86d0a..cdcf1f0577077 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -5973,6 +5973,18 @@ ieee80211_set_peer_nan_sched(struct wiphy *wiphy,
return ieee80211_nan_set_peer_sched(sdata, sched);
}
+static int
+ieee80211_set_nan_non_evac_channels(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+ lockdep_assert_wiphy(wiphy);
+
+ return ieee80211_nan_set_non_evac_channels(sdata, channels);
+}
+
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -6091,4 +6103,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.set_epcs = ieee80211_set_epcs,
.nan_set_local_sched = ieee80211_set_local_nan_sched,
.nan_set_peer_sched = ieee80211_set_peer_nan_sched,
+ .nan_set_non_evac_channels = ieee80211_set_nan_non_evac_channels,
};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9514f01778beb..eaaffb80a422c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2088,6 +2088,8 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
struct cfg80211_nan_local_sched *sched);
int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata,
struct cfg80211_nan_peer_sched *sched);
+int ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_nan_non_evac_channels *channels);
void ieee80211_nan_free_peer_sched(struct ieee80211_nan_peer_sched *sched);
void ieee80211_nan_update_ndi_carrier(struct ieee80211_sub_if_data *ndi_sdata);
struct ieee80211_nan_channel *
diff --git a/net/mac80211/nan.c b/net/mac80211/nan.c
index 19e08661be43a..38bd105121acf 100644
--- a/net/mac80211/nan.c
+++ b/net/mac80211/nan.c
@@ -248,6 +248,35 @@ ieee80211_nan_find_free_channel(struct ieee80211_nan_sched_cfg *sched_cfg)
return NULL;
}
+int
+ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_nan_non_evac_channels *channels)
+{
+ struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
+
+ /*
+ * cfg80211 already validated that all provided channels belong to the
+ * current schedule, so just clear all non-evacuable flags and set the
+ * ones in the list.
+ */
+ for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++)
+ sched_cfg->channels[j].no_evacuate = false;
+
+ for (int i = 0; i < channels->n_channels; i++) {
+ for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++) {
+ if (!sched_cfg->channels[j].chanreq.oper.chan)
+ continue;
+ if (cfg80211_chandef_identical(&sched_cfg->channels[j].chanreq.oper,
+ &channels->chandefs[i])) {
+ sched_cfg->channels[j].no_evacuate = true;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
struct cfg80211_nan_local_sched *sched)
{
@@ -786,6 +815,10 @@ ieee80211_nan_find_evac_chan(struct ieee80211_local *local,
usable_channels++;
+ /* No-evacuate channel is usable but cannot be evacuated */
+ if (chan->no_evacuate)
+ continue;
+
chan_ctx = container_of(chan->chanctx_conf,
struct ieee80211_chanctx, conf);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d13310fef691a..2f46243773f94 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -325,6 +325,41 @@ int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,
return 0;
}
+int cfg80211_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels)
+{
+ lockdep_assert_held(&rdev->wiphy.mtx);
+
+ if (wdev->iftype != NL80211_IFTYPE_NAN || !wdev_running(wdev))
+ return -EINVAL;
+
+ /*
+ * Don't allow updating the non-evacuable channels while a deferred
+ * schedule update is pending, as the set of channels may still change.
+ */
+ if (wdev->u.nan.sched_update_pending)
+ return -EBUSY;
+
+ /* All provided channels must belong to the current local schedule. */
+ for (int i = 0; i < channels->n_channels; i++) {
+ bool found = false;
+
+ for (int j = 0; j < wdev->u.nan.n_channels; j++) {
+ if (cfg80211_chandef_identical(&wdev->u.nan.chandefs[j],
+ &channels->chandefs[i])) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return -ENOENT;
+ }
+
+ return rdev_nan_set_non_evac_channels(rdev, wdev, channels);
+}
+
void cfg80211_stop_pd(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b4610f6685dcb..4ee48b9370800 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -565,6 +565,10 @@ int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct cfg80211_nan_local_sched *sched);
+int cfg80211_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels);
+
struct cfg80211_internal_bss *
cfg80211_bss_update(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *tmp,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ab5a14f5fe283..bb1abc9d18e27 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -17767,6 +17767,69 @@ static int nl80211_nan_set_local_sched(struct sk_buff *skb,
return cfg80211_nan_set_local_schedule(rdev, wdev, sched);
}
+static int
+nl80211_parse_non_evac_channel(struct cfg80211_registered_device *rdev,
+ struct nlattr *channel, struct genl_info *info,
+ struct cfg80211_chan_def *chandef)
+{
+ struct nlattr **channel_parsed __free(kfree) =
+ kcalloc(NL80211_ATTR_MAX + 1, sizeof(*channel_parsed),
+ GFP_KERNEL);
+ int ret;
+
+ if (!channel_parsed)
+ return -ENOMEM;
+
+ ret = nla_parse_nested(channel_parsed, NL80211_ATTR_MAX, channel, NULL,
+ info->extack);
+ if (ret)
+ return ret;
+
+ return nl80211_parse_chandef(rdev, info->extack, channel_parsed,
+ chandef, false);
+}
+
+static int nl80211_nan_set_non_evac_channels(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+ int rem, i = 0, n_channels = 0;
+ struct nlattr *channel;
+
+ if (wdev->iftype != NL80211_IFTYPE_NAN)
+ return -EOPNOTSUPP;
+
+ if (!wdev_running(wdev))
+ return -ENOTCONN;
+
+ /* Count how many channel attributes we got */
+ nlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL,
+ info->nlhdr, GENL_HDRLEN, rem)
+ n_channels++;
+
+ struct cfg80211_nan_non_evac_channels *channels __free(kfree) =
+ kzalloc(struct_size(channels, chandefs, n_channels),
+ GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ channels->n_channels = n_channels;
+
+ nlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL,
+ info->nlhdr, GENL_HDRLEN, rem) {
+ int ret;
+
+ ret = nl80211_parse_non_evac_channel(rdev, channel, info,
+ &channels->chandefs[i]);
+ if (ret)
+ return ret;
+ i++;
+ }
+
+ return cfg80211_nan_set_non_evac_channels(rdev, wdev, channels);
+}
+
static int nl80211_get_protocol_features(struct sk_buff *skb,
struct genl_info *info)
{
@@ -20629,6 +20692,12 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.flags = GENL_ADMIN_PERM,
.internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP),
},
+ {
+ .cmd = NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS,
+ .doit = nl80211_nan_set_non_evac_channels,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP),
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 46849fe8d0b39..269258c94a42a 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1093,6 +1093,23 @@ rdev_nan_set_peer_sched(struct cfg80211_registered_device *rdev,
return ret;
}
+static inline int
+rdev_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels)
+{
+ int ret;
+
+ trace_rdev_nan_set_non_evac_channels(&rdev->wiphy, wdev, channels);
+ if (rdev->ops->nan_set_non_evac_channels)
+ ret = rdev->ops->nan_set_non_evac_channels(&rdev->wiphy, wdev,
+ channels);
+ else
+ ret = -EOPNOTSUPP;
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
static inline int rdev_start_pd(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 8c2a91b85c396..435dc58cafbed 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2483,6 +2483,31 @@ TRACE_EVENT(rdev_nan_set_peer_sched,
)
);
+TRACE_EVENT(rdev_nan_set_non_evac_channels,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+ struct cfg80211_nan_non_evac_channels *channels),
+ TP_ARGS(wiphy, wdev, channels),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ __field(u8, n_channels)
+ __dynamic_array(u32, freqs, channels->n_channels)
+ ),
+ TP_fast_assign(
+ u32 *freqs = __get_dynamic_array(freqs);
+
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ __entry->n_channels = channels->n_channels;
+ for (int i = 0; i < channels->n_channels; i++)
+ freqs[i] = channels->chandefs[i].chan->center_freq;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", n_channels: %u, freqs: %s",
+ WIPHY_PR_ARG, WDEV_PR_ARG, __entry->n_channels,
+ __print_array(__get_dynamic_array(freqs),
+ __entry->n_channels, sizeof(u32)))
+);
+
TRACE_EVENT(rdev_set_mac_acl,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_acl_data *params),
|
| 51/3 | 2026/09/23 18:42 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 8584 output: 36 thoughts: 1280 Thoughts: **Analyzing the NAN Non-Evacuate Channel Patch** Okay, so this patch is introducing a new nl80211 command, `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS`, and the corresponding infrastructure to handle it within cfg80211 and mac80211. Let's break down what's happening. First, I see the core data structures are being extended. `cfg80211.h` gets a `cfg80211_nan_non_evac_channels` struct and a new callback, `nan_set_non_evac_channels`, in `cfg80211_ops`. The `mac80211.h` side adds a `no_evacuate` flag to the `ieee80211_nan_channel` struct – that's the crucial state variable. The UAPI is updated to reflect the new command. Then the implementation pieces start coming together. `mac80211/cfg.c` provides the `ieee80211_set_nan_non_evac_channels` function, hooking into `mac80211`'s config operations. The core logic resides in `mac80211/nan.c` within `ieee80211_nan_set_non_evac_channels`. It takes a list of channels and iterates. It *clears* the `no_evacuate` flag for all channels first, and then *sets* it for channels that are specified in the provided list. That's a good approach to ensure a known state. Importantly, the `ieee80211_nan_find_evac_chan` function now respects the `no_evacuate` flag, skipping any channel explicitly marked as "non-evacuate" for evacuation purposes. The `cfg80211` side in `core.c` has a function `cfg80211_nan_set_non_evac_channels`. It checks for NAN interface type and that the device is running, then validates the provided channels, and calls the driver's function `rdev_nan_set_non_evac_channels`. Important checks are present to ensure that the channel being set is actually supported by the driver, and that a scheduler update isn't already pending. The userspace interaction happens through `nl80211.c`. `nl80211_nan_set_non_evac_channels` handles the parsing. It iterates through the provided channel attributes and builds a `cfg80211_nan_non_evac_channels` struct, which is then passed to `cfg80211_nan_set_non_evac_channels`. The parsing logic uses the existing `nl80211_parse_non_evac_channel` which uses `nl80211_parse_chandef`. Finally, there's a tracepoint in `trace.h` for this, which is good for debugging. Now, let's step back and consider potential issues. I need to make sure there are no uninitialized memory reads or memory leaks when dealing with all this new data. I should double-check the `nl80211_parse_chandef` function to see what it returns, and how the data is used. I'll need to look at how channel definitions are handled, especially since we're comparing them in `cfg80211_chandef_identical`. I'll also check the channel list validation to be sure that the provided channels are actually valid and supported. Let's use `grep` to quickly find calls to `nl80211_parse_chandef` and related functions. |
| 52/3 | 2026/09/23 18:43 | tool | grepper |
0mArgs:{
"Expression": "int nl80211_parse_chandef",
"PathPrefix": "net/wireless/"
}Results: {
"Output": "net/wireless/nl80211.c=3928=static int _nl80211_parse_chandef(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/nl80211.c-4096-\nnet/wireless/nl80211.c:4097:int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,\nnet/wireless/nl80211.c-4098-\t\t\t struct netlink_ext_ack *extack,\n--\nnet/wireless/nl80211.h=19=static inline u64 wdev_id(struct wireless_dev *wdev)\n--\nnet/wireless/nl80211.h-24-\nnet/wireless/nl80211.h:25:int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,\nnet/wireless/nl80211.h-26-\t\t\t struct netlink_ext_ack *extack,\n"
} |
| 53/3 | 2026/09/23 18:43 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 11032 output: 41 thoughts: 24 Thoughts: Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person: **Diving into the Chandef Parsing** Alright, let's get down to brass tacks. I need to understand how the `nl80211_parse_chandef` function handles that `chandef` structure. I'm already familiar with the broader `nl80211` context, so my focus here is pinpointing the nuances of the channel definition parsing. What's the control flow? What specific fields are being scrutinized and validated? I'm looking for edge cases, potential vulnerabilities, and any assumptions the code makes about the underlying hardware or regulatory domain. Specifically, are there any potential buffer overflows or integer overflow issues? How well does it handle malformed input, and what sort of error handling is in place? I'm thinking about potential fuzzing strategies based on how this parser is structured. My goal is a solid understanding that can inform my subsequent analysis and hopefully uncover any hidden issues. |
| 54/3 | 2026/09/23 18:43 | tool | read-file |
0mArgs:{
"File": "net/wireless/nl80211.c",
"FirstLine": 4095,
"LineCount": 25
}Results: {
"Contents": "4095:\t}\n4096:\t\n4097:\tint nl80211_parse_chandef(struct cfg80211_registered_device *rdev,\n4098:\t\t\t\t struct netlink_ext_ack *extack,\n4099:\t\t\t\t struct nlattr **attrs,\n4100:\t\t\t\t struct cfg80211_chan_def *chandef,\n4101:\t\t\t\t bool permit_npca)\n4102:\t{\n4103:\t\treturn _nl80211_parse_chandef(rdev, extack, attrs, false, chandef,\n4104:\t\t\t\t\t permit_npca);\n4105:\t}\n4106:\t\n4107:\tstatic int __nl80211_set_channel(struct cfg80211_registered_device *rdev,\n4108:\t\t\t\t\t struct net_device *dev,\n4109:\t\t\t\t\t struct genl_info *info,\n4110:\t\t\t\t\t int _link_id)\n4111:\t{\n4112:\t\tstruct cfg80211_chan_def chandef;\n4113:\t\tint result;\n4114:\t\tenum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;\n4115:\t\tstruct wireless_dev *wdev = NULL;\n4116:\t\tint link_id = _link_id;\n4117:\t\tbool permit_npca;\n4118:\t\n4119:\t\tif (dev)\n"
} |
| 55/3 | 2026/09/23 18:43 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 11735 output: 41 thoughts: 18 Thoughts: Okay, here's my attempt at summarizing the thought process, as requested, aimed at an expert audience and written in the first person: **Diving into `_nl80211_parse_chandef`** Alright, let's take a look at `_nl80211_parse_chandef`. I need to understand this channel definition parsing logic. I know I'm dealing with `nl80211`, so I'm expecting some standard Netlink structures, probably nested. The goal here is to extract all the relevant channel parameters from the incoming Netlink message, right? Things like the center frequency, channel width (20MHz, 40MHz, 80MHz, 160MHz, etc.), possibly the secondary channel offset, and any regulatory domain information that's encoded in there. I'll be looking for potential error conditions, of course. Null pointers, invalid values – the usual suspects. I have to think about how robust this parsing is. Does it handle all the various channel definition formats correctly? What about different regulatory domains? Are there any potential overflow issues if we get a badly formed message? Any missing checks or missing assumptions will need to be identified and verified. Then, are there checks to validate if the channel parameters given are actually supported by the current hardware and driver configuration? What is the function’s behaviour if the parsing logic succeeds but the resulting channel definition is incompatible with the regulatory domain or the device capabilities? I need to figure out how this is communicated upstream. Are error codes being set properly? Is there any logging, and is it sufficient to debug unexpected behavior in the wireless stack? I'm anticipating potential interoperability issues based on what I see here, because the format is a standard, but it’s always a good idea to perform a deeper dive. The potential for a security issue should also be considered, if parsing of any parameter can be forced or abused in any way. |
| 56/3 | 2026/09/23 18:43 | tool | read-file |
0mArgs:{
"File": "net/wireless/nl80211.c",
"FirstLine": 3925,
"LineCount": 40
}Results: {
"Contents": "3925:\t\t\twdev-\u003eiftype == NL80211_IFTYPE_P2P_GO;\n3926:\t}\n3927:\t\n3928:\tstatic int _nl80211_parse_chandef(struct cfg80211_registered_device *rdev,\n3929:\t\t\t\t\t struct netlink_ext_ack *extack,\n3930:\t\t\t\t\t struct nlattr **attrs, bool monitor,\n3931:\t\t\t\t\t struct cfg80211_chan_def *chandef,\n3932:\t\t\t\t\t bool permit_npca)\n3933:\t{\n3934:\t\tu32 control_freq;\n3935:\t\n3936:\t\tif (!attrs[NL80211_ATTR_WIPHY_FREQ]) {\n3937:\t\t\tNL_SET_ERR_MSG_ATTR(extack, attrs[NL80211_ATTR_WIPHY_FREQ],\n3938:\t\t\t\t\t \"Frequency is missing\");\n3939:\t\t\treturn -EINVAL;\n3940:\t\t}\n3941:\t\n3942:\t\tcontrol_freq = MHZ_TO_KHZ(\n3943:\t\t\t\tnla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ]));\n3944:\t\tif (attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET])\n3945:\t\t\tcontrol_freq +=\n3946:\t\t\t nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]);\n3947:\t\n3948:\t\tmemset(chandef, 0, sizeof(*chandef));\n3949:\t\tchandef-\u003echan = ieee80211_get_channel_khz(\u0026rdev-\u003ewiphy, control_freq);\n3950:\t\tchandef-\u003ewidth = NL80211_CHAN_WIDTH_20_NOHT;\n3951:\t\tchandef-\u003ecenter_freq1 = KHZ_TO_MHZ(control_freq);\n3952:\t\tchandef-\u003efreq1_offset = control_freq % 1000;\n3953:\t\tchandef-\u003ecenter_freq2 = 0;\n3954:\t\tchandef-\u003es1g_primary_2mhz = false;\n3955:\t\n3956:\t\tif (!chandef-\u003echan) {\n3957:\t\t\tNL_SET_ERR_MSG_ATTR(extack, attrs[NL80211_ATTR_WIPHY_FREQ],\n3958:\t\t\t\t\t \"Unknown channel\");\n3959:\t\t\treturn -EINVAL;\n3960:\t\t}\n3961:\t\n3962:\t\tif (cfg80211_chandef_is_s1g(chandef))\n3963:\t\t\tchandef-\u003ewidth = NL80211_CHAN_WIDTH_1;\n3964:\t\n"
} |
| 57/3 | 2026/09/23 18:43 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 12974 output: 19 thoughts: 1845 Thoughts: **Analysis of Potential Vulnerability in `nl80211_nan_set_non_evac_channels`** Okay, so I've been looking at this `nl80211_nan_set_non_evac_channels` function, and my initial thought was about potential integer overflows when handling the number of channels. Specifically, the code: * Allocates memory for `cfg80211_nan_non_evac_channels` using `kzalloc`, which is good because it ensures zero-initialized memory. This initial zeroing also happens in several other relevant structures (`_nl80211_parse_chandef`, `channel_parsed`). * The number of channels (`n_channels`) is counted from the netlink attributes, but is stored as a `u8`. My first concern was about a classic integer overflow. If a malicious user sends more than 255 channel attributes, `n_channels` truncates to 0. * However, even if `n_channels` becomes 0, the memory allocation size is calculated using the initial, larger value (e.g. 256). The code allocates space for 256 `chandefs`, but the `n_channels` member inside is zero. * The code then loops through the netlink attributes up to the initial counter (e.g. 256) and parses the channel definitions into the allocated memory. * Afterwards, the code uses `channels->n_channels` to iterate when working with the channels, which will be 0, and the loops won't execute. This means that if an integer overflow happens, there is no out-of-bounds write since the loop iterates 0 times. This is probably a logic bug, not a memory safety one. * Moreover, even if the count wasn't 0 and the loops ran, all memory is initialized with zeros, so there are no uninitialized memory reads. * And, given that the memory allocation is correct and the values are properly initialized, it seems likely that a tool like KASAN would detect any out-of-bounds access. The overflow leads to a logic bug rather than a memory bug. However, I'm now looking at the tracepoint: * The tracepoint `trace_rdev_nan_set_non_evac_channels` shows a potential issue. It accesses `channels->chandefs[i].chan->center_freq`. * I considered a NULL dereference if `chandef->chan` was NULL. But, if `chandef->chan` is NULL, the parsing function returns an error before even getting to the tracepoint. So that's safe. * Also, any null pointer dereference would be caught by KASAN. I then did a sweep for information leakage: * I checked if this patch added any "dump" or "get" operations, but `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS` is a "set" command only, so there is no information leakage via netlink dumps. * I checked if `nl80211_nan_set_non_evac_channels` sends anything back to userspace, but no netlink messages are sent back, just a return code. * I scanned for any other uses of the `no_evacuate` flag in the codebase and haven't found any evidence of information leakage through that channel. So, while there is an integer overflow that results in a logic error (the `channels->n_channels` member being set to zero), it doesn't appear to lead to any memory safety issues or information leaks. We might still want to fix this logic bug for clarity, but it's not a vulnerability. |
| 58/3 | 2026/09/23 18:43 | tool | grepper |
0mArgs:{
"Expression": "no_evacuate"
}Results: {
"Output": "include/net/mac80211.h=801=struct ieee80211_bss_conf {\n--\ninclude/net/mac80211.h-925- *\tAvailability attribute).\ninclude/net/mac80211.h:926: * @no_evacuate: if set, this channel must not be evacuated\ninclude/net/mac80211.h-927- */\ninclude/net/mac80211.h=928=struct ieee80211_nan_channel {\n--\ninclude/net/mac80211.h-932-\tu8 channel_entry[6];\ninclude/net/mac80211.h:933:\tbool no_evacuate;\ninclude/net/mac80211.h-934-};\n--\nnet/mac80211/nan.c=252=ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/nan.c-262-\tfor (int j = 0; j \u003c ARRAY_SIZE(sched_cfg-\u003echannels); j++)\nnet/mac80211/nan.c:263:\t\tsched_cfg-\u003echannels[j].no_evacuate = false;\nnet/mac80211/nan.c-264-\n--\nnet/mac80211/nan.c-270-\t\t\t\t\t\t \u0026channels-\u003echandefs[i])) {\nnet/mac80211/nan.c:271:\t\t\t\tsched_cfg-\u003echannels[j].no_evacuate = true;\nnet/mac80211/nan.c-272-\t\t\t\tbreak;\n--\nnet/mac80211/nan.c=790=ieee80211_nan_find_evac_chan(struct ieee80211_local *local,\n--\nnet/mac80211/nan.c-818-\t\t/* No-evacuate channel is usable but cannot be evacuated */\nnet/mac80211/nan.c:819:\t\tif (chan-\u003eno_evacuate)\nnet/mac80211/nan.c-820-\t\t\tcontinue;\n"
} |
| 59/3 | 2026/09/23 18:43 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 16268 output: 40 thoughts: 171 Thoughts: **Analyzing the `no_evacuate` Flag in mac80211 for NAN Scheduling** Okay, so I see that the `no_evacuate` flag is only defined and used within `include/net/mac80211.h` and the NAN implementation specifically, in `net/mac80211/nan.c`. That's the starting point. Now, I need to understand how this flag behaves during schedule updates. I'll focus on `ieee80211_nan_set_local_sched` because that sounds like the key function handling the schedule modification. Let me see... there was something in the commit message or the uAPI documentation... yes, here it is: "Across a schedule update, channels that remain keep their non-evacuable marking, removed channels lose it, and newly added channels are evacuable by default." Alright, now the important question is: does `ieee80211_nan_set_local_sched` actually *implement* that logic, or does it simply reset some `sched_cfg` structure and leave the details for another function? Time to dive into the code for `ieee80211_nan_set_local_sched` and clarify that! |
| 60/3 | 2026/09/23 18:43 | tool | read-file |
0mArgs:{
"File": "net/mac80211/nan.c",
"FirstLine": 278,
"LineCount": 50
}Results: {
"Contents": " 278:\t}\n 279:\t\n 280:\tint ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,\n 281:\t\t\t\t\t struct cfg80211_nan_local_sched *sched)\n 282:\t{\n 283:\t\tstruct ieee80211_nan_channel *sched_idx_to_chan[IEEE80211_NAN_MAX_CHANNELS] = {};\n 284:\t\tstruct ieee80211_nan_sched_cfg *sched_cfg = \u0026sdata-\u003evif.cfg.nan_sched;\n 285:\t\tstruct ieee80211_nan_sched_cfg *backup_sched __free(kfree) = kmalloc_obj(*backup_sched);\n 286:\t\tint ret;\n 287:\t\n 288:\t\tif (!backup_sched)\n 289:\t\t\treturn -ENOMEM;\n 290:\t\n 291:\t\tif (sched-\u003en_channels \u003e IEEE80211_NAN_MAX_CHANNELS)\n 292:\t\t\treturn -EOPNOTSUPP;\n 293:\t\n 294:\t\tif (sched-\u003enan_avail_blob_len \u003e IEEE80211_NAN_AVAIL_BLOB_MAX_LEN)\n 295:\t\t\treturn -EINVAL;\n 296:\t\n 297:\t\t/*\n 298:\t\t * If a deferred schedule update is pending completion, new updates are\n 299:\t\t * not allowed. Only allow to configure an empty schedule so NAN can be\n 300:\t\t * stopped in the middle of a deferred update. This is fine because\n 301:\t\t * empty schedule means the local NAN device will not be available for\n 302:\t\t * peers anymore so there is no need to update peers about a new\n 303:\t\t * schedule.\n 304:\t\t */\n 305:\t\tif (WARN_ON(sched_cfg-\u003edeferred \u0026\u0026 sched-\u003en_channels))\n 306:\t\t\treturn -EBUSY;\n 307:\t\n 308:\t\tbitmap_zero(sdata-\u003eu.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);\n 309:\t\n 310:\t\tmemcpy(backup_sched-\u003eschedule, sched_cfg-\u003eschedule,\n 311:\t\t sizeof(backup_sched-\u003eschedule));\n 312:\t\tmemcpy(backup_sched-\u003echannels, sched_cfg-\u003echannels,\n 313:\t\t sizeof(backup_sched-\u003echannels));\n 314:\t\tmemcpy(backup_sched-\u003eavail_blob, sched_cfg-\u003eavail_blob,\n 315:\t\t sizeof(backup_sched-\u003eavail_blob));\n 316:\t\tbackup_sched-\u003eavail_blob_len = sched_cfg-\u003eavail_blob_len;\n 317:\t\n 318:\t\tmemcpy(sched_cfg-\u003eavail_blob, sched-\u003enan_avail_blob,\n 319:\t\t sched-\u003enan_avail_blob_len);\n 320:\t\tsched_cfg-\u003eavail_blob_len = sched-\u003enan_avail_blob_len;\n 321:\t\n 322:\t\t/*\n 323:\t\t * Remove channels that are no longer in the new schedule to free up\n 324:\t\t * resources before adding new channels. For deferred schedule, channels\n 325:\t\t * will be removed when the schedule is applied.\n 326:\t\t * Create a mapping from sched index to sched_cfg channel\n 327:\t\t */\n"
} |
| 61/3 | 2026/09/23 18:43 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 17676 output: 40 thoughts: 24 Thoughts: Okay, here's my attempt at summarizing the thought process, as requested, geared toward an expert audience, and written in the first person: **Diving into `ieee80211_nan_set_local_sched`** Alright, let's get into this. I need to understand what's happening within `ieee80211_nan_set_local_sched`. I'm assuming, based on the name, this is where the local scheduling parameters for NAN (Neighbor Awareness Networking) are being set. So, this function is critical for how the local device behaves in a NAN network. I'll need to pay close attention to the data structures it's manipulating, especially anything related to the schedule itself: discovery window configuration, transmit/receive probabilities, active/passive behavior, anything that dictates when and how the device will announce its services and listen for those of others. I need to see how the function interacts with the hardware, probably by setting some registers. I will need to consider how the settings are being stored, are they in some internal structure, and how are they maintained to ensure the appropriate behavior. Also, I'll need to understand how this relates to any higher-level NAN configuration or policy. Is it a direct configuration function, or does it mediate between a more abstract policy layer and the lower-level hardware controls? I also want to determine how the settings are being validated. Are there sanity checks on the input parameters to ensure the configuration makes sense and avoids conflicting settings or invalid durations? I'm assuming that it is the case. Finally, what happens if there's an error? Are there error codes or reporting mechanisms in place? I will use this information to determine the robustness of the function and how well it is designed to handle invalid situations. Let's see how it's actually implemented! |
| 62/3 | 2026/09/23 18:43 | tool | read-file |
0mArgs:{
"File": "net/mac80211/nan.c",
"FirstLine": 328,
"LineCount": 60
}Results: {
"Contents": " 328:\t\tfor (int i = 0; i \u003c ARRAY_SIZE(sched_cfg-\u003echannels); i++) {\n 329:\t\t\tbool still_needed = false;\n 330:\t\n 331:\t\t\tif (!sched_cfg-\u003echannels[i].chanreq.oper.chan)\n 332:\t\t\t\tcontinue;\n 333:\t\n 334:\t\t\tfor (int j = 0; j \u003c sched-\u003en_channels; j++) {\n 335:\t\t\t\tif (cfg80211_chandef_identical(\u0026sched_cfg-\u003echannels[i].chanreq.oper,\n 336:\t\t\t\t\t\t\t \u0026sched-\u003enan_channels[j].chandef)) {\n 337:\t\t\t\t\tsched_idx_to_chan[j] =\n 338:\t\t\t\t\t\t\u0026sched_cfg-\u003echannels[i];\n 339:\t\t\t\t\tstill_needed = true;\n 340:\t\t\t\t\tbreak;\n 341:\t\t\t\t}\n 342:\t\t\t}\n 343:\t\n 344:\t\t\tif (!still_needed) {\n 345:\t\t\t\t__set_bit(i, sdata-\u003eu.nan.removed_channels);\n 346:\t\t\t\tif (!sched-\u003edeferred)\n 347:\t\t\t\t\tieee80211_nan_remove_channel(sdata,\n 348:\t\t\t\t\t\t\t\t \u0026sched_cfg-\u003echannels[i]);\n 349:\t\t\t}\n 350:\t\t}\n 351:\t\n 352:\t\tfor (int i = 0; i \u003c sched-\u003en_channels; i++) {\n 353:\t\t\tstruct ieee80211_nan_channel *chan = sched_idx_to_chan[i];\n 354:\t\n 355:\t\t\tif (chan) {\n 356:\t\t\t\tieee80211_nan_update_channel(sdata-\u003elocal, chan,\n 357:\t\t\t\t\t\t\t \u0026sched-\u003enan_channels[i],\n 358:\t\t\t\t\t\t\t sched-\u003edeferred);\n 359:\t\t\t} else {\n 360:\t\t\t\tchan = ieee80211_nan_find_free_channel(sched_cfg);\n 361:\t\t\t\tif (WARN_ON(!chan)) {\n 362:\t\t\t\t\tret = -EINVAL;\n 363:\t\t\t\t\tgoto err;\n 364:\t\t\t\t}\n 365:\t\n 366:\t\t\t\tsched_idx_to_chan[i] = chan;\n 367:\t\t\t\tieee80211_nan_init_channel(chan,\n 368:\t\t\t\t\t\t\t \u0026sched-\u003enan_channels[i]);\n 369:\t\t\t}\n 370:\t\n 371:\t\t\t/* Also a pre-existing channel might have been ULWed, so no chanctx */\n 372:\t\t\tif (!chan-\u003echanctx_conf) {\n 373:\t\t\t\tret = ieee80211_nan_use_chanctx(sdata, chan, false);\n 374:\t\t\t\tif (ret) {\n 375:\t\t\t\t\tmemset(chan, 0, sizeof(*chan));\n 376:\t\t\t\t\tgoto err;\n 377:\t\t\t\t}\n 378:\t\t\t}\n 379:\t\t}\n 380:\t\n 381:\t\tfor (int s = 0; s \u003c ARRAY_SIZE(sched_cfg-\u003eschedule); s++) {\n 382:\t\t\tif (sched-\u003eschedule[s] \u003c ARRAY_SIZE(sched_idx_to_chan))\n 383:\t\t\t\tsched_cfg-\u003eschedule[s] =\n 384:\t\t\t\t\tsched_idx_to_chan[sched-\u003eschedule[s]];\n 385:\t\t\telse\n 386:\t\t\t\tsched_cfg-\u003eschedule[s] = NULL;\n 387:\t\t}\n"
} |
| 63/3 | 2026/09/23 18:43 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 19080 output: 42 thoughts: 63 Thoughts: Okay, here's my take on those lines of code, presented as a personal thought process, given my expertise: **Diving into NAN Channel Initialization** Alright, let's zero in on lines 367-368, specifically: `ieee80211_nan_init_channel(chan, &sched->nan_channels[i]);`. My first instinct is to understand the context. We're clearly dealing with an 802.11 implementation, likely focused on NAN (Neighbor Awareness Networking) since that function is explicitly named as such. The line itself indicates an initialization procedure. We have a `chan` which is most likely a pointer to a channel struct and `&sched->nan_channels[i]` is passed to that function, meaning that the function operates on a specific channel, based on some schedule, and within a known set of NAN channels. So, let's dig into `ieee80211_nan_init_channel` to understand precisely how this channel is being set up. I expect it to involve some crucial configurations, like setting channel parameters, possibly registering the channel with the NAN scheduler, or configuring radio settings. I'll need to see how the other parts of the scheduler interact, as it's likely a critical component for how NAN operations are handled. I anticipate that the implementation of this function is going to be crucial to determining the radio's operation for NAN, and how discovery is performed. I expect to be looking for registers to access, and the configuration thereof. |
| 64/3 | 2026/09/23 18:43 | tool | grepper |
0mArgs:{
"Expression": "ieee80211_nan_init_channel",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/nan.c=12=static void\nnet/mac80211/nan.c:13:ieee80211_nan_init_channel(struct ieee80211_nan_channel *nan_channel,\nnet/mac80211/nan.c-14-\t\t\t struct cfg80211_nan_channel *cfg_nan_channel)\n--\nnet/mac80211/nan.c=280=int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/nan.c-366-\t\t\tsched_idx_to_chan[i] = chan;\nnet/mac80211/nan.c:367:\t\t\tieee80211_nan_init_channel(chan,\nnet/mac80211/nan.c-368-\t\t\t\t\t\t \u0026sched-\u003enan_channels[i]);\n"
} |
| 65/3 | 2026/09/23 18:43 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 19779 output: 39 thoughts: 19 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person: **Initial Thoughts on `ieee80211_nan_init_channel`** Alright, let's dive into this. The instruction is to examine the `ieee80211_nan_init_channel` function. My initial assumption is that this will be where the NAN channel initialization logic resides. Given the naming convention, I expect this to be core to setting up or configuring a Wi-Fi NAN channel within the 802.11 framework. I anticipate this function will be responsible for allocating resources, setting up data structures, and perhaps even interacting with the radio hardware to ensure the NAN channel is properly established for operation. It's possible we're dealing with things like channel parameters, frequency selection, transmit power settings, and likely some sort of connection or association related activities, depending on the role this init function plays. Let's see if those presumptions are accurate. |
| 66/3 | 2026/09/23 18:43 | tool | read-file |
0mArgs:{
"File": "net/mac80211/nan.c",
"FirstLine": 12,
"LineCount": 25
}Results: {
"Contents": " 12:\tstatic void\n 13:\tieee80211_nan_init_channel(struct ieee80211_nan_channel *nan_channel,\n 14:\t\t\t\t struct cfg80211_nan_channel *cfg_nan_channel)\n 15:\t{\n 16:\t\tmemset(nan_channel, 0, sizeof(*nan_channel));\n 17:\t\n 18:\t\tnan_channel-\u003echanreq.oper = cfg_nan_channel-\u003echandef;\n 19:\t\tmemcpy(nan_channel-\u003echannel_entry, cfg_nan_channel-\u003echannel_entry,\n 20:\t\t sizeof(nan_channel-\u003echannel_entry));\n 21:\t\tnan_channel-\u003eneeded_rx_chains = cfg_nan_channel-\u003erx_nss;\n 22:\t}\n 23:\t\n 24:\tstatic void\n 25:\tieee80211_nan_update_channel(struct ieee80211_local *local,\n 26:\t\t\t\t struct ieee80211_nan_channel *nan_channel,\n 27:\t\t\t\t struct cfg80211_nan_channel *cfg_nan_channel,\n 28:\t\t\t\t bool deferred)\n 29:\t{\n 30:\t\tstruct ieee80211_chanctx_conf *conf;\n 31:\t\tbool reducing_nss;\n 32:\t\n 33:\t\tif (WARN_ON(!cfg80211_chandef_identical(\u0026nan_channel-\u003echanreq.oper,\n 34:\t\t\t\t\t\t\t\u0026cfg_nan_channel-\u003echandef)))\n 35:\t\t\treturn;\n 36:\t\n"
} |
| 67/3 | 2026/09/23 18:43 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 20487 output: 42 thoughts: 170 Thoughts: **Analyzing NAN Channel Evacuation Behavior** Okay, so here's what I'm seeing with this NAN channel management logic. The `ieee80211_nan_init_channel` function starts things off by zeroing out the `nan_channel` structure using `memset`. This is important because it means that when a new channel is introduced, the `no_evacuate` field defaults to `false` because it's been initialized to zero. Makes sense, that's the expected default. Now, where it gets interesting is how the existing channels are handled when they are updated via the `ieee80211_nan_update_channel` function. I see that this function *doesn't* touch the `no_evacuate` field. This means that any channel already in the system, even if its other data is modified, will retain its current `no_evacuate` status. If it was `true`, it stays `true`. If it was `false`, it stays `false`. This design decision needs closer scrutiny. Finally, what about channels that are being removed? Looking at `ieee80211_nan_remove_channel`, I see a similar `memset` operation is being done, and this will set the `no_evacuate` field to `false` when the channel is being removed. Therefore, `no_evacuate` is initialized to false, is updated using `ieee80211_nan_update_channel` but left untouched, and is reset to false when the channel is removed. It seems prudent to verify how this is actually implemented using the defined structure. |
| 68/3 | 2026/09/23 18:43 | tool | grepper |
0mArgs:{
"Expression": "ieee80211_nan_remove_channel",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/nan.c=176=static void\nnet/mac80211/nan.c:177:ieee80211_nan_remove_channel(struct ieee80211_sub_if_data *sdata,\nnet/mac80211/nan.c-178-\t\t\t struct ieee80211_nan_channel *nan_channel)\n--\nnet/mac80211/nan.c=280=int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/nan.c-346-\t\t\tif (!sched-\u003edeferred)\nnet/mac80211/nan.c:347:\t\t\t\tieee80211_nan_remove_channel(sdata,\nnet/mac80211/nan.c-348-\t\t\t\t\t\t\t \u0026sched_cfg-\u003echannels[i]);\n--\nnet/mac80211/nan.c-416-\t\t\t\t\t\tchan_def))\nnet/mac80211/nan.c:417:\t\t\tieee80211_nan_remove_channel(sdata,\nnet/mac80211/nan.c-418-\t\t\t\t\t\t \u0026sched_cfg-\u003echannels[i]);\n--\nnet/mac80211/nan.c=469=void ieee80211_nan_sched_update_done(struct ieee80211_vif *vif)\n--\nnet/mac80211/nan.c-498-\t\tif (test_bit(i, sdata-\u003eu.nan.removed_channels))\nnet/mac80211/nan.c:499:\t\t\tieee80211_nan_remove_channel(sdata, chan);\nnet/mac80211/nan.c-500-\t\telse if (conf)\n"
} |
| 69/3 | 2026/09/23 18:43 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 21565 output: 40 thoughts: 28 Thoughts: Okay, here's my attempt at summarizing the thought process, as requested, targeting an expert audience: **Analyzing `net/mac80211/nan.c` - Lines 176-185** Alright, I need to zero in on lines 176 through 185 within the `nan.c` module, part of the mac80211 subsystem. Given my familiarity with the codebase, I'm already anticipating these lines likely relate to either NAN discovery, service advertisements, or perhaps a filtering mechanism tied to the NAN protocol itself. I'm mentally parsing the likely function calls within that block - anything dealing with `cfg80211_` calls or direct interaction with the hardware through the driver. Context is key, so I'm also thinking about potential interactions with the NAN discovery window management and how those lines fit into the broader NAN protocol state machine. I'll be particularly interested in any error handling or edge-case management implemented there, because that's often where the subtle bugs or optimization opportunities hide. I expect to be looking for any potential race conditions, buffer overflows, or unexpected behavior that could impact the reliability or performance of NAN communications in our scenario. I'm also ready to analyze if any relevant locking mechanisms are used, and whether their usage is appropriate. I'm going to start reading and see what actually presents itself. |
| 70/3 | 2026/09/23 18:44 | tool | read-file |
0mArgs:{
"File": "net/mac80211/nan.c",
"FirstLine": 176,
"LineCount": 15
}Results: {
"Contents": " 176:\tstatic void\n 177:\tieee80211_nan_remove_channel(struct ieee80211_sub_if_data *sdata,\n 178:\t\t\t\t struct ieee80211_nan_channel *nan_channel)\n 179:\t{\n 180:\t\tstruct ieee80211_chanctx_conf *conf;\n 181:\t\tstruct ieee80211_chanctx *ctx;\n 182:\t\tstruct ieee80211_nan_sched_cfg *sched_cfg = \u0026sdata-\u003evif.cfg.nan_sched;\n 183:\t\n 184:\t\tif (WARN_ON(!nan_channel))\n 185:\t\t\treturn;\n 186:\t\n 187:\t\tlockdep_assert_wiphy(sdata-\u003elocal-\u003ehw.wiphy);\n 188:\t\n 189:\t\tif (!nan_channel-\u003echanreq.oper.chan)\n 190:\t\t\treturn;\n"
} |
| 71/3 | 2026/09/23 18:44 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 22203 output: 40 thoughts: 28 Thoughts: Okay, let's dive into this. I'm focusing on lines 191-210 within `net/mac80211/nan.c`. I know this is a critical section for NAN functionality, likely dealing with how the Network Awareness Networking (NAN) handles something fundamental. Given the context, I expect this area to be intricately tied to either the discovery process, the data exchange mechanism, or perhaps even the resource management within the NAN infrastructure. Specifically, I'm anticipating this code block might be responsible for handling a critical aspect of how NAN devices announce their presence, respond to inquiries, or manage connections and transmissions. I need to get a high-level understanding of what this specific section is responsible for. |
| 72/3 | 2026/09/23 18:44 | tool | read-file |
0mArgs:{
"File": "net/mac80211/nan.c",
"FirstLine": 191,
"LineCount": 25
}Results: {
"Contents": " 191:\t\n 192:\t\tfor (int slot = 0; slot \u003c ARRAY_SIZE(sched_cfg-\u003eschedule); slot++)\n 193:\t\t\tif (sched_cfg-\u003eschedule[slot] == nan_channel)\n 194:\t\t\t\tsched_cfg-\u003eschedule[slot] = NULL;\n 195:\t\n 196:\t\tconf = nan_channel-\u003echanctx_conf;\n 197:\t\n 198:\t\t/* If any peer nan schedule uses this chanctx, update them */\n 199:\t\tif (conf)\n 200:\t\t\tieee80211_nan_update_peer_channels(sdata, conf);\n 201:\t\n 202:\t\tmemset(nan_channel, 0, sizeof(*nan_channel));\n 203:\t\n 204:\t\t/* Update the driver before (possibly) releasing the channel context */\n 205:\t\tdrv_vif_cfg_changed(sdata-\u003elocal, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);\n 206:\t\n 207:\t\t/* Channel might not have a chanctx if it was ULWed */\n 208:\t\tif (!conf)\n 209:\t\t\treturn;\n 210:\t\n 211:\t\tctx = container_of(conf, struct ieee80211_chanctx, conf);\n 212:\t\n 213:\t\tif (ieee80211_chanctx_num_assigned(sdata-\u003elocal, ctx) \u003e 0) {\n 214:\t\t\tieee80211_recalc_chanctx_chantype(sdata-\u003elocal, ctx);\n 215:\t\t\tieee80211_recalc_smps_chanctx(sdata-\u003elocal, ctx);\n"
} |
| 73/3 | 2026/09/23 18:44 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 22885 output: 27 thoughts: 447 Thoughts: **Analyzing NAN Channel Management** Okay, so `memset` on `nan_channel` *is* definitely being called, which is good. Now, I need to understand what happens with that data. I'm going to dig into `net/wireless/core.c` and specifically the `cfg80211_nan_set_non_evac_channels` function. I see that there are a few important checks in this function: ensuring the interface type is NAN, that the device is running, and most importantly, making sure a schedule update isn't pending. It looks like it also performs a crucial check to see if the channels provided in `channels` all belong to the *current* local schedule. It iterates through the provided channels and compares them against `wdev->u.nan.chandefs`, the set of channel definitions. If even one doesn't match the current schedule, it returns an error. This is a vital sanity check. Now, I need to figure out how `wdev->u.nan.chandefs` gets initialized and maintained. The current function seems to use it, but doesn't initialize it. To understand this I'll grep the `net/wireless` directory for occurrences of `wdev->u.nan` to find where this data structure is initialized and populated. This will reveal the complete picture of the channel management flow. |
| 74/3 | 2026/09/23 18:44 | tool | grepper |
0mArgs:{
"Expression": "u\\.nan",
"PathPrefix": "net/wireless/"
}Results: {
"Output": "net/wireless/core.c=255=void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/core.c-273-\t */\nnet/wireless/core.c:274:\twdev-\u003eu.nan.sched_update_pending = false;\nnet/wireless/core.c-275-\n--\nnet/wireless/core.c-281-\nnet/wireless/core.c:282:\teth_zero_addr(wdev-\u003eu.nan.cluster_id);\nnet/wireless/core.c-283-\n--\nnet/wireless/core.c=287=int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/core.c-297-\nnet/wireless/core.c:298:\tif (wdev-\u003eu.nan.sched_update_pending)\nnet/wireless/core.c-299-\t\treturn -EBUSY;\n--\nnet/wireless/core.c-304-\nnet/wireless/core.c:305:\twdev-\u003eu.nan.sched_update_pending = sched-\u003edeferred;\nnet/wireless/core.c-306-\nnet/wireless/core.c:307:\tkfree(wdev-\u003eu.nan.chandefs);\nnet/wireless/core.c:308:\twdev-\u003eu.nan.chandefs = NULL;\nnet/wireless/core.c:309:\twdev-\u003eu.nan.n_channels = 0;\nnet/wireless/core.c-310-\n--\nnet/wireless/core.c-313-\nnet/wireless/core.c:314:\twdev-\u003eu.nan.chandefs = kcalloc(sched-\u003en_channels,\nnet/wireless/core.c:315:\t\t\t\t sizeof(*wdev-\u003eu.nan.chandefs),\nnet/wireless/core.c-316-\t\t\t\t GFP_KERNEL);\nnet/wireless/core.c:317:\tif (!wdev-\u003eu.nan.chandefs)\nnet/wireless/core.c-318-\t\treturn -ENOMEM;\n--\nnet/wireless/core.c-320-\tfor (int i = 0; i \u003c sched-\u003en_channels; i++)\nnet/wireless/core.c:321:\t\twdev-\u003eu.nan.chandefs[i] = sched-\u003enan_channels[i].chandef;\nnet/wireless/core.c-322-\nnet/wireless/core.c:323:\twdev-\u003eu.nan.n_channels = sched-\u003en_channels;\nnet/wireless/core.c-324-\n--\nnet/wireless/core.c=328=int cfg80211_nan_set_non_evac_channels(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/core.c-340-\t */\nnet/wireless/core.c:341:\tif (wdev-\u003eu.nan.sched_update_pending)\nnet/wireless/core.c-342-\t\treturn -EBUSY;\n--\nnet/wireless/core.c-347-\nnet/wireless/core.c:348:\t\tfor (int j = 0; j \u003c wdev-\u003eu.nan.n_channels; j++) {\nnet/wireless/core.c:349:\t\t\tif (cfg80211_chandef_identical(\u0026wdev-\u003eu.nan.chandefs[j],\nnet/wireless/core.c-350-\t\t\t\t\t\t \u0026channels-\u003echandefs[i])) {\n--\nnet/wireless/nl80211.c=17294=void cfg80211_nan_sched_update_done(struct wireless_dev *wdev, bool success,\n--\nnet/wireless/nl80211.c-17304-\t/* Can happen if we stopped NAN */\nnet/wireless/nl80211.c:17305:\tif (!wdev-\u003eu.nan.sched_update_pending)\nnet/wireless/nl80211.c-17306-\t\treturn;\nnet/wireless/nl80211.c-17307-\nnet/wireless/nl80211.c:17308:\twdev-\u003eu.nan.sched_update_pending = false;\nnet/wireless/nl80211.c-17309-\n--\nnet/wireless/nl80211.c=17527=static int nl80211_nan_set_peer_sched(struct sk_buff *skb,\n--\nnet/wireless/nl80211.c-17564-\t */\nnet/wireless/nl80211.c:17565:\tif (n_channels \u0026\u0026 n_channels \u003e wdev-\u003eu.nan.n_channels * 4 * 2) {\nnet/wireless/nl80211.c-17566-\t\tNL_SET_ERR_MSG_FMT(info-\u003eextack,\n--\nnet/wireless/nl80211.c-17568-\t\t\t\t n_channels,\nnet/wireless/nl80211.c:17569:\t\t\t\t wdev-\u003eu.nan.n_channels * 4 * 2);\nnet/wireless/nl80211.c-17570-\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-17590-\t\t/* Verify channel is compatible with at least one local channel */\nnet/wireless/nl80211.c:17591:\t\tfor (int j = 0; j \u003c wdev-\u003eu.nan.n_channels; j++) {\nnet/wireless/nl80211.c-17592-\t\t\tif (cfg80211_chandef_compatible(\u0026nan_channels[i].chandef,\nnet/wireless/nl80211.c:17593:\t\t\t\t\t\t\t\u0026wdev-\u003eu.nan.chandefs[j])) {\nnet/wireless/nl80211.c-17594-\t\t\t\tcompatible = true;\n--\nnet/wireless/nl80211.c=23586=void cfg80211_nan_cluster_joined(struct wireless_dev *wdev,\n--\nnet/wireless/nl80211.c-23596-\nnet/wireless/nl80211.c:23597:\tmemcpy(wdev-\u003eu.nan.cluster_id, cluster_id, ETH_ALEN);\nnet/wireless/nl80211.c-23598-\n--\nnet/wireless/reg.c=2337=static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)\n--\nnet/wireless/reg.c-2352-\tif (iftype == NL80211_IFTYPE_NAN) {\nnet/wireless/reg.c:2353:\t\tfor (int i = 0; i \u003c wdev-\u003eu.nan.n_channels; i++) {\nnet/wireless/reg.c-2354-\t\t\tret = cfg80211_reg_can_beacon(wiphy,\nnet/wireless/reg.c:2355:\t\t\t\t\t\t \u0026wdev-\u003eu.nan.chandefs[i],\nnet/wireless/reg.c-2356-\t\t\t\t\t\t NL80211_IFTYPE_NAN);\n"
} |
| 75/3 | 2026/09/23 18:44 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 25580 output: 332 thoughts: 1678 Thoughts: **Analysis of Uninitialized Memory Risks in NAN Non-Evacuation Channel Configuration** Okay, let's break this down. My initial focus was on potential issues stemming from the handling of non-evacuated channels in the NAN configuration. Specifically, I'm thinking about how `wdev->u.nan.chandefs` is handled, given it's allocated with `kcalloc` and initialized within `cfg80211_nan_set_local_schedule`. Initially, if no local schedule is present (meaning `wdev->u.nan.n_channels == 0`), there's a check that leads to `-ENOENT` if `channels->n_channels > 0`. Then I realized, what happens if `channels->n_channels` *is* zero? If it *is* zero, then I need to consider `cfg80211_nan_set_non_evac_channels`. The loop, iterating from 0 to 0, doesn't execute anything, but it calls `rdev_nan_set_non_evac_channels`. This then leads to `ieee80211_nan_set_non_evac_channels`, which cleans everything by setting `no_evacuate = false` on every channel. The loop for zero channels *still* doesn't run, and it returns 0. The setup seems clean and correctly initialized. Now, let's perform a thorough memory allocation check within the patch: 1. `nl80211_parse_non_evac_channel` uses `kcalloc` to allocate `channel_parsed`, which is zero-initialized and freed automatically. `nla_parse_nested` then populates it. The `chandef` struct is initialized with `memset(chandef, 0, sizeof(*chandef));` before being filled. So far, so good. 2. `nl80211_nan_set_non_evac_channels` utilizes `kzalloc` to allocate `channels`, which is zero-initialized and gets automatically freed. `channels->n_channels` is explicitly set. The loop then populates `channels->chandefs[i]`. If parsing fails, the function returns, and the allocated memory is freed; otherwise, the populated data is passed to other functions. 3. Next, I have to ensure there is no data being sent to userspace. I looked for any instances of data being copied for userspace (no `nla_put`, `skb` generated for user, or `copy_to_user`). There aren't any, which is a good sign. 4. Are there any uninitialized stack variables? I'm checking each function, and all variables appear initialized correctly. I looked at the variables in `nl80211_nan_set_non_evac_channels`, `nl80211_parse_non_evac_channel`, `cfg80211_nan_set_non_evac_channels` and `ieee80211_nan_set_non_evac_channels`. It's pretty clear that there are no uninitialized variables being used. 5. Finally, do the changes alter any data lengths, introduce any new bounds checks, or buffer sizes in a manner that could allow surrounding code to read uninitialized memory? The introduction of `no_evacuate` within `struct ieee80211_nan_channel` is a boolean. `ieee80211_nan_init_channel` initializes the struct with zeroes, and `ieee80211_nan_remove_channel` does the same. `ieee80211_nan_set_non_evac_channels` explicitly iterates and sets the value to `false`, then to `true`. In `ieee80211_nan_find_evac_chan`, the `if (chan->no_evacuate) continue;` simply reads a boolean. Finally, in `trace_rdev_nan_set_non_evac_channels`, array size `channels->n_channels` is being read. The values are initialized. Given that `channels` was `kzalloc`'d and the parsed channels had a non-NULL `chan` (checked in `nl80211_parse_chandef`), there are no reads of uninitialized fields. Considering the "NeedsKMSAN" criteria, the patch doesn't fit the criteria. The analysis confirms the following: * Heap structures are allocated using `kzalloc` or `kcalloc` and fully initialized. * The `chandef` struct is initialized |
| 76/3 | 2026/09/23 18:44 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch introduces a new nl80211 command `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS` along with mac80211/cfg80211 handling to configure channels that must not be evacuated.\n\n1. Memory Initialization: All newly allocated heap structures (`channels` and `channel_parsed`) are allocated using `kzalloc` and `kcalloc`, respectively. Furthermore, `nl80211_parse_chandef()` explicitly zeroes the destination `cfg80211_chan_def` using `memset()`. The struct `ieee80211_nan_channel` containing the new `no_evacuate` boolean is already zeroed via `memset()` during channel init and removal.\n2. Kernel-to-User Information Leaks: The command is a setter (`doit` only) and does not copy any kernel structures or Netlink attributes back to user space.\n3. KMSAN vs. KASAN applicability: Any theoretical issues introduced by the patch (such as integer truncation on `n_channels`, channel index lookups, or NULL pointer dereferencing) fall under bounds checks, memory corruption, or locking issues, which are comprehensively caught by KASAN, UBSAN, and LOCKDEP. No uninitialized memory usage or info-leak vectors are introduced. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch introduces a new nl80211 command `NL80211_CMD_NAN_SET_NON_EVAC_CHANNELS` along with mac80211/cfg80211 handling to configure channels that must not be evacuated.\n\n1. Memory Initialization: All newly allocated heap structures (`channels` and `channel_parsed`) are allocated using `kzalloc` and `kcalloc`, respectively. Furthermore, `nl80211_parse_chandef()` explicitly zeroes the destination `cfg80211_chan_def` using `memset()`. The struct `ieee80211_nan_channel` containing the new `no_evacuate` boolean is already zeroed via `memset()` during channel init and removal.\n2. Kernel-to-User Information Leaks: The command is a setter (`doit` only) and does not copy any kernel structures or Netlink attributes back to user space.\n3. KMSAN vs. KASAN applicability: Any theoretical issues introduced by the patch (such as integer truncation on `n_channels`, channel index lookups, or NULL pointer dereferencing) fall under bounds checks, memory corruption, or locking issues, which are comprehensively caught by KASAN, UBSAN, and LOCKDEP. No uninitialized memory usage or info-leak vectors are introduced. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|