| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/23 10:50 | flow | patch-triage |
3mArgs:null Results: {
"EnableConfigs": [
"CFG80211",
"MAC80211",
"MAC80211_HWSIM",
"MAC80211_DEBUGFS"
],
"FocusSymbols": [
"nl80211_new_key",
"nl80211_del_key",
"nl80211_get_key",
"cfg80211_cigtk_supported",
"cfg80211_validate_key_settings",
"ieee80211_add_key",
"ieee80211_del_key",
"ieee80211_lookup_key",
"ieee80211_key_link",
"ieee80211_gtk_rekey_add",
"ieee80211_put_cip_cap"
],
"KMSANReasoning": "The patch series introduces support for the Control Integrity Protocol (CIP) and Control Integrity Group Temporal Keys (CIGTK) in cfg80211/mac80211, updating the cfg80211 add_key/del_key/get_key operations across wireless drivers to use an enum nl80211_key_type instead of a boolean pairwise flag.\n\nAnalysis regarding KMSAN vs KASAN applicability:\n1. Kernel data exposed to userspace: The new netlink attribute NL80211_ATTR_CIP_CAPABILITIES sends a single u8 from wiphy_iftype_ext_capab. These capability structures are statically allocated in driver rodata/BSS and thus zero-initialized. Station parameters and request structs in nl80211 handlers (such as nl80211_set_station, nl80211_new_station, nl80211_add_mod_link_station, and nl80211_associate) are explicitly zero-initialized with memset(\u0026params, 0, sizeof(params)) or struct initializer = {}.\n2. Data structures in mac80211: New fields (such as cigtk pointers, cip flag, and cip_cap) reside within structures (ieee80211_link_data, link_sta_info, sta_info, ieee80211_key) that are dynamically allocated with kzalloc.\n3. Parsing and bounds: Frame parsing for the new CIP capability element validates element length (len \u003e= sizeof(*elems-\u003ecip_cap)) before referencing payload bytes, and new packet generation via ieee80211_put_cip_cap initializes all four bytes added to the skb. Key indices for CIGTK are validated against NUM_CTRL_KEYS (2) in nl80211 and cfg80211 before use.\n4. Any potential memory corruption, out-of-bounds array access, or reference count / lifetime issues with key objects are fully covered by standard KASAN.\n\nNo uninitialized memory reads or information leak risks are introduced. Spawning a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false,
"Reasoning": "The patch introduces support for the Control Integrity Protocol (CIP) and Control Integrity Group Temporal Key (CIGTK) across cfg80211, nl80211, mac80211, and the virtual driver mac80211_hwsim. It changes key management callbacks to accept nl80211 key types, adds new netlink attributes (NL80211_ATTR_ASSOC_CIP, NL80211_ATTR_CIP_CAPABILITIES) and flags (NL80211_STA_FLAG_CIP), and alters key addition, lookup, replacement, and rekeying logic. This code is accessible via generic netlink and directly testable in virtual environments using mac80211_hwsim.",
"WorthFuzzing": true
} |
| 1/1 | 2026/09/23 10:50 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 196c10554dabba6bd2ef550968db4912fe03b80f\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Sep 23 10:50:14 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c\nindex 8bbe554a9b364..a9a35476fecd7 100644\n--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c\n+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c\n@@ -1130,13 +1130,15 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,\n }\n \n static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t\t int link_id, u8 key_index,\n+\t\t\t\t enum nl80211_key_type type,\n \t\t\t\t const u8 *mac_addr,\n \t\t\t\t struct key_params *params)\n {\n \tstruct ath6kl *ar = ath6kl_priv(wdev-\u003enetdev);\n \tstruct ath6kl_vif *vif = netdev_priv(wdev-\u003enetdev);\n \tstruct ath6kl_key *key = NULL;\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n \tint seq_len;\n \tu8 key_usage;\n \tu8 key_type;\n@@ -1255,7 +1257,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wde\n }\n \n static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t\t int link_id, u8 key_index,\n+\t\t\t\t enum nl80211_key_type type,\n \t\t\t\t const u8 *mac_addr)\n {\n \tstruct ath6kl *ar = ath6kl_priv(wdev-\u003enetdev);\n@@ -1285,7 +1288,8 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wde\n }\n \n static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t\t int link_id, u8 key_index,\n+\t\t\t\t enum nl80211_key_type type,\n \t\t\t\t const u8 *mac_addr, void *cookie,\n \t\t\t\t void (*callback) (void *cookie,\n \t\t\t\t\t\t struct key_params *))\ndiff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c\nindex 9ac33d827f801..bf060281c9a2c 100644\n--- a/drivers/net/wireless/ath/wil6210/cfg80211.c\n+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c\n@@ -1620,11 +1620,13 @@ static void wil_del_rx_key(u8 key_index, enum wmi_key_usage key_usage,\n \n static int wil_cfg80211_add_key(struct wiphy *wiphy,\n \t\t\t\tstruct wireless_dev *wdev, int link_id,\n-\t\t\t\tu8 key_index, bool pairwise,\n+\t\t\t\tu8 key_index,\n+\t\t\t\tenum nl80211_key_type type,\n \t\t\t\tconst u8 *mac_addr,\n \t\t\t\tstruct key_params *params)\n {\n \tint rc;\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n \tstruct wil6210_priv *wil = wiphy_to_wil(wiphy);\n \tstruct wil6210_vif *vif = wdev_to_vif(wil, wdev);\n \tenum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);\n@@ -1695,12 +1697,14 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,\n \n static int wil_cfg80211_del_key(struct wiphy *wiphy,\n \t\t\t\tstruct wireless_dev *wdev, int link_id,\n-\t\t\t\tu8 key_index, bool pairwise,\n+\t\t\t\tu8 key_index,\n+\t\t\t\tenum nl80211_key_type type,\n \t\t\t\tconst u8 *mac_addr)\n {\n \tstruct wil6210_priv *wil = wiphy_to_wil(wiphy);\n \tstruct wil6210_vif *vif = wdev_to_vif(wil, wdev);\n-\tenum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);\n+\tenum wmi_key_usage key_usage =\n+\t\twil_detect_key_usage(wdev, type == NL80211_KEYTYPE_PAIRWISE);\n \tstruct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif-\u003emid,\n \t\t\t\t\t\t\t key_usage,\n \t\t\t\t\t\t\t mac_addr);\n@@ -2071,7 +2075,8 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)\n \t\tkey_params.seq_len = IEEE80211_GCMP_PN_LEN;\n \t\trc = wil_cfg80211_add_key(wiphy, vif_to_wdev(vif), -1,\n \t\t\t\t\t vif-\u003egtk_index,\n-\t\t\t\t\t false, NULL, \u0026key_params);\n+\t\t\t\t\t NL80211_KEYTYPE_PAIRWISE,\n+\t\t\t\t\t NULL, \u0026key_params);\n \t\tif (rc)\n \t\t\twil_err(wil, \"vif %d recovery add key failed (%d)\\n\",\n \t\t\t\ti, rc);\ndiff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c\nindex 9d8ce7bb046e0..ede76a9e12c87 100644\n--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c\n+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c\n@@ -2802,7 +2802,8 @@ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,\n \n static s32\n brcmf_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t int link_id, u8 key_idx, bool pairwise,\n+\t\t int link_id, u8 key_idx,\n+\t\t enum nl80211_key_type type,\n \t\t const u8 *mac_addr)\n {\n \tstruct brcmf_if *ifp = netdev_priv(wdev-\u003enetdev);\n@@ -2840,7 +2841,8 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n \n static s32\n brcmf_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t int link_id, u8 key_idx, bool pairwise,\n+\t\t int link_id, u8 key_idx,\n+\t\t enum nl80211_key_type type,\n \t\t const u8 *mac_addr, struct key_params *params)\n {\n \tstruct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);\n@@ -2866,7 +2868,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n \n \tif (params-\u003ekey_len == 0)\n \t\treturn brcmf_cfg80211_del_key(wiphy, wdev, -1, key_idx,\n-\t\t\t\t\t pairwise, mac_addr);\n+\t\t\t\t\t type, mac_addr);\n \n \tif (params-\u003ekey_len \u003e sizeof(key-\u003edata)) {\n \t\tbphy_err(drvr, \"Too long key length (%u)\\n\", params-\u003ekey_len);\n@@ -2962,7 +2964,8 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n \n static s32\n brcmf_cfg80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t int link_id, u8 key_idx, bool pairwise,\n+\t\t int link_id, u8 key_idx,\n+\t\t enum nl80211_key_type type,\n \t\t const u8 *mac_addr, void *cookie,\n \t\t void (*callback)(void *cookie,\n \t\t\t\t\tstruct key_params *params))\ndiff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c\nindex 55f9b809e764d..6d8ede336d59b 100644\n--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c\n+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c\n@@ -1138,7 +1138,8 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,\n \t\treturn;\n \n \tkey_config = ieee80211_gtk_rekey_add(vif, key_data-\u003eid, key_data-\u003ekey,\n-\t\t\t\t\t sizeof(key_data-\u003ekey), link_id);\n+\t\t\t\t\t sizeof(key_data-\u003ekey), link_id,\n+\t\t\t\t\t false);\n \tif (IS_ERR(key_config))\n \t\treturn;\n \n@@ -1220,7 +1221,8 @@ static void iwl_mld_mlo_rekey(struct iwl_mld *mld,\n \t\t\t\t mlo_key-\u003eidx, link_id);\n \n \t\tkey = ieee80211_gtk_rekey_add(vif, mlo_key-\u003eidx, mlo_key-\u003ekey,\n-\t\t\t\t\t sizeof(mlo_key-\u003ekey), link_id);\n+\t\t\t\t\t sizeof(mlo_key-\u003ekey), link_id,\n+\t\t\t\t\t false);\n \n \t\tif (IS_ERR(key))\n \t\t\tcontinue;\ndiff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c\nindex 6b11fa32ea5c6..bd52f2ebd3ba1 100644\n--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c\n+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c\n@@ -1887,7 +1887,8 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,\n \n \t\tkey = ieee80211_gtk_rekey_add(vif, status-\u003egtk[i].id,\n \t\t\t\t\t status-\u003egtk[i].key,\n-\t\t\t\t\t sizeof(status-\u003egtk[i].key), -1);\n+\t\t\t\t\t sizeof(status-\u003egtk[i].key), -1,\n+\t\t\t\t\t false);\n \t\tif (IS_ERR(key)) {\n \t\t\t/* FW may send also the old keys */\n \t\t\tif (PTR_ERR(key) == -EALREADY)\n@@ -1922,7 +1923,8 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,\n \t\treturn true;\n \n \tkey_config = ieee80211_gtk_rekey_add(vif, keyidx, key_data-\u003ekey,\n-\t\t\t\t\t sizeof(key_data-\u003ekey), -1);\n+\t\t\t\t\t sizeof(key_data-\u003ekey), -1,\n+\t\t\t\t\t false);\n \tif (IS_ERR(key_config)) {\n \t\t/* FW may send also the old keys */\n \t\treturn PTR_ERR(key_config) == -EALREADY;\ndiff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c\nindex 72c92f72469de..e015cfa1950c1 100644\n--- a/drivers/net/wireless/marvell/libertas/cfg.c\n+++ b/drivers/net/wireless/marvell/libertas/cfg.c\n@@ -1508,7 +1508,8 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,\n \n \n static int lbs_cfg_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 idx, bool pairwise,\n+\t\t\t int link_id, u8 idx,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr, struct key_params *params)\n {\n \tstruct lbs_private *priv = wiphy_priv(wiphy);\n@@ -1569,7 +1570,8 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n \n \n static int lbs_cfg_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t int link_id, u8 key_index,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr)\n {\n \ndiff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c\nindex 293876397b670..1db1017ef76a1 100644\n--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c\n+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c\n@@ -142,12 +142,14 @@ static void *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy)\n */\n static int\n mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t int link_id, u8 key_index,\n+\t\t\tenum nl80211_key_type type,\n \t\t\t const u8 *mac_addr)\n {\n \tstruct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev-\u003enetdev);\n \tstatic const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\n-\tconst u8 *peer_mac = pairwise ? mac_addr : bc_mac;\n+\tconst u8 *peer_mac =\n+\t\t(type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;\n \n \tif (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1)) {\n \t\tmwifiex_dbg(priv-\u003eadapter, ERROR, \"deleting the crypto keys\\n\");\n@@ -480,13 +482,15 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,\n */\n static int\n mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t int link_id, u8 key_index,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr, struct key_params *params)\n {\n \tstruct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev-\u003enetdev);\n \tstruct mwifiex_wep_key *wep_key;\n \tstatic const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\n-\tconst u8 *peer_mac = pairwise ? mac_addr : bc_mac;\n+\tconst u8 *peer_mac =\n+\t\t(type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;\n \n \tif (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP \u0026\u0026\n \t (params-\u003ecipher == WLAN_CIPHER_SUITE_WEP40 ||\ndiff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c\nindex bb2748a193294..651a527f6881e 100644\n--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c\n+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c\n@@ -535,10 +535,13 @@ static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info,\n }\n \n static int add_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n-\t\t u8 key_index, bool pairwise, const u8 *mac_addr,\n+\t\t u8 key_index,\n+\t\t enum nl80211_key_type type,\n+\t\t const u8 *mac_addr,\n \t\t struct key_params *params)\n \n {\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n \tint ret = 0, keylen = params-\u003ekey_len;\n \tconst u8 *rx_mic = NULL;\n \tconst u8 *tx_mic = NULL;\n@@ -641,9 +644,10 @@ static int add_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n \n static int del_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n \t\t u8 key_index,\n-\t\t bool pairwise,\n+\t\t enum nl80211_key_type type,\n \t\t const u8 *mac_addr)\n {\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n \tstruct wilc_vif *vif = netdev_priv(wdev-\u003enetdev);\n \tstruct wilc_priv *priv = \u0026vif-\u003epriv;\n \n@@ -681,10 +685,11 @@ static int del_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n }\n \n static int get_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n-\t\t u8 key_index, bool pairwise, const u8 *mac_addr,\n-\t\t void *cookie,\n+\t\t u8 key_index, enum nl80211_key_type type,\n+\t\t const u8 *mac_addr, void *cookie,\n \t\t void (*callback)(void *cookie, struct key_params *))\n {\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n \tstruct wilc_vif *vif = netdev_priv(wdev-\u003enetdev);\n \tstruct wilc_priv *priv = \u0026vif-\u003epriv;\n \tstruct key_params key_params;\ndiff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c\nindex 5cc8cdf594d3e..d4233f5a31dfa 100644\n--- a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c\n+++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c\n@@ -99,12 +99,14 @@ static void *nxpwifi_cfg80211_get_adapter(struct wiphy *wiphy)\n /* cfg80211 operation handler to delete a network key. */\n static int\n nxpwifi_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t int link_id, u8 key_index,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr)\n {\n \tstruct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev-\u003enetdev);\n \tstatic const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\n-\tconst u8 *peer_mac = pairwise ? mac_addr : bc_mac;\n+\tconst u8 *peer_mac =\n+\t\t(type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;\n \tint ret;\n \n \tret = nxpwifi_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1);\n@@ -426,7 +428,8 @@ nxpwifi_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,\n /* cfg80211 handler for adding an 802.11 encryption key. */\n static int\n nxpwifi_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t int link_id, u8 key_index,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr, struct key_params *params)\n {\n \tstruct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev-\u003enetdev);\n@@ -436,7 +439,7 @@ nxpwifi_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n \tint ret;\n \n \teth_broadcast_addr(bc_mac);\n-\tpeer_mac = pairwise ? mac_addr : bc_mac;\n+\tpeer_mac = (type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;\n \n \tif (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP \u0026\u0026\n \t (params-\u003ecipher == WLAN_CIPHER_SUITE_WEP40 ||\ndiff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c\nindex 45e2b7ae96333..d9c84d5ce2548 100644\n--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c\n+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c\n@@ -531,10 +531,12 @@ qtnf_dump_station(struct wiphy *wiphy, struct wireless_dev *wdev,\n }\n \n static int qtnf_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\tint link_id, u8 key_index, bool pairwise,\n+\t\t\tint link_id, u8 key_index,\n+\t\t\tenum nl80211_key_type type,\n \t\t\tconst u8 *mac_addr, struct key_params *params)\n {\n \tstruct qtnf_vif *vif = qtnf_netdev_get_priv(wdev-\u003enetdev);\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n \tint ret;\n \n \tret = qtnf_cmd_send_add_key(vif, key_index, pairwise, mac_addr, params);\n@@ -547,10 +549,12 @@ static int qtnf_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n }\n \n static int qtnf_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\tint link_id, u8 key_index, bool pairwise,\n+\t\t\tint link_id, u8 key_index,\n+\t\t\tenum nl80211_key_type type,\n \t\t\tconst u8 *mac_addr)\n {\n \tstruct qtnf_vif *vif = qtnf_netdev_get_priv(wdev-\u003enetdev);\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n \tint ret;\n \n \tret = qtnf_cmd_send_del_key(vif, key_index, pairwise, mac_addr);\ndiff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c\nindex 2dfa24c54e7d7..2e37e1fafbef5 100644\n--- a/drivers/net/wireless/realtek/rtw89/wow.c\n+++ b/drivers/net/wireless/realtek/rtw89/wow.c\n@@ -669,10 +669,12 @@ static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev,\n \tif (ieee80211_vif_is_mld(wow_vif))\n \t\tkey = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk,\n \t\t\t\t\t cipher_info-\u003elen,\n-\t\t\t\t\t rtwvif_link-\u003elink_id);\n+\t\t\t\t\t rtwvif_link-\u003elink_id,\n+\t\t\t\t\t false);\n \telse\n \t\tkey = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk,\n-\t\t\t\t\t cipher_info-\u003elen, -1);\n+\t\t\t\t\t cipher_info-\u003elen, -1,\n+\t\t\t\t\t false);\n \n \tkfree(rekey_conf);\n \tif (IS_ERR(key)) {\ndiff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c\nindex 1a12261f3e8e5..0cf9ef8959e1b 100644\n--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c\n+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c\n@@ -5645,6 +5645,14 @@ static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband)\n \t BIT(NL80211_IFTYPE_MESH_POINT) | \\\n \t BIT(NL80211_IFTYPE_OCB))\n \n+static const u8 iftypes_ext_capa[] = {\n+\t [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,\n+\t [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,\n+\t [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF |\n+\t WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB,\n+\t [8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB,\n+};\n+\n static const u8 iftypes_ext_capa_ap[] = {\n \t [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,\n \t [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,\n@@ -5669,6 +5677,33 @@ static const struct wiphy_iftype_ext_capab mac80211_hwsim_iftypes_ext_capa[] = {\n \t\t.eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP |\n \t\t\t\t IEEE80211_EML_CAP_EMLMR_SUPPORT,\n \t\t.mld_capa_and_ops = MAC80211_HWSIM_MLD_CAPA_OPS,\n+\t\t/* CIP works as hwsim does not have control frames */\n+\t\t.cip_supported = true,\n+\t\t.cip_capabilities = 0,\n+\t},\n+\t{\n+\t\t.iftype = NL80211_IFTYPE_STATION,\n+\t\t.extended_capabilities = iftypes_ext_capa,\n+\t\t.extended_capabilities_mask = iftypes_ext_capa,\n+\t\t.extended_capabilities_len = sizeof(iftypes_ext_capa),\n+\t\t.cip_supported = true,\n+\t\t.cip_capabilities = 0,\n+\t},\n+\t{\n+\t\t.iftype = NL80211_IFTYPE_P2P_CLIENT,\n+\t\t.extended_capabilities = iftypes_ext_capa,\n+\t\t.extended_capabilities_mask = iftypes_ext_capa,\n+\t\t.extended_capabilities_len = sizeof(iftypes_ext_capa),\n+\t\t.cip_supported = true,\n+\t\t.cip_capabilities = 0,\n+\t},\n+\t{\n+\t\t.iftype = NL80211_IFTYPE_P2P_GO,\n+\t\t.extended_capabilities = iftypes_ext_capa,\n+\t\t.extended_capabilities_mask = iftypes_ext_capa,\n+\t\t.extended_capabilities_len = sizeof(iftypes_ext_capa),\n+\t\t.cip_supported = true,\n+\t\t.cip_capabilities = 0,\n \t},\n };\n \ndiff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c\nindex 3468d4114f604..be233a471b433 100644\n--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c\n+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c\n@@ -825,7 +825,8 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param\n }\n \n static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t\tint link_id, u8 key_index, bool pairwise,\n+\t\t\t\tint link_id, u8 key_index,\n+\t\t\t\tenum nl80211_key_type type,\n \t\t\t\tconst u8 *mac_addr, struct key_params *params)\n {\n \tchar *alg_name;\n@@ -904,7 +905,8 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n }\n \n static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t\tint link_id, u8 key_index, bool pairwise,\n+\t\t\t\tint link_id, u8 key_index,\n+\t\t\t\tenum nl80211_key_type type,\n \t\t\t\tconst u8 *mac_addr, void *cookie,\n \t\t\t\tvoid (*callback)(void *cookie,\n \t\t\t\t\t\t struct key_params*))\n@@ -913,7 +915,8 @@ static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n }\n \n static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t\tint link_id, u8 key_index, bool pairwise,\n+\t\t\t\tint link_id, u8 key_index,\n+\t\t\t\tenum nl80211_key_type type,\n \t\t\t\tconst u8 *mac_addr)\n {\n \tstruct adapter *padapter = rtw_netdev_priv(wdev-\u003enetdev);\ndiff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h\nindex 7fbc51f873ff1..73ac5336a17ad 100644\n--- a/include/linux/ieee80211.h\n+++ b/include/linux/ieee80211.h\n@@ -1828,6 +1828,7 @@ enum ieee80211_eid_ext {\n \tWLAN_EID_EXT_BANDWIDTH_INDICATION = 135,\n \tWLAN_EID_EXT_KNOWN_STA_IDENTIFCATION = 136,\n \tWLAN_EID_EXT_NON_AP_STA_REG_CON = 137,\n+\tWLAN_EID_EXT_CIP_CAPA = 150,\n \tWLAN_EID_EXT_UHR_OPER = 151,\n \tWLAN_EID_EXT_UHR_CAPA = 152,\n \tWLAN_EID_EXT_MACP = 153,\n@@ -2899,4 +2900,25 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,\n \t\t __ieee80211_check_tim(tim, tim_len, aid);\n }\n \n+/**\n+ * enum ieee80211_cip_cap_fields - CIP Capabilities element fields\n+ * @IEEE80211_CIP_CAP_MIC_PADDING: The MIC padding subfield in the CIP\n+ *\tcapabilities\n+ * @IEEE80211_CIP_CAP_PROTECTED_CTRL_FRAME_ONLY: The MIC Padding For Protected\n+ *\tControl Frames Only bit in CIP capabilities\n+ */\n+enum ieee80211_cip_cap_fields {\n+\tIEEE80211_CIP_CAP_MIC_PADDING\t\t\t= 0x0F,\n+\tIEEE80211_CIP_CAP_PROTECTED_CTRL_FRAME_ONLY\t= 0x10,\n+};\n+\n+/**\n+ * struct ieee80211_cip_cap - CIP Capabilities element\n+ *\n+ * @v: The value of the Control Integrity Protocol Capability element\n+ */\n+struct ieee80211_cip_cap {\n+\tu8 v;\n+} __packed;\n+\n #endif /* LINUX_IEEE80211_H */\ndiff --git a/include/net/cfg80211.h b/include/net/cfg80211.h\nindex 9aa7d2d4a1841..1ef5f85a93764 100644\n--- a/include/net/cfg80211.h\n+++ b/include/net/cfg80211.h\n@@ -1821,6 +1821,8 @@ struct sta_txpwr {\n * @s1g_capa: S1G capabilities of station\n * @uhr_capa: UHR capabilities of the station\n * @uhr_capa_len: the length of the UHR capabilities\n+ * @cip_cap_set: If CIP capabilities are present, required for CIP stations\n+ * @cip_cap: CIP capabilities of station\n */\n struct link_station_parameters {\n \tconst u8 *mld_mac;\n@@ -1842,6 +1844,8 @@ struct link_station_parameters {\n \tconst struct ieee80211_s1g_cap *s1g_capa;\n \tconst struct ieee80211_uhr_cap *uhr_capa;\n \tu8 uhr_capa_len;\n+\tbool cip_cap_set;\n+\tu8 cip_cap;\n };\n \n /**\n@@ -3402,6 +3406,7 @@ struct cfg80211_ml_reconf_req {\n *\tflag is not set.\n * @ASSOC_REQ_SPP_AMSDU: SPP A-MSDUs will be used on this connection (if any)\n * @ASSOC_REQ_DISABLE_UHR: Disable UHR\n+ * @ASSOC_REQ_CIP: Enable Control Integrity Protocol\n */\n enum cfg80211_assoc_req_flags {\n \tASSOC_REQ_DISABLE_HT\t\t\t= BIT(0),\n@@ -3413,6 +3418,7 @@ enum cfg80211_assoc_req_flags {\n \tCONNECT_REQ_MLO_SUPPORT\t\t\t= BIT(6),\n \tASSOC_REQ_SPP_AMSDU\t\t\t= BIT(7),\n \tASSOC_REQ_DISABLE_UHR\t\t\t= BIT(8),\n+\tASSOC_REQ_CIP\t\t\t\t= BIT(9),\n };\n \n /**\n@@ -5304,14 +5310,17 @@ struct cfg80211_ops {\n \t\t\t\t unsigned int link_id);\n \n \tint\t(*add_key)(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t int link_id, u8 key_index,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr, struct key_params *params);\n \tint\t(*get_key)(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t int link_id, u8 key_index,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr, void *cookie,\n \t\t\t void (*callback)(void *cookie, struct key_params*));\n \tint\t(*del_key)(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_index, bool pairwise,\n+\t\t\t int link_id, u8 key_index,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr);\n \tint\t(*set_default_key)(struct wiphy *wiphy,\n \t\t\t\t struct net_device *netdev, int link_id,\n@@ -6045,6 +6054,8 @@ struct wiphy_vendor_command {\n * @eml_capabilities: EML capabilities (for MLO)\n * @mld_capa_and_ops: MLD capabilities and operations (for MLO)\n * @ext_mld_capa_and_ops: Extended MLD capabilities and operations (for MLO)\n+ * @cip_supported: CIP is supported and the capabilities are valid\n+ * @cip_capabilities: CIP Capabilities element containing the MIC padding delay\n */\n struct wiphy_iftype_ext_capab {\n \tenum nl80211_iftype iftype;\n@@ -6054,6 +6065,8 @@ struct wiphy_iftype_ext_capab {\n \tu16 eml_capabilities;\n \tu16 mld_capa_and_ops;\n \tu16 ext_mld_capa_and_ops;\n+\tbool cip_supported;\n+\tu8 cip_capabilities;\n };\n \n /**\ndiff --git a/include/net/mac80211.h b/include/net/mac80211.h\nindex 1172d7b83ed18..15ac95048ce58 100644\n--- a/include/net/mac80211.h\n+++ b/include/net/mac80211.h\n@@ -2395,6 +2395,8 @@ static inline bool lockdep_vif_wiphy_mutex_held(struct ieee80211_vif *vif)\n *\tnumber generation only\n * @IEEE80211_KEY_FLAG_SPP_AMSDU: SPP A-MSDUs can be used with this key\n *\t(set by mac80211 from the sta-\u003espp_amsdu flag)\n+ * @IEEE80211_KEY_FLAG_CIP: This key is used for the Control Integrity\n+ *\tProtocol, and is either a pairwise key or a CIGTK.\n */\n enum ieee80211_key_flags {\n \tIEEE80211_KEY_FLAG_GENERATE_IV_MGMT\t= BIT(0),\n@@ -2409,6 +2411,7 @@ enum ieee80211_key_flags {\n \tIEEE80211_KEY_FLAG_NO_AUTO_TX\t\t= BIT(9),\n \tIEEE80211_KEY_FLAG_GENERATE_MMIE\t= BIT(10),\n \tIEEE80211_KEY_FLAG_SPP_AMSDU\t\t= BIT(11),\n+\tIEEE80211_KEY_FLAG_CIP\t\t\t= BIT(12),\n };\n \n /**\n@@ -2629,6 +2632,7 @@ struct ieee80211_sta_aggregates {\n * @eht_cap: EHT capabilities of this STA\n * @uhr_cap: UHR capabilities of this STA\n * @s1g_cap: S1G capabilities of this STA\n+ * @cip_cap: the CIP capabilities of this STA (or zero)\n * @agg: per-link data for multi-link aggregation\n * @bandwidth: current bandwidth the station can receive with.\n *\tThis is the minimum between the peer's capabilities and our own\n@@ -2657,6 +2661,7 @@ struct ieee80211_link_sta {\n \tstruct ieee80211_sta_eht_cap eht_cap;\n \tstruct ieee80211_sta_uhr_cap uhr_cap;\n \tstruct ieee80211_sta_s1g_cap s1g_cap;\n+\tu8 cip_cap;\n \n \tstruct ieee80211_sta_aggregates agg;\n \n@@ -2720,6 +2725,7 @@ struct ieee80211_link_sta {\n * @valid_links: bitmap of valid links, or 0 for non-MLO\n * @spp_amsdu: indicates whether the STA uses SPP A-MSDU or not.\n * @epp_peer: indicates that the peer is an EPP peer.\n+ * @cip: indicates whether the STA uses control frame protection or not.\n * @nmi: For NDI stations, pointer to the NMI station of the peer.\n * @nan_sched: NAN peer schedule for this station. Valid only for NMI stations.\n * @ext_mld_capa_ops: the MLD's extended MLD capabilities and operations\n@@ -2741,6 +2747,8 @@ struct ieee80211_sta {\n \tu8 max_amsdu_subframes;\n \tu16 eml_cap;\n \n+\tbool cip;\n+\n \tstruct ieee80211_sta_aggregates *cur;\n \n \tbool support_p2p_ps;\n@@ -6278,6 +6286,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,\n * @key_len: the key data. Might be bigger than the actual key length,\n *\tbut not smaller (for the driver convinence)\n * @link_id: the link id of the key or -1 for non-MLO\n+ * @cigtk: whether this is a CIGTK\n *\n * When GTK rekeying was done while the system was suspended, (a) new\n * key(s) will be available. These will be needed by mac80211 for proper\n@@ -6304,7 +6313,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,\n struct ieee80211_key_conf *\n ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,\n \t\t\tu8 idx, u8 *key_data, u8 key_len,\n-\t\t\tint link_id);\n+\t\t\tint link_id, bool cigtk);\n \n /**\n * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying\ndiff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h\nindex 9a2ccb8d66b86..843d1dbb725d9 100644\n--- a/include/uapi/linux/nl80211.h\n+++ b/include/uapi/linux/nl80211.h\n@@ -3190,6 +3190,11 @@ enum nl80211_commands {\n *\tknown station to transmit a frame. This is relevant to know whether\n *\tMLD address translation happened or to disable it when sending a frame.\n *\n+ * @NL80211_ATTR_ASSOC_CIP: Enable Control Integrity Protocol for the\n+ *\tassociation\n+ * @NL80211_ATTR_CIP_CAPABILITIES: The Control Integrity Protocol for the\n+ *\tstation.\n+ *\n * @NUM_NL80211_ATTR: total number of nl80211_attrs available\n * @NL80211_ATTR_MAX: highest attribute number currently defined\n * @__NL80211_ATTR_AFTER_LAST: internal use\n@@ -3792,6 +3797,9 @@ enum nl80211_attrs {\n \n \tNL80211_ATTR_FRAME_NO_STA,\n \n+\tNL80211_ATTR_ASSOC_CIP,\n+\tNL80211_ATTR_CIP_CAPABILITIES,\n+\n \t/* add attributes here, update the policy in nl80211.c */\n \n \t__NL80211_ATTR_AFTER_LAST,\n@@ -3942,6 +3950,7 @@ enum nl80211_iftype {\n *\tthat support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a\n *\tpreviously added station into associated state\n * @NL80211_STA_FLAG_SPP_AMSDU: station supports SPP A-MSDUs\n+ * @NL80211_STA_FLAG_CIP: station has Control Integrity Protocol (CIP) enabled\n * @NL80211_STA_FLAG_MAX: highest station flag number currently defined\n * @__NL80211_STA_FLAG_AFTER_LAST: internal use\n */\n@@ -3955,6 +3964,7 @@ enum nl80211_sta_flags {\n \tNL80211_STA_FLAG_TDLS_PEER,\n \tNL80211_STA_FLAG_ASSOCIATED,\n \tNL80211_STA_FLAG_SPP_AMSDU,\n+\tNL80211_STA_FLAG_CIP,\n \n \t/* keep last */\n \t__NL80211_STA_FLAG_AFTER_LAST,\n@@ -5786,12 +5796,16 @@ enum nl80211_auth_type {\n * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key\n * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key\n * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)\n+ * @NL80211_KEYTYPE_CIGTK: Control Integrity Group Temporal Key\n+ *\tThe cipher is GMAC-256 but passed as GCMP-256,\n+ *\tsame as the pairwise key when used for CIP.\n * @NUM_NL80211_KEYTYPES: number of defined key types\n */\n enum nl80211_key_type {\n \tNL80211_KEYTYPE_GROUP,\n \tNL80211_KEYTYPE_PAIRWISE,\n \tNL80211_KEYTYPE_PEERKEY,\n+\tNL80211_KEYTYPE_CIGTK,\n \n \tNUM_NL80211_KEYTYPES\n };\ndiff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c\nindex 23f4f9ec86d0a..3714f8ccdf82d 100644\n--- a/net/mac80211/cfg.c\n+++ b/net/mac80211/cfg.c\n@@ -611,12 +611,15 @@ static int ieee80211_set_tx(struct ieee80211_sub_if_data *sdata,\n }\n \n static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_idx, bool pairwise,\n+\t\t\t int link_id, u8 key_idx,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr, struct key_params *params)\n {\n \tstruct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);\n \tstruct ieee80211_link_data *link =\n \t\tieee80211_link_or_deflink(sdata, link_id, false);\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n+\tbool cigtk = type == NL80211_KEYTYPE_CIGTK;\n \tstruct ieee80211_local *local = sdata-\u003elocal;\n \tstruct sta_info *sta = NULL;\n \tstruct ieee80211_key *key;\n@@ -660,6 +663,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n \t\tkey-\u003econf.link_id = -1;\n \t} else {\n \t\tkey-\u003econf.link_id = link-\u003elink_id;\n+\n+\t\tif (cigtk)\n+\t\t\tkey-\u003econf.flags |= IEEE80211_KEY_FLAG_CIP;\n \t}\n \n \tif (params-\u003emode == NL80211_KEY_NO_TX)\n@@ -737,10 +743,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n \n static struct ieee80211_key *\n ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,\n-\t\t u8 key_idx, bool pairwise, const u8 *mac_addr)\n+\t\t u8 key_idx, enum nl80211_key_type type,\n+\t\t const u8 *mac_addr)\n {\n \tstruct ieee80211_local *local __maybe_unused = sdata-\u003elocal;\n \tstruct ieee80211_link_data *link = \u0026sdata-\u003edeflink;\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n+\tbool cigtk = type == NL80211_KEYTYPE_CIGTK;\n \tstruct ieee80211_key *key;\n \n \tif (link_id \u003e= 0) {\n@@ -770,7 +779,11 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,\n \t\t\treturn wiphy_dereference(local-\u003ehw.wiphy,\n \t\t\t\t\t\t sta-\u003eptk[key_idx]);\n \n-\t\tif (!pairwise \u0026\u0026\n+\t\tif (cigtk \u0026\u0026 key_idx \u003c NUM_CTRL_KEYS)\n+\t\t\treturn wiphy_dereference(local-\u003ehw.wiphy,\n+\t\t\t\t\t\t link_sta-\u003ecigtk[key_idx]);\n+\n+\t\tif (!pairwise \u0026\u0026 !cigtk \u0026\u0026\n \t\t key_idx \u003c NUM_DEFAULT_KEYS +\n \t\t\t NUM_DEFAULT_MGMT_KEYS +\n \t\t\t NUM_DEFAULT_BEACON_KEYS)\n@@ -783,6 +796,9 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,\n \tif (pairwise \u0026\u0026 key_idx \u003c NUM_DEFAULT_KEYS)\n \t\treturn wiphy_dereference(local-\u003ehw.wiphy, sdata-\u003ekeys[key_idx]);\n \n+\tif (cigtk)\n+\t\treturn wiphy_dereference(local-\u003ehw.wiphy, link-\u003ecigtk[key_idx]);\n+\n \tkey = wiphy_dereference(local-\u003ehw.wiphy, link-\u003egtk[key_idx]);\n \tif (key)\n \t\treturn key;\n@@ -795,8 +811,8 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,\n }\n \n static int ieee80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_idx, bool pairwise,\n-\t\t\t const u8 *mac_addr)\n+\t\t\t int link_id, u8 key_idx,\n+\t\t\t enum nl80211_key_type type, const u8 *mac_addr)\n {\n \tstruct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);\n \tstruct ieee80211_local *local = sdata-\u003elocal;\n@@ -804,7 +820,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n \n \tlockdep_assert_wiphy(local-\u003ehw.wiphy);\n \n-\tkey = ieee80211_lookup_key(sdata, link_id, key_idx, pairwise, mac_addr);\n+\tkey = ieee80211_lookup_key(sdata, link_id, key_idx, type, mac_addr);\n \tif (!key)\n \t\treturn -ENOENT;\n \n@@ -814,7 +830,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n }\n \n static int ieee80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n-\t\t\t int link_id, u8 key_idx, bool pairwise,\n+\t\t\t int link_id, u8 key_idx,\n+\t\t\t enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr, void *cookie,\n \t\t\t void (*callback)(void *cookie,\n \t\t\t\t\t struct key_params *params))\n@@ -833,7 +850,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n \n \trcu_read_lock();\n \n-\tkey = ieee80211_lookup_key(sdata, link_id, key_idx, pairwise, mac_addr);\n+\tkey = ieee80211_lookup_key(sdata, link_id, key_idx, type, mac_addr);\n \tif (!key)\n \t\tgoto out;\n \n@@ -2289,6 +2306,8 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,\n \tcase STA_LINK_MODE_NEW:\n \t\tif (!params-\u003elink_mac)\n \t\t\treturn -EINVAL;\n+\t\tif (sta-\u003esta.cip \u0026\u0026 !params-\u003ecip_cap_set)\n+\t\t\treturn -EINVAL;\n \t\tbreak;\n \tcase STA_LINK_MODE_LINK_MODIFY:\n \t\tbreak;\n@@ -2411,6 +2430,9 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,\n \t\tieee80211_s1g_cap_to_sta_s1g_cap(sdata, params-\u003es1g_capa,\n \t\t\t\t\t\t link_sta);\n \n+\tif (params-\u003ecip_cap_set)\n+\t\tlink_sta-\u003epub-\u003ecip_cap = params-\u003ecip_cap;\n+\n \tswitch (sdata-\u003evif.type) {\n \tcase NL80211_IFTYPE_NAN:\n \tcase NL80211_IFTYPE_NAN_DATA:\n@@ -2573,6 +2595,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,\n \tif (params-\u003eeml_cap_present)\n \t\tsta-\u003esta.eml_cap = params-\u003eeml_cap;\n \n+\tif (params-\u003esta_flags_set \u0026 BIT(NL80211_STA_FLAG_CIP))\n+\t\tsta-\u003esta.cip = true;\n+\n \tret = sta_link_apply_parameters(local, sta, STA_LINK_MODE_STA_MODIFY,\n \t\t\t\t\t\u0026params-\u003elink_sta_params);\n \tif (ret)\ndiff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c\nindex 117f58af5ff9d..3a4f8e9e54dc1 100644\n--- a/net/mac80211/debugfs_key.c\n+++ b/net/mac80211/debugfs_key.c\n@@ -4,7 +4,7 @@\n * Copyright (c) 2006\tJiri Benc \u003cjbenc@suse.cz\u003e\n * Copyright 2007\tJohannes Berg \u003cjohannes@sipsolutions.net\u003e\n * Copyright (C) 2015\tIntel Deutschland GmbH\n- * Copyright (C) 2021-2023 Intel Corporation\n+ * Copyright (C) 2021-2023, 2026 Intel Corporation\n */\n \n #include \u003clinux/kobject.h\u003e\n@@ -42,9 +42,10 @@ static const struct debugfs_short_fops key_ ##name## _ops = {\t\t\\\n \t\t KEY_READ_##format(name)\t\t\t\t\\\n \t\t KEY_OPS(name)\n \n-#define KEY_CONF_READ(name, format_string)\t\t\t\t\\\n-\tKEY_READ(conf_##name, conf.name, format_string)\n-#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, \"%d\\n\")\n+#define KEY_CONF_READ(name, val, format_string)\t\t\t\t\\\n+\tKEY_READ(conf_##name, conf.val, format_string)\n+#define KEY_CONF_READ_D(name, val) KEY_CONF_READ(name, val, \"%d\\n\")\n+#define KEY_CONF_READ_X(name, val) KEY_CONF_READ(name, val, \"0x%x\\n\")\n \n #define KEY_CONF_OPS(name)\t\t\t\t\t\t\\\n static const struct debugfs_short_fops key_ ##name## _ops = {\t\t\\\n@@ -53,13 +54,18 @@ static const struct debugfs_short_fops key_ ##name## _ops = {\t\t\\\n }\n \n #define KEY_CONF_FILE(name, format)\t\t\t\t\t\\\n-\t\t KEY_CONF_READ_##format(name)\t\t\t\t\\\n+\t\t KEY_CONF_READ_##format(name, name)\t\t\t\\\n+\t\t KEY_CONF_OPS(name)\n+#define KEY_CONF_FILE_NAMED(name, val, format)\t\t\t\t\\\n+\t\t KEY_CONF_READ_##format(name, val)\t\t\t\\\n \t\t KEY_CONF_OPS(name)\n \n KEY_CONF_FILE(keylen, D);\n KEY_CONF_FILE(keyidx, D);\n KEY_CONF_FILE(hw_key_idx, D);\n+KEY_CONF_FILE_NAMED(conf_flags, flags, X);\n KEY_FILE(flags, X);\n+KEY_CONF_FILE(link_id, D);\n KEY_READ(ifindex, sdata-\u003ename, \"%s\\n\");\n KEY_OPS(ifindex);\n \n@@ -356,6 +362,8 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key)\n \tDEBUGFS_ADD(mic_failures);\n \tDEBUGFS_ADD(key);\n \tDEBUGFS_ADD(ifindex);\n+\tDEBUGFS_ADD(conf_flags);\n+\tDEBUGFS_ADD(link_id);\n };\n \n void ieee80211_debugfs_key_remove(struct ieee80211_key *key)\ndiff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h\nindex 9514f01778beb..66231ea8a985d 100644\n--- a/net/mac80211/ieee80211_i.h\n+++ b/net/mac80211/ieee80211_i.h\n@@ -486,6 +486,7 @@ struct ieee80211_mgd_assoc_data {\n \tbool comeback; /* whether the AP has requested association comeback */\n \tbool s1g;\n \tbool spp_amsdu;\n+\tbool cip;\n \n \ts8 assoc_link_id;\n \n@@ -1113,6 +1114,7 @@ struct ieee80211_link_data {\n \tstruct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +\n \t\t\t\t\tNUM_DEFAULT_MGMT_KEYS +\n \t\t\t\t\tNUM_DEFAULT_BEACON_KEYS];\n+\tstruct ieee80211_key __rcu *cigtk[NUM_CTRL_KEYS];\n \tstruct ieee80211_key __rcu *default_multicast_key;\n \tstruct ieee80211_key __rcu *default_mgmt_key;\n \tstruct ieee80211_key __rcu *default_beacon_key;\n@@ -1878,6 +1880,7 @@ struct ieee802_11_elems {\n \tconst struct ieee80211_ttlm_elem *ttlm[IEEE80211_TTLM_MAX_CNT];\n \tconst struct ieee80211_uhr_cap *uhr_cap;\n \tconst struct ieee80211_uhr_operation *uhr_operation;\n+\tconst struct ieee80211_cip_cap *cip_cap;\n \n \t/* not the order in the psd values is per element, not per chandef */\n \tstruct ieee80211_parsed_tpe tpe;\n@@ -2778,6 +2781,8 @@ int ieee80211_put_uhr_cap(struct sk_buff *skb,\n \t\t\t const struct ieee80211_supported_band *sband);\n void ieee80211_put_reg_conn(struct ieee80211_sub_if_data *sdata,\n \t\t\t struct sk_buff *skb);\n+int ieee80211_put_cip_cap(struct sk_buff *skb,\n+\t\t\t struct ieee80211_sub_if_data *sdata);\n \n /* channel management */\n bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,\ndiff --git a/net/mac80211/key.c b/net/mac80211/key.c\nindex f45e792abede5..4c9788ec0b74f 100644\n--- a/net/mac80211/key.c\n+++ b/net/mac80211/key.c\n@@ -205,6 +205,10 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)\n \t\t\t sta ? sta-\u003esta.addr : bcast_addr, ret);\n \n out_unsupported:\n+\t/* Control Integrity Protocol can only be done in hardware */\n+\tif (key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_CIP)\n+\t\treturn -EINVAL;\n+\n \tswitch (key-\u003econf.cipher) {\n \tcase WLAN_CIPHER_SUITE_WEP40:\n \tcase WLAN_CIPHER_SUITE_WEP104:\n@@ -440,11 +444,13 @@ void ieee80211_set_default_beacon_key(struct ieee80211_link_data *link,\n static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,\n \t\t\t\t struct ieee80211_link_data *link,\n \t\t\t\t struct sta_info *sta,\n-\t\t\t\t bool pairwise,\n+\t\t\t\t enum ieee80211_key_flags flags,\n \t\t\t\t struct ieee80211_key *old,\n \t\t\t\t struct ieee80211_key *new)\n {\n \tstruct link_sta_info *link_sta = sta ? \u0026sta-\u003edeflink : NULL;\n+\tbool pairwise = flags \u0026 IEEE80211_KEY_FLAG_PAIRWISE;\n+\tbool cip = flags \u0026 IEEE80211_KEY_FLAG_CIP;\n \tint link_id;\n \tint idx;\n \tint ret = 0;\n@@ -535,6 +541,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,\n \t\t\tif (new \u0026\u0026\n \t\t\t !(new-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_NO_AUTO_TX))\n \t\t\t\t_ieee80211_set_tx_key(new, true);\n+\t\t} else if (cip) {\n+\t\t\trcu_assign_pointer(link_sta-\u003ecigtk[idx], new);\n \t\t} else {\n \t\t\trcu_assign_pointer(link_sta-\u003egtk[idx], new);\n \t\t}\n@@ -569,6 +577,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,\n \n \t\tif (is_wep || pairwise)\n \t\t\trcu_assign_pointer(sdata-\u003ekeys[idx], new);\n+\t\telse if (cip)\n+\t\t\trcu_assign_pointer(link-\u003ecigtk[idx], new);\n \t\telse\n \t\t\trcu_assign_pointer(link-\u003egtk[idx], new);\n \n@@ -883,6 +893,10 @@ int ieee80211_key_link(struct ieee80211_key *key,\n \t\t\tret = -EOPNOTSUPP;\n \t\t\tgoto out;\n \t\t}\n+\n+\t\t/* Set CIP flag if enabled for the station */\n+\t\tif (sta-\u003esta.cip)\n+\t\t\tkey-\u003econf.flags |= IEEE80211_KEY_FLAG_CIP;\n \t} else if (sta) {\n \t\tstruct link_sta_info *link_sta = \u0026sta-\u003edeflink;\n \t\tint link_id = key-\u003econf.link_id;\n@@ -896,15 +910,25 @@ int ieee80211_key_link(struct ieee80211_key *key,\n \t\t\t}\n \t\t}\n \n-\t\told_key = wiphy_dereference(sdata-\u003elocal-\u003ehw.wiphy,\n-\t\t\t\t\t link_sta-\u003egtk[idx]);\n-\t} else {\n-\t\tif (idx \u003c NUM_DEFAULT_KEYS)\n+\t\tif (key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_CIP)\n \t\t\told_key = wiphy_dereference(sdata-\u003elocal-\u003ehw.wiphy,\n-\t\t\t\t\t\t sdata-\u003ekeys[idx]);\n-\t\tif (!old_key)\n+\t\t\t\t\t\t link_sta-\u003ecigtk[idx]);\n+\t\telse\n \t\t\told_key = wiphy_dereference(sdata-\u003elocal-\u003ehw.wiphy,\n-\t\t\t\t\t\t link-\u003egtk[idx]);\n+\t\t\t\t\t\t link_sta-\u003egtk[idx]);\n+\t} else {\n+\t\tif (key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_CIP) {\n+\t\t\told_key = wiphy_dereference(sdata-\u003elocal-\u003ehw.wiphy,\n+\t\t\t\t\t\t link-\u003ecigtk[idx]);\n+\t\t} else {\n+\t\t\tif (idx \u003c NUM_DEFAULT_KEYS)\n+\t\t\t\told_key = wiphy_dereference(sdata-\u003elocal-\u003ehw.wiphy,\n+\t\t\t\t\t\t\t sdata-\u003ekeys[idx]);\n+\n+\t\t\tif (!old_key)\n+\t\t\t\told_key = wiphy_dereference(sdata-\u003elocal-\u003ehw.wiphy,\n+\t\t\t\t\t\t\t link-\u003egtk[idx]);\n+\t\t}\n \t}\n \n \t/* Non-pairwise keys must also not switch the cipher on rekey */\n@@ -938,9 +962,17 @@ int ieee80211_key_link(struct ieee80211_key *key,\n \tif (sta \u0026\u0026 sta-\u003esta.spp_amsdu)\n \t\tkey-\u003econf.flags |= IEEE80211_KEY_FLAG_SPP_AMSDU;\n \n+\t/* A CIP related key must be GCMP-256 (really GMAC-256) */\n+\tif ((key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_CIP) \u0026\u0026\n+\t key-\u003econf.cipher != WLAN_CIPHER_SUITE_GCMP_256) {\n+\t\tret = -EINVAL;\n+\t\tgoto out;\n+\t}\n+\n \tincrement_tailroom_need_count(sdata);\n \n-\tret = ieee80211_key_replace(sdata, link, sta, pairwise, old_key, key);\n+\tret = ieee80211_key_replace(sdata, link, sta, key-\u003econf.flags,\n+\t\t\t\t old_key, key);\n \n \tif (!ret) {\n \t\tieee80211_debugfs_key_add(key);\n@@ -966,8 +998,7 @@ void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)\n \t */\n \tif (key-\u003esdata)\n \t\tieee80211_key_replace(key-\u003esdata, NULL, key-\u003esta,\n-\t\t\t\t key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_PAIRWISE,\n-\t\t\t\t key, NULL);\n+\t\t\t\t key-\u003econf.flags, key, NULL);\n \tieee80211_key_destroy(key, delay_tailroom);\n }\n \n@@ -1098,8 +1129,7 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,\n \n \tlist_for_each_entry_safe(key, tmp, \u0026sdata-\u003ekey_list, list) {\n \t\tieee80211_key_replace(key-\u003esdata, NULL, key-\u003esta,\n-\t\t\t\t key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_PAIRWISE,\n-\t\t\t\t key, NULL);\n+\t\t\t\t key-\u003econf.flags, key, NULL);\n \t\tlist_add_tail(\u0026key-\u003elist, keys);\n \t}\n \n@@ -1119,8 +1149,7 @@ void ieee80211_remove_link_keys(struct ieee80211_link_data *link,\n \t\tif (key-\u003econf.link_id != link-\u003elink_id)\n \t\t\tcontinue;\n \t\tieee80211_key_replace(key-\u003esdata, link, key-\u003esta,\n-\t\t\t\t key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_PAIRWISE,\n-\t\t\t\t key, NULL);\n+\t\t\t\t key-\u003econf.flags, key, NULL);\n \t\tlist_add_tail(\u0026key-\u003elist, keys);\n \t}\n }\n@@ -1196,8 +1225,17 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,\n \t\tif (!key)\n \t\t\tcontinue;\n \t\tieee80211_key_replace(key-\u003esdata, NULL, key-\u003esta,\n-\t\t\t\t key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_PAIRWISE,\n-\t\t\t\t key, NULL);\n+\t\t\t\t key-\u003econf.flags, key, NULL);\n+\t\t__ieee80211_key_destroy(key, key-\u003esdata-\u003evif.type ==\n+\t\t\t\t\tNL80211_IFTYPE_STATION);\n+\t}\n+\n+\tfor (i = 0; i \u003c ARRAY_SIZE(sta-\u003edeflink.cigtk); i++) {\n+\t\tkey = wiphy_dereference(local-\u003ehw.wiphy, sta-\u003edeflink.cigtk[i]);\n+\t\tif (!key)\n+\t\t\tcontinue;\n+\t\tieee80211_key_replace(key-\u003esdata, NULL, key-\u003esta,\n+\t\t\t\t key-\u003econf.flags, key, NULL);\n \t\t__ieee80211_key_destroy(key, key-\u003esdata-\u003evif.type ==\n \t\t\t\t\tNL80211_IFTYPE_STATION);\n \t}\n@@ -1207,8 +1245,7 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,\n \t\tif (!key)\n \t\t\tcontinue;\n \t\tieee80211_key_replace(key-\u003esdata, NULL, key-\u003esta,\n-\t\t\t\t key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_PAIRWISE,\n-\t\t\t\t key, NULL);\n+\t\t\t\t key-\u003econf.flags, key, NULL);\n \t\t__ieee80211_key_destroy(key, key-\u003esdata-\u003evif.type ==\n \t\t\t\t\tNL80211_IFTYPE_STATION);\n \t}\n@@ -1366,7 +1403,7 @@ EXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq);\n struct ieee80211_key_conf *\n ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,\n \t\t\tu8 idx, u8 *key_data, u8 key_len,\n-\t\t\tint link_id)\n+\t\t\tint link_id, bool cigtk)\n {\n \tstruct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);\n \tstruct ieee80211_local *local = sdata-\u003elocal;\n@@ -1390,10 +1427,20 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,\n \t\t NUM_DEFAULT_BEACON_KEYS))\n \t\treturn ERR_PTR(-EINVAL);\n \n-\tprev_key = wiphy_dereference(local-\u003ehw.wiphy,\n-\t\t\t\t link_data-\u003egtk[idx]);\n+\tif (WARN_ON(cigtk \u0026\u0026 idx \u003e= NUM_CTRL_KEYS))\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\tif (cigtk)\n+\t\tprev_key = wiphy_dereference(local-\u003ehw.wiphy,\n+\t\t\t\t\t link_data-\u003ecigtk[idx]);\n+\telse\n+\t\tprev_key = wiphy_dereference(local-\u003ehw.wiphy,\n+\t\t\t\t\t link_data-\u003egtk[idx]);\n \tif (!prev_key) {\n-\t\tif (idx \u003c NUM_DEFAULT_KEYS) {\n+\t\tif (cigtk) {\n+\t\t\tprev_key = wiphy_dereference(local-\u003ehw.wiphy,\n+\t\t\t\t\t\t link_data-\u003ecigtk[idx ^ 1]);\n+\t\t} else if (idx \u003c NUM_DEFAULT_KEYS) {\n \t\t\tfor (int i = 0; i \u003c NUM_DEFAULT_KEYS; i++) {\n \t\t\t\tif (i == idx)\n \t\t\t\t\tcontinue;\n@@ -1424,6 +1471,9 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,\n \tif (sdata-\u003eu.mgd.mfp != IEEE80211_MFP_DISABLED)\n \t\tkey-\u003econf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;\n \n+\tif (prev_key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_CIP)\n+\t\tkey-\u003econf.flags |= IEEE80211_KEY_FLAG_CIP;\n+\n \tkey-\u003econf.link_id = link_data-\u003elink_id;\n \n \terr = ieee80211_key_link(key, link_data, NULL);\ndiff --git a/net/mac80211/key.h b/net/mac80211/key.h\nindex 826e4e9387c55..c85992493afd1 100644\n--- a/net/mac80211/key.h\n+++ b/net/mac80211/key.h\n@@ -2,7 +2,7 @@\n /*\n * Copyright 2002-2004, Instant802 Networks, Inc.\n * Copyright 2005, Devicescape Software, Inc.\n- * Copyright (C) 2019, 2022-2023 Intel Corporation\n+ * Copyright (C) 2019, 2022-2023, 2026 Intel Corporation\n */\n \n #ifndef IEEE80211_KEY_H\n@@ -19,6 +19,7 @@\n #define NUM_DEFAULT_KEYS 4\n #define NUM_DEFAULT_MGMT_KEYS 2\n #define NUM_DEFAULT_BEACON_KEYS 2\n+#define NUM_CTRL_KEYS 2\n #define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */\n \n struct ieee80211_local;\ndiff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c\nindex cf3873d8855b6..76c45a0eea621 100644\n--- a/net/mac80211/mlme.c\n+++ b/net/mac80211/mlme.c\n@@ -2337,6 +2337,10 @@ ieee80211_add_link_elems(struct ieee80211_sub_if_data *sdata,\n \t\tieee80211_put_eht_cap(skb, sdata, sband,\n \t\t\t\t \u0026assoc_data-\u003elink[link_id].conn);\n \n+\t/* Insert CIP only on the assoc link (it will be inherited) */\n+\tif (link_id == assoc_data-\u003eassoc_link_id \u0026\u0026 assoc_data-\u003ecip)\n+\t\tieee80211_put_cip_cap(skb, sdata);\n+\n \tif (assoc_data-\u003elink[link_id].conn.mode \u003e= IEEE80211_CONN_MODE_UHR)\n \t\tieee80211_put_uhr_cap(skb, sdata, sband);\n \n@@ -2613,7 +2617,8 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)\n \t assoc_data-\u003eie_len + /* extra IEs */\n \t (assoc_data-\u003efils_kek_len ? 16 /* AES-SIV */ : 0) +\n \t 9 /* WMM */ +\n-\t 4 /* regulatory connectivity, if 6 GHz is supported */;\n+\t 4 /* regulatory connectivity, if 6 GHz is supported */ +\n+\t (assoc_data-\u003ecip ? 4 /* CIP capabilities */ : 0);\n \n \tfor (link_id = 0; link_id \u003c IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {\n \t\tstruct cfg80211_bss *cbss = assoc_data-\u003elink[link_id].bss;\n@@ -6274,6 +6279,17 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,\n \t\t/* TODO: OPEN: what happens if BSS color disable is set? */\n \t}\n \n+\tif (assoc_data-\u003ecip) {\n+\t\tif (elems-\u003ecip_cap) {\n+\t\t\tlink_sta-\u003epub-\u003ecip_cap = elems-\u003ecip_cap-\u003ev;\n+\t\t} else {\n+\t\t\tsdata_info(sdata,\n+\t\t\t\t \"CIP Capabilities not included in association response\\n\");\n+\t\t\tret = false;\n+\t\t\tgoto out;\n+\t\t}\n+\t}\n+\n \tif (cbss-\u003etransmitted_bss) {\n \t\tbss_conf-\u003enontransmitted = true;\n \t\tether_addr_copy(bss_conf-\u003etransmitter_bssid,\n@@ -6999,6 +7015,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,\n \t\tgoto out_err;\n \n \tsta-\u003esta.spp_amsdu = assoc_data-\u003espp_amsdu;\n+\tsta-\u003esta.cip = assoc_data-\u003ecip;\n \n \tif (ieee80211_vif_is_mld(\u0026sdata-\u003evif)) {\n \t\tif (!elems-\u003eml_basic)\n@@ -10536,6 +10553,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,\n \t}\n \n \tassoc_data-\u003espp_amsdu = req-\u003eflags \u0026 ASSOC_REQ_SPP_AMSDU;\n+\tassoc_data-\u003ecip = req-\u003eflags \u0026 ASSOC_REQ_CIP;\n \n \tif (ifmgd-\u003eauth_data \u0026\u0026 !ifmgd-\u003eauth_data-\u003edone) {\n \t\terr = -EBUSY;\ndiff --git a/net/mac80211/parse.c b/net/mac80211/parse.c\nindex cb2be167cde79..3b66ca7d7a5c2 100644\n--- a/net/mac80211/parse.c\n+++ b/net/mac80211/parse.c\n@@ -205,6 +205,10 @@ ieee80211_parse_extension_element(u32 *crc,\n \t\t\telems-\u003ettlm_num++;\n \t\t}\n \t\tbreak;\n+\tcase WLAN_EID_EXT_CIP_CAPA:\n+\t\tif (len \u003e= sizeof(*elems-\u003ecip_cap))\n+\t\t\telems-\u003ecip_cap = data;\n+\t\tbreak;\n \tcase WLAN_EID_EXT_UHR_OPER:\n \t\tif (params-\u003emode \u003c IEEE80211_CONN_MODE_UHR)\n \t\t\tbreak;\ndiff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h\nindex ee0d32877c5b4..f409f6a3afa1f 100644\n--- a/net/mac80211/sta_info.h\n+++ b/net/mac80211/sta_info.h\n@@ -485,6 +485,7 @@ struct ieee80211_fragment_cache {\n * @link_hash_node: hash node for rhashtable\n * @sta: Points to the STA info\n * @gtk: group keys negotiated with this station, if any\n+ * @cigtk: control integrity group keys negotiated with this station, if any\n * @tx_stats: TX statistics\n * @tx_stats.packets: # of packets transmitted\n * @tx_stats.bytes: # of bytes in all packets transmitted\n@@ -535,6 +536,7 @@ struct link_sta_info {\n \tstruct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +\n \t\t\t\t\tNUM_DEFAULT_MGMT_KEYS +\n \t\t\t\t\tNUM_DEFAULT_BEACON_KEYS];\n+\tstruct ieee80211_key __rcu *cigtk[NUM_CTRL_KEYS];\n \tstruct ieee80211_sta_rx_stats __percpu *pcpu_rx_stats;\n \n \t/* Updated from RX path only, no locking requirements */\ndiff --git a/net/mac80211/util.c b/net/mac80211/util.c\nindex e2b5b2b21c347..c193a75ef06ea 100644\n--- a/net/mac80211/util.c\n+++ b/net/mac80211/util.c\n@@ -4680,6 +4680,25 @@ int ieee80211_put_uhr_cap(struct sk_buff *skb,\n \treturn 0;\n }\n \n+int ieee80211_put_cip_cap(struct sk_buff *skb,\n+\t\t\t struct ieee80211_sub_if_data *sdata)\n+{\n+\tconst struct wiphy_iftype_ext_capab *ift_ext_capa =\n+\t\tcfg80211_get_iftype_ext_capa(sdata-\u003elocal-\u003ehw.wiphy,\n+\t\t\t\t\t ieee80211_vif_type_p2p(\u0026sdata-\u003evif));\n+\tu8 cip_capabilities = ift_ext_capa ? ift_ext_capa-\u003ecip_capabilities : 0;\n+\n+\tif (skb_tailroom(skb) \u003c 4)\n+\t\treturn -ENOBUFS;\n+\n+\tskb_put_u8(skb, WLAN_EID_EXTENSION);\n+\tskb_put_u8(skb, 2);\n+\tskb_put_u8(skb, WLAN_EID_EXT_CIP_CAPA);\n+\tskb_put_u8(skb, cip_capabilities);\n+\n+\treturn 0;\n+}\n+\n const char *ieee80211_conn_mode_str(enum ieee80211_conn_mode mode)\n {\n \tstatic const char * const modes[] = {\ndiff --git a/net/wireless/core.h b/net/wireless/core.h\nindex b4610f6685dcb..508d731fbf336 100644\n--- a/net/wireless/core.h\n+++ b/net/wireless/core.h\n@@ -443,13 +443,16 @@ void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev);\n \n /* internal helpers */\n bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);\n+bool cfg80211_cigtk_supported(struct wireless_dev *wdev,\n+\t\t\t struct genl_info *info);\n bool cfg80211_valid_key_idx(struct wireless_dev *wdev,\n-\t\t\t int key_idx, bool pairwise,\n+\t\t\t int key_idx, enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr);\n int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,\n \t\t\t\t struct wireless_dev *wdev,\n \t\t\t\t struct key_params *params, int key_idx,\n-\t\t\t\t bool pairwise, const u8 *mac_addr);\n+\t\t\t\t enum nl80211_key_type type,\n+\t\t\t\t const u8 *mac_addr);\n void __cfg80211_scan_done(struct wiphy *wiphy, struct wiphy_work *wk);\n void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,\n \t\t\t bool send_message);\ndiff --git a/net/wireless/ibss.c b/net/wireless/ibss.c\nindex b1d748bdb504e..6ae561ed7f37f 100644\n--- a/net/wireless/ibss.c\n+++ b/net/wireless/ibss.c\n@@ -172,7 +172,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)\n \t */\n \tif (rdev-\u003eops-\u003edel_key)\n \t\tfor (i = 0; i \u003c 6; i++)\n-\t\t\trdev_del_key(rdev, wdev, -1, i, false, NULL);\n+\t\t\trdev_del_key(rdev, wdev, -1, i, NL80211_KEYTYPE_GROUP,\n+\t\t\t\t NULL);\n \n \tif (wdev-\u003eu.ibss.current_bss) {\n \t\tcfg80211_unhold_bss(wdev-\u003eu.ibss.current_bss);\ndiff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c\nindex ab5a14f5fe283..bfba773c6d9c1 100644\n--- a/net/wireless/nl80211.c\n+++ b/net/wireless/nl80211.c\n@@ -1098,6 +1098,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {\n \t\tNLA_POLICY_FULL_RANGE(NLA_U32, \u0026nl80211_punct_bitmap_range),\n \t[NL80211_ATTR_STA_DUMP_LINK_STATS] = { .type = NLA_FLAG },\n \t[NL80211_ATTR_FRAME_NO_STA] = { .type = NLA_FLAG },\n+\t[NL80211_ATTR_ASSOC_CIP] = { .type = NLA_FLAG },\n+\t[NL80211_ATTR_CIP_CAPABILITIES] = { .type = NLA_U8 },\n };\n \n /* policy for the key attributes */\n@@ -1763,6 +1765,11 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)\n \t\t\t\tGENL_SET_ERR_MSG(info, \"def key idx not 0-3\");\n \t\t\t\treturn -EINVAL;\n \t\t\t}\n+\t\t} else if (k-\u003etype == NL80211_KEYTYPE_CIGTK) {\n+\t\t\tif (k-\u003eidx \u003c 0 || k-\u003eidx \u003e 1) {\n+\t\t\t\tGENL_SET_ERR_MSG(info, \"CIGTK idx not 0-1\");\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n \t\t} else {\n \t\t\tif (k-\u003eidx \u003c 0 || k-\u003eidx \u003e 7) {\n \t\t\t\tGENL_SET_ERR_MSG(info, \"key idx not 0-7\");\n@@ -1827,7 +1834,9 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,\n \t\t} else if (parse.defmgmt)\n \t\t\tgoto error;\n \t\terr = cfg80211_validate_key_settings(rdev, wdev, \u0026parse.p,\n-\t\t\t\t\t\t parse.idx, false, NULL);\n+\t\t\t\t\t\t parse.idx,\n+\t\t\t\t\t\t NL80211_KEYTYPE_GROUP,\n+\t\t\t\t\t\t NULL);\n \t\tif (err)\n \t\t\tgoto error;\n \t\tif (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 \u0026\u0026\n@@ -3617,6 +3626,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,\n \t\t\t\t\t\tNL80211_ATTR_EXT_MLD_CAPA_AND_OPS,\n \t\t\t\t\t\tcapab-\u003eext_mld_capa_and_ops))\n \t\t\t\t\tgoto nla_put_failure;\n+\t\t\t\tif (capab-\u003ecip_supported \u0026\u0026\n+\t\t\t\t nla_put_u8(msg,\n+\t\t\t\t\t NL80211_ATTR_CIP_CAPABILITIES,\n+\t\t\t\t\t capab-\u003ecip_capabilities))\n+\t\t\t\t\tgoto nla_put_failure;\n \n \t\t\t\tnla_nest_end(msg, nested_ext_capab);\n \t\t\t\tif (state-\u003esplit)\n@@ -5373,6 +5387,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)\n \tstruct wireless_dev *wdev = info-\u003euser_ptr[1];\n \tu8 key_idx = 0;\n \tconst u8 *mac_addr = NULL;\n+\tenum nl80211_key_type type;\n \tbool pairwise;\n \tstruct get_key_cookie cookie = {\n \t\t.error = 0,\n@@ -5405,19 +5420,24 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)\n \t\tmac_addr = nla_data(info-\u003eattrs[NL80211_ATTR_MAC]);\n \n \tpairwise = !!mac_addr;\n+\ttype = pairwise ? NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP;\n \tif (info-\u003eattrs[NL80211_ATTR_KEY_TYPE]) {\n-\t\tu32 kt = nla_get_u32(info-\u003eattrs[NL80211_ATTR_KEY_TYPE]);\n+\t\ttype = nla_get_u32(info-\u003eattrs[NL80211_ATTR_KEY_TYPE]);\n \n-\t\tif (kt != NL80211_KEYTYPE_GROUP \u0026\u0026\n-\t\t kt != NL80211_KEYTYPE_PAIRWISE)\n+\t\tif (type != NL80211_KEYTYPE_GROUP \u0026\u0026\n+\t\t type != NL80211_KEYTYPE_PAIRWISE \u0026\u0026\n+\t\t type != NL80211_KEYTYPE_CIGTK) {\n+\t\t\tGENL_SET_ERR_MSG(info, \"key type not pairwise, group or CIGTK\");\n \t\t\treturn -EINVAL;\n-\t\tpairwise = kt == NL80211_KEYTYPE_PAIRWISE;\n+\t\t}\n+\n+\t\tpairwise = type == NL80211_KEYTYPE_PAIRWISE;\n \t}\n \n \tif (!rdev-\u003eops-\u003eget_key)\n \t\treturn -EOPNOTSUPP;\n \n-\tif (!cfg80211_valid_key_idx(wdev, key_idx, pairwise, mac_addr))\n+\tif (!cfg80211_valid_key_idx(wdev, key_idx, type, mac_addr))\n \t\treturn -ENOENT;\n \n \tmsg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);\n@@ -5446,7 +5466,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)\n \tif (err)\n \t\tgoto free_msg;\n \n-\terr = rdev_get_key(rdev, wdev, link_id, key_idx, pairwise, mac_addr,\n+\terr = rdev_get_key(rdev, wdev, link_id, key_idx, type, mac_addr,\n \t\t\t \u0026cookie, get_key_callback);\n \n \tif (err)\n@@ -5605,8 +5625,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)\n \n \t/* for now */\n \tif (key.type != NL80211_KEYTYPE_PAIRWISE \u0026\u0026\n-\t key.type != NL80211_KEYTYPE_GROUP) {\n-\t\tGENL_SET_ERR_MSG(info, \"key type not pairwise or group\");\n+\t key.type != NL80211_KEYTYPE_GROUP \u0026\u0026\n+\t key.type != NL80211_KEYTYPE_CIGTK) {\n+\t\tGENL_SET_ERR_MSG(info, \"key type not pairwise, group or CIGTK\");\n \t\treturn -EINVAL;\n \t}\n \n@@ -5618,8 +5639,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)\n \t\treturn -EOPNOTSUPP;\n \n \tif (cfg80211_validate_key_settings(rdev, wdev, \u0026key.p, key.idx,\n-\t\t\t\t\t key.type == NL80211_KEYTYPE_PAIRWISE,\n-\t\t\t\t\t mac_addr)) {\n+\t\t\t\t\t key.type, mac_addr)) {\n \t\tGENL_SET_ERR_MSG(info, \"key setting validation failed\");\n \t\treturn -EINVAL;\n \t}\n@@ -5633,8 +5653,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)\n \t\t\t\tkey.type == NL80211_KEYTYPE_PAIRWISE);\n \n \tif (!err) {\n-\t\terr = rdev_add_key(rdev, wdev, link_id, key.idx,\n-\t\t\t\t key.type == NL80211_KEYTYPE_PAIRWISE,\n+\t\terr = rdev_add_key(rdev, wdev, link_id, key.idx, key.type,\n \t\t\t\t mac_addr, \u0026key.p);\n \t\tif (err)\n \t\t\tGENL_SET_ERR_MSG(info, \"key addition failed\");\n@@ -5668,12 +5687,13 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)\n \n \t/* for now */\n \tif (key.type != NL80211_KEYTYPE_PAIRWISE \u0026\u0026\n-\t key.type != NL80211_KEYTYPE_GROUP)\n+\t key.type != NL80211_KEYTYPE_GROUP \u0026\u0026\n+\t key.type != NL80211_KEYTYPE_CIGTK) {\n+\t\tGENL_SET_ERR_MSG(info, \"key type not pairwise, group or CIGTK\");\n \t\treturn -EINVAL;\n+\t}\n \n-\tif (!cfg80211_valid_key_idx(wdev, key.idx,\n-\t\t\t\t key.type == NL80211_KEYTYPE_PAIRWISE,\n-\t\t\t\t mac_addr))\n+\tif (!cfg80211_valid_key_idx(wdev, key.idx, key.type, mac_addr))\n \t\treturn -EINVAL;\n \n \tif (!rdev-\u003eops-\u003edel_key)\n@@ -5687,8 +5707,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)\n \n \tif (!err)\n \t\terr = rdev_del_key(rdev, wdev, link_id, key.idx,\n-\t\t\t\t key.type == NL80211_KEYTYPE_PAIRWISE,\n-\t\t\t\t mac_addr);\n+\t\t\t\t key.type, mac_addr);\n \n #ifdef CONFIG_CFG80211_WEXT\n \tif (!err) {\n@@ -8819,7 +8838,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,\n \t\treturn -EINVAL;\n \n \t/* When you run into this, adjust the code below for the new flag */\n-\tBUILD_BUG_ON(NL80211_STA_FLAG_MAX != 8);\n+\tBUILD_BUG_ON(NL80211_STA_FLAG_MAX != 9);\n \n \tswitch (statype) {\n \tcase CFG80211_STA_MESH_PEER_KERNEL:\n@@ -8913,7 +8932,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,\n \t\t\t\t BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |\n \t\t\t\t BIT(NL80211_STA_FLAG_WME) |\n \t\t\t\t BIT(NL80211_STA_FLAG_MFP) |\n-\t\t\t\t BIT(NL80211_STA_FLAG_SPP_AMSDU)))\n+\t\t\t\t BIT(NL80211_STA_FLAG_SPP_AMSDU) |\n+\t\t\t\t BIT(NL80211_STA_FLAG_CIP)))\n \t\t\treturn -EINVAL;\n \n \t\t/* but authenticated/associated only if driver handles it */\n@@ -9290,6 +9310,22 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)\n \t\t\tnla_get_u16(info-\u003eattrs[NL80211_ATTR_EML_CAPABILITY]);\n \t}\n \n+\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_CIP) \u0026\u0026\n+\t params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_CIP)) {\n+\t\tif (!cfg80211_cigtk_supported(wdev, info))\n+\t\t\treturn -EINVAL;\n+\n+\t\t/* CIP capabilities are required if CIP is being enabled */\n+\t\tif (info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]) {\n+\t\t\tparams.link_sta_params.cip_cap_set = true;\n+\t\t\tparams.link_sta_params.cip_cap =\n+\t\t\t\tnla_get_u8(info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]);\n+\t\t} else {\n+\t\t\tGENL_SET_ERR_MSG(info, \"No CIP capabilities provided\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n \tif (info-\u003eattrs[NL80211_ATTR_AIRTIME_WEIGHT])\n \t\tparams.airtime_weight =\n \t\t\tnla_get_u16(info-\u003eattrs[NL80211_ATTR_AIRTIME_WEIGHT]);\n@@ -9489,6 +9525,22 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)\n \t\t\tnla_get_u16(info-\u003eattrs[NL80211_ATTR_EML_CAPABILITY]);\n \t}\n \n+\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_CIP) \u0026\u0026\n+\t params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_CIP)) {\n+\t\tif (!cfg80211_cigtk_supported(wdev, info))\n+\t\t\treturn -EINVAL;\n+\n+\t\t/* CIP capabilities are required if CIP is enabled */\n+\t\tif (info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]) {\n+\t\t\tparams.link_sta_params.cip_cap_set = true;\n+\t\t\tparams.link_sta_params.cip_cap =\n+\t\t\t\tnla_get_u8(info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]);\n+\t\t} else {\n+\t\t\tGENL_SET_ERR_MSG(info, \"No CIP capabilities provided\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n \tif (info-\u003eattrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])\n \t\tparams.link_sta_params.he_6ghz_capa =\n \t\t\tnla_data(info-\u003eattrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);\n@@ -9566,7 +9618,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)\n \t\treturn -EINVAL;\n \n \t/* When you run into this, adjust the code below for the new flag */\n-\tBUILD_BUG_ON(NL80211_STA_FLAG_MAX != 8);\n+\tBUILD_BUG_ON(NL80211_STA_FLAG_MAX != 9);\n \n \tswitch (wdev-\u003eiftype) {\n \tcase NL80211_IFTYPE_AP:\n@@ -9595,6 +9647,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)\n \t\t params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_SPP_AMSDU))\n \t\t\treturn -EINVAL;\n \n+\t\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_CIP) \u0026\u0026\n+\t\t !cfg80211_cigtk_supported(wdev, info))\n+\t\t\treturn -EINVAL;\n+\n \t\t/* Older userspace, or userspace wanting to be compatible with\n \t\t * !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth\n \t\t * and assoc flags in the mask, but assumes the station will be\n@@ -13321,6 +13377,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)\n \t\treq.flags |= ASSOC_REQ_SPP_AMSDU;\n \t}\n \n+\tif (nla_get_flag(info-\u003eattrs[NL80211_ATTR_ASSOC_CIP])) {\n+\t\tif (!cfg80211_cigtk_supported(dev-\u003eieee80211_ptr, info))\n+\t\t\treturn -EINVAL;\n+\n+\t\treq.flags |= ASSOC_REQ_CIP;\n+\t}\n+\n \treq.link_id = nl80211_link_id_or_invalid(info-\u003eattrs);\n \n \tif (info-\u003eattrs[NL80211_ATTR_MLO_LINKS]) {\n@@ -19201,6 +19264,23 @@ nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info,\n \t\tparams.he_6ghz_capa =\n \t\t\tnla_data(info-\u003eattrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);\n \n+\tif (info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]) {\n+\t\tstruct wireless_dev *wdev = dev-\u003eieee80211_ptr;\n+\n+\t\tif (!cfg80211_cigtk_supported(wdev, info))\n+\t\t\treturn -EINVAL;\n+\n+\t\tparams.cip_cap_set = true;\n+\t\tparams.cip_cap =\n+\t\t\tnla_get_u8(info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]);\n+\n+\t\t/* Only permit CIP capabilities when adding link stations */\n+\t\tif (!add) {\n+\t\t\tGENL_SET_ERR_MSG(info, \"Cannot modify CIP capabilities\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n \tif (info-\u003eattrs[NL80211_ATTR_OPMODE_NOTIF]) {\n \t\tparams.opmode_notif_used = true;\n \t\tparams.opmode_notif =\ndiff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h\nindex 46849fe8d0b39..7653cd0da9b93 100644\n--- a/net/wireless/rdev-ops.h\n+++ b/net/wireless/rdev-ops.h\n@@ -78,42 +78,43 @@ rdev_change_virtual_intf(struct cfg80211_registered_device *rdev,\n \n static inline int rdev_add_key(struct cfg80211_registered_device *rdev,\n \t\t\t struct wireless_dev *wdev, int link_id,\n-\t\t\t u8 key_index, bool pairwise, const u8 *mac_addr,\n-\t\t\t struct key_params *params)\n+\t\t\t u8 key_index, enum nl80211_key_type type,\n+\t\t\t const u8 *mac_addr, struct key_params *params)\n {\n \tint ret;\n-\ttrace_rdev_add_key(\u0026rdev-\u003ewiphy, wdev, link_id, key_index, pairwise,\n+\ttrace_rdev_add_key(\u0026rdev-\u003ewiphy, wdev, link_id, key_index, type,\n \t\t\t mac_addr, params-\u003emode);\n \tret = rdev-\u003eops-\u003eadd_key(\u0026rdev-\u003ewiphy, wdev, link_id, key_index,\n-\t\t\t\t pairwise, mac_addr, params);\n+\t\t\t\t type, mac_addr, params);\n \ttrace_rdev_return_int(\u0026rdev-\u003ewiphy, ret);\n \treturn ret;\n }\n \n static inline int\n rdev_get_key(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev,\n-\t int link_id, u8 key_index, bool pairwise, const u8 *mac_addr,\n-\t void *cookie,\n+\t int link_id, u8 key_index, enum nl80211_key_type type,\n+\t const u8 *mac_addr, void *cookie,\n \t void (*callback)(void *cookie, struct key_params*))\n {\n \tint ret;\n-\ttrace_rdev_get_key(\u0026rdev-\u003ewiphy, wdev, link_id, key_index, pairwise,\n+\ttrace_rdev_get_key(\u0026rdev-\u003ewiphy, wdev, link_id, key_index, type,\n \t\t\t mac_addr);\n \tret = rdev-\u003eops-\u003eget_key(\u0026rdev-\u003ewiphy, wdev, link_id, key_index,\n-\t\t\t\t pairwise, mac_addr, cookie, callback);\n+\t\t\t\t type, mac_addr, cookie, callback);\n \ttrace_rdev_return_int(\u0026rdev-\u003ewiphy, ret);\n \treturn ret;\n }\n \n static inline int rdev_del_key(struct cfg80211_registered_device *rdev,\n \t\t\t struct wireless_dev *wdev, int link_id,\n-\t\t\t u8 key_index, bool pairwise, const u8 *mac_addr)\n+\t\t\t u8 key_index, enum nl80211_key_type type,\n+\t\t\t const u8 *mac_addr)\n {\n \tint ret;\n-\ttrace_rdev_del_key(\u0026rdev-\u003ewiphy, wdev, link_id, key_index, pairwise,\n+\ttrace_rdev_del_key(\u0026rdev-\u003ewiphy, wdev, link_id, key_index, type,\n \t\t\t mac_addr);\n \tret = rdev-\u003eops-\u003edel_key(\u0026rdev-\u003ewiphy, wdev, link_id, key_index,\n-\t\t\t\t pairwise, mac_addr);\n+\t\t\t\t type, mac_addr);\n \ttrace_rdev_return_int(\u0026rdev-\u003ewiphy, ret);\n \treturn ret;\n }\ndiff --git a/net/wireless/sme.c b/net/wireless/sme.c\nindex 2a719b5c487e3..458f72d8351ab 100644\n--- a/net/wireless/sme.c\n+++ b/net/wireless/sme.c\n@@ -1387,7 +1387,15 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,\n \t\t\t NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))\n \t\t\tmax_key_idx = 7;\n \t\tfor (i = 0; i \u003c= max_key_idx; i++)\n-\t\t\trdev_del_key(rdev, wdev, -1, i, false, NULL);\n+\t\t\trdev_del_key(rdev, wdev, -1, i, NL80211_KEYTYPE_GROUP,\n+\t\t\t\t NULL);\n+\n+\t\tif (cfg80211_cigtk_supported(wdev, NULL)) {\n+\t\t\trdev_del_key(rdev, wdev, -1, 0, NL80211_KEYTYPE_CIGTK,\n+\t\t\t\t NULL);\n+\t\t\trdev_del_key(rdev, wdev, -1, 1, NL80211_KEYTYPE_CIGTK,\n+\t\t\t\t NULL);\n+\t\t}\n \t}\n \n \trdev_set_qos_map(rdev, dev, NULL);\ndiff --git a/net/wireless/trace.h b/net/wireless/trace.h\nindex 8c2a91b85c396..c210ca1e44e2b 100644\n--- a/net/wireless/trace.h\n+++ b/net/wireless/trace.h\n@@ -557,15 +557,15 @@ TRACE_EVENT(rdev_change_virtual_intf,\n \n DECLARE_EVENT_CLASS(key_handle,\n \tTP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n-\t\t u8 key_index, bool pairwise, const u8 *mac_addr),\n-\tTP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr),\n+\t\t u8 key_index, enum nl80211_key_type type, const u8 *mac_addr),\n+\tTP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr),\n \tTP_STRUCT__entry(\n \t\tWIPHY_ENTRY\n \t\tWDEV_ENTRY\n \t\tMAC_ENTRY(mac_addr)\n \t\t__field(int, link_id)\n \t\t__field(u8, key_index)\n-\t\t__field(bool, pairwise)\n+\t\t__field(u8, type)\n \t),\n \tTP_fast_assign(\n \t\tWIPHY_ASSIGN;\n@@ -573,38 +573,40 @@ DECLARE_EVENT_CLASS(key_handle,\n \t\tMAC_ASSIGN(mac_addr, mac_addr);\n \t\t__entry-\u003elink_id = link_id;\n \t\t__entry-\u003ekey_index = key_index;\n-\t\t__entry-\u003epairwise = pairwise;\n+\t\t__entry-\u003etype = type;\n \t),\n \tTP_printk(WIPHY_PR_FMT \", \" WDEV_PR_FMT \", link_id: %d, \"\n-\t\t \"key_index: %u, pairwise: %s, mac addr: %pM\",\n+\t\t \"key_index: %u, pairwise: %s, type: %d, mac addr: %pM\",\n \t\t WIPHY_PR_ARG, WDEV_PR_ARG, __entry-\u003elink_id,\n-\t\t __entry-\u003ekey_index, BOOL_TO_STR(__entry-\u003epairwise),\n-\t\t __entry-\u003emac_addr)\n+\t\t __entry-\u003ekey_index,\n+\t\t BOOL_TO_STR(__entry-\u003etype == NL80211_KEYTYPE_PAIRWISE),\n+\t\t __entry-\u003etype, __entry-\u003emac_addr)\n );\n \n DEFINE_EVENT(key_handle, rdev_get_key,\n \tTP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n-\t\t u8 key_index, bool pairwise, const u8 *mac_addr),\n-\tTP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr)\n+\t\t u8 key_index, enum nl80211_key_type type, const u8 *mac_addr),\n+\tTP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr)\n );\n \n DEFINE_EVENT(key_handle, rdev_del_key,\n \tTP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n-\t\t u8 key_index, bool pairwise, const u8 *mac_addr),\n-\tTP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr)\n+\t\t u8 key_index, enum nl80211_key_type type, const u8 *mac_addr),\n+\tTP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr)\n );\n \n TRACE_EVENT(rdev_add_key,\n \tTP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,\n-\t\t u8 key_index, bool pairwise, const u8 *mac_addr, u8 mode),\n-\tTP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr, mode),\n+\t\t u8 key_index, enum nl80211_key_type type, const u8 *mac_addr,\n+\t\t u8 mode),\n+\tTP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr, mode),\n \tTP_STRUCT__entry(\n \t\tWIPHY_ENTRY\n \t\tWDEV_ENTRY\n \t\tMAC_ENTRY(mac_addr)\n \t\t__field(int, link_id)\n \t\t__field(u8, key_index)\n-\t\t__field(bool, pairwise)\n+\t\t__field(u8, type)\n \t\t__field(u8, mode)\n \t),\n \tTP_fast_assign(\n@@ -613,15 +615,16 @@ TRACE_EVENT(rdev_add_key,\n \t\tMAC_ASSIGN(mac_addr, mac_addr);\n \t\t__entry-\u003elink_id = link_id;\n \t\t__entry-\u003ekey_index = key_index;\n-\t\t__entry-\u003epairwise = pairwise;\n+\t\t__entry-\u003etype = type;\n \t\t__entry-\u003emode = mode;\n \t),\n \tTP_printk(WIPHY_PR_FMT \", \" WDEV_PR_FMT \", link_id: %d, \"\n-\t\t \"key_index: %u, mode: %u, pairwise: %s, \"\n+\t\t \"key_index: %u, mode: %u, pairwise: %s, type: %d, \"\n \t\t \"mac addr: %pM\",\n \t\t WIPHY_PR_ARG, WDEV_PR_ARG, __entry-\u003elink_id,\n \t\t __entry-\u003ekey_index, __entry-\u003emode,\n-\t\t BOOL_TO_STR(__entry-\u003epairwise), __entry-\u003emac_addr)\n+\t\t BOOL_TO_STR(__entry-\u003etype == NL80211_KEYTYPE_PAIRWISE),\n+\t\t __entry-\u003etype, __entry-\u003emac_addr)\n );\n \n TRACE_EVENT(rdev_set_default_key,\ndiff --git a/net/wireless/util.c b/net/wireless/util.c\nindex 3e584d0ca3e26..dd166c352910f 100644\n--- a/net/wireless/util.c\n+++ b/net/wireless/util.c\n@@ -258,8 +258,24 @@ static bool cfg80211_igtk_cipher_supported(struct wiphy *wiphy)\n \treturn false;\n }\n \n+bool cfg80211_cigtk_supported(struct wireless_dev *wdev,\n+\t\t\t struct genl_info *info)\n+{\n+\tconst struct wiphy_iftype_ext_capab *ext_capab =\n+\t\tcfg80211_get_iftype_ext_capa(wdev-\u003ewiphy, wdev-\u003eiftype);\n+\n+\tif (ext_capab \u0026\u0026 ext_capab-\u003ecip_supported)\n+\t\treturn true;\n+\n+\tif (info)\n+\t\tGENL_SET_ERR_MSG(info,\n+\t\t\t\t \"Control Integrity Protocol not supported\");\n+\n+\treturn false;\n+}\n+\n bool cfg80211_valid_key_idx(struct wireless_dev *wdev,\n-\t\t\t int key_idx, bool pairwise,\n+\t\t\t int key_idx, enum nl80211_key_type type,\n \t\t\t const u8 *mac_addr)\n {\n \tif (WARN_ON(!wdev))\n@@ -272,13 +288,24 @@ bool cfg80211_valid_key_idx(struct wireless_dev *wdev,\n \t * Can't differentiate ciphers here so allow 0..3.\n \t * Pairwise keys must be for a station (MAC address given).\n \t */\n-\tif (pairwise) {\n+\tif (type == NL80211_KEYTYPE_PAIRWISE) {\n \t\tif (!mac_addr)\n \t\t\treturn false;\n \n \t\treturn key_idx \u003c 4;\n \t}\n \n+\t/* Check the wdev/iftype supports CIGTK */\n+\tif (type == NL80211_KEYTYPE_CIGTK) {\n+\t\tif (!cfg80211_cigtk_supported(wdev, NULL))\n+\t\t\treturn false;\n+\n+\t\tif (key_idx \u003e= 2)\n+\t\t\treturn false;\n+\n+\t\t/* fallthrough for mac_addr checks */\n+\t}\n+\n \t/*\n \t * For group keys, mac_addr==NULL means setting a group key\n \t * for TX, which is only supported on some interface types,\n@@ -343,9 +370,12 @@ bool cfg80211_valid_key_idx(struct wireless_dev *wdev,\n int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,\n \t\t\t\t struct wireless_dev *wdev,\n \t\t\t\t struct key_params *params, int key_idx,\n-\t\t\t\t bool pairwise, const u8 *mac_addr)\n+\t\t\t\t enum nl80211_key_type type,\n+\t\t\t\t const u8 *mac_addr)\n {\n-\tif (!cfg80211_valid_key_idx(wdev, key_idx, pairwise, mac_addr))\n+\tbool pairwise = type == NL80211_KEYTYPE_PAIRWISE;\n+\n+\tif (!cfg80211_valid_key_idx(wdev, key_idx, type, mac_addr))\n \t\treturn -EINVAL;\n \n \tswitch (params-\u003ecipher) {\n@@ -1172,7 +1202,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)\n \tfor (i = 0; i \u003c 4; i++) {\n \t\tif (!wdev-\u003econnect_keys-\u003eparams[i].cipher)\n \t\t\tcontinue;\n-\t\tif (rdev_add_key(rdev, wdev, -1, i, false, NULL,\n+\t\tif (rdev_add_key(rdev, wdev, -1, i, NL80211_KEYTYPE_GROUP, NULL,\n \t\t\t\t \u0026wdev-\u003econnect_keys-\u003eparams[i])) {\n \t\t\tnetdev_err(dev, \"failed to set key %d\\n\", i);\n \t\t\tcontinue;\ndiff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c\nindex d45bc08c0de49..ec2389f6b8b18 100644\n--- a/net/wireless/wext-compat.c\n+++ b/net/wireless/wext-compat.c\n@@ -401,6 +401,8 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,\n \t\t\t\t int idx, struct key_params *params)\n {\n \tstruct wireless_dev *wdev = dev-\u003eieee80211_ptr;\n+\tenum nl80211_key_type key_type =\n+\t\tpairwise ? NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP;\n \tint err, i;\n \tbool rejoin = false;\n \n@@ -454,11 +456,11 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,\n \t\t\t\trejoin = true;\n \t\t\t}\n \n-\t\t\tif (!cfg80211_valid_key_idx(wdev, idx, pairwise, addr))\n+\t\t\tif (!cfg80211_valid_key_idx(wdev, idx, key_type, addr))\n \t\t\t\terr = -ENOENT;\n \t\t\telse\n-\t\t\t\terr = rdev_del_key(rdev, wdev, -1, idx, pairwise,\n-\t\t\t\t\t\t addr);\n+\t\t\t\terr = rdev_del_key(rdev, wdev, -1, idx,\n+\t\t\t\t\t\t key_type, addr);\n \t\t}\n \t\twdev-\u003ewext.connect.privacy = false;\n \t\t/*\n"
} |
| 2/1 | 2026/09/23 10:50 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": [
"CFG80211",
"MAC80211",
"MAC80211_HWSIM",
"MAC80211_DEBUGFS"
],
"FocusSymbols": [
"nl80211_new_key",
"nl80211_del_key",
"nl80211_get_key",
"cfg80211_cigtk_supported",
"cfg80211_validate_key_settings",
"ieee80211_add_key",
"ieee80211_del_key",
"ieee80211_lookup_key",
"ieee80211_key_link",
"ieee80211_gtk_rekey_add",
"ieee80211_put_cip_cap"
],
"Reasoning": "The patch introduces support for the Control Integrity Protocol (CIP) and Control Integrity Group Temporal Key (CIGTK) across cfg80211, nl80211, mac80211, and the virtual driver mac80211_hwsim. It changes key management callbacks to accept nl80211 key types, adds new netlink attributes (NL80211_ATTR_ASSOC_CIP, NL80211_ATTR_CIP_CAPABILITIES) and flags (NL80211_STA_FLAG_CIP), and alters key addition, lookup, replacement, and rekeying logic. This code is accessible via generic netlink and directly testable in virtual environments using mac80211_hwsim.",
"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 196c10554dabba6bd2ef550968db4912fe03b80f
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Sep 23 10:50:14 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 8bbe554a9b364..a9a35476fecd7 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1130,13 +1130,15 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
}
static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr,
struct key_params *params)
{
struct ath6kl *ar = ath6kl_priv(wdev->netdev);
struct ath6kl_vif *vif = netdev_priv(wdev->netdev);
struct ath6kl_key *key = NULL;
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
int seq_len;
u8 key_usage;
u8 key_type;
@@ -1255,7 +1257,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wde
}
static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct ath6kl *ar = ath6kl_priv(wdev->netdev);
@@ -1285,7 +1288,8 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wde
}
static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback) (void *cookie,
struct key_params *))
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 9ac33d827f801..bf060281c9a2c 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1620,11 +1620,13 @@ static void wil_del_rx_key(u8 key_index, enum wmi_key_usage key_usage,
static int wil_cfg80211_add_key(struct wiphy *wiphy,
struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise,
+ u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr,
struct key_params *params)
{
int rc;
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
enum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);
@@ -1695,12 +1697,14 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
static int wil_cfg80211_del_key(struct wiphy *wiphy,
struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise,
+ u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
- enum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);
+ enum wmi_key_usage key_usage =
+ wil_detect_key_usage(wdev, type == NL80211_KEYTYPE_PAIRWISE);
struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif->mid,
key_usage,
mac_addr);
@@ -2071,7 +2075,8 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)
key_params.seq_len = IEEE80211_GCMP_PN_LEN;
rc = wil_cfg80211_add_key(wiphy, vif_to_wdev(vif), -1,
vif->gtk_index,
- false, NULL, &key_params);
+ NL80211_KEYTYPE_PAIRWISE,
+ NULL, &key_params);
if (rc)
wil_err(wil, "vif %d recovery add key failed (%d)\n",
i, rc);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 9d8ce7bb046e0..ede76a9e12c87 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2802,7 +2802,8 @@ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
static s32
brcmf_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct brcmf_if *ifp = netdev_priv(wdev->netdev);
@@ -2840,7 +2841,8 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
static s32
brcmf_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
@@ -2866,7 +2868,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
if (params->key_len == 0)
return brcmf_cfg80211_del_key(wiphy, wdev, -1, key_idx,
- pairwise, mac_addr);
+ type, mac_addr);
if (params->key_len > sizeof(key->data)) {
bphy_err(drvr, "Too long key length (%u)\n", params->key_len);
@@ -2962,7 +2964,8 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
static s32
brcmf_cfg80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
index 55f9b809e764d..6d8ede336d59b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
@@ -1138,7 +1138,8 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
return;
key_config = ieee80211_gtk_rekey_add(vif, key_data->id, key_data->key,
- sizeof(key_data->key), link_id);
+ sizeof(key_data->key), link_id,
+ false);
if (IS_ERR(key_config))
return;
@@ -1220,7 +1221,8 @@ static void iwl_mld_mlo_rekey(struct iwl_mld *mld,
mlo_key->idx, link_id);
key = ieee80211_gtk_rekey_add(vif, mlo_key->idx, mlo_key->key,
- sizeof(mlo_key->key), link_id);
+ sizeof(mlo_key->key), link_id,
+ false);
if (IS_ERR(key))
continue;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 6b11fa32ea5c6..bd52f2ebd3ba1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1887,7 +1887,8 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id,
status->gtk[i].key,
- sizeof(status->gtk[i].key), -1);
+ sizeof(status->gtk[i].key), -1,
+ false);
if (IS_ERR(key)) {
/* FW may send also the old keys */
if (PTR_ERR(key) == -EALREADY)
@@ -1922,7 +1923,8 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,
return true;
key_config = ieee80211_gtk_rekey_add(vif, keyidx, key_data->key,
- sizeof(key_data->key), -1);
+ sizeof(key_data->key), -1,
+ false);
if (IS_ERR(key_config)) {
/* FW may send also the old keys */
return PTR_ERR(key_config) == -EALREADY;
diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c
index 72c92f72469de..e015cfa1950c1 100644
--- a/drivers/net/wireless/marvell/libertas/cfg.c
+++ b/drivers/net/wireless/marvell/libertas/cfg.c
@@ -1508,7 +1508,8 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
static int lbs_cfg_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 idx, bool pairwise,
+ int link_id, u8 idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct lbs_private *priv = wiphy_priv(wiphy);
@@ -1569,7 +1570,8 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
static int lbs_cfg_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 293876397b670..1db1017ef76a1 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -142,12 +142,14 @@ static void *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy)
*/
static int
mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
+ const u8 *peer_mac =
+ (type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1)) {
mwifiex_dbg(priv->adapter, ERROR, "deleting the crypto keys\n");
@@ -480,13 +482,15 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
*/
static int
mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
struct mwifiex_wep_key *wep_key;
static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
+ const u8 *peer_mac =
+ (type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP &&
(params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index bb2748a193294..651a527f6881e 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -535,10 +535,13 @@ static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info,
}
static int add_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr,
+ u8 key_index,
+ enum nl80211_key_type type,
+ const u8 *mac_addr,
struct key_params *params)
{
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
int ret = 0, keylen = params->key_len;
const u8 *rx_mic = NULL;
const u8 *tx_mic = NULL;
@@ -641,9 +644,10 @@ static int add_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
static int del_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
u8 key_index,
- bool pairwise,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
struct wilc_vif *vif = netdev_priv(wdev->netdev);
struct wilc_priv *priv = &vif->priv;
@@ -681,10 +685,11 @@ static int del_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
}
static int get_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr,
- void *cookie,
+ u8 key_index, enum nl80211_key_type type,
+ const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params *))
{
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
struct wilc_vif *vif = netdev_priv(wdev->netdev);
struct wilc_priv *priv = &vif->priv;
struct key_params key_params;
diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
index 5cc8cdf594d3e..d4233f5a31dfa 100644
--- a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
+++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
@@ -99,12 +99,14 @@ static void *nxpwifi_cfg80211_get_adapter(struct wiphy *wiphy)
/* cfg80211 operation handler to delete a network key. */
static int
nxpwifi_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev);
static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
+ const u8 *peer_mac =
+ (type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;
int ret;
ret = nxpwifi_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1);
@@ -426,7 +428,8 @@ nxpwifi_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
/* cfg80211 handler for adding an 802.11 encryption key. */
static int
nxpwifi_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev);
@@ -436,7 +439,7 @@ nxpwifi_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
int ret;
eth_broadcast_addr(bc_mac);
- peer_mac = pairwise ? mac_addr : bc_mac;
+ peer_mac = (type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;
if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP &&
(params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index 45e2b7ae96333..d9c84d5ce2548 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -531,10 +531,12 @@ qtnf_dump_station(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int qtnf_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
int ret;
ret = qtnf_cmd_send_add_key(vif, key_index, pairwise, mac_addr, params);
@@ -547,10 +549,12 @@ static int qtnf_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int qtnf_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
int ret;
ret = qtnf_cmd_send_del_key(vif, key_index, pairwise, mac_addr);
diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c
index 2dfa24c54e7d7..2e37e1fafbef5 100644
--- a/drivers/net/wireless/realtek/rtw89/wow.c
+++ b/drivers/net/wireless/realtek/rtw89/wow.c
@@ -669,10 +669,12 @@ static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev,
if (ieee80211_vif_is_mld(wow_vif))
key = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk,
cipher_info->len,
- rtwvif_link->link_id);
+ rtwvif_link->link_id,
+ false);
else
key = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk,
- cipher_info->len, -1);
+ cipher_info->len, -1,
+ false);
kfree(rekey_conf);
if (IS_ERR(key)) {
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
index 1a12261f3e8e5..0cf9ef8959e1b 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
@@ -5645,6 +5645,14 @@ static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband)
BIT(NL80211_IFTYPE_MESH_POINT) | \
BIT(NL80211_IFTYPE_OCB))
+static const u8 iftypes_ext_capa[] = {
+ [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+ [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
+ [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF |
+ WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB,
+ [8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB,
+};
+
static const u8 iftypes_ext_capa_ap[] = {
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
@@ -5669,6 +5677,33 @@ static const struct wiphy_iftype_ext_capab mac80211_hwsim_iftypes_ext_capa[] = {
.eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP |
IEEE80211_EML_CAP_EMLMR_SUPPORT,
.mld_capa_and_ops = MAC80211_HWSIM_MLD_CAPA_OPS,
+ /* CIP works as hwsim does not have control frames */
+ .cip_supported = true,
+ .cip_capabilities = 0,
+ },
+ {
+ .iftype = NL80211_IFTYPE_STATION,
+ .extended_capabilities = iftypes_ext_capa,
+ .extended_capabilities_mask = iftypes_ext_capa,
+ .extended_capabilities_len = sizeof(iftypes_ext_capa),
+ .cip_supported = true,
+ .cip_capabilities = 0,
+ },
+ {
+ .iftype = NL80211_IFTYPE_P2P_CLIENT,
+ .extended_capabilities = iftypes_ext_capa,
+ .extended_capabilities_mask = iftypes_ext_capa,
+ .extended_capabilities_len = sizeof(iftypes_ext_capa),
+ .cip_supported = true,
+ .cip_capabilities = 0,
+ },
+ {
+ .iftype = NL80211_IFTYPE_P2P_GO,
+ .extended_capabilities = iftypes_ext_capa,
+ .extended_capabilities_mask = iftypes_ext_capa,
+ .extended_capabilities_len = sizeof(iftypes_ext_capa),
+ .cip_supported = true,
+ .cip_capabilities = 0,
},
};
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
index 3468d4114f604..be233a471b433 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
@@ -825,7 +825,8 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param
}
static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
char *alg_name;
@@ -904,7 +905,8 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params*))
@@ -913,7 +915,8 @@ static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct adapter *padapter = rtw_netdev_priv(wdev->netdev);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 7fbc51f873ff1..73ac5336a17ad 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1828,6 +1828,7 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_BANDWIDTH_INDICATION = 135,
WLAN_EID_EXT_KNOWN_STA_IDENTIFCATION = 136,
WLAN_EID_EXT_NON_AP_STA_REG_CON = 137,
+ WLAN_EID_EXT_CIP_CAPA = 150,
WLAN_EID_EXT_UHR_OPER = 151,
WLAN_EID_EXT_UHR_CAPA = 152,
WLAN_EID_EXT_MACP = 153,
@@ -2899,4 +2900,25 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
__ieee80211_check_tim(tim, tim_len, aid);
}
+/**
+ * enum ieee80211_cip_cap_fields - CIP Capabilities element fields
+ * @IEEE80211_CIP_CAP_MIC_PADDING: The MIC padding subfield in the CIP
+ * capabilities
+ * @IEEE80211_CIP_CAP_PROTECTED_CTRL_FRAME_ONLY: The MIC Padding For Protected
+ * Control Frames Only bit in CIP capabilities
+ */
+enum ieee80211_cip_cap_fields {
+ IEEE80211_CIP_CAP_MIC_PADDING = 0x0F,
+ IEEE80211_CIP_CAP_PROTECTED_CTRL_FRAME_ONLY = 0x10,
+};
+
+/**
+ * struct ieee80211_cip_cap - CIP Capabilities element
+ *
+ * @v: The value of the Control Integrity Protocol Capability element
+ */
+struct ieee80211_cip_cap {
+ u8 v;
+} __packed;
+
#endif /* LINUX_IEEE80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9aa7d2d4a1841..1ef5f85a93764 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1821,6 +1821,8 @@ struct sta_txpwr {
* @s1g_capa: S1G capabilities of station
* @uhr_capa: UHR capabilities of the station
* @uhr_capa_len: the length of the UHR capabilities
+ * @cip_cap_set: If CIP capabilities are present, required for CIP stations
+ * @cip_cap: CIP capabilities of station
*/
struct link_station_parameters {
const u8 *mld_mac;
@@ -1842,6 +1844,8 @@ struct link_station_parameters {
const struct ieee80211_s1g_cap *s1g_capa;
const struct ieee80211_uhr_cap *uhr_capa;
u8 uhr_capa_len;
+ bool cip_cap_set;
+ u8 cip_cap;
};
/**
@@ -3402,6 +3406,7 @@ struct cfg80211_ml_reconf_req {
* flag is not set.
* @ASSOC_REQ_SPP_AMSDU: SPP A-MSDUs will be used on this connection (if any)
* @ASSOC_REQ_DISABLE_UHR: Disable UHR
+ * @ASSOC_REQ_CIP: Enable Control Integrity Protocol
*/
enum cfg80211_assoc_req_flags {
ASSOC_REQ_DISABLE_HT = BIT(0),
@@ -3413,6 +3418,7 @@ enum cfg80211_assoc_req_flags {
CONNECT_REQ_MLO_SUPPORT = BIT(6),
ASSOC_REQ_SPP_AMSDU = BIT(7),
ASSOC_REQ_DISABLE_UHR = BIT(8),
+ ASSOC_REQ_CIP = BIT(9),
};
/**
@@ -5304,14 +5310,17 @@ struct cfg80211_ops {
unsigned int link_id);
int (*add_key)(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params);
int (*get_key)(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params*));
int (*del_key)(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr);
int (*set_default_key)(struct wiphy *wiphy,
struct net_device *netdev, int link_id,
@@ -6045,6 +6054,8 @@ struct wiphy_vendor_command {
* @eml_capabilities: EML capabilities (for MLO)
* @mld_capa_and_ops: MLD capabilities and operations (for MLO)
* @ext_mld_capa_and_ops: Extended MLD capabilities and operations (for MLO)
+ * @cip_supported: CIP is supported and the capabilities are valid
+ * @cip_capabilities: CIP Capabilities element containing the MIC padding delay
*/
struct wiphy_iftype_ext_capab {
enum nl80211_iftype iftype;
@@ -6054,6 +6065,8 @@ struct wiphy_iftype_ext_capab {
u16 eml_capabilities;
u16 mld_capa_and_ops;
u16 ext_mld_capa_and_ops;
+ bool cip_supported;
+ u8 cip_capabilities;
};
/**
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1172d7b83ed18..15ac95048ce58 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2395,6 +2395,8 @@ static inline bool lockdep_vif_wiphy_mutex_held(struct ieee80211_vif *vif)
* number generation only
* @IEEE80211_KEY_FLAG_SPP_AMSDU: SPP A-MSDUs can be used with this key
* (set by mac80211 from the sta->spp_amsdu flag)
+ * @IEEE80211_KEY_FLAG_CIP: This key is used for the Control Integrity
+ * Protocol, and is either a pairwise key or a CIGTK.
*/
enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0),
@@ -2409,6 +2411,7 @@ enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_NO_AUTO_TX = BIT(9),
IEEE80211_KEY_FLAG_GENERATE_MMIE = BIT(10),
IEEE80211_KEY_FLAG_SPP_AMSDU = BIT(11),
+ IEEE80211_KEY_FLAG_CIP = BIT(12),
};
/**
@@ -2629,6 +2632,7 @@ struct ieee80211_sta_aggregates {
* @eht_cap: EHT capabilities of this STA
* @uhr_cap: UHR capabilities of this STA
* @s1g_cap: S1G capabilities of this STA
+ * @cip_cap: the CIP capabilities of this STA (or zero)
* @agg: per-link data for multi-link aggregation
* @bandwidth: current bandwidth the station can receive with.
* This is the minimum between the peer's capabilities and our own
@@ -2657,6 +2661,7 @@ struct ieee80211_link_sta {
struct ieee80211_sta_eht_cap eht_cap;
struct ieee80211_sta_uhr_cap uhr_cap;
struct ieee80211_sta_s1g_cap s1g_cap;
+ u8 cip_cap;
struct ieee80211_sta_aggregates agg;
@@ -2720,6 +2725,7 @@ struct ieee80211_link_sta {
* @valid_links: bitmap of valid links, or 0 for non-MLO
* @spp_amsdu: indicates whether the STA uses SPP A-MSDU or not.
* @epp_peer: indicates that the peer is an EPP peer.
+ * @cip: indicates whether the STA uses control frame protection or not.
* @nmi: For NDI stations, pointer to the NMI station of the peer.
* @nan_sched: NAN peer schedule for this station. Valid only for NMI stations.
* @ext_mld_capa_ops: the MLD's extended MLD capabilities and operations
@@ -2741,6 +2747,8 @@ struct ieee80211_sta {
u8 max_amsdu_subframes;
u16 eml_cap;
+ bool cip;
+
struct ieee80211_sta_aggregates *cur;
bool support_p2p_ps;
@@ -6278,6 +6286,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
* @key_len: the key data. Might be bigger than the actual key length,
* but not smaller (for the driver convinence)
* @link_id: the link id of the key or -1 for non-MLO
+ * @cigtk: whether this is a CIGTK
*
* When GTK rekeying was done while the system was suspended, (a) new
* key(s) will be available. These will be needed by mac80211 for proper
@@ -6304,7 +6313,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
struct ieee80211_key_conf *
ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
u8 idx, u8 *key_data, u8 key_len,
- int link_id);
+ int link_id, bool cigtk);
/**
* ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9a2ccb8d66b86..843d1dbb725d9 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3190,6 +3190,11 @@ enum nl80211_commands {
* known station to transmit a frame. This is relevant to know whether
* MLD address translation happened or to disable it when sending a frame.
*
+ * @NL80211_ATTR_ASSOC_CIP: Enable Control Integrity Protocol for the
+ * association
+ * @NL80211_ATTR_CIP_CAPABILITIES: The Control Integrity Protocol for the
+ * station.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3792,6 +3797,9 @@ enum nl80211_attrs {
NL80211_ATTR_FRAME_NO_STA,
+ NL80211_ATTR_ASSOC_CIP,
+ NL80211_ATTR_CIP_CAPABILITIES,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3942,6 +3950,7 @@ enum nl80211_iftype {
* that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a
* previously added station into associated state
* @NL80211_STA_FLAG_SPP_AMSDU: station supports SPP A-MSDUs
+ * @NL80211_STA_FLAG_CIP: station has Control Integrity Protocol (CIP) enabled
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
@@ -3955,6 +3964,7 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_TDLS_PEER,
NL80211_STA_FLAG_ASSOCIATED,
NL80211_STA_FLAG_SPP_AMSDU,
+ NL80211_STA_FLAG_CIP,
/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
@@ -5786,12 +5796,16 @@ enum nl80211_auth_type {
* @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
* @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
* @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ * @NL80211_KEYTYPE_CIGTK: Control Integrity Group Temporal Key
+ * The cipher is GMAC-256 but passed as GCMP-256,
+ * same as the pairwise key when used for CIP.
* @NUM_NL80211_KEYTYPES: number of defined key types
*/
enum nl80211_key_type {
NL80211_KEYTYPE_GROUP,
NL80211_KEYTYPE_PAIRWISE,
NL80211_KEYTYPE_PEERKEY,
+ NL80211_KEYTYPE_CIGTK,
NUM_NL80211_KEYTYPES
};
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 23f4f9ec86d0a..3714f8ccdf82d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -611,12 +611,15 @@ static int ieee80211_set_tx(struct ieee80211_sub_if_data *sdata,
}
static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_link_data *link =
ieee80211_link_or_deflink(sdata, link_id, false);
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
+ bool cigtk = type == NL80211_KEYTYPE_CIGTK;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta = NULL;
struct ieee80211_key *key;
@@ -660,6 +663,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
key->conf.link_id = -1;
} else {
key->conf.link_id = link->link_id;
+
+ if (cigtk)
+ key->conf.flags |= IEEE80211_KEY_FLAG_CIP;
}
if (params->mode == NL80211_KEY_NO_TX)
@@ -737,10 +743,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
static struct ieee80211_key *
ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,
- u8 key_idx, bool pairwise, const u8 *mac_addr)
+ u8 key_idx, enum nl80211_key_type type,
+ const u8 *mac_addr)
{
struct ieee80211_local *local __maybe_unused = sdata->local;
struct ieee80211_link_data *link = &sdata->deflink;
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
+ bool cigtk = type == NL80211_KEYTYPE_CIGTK;
struct ieee80211_key *key;
if (link_id >= 0) {
@@ -770,7 +779,11 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,
return wiphy_dereference(local->hw.wiphy,
sta->ptk[key_idx]);
- if (!pairwise &&
+ if (cigtk && key_idx < NUM_CTRL_KEYS)
+ return wiphy_dereference(local->hw.wiphy,
+ link_sta->cigtk[key_idx]);
+
+ if (!pairwise && !cigtk &&
key_idx < NUM_DEFAULT_KEYS +
NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS)
@@ -783,6 +796,9 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,
if (pairwise && key_idx < NUM_DEFAULT_KEYS)
return wiphy_dereference(local->hw.wiphy, sdata->keys[key_idx]);
+ if (cigtk)
+ return wiphy_dereference(local->hw.wiphy, link->cigtk[key_idx]);
+
key = wiphy_dereference(local->hw.wiphy, link->gtk[key_idx]);
if (key)
return key;
@@ -795,8 +811,8 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,
}
static int ieee80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
- const u8 *mac_addr)
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type, const u8 *mac_addr)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_local *local = sdata->local;
@@ -804,7 +820,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
lockdep_assert_wiphy(local->hw.wiphy);
- key = ieee80211_lookup_key(sdata, link_id, key_idx, pairwise, mac_addr);
+ key = ieee80211_lookup_key(sdata, link_id, key_idx, type, mac_addr);
if (!key)
return -ENOENT;
@@ -814,7 +830,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int ieee80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
@@ -833,7 +850,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
rcu_read_lock();
- key = ieee80211_lookup_key(sdata, link_id, key_idx, pairwise, mac_addr);
+ key = ieee80211_lookup_key(sdata, link_id, key_idx, type, mac_addr);
if (!key)
goto out;
@@ -2289,6 +2306,8 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
case STA_LINK_MODE_NEW:
if (!params->link_mac)
return -EINVAL;
+ if (sta->sta.cip && !params->cip_cap_set)
+ return -EINVAL;
break;
case STA_LINK_MODE_LINK_MODIFY:
break;
@@ -2411,6 +2430,9 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
ieee80211_s1g_cap_to_sta_s1g_cap(sdata, params->s1g_capa,
link_sta);
+ if (params->cip_cap_set)
+ link_sta->pub->cip_cap = params->cip_cap;
+
switch (sdata->vif.type) {
case NL80211_IFTYPE_NAN:
case NL80211_IFTYPE_NAN_DATA:
@@ -2573,6 +2595,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (params->eml_cap_present)
sta->sta.eml_cap = params->eml_cap;
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_CIP))
+ sta->sta.cip = true;
+
ret = sta_link_apply_parameters(local, sta, STA_LINK_MODE_STA_MODIFY,
¶ms->link_sta_params);
if (ret)
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 117f58af5ff9d..3a4f8e9e54dc1 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2015 Intel Deutschland GmbH
- * Copyright (C) 2021-2023 Intel Corporation
+ * Copyright (C) 2021-2023, 2026 Intel Corporation
*/
#include <linux/kobject.h>
@@ -42,9 +42,10 @@ static const struct debugfs_short_fops key_ ##name## _ops = { \
KEY_READ_##format(name) \
KEY_OPS(name)
-#define KEY_CONF_READ(name, format_string) \
- KEY_READ(conf_##name, conf.name, format_string)
-#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n")
+#define KEY_CONF_READ(name, val, format_string) \
+ KEY_READ(conf_##name, conf.val, format_string)
+#define KEY_CONF_READ_D(name, val) KEY_CONF_READ(name, val, "%d\n")
+#define KEY_CONF_READ_X(name, val) KEY_CONF_READ(name, val, "0x%x\n")
#define KEY_CONF_OPS(name) \
static const struct debugfs_short_fops key_ ##name## _ops = { \
@@ -53,13 +54,18 @@ static const struct debugfs_short_fops key_ ##name## _ops = { \
}
#define KEY_CONF_FILE(name, format) \
- KEY_CONF_READ_##format(name) \
+ KEY_CONF_READ_##format(name, name) \
+ KEY_CONF_OPS(name)
+#define KEY_CONF_FILE_NAMED(name, val, format) \
+ KEY_CONF_READ_##format(name, val) \
KEY_CONF_OPS(name)
KEY_CONF_FILE(keylen, D);
KEY_CONF_FILE(keyidx, D);
KEY_CONF_FILE(hw_key_idx, D);
+KEY_CONF_FILE_NAMED(conf_flags, flags, X);
KEY_FILE(flags, X);
+KEY_CONF_FILE(link_id, D);
KEY_READ(ifindex, sdata->name, "%s\n");
KEY_OPS(ifindex);
@@ -356,6 +362,8 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key)
DEBUGFS_ADD(mic_failures);
DEBUGFS_ADD(key);
DEBUGFS_ADD(ifindex);
+ DEBUGFS_ADD(conf_flags);
+ DEBUGFS_ADD(link_id);
};
void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9514f01778beb..66231ea8a985d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -486,6 +486,7 @@ struct ieee80211_mgd_assoc_data {
bool comeback; /* whether the AP has requested association comeback */
bool s1g;
bool spp_amsdu;
+ bool cip;
s8 assoc_link_id;
@@ -1113,6 +1114,7 @@ struct ieee80211_link_data {
struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +
NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS];
+ struct ieee80211_key __rcu *cigtk[NUM_CTRL_KEYS];
struct ieee80211_key __rcu *default_multicast_key;
struct ieee80211_key __rcu *default_mgmt_key;
struct ieee80211_key __rcu *default_beacon_key;
@@ -1878,6 +1880,7 @@ struct ieee802_11_elems {
const struct ieee80211_ttlm_elem *ttlm[IEEE80211_TTLM_MAX_CNT];
const struct ieee80211_uhr_cap *uhr_cap;
const struct ieee80211_uhr_operation *uhr_operation;
+ const struct ieee80211_cip_cap *cip_cap;
/* not the order in the psd values is per element, not per chandef */
struct ieee80211_parsed_tpe tpe;
@@ -2778,6 +2781,8 @@ int ieee80211_put_uhr_cap(struct sk_buff *skb,
const struct ieee80211_supported_band *sband);
void ieee80211_put_reg_conn(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
+int ieee80211_put_cip_cap(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata);
/* channel management */
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index f45e792abede5..4c9788ec0b74f 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -205,6 +205,10 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
sta ? sta->sta.addr : bcast_addr, ret);
out_unsupported:
+ /* Control Integrity Protocol can only be done in hardware */
+ if (key->conf.flags & IEEE80211_KEY_FLAG_CIP)
+ return -EINVAL;
+
switch (key->conf.cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
@@ -440,11 +444,13 @@ void ieee80211_set_default_beacon_key(struct ieee80211_link_data *link,
static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
struct ieee80211_link_data *link,
struct sta_info *sta,
- bool pairwise,
+ enum ieee80211_key_flags flags,
struct ieee80211_key *old,
struct ieee80211_key *new)
{
struct link_sta_info *link_sta = sta ? &sta->deflink : NULL;
+ bool pairwise = flags & IEEE80211_KEY_FLAG_PAIRWISE;
+ bool cip = flags & IEEE80211_KEY_FLAG_CIP;
int link_id;
int idx;
int ret = 0;
@@ -535,6 +541,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (new &&
!(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX))
_ieee80211_set_tx_key(new, true);
+ } else if (cip) {
+ rcu_assign_pointer(link_sta->cigtk[idx], new);
} else {
rcu_assign_pointer(link_sta->gtk[idx], new);
}
@@ -569,6 +577,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (is_wep || pairwise)
rcu_assign_pointer(sdata->keys[idx], new);
+ else if (cip)
+ rcu_assign_pointer(link->cigtk[idx], new);
else
rcu_assign_pointer(link->gtk[idx], new);
@@ -883,6 +893,10 @@ int ieee80211_key_link(struct ieee80211_key *key,
ret = -EOPNOTSUPP;
goto out;
}
+
+ /* Set CIP flag if enabled for the station */
+ if (sta->sta.cip)
+ key->conf.flags |= IEEE80211_KEY_FLAG_CIP;
} else if (sta) {
struct link_sta_info *link_sta = &sta->deflink;
int link_id = key->conf.link_id;
@@ -896,15 +910,25 @@ int ieee80211_key_link(struct ieee80211_key *key,
}
}
- old_key = wiphy_dereference(sdata->local->hw.wiphy,
- link_sta->gtk[idx]);
- } else {
- if (idx < NUM_DEFAULT_KEYS)
+ if (key->conf.flags & IEEE80211_KEY_FLAG_CIP)
old_key = wiphy_dereference(sdata->local->hw.wiphy,
- sdata->keys[idx]);
- if (!old_key)
+ link_sta->cigtk[idx]);
+ else
old_key = wiphy_dereference(sdata->local->hw.wiphy,
- link->gtk[idx]);
+ link_sta->gtk[idx]);
+ } else {
+ if (key->conf.flags & IEEE80211_KEY_FLAG_CIP) {
+ old_key = wiphy_dereference(sdata->local->hw.wiphy,
+ link->cigtk[idx]);
+ } else {
+ if (idx < NUM_DEFAULT_KEYS)
+ old_key = wiphy_dereference(sdata->local->hw.wiphy,
+ sdata->keys[idx]);
+
+ if (!old_key)
+ old_key = wiphy_dereference(sdata->local->hw.wiphy,
+ link->gtk[idx]);
+ }
}
/* Non-pairwise keys must also not switch the cipher on rekey */
@@ -938,9 +962,17 @@ int ieee80211_key_link(struct ieee80211_key *key,
if (sta && sta->sta.spp_amsdu)
key->conf.flags |= IEEE80211_KEY_FLAG_SPP_AMSDU;
+ /* A CIP related key must be GCMP-256 (really GMAC-256) */
+ if ((key->conf.flags & IEEE80211_KEY_FLAG_CIP) &&
+ key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256) {
+ ret = -EINVAL;
+ goto out;
+ }
+
increment_tailroom_need_count(sdata);
- ret = ieee80211_key_replace(sdata, link, sta, pairwise, old_key, key);
+ ret = ieee80211_key_replace(sdata, link, sta, key->conf.flags,
+ old_key, key);
if (!ret) {
ieee80211_debugfs_key_add(key);
@@ -966,8 +998,7 @@ void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
*/
if (key->sdata)
ieee80211_key_replace(key->sdata, NULL, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
ieee80211_key_destroy(key, delay_tailroom);
}
@@ -1098,8 +1129,7 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
ieee80211_key_replace(key->sdata, NULL, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
list_add_tail(&key->list, keys);
}
@@ -1119,8 +1149,7 @@ void ieee80211_remove_link_keys(struct ieee80211_link_data *link,
if (key->conf.link_id != link->link_id)
continue;
ieee80211_key_replace(key->sdata, link, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
list_add_tail(&key->list, keys);
}
}
@@ -1196,8 +1225,17 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
if (!key)
continue;
ieee80211_key_replace(key->sdata, NULL, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
+ __ieee80211_key_destroy(key, key->sdata->vif.type ==
+ NL80211_IFTYPE_STATION);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sta->deflink.cigtk); i++) {
+ key = wiphy_dereference(local->hw.wiphy, sta->deflink.cigtk[i]);
+ if (!key)
+ continue;
+ ieee80211_key_replace(key->sdata, NULL, key->sta,
+ key->conf.flags, key, NULL);
__ieee80211_key_destroy(key, key->sdata->vif.type ==
NL80211_IFTYPE_STATION);
}
@@ -1207,8 +1245,7 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
if (!key)
continue;
ieee80211_key_replace(key->sdata, NULL, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
__ieee80211_key_destroy(key, key->sdata->vif.type ==
NL80211_IFTYPE_STATION);
}
@@ -1366,7 +1403,7 @@ EXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq);
struct ieee80211_key_conf *
ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
u8 idx, u8 *key_data, u8 key_len,
- int link_id)
+ int link_id, bool cigtk)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
@@ -1390,10 +1427,20 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
NUM_DEFAULT_BEACON_KEYS))
return ERR_PTR(-EINVAL);
- prev_key = wiphy_dereference(local->hw.wiphy,
- link_data->gtk[idx]);
+ if (WARN_ON(cigtk && idx >= NUM_CTRL_KEYS))
+ return ERR_PTR(-EINVAL);
+
+ if (cigtk)
+ prev_key = wiphy_dereference(local->hw.wiphy,
+ link_data->cigtk[idx]);
+ else
+ prev_key = wiphy_dereference(local->hw.wiphy,
+ link_data->gtk[idx]);
if (!prev_key) {
- if (idx < NUM_DEFAULT_KEYS) {
+ if (cigtk) {
+ prev_key = wiphy_dereference(local->hw.wiphy,
+ link_data->cigtk[idx ^ 1]);
+ } else if (idx < NUM_DEFAULT_KEYS) {
for (int i = 0; i < NUM_DEFAULT_KEYS; i++) {
if (i == idx)
continue;
@@ -1424,6 +1471,9 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)
key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
+ if (prev_key->conf.flags & IEEE80211_KEY_FLAG_CIP)
+ key->conf.flags |= IEEE80211_KEY_FLAG_CIP;
+
key->conf.link_id = link_data->link_id;
err = ieee80211_key_link(key, link_data, NULL);
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 826e4e9387c55..c85992493afd1 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -2,7 +2,7 @@
/*
* Copyright 2002-2004, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
- * Copyright (C) 2019, 2022-2023 Intel Corporation
+ * Copyright (C) 2019, 2022-2023, 2026 Intel Corporation
*/
#ifndef IEEE80211_KEY_H
@@ -19,6 +19,7 @@
#define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2
#define NUM_DEFAULT_BEACON_KEYS 2
+#define NUM_CTRL_KEYS 2
#define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */
struct ieee80211_local;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cf3873d8855b6..76c45a0eea621 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2337,6 +2337,10 @@ ieee80211_add_link_elems(struct ieee80211_sub_if_data *sdata,
ieee80211_put_eht_cap(skb, sdata, sband,
&assoc_data->link[link_id].conn);
+ /* Insert CIP only on the assoc link (it will be inherited) */
+ if (link_id == assoc_data->assoc_link_id && assoc_data->cip)
+ ieee80211_put_cip_cap(skb, sdata);
+
if (assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_UHR)
ieee80211_put_uhr_cap(skb, sdata, sband);
@@ -2613,7 +2617,8 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
assoc_data->ie_len + /* extra IEs */
(assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
9 /* WMM */ +
- 4 /* regulatory connectivity, if 6 GHz is supported */;
+ 4 /* regulatory connectivity, if 6 GHz is supported */ +
+ (assoc_data->cip ? 4 /* CIP capabilities */ : 0);
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
struct cfg80211_bss *cbss = assoc_data->link[link_id].bss;
@@ -6274,6 +6279,17 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
/* TODO: OPEN: what happens if BSS color disable is set? */
}
+ if (assoc_data->cip) {
+ if (elems->cip_cap) {
+ link_sta->pub->cip_cap = elems->cip_cap->v;
+ } else {
+ sdata_info(sdata,
+ "CIP Capabilities not included in association response\n");
+ ret = false;
+ goto out;
+ }
+ }
+
if (cbss->transmitted_bss) {
bss_conf->nontransmitted = true;
ether_addr_copy(bss_conf->transmitter_bssid,
@@ -6999,6 +7015,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out_err;
sta->sta.spp_amsdu = assoc_data->spp_amsdu;
+ sta->sta.cip = assoc_data->cip;
if (ieee80211_vif_is_mld(&sdata->vif)) {
if (!elems->ml_basic)
@@ -10536,6 +10553,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
}
assoc_data->spp_amsdu = req->flags & ASSOC_REQ_SPP_AMSDU;
+ assoc_data->cip = req->flags & ASSOC_REQ_CIP;
if (ifmgd->auth_data && !ifmgd->auth_data->done) {
err = -EBUSY;
diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c
index cb2be167cde79..3b66ca7d7a5c2 100644
--- a/net/mac80211/parse.c
+++ b/net/mac80211/parse.c
@@ -205,6 +205,10 @@ ieee80211_parse_extension_element(u32 *crc,
elems->ttlm_num++;
}
break;
+ case WLAN_EID_EXT_CIP_CAPA:
+ if (len >= sizeof(*elems->cip_cap))
+ elems->cip_cap = data;
+ break;
case WLAN_EID_EXT_UHR_OPER:
if (params->mode < IEEE80211_CONN_MODE_UHR)
break;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index ee0d32877c5b4..f409f6a3afa1f 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -485,6 +485,7 @@ struct ieee80211_fragment_cache {
* @link_hash_node: hash node for rhashtable
* @sta: Points to the STA info
* @gtk: group keys negotiated with this station, if any
+ * @cigtk: control integrity group keys negotiated with this station, if any
* @tx_stats: TX statistics
* @tx_stats.packets: # of packets transmitted
* @tx_stats.bytes: # of bytes in all packets transmitted
@@ -535,6 +536,7 @@ struct link_sta_info {
struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +
NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS];
+ struct ieee80211_key __rcu *cigtk[NUM_CTRL_KEYS];
struct ieee80211_sta_rx_stats __percpu *pcpu_rx_stats;
/* Updated from RX path only, no locking requirements */
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index e2b5b2b21c347..c193a75ef06ea 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -4680,6 +4680,25 @@ int ieee80211_put_uhr_cap(struct sk_buff *skb,
return 0;
}
+int ieee80211_put_cip_cap(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata)
+{
+ const struct wiphy_iftype_ext_capab *ift_ext_capa =
+ cfg80211_get_iftype_ext_capa(sdata->local->hw.wiphy,
+ ieee80211_vif_type_p2p(&sdata->vif));
+ u8 cip_capabilities = ift_ext_capa ? ift_ext_capa->cip_capabilities : 0;
+
+ if (skb_tailroom(skb) < 4)
+ return -ENOBUFS;
+
+ skb_put_u8(skb, WLAN_EID_EXTENSION);
+ skb_put_u8(skb, 2);
+ skb_put_u8(skb, WLAN_EID_EXT_CIP_CAPA);
+ skb_put_u8(skb, cip_capabilities);
+
+ return 0;
+}
+
const char *ieee80211_conn_mode_str(enum ieee80211_conn_mode mode)
{
static const char * const modes[] = {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b4610f6685dcb..508d731fbf336 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -443,13 +443,16 @@ void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev);
/* internal helpers */
bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
+bool cfg80211_cigtk_supported(struct wireless_dev *wdev,
+ struct genl_info *info);
bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
- int key_idx, bool pairwise,
+ int key_idx, enum nl80211_key_type type,
const u8 *mac_addr);
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct key_params *params, int key_idx,
- bool pairwise, const u8 *mac_addr);
+ enum nl80211_key_type type,
+ const u8 *mac_addr);
void __cfg80211_scan_done(struct wiphy *wiphy, struct wiphy_work *wk);
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
bool send_message);
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index b1d748bdb504e..6ae561ed7f37f 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -172,7 +172,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
*/
if (rdev->ops->del_key)
for (i = 0; i < 6; i++)
- rdev_del_key(rdev, wdev, -1, i, false, NULL);
+ rdev_del_key(rdev, wdev, -1, i, NL80211_KEYTYPE_GROUP,
+ NULL);
if (wdev->u.ibss.current_bss) {
cfg80211_unhold_bss(wdev->u.ibss.current_bss);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ab5a14f5fe283..bfba773c6d9c1 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1098,6 +1098,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
NLA_POLICY_FULL_RANGE(NLA_U32, &nl80211_punct_bitmap_range),
[NL80211_ATTR_STA_DUMP_LINK_STATS] = { .type = NLA_FLAG },
[NL80211_ATTR_FRAME_NO_STA] = { .type = NLA_FLAG },
+ [NL80211_ATTR_ASSOC_CIP] = { .type = NLA_FLAG },
+ [NL80211_ATTR_CIP_CAPABILITIES] = { .type = NLA_U8 },
};
/* policy for the key attributes */
@@ -1763,6 +1765,11 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
GENL_SET_ERR_MSG(info, "def key idx not 0-3");
return -EINVAL;
}
+ } else if (k->type == NL80211_KEYTYPE_CIGTK) {
+ if (k->idx < 0 || k->idx > 1) {
+ GENL_SET_ERR_MSG(info, "CIGTK idx not 0-1");
+ return -EINVAL;
+ }
} else {
if (k->idx < 0 || k->idx > 7) {
GENL_SET_ERR_MSG(info, "key idx not 0-7");
@@ -1827,7 +1834,9 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
} else if (parse.defmgmt)
goto error;
err = cfg80211_validate_key_settings(rdev, wdev, &parse.p,
- parse.idx, false, NULL);
+ parse.idx,
+ NL80211_KEYTYPE_GROUP,
+ NULL);
if (err)
goto error;
if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
@@ -3617,6 +3626,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
NL80211_ATTR_EXT_MLD_CAPA_AND_OPS,
capab->ext_mld_capa_and_ops))
goto nla_put_failure;
+ if (capab->cip_supported &&
+ nla_put_u8(msg,
+ NL80211_ATTR_CIP_CAPABILITIES,
+ capab->cip_capabilities))
+ goto nla_put_failure;
nla_nest_end(msg, nested_ext_capab);
if (state->split)
@@ -5373,6 +5387,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
struct wireless_dev *wdev = info->user_ptr[1];
u8 key_idx = 0;
const u8 *mac_addr = NULL;
+ enum nl80211_key_type type;
bool pairwise;
struct get_key_cookie cookie = {
.error = 0,
@@ -5405,19 +5420,24 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
pairwise = !!mac_addr;
+ type = pairwise ? NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP;
if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
- u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
+ type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
- if (kt != NL80211_KEYTYPE_GROUP &&
- kt != NL80211_KEYTYPE_PAIRWISE)
+ if (type != NL80211_KEYTYPE_GROUP &&
+ type != NL80211_KEYTYPE_PAIRWISE &&
+ type != NL80211_KEYTYPE_CIGTK) {
+ GENL_SET_ERR_MSG(info, "key type not pairwise, group or CIGTK");
return -EINVAL;
- pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
+ }
+
+ pairwise = type == NL80211_KEYTYPE_PAIRWISE;
}
if (!rdev->ops->get_key)
return -EOPNOTSUPP;
- if (!cfg80211_valid_key_idx(wdev, key_idx, pairwise, mac_addr))
+ if (!cfg80211_valid_key_idx(wdev, key_idx, type, mac_addr))
return -ENOENT;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -5446,7 +5466,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (err)
goto free_msg;
- err = rdev_get_key(rdev, wdev, link_id, key_idx, pairwise, mac_addr,
+ err = rdev_get_key(rdev, wdev, link_id, key_idx, type, mac_addr,
&cookie, get_key_callback);
if (err)
@@ -5605,8 +5625,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
/* for now */
if (key.type != NL80211_KEYTYPE_PAIRWISE &&
- key.type != NL80211_KEYTYPE_GROUP) {
- GENL_SET_ERR_MSG(info, "key type not pairwise or group");
+ key.type != NL80211_KEYTYPE_GROUP &&
+ key.type != NL80211_KEYTYPE_CIGTK) {
+ GENL_SET_ERR_MSG(info, "key type not pairwise, group or CIGTK");
return -EINVAL;
}
@@ -5618,8 +5639,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
return -EOPNOTSUPP;
if (cfg80211_validate_key_settings(rdev, wdev, &key.p, key.idx,
- key.type == NL80211_KEYTYPE_PAIRWISE,
- mac_addr)) {
+ key.type, mac_addr)) {
GENL_SET_ERR_MSG(info, "key setting validation failed");
return -EINVAL;
}
@@ -5633,8 +5653,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
key.type == NL80211_KEYTYPE_PAIRWISE);
if (!err) {
- err = rdev_add_key(rdev, wdev, link_id, key.idx,
- key.type == NL80211_KEYTYPE_PAIRWISE,
+ err = rdev_add_key(rdev, wdev, link_id, key.idx, key.type,
mac_addr, &key.p);
if (err)
GENL_SET_ERR_MSG(info, "key addition failed");
@@ -5668,12 +5687,13 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
/* for now */
if (key.type != NL80211_KEYTYPE_PAIRWISE &&
- key.type != NL80211_KEYTYPE_GROUP)
+ key.type != NL80211_KEYTYPE_GROUP &&
+ key.type != NL80211_KEYTYPE_CIGTK) {
+ GENL_SET_ERR_MSG(info, "key type not pairwise, group or CIGTK");
return -EINVAL;
+ }
- if (!cfg80211_valid_key_idx(wdev, key.idx,
- key.type == NL80211_KEYTYPE_PAIRWISE,
- mac_addr))
+ if (!cfg80211_valid_key_idx(wdev, key.idx, key.type, mac_addr))
return -EINVAL;
if (!rdev->ops->del_key)
@@ -5687,8 +5707,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (!err)
err = rdev_del_key(rdev, wdev, link_id, key.idx,
- key.type == NL80211_KEYTYPE_PAIRWISE,
- mac_addr);
+ key.type, mac_addr);
#ifdef CONFIG_CFG80211_WEXT
if (!err) {
@@ -8819,7 +8838,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
return -EINVAL;
/* When you run into this, adjust the code below for the new flag */
- BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 8);
+ BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 9);
switch (statype) {
case CFG80211_STA_MESH_PEER_KERNEL:
@@ -8913,7 +8932,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
BIT(NL80211_STA_FLAG_WME) |
BIT(NL80211_STA_FLAG_MFP) |
- BIT(NL80211_STA_FLAG_SPP_AMSDU)))
+ BIT(NL80211_STA_FLAG_SPP_AMSDU) |
+ BIT(NL80211_STA_FLAG_CIP)))
return -EINVAL;
/* but authenticated/associated only if driver handles it */
@@ -9290,6 +9310,22 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
nla_get_u16(info->attrs[NL80211_ATTR_EML_CAPABILITY]);
}
+ if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_CIP) &&
+ params.sta_flags_set & BIT(NL80211_STA_FLAG_CIP)) {
+ if (!cfg80211_cigtk_supported(wdev, info))
+ return -EINVAL;
+
+ /* CIP capabilities are required if CIP is being enabled */
+ if (info->attrs[NL80211_ATTR_CIP_CAPABILITIES]) {
+ params.link_sta_params.cip_cap_set = true;
+ params.link_sta_params.cip_cap =
+ nla_get_u8(info->attrs[NL80211_ATTR_CIP_CAPABILITIES]);
+ } else {
+ GENL_SET_ERR_MSG(info, "No CIP capabilities provided");
+ return -EINVAL;
+ }
+ }
+
if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
params.airtime_weight =
nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
@@ -9489,6 +9525,22 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
nla_get_u16(info->attrs[NL80211_ATTR_EML_CAPABILITY]);
}
+ if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_CIP) &&
+ params.sta_flags_set & BIT(NL80211_STA_FLAG_CIP)) {
+ if (!cfg80211_cigtk_supported(wdev, info))
+ return -EINVAL;
+
+ /* CIP capabilities are required if CIP is enabled */
+ if (info->attrs[NL80211_ATTR_CIP_CAPABILITIES]) {
+ params.link_sta_params.cip_cap_set = true;
+ params.link_sta_params.cip_cap =
+ nla_get_u8(info->attrs[NL80211_ATTR_CIP_CAPABILITIES]);
+ } else {
+ GENL_SET_ERR_MSG(info, "No CIP capabilities provided");
+ return -EINVAL;
+ }
+ }
+
if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
params.link_sta_params.he_6ghz_capa =
nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
@@ -9566,7 +9618,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
/* When you run into this, adjust the code below for the new flag */
- BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 8);
+ BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 9);
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
@@ -9595,6 +9647,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.sta_flags_mask & BIT(NL80211_STA_FLAG_SPP_AMSDU))
return -EINVAL;
+ if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_CIP) &&
+ !cfg80211_cigtk_supported(wdev, info))
+ return -EINVAL;
+
/* Older userspace, or userspace wanting to be compatible with
* !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
* and assoc flags in the mask, but assumes the station will be
@@ -13321,6 +13377,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
req.flags |= ASSOC_REQ_SPP_AMSDU;
}
+ if (nla_get_flag(info->attrs[NL80211_ATTR_ASSOC_CIP])) {
+ if (!cfg80211_cigtk_supported(dev->ieee80211_ptr, info))
+ return -EINVAL;
+
+ req.flags |= ASSOC_REQ_CIP;
+ }
+
req.link_id = nl80211_link_id_or_invalid(info->attrs);
if (info->attrs[NL80211_ATTR_MLO_LINKS]) {
@@ -19201,6 +19264,23 @@ nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info,
params.he_6ghz_capa =
nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
+ if (info->attrs[NL80211_ATTR_CIP_CAPABILITIES]) {
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (!cfg80211_cigtk_supported(wdev, info))
+ return -EINVAL;
+
+ params.cip_cap_set = true;
+ params.cip_cap =
+ nla_get_u8(info->attrs[NL80211_ATTR_CIP_CAPABILITIES]);
+
+ /* Only permit CIP capabilities when adding link stations */
+ if (!add) {
+ GENL_SET_ERR_MSG(info, "Cannot modify CIP capabilities");
+ return -EINVAL;
+ }
+ }
+
if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
params.opmode_notif_used = true;
params.opmode_notif =
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 46849fe8d0b39..7653cd0da9b93 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -78,42 +78,43 @@ rdev_change_virtual_intf(struct cfg80211_registered_device *rdev,
static inline int rdev_add_key(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr,
- struct key_params *params)
+ u8 key_index, enum nl80211_key_type type,
+ const u8 *mac_addr, struct key_params *params)
{
int ret;
- trace_rdev_add_key(&rdev->wiphy, wdev, link_id, key_index, pairwise,
+ trace_rdev_add_key(&rdev->wiphy, wdev, link_id, key_index, type,
mac_addr, params->mode);
ret = rdev->ops->add_key(&rdev->wiphy, wdev, link_id, key_index,
- pairwise, mac_addr, params);
+ type, mac_addr, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_get_key(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise, const u8 *mac_addr,
- void *cookie,
+ int link_id, u8 key_index, enum nl80211_key_type type,
+ const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params*))
{
int ret;
- trace_rdev_get_key(&rdev->wiphy, wdev, link_id, key_index, pairwise,
+ trace_rdev_get_key(&rdev->wiphy, wdev, link_id, key_index, type,
mac_addr);
ret = rdev->ops->get_key(&rdev->wiphy, wdev, link_id, key_index,
- pairwise, mac_addr, cookie, callback);
+ type, mac_addr, cookie, callback);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_del_key(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr)
+ u8 key_index, enum nl80211_key_type type,
+ const u8 *mac_addr)
{
int ret;
- trace_rdev_del_key(&rdev->wiphy, wdev, link_id, key_index, pairwise,
+ trace_rdev_del_key(&rdev->wiphy, wdev, link_id, key_index, type,
mac_addr);
ret = rdev->ops->del_key(&rdev->wiphy, wdev, link_id, key_index,
- pairwise, mac_addr);
+ type, mac_addr);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 2a719b5c487e3..458f72d8351ab 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -1387,7 +1387,15 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
max_key_idx = 7;
for (i = 0; i <= max_key_idx; i++)
- rdev_del_key(rdev, wdev, -1, i, false, NULL);
+ rdev_del_key(rdev, wdev, -1, i, NL80211_KEYTYPE_GROUP,
+ NULL);
+
+ if (cfg80211_cigtk_supported(wdev, NULL)) {
+ rdev_del_key(rdev, wdev, -1, 0, NL80211_KEYTYPE_CIGTK,
+ NULL);
+ rdev_del_key(rdev, wdev, -1, 1, NL80211_KEYTYPE_CIGTK,
+ NULL);
+ }
}
rdev_set_qos_map(rdev, dev, NULL);
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 8c2a91b85c396..c210ca1e44e2b 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -557,15 +557,15 @@ TRACE_EVENT(rdev_change_virtual_intf,
DECLARE_EVENT_CLASS(key_handle,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr),
- TP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr),
+ u8 key_index, enum nl80211_key_type type, const u8 *mac_addr),
+ TP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
MAC_ENTRY(mac_addr)
__field(int, link_id)
__field(u8, key_index)
- __field(bool, pairwise)
+ __field(u8, type)
),
TP_fast_assign(
WIPHY_ASSIGN;
@@ -573,38 +573,40 @@ DECLARE_EVENT_CLASS(key_handle,
MAC_ASSIGN(mac_addr, mac_addr);
__entry->link_id = link_id;
__entry->key_index = key_index;
- __entry->pairwise = pairwise;
+ __entry->type = type;
),
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %d, "
- "key_index: %u, pairwise: %s, mac addr: %pM",
+ "key_index: %u, pairwise: %s, type: %d, mac addr: %pM",
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id,
- __entry->key_index, BOOL_TO_STR(__entry->pairwise),
- __entry->mac_addr)
+ __entry->key_index,
+ BOOL_TO_STR(__entry->type == NL80211_KEYTYPE_PAIRWISE),
+ __entry->type, __entry->mac_addr)
);
DEFINE_EVENT(key_handle, rdev_get_key,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr),
- TP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr)
+ u8 key_index, enum nl80211_key_type type, const u8 *mac_addr),
+ TP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr)
);
DEFINE_EVENT(key_handle, rdev_del_key,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr),
- TP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr)
+ u8 key_index, enum nl80211_key_type type, const u8 *mac_addr),
+ TP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr)
);
TRACE_EVENT(rdev_add_key,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr, u8 mode),
- TP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr, mode),
+ u8 key_index, enum nl80211_key_type type, const u8 *mac_addr,
+ u8 mode),
+ TP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr, mode),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
MAC_ENTRY(mac_addr)
__field(int, link_id)
__field(u8, key_index)
- __field(bool, pairwise)
+ __field(u8, type)
__field(u8, mode)
),
TP_fast_assign(
@@ -613,15 +615,16 @@ TRACE_EVENT(rdev_add_key,
MAC_ASSIGN(mac_addr, mac_addr);
__entry->link_id = link_id;
__entry->key_index = key_index;
- __entry->pairwise = pairwise;
+ __entry->type = type;
__entry->mode = mode;
),
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %d, "
- "key_index: %u, mode: %u, pairwise: %s, "
+ "key_index: %u, mode: %u, pairwise: %s, type: %d, "
"mac addr: %pM",
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id,
__entry->key_index, __entry->mode,
- BOOL_TO_STR(__entry->pairwise), __entry->mac_addr)
+ BOOL_TO_STR(__entry->type == NL80211_KEYTYPE_PAIRWISE),
+ __entry->type, __entry->mac_addr)
);
TRACE_EVENT(rdev_set_default_key,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 3e584d0ca3e26..dd166c352910f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -258,8 +258,24 @@ static bool cfg80211_igtk_cipher_supported(struct wiphy *wiphy)
return false;
}
+bool cfg80211_cigtk_supported(struct wireless_dev *wdev,
+ struct genl_info *info)
+{
+ const struct wiphy_iftype_ext_capab *ext_capab =
+ cfg80211_get_iftype_ext_capa(wdev->wiphy, wdev->iftype);
+
+ if (ext_capab && ext_capab->cip_supported)
+ return true;
+
+ if (info)
+ GENL_SET_ERR_MSG(info,
+ "Control Integrity Protocol not supported");
+
+ return false;
+}
+
bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
- int key_idx, bool pairwise,
+ int key_idx, enum nl80211_key_type type,
const u8 *mac_addr)
{
if (WARN_ON(!wdev))
@@ -272,13 +288,24 @@ bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
* Can't differentiate ciphers here so allow 0..3.
* Pairwise keys must be for a station (MAC address given).
*/
- if (pairwise) {
+ if (type == NL80211_KEYTYPE_PAIRWISE) {
if (!mac_addr)
return false;
return key_idx < 4;
}
+ /* Check the wdev/iftype supports CIGTK */
+ if (type == NL80211_KEYTYPE_CIGTK) {
+ if (!cfg80211_cigtk_supported(wdev, NULL))
+ return false;
+
+ if (key_idx >= 2)
+ return false;
+
+ /* fallthrough for mac_addr checks */
+ }
+
/*
* For group keys, mac_addr==NULL means setting a group key
* for TX, which is only supported on some interface types,
@@ -343,9 +370,12 @@ bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct key_params *params, int key_idx,
- bool pairwise, const u8 *mac_addr)
+ enum nl80211_key_type type,
+ const u8 *mac_addr)
{
- if (!cfg80211_valid_key_idx(wdev, key_idx, pairwise, mac_addr))
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
+
+ if (!cfg80211_valid_key_idx(wdev, key_idx, type, mac_addr))
return -EINVAL;
switch (params->cipher) {
@@ -1172,7 +1202,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
for (i = 0; i < 4; i++) {
if (!wdev->connect_keys->params[i].cipher)
continue;
- if (rdev_add_key(rdev, wdev, -1, i, false, NULL,
+ if (rdev_add_key(rdev, wdev, -1, i, NL80211_KEYTYPE_GROUP, NULL,
&wdev->connect_keys->params[i])) {
netdev_err(dev, "failed to set key %d\n", i);
continue;
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index d45bc08c0de49..ec2389f6b8b18 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -401,6 +401,8 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
int idx, struct key_params *params)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
+ enum nl80211_key_type key_type =
+ pairwise ? NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP;
int err, i;
bool rejoin = false;
@@ -454,11 +456,11 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
rejoin = true;
}
- if (!cfg80211_valid_key_idx(wdev, idx, pairwise, addr))
+ if (!cfg80211_valid_key_idx(wdev, idx, key_type, addr))
err = -ENOENT;
else
- err = rdev_del_key(rdev, wdev, -1, idx, pairwise,
- addr);
+ err = rdev_del_key(rdev, wdev, -1, idx,
+ key_type, addr);
}
wdev->wext.connect.privacy = false;
/*
|
| 3/2 | 2026/09/23 10:50 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 35329 output: 39 thoughts: 907 Thoughts: **Worthwhile Fuzzing Target: CIP/CIGTK Implementation in mac80211** Okay, so I'm looking at a patch that's delving into the wireless subsystem, specifically the mac80211, cfg80211, and nl80211 layers, and several drivers as well. The target architecture is amd64. This immediately piques my interest; anything touching the wireless stack is always a prime candidate for fuzzing. Diving deeper, the core of this patch seems to be about adding support for CIP (Control Integrity Protocol) and CIGTK (Control Integrity Group Temporal Key) within mac80211, cfg80211, and nl80211. I see that even `mac80211_hwsim` has been tweaked to enable CIP support, which is insightful because that software-simulated environment is incredibly valuable for testing. This alone strongly suggests this is reachable. The patch modifies key management ops (`add_key`, `del_key`, `get_key`) within `cfg80211_ops`, switching from a `bool pairwise` to an `enum nl80211_key_type type`. My initial thought is that this introduces a new attack surface. Looking at the modifications in `net/wireless/nl80211.c` and mac80211 itself, I can see significant changes to how keys are handled, added, deleted, and looked up. Specifically in nl80211 I see `nl80211_parse_key`, `nl80211_get_key`, `nl80211_new_key`, `nl80211_del_key`, etc. in mac80211 I see `ieee80211_add_key`, `ieee80211_lookup_key`, etc. The netlink interface seems to be getting more complex with the introduction of new attributes (NL80211_ATTR_ASSOC_CIP, NL80211_ATTR_CIP_CAPABILITIES, etc.) and handling for CIGTK keys within station and default link structures. I'm noting specific functions such as `ieee80211_gtk_rekey_add` with assertions (WARN_ON) that warrant a closer look. Now, let's determine if this is a good fuzzing target based on our guidelines. My expert opinion is that this is reachable and valuable. nl80211 is exposed directly to userspace via generic netlink, which is an immediate win for fuzzing as it's a well-known entry point. The fact that `mac80211_hwsim` is included and is widely supported by QEMU and syzkaller is another huge advantage. Syzkaller's existing descriptions of netlink nl80211 and mac80211_hwsim make it an ideal candidate, and I think I can almost guarantee that this warrants fuzzing. This patch appears to implement new netlink attributes, handle key operations for CIGTK, and introduces some new defensive checks, which are all ideal features for fuzzing. My next step? Check the Kconfig options required to enable this functionality using grepper or by inspecting the Kconfig files. This will tell me how to build the kernel with the necessary features to reach this code during fuzzing. |
| 4/2 | 2026/09/23 10:50 | 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"
} |
| 5/2 | 2026/09/23 10:50 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 37086 output: 36 thoughts: 47 Thoughts: Here's my take on the thought process: **Diving into Wireless Driver Dependencies** Okay, time to get to the heart of this. I need to understand the relationships between those wireless driver components. Let's head straight to `drivers/net/wireless/virtual/Kconfig`. That's where the dependencies are defined. I'm thinking specifically about `MAC80211_HWSIM`, `CFG80211`, and `MAC80211` – the core players. By examining the Kconfig, I can determine which options rely on which, how they are interlinked, and what other configurations need to be in place for them to function correctly. This is the starting point for really digging into how everything fits together in the wireless subsystem. |
| 6/2 | 2026/09/23 10:50 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/virtual/Kconfig",
"FirstLine": 1,
"LineCount": 30
}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"
} |
| 7/2 | 2026/09/23 10:50 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 37660 output: 32 thoughts: 38 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Kernel Configuration Hunting** Alright, time to get this sorted. I need to dive into the kernel configuration files for the wireless subsystem. Specifically, I'm thinking I should start by meticulously examining `net/wireless/Kconfig` and `net/mac80211/Kconfig`. These are the likely places where the configuration options for CFG80211 and MAC80211 are defined. I'll be looking for dependencies, default settings, and any conditional logic tied to those specific modules. I'll need to understand how these modules are enabled, and any related options that could be at play. Gotta make sure I'm not missing any pieces of the puzzle that might influence my end goal. Let's see what the Kconfig files reveal. |
| 8/2 | 2026/09/23 10:50 | tool | read-file |
0mArgs:{
"File": "net/wireless/Kconfig",
"FirstLine": 1,
"LineCount": 50
}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 41:\t\t The nl80211 testmode command helps implementing things like\n 42:\t\t factory calibration or validation tools for wireless chips.\n 43:\t\n 44:\t\t Select this option ONLY for kernels that are specifically\n 45:\t\t built for such purposes.\n 46:\t\n 47:\t\t Debugging tools that are supposed to end up in the hands of\n 48:\t\t users should better be implemented with debugfs.\n 49:\t\n 50:\t\t Say N.\n"
} |
| 9/2 | 2026/09/23 10:50 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 38579 output: 37 thoughts: 17 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Investigating Kconfig for Configuration Options** Alright, I'm digging into this. We're looking at some potential configuration adjustments, and I need to make sure we've considered every relevant aspect. My immediate thought is to expand our search. We've been focusing on certain areas, but let's not overlook `net/mac80211/Kconfig`. It's a key spot for anything related to the 802.11 stack, and I have a feeling there might be crucial configuration options lurking within that we need to examine to cover all our bases. This is just a quick cross-check to make sure we haven't missed any obvious knobs, dependencies, or hidden features. Let's make sure it's all covered! |
| 10/2 | 2026/09/23 10:50 | tool | read-file |
0mArgs:{
"File": "net/mac80211/Kconfig",
"FirstLine": 1,
"LineCount": 40
}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 31:\tchoice\n 32:\t\tprompt \"Default rate control algorithm\"\n 33:\t\tdepends on MAC80211_HAS_RC\n 34:\t\tdefault MAC80211_RC_DEFAULT_MINSTREL\n 35:\t\thelp\n 36:\t\t This option selects the default rate control algorithm\n 37:\t\t mac80211 will use. Note that this default can still be\n 38:\t\t overridden through the ieee80211_default_rc_algo module\n 39:\t\t parameter if different algorithms are available.\n 40:\t\n"
} |
| 11/2 | 2026/09/23 10:50 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 39365 output: 33 thoughts: 118 Thoughts: Okay, let's break this down. **Analyzing Recent MAC80211 Code Changes** Right, so I'm looking at a diff related to `MAC80211_HWSIM`, `MAC80211` and `CFG80211`. My immediate thought is to zero in on the implications for debugging and diagnostics, especially with the mention of `debugfs`. I know that `debugfs` is a powerful tool for low-level interaction, so any modifications there are worth a closer look. The specific file being modified is `debugfs_key.c`. My first step is going to be confirming whether the changes in `debugfs_key.c` are conditional. I need to check if the code is guarded by `CONFIG_MAC80211_DEBUGFS`. Knowing whether this feature is enabled through a configuration option will give me critical context about the intent and scope of the changes. This will help me quickly understand if the modification is widely applicable or specific to deployments where debugfs is enabled. |
| 12/2 | 2026/09/23 10:50 | tool | grepper |
0mArgs:{
"Expression": "debugfs_key",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/Makefile=41=mac80211-$(CONFIG_MAC80211_DEBUGFS) += \\\n--\nnet/mac80211/Makefile-44-\tdebugfs_netdev.o \\\nnet/mac80211/Makefile:45:\tdebugfs_key.o\nnet/mac80211/Makefile-46-\n--\nnet/mac80211/debugfs_key.c-14-#include \"debugfs.h\"\nnet/mac80211/debugfs_key.c:15:#include \"debugfs_key.h\"\nnet/mac80211/debugfs_key.c-16-\n--\nnet/mac80211/debugfs_key.c=321=KEY_OPS(key);\n--\nnet/mac80211/debugfs_key.c-329-\nnet/mac80211/debugfs_key.c:330:void ieee80211_debugfs_key_add(struct ieee80211_key *key)\nnet/mac80211/debugfs_key.c-331-{\n--\nnet/mac80211/debugfs_key.c-368-\nnet/mac80211/debugfs_key.c:369:void ieee80211_debugfs_key_remove(struct ieee80211_key *key)\nnet/mac80211/debugfs_key.c-370-{\n--\nnet/mac80211/debugfs_key.c-377-\nnet/mac80211/debugfs_key.c:378:void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)\nnet/mac80211/debugfs_key.c-379-{\n--\nnet/mac80211/debugfs_key.c-412-\nnet/mac80211/debugfs_key.c:413:void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sdata)\nnet/mac80211/debugfs_key.c-414-{\n--\nnet/mac80211/debugfs_key.c=422=void\nnet/mac80211/debugfs_key.c:423:ieee80211_debugfs_key_remove_beacon_default(struct ieee80211_sub_if_data *sdata)\nnet/mac80211/debugfs_key.c-424-{\n--\nnet/mac80211/debugfs_key.h-5-#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/debugfs_key.h:6:void ieee80211_debugfs_key_add(struct ieee80211_key *key);\nnet/mac80211/debugfs_key.h:7:void ieee80211_debugfs_key_remove(struct ieee80211_key *key);\nnet/mac80211/debugfs_key.h:8:void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata);\nnet/mac80211/debugfs_key.h:9:void ieee80211_debugfs_key_remove_mgmt_default(\nnet/mac80211/debugfs_key.h-10-\tstruct ieee80211_sub_if_data *sdata);\nnet/mac80211/debugfs_key.h:11:void ieee80211_debugfs_key_remove_beacon_default(\nnet/mac80211/debugfs_key.h-12-\tstruct ieee80211_sub_if_data *sdata);\nnet/mac80211/debugfs_key.h-13-#else\nnet/mac80211/debugfs_key.h:14:static inline void ieee80211_debugfs_key_add(struct ieee80211_key *key)\nnet/mac80211/debugfs_key.h-15-{}\nnet/mac80211/debugfs_key.h:16:static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key)\nnet/mac80211/debugfs_key.h-17-{}\nnet/mac80211/debugfs_key.h:18:static inline void ieee80211_debugfs_key_update_default(\nnet/mac80211/debugfs_key.h-19-\tstruct ieee80211_sub_if_data *sdata)\nnet/mac80211/debugfs_key.h-20-{}\nnet/mac80211/debugfs_key.h:21:static inline void ieee80211_debugfs_key_remove_mgmt_default(\nnet/mac80211/debugfs_key.h-22-\tstruct ieee80211_sub_if_data *sdata)\nnet/mac80211/debugfs_key.h-23-{}\nnet/mac80211/debugfs_key.h:24:static inline void ieee80211_debugfs_key_remove_beacon_default(\nnet/mac80211/debugfs_key.h-25-\tstruct ieee80211_sub_if_data *sdata)\n--\nnet/mac80211/key.c-23-#include \"driver-ops.h\"\nnet/mac80211/key.c:24:#include \"debugfs_key.h\"\nnet/mac80211/key.c-25-#include \"aes_ccm.h\"\n--\nnet/mac80211/key.c=354=static void __ieee80211_set_default_key(struct ieee80211_link_data *link,\n--\nnet/mac80211/key.c-379-\nnet/mac80211/key.c:380:\tieee80211_debugfs_key_update_default(sdata);\nnet/mac80211/key.c-381-}\n--\nnet/mac80211/key.c=392=__ieee80211_set_default_mgmt_key(struct ieee80211_link_data *link, int idx)\n--\nnet/mac80211/key.c-405-\nnet/mac80211/key.c:406:\tieee80211_debugfs_key_update_default(sdata);\nnet/mac80211/key.c-407-}\n--\nnet/mac80211/key.c=418=__ieee80211_set_default_beacon_key(struct ieee80211_link_data *link, int idx)\n--\nnet/mac80211/key.c-432-\nnet/mac80211/key.c:433:\tieee80211_debugfs_key_update_default(sdata);\nnet/mac80211/key.c-434-}\n--\nnet/mac80211/key.c=777=static void __ieee80211_key_destroy(struct ieee80211_key *key,\n--\nnet/mac80211/key.c-782-\nnet/mac80211/key.c:783:\t\tieee80211_debugfs_key_remove(key);\nnet/mac80211/key.c-784-\n--\nnet/mac80211/key.c=856=int ieee80211_key_link(struct ieee80211_key *key,\n--\nnet/mac80211/key.c-977-\tif (!ret) {\nnet/mac80211/key.c:978:\t\tieee80211_debugfs_key_add(key);\nnet/mac80211/key.c-979-\t\tieee80211_key_destroy(old_key, delay_tailroom);\n--\nnet/mac80211/key.c=1118=static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/key.c-1126-\nnet/mac80211/key.c:1127:\tieee80211_debugfs_key_remove_mgmt_default(sdata);\nnet/mac80211/key.c:1128:\tieee80211_debugfs_key_remove_beacon_default(sdata);\nnet/mac80211/key.c-1129-\n--\nnet/mac80211/key.c-1135-\nnet/mac80211/key.c:1136:\tieee80211_debugfs_key_update_default(sdata);\nnet/mac80211/key.c-1137-}\n"
} |
| 13/2 | 2026/09/23 10:50 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 42242 output: 37 thoughts: 46 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Diving into the MAC80211 DebugFS Integration** Right, so `MAC80211_DEBUGFS` is enabled, and that automatically pulls in `debugfs_key.c`. Naturally, my first instinct is to confirm that dependency explicitly. I need to be absolutely certain of the configuration, so I'm heading directly to `net/mac80211/Kconfig`. I need to understand *precisely* how that configuration option is tied to the enablement of the debugfs key functionality. I'm looking for the immediate source of truth regarding the conditional inclusion of the key's features. This isn't just a casual check; I'm digging into the underlying logic. I want to know if there's any nuance to that dependency, any potential caveats or side effects that I need to be aware of within the broader MAC80211 framework. I have to know all the angles on this feature. |
| 14/2 | 2026/09/23 10:50 | tool | grepper |
0mArgs:{
"Expression": "MAC80211_DEBUGFS",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/Kconfig=79=config MAC80211_LEDS\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=293=config MAC80211_DEBUG_COUNTERS\n--\nnet/mac80211/Kconfig-295-\tdepends on MAC80211_DEBUG_MENU\nnet/mac80211/Kconfig:296:\tdepends on MAC80211_DEBUGFS\nnet/mac80211/Kconfig-297-\thelp\n--\nnet/mac80211/Makefile=40=mac80211-$(CONFIG_MAC80211_LEDS) += led.o\nnet/mac80211/Makefile:41:mac80211-$(CONFIG_MAC80211_DEBUGFS) += \\\nnet/mac80211/Makefile-42-\tdebugfs.o \\\n--\nnet/mac80211/Makefile=59=rc80211_minstrel-y := \\\n--\nnet/mac80211/Makefile-61-\nnet/mac80211/Makefile:62:rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += \\\nnet/mac80211/Makefile-63-\trc80211_minstrel_ht_debugfs.o\n--\nnet/mac80211/debugfs.h-1-/* SPDX-License-Identifier: GPL-2.0 */\nnet/mac80211/debugfs.h:2:#ifndef __MAC80211_DEBUGFS_H\nnet/mac80211/debugfs.h:3:#define __MAC80211_DEBUGFS_H\nnet/mac80211/debugfs.h-4-\n--\nnet/mac80211/debugfs.h-6-\nnet/mac80211/debugfs.h:7:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/debugfs.h-8-void debugfs_hw_add(struct ieee80211_local *local);\n--\nnet/mac80211/debugfs.h=12=static inline void debugfs_hw_add(struct ieee80211_local *local)\n--\nnet/mac80211/debugfs.h-16-\nnet/mac80211/debugfs.h:17:#endif /* __MAC80211_DEBUGFS_H */\n--\nnet/mac80211/debugfs_key.h-1-/* SPDX-License-Identifier: GPL-2.0 */\nnet/mac80211/debugfs_key.h:2:#ifndef __MAC80211_DEBUGFS_KEY_H\nnet/mac80211/debugfs_key.h:3:#define __MAC80211_DEBUGFS_KEY_H\nnet/mac80211/debugfs_key.h-4-\nnet/mac80211/debugfs_key.h:5:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/debugfs_key.h-6-void ieee80211_debugfs_key_add(struct ieee80211_key *key);\n--\nnet/mac80211/debugfs_key.h=24=static inline void ieee80211_debugfs_key_remove_beacon_default(\n--\nnet/mac80211/debugfs_key.h-28-\nnet/mac80211/debugfs_key.h:29:#endif /* __MAC80211_DEBUGFS_KEY_H */\n--\nnet/mac80211/debugfs_netdev.h-12-\nnet/mac80211/debugfs_netdev.h:13:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/debugfs_netdev.h-14-void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);\n--\nnet/mac80211/debugfs_sta.h-1-/* SPDX-License-Identifier: GPL-2.0 */\nnet/mac80211/debugfs_sta.h:2:#ifndef __MAC80211_DEBUGFS_STA_H\nnet/mac80211/debugfs_sta.h:3:#define __MAC80211_DEBUGFS_STA_H\nnet/mac80211/debugfs_sta.h-4-\n--\nnet/mac80211/debugfs_sta.h-6-\nnet/mac80211/debugfs_sta.h:7:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/debugfs_sta.h-8-void ieee80211_sta_debugfs_add(struct sta_info *sta);\n--\nnet/mac80211/debugfs_sta.h=24=static inline void ieee80211_link_sta_debugfs_drv_remove(struct link_sta_info *link_sta) {}\n--\nnet/mac80211/debugfs_sta.h-26-\nnet/mac80211/debugfs_sta.h:27:#endif /* __MAC80211_DEBUGFS_STA_H */\n--\nnet/mac80211/driver-ops.h=477=static inline void drv_sta_remove(struct ieee80211_local *local,\n--\nnet/mac80211/driver-ops.h-494-\nnet/mac80211/driver-ops.h:495:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/driver-ops.h-496-static inline void drv_vif_add_debugfs(struct ieee80211_local *local,\n--\nnet/mac80211/ieee80211_i.h=1109=struct ieee80211_link_data {\n--\nnet/mac80211/ieee80211_i.h-1162-\nnet/mac80211/ieee80211_i.h:1163:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/ieee80211_i.h-1164-\tstruct dentry *debugfs_dir;\n--\nnet/mac80211/ieee80211_i.h=1168=struct ieee80211_sub_if_data {\n--\nnet/mac80211/ieee80211_i.h-1255-\nnet/mac80211/ieee80211_i.h:1256:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/ieee80211_i.h-1257-\tstruct {\n--\nnet/mac80211/ieee80211_i.h=1459=struct ieee80211_local {\n--\nnet/mac80211/ieee80211_i.h-1709-\nnet/mac80211/ieee80211_i.h:1710:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/ieee80211_i.h-1711-\tstruct local_debugfsdentries {\n--\nnet/mac80211/key.h=60=struct ieee80211_key {\n--\nnet/mac80211/key.h-123-\nnet/mac80211/key.h:124:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/key.h-125-\tstruct {\n--\nnet/mac80211/rate.c=215=ieee80211_rate_control_ops_get(const char *name)\n--\nnet/mac80211/rate.c-240-\nnet/mac80211/rate.c:241:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/rate.c-242-static ssize_t rcname_read(struct file *file, char __user *userbuf,\n--\nnet/mac80211/rate.c=280=static void rate_control_free(struct ieee80211_local *local,\n--\nnet/mac80211/rate.c-284-\nnet/mac80211/rate.c:285:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/rate.c-286-\tdebugfs_remove_recursive(local-\u003edebugfs.rcdir);\n--\nnet/mac80211/rate.h=55=static inline void rate_control_add_sta_debugfs(struct sta_info *sta)\nnet/mac80211/rate.h-56-{\nnet/mac80211/rate.h:57:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/rate.h-58-\tstruct rate_control_ref *ref = sta-\u003erate_ctrl;\n--\nnet/mac80211/rate.h=67=static inline void rate_control_add_debugfs(struct ieee80211_local *local)\nnet/mac80211/rate.h-68-{\nnet/mac80211/rate.h:69:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/rate.h-70-\tstruct dentry *debugfsdir;\n--\nnet/mac80211/rc80211_minstrel_ht.c=1059=minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)\n--\nnet/mac80211/rc80211_minstrel_ht.c-1181-\nnet/mac80211/rc80211_minstrel_ht.c:1182:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/rc80211_minstrel_ht.c-1183-\t/* use fixed index if set */\n--\nnet/mac80211/rc80211_minstrel_ht.c=1595=minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,\n--\nnet/mac80211/rc80211_minstrel_ht.c-1606-\nnet/mac80211/rc80211_minstrel_ht.c:1607:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/rc80211_minstrel_ht.c-1608-\tif (mp-\u003efixed_rate_idx != -1)\n--\nnet/mac80211/rc80211_minstrel_ht.c=1915=minstrel_ht_alloc(struct ieee80211_hw *hw)\n--\nnet/mac80211/rc80211_minstrel_ht.c-1948-\nnet/mac80211/rc80211_minstrel_ht.c:1949:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/rc80211_minstrel_ht.c-1950-static void minstrel_ht_add_debugfs(struct ieee80211_hw *hw, void *priv,\n--\nnet/mac80211/rc80211_minstrel_ht.c=1983=static const struct rate_control_ops mac80211_minstrel_ht = {\n--\nnet/mac80211/rc80211_minstrel_ht.c-1993-\t.free = minstrel_ht_free,\nnet/mac80211/rc80211_minstrel_ht.c:1994:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/rc80211_minstrel_ht.c-1995-\t.add_debugfs = minstrel_ht_add_debugfs,\n--\nnet/mac80211/rc80211_minstrel_ht.h=75=struct minstrel_priv {\n--\nnet/mac80211/rc80211_minstrel_ht.h-85-\nnet/mac80211/rc80211_minstrel_ht.h:86:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/rc80211_minstrel_ht.h-87-\t/*\n--\nnet/mac80211/sta_info.h=527=struct link_sta_info {\n--\nnet/mac80211/sta_info.h-579-\nnet/mac80211/sta_info.h:580:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/sta_info.h-581-\tstruct dentry *debugfs_dir;\n--\nnet/mac80211/sta_info.h=717=struct sta_info {\n--\nnet/mac80211/sta_info.h-775-\nnet/mac80211/sta_info.h:776:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/sta_info.h-777-\tstruct dentry *debugfs_dir;\n--\nnet/mac80211/tx.c=2689=static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/tx.c-2714-\nnet/mac80211/tx.c:2715:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/tx.c-2716-\tif (local-\u003eforce_tx_status)\n--\nnet/mac80211/tx.c=3726=void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/tx.c-3772-\nnet/mac80211/tx.c:3773:#ifdef CONFIG_MAC80211_DEBUGFS\nnet/mac80211/tx.c-3774-\tif (local-\u003eforce_tx_status)\n"
} |
| 15/2 | 2026/09/23 10:50 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 46494 output: 31 thoughts: 210 Thoughts: Okay, let's break this down. **Investigating the Core Wireless Configuration Requirements** Alright, I need to figure out the essential kernel configurations for this. My initial thought is to make sure we have `CFG80211`, `MAC80211`, and `MAC80211_HWSIM` enabled. Hmm, and `MAC80211_DEBUGFS` is optional but definitely worth considering for debugging purposes, depending on the need. Now, are there any dependencies at play here? Let's verify. `CFG80211` has a dependency on `RFKILL || !RFKILL` which is interesting, seems like it needs RFKILL or doesn't care. `MAC80211` relies on `CFG80211`, so that's expected. And `MAC80211_HWSIM` needs `MAC80211`, naturally. I should probably also confirm that `NL80211` is handled by `CFG80211` and appears that `nl80211.c` is compiled when `CFG80211` is turned on, confirming the relationship. Finally, I'll take a look at the `net/wireless/Makefile` to confirm the build process. |
| 16/2 | 2026/09/23 10:50 | tool | grepper |
0mArgs:{
"Expression": "nl80211",
"PathPrefix": "net/wireless/Makefile"
}Results: {
"Output": "net/wireless/Makefile=7=obj-$(CONFIG_WEXT_PRIV) += wext-priv.o\nnet/wireless/Makefile-8-\nnet/wireless/Makefile:9:cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o\nnet/wireless/Makefile-10-cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o\n"
} |
| 17/2 | 2026/09/23 10:50 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 47167 output: 36 thoughts: 93 Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective: **Diving into the 802.11 Driver Build Process** Right, let me see... `cfg80211-y += ... nl80211.o`. Aha, so `CONFIG_CFG80211` is pulling in the `nl80211.c`, `util.c`, `sme.c`, `ibss.c`, and all those other core nl80211 files during compilation. That makes sense; it's the foundation of the userspace/kernel interaction for wireless configuration. And of course, the `CONFIG_MAC80211` option compiles the `net/mac80211/` directory. That's the heart of the mac80211 wireless stack. Now, I need to understand more about that mac80211 piece... I need to check the `net/mac80211/Makefile` to see how it's all built and linked together. Let's see what's in there... |
| 18/2 | 2026/09/23 10:50 | tool | read-file |
0mArgs:{
"File": "net/mac80211/Makefile",
"FirstLine": 1,
"LineCount": 40
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0\n 2:\tobj-$(CONFIG_MAC80211) += mac80211.o\n 3:\t\n 4:\t# mac80211 objects\n 5:\tmac80211-y := \\\n 6:\t\tmain.o status.o \\\n 7:\t\tdriver-ops.o \\\n 8:\t\tsta_info.o \\\n 9:\t\twep.o \\\n 10:\t\taead_api.o \\\n 11:\t\twpa.o \\\n 12:\t\tscan.o offchannel.o \\\n 13:\t\tht.o agg-tx.o agg-rx.o \\\n 14:\t\tvht.o \\\n 15:\t\the.o \\\n 16:\t\ts1g.o \\\n 17:\t\tibss.o \\\n 18:\t\tiface.o \\\n 19:\t\tlink.o \\\n 20:\t\trate.o \\\n 21:\t\ttkip.o \\\n 22:\t\taes_cmac.o \\\n 23:\t\taes_gmac.o \\\n 24:\t\tfils_aead.o \\\n 25:\t\tcfg.o \\\n 26:\t\tethtool.o \\\n 27:\t\trx.o \\\n 28:\t\tspectmgmt.o \\\n 29:\t\ttx.o \\\n 30:\t\tkey.o \\\n 31:\t\tutil.o parse.o \\\n 32:\t\twme.o \\\n 33:\t\tchan.o ap.o \\\n 34:\t\ttrace.o mlme.o \\\n 35:\t\ttdls.o \\\n 36:\t\tocb.o \\\n 37:\t\tairtime.o \\\n 38:\t\teht.o uhr.o nan.o\n 39:\t\n 40:\tmac80211-$(CONFIG_MAC80211_LEDS) += led.o\n"
} |
| 19/2 | 2026/09/23 10:50 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 48059 output: 395 thoughts: 2097 Thoughts: **Analysis of CIP and CIGTK Implementation in mac80211 and Related Subsystems** Okay, so the modified files, `cfg.o`, `key.o`, `util.o`, `parse.o`, and `mlme.o`, are all within `mac80211-y`. I need to understand the implications of these changes. My first thought is to break down the modified symbols. In `net/wireless/nl80211.c`, I see a cluster of static functions: `nl80211_parse_key`, `nl80211_get_key`, `nl80211_new_key`, `nl80211_del_key`, `nl80211_set_station`, `nl80211_new_station`, `nl80211_associate`, and `nl80211_add_mod_link_station`. There's also `cfg80211_check_station_change`, which is exported. Then, in `net/wireless/util.c`, I see `cfg80211_cigtk_supported`, `cfg80211_valid_key_idx`, and `cfg80211_validate_key_settings`. `__cfg80211_disconnected` is modified in `sme.c`. `mac80211` has its own modifications, particularly in `cfg.c` with the static functions `ieee80211_add_key`, `ieee80211_lookup_key`, `ieee80211_del_key`, `ieee80211_get_key`, `sta_link_apply_parameters`, and `sta_apply_parameters`. `key.c` has `ieee80211_key_enable_hw_accel`, `ieee80211_key_replace`, `ieee80211_free_keys_iface`, and the exported `ieee80211_gtk_rekey_add` along with some non-static symbols. `mlme.c` has static functions like `ieee80211_add_link_elems`, `ieee80211_send_assoc`, and `ieee80211_assoc_config_link`. Also, in `util.c`, `ieee80211_put_cip_cap` is modified. Now, let's look closer at those static functions in `nl80211.c`. Are they potentially inlined, or are they distinct symbols? In the Linux kernel, static functions in `.c` files *can* be distinct symbols, if they have their address taken. Let's see... Ah, they are Netlink command handlers in `nl80211_ops[]`. The compiler *can't* inline them because their addresses are taken! They are distinct, not inlined. The same applies to `nl80211_new_key`, `nl80211_del_key`, `nl80211_get_key`, etc. This means they're exposed via Netlink, making them interesting for fuzzing. Now, `cfg80211_cigtk_supported`, `cfg80211_validate_key_settings`, `ieee80211_key_link`, and `ieee80211_gtk_rekey_add`... I need to track down their definitions and dependencies. Okay, I see them defined in either `net/wireless/util.c` or `net/mac80211/key.c`. Similarly, `ieee80211_add_key`, `ieee80211_del_key`, and `ieee80211_get_key` in `cfg.c` are ops in `mac80211_config_ops`. Their addresses are taken as well. They're definitely not inlined. Now, let's not forget `mac80211_hwsim_main.c`. It looks like `mac80211_hwsim_iftypes_ext_capa` now has `.cip_supported = true`! Excellent. This means CIP is enabled in the hwsim driver, and syzkaller *frequently* fuzzes nl80211 with mac80211_hwsim devices. Following the instructions, I need to identify |
| 20/2 | 2026/09/23 10:51 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"CFG80211",
"MAC80211",
"MAC80211_HWSIM",
"MAC80211_DEBUGFS"
],
"FocusSymbols": [
"nl80211_new_key",
"nl80211_del_key",
"nl80211_get_key",
"cfg80211_cigtk_supported",
"cfg80211_validate_key_settings",
"ieee80211_add_key",
"ieee80211_del_key",
"ieee80211_lookup_key",
"ieee80211_key_link",
"ieee80211_gtk_rekey_add",
"ieee80211_put_cip_cap"
],
"Reasoning": "The patch introduces support for the Control Integrity Protocol (CIP) and Control Integrity Group Temporal Key (CIGTK) across cfg80211, nl80211, mac80211, and the virtual driver mac80211_hwsim. It changes key management callbacks to accept nl80211 key types, adds new netlink attributes (NL80211_ATTR_ASSOC_CIP, NL80211_ATTR_CIP_CAPABILITIES) and flags (NL80211_STA_FLAG_CIP), and alters key addition, lookup, replacement, and rekeying logic. This code is accessible via generic netlink and directly testable in virtual environments using mac80211_hwsim.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"CFG80211",
"MAC80211",
"MAC80211_HWSIM",
"MAC80211_DEBUGFS"
],
"FocusSymbols": [
"nl80211_new_key",
"nl80211_del_key",
"nl80211_get_key",
"cfg80211_cigtk_supported",
"cfg80211_validate_key_settings",
"ieee80211_add_key",
"ieee80211_del_key",
"ieee80211_lookup_key",
"ieee80211_key_link",
"ieee80211_gtk_rekey_add",
"ieee80211_put_cip_cap"
],
"Reasoning": "The patch introduces support for the Control Integrity Protocol (CIP) and Control Integrity Group Temporal Key (CIGTK) across cfg80211, nl80211, mac80211, and the virtual driver mac80211_hwsim. It changes key management callbacks to accept nl80211 key types, adds new netlink attributes (NL80211_ATTR_ASSOC_CIP, NL80211_ATTR_CIP_CAPABILITIES) and flags (NL80211_STA_FLAG_CIP), and alters key addition, lookup, replacement, and rekeying logic. This code is accessible via generic netlink and directly testable in virtual environments using mac80211_hwsim.",
"WorthFuzzing": true
} |
| 21/1 | 2026/09/23 10:51 | action | If |
2mArgs:{
"WorthFuzzing": true
}Results: null |
| 22/2 | 2026/09/23 10:51 | agent | kmsan-evaluator |
2mModel:core Args: null Results: {
"KMSANReasoning": "The patch series introduces support for the Control Integrity Protocol (CIP) and Control Integrity Group Temporal Keys (CIGTK) in cfg80211/mac80211, updating the cfg80211 add_key/del_key/get_key operations across wireless drivers to use an enum nl80211_key_type instead of a boolean pairwise flag.\n\nAnalysis regarding KMSAN vs KASAN applicability:\n1. Kernel data exposed to userspace: The new netlink attribute NL80211_ATTR_CIP_CAPABILITIES sends a single u8 from wiphy_iftype_ext_capab. These capability structures are statically allocated in driver rodata/BSS and thus zero-initialized. Station parameters and request structs in nl80211 handlers (such as nl80211_set_station, nl80211_new_station, nl80211_add_mod_link_station, and nl80211_associate) are explicitly zero-initialized with memset(\u0026params, 0, sizeof(params)) or struct initializer = {}.\n2. Data structures in mac80211: New fields (such as cigtk pointers, cip flag, and cip_cap) reside within structures (ieee80211_link_data, link_sta_info, sta_info, ieee80211_key) that are dynamically allocated with kzalloc.\n3. Parsing and bounds: Frame parsing for the new CIP capability element validates element length (len \u003e= sizeof(*elems-\u003ecip_cap)) before referencing payload bytes, and new packet generation via ieee80211_put_cip_cap initializes all four bytes added to the skb. Key indices for CIGTK are validated against NUM_CTRL_KEYS (2) in nl80211 and cfg80211 before use.\n4. Any potential memory corruption, out-of-bounds array access, or reference count / lifetime issues with key objects are fully covered by standard KASAN.\n\nNo uninitialized memory reads or information leak risks are introduced. Spawning 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 196c10554dabba6bd2ef550968db4912fe03b80f
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Sep 23 10:50:14 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 8bbe554a9b364..a9a35476fecd7 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1130,13 +1130,15 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
}
static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr,
struct key_params *params)
{
struct ath6kl *ar = ath6kl_priv(wdev->netdev);
struct ath6kl_vif *vif = netdev_priv(wdev->netdev);
struct ath6kl_key *key = NULL;
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
int seq_len;
u8 key_usage;
u8 key_type;
@@ -1255,7 +1257,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wde
}
static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct ath6kl *ar = ath6kl_priv(wdev->netdev);
@@ -1285,7 +1288,8 @@ static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wde
}
static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback) (void *cookie,
struct key_params *))
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 9ac33d827f801..bf060281c9a2c 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1620,11 +1620,13 @@ static void wil_del_rx_key(u8 key_index, enum wmi_key_usage key_usage,
static int wil_cfg80211_add_key(struct wiphy *wiphy,
struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise,
+ u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr,
struct key_params *params)
{
int rc;
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
enum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);
@@ -1695,12 +1697,14 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
static int wil_cfg80211_del_key(struct wiphy *wiphy,
struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise,
+ u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
- enum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);
+ enum wmi_key_usage key_usage =
+ wil_detect_key_usage(wdev, type == NL80211_KEYTYPE_PAIRWISE);
struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif->mid,
key_usage,
mac_addr);
@@ -2071,7 +2075,8 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)
key_params.seq_len = IEEE80211_GCMP_PN_LEN;
rc = wil_cfg80211_add_key(wiphy, vif_to_wdev(vif), -1,
vif->gtk_index,
- false, NULL, &key_params);
+ NL80211_KEYTYPE_PAIRWISE,
+ NULL, &key_params);
if (rc)
wil_err(wil, "vif %d recovery add key failed (%d)\n",
i, rc);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 9d8ce7bb046e0..ede76a9e12c87 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2802,7 +2802,8 @@ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
static s32
brcmf_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct brcmf_if *ifp = netdev_priv(wdev->netdev);
@@ -2840,7 +2841,8 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
static s32
brcmf_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
@@ -2866,7 +2868,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
if (params->key_len == 0)
return brcmf_cfg80211_del_key(wiphy, wdev, -1, key_idx,
- pairwise, mac_addr);
+ type, mac_addr);
if (params->key_len > sizeof(key->data)) {
bphy_err(drvr, "Too long key length (%u)\n", params->key_len);
@@ -2962,7 +2964,8 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
static s32
brcmf_cfg80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
index 55f9b809e764d..6d8ede336d59b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
@@ -1138,7 +1138,8 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
return;
key_config = ieee80211_gtk_rekey_add(vif, key_data->id, key_data->key,
- sizeof(key_data->key), link_id);
+ sizeof(key_data->key), link_id,
+ false);
if (IS_ERR(key_config))
return;
@@ -1220,7 +1221,8 @@ static void iwl_mld_mlo_rekey(struct iwl_mld *mld,
mlo_key->idx, link_id);
key = ieee80211_gtk_rekey_add(vif, mlo_key->idx, mlo_key->key,
- sizeof(mlo_key->key), link_id);
+ sizeof(mlo_key->key), link_id,
+ false);
if (IS_ERR(key))
continue;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 6b11fa32ea5c6..bd52f2ebd3ba1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1887,7 +1887,8 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id,
status->gtk[i].key,
- sizeof(status->gtk[i].key), -1);
+ sizeof(status->gtk[i].key), -1,
+ false);
if (IS_ERR(key)) {
/* FW may send also the old keys */
if (PTR_ERR(key) == -EALREADY)
@@ -1922,7 +1923,8 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,
return true;
key_config = ieee80211_gtk_rekey_add(vif, keyidx, key_data->key,
- sizeof(key_data->key), -1);
+ sizeof(key_data->key), -1,
+ false);
if (IS_ERR(key_config)) {
/* FW may send also the old keys */
return PTR_ERR(key_config) == -EALREADY;
diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c
index 72c92f72469de..e015cfa1950c1 100644
--- a/drivers/net/wireless/marvell/libertas/cfg.c
+++ b/drivers/net/wireless/marvell/libertas/cfg.c
@@ -1508,7 +1508,8 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
static int lbs_cfg_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 idx, bool pairwise,
+ int link_id, u8 idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct lbs_private *priv = wiphy_priv(wiphy);
@@ -1569,7 +1570,8 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
static int lbs_cfg_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 293876397b670..1db1017ef76a1 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -142,12 +142,14 @@ static void *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy)
*/
static int
mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
+ const u8 *peer_mac =
+ (type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1)) {
mwifiex_dbg(priv->adapter, ERROR, "deleting the crypto keys\n");
@@ -480,13 +482,15 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
*/
static int
mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
struct mwifiex_wep_key *wep_key;
static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
+ const u8 *peer_mac =
+ (type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP &&
(params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index bb2748a193294..651a527f6881e 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -535,10 +535,13 @@ static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info,
}
static int add_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr,
+ u8 key_index,
+ enum nl80211_key_type type,
+ const u8 *mac_addr,
struct key_params *params)
{
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
int ret = 0, keylen = params->key_len;
const u8 *rx_mic = NULL;
const u8 *tx_mic = NULL;
@@ -641,9 +644,10 @@ static int add_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
static int del_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
u8 key_index,
- bool pairwise,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
struct wilc_vif *vif = netdev_priv(wdev->netdev);
struct wilc_priv *priv = &vif->priv;
@@ -681,10 +685,11 @@ static int del_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
}
static int get_key(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr,
- void *cookie,
+ u8 key_index, enum nl80211_key_type type,
+ const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params *))
{
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
struct wilc_vif *vif = netdev_priv(wdev->netdev);
struct wilc_priv *priv = &vif->priv;
struct key_params key_params;
diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
index 5cc8cdf594d3e..d4233f5a31dfa 100644
--- a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
+++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
@@ -99,12 +99,14 @@ static void *nxpwifi_cfg80211_get_adapter(struct wiphy *wiphy)
/* cfg80211 operation handler to delete a network key. */
static int
nxpwifi_cfg80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev);
static const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
+ const u8 *peer_mac =
+ (type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;
int ret;
ret = nxpwifi_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1);
@@ -426,7 +428,8 @@ nxpwifi_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
/* cfg80211 handler for adding an 802.11 encryption key. */
static int
nxpwifi_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct nxpwifi_private *priv = nxpwifi_netdev_get_priv(wdev->netdev);
@@ -436,7 +439,7 @@ nxpwifi_cfg80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
int ret;
eth_broadcast_addr(bc_mac);
- peer_mac = pairwise ? mac_addr : bc_mac;
+ peer_mac = (type == NL80211_KEYTYPE_PAIRWISE) ? mac_addr : bc_mac;
if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP &&
(params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index 45e2b7ae96333..d9c84d5ce2548 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -531,10 +531,12 @@ qtnf_dump_station(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int qtnf_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
int ret;
ret = qtnf_cmd_send_add_key(vif, key_index, pairwise, mac_addr, params);
@@ -547,10 +549,12 @@ static int qtnf_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int qtnf_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
int ret;
ret = qtnf_cmd_send_del_key(vif, key_index, pairwise, mac_addr);
diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c
index 2dfa24c54e7d7..2e37e1fafbef5 100644
--- a/drivers/net/wireless/realtek/rtw89/wow.c
+++ b/drivers/net/wireless/realtek/rtw89/wow.c
@@ -669,10 +669,12 @@ static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev,
if (ieee80211_vif_is_mld(wow_vif))
key = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk,
cipher_info->len,
- rtwvif_link->link_id);
+ rtwvif_link->link_id,
+ false);
else
key = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk,
- cipher_info->len, -1);
+ cipher_info->len, -1,
+ false);
kfree(rekey_conf);
if (IS_ERR(key)) {
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
index 1a12261f3e8e5..0cf9ef8959e1b 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
@@ -5645,6 +5645,14 @@ static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband)
BIT(NL80211_IFTYPE_MESH_POINT) | \
BIT(NL80211_IFTYPE_OCB))
+static const u8 iftypes_ext_capa[] = {
+ [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+ [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
+ [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF |
+ WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB,
+ [8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB,
+};
+
static const u8 iftypes_ext_capa_ap[] = {
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
@@ -5669,6 +5677,33 @@ static const struct wiphy_iftype_ext_capab mac80211_hwsim_iftypes_ext_capa[] = {
.eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP |
IEEE80211_EML_CAP_EMLMR_SUPPORT,
.mld_capa_and_ops = MAC80211_HWSIM_MLD_CAPA_OPS,
+ /* CIP works as hwsim does not have control frames */
+ .cip_supported = true,
+ .cip_capabilities = 0,
+ },
+ {
+ .iftype = NL80211_IFTYPE_STATION,
+ .extended_capabilities = iftypes_ext_capa,
+ .extended_capabilities_mask = iftypes_ext_capa,
+ .extended_capabilities_len = sizeof(iftypes_ext_capa),
+ .cip_supported = true,
+ .cip_capabilities = 0,
+ },
+ {
+ .iftype = NL80211_IFTYPE_P2P_CLIENT,
+ .extended_capabilities = iftypes_ext_capa,
+ .extended_capabilities_mask = iftypes_ext_capa,
+ .extended_capabilities_len = sizeof(iftypes_ext_capa),
+ .cip_supported = true,
+ .cip_capabilities = 0,
+ },
+ {
+ .iftype = NL80211_IFTYPE_P2P_GO,
+ .extended_capabilities = iftypes_ext_capa,
+ .extended_capabilities_mask = iftypes_ext_capa,
+ .extended_capabilities_len = sizeof(iftypes_ext_capa),
+ .cip_supported = true,
+ .cip_capabilities = 0,
},
};
diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
index 3468d4114f604..be233a471b433 100644
--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
@@ -825,7 +825,8 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param
}
static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
char *alg_name;
@@ -904,7 +905,8 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params*))
@@ -913,7 +915,8 @@ static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr)
{
struct adapter *padapter = rtw_netdev_priv(wdev->netdev);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 7fbc51f873ff1..73ac5336a17ad 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1828,6 +1828,7 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_BANDWIDTH_INDICATION = 135,
WLAN_EID_EXT_KNOWN_STA_IDENTIFCATION = 136,
WLAN_EID_EXT_NON_AP_STA_REG_CON = 137,
+ WLAN_EID_EXT_CIP_CAPA = 150,
WLAN_EID_EXT_UHR_OPER = 151,
WLAN_EID_EXT_UHR_CAPA = 152,
WLAN_EID_EXT_MACP = 153,
@@ -2899,4 +2900,25 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
__ieee80211_check_tim(tim, tim_len, aid);
}
+/**
+ * enum ieee80211_cip_cap_fields - CIP Capabilities element fields
+ * @IEEE80211_CIP_CAP_MIC_PADDING: The MIC padding subfield in the CIP
+ * capabilities
+ * @IEEE80211_CIP_CAP_PROTECTED_CTRL_FRAME_ONLY: The MIC Padding For Protected
+ * Control Frames Only bit in CIP capabilities
+ */
+enum ieee80211_cip_cap_fields {
+ IEEE80211_CIP_CAP_MIC_PADDING = 0x0F,
+ IEEE80211_CIP_CAP_PROTECTED_CTRL_FRAME_ONLY = 0x10,
+};
+
+/**
+ * struct ieee80211_cip_cap - CIP Capabilities element
+ *
+ * @v: The value of the Control Integrity Protocol Capability element
+ */
+struct ieee80211_cip_cap {
+ u8 v;
+} __packed;
+
#endif /* LINUX_IEEE80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9aa7d2d4a1841..1ef5f85a93764 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1821,6 +1821,8 @@ struct sta_txpwr {
* @s1g_capa: S1G capabilities of station
* @uhr_capa: UHR capabilities of the station
* @uhr_capa_len: the length of the UHR capabilities
+ * @cip_cap_set: If CIP capabilities are present, required for CIP stations
+ * @cip_cap: CIP capabilities of station
*/
struct link_station_parameters {
const u8 *mld_mac;
@@ -1842,6 +1844,8 @@ struct link_station_parameters {
const struct ieee80211_s1g_cap *s1g_capa;
const struct ieee80211_uhr_cap *uhr_capa;
u8 uhr_capa_len;
+ bool cip_cap_set;
+ u8 cip_cap;
};
/**
@@ -3402,6 +3406,7 @@ struct cfg80211_ml_reconf_req {
* flag is not set.
* @ASSOC_REQ_SPP_AMSDU: SPP A-MSDUs will be used on this connection (if any)
* @ASSOC_REQ_DISABLE_UHR: Disable UHR
+ * @ASSOC_REQ_CIP: Enable Control Integrity Protocol
*/
enum cfg80211_assoc_req_flags {
ASSOC_REQ_DISABLE_HT = BIT(0),
@@ -3413,6 +3418,7 @@ enum cfg80211_assoc_req_flags {
CONNECT_REQ_MLO_SUPPORT = BIT(6),
ASSOC_REQ_SPP_AMSDU = BIT(7),
ASSOC_REQ_DISABLE_UHR = BIT(8),
+ ASSOC_REQ_CIP = BIT(9),
};
/**
@@ -5304,14 +5310,17 @@ struct cfg80211_ops {
unsigned int link_id);
int (*add_key)(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params);
int (*get_key)(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params*));
int (*del_key)(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise,
+ int link_id, u8 key_index,
+ enum nl80211_key_type type,
const u8 *mac_addr);
int (*set_default_key)(struct wiphy *wiphy,
struct net_device *netdev, int link_id,
@@ -6045,6 +6054,8 @@ struct wiphy_vendor_command {
* @eml_capabilities: EML capabilities (for MLO)
* @mld_capa_and_ops: MLD capabilities and operations (for MLO)
* @ext_mld_capa_and_ops: Extended MLD capabilities and operations (for MLO)
+ * @cip_supported: CIP is supported and the capabilities are valid
+ * @cip_capabilities: CIP Capabilities element containing the MIC padding delay
*/
struct wiphy_iftype_ext_capab {
enum nl80211_iftype iftype;
@@ -6054,6 +6065,8 @@ struct wiphy_iftype_ext_capab {
u16 eml_capabilities;
u16 mld_capa_and_ops;
u16 ext_mld_capa_and_ops;
+ bool cip_supported;
+ u8 cip_capabilities;
};
/**
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1172d7b83ed18..15ac95048ce58 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2395,6 +2395,8 @@ static inline bool lockdep_vif_wiphy_mutex_held(struct ieee80211_vif *vif)
* number generation only
* @IEEE80211_KEY_FLAG_SPP_AMSDU: SPP A-MSDUs can be used with this key
* (set by mac80211 from the sta->spp_amsdu flag)
+ * @IEEE80211_KEY_FLAG_CIP: This key is used for the Control Integrity
+ * Protocol, and is either a pairwise key or a CIGTK.
*/
enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0),
@@ -2409,6 +2411,7 @@ enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_NO_AUTO_TX = BIT(9),
IEEE80211_KEY_FLAG_GENERATE_MMIE = BIT(10),
IEEE80211_KEY_FLAG_SPP_AMSDU = BIT(11),
+ IEEE80211_KEY_FLAG_CIP = BIT(12),
};
/**
@@ -2629,6 +2632,7 @@ struct ieee80211_sta_aggregates {
* @eht_cap: EHT capabilities of this STA
* @uhr_cap: UHR capabilities of this STA
* @s1g_cap: S1G capabilities of this STA
+ * @cip_cap: the CIP capabilities of this STA (or zero)
* @agg: per-link data for multi-link aggregation
* @bandwidth: current bandwidth the station can receive with.
* This is the minimum between the peer's capabilities and our own
@@ -2657,6 +2661,7 @@ struct ieee80211_link_sta {
struct ieee80211_sta_eht_cap eht_cap;
struct ieee80211_sta_uhr_cap uhr_cap;
struct ieee80211_sta_s1g_cap s1g_cap;
+ u8 cip_cap;
struct ieee80211_sta_aggregates agg;
@@ -2720,6 +2725,7 @@ struct ieee80211_link_sta {
* @valid_links: bitmap of valid links, or 0 for non-MLO
* @spp_amsdu: indicates whether the STA uses SPP A-MSDU or not.
* @epp_peer: indicates that the peer is an EPP peer.
+ * @cip: indicates whether the STA uses control frame protection or not.
* @nmi: For NDI stations, pointer to the NMI station of the peer.
* @nan_sched: NAN peer schedule for this station. Valid only for NMI stations.
* @ext_mld_capa_ops: the MLD's extended MLD capabilities and operations
@@ -2741,6 +2747,8 @@ struct ieee80211_sta {
u8 max_amsdu_subframes;
u16 eml_cap;
+ bool cip;
+
struct ieee80211_sta_aggregates *cur;
bool support_p2p_ps;
@@ -6278,6 +6286,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
* @key_len: the key data. Might be bigger than the actual key length,
* but not smaller (for the driver convinence)
* @link_id: the link id of the key or -1 for non-MLO
+ * @cigtk: whether this is a CIGTK
*
* When GTK rekeying was done while the system was suspended, (a) new
* key(s) will be available. These will be needed by mac80211 for proper
@@ -6304,7 +6313,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
struct ieee80211_key_conf *
ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
u8 idx, u8 *key_data, u8 key_len,
- int link_id);
+ int link_id, bool cigtk);
/**
* ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9a2ccb8d66b86..843d1dbb725d9 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3190,6 +3190,11 @@ enum nl80211_commands {
* known station to transmit a frame. This is relevant to know whether
* MLD address translation happened or to disable it when sending a frame.
*
+ * @NL80211_ATTR_ASSOC_CIP: Enable Control Integrity Protocol for the
+ * association
+ * @NL80211_ATTR_CIP_CAPABILITIES: The Control Integrity Protocol for the
+ * station.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3792,6 +3797,9 @@ enum nl80211_attrs {
NL80211_ATTR_FRAME_NO_STA,
+ NL80211_ATTR_ASSOC_CIP,
+ NL80211_ATTR_CIP_CAPABILITIES,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3942,6 +3950,7 @@ enum nl80211_iftype {
* that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a
* previously added station into associated state
* @NL80211_STA_FLAG_SPP_AMSDU: station supports SPP A-MSDUs
+ * @NL80211_STA_FLAG_CIP: station has Control Integrity Protocol (CIP) enabled
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
@@ -3955,6 +3964,7 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_TDLS_PEER,
NL80211_STA_FLAG_ASSOCIATED,
NL80211_STA_FLAG_SPP_AMSDU,
+ NL80211_STA_FLAG_CIP,
/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
@@ -5786,12 +5796,16 @@ enum nl80211_auth_type {
* @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
* @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
* @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ * @NL80211_KEYTYPE_CIGTK: Control Integrity Group Temporal Key
+ * The cipher is GMAC-256 but passed as GCMP-256,
+ * same as the pairwise key when used for CIP.
* @NUM_NL80211_KEYTYPES: number of defined key types
*/
enum nl80211_key_type {
NL80211_KEYTYPE_GROUP,
NL80211_KEYTYPE_PAIRWISE,
NL80211_KEYTYPE_PEERKEY,
+ NL80211_KEYTYPE_CIGTK,
NUM_NL80211_KEYTYPES
};
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 23f4f9ec86d0a..3714f8ccdf82d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -611,12 +611,15 @@ static int ieee80211_set_tx(struct ieee80211_sub_if_data *sdata,
}
static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, struct key_params *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_link_data *link =
ieee80211_link_or_deflink(sdata, link_id, false);
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
+ bool cigtk = type == NL80211_KEYTYPE_CIGTK;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta = NULL;
struct ieee80211_key *key;
@@ -660,6 +663,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
key->conf.link_id = -1;
} else {
key->conf.link_id = link->link_id;
+
+ if (cigtk)
+ key->conf.flags |= IEEE80211_KEY_FLAG_CIP;
}
if (params->mode == NL80211_KEY_NO_TX)
@@ -737,10 +743,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
static struct ieee80211_key *
ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,
- u8 key_idx, bool pairwise, const u8 *mac_addr)
+ u8 key_idx, enum nl80211_key_type type,
+ const u8 *mac_addr)
{
struct ieee80211_local *local __maybe_unused = sdata->local;
struct ieee80211_link_data *link = &sdata->deflink;
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
+ bool cigtk = type == NL80211_KEYTYPE_CIGTK;
struct ieee80211_key *key;
if (link_id >= 0) {
@@ -770,7 +779,11 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,
return wiphy_dereference(local->hw.wiphy,
sta->ptk[key_idx]);
- if (!pairwise &&
+ if (cigtk && key_idx < NUM_CTRL_KEYS)
+ return wiphy_dereference(local->hw.wiphy,
+ link_sta->cigtk[key_idx]);
+
+ if (!pairwise && !cigtk &&
key_idx < NUM_DEFAULT_KEYS +
NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS)
@@ -783,6 +796,9 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,
if (pairwise && key_idx < NUM_DEFAULT_KEYS)
return wiphy_dereference(local->hw.wiphy, sdata->keys[key_idx]);
+ if (cigtk)
+ return wiphy_dereference(local->hw.wiphy, link->cigtk[key_idx]);
+
key = wiphy_dereference(local->hw.wiphy, link->gtk[key_idx]);
if (key)
return key;
@@ -795,8 +811,8 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,
}
static int ieee80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
- const u8 *mac_addr)
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type, const u8 *mac_addr)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_local *local = sdata->local;
@@ -804,7 +820,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
lockdep_assert_wiphy(local->hw.wiphy);
- key = ieee80211_lookup_key(sdata, link_id, key_idx, pairwise, mac_addr);
+ key = ieee80211_lookup_key(sdata, link_id, key_idx, type, mac_addr);
if (!key)
return -ENOENT;
@@ -814,7 +830,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct wireless_dev *wdev,
}
static int ieee80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
- int link_id, u8 key_idx, bool pairwise,
+ int link_id, u8 key_idx,
+ enum nl80211_key_type type,
const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
@@ -833,7 +850,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct wireless_dev *wdev,
rcu_read_lock();
- key = ieee80211_lookup_key(sdata, link_id, key_idx, pairwise, mac_addr);
+ key = ieee80211_lookup_key(sdata, link_id, key_idx, type, mac_addr);
if (!key)
goto out;
@@ -2289,6 +2306,8 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
case STA_LINK_MODE_NEW:
if (!params->link_mac)
return -EINVAL;
+ if (sta->sta.cip && !params->cip_cap_set)
+ return -EINVAL;
break;
case STA_LINK_MODE_LINK_MODIFY:
break;
@@ -2411,6 +2430,9 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
ieee80211_s1g_cap_to_sta_s1g_cap(sdata, params->s1g_capa,
link_sta);
+ if (params->cip_cap_set)
+ link_sta->pub->cip_cap = params->cip_cap;
+
switch (sdata->vif.type) {
case NL80211_IFTYPE_NAN:
case NL80211_IFTYPE_NAN_DATA:
@@ -2573,6 +2595,9 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (params->eml_cap_present)
sta->sta.eml_cap = params->eml_cap;
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_CIP))
+ sta->sta.cip = true;
+
ret = sta_link_apply_parameters(local, sta, STA_LINK_MODE_STA_MODIFY,
¶ms->link_sta_params);
if (ret)
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 117f58af5ff9d..3a4f8e9e54dc1 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2015 Intel Deutschland GmbH
- * Copyright (C) 2021-2023 Intel Corporation
+ * Copyright (C) 2021-2023, 2026 Intel Corporation
*/
#include <linux/kobject.h>
@@ -42,9 +42,10 @@ static const struct debugfs_short_fops key_ ##name## _ops = { \
KEY_READ_##format(name) \
KEY_OPS(name)
-#define KEY_CONF_READ(name, format_string) \
- KEY_READ(conf_##name, conf.name, format_string)
-#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n")
+#define KEY_CONF_READ(name, val, format_string) \
+ KEY_READ(conf_##name, conf.val, format_string)
+#define KEY_CONF_READ_D(name, val) KEY_CONF_READ(name, val, "%d\n")
+#define KEY_CONF_READ_X(name, val) KEY_CONF_READ(name, val, "0x%x\n")
#define KEY_CONF_OPS(name) \
static const struct debugfs_short_fops key_ ##name## _ops = { \
@@ -53,13 +54,18 @@ static const struct debugfs_short_fops key_ ##name## _ops = { \
}
#define KEY_CONF_FILE(name, format) \
- KEY_CONF_READ_##format(name) \
+ KEY_CONF_READ_##format(name, name) \
+ KEY_CONF_OPS(name)
+#define KEY_CONF_FILE_NAMED(name, val, format) \
+ KEY_CONF_READ_##format(name, val) \
KEY_CONF_OPS(name)
KEY_CONF_FILE(keylen, D);
KEY_CONF_FILE(keyidx, D);
KEY_CONF_FILE(hw_key_idx, D);
+KEY_CONF_FILE_NAMED(conf_flags, flags, X);
KEY_FILE(flags, X);
+KEY_CONF_FILE(link_id, D);
KEY_READ(ifindex, sdata->name, "%s\n");
KEY_OPS(ifindex);
@@ -356,6 +362,8 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key)
DEBUGFS_ADD(mic_failures);
DEBUGFS_ADD(key);
DEBUGFS_ADD(ifindex);
+ DEBUGFS_ADD(conf_flags);
+ DEBUGFS_ADD(link_id);
};
void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9514f01778beb..66231ea8a985d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -486,6 +486,7 @@ struct ieee80211_mgd_assoc_data {
bool comeback; /* whether the AP has requested association comeback */
bool s1g;
bool spp_amsdu;
+ bool cip;
s8 assoc_link_id;
@@ -1113,6 +1114,7 @@ struct ieee80211_link_data {
struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +
NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS];
+ struct ieee80211_key __rcu *cigtk[NUM_CTRL_KEYS];
struct ieee80211_key __rcu *default_multicast_key;
struct ieee80211_key __rcu *default_mgmt_key;
struct ieee80211_key __rcu *default_beacon_key;
@@ -1878,6 +1880,7 @@ struct ieee802_11_elems {
const struct ieee80211_ttlm_elem *ttlm[IEEE80211_TTLM_MAX_CNT];
const struct ieee80211_uhr_cap *uhr_cap;
const struct ieee80211_uhr_operation *uhr_operation;
+ const struct ieee80211_cip_cap *cip_cap;
/* not the order in the psd values is per element, not per chandef */
struct ieee80211_parsed_tpe tpe;
@@ -2778,6 +2781,8 @@ int ieee80211_put_uhr_cap(struct sk_buff *skb,
const struct ieee80211_supported_band *sband);
void ieee80211_put_reg_conn(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
+int ieee80211_put_cip_cap(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata);
/* channel management */
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index f45e792abede5..4c9788ec0b74f 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -205,6 +205,10 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
sta ? sta->sta.addr : bcast_addr, ret);
out_unsupported:
+ /* Control Integrity Protocol can only be done in hardware */
+ if (key->conf.flags & IEEE80211_KEY_FLAG_CIP)
+ return -EINVAL;
+
switch (key->conf.cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
@@ -440,11 +444,13 @@ void ieee80211_set_default_beacon_key(struct ieee80211_link_data *link,
static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
struct ieee80211_link_data *link,
struct sta_info *sta,
- bool pairwise,
+ enum ieee80211_key_flags flags,
struct ieee80211_key *old,
struct ieee80211_key *new)
{
struct link_sta_info *link_sta = sta ? &sta->deflink : NULL;
+ bool pairwise = flags & IEEE80211_KEY_FLAG_PAIRWISE;
+ bool cip = flags & IEEE80211_KEY_FLAG_CIP;
int link_id;
int idx;
int ret = 0;
@@ -535,6 +541,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (new &&
!(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX))
_ieee80211_set_tx_key(new, true);
+ } else if (cip) {
+ rcu_assign_pointer(link_sta->cigtk[idx], new);
} else {
rcu_assign_pointer(link_sta->gtk[idx], new);
}
@@ -569,6 +577,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (is_wep || pairwise)
rcu_assign_pointer(sdata->keys[idx], new);
+ else if (cip)
+ rcu_assign_pointer(link->cigtk[idx], new);
else
rcu_assign_pointer(link->gtk[idx], new);
@@ -883,6 +893,10 @@ int ieee80211_key_link(struct ieee80211_key *key,
ret = -EOPNOTSUPP;
goto out;
}
+
+ /* Set CIP flag if enabled for the station */
+ if (sta->sta.cip)
+ key->conf.flags |= IEEE80211_KEY_FLAG_CIP;
} else if (sta) {
struct link_sta_info *link_sta = &sta->deflink;
int link_id = key->conf.link_id;
@@ -896,15 +910,25 @@ int ieee80211_key_link(struct ieee80211_key *key,
}
}
- old_key = wiphy_dereference(sdata->local->hw.wiphy,
- link_sta->gtk[idx]);
- } else {
- if (idx < NUM_DEFAULT_KEYS)
+ if (key->conf.flags & IEEE80211_KEY_FLAG_CIP)
old_key = wiphy_dereference(sdata->local->hw.wiphy,
- sdata->keys[idx]);
- if (!old_key)
+ link_sta->cigtk[idx]);
+ else
old_key = wiphy_dereference(sdata->local->hw.wiphy,
- link->gtk[idx]);
+ link_sta->gtk[idx]);
+ } else {
+ if (key->conf.flags & IEEE80211_KEY_FLAG_CIP) {
+ old_key = wiphy_dereference(sdata->local->hw.wiphy,
+ link->cigtk[idx]);
+ } else {
+ if (idx < NUM_DEFAULT_KEYS)
+ old_key = wiphy_dereference(sdata->local->hw.wiphy,
+ sdata->keys[idx]);
+
+ if (!old_key)
+ old_key = wiphy_dereference(sdata->local->hw.wiphy,
+ link->gtk[idx]);
+ }
}
/* Non-pairwise keys must also not switch the cipher on rekey */
@@ -938,9 +962,17 @@ int ieee80211_key_link(struct ieee80211_key *key,
if (sta && sta->sta.spp_amsdu)
key->conf.flags |= IEEE80211_KEY_FLAG_SPP_AMSDU;
+ /* A CIP related key must be GCMP-256 (really GMAC-256) */
+ if ((key->conf.flags & IEEE80211_KEY_FLAG_CIP) &&
+ key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256) {
+ ret = -EINVAL;
+ goto out;
+ }
+
increment_tailroom_need_count(sdata);
- ret = ieee80211_key_replace(sdata, link, sta, pairwise, old_key, key);
+ ret = ieee80211_key_replace(sdata, link, sta, key->conf.flags,
+ old_key, key);
if (!ret) {
ieee80211_debugfs_key_add(key);
@@ -966,8 +998,7 @@ void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
*/
if (key->sdata)
ieee80211_key_replace(key->sdata, NULL, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
ieee80211_key_destroy(key, delay_tailroom);
}
@@ -1098,8 +1129,7 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
ieee80211_key_replace(key->sdata, NULL, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
list_add_tail(&key->list, keys);
}
@@ -1119,8 +1149,7 @@ void ieee80211_remove_link_keys(struct ieee80211_link_data *link,
if (key->conf.link_id != link->link_id)
continue;
ieee80211_key_replace(key->sdata, link, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
list_add_tail(&key->list, keys);
}
}
@@ -1196,8 +1225,17 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
if (!key)
continue;
ieee80211_key_replace(key->sdata, NULL, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
+ __ieee80211_key_destroy(key, key->sdata->vif.type ==
+ NL80211_IFTYPE_STATION);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sta->deflink.cigtk); i++) {
+ key = wiphy_dereference(local->hw.wiphy, sta->deflink.cigtk[i]);
+ if (!key)
+ continue;
+ ieee80211_key_replace(key->sdata, NULL, key->sta,
+ key->conf.flags, key, NULL);
__ieee80211_key_destroy(key, key->sdata->vif.type ==
NL80211_IFTYPE_STATION);
}
@@ -1207,8 +1245,7 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
if (!key)
continue;
ieee80211_key_replace(key->sdata, NULL, key->sta,
- key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
- key, NULL);
+ key->conf.flags, key, NULL);
__ieee80211_key_destroy(key, key->sdata->vif.type ==
NL80211_IFTYPE_STATION);
}
@@ -1366,7 +1403,7 @@ EXPORT_SYMBOL_GPL(ieee80211_set_key_rx_seq);
struct ieee80211_key_conf *
ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
u8 idx, u8 *key_data, u8 key_len,
- int link_id)
+ int link_id, bool cigtk)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
@@ -1390,10 +1427,20 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
NUM_DEFAULT_BEACON_KEYS))
return ERR_PTR(-EINVAL);
- prev_key = wiphy_dereference(local->hw.wiphy,
- link_data->gtk[idx]);
+ if (WARN_ON(cigtk && idx >= NUM_CTRL_KEYS))
+ return ERR_PTR(-EINVAL);
+
+ if (cigtk)
+ prev_key = wiphy_dereference(local->hw.wiphy,
+ link_data->cigtk[idx]);
+ else
+ prev_key = wiphy_dereference(local->hw.wiphy,
+ link_data->gtk[idx]);
if (!prev_key) {
- if (idx < NUM_DEFAULT_KEYS) {
+ if (cigtk) {
+ prev_key = wiphy_dereference(local->hw.wiphy,
+ link_data->cigtk[idx ^ 1]);
+ } else if (idx < NUM_DEFAULT_KEYS) {
for (int i = 0; i < NUM_DEFAULT_KEYS; i++) {
if (i == idx)
continue;
@@ -1424,6 +1471,9 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)
key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
+ if (prev_key->conf.flags & IEEE80211_KEY_FLAG_CIP)
+ key->conf.flags |= IEEE80211_KEY_FLAG_CIP;
+
key->conf.link_id = link_data->link_id;
err = ieee80211_key_link(key, link_data, NULL);
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 826e4e9387c55..c85992493afd1 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -2,7 +2,7 @@
/*
* Copyright 2002-2004, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
- * Copyright (C) 2019, 2022-2023 Intel Corporation
+ * Copyright (C) 2019, 2022-2023, 2026 Intel Corporation
*/
#ifndef IEEE80211_KEY_H
@@ -19,6 +19,7 @@
#define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2
#define NUM_DEFAULT_BEACON_KEYS 2
+#define NUM_CTRL_KEYS 2
#define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */
struct ieee80211_local;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cf3873d8855b6..76c45a0eea621 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2337,6 +2337,10 @@ ieee80211_add_link_elems(struct ieee80211_sub_if_data *sdata,
ieee80211_put_eht_cap(skb, sdata, sband,
&assoc_data->link[link_id].conn);
+ /* Insert CIP only on the assoc link (it will be inherited) */
+ if (link_id == assoc_data->assoc_link_id && assoc_data->cip)
+ ieee80211_put_cip_cap(skb, sdata);
+
if (assoc_data->link[link_id].conn.mode >= IEEE80211_CONN_MODE_UHR)
ieee80211_put_uhr_cap(skb, sdata, sband);
@@ -2613,7 +2617,8 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
assoc_data->ie_len + /* extra IEs */
(assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
9 /* WMM */ +
- 4 /* regulatory connectivity, if 6 GHz is supported */;
+ 4 /* regulatory connectivity, if 6 GHz is supported */ +
+ (assoc_data->cip ? 4 /* CIP capabilities */ : 0);
for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
struct cfg80211_bss *cbss = assoc_data->link[link_id].bss;
@@ -6274,6 +6279,17 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
/* TODO: OPEN: what happens if BSS color disable is set? */
}
+ if (assoc_data->cip) {
+ if (elems->cip_cap) {
+ link_sta->pub->cip_cap = elems->cip_cap->v;
+ } else {
+ sdata_info(sdata,
+ "CIP Capabilities not included in association response\n");
+ ret = false;
+ goto out;
+ }
+ }
+
if (cbss->transmitted_bss) {
bss_conf->nontransmitted = true;
ether_addr_copy(bss_conf->transmitter_bssid,
@@ -6999,6 +7015,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out_err;
sta->sta.spp_amsdu = assoc_data->spp_amsdu;
+ sta->sta.cip = assoc_data->cip;
if (ieee80211_vif_is_mld(&sdata->vif)) {
if (!elems->ml_basic)
@@ -10536,6 +10553,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
}
assoc_data->spp_amsdu = req->flags & ASSOC_REQ_SPP_AMSDU;
+ assoc_data->cip = req->flags & ASSOC_REQ_CIP;
if (ifmgd->auth_data && !ifmgd->auth_data->done) {
err = -EBUSY;
diff --git a/net/mac80211/parse.c b/net/mac80211/parse.c
index cb2be167cde79..3b66ca7d7a5c2 100644
--- a/net/mac80211/parse.c
+++ b/net/mac80211/parse.c
@@ -205,6 +205,10 @@ ieee80211_parse_extension_element(u32 *crc,
elems->ttlm_num++;
}
break;
+ case WLAN_EID_EXT_CIP_CAPA:
+ if (len >= sizeof(*elems->cip_cap))
+ elems->cip_cap = data;
+ break;
case WLAN_EID_EXT_UHR_OPER:
if (params->mode < IEEE80211_CONN_MODE_UHR)
break;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index ee0d32877c5b4..f409f6a3afa1f 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -485,6 +485,7 @@ struct ieee80211_fragment_cache {
* @link_hash_node: hash node for rhashtable
* @sta: Points to the STA info
* @gtk: group keys negotiated with this station, if any
+ * @cigtk: control integrity group keys negotiated with this station, if any
* @tx_stats: TX statistics
* @tx_stats.packets: # of packets transmitted
* @tx_stats.bytes: # of bytes in all packets transmitted
@@ -535,6 +536,7 @@ struct link_sta_info {
struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +
NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS];
+ struct ieee80211_key __rcu *cigtk[NUM_CTRL_KEYS];
struct ieee80211_sta_rx_stats __percpu *pcpu_rx_stats;
/* Updated from RX path only, no locking requirements */
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index e2b5b2b21c347..c193a75ef06ea 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -4680,6 +4680,25 @@ int ieee80211_put_uhr_cap(struct sk_buff *skb,
return 0;
}
+int ieee80211_put_cip_cap(struct sk_buff *skb,
+ struct ieee80211_sub_if_data *sdata)
+{
+ const struct wiphy_iftype_ext_capab *ift_ext_capa =
+ cfg80211_get_iftype_ext_capa(sdata->local->hw.wiphy,
+ ieee80211_vif_type_p2p(&sdata->vif));
+ u8 cip_capabilities = ift_ext_capa ? ift_ext_capa->cip_capabilities : 0;
+
+ if (skb_tailroom(skb) < 4)
+ return -ENOBUFS;
+
+ skb_put_u8(skb, WLAN_EID_EXTENSION);
+ skb_put_u8(skb, 2);
+ skb_put_u8(skb, WLAN_EID_EXT_CIP_CAPA);
+ skb_put_u8(skb, cip_capabilities);
+
+ return 0;
+}
+
const char *ieee80211_conn_mode_str(enum ieee80211_conn_mode mode)
{
static const char * const modes[] = {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b4610f6685dcb..508d731fbf336 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -443,13 +443,16 @@ void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev);
/* internal helpers */
bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
+bool cfg80211_cigtk_supported(struct wireless_dev *wdev,
+ struct genl_info *info);
bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
- int key_idx, bool pairwise,
+ int key_idx, enum nl80211_key_type type,
const u8 *mac_addr);
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct key_params *params, int key_idx,
- bool pairwise, const u8 *mac_addr);
+ enum nl80211_key_type type,
+ const u8 *mac_addr);
void __cfg80211_scan_done(struct wiphy *wiphy, struct wiphy_work *wk);
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
bool send_message);
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index b1d748bdb504e..6ae561ed7f37f 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -172,7 +172,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
*/
if (rdev->ops->del_key)
for (i = 0; i < 6; i++)
- rdev_del_key(rdev, wdev, -1, i, false, NULL);
+ rdev_del_key(rdev, wdev, -1, i, NL80211_KEYTYPE_GROUP,
+ NULL);
if (wdev->u.ibss.current_bss) {
cfg80211_unhold_bss(wdev->u.ibss.current_bss);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ab5a14f5fe283..bfba773c6d9c1 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1098,6 +1098,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
NLA_POLICY_FULL_RANGE(NLA_U32, &nl80211_punct_bitmap_range),
[NL80211_ATTR_STA_DUMP_LINK_STATS] = { .type = NLA_FLAG },
[NL80211_ATTR_FRAME_NO_STA] = { .type = NLA_FLAG },
+ [NL80211_ATTR_ASSOC_CIP] = { .type = NLA_FLAG },
+ [NL80211_ATTR_CIP_CAPABILITIES] = { .type = NLA_U8 },
};
/* policy for the key attributes */
@@ -1763,6 +1765,11 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
GENL_SET_ERR_MSG(info, "def key idx not 0-3");
return -EINVAL;
}
+ } else if (k->type == NL80211_KEYTYPE_CIGTK) {
+ if (k->idx < 0 || k->idx > 1) {
+ GENL_SET_ERR_MSG(info, "CIGTK idx not 0-1");
+ return -EINVAL;
+ }
} else {
if (k->idx < 0 || k->idx > 7) {
GENL_SET_ERR_MSG(info, "key idx not 0-7");
@@ -1827,7 +1834,9 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
} else if (parse.defmgmt)
goto error;
err = cfg80211_validate_key_settings(rdev, wdev, &parse.p,
- parse.idx, false, NULL);
+ parse.idx,
+ NL80211_KEYTYPE_GROUP,
+ NULL);
if (err)
goto error;
if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
@@ -3617,6 +3626,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
NL80211_ATTR_EXT_MLD_CAPA_AND_OPS,
capab->ext_mld_capa_and_ops))
goto nla_put_failure;
+ if (capab->cip_supported &&
+ nla_put_u8(msg,
+ NL80211_ATTR_CIP_CAPABILITIES,
+ capab->cip_capabilities))
+ goto nla_put_failure;
nla_nest_end(msg, nested_ext_capab);
if (state->split)
@@ -5373,6 +5387,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
struct wireless_dev *wdev = info->user_ptr[1];
u8 key_idx = 0;
const u8 *mac_addr = NULL;
+ enum nl80211_key_type type;
bool pairwise;
struct get_key_cookie cookie = {
.error = 0,
@@ -5405,19 +5420,24 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
pairwise = !!mac_addr;
+ type = pairwise ? NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP;
if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
- u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
+ type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
- if (kt != NL80211_KEYTYPE_GROUP &&
- kt != NL80211_KEYTYPE_PAIRWISE)
+ if (type != NL80211_KEYTYPE_GROUP &&
+ type != NL80211_KEYTYPE_PAIRWISE &&
+ type != NL80211_KEYTYPE_CIGTK) {
+ GENL_SET_ERR_MSG(info, "key type not pairwise, group or CIGTK");
return -EINVAL;
- pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
+ }
+
+ pairwise = type == NL80211_KEYTYPE_PAIRWISE;
}
if (!rdev->ops->get_key)
return -EOPNOTSUPP;
- if (!cfg80211_valid_key_idx(wdev, key_idx, pairwise, mac_addr))
+ if (!cfg80211_valid_key_idx(wdev, key_idx, type, mac_addr))
return -ENOENT;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -5446,7 +5466,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (err)
goto free_msg;
- err = rdev_get_key(rdev, wdev, link_id, key_idx, pairwise, mac_addr,
+ err = rdev_get_key(rdev, wdev, link_id, key_idx, type, mac_addr,
&cookie, get_key_callback);
if (err)
@@ -5605,8 +5625,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
/* for now */
if (key.type != NL80211_KEYTYPE_PAIRWISE &&
- key.type != NL80211_KEYTYPE_GROUP) {
- GENL_SET_ERR_MSG(info, "key type not pairwise or group");
+ key.type != NL80211_KEYTYPE_GROUP &&
+ key.type != NL80211_KEYTYPE_CIGTK) {
+ GENL_SET_ERR_MSG(info, "key type not pairwise, group or CIGTK");
return -EINVAL;
}
@@ -5618,8 +5639,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
return -EOPNOTSUPP;
if (cfg80211_validate_key_settings(rdev, wdev, &key.p, key.idx,
- key.type == NL80211_KEYTYPE_PAIRWISE,
- mac_addr)) {
+ key.type, mac_addr)) {
GENL_SET_ERR_MSG(info, "key setting validation failed");
return -EINVAL;
}
@@ -5633,8 +5653,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
key.type == NL80211_KEYTYPE_PAIRWISE);
if (!err) {
- err = rdev_add_key(rdev, wdev, link_id, key.idx,
- key.type == NL80211_KEYTYPE_PAIRWISE,
+ err = rdev_add_key(rdev, wdev, link_id, key.idx, key.type,
mac_addr, &key.p);
if (err)
GENL_SET_ERR_MSG(info, "key addition failed");
@@ -5668,12 +5687,13 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
/* for now */
if (key.type != NL80211_KEYTYPE_PAIRWISE &&
- key.type != NL80211_KEYTYPE_GROUP)
+ key.type != NL80211_KEYTYPE_GROUP &&
+ key.type != NL80211_KEYTYPE_CIGTK) {
+ GENL_SET_ERR_MSG(info, "key type not pairwise, group or CIGTK");
return -EINVAL;
+ }
- if (!cfg80211_valid_key_idx(wdev, key.idx,
- key.type == NL80211_KEYTYPE_PAIRWISE,
- mac_addr))
+ if (!cfg80211_valid_key_idx(wdev, key.idx, key.type, mac_addr))
return -EINVAL;
if (!rdev->ops->del_key)
@@ -5687,8 +5707,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (!err)
err = rdev_del_key(rdev, wdev, link_id, key.idx,
- key.type == NL80211_KEYTYPE_PAIRWISE,
- mac_addr);
+ key.type, mac_addr);
#ifdef CONFIG_CFG80211_WEXT
if (!err) {
@@ -8819,7 +8838,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
return -EINVAL;
/* When you run into this, adjust the code below for the new flag */
- BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 8);
+ BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 9);
switch (statype) {
case CFG80211_STA_MESH_PEER_KERNEL:
@@ -8913,7 +8932,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
BIT(NL80211_STA_FLAG_WME) |
BIT(NL80211_STA_FLAG_MFP) |
- BIT(NL80211_STA_FLAG_SPP_AMSDU)))
+ BIT(NL80211_STA_FLAG_SPP_AMSDU) |
+ BIT(NL80211_STA_FLAG_CIP)))
return -EINVAL;
/* but authenticated/associated only if driver handles it */
@@ -9290,6 +9310,22 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
nla_get_u16(info->attrs[NL80211_ATTR_EML_CAPABILITY]);
}
+ if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_CIP) &&
+ params.sta_flags_set & BIT(NL80211_STA_FLAG_CIP)) {
+ if (!cfg80211_cigtk_supported(wdev, info))
+ return -EINVAL;
+
+ /* CIP capabilities are required if CIP is being enabled */
+ if (info->attrs[NL80211_ATTR_CIP_CAPABILITIES]) {
+ params.link_sta_params.cip_cap_set = true;
+ params.link_sta_params.cip_cap =
+ nla_get_u8(info->attrs[NL80211_ATTR_CIP_CAPABILITIES]);
+ } else {
+ GENL_SET_ERR_MSG(info, "No CIP capabilities provided");
+ return -EINVAL;
+ }
+ }
+
if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
params.airtime_weight =
nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
@@ -9489,6 +9525,22 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
nla_get_u16(info->attrs[NL80211_ATTR_EML_CAPABILITY]);
}
+ if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_CIP) &&
+ params.sta_flags_set & BIT(NL80211_STA_FLAG_CIP)) {
+ if (!cfg80211_cigtk_supported(wdev, info))
+ return -EINVAL;
+
+ /* CIP capabilities are required if CIP is enabled */
+ if (info->attrs[NL80211_ATTR_CIP_CAPABILITIES]) {
+ params.link_sta_params.cip_cap_set = true;
+ params.link_sta_params.cip_cap =
+ nla_get_u8(info->attrs[NL80211_ATTR_CIP_CAPABILITIES]);
+ } else {
+ GENL_SET_ERR_MSG(info, "No CIP capabilities provided");
+ return -EINVAL;
+ }
+ }
+
if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
params.link_sta_params.he_6ghz_capa =
nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
@@ -9566,7 +9618,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
/* When you run into this, adjust the code below for the new flag */
- BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 8);
+ BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 9);
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
@@ -9595,6 +9647,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.sta_flags_mask & BIT(NL80211_STA_FLAG_SPP_AMSDU))
return -EINVAL;
+ if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_CIP) &&
+ !cfg80211_cigtk_supported(wdev, info))
+ return -EINVAL;
+
/* Older userspace, or userspace wanting to be compatible with
* !NL80211_FEATURE_FULL_AP_CLIENT_STATE, will not set the auth
* and assoc flags in the mask, but assumes the station will be
@@ -13321,6 +13377,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
req.flags |= ASSOC_REQ_SPP_AMSDU;
}
+ if (nla_get_flag(info->attrs[NL80211_ATTR_ASSOC_CIP])) {
+ if (!cfg80211_cigtk_supported(dev->ieee80211_ptr, info))
+ return -EINVAL;
+
+ req.flags |= ASSOC_REQ_CIP;
+ }
+
req.link_id = nl80211_link_id_or_invalid(info->attrs);
if (info->attrs[NL80211_ATTR_MLO_LINKS]) {
@@ -19201,6 +19264,23 @@ nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info,
params.he_6ghz_capa =
nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
+ if (info->attrs[NL80211_ATTR_CIP_CAPABILITIES]) {
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (!cfg80211_cigtk_supported(wdev, info))
+ return -EINVAL;
+
+ params.cip_cap_set = true;
+ params.cip_cap =
+ nla_get_u8(info->attrs[NL80211_ATTR_CIP_CAPABILITIES]);
+
+ /* Only permit CIP capabilities when adding link stations */
+ if (!add) {
+ GENL_SET_ERR_MSG(info, "Cannot modify CIP capabilities");
+ return -EINVAL;
+ }
+ }
+
if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
params.opmode_notif_used = true;
params.opmode_notif =
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 46849fe8d0b39..7653cd0da9b93 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -78,42 +78,43 @@ rdev_change_virtual_intf(struct cfg80211_registered_device *rdev,
static inline int rdev_add_key(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr,
- struct key_params *params)
+ u8 key_index, enum nl80211_key_type type,
+ const u8 *mac_addr, struct key_params *params)
{
int ret;
- trace_rdev_add_key(&rdev->wiphy, wdev, link_id, key_index, pairwise,
+ trace_rdev_add_key(&rdev->wiphy, wdev, link_id, key_index, type,
mac_addr, params->mode);
ret = rdev->ops->add_key(&rdev->wiphy, wdev, link_id, key_index,
- pairwise, mac_addr, params);
+ type, mac_addr, params);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_get_key(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev,
- int link_id, u8 key_index, bool pairwise, const u8 *mac_addr,
- void *cookie,
+ int link_id, u8 key_index, enum nl80211_key_type type,
+ const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params*))
{
int ret;
- trace_rdev_get_key(&rdev->wiphy, wdev, link_id, key_index, pairwise,
+ trace_rdev_get_key(&rdev->wiphy, wdev, link_id, key_index, type,
mac_addr);
ret = rdev->ops->get_key(&rdev->wiphy, wdev, link_id, key_index,
- pairwise, mac_addr, cookie, callback);
+ type, mac_addr, cookie, callback);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_del_key(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr)
+ u8 key_index, enum nl80211_key_type type,
+ const u8 *mac_addr)
{
int ret;
- trace_rdev_del_key(&rdev->wiphy, wdev, link_id, key_index, pairwise,
+ trace_rdev_del_key(&rdev->wiphy, wdev, link_id, key_index, type,
mac_addr);
ret = rdev->ops->del_key(&rdev->wiphy, wdev, link_id, key_index,
- pairwise, mac_addr);
+ type, mac_addr);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 2a719b5c487e3..458f72d8351ab 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -1387,7 +1387,15 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
max_key_idx = 7;
for (i = 0; i <= max_key_idx; i++)
- rdev_del_key(rdev, wdev, -1, i, false, NULL);
+ rdev_del_key(rdev, wdev, -1, i, NL80211_KEYTYPE_GROUP,
+ NULL);
+
+ if (cfg80211_cigtk_supported(wdev, NULL)) {
+ rdev_del_key(rdev, wdev, -1, 0, NL80211_KEYTYPE_CIGTK,
+ NULL);
+ rdev_del_key(rdev, wdev, -1, 1, NL80211_KEYTYPE_CIGTK,
+ NULL);
+ }
}
rdev_set_qos_map(rdev, dev, NULL);
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 8c2a91b85c396..c210ca1e44e2b 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -557,15 +557,15 @@ TRACE_EVENT(rdev_change_virtual_intf,
DECLARE_EVENT_CLASS(key_handle,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr),
- TP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr),
+ u8 key_index, enum nl80211_key_type type, const u8 *mac_addr),
+ TP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
MAC_ENTRY(mac_addr)
__field(int, link_id)
__field(u8, key_index)
- __field(bool, pairwise)
+ __field(u8, type)
),
TP_fast_assign(
WIPHY_ASSIGN;
@@ -573,38 +573,40 @@ DECLARE_EVENT_CLASS(key_handle,
MAC_ASSIGN(mac_addr, mac_addr);
__entry->link_id = link_id;
__entry->key_index = key_index;
- __entry->pairwise = pairwise;
+ __entry->type = type;
),
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %d, "
- "key_index: %u, pairwise: %s, mac addr: %pM",
+ "key_index: %u, pairwise: %s, type: %d, mac addr: %pM",
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id,
- __entry->key_index, BOOL_TO_STR(__entry->pairwise),
- __entry->mac_addr)
+ __entry->key_index,
+ BOOL_TO_STR(__entry->type == NL80211_KEYTYPE_PAIRWISE),
+ __entry->type, __entry->mac_addr)
);
DEFINE_EVENT(key_handle, rdev_get_key,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr),
- TP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr)
+ u8 key_index, enum nl80211_key_type type, const u8 *mac_addr),
+ TP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr)
);
DEFINE_EVENT(key_handle, rdev_del_key,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr),
- TP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr)
+ u8 key_index, enum nl80211_key_type type, const u8 *mac_addr),
+ TP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr)
);
TRACE_EVENT(rdev_add_key,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id,
- u8 key_index, bool pairwise, const u8 *mac_addr, u8 mode),
- TP_ARGS(wiphy, wdev, link_id, key_index, pairwise, mac_addr, mode),
+ u8 key_index, enum nl80211_key_type type, const u8 *mac_addr,
+ u8 mode),
+ TP_ARGS(wiphy, wdev, link_id, key_index, type, mac_addr, mode),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
MAC_ENTRY(mac_addr)
__field(int, link_id)
__field(u8, key_index)
- __field(bool, pairwise)
+ __field(u8, type)
__field(u8, mode)
),
TP_fast_assign(
@@ -613,15 +615,16 @@ TRACE_EVENT(rdev_add_key,
MAC_ASSIGN(mac_addr, mac_addr);
__entry->link_id = link_id;
__entry->key_index = key_index;
- __entry->pairwise = pairwise;
+ __entry->type = type;
__entry->mode = mode;
),
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %d, "
- "key_index: %u, mode: %u, pairwise: %s, "
+ "key_index: %u, mode: %u, pairwise: %s, type: %d, "
"mac addr: %pM",
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id,
__entry->key_index, __entry->mode,
- BOOL_TO_STR(__entry->pairwise), __entry->mac_addr)
+ BOOL_TO_STR(__entry->type == NL80211_KEYTYPE_PAIRWISE),
+ __entry->type, __entry->mac_addr)
);
TRACE_EVENT(rdev_set_default_key,
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 3e584d0ca3e26..dd166c352910f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -258,8 +258,24 @@ static bool cfg80211_igtk_cipher_supported(struct wiphy *wiphy)
return false;
}
+bool cfg80211_cigtk_supported(struct wireless_dev *wdev,
+ struct genl_info *info)
+{
+ const struct wiphy_iftype_ext_capab *ext_capab =
+ cfg80211_get_iftype_ext_capa(wdev->wiphy, wdev->iftype);
+
+ if (ext_capab && ext_capab->cip_supported)
+ return true;
+
+ if (info)
+ GENL_SET_ERR_MSG(info,
+ "Control Integrity Protocol not supported");
+
+ return false;
+}
+
bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
- int key_idx, bool pairwise,
+ int key_idx, enum nl80211_key_type type,
const u8 *mac_addr)
{
if (WARN_ON(!wdev))
@@ -272,13 +288,24 @@ bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
* Can't differentiate ciphers here so allow 0..3.
* Pairwise keys must be for a station (MAC address given).
*/
- if (pairwise) {
+ if (type == NL80211_KEYTYPE_PAIRWISE) {
if (!mac_addr)
return false;
return key_idx < 4;
}
+ /* Check the wdev/iftype supports CIGTK */
+ if (type == NL80211_KEYTYPE_CIGTK) {
+ if (!cfg80211_cigtk_supported(wdev, NULL))
+ return false;
+
+ if (key_idx >= 2)
+ return false;
+
+ /* fallthrough for mac_addr checks */
+ }
+
/*
* For group keys, mac_addr==NULL means setting a group key
* for TX, which is only supported on some interface types,
@@ -343,9 +370,12 @@ bool cfg80211_valid_key_idx(struct wireless_dev *wdev,
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct key_params *params, int key_idx,
- bool pairwise, const u8 *mac_addr)
+ enum nl80211_key_type type,
+ const u8 *mac_addr)
{
- if (!cfg80211_valid_key_idx(wdev, key_idx, pairwise, mac_addr))
+ bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
+
+ if (!cfg80211_valid_key_idx(wdev, key_idx, type, mac_addr))
return -EINVAL;
switch (params->cipher) {
@@ -1172,7 +1202,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
for (i = 0; i < 4; i++) {
if (!wdev->connect_keys->params[i].cipher)
continue;
- if (rdev_add_key(rdev, wdev, -1, i, false, NULL,
+ if (rdev_add_key(rdev, wdev, -1, i, NL80211_KEYTYPE_GROUP, NULL,
&wdev->connect_keys->params[i])) {
netdev_err(dev, "failed to set key %d\n", i);
continue;
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index d45bc08c0de49..ec2389f6b8b18 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -401,6 +401,8 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
int idx, struct key_params *params)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
+ enum nl80211_key_type key_type =
+ pairwise ? NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP;
int err, i;
bool rejoin = false;
@@ -454,11 +456,11 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
rejoin = true;
}
- if (!cfg80211_valid_key_idx(wdev, idx, pairwise, addr))
+ if (!cfg80211_valid_key_idx(wdev, idx, key_type, addr))
err = -ENOENT;
else
- err = rdev_del_key(rdev, wdev, -1, idx, pairwise,
- addr);
+ err = rdev_del_key(rdev, wdev, -1, idx,
+ key_type, addr);
}
wdev->wext.connect.privacy = false;
/*
|
| 23/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 34541 output: 24 thoughts: 1136 Thoughts: **KMSAN Fuzzing Justification: Wireless Networking Patch Analysis** Okay, so the question is whether this patch series warrants a dedicated KMSAN fuzzing run. Let's break it down methodically. First, the patch scope: wireless networking. That covers a broad area, but a targeted KMSAN run could be valuable if the changes are significant. The code touches a lot of files, including headers, so it will probably impact a large number of wireless drivers. The first change is the signature modification of `add_key`, `del_key`, and `get_key` operations within `cfg80211_ops`. The `bool pairwise` argument is being replaced with an `enum nl80211_key_type type`. Now, most drivers updated to handle this new enum, translating the enum into `bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;`. Okay, this is a bit concerning. Specifically, in `wil6210`, I see something I don't like. Previously the code was passing `false` for `pairwise`, and now it's passing `NL80211_KEYTYPE_PAIRWISE`. This makes me think it could be a typo, potentially changing the key type. That's a memory safety concern immediately. If `false` previously meant a group key, but now it's being interpreted as a pairwise key, that could lead to subtle bugs, especially around key usage or access. I'll need to dig deeper into the semantics of the `wil6210` driver, and how it handles key management, for a full understanding. Next, there's the addition of CIP (Control Integrity Protocol) support. This is a bigger change, and it introduces a whole set of new structures and attributes: `NL80211_ATTR_ASSOC_CIP`, `NL80211_ATTR_CIP_CAPABILITIES`, `NL80211_STA_FLAG_CIP`, `NL80211_KEYTYPE_CIGTK`, `struct ieee80211_cip_cap`, and several additions to `wiphy_iftype_ext_capab`, `link_station_parameters`, etc. The critical area now is figuring out where these new `cip_*` fields are read and passed to userspace. If they're being sent via Netlink, there's always a risk of uninitialized data leaks or incorrect parsing on the user-space side, which can create memory safety issues. So, I need to check where `cip_cap` / `cip_capabilities` or any new fields are read or sent to user space. It looks like `nl80211_send_wiphy` is the function that may be of concern. Yes, the code is adding `NL80211_ATTR_CIP_CAPABILITIES` to the Netlink message if `capab->cip_supported` is true. Where does `capab` come from? I need to understand where `wiphy_iftype_ext_capab` is defined and populated, which is where the data will have come from. I'll search for `wiphy_iftype_ext_capab` to check that. Considering the scope of changes, the potential for key handling bugs in `wil6210` that could be related to key type, and the introduction of new CIP protocol fields transmitted to user space, I'd say a dedicated KMSAN run is *absolutely* justified. The risk/reward ratio is very favorable here. |
| 24/3 | 2026/09/23 10:51 | tool | grepper |
0mArgs:{
"Expression": "wiphy_iftype_ext_capab"
}Results: {
"Output": "drivers/net/wireless/ath/ath11k/mac.c=10374=static const u8 ath11k_if_types_ext_capa_ap[] = {\n--\ndrivers/net/wireless/ath/ath11k/mac.c-10381-\ndrivers/net/wireless/ath/ath11k/mac.c:10382:static const struct wiphy_iftype_ext_capab ath11k_iftypes_ext_capa[] = {\ndrivers/net/wireless/ath/ath11k/mac.c-10383-\t{\n--\ndrivers/net/wireless/ath/ath12k/mac.c=14706=static const u8 ath12k_if_types_ext_capa_ap[] = {\n--\ndrivers/net/wireless/ath/ath12k/mac.c-14713-\ndrivers/net/wireless/ath/ath12k/mac.c:14714:static struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = {\ndrivers/net/wireless/ath/ath12k/mac.c-14715-\t{\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mld.h=203=struct iwl_mld {\n--\ndrivers/net/wireless/intel/iwlwifi/mld/mld.h-240-\tstruct wiphy *wiphy;\ndrivers/net/wireless/intel/iwlwifi/mld/mld.h:241:\tstruct wiphy_iftype_ext_capab ext_capab[IWL_MLD_EXT_CAPA_NUM_IFTYPES];\ndrivers/net/wireless/intel/iwlwifi/mld/mld.h-242-\tu8 sta_ext_capab[IWL_MLD_STA_EXT_CAPA_SIZE];\n--\ndrivers/net/wireless/intel/iwlwifi/mvm/mac80211.c=251=static const u8 tm_if_types_ext_capa_sta[] = {\n--\ndrivers/net/wireless/intel/iwlwifi/mvm/mac80211.c-274-\ndrivers/net/wireless/intel/iwlwifi/mvm/mac80211.c:275:static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = {\ndrivers/net/wireless/intel/iwlwifi/mvm/mac80211.c-276-\t{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c=267=int mt7925_init_mlo_caps(struct mt792x_phy *phy)\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-274-\t};\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c:275:\tstatic struct wiphy_iftype_ext_capab ext_capab[] = {\ndrivers/net/wireless/mediatek/mt76/mt7925/main.c-276-\t\t{\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c=2026=mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb,\n--\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2030-\tstruct wiphy *wiphy = mvif-\u003ephy-\u003emt76-\u003ehw-\u003ewiphy;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c:2031:\tconst struct wiphy_iftype_ext_capab *ext_capa;\ndrivers/net/wireless/mediatek/mt76/mt7925/mcu.c-2032-\tstruct sta_rec_eht_mld *eht_mld;\n--\ndrivers/net/wireless/mediatek/mt76/mt7996/init.c=78=static const u8 if_types_ext_capa_ap[] = {\n--\ndrivers/net/wireless/mediatek/mt76/mt7996/init.c-83-\ndrivers/net/wireless/mediatek/mt76/mt7996/init.c:84:static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = {\ndrivers/net/wireless/mediatek/mt76/mt7996/init.c-85-\t{\n--\ndrivers/net/wireless/realtek/rtw89/core.c=208=static const u8 rtw89_ext_capa_sta[] = {\n--\ndrivers/net/wireless/realtek/rtw89/core.c-213-\ndrivers/net/wireless/realtek/rtw89/core.c:214:static const struct wiphy_iftype_ext_capab rtw89_iftypes_ext_capa[] = {\ndrivers/net/wireless/realtek/rtw89/core.c-215-\t{\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c=5656=static const u8 iftypes_ext_capa_ap[] = {\n--\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5670-\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c:5671:static const struct wiphy_iftype_ext_capab mac80211_hwsim_iftypes_ext_capa[] = {\ndrivers/net/wireless/virtual/mac80211_hwsim_main.c-5672-\t{\n--\ninclude/net/cfg80211.h=6032=struct wiphy_vendor_command {\n--\ninclude/net/cfg80211.h-6044-/**\ninclude/net/cfg80211.h:6045: * struct wiphy_iftype_ext_capab - extended capabilities per interface type\ninclude/net/cfg80211.h-6046- * @iftype: interface type\n--\ninclude/net/cfg80211.h-6059- */\ninclude/net/cfg80211.h:6060:struct wiphy_iftype_ext_capab {\ninclude/net/cfg80211.h-6061-\tenum nl80211_iftype iftype;\n--\ninclude/net/cfg80211.h-6078- */\ninclude/net/cfg80211.h:6079:const struct wiphy_iftype_ext_capab *\ninclude/net/cfg80211.h-6080-cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type);\n--\ninclude/net/cfg80211.h=6557=struct wiphy {\n--\ninclude/net/cfg80211.h-6632-\ninclude/net/cfg80211.h:6633:\tconst struct wiphy_iftype_ext_capab *iftype_ext_capab;\ninclude/net/cfg80211.h-6634-\tunsigned int num_iftype_ext_capab;\n--\nnet/mac80211/ap.c=51=ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/ap.c-56-\tstruct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);\nnet/mac80211/ap.c:57:\tconst struct wiphy_iftype_ext_capab *ift_ext_capa;\nnet/mac80211/ap.c-58-\tstruct ieee80211_mgmt *mgmt = (void *)skb-\u003edata;\n--\nnet/mac80211/mlme.c=2418=ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/mlme.c-2426-\tstruct ieee80211_mle_basic_common_info *common;\nnet/mac80211/mlme.c:2427:\tconst struct wiphy_iftype_ext_capab *ift_ext_capa;\nnet/mac80211/mlme.c-2428-\t__le16 eml_capa = 0, mld_capa_ops = 0;\n--\nnet/mac80211/mlme.c=10336=int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/mlme.c-10344-\tstruct ieee80211_vif_cfg *vif_cfg = \u0026sdata-\u003evif.cfg;\nnet/mac80211/mlme.c:10345:\tconst struct wiphy_iftype_ext_capab *ift_ext_capa;\nnet/mac80211/mlme.c-10346-\tstruct ieee80211_link_data *link;\n--\nnet/mac80211/mlme.c=11171=ieee80211_build_ml_reconf_req(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/mlme.c-11202-\tif (add_links_data) {\nnet/mac80211/mlme.c:11203:\t\tconst struct wiphy_iftype_ext_capab *ift_ext_capa =\nnet/mac80211/mlme.c-11204-\t\t\tcfg80211_get_iftype_ext_capa(local-\u003ehw.wiphy,\n--\nnet/mac80211/mlme.c=11400=int ieee80211_mgd_assoc_ml_reconf(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/mlme.c-11402-{\nnet/mac80211/mlme.c:11403:\tconst struct wiphy_iftype_ext_capab *ift_ext_capa;\nnet/mac80211/mlme.c-11404-\tstruct ieee80211_local *local = sdata-\u003elocal;\n--\nnet/mac80211/util.c=4683=int ieee80211_put_cip_cap(struct sk_buff *skb,\n--\nnet/mac80211/util.c-4685-{\nnet/mac80211/util.c:4686:\tconst struct wiphy_iftype_ext_capab *ift_ext_capa =\nnet/mac80211/util.c-4687-\t\tcfg80211_get_iftype_ext_capa(sdata-\u003elocal-\u003ehw.wiphy,\n--\nnet/wireless/core.c=853=int wiphy_register(struct wiphy *wiphy)\n--\nnet/wireless/core.c-1209-\t\tu8 supported_on_all, j;\nnet/wireless/core.c:1210:\t\tconst struct wiphy_iftype_ext_capab *capab;\nnet/wireless/core.c-1211-\n--\nnet/wireless/nl80211.c=3068=static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/nl80211.c-3597-\t\t\t i \u003c rdev-\u003ewiphy.num_iftype_ext_capab; i++) {\nnet/wireless/nl80211.c:3598:\t\t\t\tconst struct wiphy_iftype_ext_capab *capab;\nnet/wireless/nl80211.c-3599-\n--\nnet/wireless/util.c=261=bool cfg80211_cigtk_supported(struct wireless_dev *wdev,\n--\nnet/wireless/util.c-263-{\nnet/wireless/util.c:264:\tconst struct wiphy_iftype_ext_capab *ext_capab =\nnet/wireless/util.c-265-\t\tcfg80211_get_iftype_ext_capa(wdev-\u003ewiphy, wdev-\u003eiftype);\n--\nnet/wireless/util.c=3082=int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/util.c-3089-\nnet/wireless/util.c:3090:const struct wiphy_iftype_ext_capab *\nnet/wireless/util.c-3091-cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type)\n"
} |
| 25/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 39958 output: 37 thoughts: 238 Thoughts: **Analyzing Station Parameter Initialization in nl80211 Functions** Okay, so I'm looking at how extended capabilities are handled for different interface types. I see that `wiphy_iftype_ext_capab` is defined statically within various driver implementations—`mac80211_hwsim_iftypes_ext_capa`, `ath11k_iftypes_ext_capa`, you get the idea. That's fine; anything uninitialized in those `static const` structures will just default to zero. Pretty standard stuff. Now, my focus is on how station parameters are handled in the `nl80211` context. I need to understand how the system manages the extended capabilities of the station, so I'm digging into `nl80211_new_station`, `nl80211_set_station`, and `nl80211_add_mod_link_station`. Aha, here's a curious point. In these functions, I see the declaration: ```c struct station_parameters params; ``` But, hold on a second. Where is this `params` structure actually allocated and initialized *within* these three functions? I need to check where `params` is assigned. It's allocated on the stack (implicitly) but where are the values assigned? Let me reread those functions and get a good understanding of what's happening. I need to make sure I'm not missing something subtle. |
| 26/3 | 2026/09/23 10:51 | tool | grepper |
0mArgs:{
"Expression": "struct station_parameters params",
"PathPrefix": "net/wireless/nl80211.c"
}Results: {
"Output": "net/wireless/nl80211.c=9190=static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-9194-\tstruct net_device *dev = wdev-\u003enetdev;\nnet/wireless/nl80211.c:9195:\tstruct station_parameters params;\nnet/wireless/nl80211.c-9196-\tu8 *mac_addr;\n--\nnet/wireless/nl80211.c=9378=static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-9383-\tstruct net_device *dev = wdev-\u003enetdev;\nnet/wireless/nl80211.c:9384:\tstruct station_parameters params;\nnet/wireless/nl80211.c-9385-\tu8 *mac_addr = NULL;\n"
} |
| 27/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 40842 output: 41 thoughts: 42 Thoughts: Here's my analysis of the provided snippet, as if it were my thought process: **Diving into the `nl80211.c` Code** Okay, so we're looking at something in the `nl80211.c` file. Right, that's the Netlink interface for wireless configuration and events – pretty fundamental stuff. Specifically, I need to get a handle on how this `params` variable is being handled. I recall this area, so let me immediately jump to around line 9195 and then 9384. I'm keen to determine if `params` is subjected to a `memset` call. That's a classic code pattern for zeroing out memory, and it's essential for ensuring a clean slate before populating a structure. Understanding if it's being cleared is crucial; it helps to determine if the data is reliable. |
| 28/3 | 2026/09/23 10:51 | tool | read-file |
0mArgs:{
"File": "net/wireless/nl80211.c",
"FirstLine": 9190,
"LineCount": 40
}Results: {
"Contents": "9190:\tstatic int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)\n9191:\t{\n9192:\t\tstruct cfg80211_registered_device *rdev = info-\u003euser_ptr[0];\n9193:\t\tstruct wireless_dev *wdev = info-\u003euser_ptr[1];\n9194:\t\tstruct net_device *dev = wdev-\u003enetdev;\n9195:\t\tstruct station_parameters params;\n9196:\t\tu8 *mac_addr;\n9197:\t\tint err;\n9198:\t\n9199:\t\tmemset(\u0026params, 0, sizeof(params));\n9200:\t\n9201:\t\tif (!dev \u0026\u0026 wdev-\u003eiftype != NL80211_IFTYPE_NAN \u0026\u0026\n9202:\t\t wdev-\u003eiftype != NL80211_IFTYPE_NAN_DATA)\n9203:\t\t\treturn -EINVAL;\n9204:\t\n9205:\t\tif (!rdev-\u003eops-\u003echange_station)\n9206:\t\t\treturn -EOPNOTSUPP;\n9207:\t\n9208:\t\t/*\n9209:\t\t * AID and listen_interval properties can be set only for unassociated\n9210:\t\t * station. Include these parameters here and will check them in\n9211:\t\t * cfg80211_check_station_change().\n9212:\t\t */\n9213:\t\tif (info-\u003eattrs[NL80211_ATTR_STA_AID])\n9214:\t\t\tparams.aid = nla_get_u16(info-\u003eattrs[NL80211_ATTR_STA_AID]);\n9215:\t\n9216:\t\tif (info-\u003eattrs[NL80211_ATTR_VLAN_ID])\n9217:\t\t\tparams.vlan_id = nla_get_u16(info-\u003eattrs[NL80211_ATTR_VLAN_ID]);\n9218:\t\n9219:\t\tif (info-\u003eattrs[NL80211_ATTR_STA_LISTEN_INTERVAL])\n9220:\t\t\tparams.listen_interval =\n9221:\t\t\t nla_get_u16(info-\u003eattrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);\n9222:\t\telse\n9223:\t\t\tparams.listen_interval = -1;\n9224:\t\n9225:\t\tif (info-\u003eattrs[NL80211_ATTR_STA_SUPPORT_P2P_PS])\n9226:\t\t\tparams.support_p2p_ps =\n9227:\t\t\t\tnla_get_u8(info-\u003eattrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]);\n9228:\t\telse\n9229:\t\t\tparams.support_p2p_ps = -1;\n"
} |
| 29/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 41878 output: 41 thoughts: 58 Thoughts: Here's my summary, as if I were thinking these thoughts: **Initial Setup and Contextual Checks** Okay, first things first, `memset(¶ms, 0, sizeof(params))` - that's standard initialization. Always a good practice to start with a clean slate. Now, let's dive deeper and consider how this relates to the overall flow, specifically `nl80211_new_station` and `nl80211_add_mod_link_station`. I need to understand how these routines interact within this section of the code. My expert understanding of this field dictates a need to trace these calls and what parameters are being passed to them. I have to make sure no important initial values are being overwritten. This is key to ensuring the station setup and link modification are handled correctly and don't introduce any unexpected behavior or vulnerabilities. |
| 30/3 | 2026/09/23 10:51 | tool | read-file |
0mArgs:{
"File": "net/wireless/nl80211.c",
"FirstLine": 9380,
"LineCount": 40
}Results: {
"Contents": "9380:\t\tstruct cfg80211_registered_device *rdev = info-\u003euser_ptr[0];\n9381:\t\tint err;\n9382:\t\tstruct wireless_dev *wdev = info-\u003euser_ptr[1];\n9383:\t\tstruct net_device *dev = wdev-\u003enetdev;\n9384:\t\tstruct station_parameters params;\n9385:\t\tu8 *mac_addr = NULL;\n9386:\t\tu32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |\n9387:\t\t\t\t BIT(NL80211_STA_FLAG_ASSOCIATED);\n9388:\t\n9389:\t\tmemset(\u0026params, 0, sizeof(params));\n9390:\t\n9391:\t\tif (!dev \u0026\u0026 wdev-\u003eiftype != NL80211_IFTYPE_NAN)\n9392:\t\t\treturn -EINVAL;\n9393:\t\n9394:\t\tif (!rdev-\u003eops-\u003eadd_station)\n9395:\t\t\treturn -EOPNOTSUPP;\n9396:\t\n9397:\t\tif (!info-\u003eattrs[NL80211_ATTR_MAC])\n9398:\t\t\treturn -EINVAL;\n9399:\t\n9400:\t\tif (wdev-\u003eiftype == NL80211_IFTYPE_NAN ||\n9401:\t\t wdev-\u003eiftype == NL80211_IFTYPE_NAN_DATA) {\n9402:\t\t\tif (info-\u003eattrs[NL80211_ATTR_STA_SUPPORTED_RATES])\n9403:\t\t\t\treturn -EINVAL;\n9404:\t\t\tif (wdev-\u003eiftype == NL80211_IFTYPE_NAN_DATA) {\n9405:\t\t\t\tif (!info-\u003eattrs[NL80211_ATTR_NAN_NMI_MAC])\n9406:\t\t\t\t\treturn -EINVAL;\n9407:\t\n9408:\t\t\t\t/* Only NMI stations receive the HT/VHT/HE capabilities */\n9409:\t\t\t\tif (info-\u003eattrs[NL80211_ATTR_HT_CAPABILITY] ||\n9410:\t\t\t\t info-\u003eattrs[NL80211_ATTR_VHT_CAPABILITY] ||\n9411:\t\t\t\t info-\u003eattrs[NL80211_ATTR_HE_CAPABILITY])\n9412:\t\t\t\t\treturn -EINVAL;\n9413:\t\t\t}\n9414:\t\t} else {\n9415:\t\t\tif (!info-\u003eattrs[NL80211_ATTR_STA_LISTEN_INTERVAL])\n9416:\t\t\t\treturn -EINVAL;\n9417:\t\n9418:\t\t\tif (!info-\u003eattrs[NL80211_ATTR_STA_SUPPORTED_RATES])\n9419:\t\t\t\treturn -EINVAL;\n"
} |
| 31/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 42902 output: 46 thoughts: 38 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience: **Analyzing nl80211 Module Linking** Alright, so I see a `memset` being used to zero out a `params` structure. Standard practice, of course – good for initializing and ensuring a clean slate before populating it. Nothing unexpected there, just making sure we're starting fresh. The `sizeof(params)` argument is correct, obviously. Now, my focus shifts to the `nl80211_add_mod_link_station` function. This suggests we're likely dealing with establishing a link between a station and a specific module within the nl80211 subsystem. Probably some interaction with regulatory, hardware or software aspects. I'll need to figure out what data is getting sent by this function. I'll have to investigate the purpose and impact, and the underlying data structures, to understand the overall architecture. I suspect there might be several factors at play here, which is why a modular structure is present. |
| 32/3 | 2026/09/23 10:51 | tool | grepper |
0mArgs:{
"Expression": "nl80211_add_mod_link_station",
"PathPrefix": "net/wireless/nl80211.c"
}Results: {
"Output": "net/wireless/nl80211.c=19183=static int\nnet/wireless/nl80211.c:19184:nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info,\nnet/wireless/nl80211.c-19185-\t\t\t bool add)\n--\nnet/wireless/nl80211.c=19302=nl80211_add_link_station(struct sk_buff *skb, struct genl_info *info)\nnet/wireless/nl80211.c-19303-{\nnet/wireless/nl80211.c:19304:\treturn nl80211_add_mod_link_station(skb, info, true);\nnet/wireless/nl80211.c-19305-}\n--\nnet/wireless/nl80211.c=19308=nl80211_modify_link_station(struct sk_buff *skb, struct genl_info *info)\nnet/wireless/nl80211.c-19309-{\nnet/wireless/nl80211.c:19310:\treturn nl80211_add_mod_link_station(skb, info, false);\nnet/wireless/nl80211.c-19311-}\n"
} |
| 33/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 43586 output: 42 thoughts: 20 Thoughts: Okay, let's dive into this `nl80211_add_mod_link_station` function. **Analyzing nl80211_add_mod_link_station** Alright, I'm going to take a look at `nl80211_add_mod_link_station` and see what it's all about. From the name, I'm expecting this to handle either the addition or modification of a station link within the nl80211 framework. Given my experience, I'm expecting it probably to interact with the station manager, the regulatory database (if any of the attributes involve regulatory data), and maybe even the rate control module. I need to understand the data structures it uses, particularly any `cfg80211_` or `nlattr_` based structs. I'll need to look for calls to `genlmsg_put` or other Netlink-related functions. If this is modifying existing stations, I'm anticipating some checks to make sure the station exists. It's also likely dealing with authorization, making sure the user has the permissions to make such changes, and some locking mechanism to make sure there are no race conditions. I'm going to look for any interaction with mac addresses, as well as configuration attributes like channel, tx power, etc., that define the parameters of the link. I'll be looking carefully at the error handling, and making sure that the error codes are properly set and meaningful to an end user. Finally, I'll be interested to see how it handles things like rate selection. Is it using the standard rate control mechanisms or some custom logic? I'm ready to dig in and see the details of its implementation. |
| 34/3 | 2026/09/23 10:51 | tool | read-file |
0mArgs:{
"File": "net/wireless/nl80211.c",
"FirstLine": 19183,
"LineCount": 40
}Results: {
"Contents": "19183:\tstatic int\n19184:\tnl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info,\n19185:\t\t\t\t bool add)\n19186:\t{\n19187:\t\tstruct link_station_parameters params = {};\n19188:\t\tstruct cfg80211_registered_device *rdev = info-\u003euser_ptr[0];\n19189:\t\tstruct net_device *dev = info-\u003euser_ptr[1];\n19190:\t\tint err;\n19191:\t\n19192:\t\tif ((add \u0026\u0026 !rdev-\u003eops-\u003eadd_link_station) ||\n19193:\t\t (!add \u0026\u0026 !rdev-\u003eops-\u003emod_link_station))\n19194:\t\t\treturn -EOPNOTSUPP;\n19195:\t\n19196:\t\tif (add \u0026\u0026 !info-\u003eattrs[NL80211_ATTR_MAC])\n19197:\t\t\treturn -EINVAL;\n19198:\t\n19199:\t\tif (!info-\u003eattrs[NL80211_ATTR_MLD_ADDR])\n19200:\t\t\treturn -EINVAL;\n19201:\t\n19202:\t\tif (add \u0026\u0026 !info-\u003eattrs[NL80211_ATTR_STA_SUPPORTED_RATES])\n19203:\t\t\treturn -EINVAL;\n19204:\t\n19205:\t\tparams.mld_mac = nla_data(info-\u003eattrs[NL80211_ATTR_MLD_ADDR]);\n19206:\t\n19207:\t\tif (info-\u003eattrs[NL80211_ATTR_MAC]) {\n19208:\t\t\tparams.link_mac = nla_data(info-\u003eattrs[NL80211_ATTR_MAC]);\n19209:\t\t\tif (!is_valid_ether_addr(params.link_mac))\n19210:\t\t\t\treturn -EINVAL;\n19211:\t\t}\n19212:\t\n19213:\t\tif (!info-\u003eattrs[NL80211_ATTR_MLO_LINK_ID])\n19214:\t\t\treturn -EINVAL;\n19215:\t\n19216:\t\tparams.link_id = nla_get_u8(info-\u003eattrs[NL80211_ATTR_MLO_LINK_ID]);\n19217:\t\n19218:\t\tif (info-\u003eattrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {\n19219:\t\t\tparams.supported_rates =\n19220:\t\t\t\tnla_data(info-\u003eattrs[NL80211_ATTR_STA_SUPPORTED_RATES]);\n19221:\t\t\tparams.supported_rates_len =\n19222:\t\t\t\tnla_len(info-\u003eattrs[NL80211_ATTR_STA_SUPPORTED_RATES]);\n"
} |
| 35/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 44803 output: 27 thoughts: 84 Thoughts: Okay, let's see what we've got here.
**Initial Considerations for Station Parameter Handling**
Right, so I'm starting with a clean slate – `struct link_station_parameters params = {};`. I'm zeroing out the structure, which is always a good practice to ensure a known initial state. Prevents any nasty surprises down the line. Now, I'm thinking about the user interface – how is this information, or any similar station data, going to be exposed to userspace?
Specifically, I'm trying to figure out if `cip` or `cip_cap` (which I assume relates to Client Information Protocol, or some capability derived from it) is accessible. The next logical step is to dive into the existing functions. I'm thinking of checking `nl80211_dump_station` or any similar get/dump functions to see what they expose. Is the information currently being passed through?
If it's not currently exposed I'll have to consider how to accomplish that.
Alright, time to get my hands dirty and start searching through the kernel source to see where `NL80211_ATTR_CIP_CAPABILITIES` is used. That should tell me if we're even *tracking* that information anywhere in the first place, and if so, how it's handled. Let's see what that search turns up.
|
| 36/3 | 2026/09/23 10:51 | tool | grepper |
0mArgs:{
"Expression": "NL80211_ATTR_CIP_CAPABILITIES"
}Results: {
"Output": "include/uapi/linux/nl80211.h=1433=enum nl80211_commands {\n--\ninclude/uapi/linux/nl80211.h-3194- *\tassociation\ninclude/uapi/linux/nl80211.h:3195: * @NL80211_ATTR_CIP_CAPABILITIES: The Control Integrity Protocol for the\ninclude/uapi/linux/nl80211.h-3196- *\tstation.\n--\ninclude/uapi/linux/nl80211.h=3202=enum nl80211_attrs {\n--\ninclude/uapi/linux/nl80211.h-3800-\tNL80211_ATTR_ASSOC_CIP,\ninclude/uapi/linux/nl80211.h:3801:\tNL80211_ATTR_CIP_CAPABILITIES,\ninclude/uapi/linux/nl80211.h-3802-\n--\nnet/wireless/nl80211.c=701=static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {\n--\nnet/wireless/nl80211.c-1101-\t[NL80211_ATTR_ASSOC_CIP] = { .type = NLA_FLAG },\nnet/wireless/nl80211.c:1102:\t[NL80211_ATTR_CIP_CAPABILITIES] = { .type = NLA_U8 },\nnet/wireless/nl80211.c-1103-};\n--\nnet/wireless/nl80211.c=3068=static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,\n--\nnet/wireless/nl80211.c-3630-\t\t\t\t nla_put_u8(msg,\nnet/wireless/nl80211.c:3631:\t\t\t\t\t NL80211_ATTR_CIP_CAPABILITIES,\nnet/wireless/nl80211.c-3632-\t\t\t\t\t capab-\u003ecip_capabilities))\n--\nnet/wireless/nl80211.c=9190=static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-9318-\t\t/* CIP capabilities are required if CIP is being enabled */\nnet/wireless/nl80211.c:9319:\t\tif (info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]) {\nnet/wireless/nl80211.c-9320-\t\t\tparams.link_sta_params.cip_cap_set = true;\nnet/wireless/nl80211.c-9321-\t\t\tparams.link_sta_params.cip_cap =\nnet/wireless/nl80211.c:9322:\t\t\t\tnla_get_u8(info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]);\nnet/wireless/nl80211.c-9323-\t\t} else {\n--\nnet/wireless/nl80211.c=9378=static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-9533-\t\t/* CIP capabilities are required if CIP is enabled */\nnet/wireless/nl80211.c:9534:\t\tif (info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]) {\nnet/wireless/nl80211.c-9535-\t\t\tparams.link_sta_params.cip_cap_set = true;\nnet/wireless/nl80211.c-9536-\t\t\tparams.link_sta_params.cip_cap =\nnet/wireless/nl80211.c:9537:\t\t\t\tnla_get_u8(info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]);\nnet/wireless/nl80211.c-9538-\t\t} else {\n--\nnet/wireless/nl80211.c=19184=nl80211_add_mod_link_station(struct sk_buff *skb, struct genl_info *info,\n--\nnet/wireless/nl80211.c-19266-\nnet/wireless/nl80211.c:19267:\tif (info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]) {\nnet/wireless/nl80211.c-19268-\t\tstruct wireless_dev *wdev = dev-\u003eieee80211_ptr;\n--\nnet/wireless/nl80211.c-19274-\t\tparams.cip_cap =\nnet/wireless/nl80211.c:19275:\t\t\tnla_get_u8(info-\u003eattrs[NL80211_ATTR_CIP_CAPABILITIES]);\nnet/wireless/nl80211.c-19276-\n"
} |
| 37/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 46563 output: 26 thoughts: 41 Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience: **Investigating `NL80211_STA_FLAG_CIP` Usage** Alright, let's dive in. I need to understand the implications of `NL80211_STA_FLAG_CIP`. I'm going to start by tracing its use. Where exactly is this flag being checked within the wireless stack? More specifically, where is this flag used, inspected, or, crucially, dumped for debugging purposes? I need to identify all code paths where it plays a role to get a comprehensive view. This will give me a solid base to understand its function and potential impact. Time to start digging through the relevant codebases and cross-references. |
| 38/3 | 2026/09/23 10:51 | tool | grepper |
0mArgs:{
"Expression": "NL80211_STA_FLAG_CIP"
}Results: {
"Output": "include/uapi/linux/nl80211.h=3909=enum nl80211_iftype {\n--\ninclude/uapi/linux/nl80211.h-3952- * @NL80211_STA_FLAG_SPP_AMSDU: station supports SPP A-MSDUs\ninclude/uapi/linux/nl80211.h:3953: * @NL80211_STA_FLAG_CIP: station has Control Integrity Protocol (CIP) enabled\ninclude/uapi/linux/nl80211.h-3954- * @NL80211_STA_FLAG_MAX: highest station flag number currently defined\n--\ninclude/uapi/linux/nl80211.h=3957=enum nl80211_sta_flags {\n--\ninclude/uapi/linux/nl80211.h-3966-\tNL80211_STA_FLAG_SPP_AMSDU,\ninclude/uapi/linux/nl80211.h:3967:\tNL80211_STA_FLAG_CIP,\ninclude/uapi/linux/nl80211.h-3968-\n--\nnet/mac80211/cfg.c=2472=static int sta_apply_parameters(struct ieee80211_local *local,\n--\nnet/mac80211/cfg.c-2597-\nnet/mac80211/cfg.c:2598:\tif (params-\u003esta_flags_set \u0026 BIT(NL80211_STA_FLAG_CIP))\nnet/mac80211/cfg.c-2599-\t\tsta-\u003esta.cip = true;\n--\nnet/wireless/nl80211.c=8823=int cfg80211_check_station_change(struct wiphy *wiphy,\n--\nnet/wireless/nl80211.c-8935-\t\t\t\t BIT(NL80211_STA_FLAG_SPP_AMSDU) |\nnet/wireless/nl80211.c:8936:\t\t\t\t BIT(NL80211_STA_FLAG_CIP)))\nnet/wireless/nl80211.c-8937-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c=9190=static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-9312-\nnet/wireless/nl80211.c:9313:\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_CIP) \u0026\u0026\nnet/wireless/nl80211.c:9314:\t params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_CIP)) {\nnet/wireless/nl80211.c-9315-\t\tif (!cfg80211_cigtk_supported(wdev, info))\n--\nnet/wireless/nl80211.c=9378=static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-9527-\nnet/wireless/nl80211.c:9528:\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_CIP) \u0026\u0026\nnet/wireless/nl80211.c:9529:\t params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_CIP)) {\nnet/wireless/nl80211.c-9530-\t\tif (!cfg80211_cigtk_supported(wdev, info))\n--\nnet/wireless/nl80211.c-9649-\nnet/wireless/nl80211.c:9650:\t\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_CIP) \u0026\u0026\nnet/wireless/nl80211.c-9651-\t\t !cfg80211_cigtk_supported(wdev, info))\n"
} |
| 39/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 47908 output: 43 thoughts: 41 Thoughts: Okay, let's see. My first thought is: **Decoding the Station Info - Is `NL80211_STA_FLAG_CIP` making it to userspace?** I need to confirm if that particular flag, `NL80211_STA_FLAG_CIP`, is actually being dumped to userspace within the station information. I know how critical the accurate transmission of this data is, and I want to be certain that the logic is correct. My mental checklist says, "the critical function here is `nl80211_send_station`". That's the one to trace to verify its behavior regarding this specific flag. I need to dive into that function to see how it handles `NL80211_STA_FLAG_CIP` and how it's packed in the netlink message. Time to get to work. |
| 40/3 | 2026/09/23 10:51 | tool | grepper |
0mArgs:{
"Expression": "NL80211_STA_FLAG_",
"PathPrefix": "net/wireless/nl80211.c"
}Results: {
"Output": "net/wireless/nl80211.c=7614=static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-7622-\nnet/wireless/nl80211.c:7623:static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {\nnet/wireless/nl80211.c:7624:\t[NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },\nnet/wireless/nl80211.c:7625:\t[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },\nnet/wireless/nl80211.c:7626:\t[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },\nnet/wireless/nl80211.c:7627:\t[NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },\nnet/wireless/nl80211.c:7628:\t[NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG },\nnet/wireless/nl80211.c:7629:\t[NL80211_STA_FLAG_TDLS_PEER] = { .type = NLA_FLAG },\nnet/wireless/nl80211.c-7630-};\n--\nnet/wireless/nl80211.c=7632=static int parse_station_flags(struct genl_info *info,\n--\nnet/wireless/nl80211.c-7635-{\nnet/wireless/nl80211.c:7636:\tstruct nlattr *flags[NL80211_STA_FLAG_MAX + 1];\nnet/wireless/nl80211.c-7637-\tstruct nlattr *nla;\n--\nnet/wireless/nl80211.c-7652-\t\tif ((params-\u003esta_flags_mask |\nnet/wireless/nl80211.c:7653:\t\t params-\u003esta_flags_set) \u0026 BIT(__NL80211_STA_FLAG_INVALID))\nnet/wireless/nl80211.c-7654-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-7658-\t\t params-\u003esta_flags_mask \u0026\nnet/wireless/nl80211.c:7659:\t\t ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |\nnet/wireless/nl80211.c:7660:\t\t BIT(NL80211_STA_FLAG_ASSOCIATED) |\nnet/wireless/nl80211.c:7661:\t\t BIT(NL80211_STA_FLAG_AUTHORIZED) |\nnet/wireless/nl80211.c:7662:\t\t BIT(NL80211_STA_FLAG_MFP)))\nnet/wireless/nl80211.c-7663-\t\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-7667-\t\t\t/* but don't let userspace control it */\nnet/wireless/nl80211.c:7668:\t\t\tif (params-\u003esta_flags_mask \u0026 BIT(NL80211_STA_FLAG_WME))\nnet/wireless/nl80211.c-7669-\t\t\t\treturn -EINVAL;\nnet/wireless/nl80211.c-7670-\nnet/wireless/nl80211.c:7671:\t\t\tparams-\u003esta_flags_mask |= BIT(NL80211_STA_FLAG_WME);\nnet/wireless/nl80211.c:7672:\t\t\tparams-\u003esta_flags_set |= BIT(NL80211_STA_FLAG_WME);\nnet/wireless/nl80211.c-7673-\t\t}\n--\nnet/wireless/nl80211.c-7683-\nnet/wireless/nl80211.c:7684:\tif (nla_parse_nested_deprecated(flags, NL80211_STA_FLAG_MAX, nla, sta_flags_policy, info-\u003eextack))\nnet/wireless/nl80211.c-7685-\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-7696-\tcase NL80211_IFTYPE_P2P_GO:\nnet/wireless/nl80211.c:7697:\t\tparams-\u003esta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |\nnet/wireless/nl80211.c:7698:\t\t\t\t\t BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |\nnet/wireless/nl80211.c:7699:\t\t\t\t\t BIT(NL80211_STA_FLAG_WME) |\nnet/wireless/nl80211.c:7700:\t\t\t\t\t BIT(NL80211_STA_FLAG_MFP);\nnet/wireless/nl80211.c-7701-\t\tbreak;\n--\nnet/wireless/nl80211.c-7703-\tcase NL80211_IFTYPE_STATION:\nnet/wireless/nl80211.c:7704:\t\tparams-\u003esta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |\nnet/wireless/nl80211.c:7705:\t\t\t\t\t BIT(NL80211_STA_FLAG_TDLS_PEER);\nnet/wireless/nl80211.c-7706-\t\tbreak;\nnet/wireless/nl80211.c-7707-\tcase NL80211_IFTYPE_MESH_POINT:\nnet/wireless/nl80211.c:7708:\t\tparams-\u003esta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |\nnet/wireless/nl80211.c:7709:\t\t\t\t\t BIT(NL80211_STA_FLAG_MFP) |\nnet/wireless/nl80211.c:7710:\t\t\t\t\t BIT(NL80211_STA_FLAG_AUTHORIZED);\nnet/wireless/nl80211.c-7711-\t\tbreak;\n--\nnet/wireless/nl80211.c-7715-\nnet/wireless/nl80211.c:7716:\tfor (flag = 1; flag \u003c= NL80211_STA_FLAG_MAX; flag++) {\nnet/wireless/nl80211.c-7717-\t\tif (flags[flag]) {\n--\nnet/wireless/nl80211.c-7720-\t\t\t/* no longer support new API additions in old API */\nnet/wireless/nl80211.c:7721:\t\t\tif (flag \u003e NL80211_STA_FLAG_MAX_OLD_API)\nnet/wireless/nl80211.c-7722-\t\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c=8823=int cfg80211_check_station_change(struct wiphy *wiphy,\n--\nnet/wireless/nl80211.c-8835-\tif (params-\u003eaid \u0026\u0026\nnet/wireless/nl80211.c:8836:\t !(params-\u003esta_flags_set \u0026 BIT(NL80211_STA_FLAG_TDLS_PEER)) \u0026\u0026\nnet/wireless/nl80211.c-8837-\t statype != CFG80211_STA_AP_CLIENT_UNASSOC)\n--\nnet/wireless/nl80211.c-8840-\t/* When you run into this, adjust the code below for the new flag */\nnet/wireless/nl80211.c:8841:\tBUILD_BUG_ON(NL80211_STA_FLAG_MAX != 9);\nnet/wireless/nl80211.c-8842-\n--\nnet/wireless/nl80211.c-8851-\t\tif (params-\u003esta_flags_mask \u0026\nnet/wireless/nl80211.c:8852:\t\t\t\t~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |\nnet/wireless/nl80211.c:8853:\t\t\t\t BIT(NL80211_STA_FLAG_MFP) |\nnet/wireless/nl80211.c:8854:\t\t\t\t BIT(NL80211_STA_FLAG_AUTHORIZED)))\nnet/wireless/nl80211.c-8855-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-8858-\tcase CFG80211_STA_TDLS_PEER_ACTIVE:\nnet/wireless/nl80211.c:8859:\t\tif (!(params-\u003esta_flags_set \u0026 BIT(NL80211_STA_FLAG_TDLS_PEER)))\nnet/wireless/nl80211.c-8860-\t\t\treturn -EINVAL;\nnet/wireless/nl80211.c-8861-\t\t/* ignore since it can't change */\nnet/wireless/nl80211.c:8862:\t\tparams-\u003esta_flags_mask \u0026= ~BIT(NL80211_STA_FLAG_TDLS_PEER);\nnet/wireless/nl80211.c-8863-\t\tbreak;\n--\nnet/wireless/nl80211.c-8876-\t\t/* TDLS can't be set, ... */\nnet/wireless/nl80211.c:8877:\t\tif (params-\u003esta_flags_set \u0026 BIT(NL80211_STA_FLAG_TDLS_PEER))\nnet/wireless/nl80211.c-8878-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-8883-\t\t */\nnet/wireless/nl80211.c:8884:\t\tparams-\u003esta_flags_mask \u0026= ~BIT(NL80211_STA_FLAG_TDLS_PEER);\nnet/wireless/nl80211.c-8885-\t}\n--\nnet/wireless/nl80211.c-8903-\t\t\treturn -EINVAL;\nnet/wireless/nl80211.c:8904:\t\tif (params-\u003esta_flags_mask \u0026 BIT(NL80211_STA_FLAG_SPP_AMSDU))\nnet/wireless/nl80211.c-8905-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-8921-\t\t/* Use this only for authorizing/unauthorizing a station */\nnet/wireless/nl80211.c:8922:\t\tif (!(params-\u003esta_flags_mask \u0026 BIT(NL80211_STA_FLAG_AUTHORIZED)))\nnet/wireless/nl80211.c-8923-\t\t\treturn -EOPNOTSUPP;\n--\nnet/wireless/nl80211.c-8928-\t\tif (params-\u003esta_flags_mask \u0026\nnet/wireless/nl80211.c:8929:\t\t\t\t~(BIT(NL80211_STA_FLAG_AUTHORIZED) |\nnet/wireless/nl80211.c:8930:\t\t\t\t BIT(NL80211_STA_FLAG_AUTHENTICATED) |\nnet/wireless/nl80211.c:8931:\t\t\t\t BIT(NL80211_STA_FLAG_ASSOCIATED) |\nnet/wireless/nl80211.c:8932:\t\t\t\t BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |\nnet/wireless/nl80211.c:8933:\t\t\t\t BIT(NL80211_STA_FLAG_WME) |\nnet/wireless/nl80211.c:8934:\t\t\t\t BIT(NL80211_STA_FLAG_MFP) |\nnet/wireless/nl80211.c:8935:\t\t\t\t BIT(NL80211_STA_FLAG_SPP_AMSDU) |\nnet/wireless/nl80211.c:8936:\t\t\t\t BIT(NL80211_STA_FLAG_CIP)))\nnet/wireless/nl80211.c-8937-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-8941-\t\t params-\u003esta_flags_mask \u0026\nnet/wireless/nl80211.c:8942:\t\t\t\t(BIT(NL80211_STA_FLAG_AUTHENTICATED) |\nnet/wireless/nl80211.c:8943:\t\t\t\t BIT(NL80211_STA_FLAG_ASSOCIATED)))\nnet/wireless/nl80211.c-8944-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-8948-\t\t/* reject any changes other than AUTHORIZED */\nnet/wireless/nl80211.c:8949:\t\tif (params-\u003esta_flags_mask \u0026 ~BIT(NL80211_STA_FLAG_AUTHORIZED))\nnet/wireless/nl80211.c-8950-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-8953-\t\t/* reject any changes other than AUTHORIZED or WME */\nnet/wireless/nl80211.c:8954:\t\tif (params-\u003esta_flags_mask \u0026 ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |\nnet/wireless/nl80211.c:8955:\t\t\t\t\t BIT(NL80211_STA_FLAG_WME)))\nnet/wireless/nl80211.c-8956-\t\t\treturn -EINVAL;\nnet/wireless/nl80211.c-8957-\t\t/* force (at least) rates when authorizing */\nnet/wireless/nl80211.c:8958:\t\tif (params-\u003esta_flags_set \u0026 BIT(NL80211_STA_FLAG_AUTHORIZED) \u0026\u0026\nnet/wireless/nl80211.c-8959-\t\t !params-\u003elink_sta_params.supported_rates)\n--\nnet/wireless/nl80211.c-8975-\t\tif (params-\u003esta_flags_mask \u0026\nnet/wireless/nl80211.c:8976:\t\t ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |\nnet/wireless/nl80211.c:8977:\t\t BIT(NL80211_STA_FLAG_MFP)))\nnet/wireless/nl80211.c-8978-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-8981-\t\tif (params-\u003esta_flags_mask \u0026\nnet/wireless/nl80211.c:8982:\t\t ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |\nnet/wireless/nl80211.c:8983:\t\t BIT(NL80211_STA_FLAG_MFP) |\nnet/wireless/nl80211.c:8984:\t\t BIT(NL80211_STA_FLAG_WME)))\nnet/wireless/nl80211.c-8985-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c=9190=static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-9312-\nnet/wireless/nl80211.c:9313:\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_CIP) \u0026\u0026\nnet/wireless/nl80211.c:9314:\t params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_CIP)) {\nnet/wireless/nl80211.c-9315-\t\tif (!cfg80211_cigtk_supported(wdev, info))\n--\nnet/wireless/nl80211.c=9378=static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-9385-\tu8 *mac_addr = NULL;\nnet/wireless/nl80211.c:9386:\tu32 auth_assoc = BIT(NL80211_STA_FLAG_AUTHENTICATED) |\nnet/wireless/nl80211.c:9387:\t\t\t BIT(NL80211_STA_FLAG_ASSOCIATED);\nnet/wireless/nl80211.c-9388-\n--\nnet/wireless/nl80211.c-9527-\nnet/wireless/nl80211.c:9528:\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_CIP) \u0026\u0026\nnet/wireless/nl80211.c:9529:\t params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_CIP)) {\nnet/wireless/nl80211.c-9530-\t\tif (!cfg80211_cigtk_supported(wdev, info))\n--\nnet/wireless/nl80211.c-9592-\t */\nnet/wireless/nl80211.c:9593:\tif (!(params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_WME))) {\nnet/wireless/nl80211.c-9594-\t\tparams.link_sta_params.ht_capa = NULL;\n--\nnet/wireless/nl80211.c-9609-\t\t/* NAN NMI station must be added in associated or authorized state */\nnet/wireless/nl80211.c:9610:\t\tif (!(params.sta_flags_set \u0026 (BIT(NL80211_STA_FLAG_ASSOCIATED) |\nnet/wireless/nl80211.c:9611:\t\t\t\t\t BIT(NL80211_STA_FLAG_AUTHENTICATED))))\nnet/wireless/nl80211.c-9612-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-9620-\t/* When you run into this, adjust the code below for the new flag */\nnet/wireless/nl80211.c:9621:\tBUILD_BUG_ON(NL80211_STA_FLAG_MAX != 9);\nnet/wireless/nl80211.c-9622-\n--\nnet/wireless/nl80211.c-9628-\t\tif (!(rdev-\u003ewiphy.flags \u0026 WIPHY_FLAG_AP_UAPSD) ||\nnet/wireless/nl80211.c:9629:\t\t !(params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_WME)))\nnet/wireless/nl80211.c-9630-\t\t\tparams.sta_modify_mask \u0026= ~STATION_PARAM_APPLY_UAPSD;\n--\nnet/wireless/nl80211.c-9632-\t\t/* TDLS peers cannot be added */\nnet/wireless/nl80211.c:9633:\t\tif ((params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_TDLS_PEER)) ||\nnet/wireless/nl80211.c-9634-\t\t info-\u003eattrs[NL80211_ATTR_PEER_AID])\n--\nnet/wireless/nl80211.c-9636-\t\t/* but don't bother the driver with it */\nnet/wireless/nl80211.c:9637:\t\tparams.sta_flags_mask \u0026= ~BIT(NL80211_STA_FLAG_TDLS_PEER);\nnet/wireless/nl80211.c-9638-\n--\nnet/wireless/nl80211.c-9646-\t\t\t\t\t NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT) \u0026\u0026\nnet/wireless/nl80211.c:9647:\t\t params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_SPP_AMSDU))\nnet/wireless/nl80211.c-9648-\t\t\treturn -EINVAL;\nnet/wireless/nl80211.c-9649-\nnet/wireless/nl80211.c:9650:\t\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_CIP) \u0026\u0026\nnet/wireless/nl80211.c-9651-\t\t !cfg80211_cigtk_supported(wdev, info))\n--\nnet/wireless/nl80211.c-9678-\t\t/* associated is disallowed */\nnet/wireless/nl80211.c:9679:\t\tif (params.sta_flags_mask \u0026 BIT(NL80211_STA_FLAG_ASSOCIATED))\nnet/wireless/nl80211.c-9680-\t\t\treturn -EINVAL;\nnet/wireless/nl80211.c-9681-\t\t/* TDLS peers cannot be added */\nnet/wireless/nl80211.c:9682:\t\tif ((params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_TDLS_PEER)) ||\nnet/wireless/nl80211.c-9683-\t\t info-\u003eattrs[NL80211_ATTR_PEER_AID])\n--\nnet/wireless/nl80211.c-9692-\t\tif (params.sta_flags_mask \u0026\nnet/wireless/nl80211.c:9693:\t\t\t\t(BIT(NL80211_STA_FLAG_ASSOCIATED) |\nnet/wireless/nl80211.c:9694:\t\t\t\t BIT(NL80211_STA_FLAG_AUTHENTICATED)))\nnet/wireless/nl80211.c-9695-\t\t\treturn -EINVAL;\nnet/wireless/nl80211.c-9696-\t\t/* Only TDLS peers can be added */\nnet/wireless/nl80211.c:9697:\t\tif (!(params.sta_flags_set \u0026 BIT(NL80211_STA_FLAG_TDLS_PEER)))\nnet/wireless/nl80211.c-9698-\t\t\treturn -EINVAL;\n--\nnet/wireless/nl80211.c-9708-\t\t */\nnet/wireless/nl80211.c:9709:\t\tparams.sta_flags_mask \u0026= ~BIT(NL80211_STA_FLAG_AUTHORIZED);\nnet/wireless/nl80211.c-9710-\t\tbreak;\n"
} |
| 41/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 54310 output: 38 thoughts: 91 Thoughts: Here's my thought process, as it stands: **Examining Station Flag Transmission** Okay, so I'm noticing that `NL80211_STA_FLAG_CIP` isn't being added to `sta_flags_policy`. My immediate reaction is to double-check where and how station flags are actually communicated to userspace. I need to refresh my memory on the data flow. Right, let me look into how `nl80211_send_station` functions, or, at a broader level, how station flags get transmitted in general. I need to be sure the lack of this specific flag is intentional, and not an oversight. I'll focus my search on areas dealing with station information attributes. Specifically, I should be looking for any uses or mentions of `NL80211_ATTR_STA_INFO` and the related flag attribute `NL80211_STA_INFO_STA_FLAGS`. That should give me the context I need to assess this missing flag. |
| 42/3 | 2026/09/23 10:51 | tool | grepper |
0mArgs:{
"Expression": "NL80211_STA_INFO_STA_FLAGS",
"PathPrefix": "net/wireless/"
}Results: {
"Output": "net/wireless/nl80211.c=8078=static int nl80211_put_sta_info_common(struct sk_buff *msg,\n--\nnet/wireless/nl80211.c-8194-\t}\nnet/wireless/nl80211.c:8195:\tif ((sinfo-\u003efilled \u0026 BIT_ULL(NL80211_STA_INFO_STA_FLAGS)) \u0026\u0026\nnet/wireless/nl80211.c:8196:\t nla_put(msg, NL80211_STA_INFO_STA_FLAGS,\nnet/wireless/nl80211.c-8197-\t\t sizeof(struct nl80211_sta_flag_update),\n"
} |
| 43/3 | 2026/09/23 10:51 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 54861 output: 41 thoughts: 28 Thoughts: Okay, let's dive into this. Here's my thought process summarized, assuming I'm already pretty familiar with wireless networking internals and the kernel: **Examining `nl80211_put_sta_info_common`** Right, let's take a look at `nl80211_put_sta_info_common`. I'm going to focus around line 8195. That's a reasonable place to start, as it's likely involved in constructing or manipulating the station information that gets passed through the nl80211 interface. I'm assuming that it's related to some sort of query or event regarding station status. I'll be looking for things like: * How it's populating the attributes, specifically any common or base information. * Whether it's handling errors and edge cases. * How it interacts with other functions, and what data structures are being used (like `cfg80211_inform_sta` etc.) * Anything that might seem inefficient or that could cause issues with performance, especially if it's within a loop or called frequently. * The overall goal of this function: what information is it trying to relay? * Any dependencies it has on other parts of the wireless stack. * How it interacts with the regulatory domain information. Basically, I'm expecting this to be a core function for reporting station details and I'll need to understand how it's assembling the data structure to make sure everything is being handled and presented correctly. My expectation is that this should be a reliable, efficient method and the line referenced is probably some part of that process. |
| 44/3 | 2026/09/23 10:52 | tool | read-file |
0mArgs:{
"File": "net/wireless/nl80211.c",
"FirstLine": 8190,
"LineCount": 20
}Results: {
"Contents": "8190:\t\t\t\t\tsinfo-\u003ebss_param.beacon_interval))\n8191:\t\t\t\tgoto nla_put_failure;\n8192:\t\n8193:\t\t\tnla_nest_end(msg, bss_param);\n8194:\t\t}\n8195:\t\tif ((sinfo-\u003efilled \u0026 BIT_ULL(NL80211_STA_INFO_STA_FLAGS)) \u0026\u0026\n8196:\t\t nla_put(msg, NL80211_STA_INFO_STA_FLAGS,\n8197:\t\t\t sizeof(struct nl80211_sta_flag_update),\n8198:\t\t\t \u0026sinfo-\u003esta_flags))\n8199:\t\t\tgoto nla_put_failure;\n8200:\t\n8201:\t\tPUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);\n8202:\t\tPUT_SINFO_U64(BEACON_RX, rx_beacon);\n8203:\t\tPUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);\n8204:\t\tPUT_SINFO(RX_MPDUS, rx_mpdu_count, u32);\n8205:\t\tPUT_SINFO(FCS_ERROR_COUNT, fcs_err_count, u32);\n8206:\t\tif (wiphy_ext_feature_isset(\u0026rdev-\u003ewiphy,\n8207:\t\t\t\t\t NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT)) {\n8208:\t\t\tPUT_SINFO(ACK_SIGNAL, ack_signal, u8);\n8209:\t\t\tPUT_SINFO(ACK_SIGNAL_AVG, avg_ack_signal, s8);\n"
} |
| 45/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 55744 output: 28 thoughts: 84 Thoughts: Here's my thought process, as it stands: **Debugging the CIP Flag in Station Information** Okay, so I'm looking at `sinfo->sta_flags`, which is a `struct nl80211_sta_flag_update`. Right, I need to figure out where the `sta_flags` field is populated. The goal is to determine if `NL80211_STA_FLAG_CIP` is being set correctly, or even set at all, within that structure. To do that, the logical next step is to trace back the assignments. So, I need to search the codebase to see where `NL80211_STA_INFO_STA_FLAGS` is used to understand how and when the flag gets set. Let me get to it and start that grep immediately. |
| 46/3 | 2026/09/23 10:52 | tool | grepper |
0mArgs:{
"Expression": "NL80211_STA_INFO_STA_FLAGS"
}Results: {
"Output": "drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c=3074=static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si)\n--\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-3078-\tbrcmf_dbg(TRACE, \"flags %08x\\n\", fw_sta_flags);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:3079:\tsi-\u003efilled |= BIT_ULL(NL80211_STA_INFO_STA_FLAGS);\ndrivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c-3080-\tsfu = \u0026si-\u003esta_flags;\n--\ndrivers/net/wireless/quantenna/qtnfmac/commands.c=579=qtnf_cmd_sta_info_parse(struct station_info *sinfo, const u8 *data,\n--\ndrivers/net/wireless/quantenna/qtnfmac/commands.c-649-\tif (qtnf_sta_stat_avail(sta_flags, QLINK_STA_INFO_STA_FLAGS)) {\ndrivers/net/wireless/quantenna/qtnfmac/commands.c:650:\t\tsinfo-\u003efilled |= BIT_ULL(NL80211_STA_INFO_STA_FLAGS);\ndrivers/net/wireless/quantenna/qtnfmac/commands.c-651-\t\tqtnf_sta_info_parse_flags(\u0026sinfo-\u003esta_flags, \u0026stats-\u003esta_flags);\n--\ninclude/uapi/linux/nl80211.h=4230=enum nl80211_sta_bss_param {\n--\ninclude/uapi/linux/nl80211.h-4278- * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected\ninclude/uapi/linux/nl80211.h:4279: * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.\ninclude/uapi/linux/nl80211.h-4280- * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)\n--\ninclude/uapi/linux/nl80211.h=4326=enum nl80211_sta_info {\n--\ninclude/uapi/linux/nl80211.h-4343-\tNL80211_STA_INFO_CONNECTED_TIME,\ninclude/uapi/linux/nl80211.h:4344:\tNL80211_STA_INFO_STA_FLAGS,\ninclude/uapi/linux/nl80211.h-4345-\tNL80211_STA_INFO_BEACON_LOSS,\n--\nnet/mac80211/sta_info.c=3079=void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,\n--\nnet/mac80211/sta_info.c-3100-\tsinfo-\u003efilled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) |\nnet/mac80211/sta_info.c:3101:\t\t\t BIT_ULL(NL80211_STA_INFO_STA_FLAGS) |\nnet/mac80211/sta_info.c-3102-\t\t\t BIT_ULL(NL80211_STA_INFO_BSS_PARAM) |\n--\nnet/wireless/nl80211.c=8078=static int nl80211_put_sta_info_common(struct sk_buff *msg,\n--\nnet/wireless/nl80211.c-8194-\t}\nnet/wireless/nl80211.c:8195:\tif ((sinfo-\u003efilled \u0026 BIT_ULL(NL80211_STA_INFO_STA_FLAGS)) \u0026\u0026\nnet/wireless/nl80211.c:8196:\t nla_put(msg, NL80211_STA_INFO_STA_FLAGS,\nnet/wireless/nl80211.c-8197-\t\t sizeof(struct nl80211_sta_flag_update),\n"
} |
| 47/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 57205 output: 43 thoughts: 29 Thoughts: Okay, let's dive into this. Here's my summary, taking the first-person perspective as requested: **Diving into `sta_set_sinfo`** Alright, I need to understand this specific function, `sta_set_sinfo`, so I'm heading directly to its source. It's in the `net/mac80211/sta_info.c` file. This tells me we're dealing with station information within the mac80211 subsystem – that's the core of the 802.11 wireless stack in the Linux kernel. Given the naming convention, I'm expecting this function to be responsible for setting or updating station-specific information. I’ll need to understand what this “sinfo” actually entails. Is it related to signal strength, data rates, supported capabilities, or something else entirely? A quick code inspection will hopefully clarify its exact role and what parameters it takes. I'm guessing it’s critical for per-station management within the MAC layer. I'm going to look for how this function interacts with the other data structures involved, such as the `ieee80211_sta` structure and any related locks. This is where the real complexity and potential for subtle concurrency issues often reside. Let's get started. |
| 48/3 | 2026/09/23 10:52 | tool | read-file |
0mArgs:{
"File": "net/mac80211/sta_info.c",
"FirstLine": 3100,
"LineCount": 40
}Results: {
"Contents": "3100:\t\tsinfo-\u003efilled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) |\n3101:\t\t\t\t BIT_ULL(NL80211_STA_INFO_STA_FLAGS) |\n3102:\t\t\t\t BIT_ULL(NL80211_STA_INFO_BSS_PARAM) |\n3103:\t\t\t\t BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME) |\n3104:\t\t\t\t BIT_ULL(NL80211_STA_INFO_ASSOC_AT_BOOTTIME) |\n3105:\t\t\t\t BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC);\n3106:\t\n3107:\t\tif (sdata-\u003evif.type == NL80211_IFTYPE_STATION) {\n3108:\t\t\tsinfo-\u003ebeacon_loss_count =\n3109:\t\t\t\tsdata-\u003edeflink.u.mgd.beacon_loss_count;\n3110:\t\t\tsinfo-\u003efilled |= BIT_ULL(NL80211_STA_INFO_BEACON_LOSS);\n3111:\t\t}\n3112:\t\n3113:\t\tsinfo-\u003econnected_time = ktime_get_seconds() - sta-\u003elast_connected;\n3114:\t\tsinfo-\u003eassoc_at = sta-\u003eassoc_at;\n3115:\t\tsinfo-\u003einactive_time =\n3116:\t\t\tjiffies_delta_to_msecs(jiffies -\n3117:\t\t\t\t\t ieee80211_sta_last_active(sta, -1));\n3118:\t\n3119:\t\tif (!(sinfo-\u003efilled \u0026 (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |\n3120:\t\t\t\t BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) {\n3121:\t\t\tsinfo-\u003etx_bytes = 0;\n3122:\t\t\tfor (ac = 0; ac \u003c IEEE80211_NUM_ACS; ac++)\n3123:\t\t\t\tsinfo-\u003etx_bytes += sta-\u003edeflink.tx_stats.bytes[ac];\n3124:\t\t\tsinfo-\u003efilled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);\n3125:\t\t}\n3126:\t\n3127:\t\tif (!(sinfo-\u003efilled \u0026 BIT_ULL(NL80211_STA_INFO_TX_PACKETS))) {\n3128:\t\t\tsinfo-\u003etx_packets = 0;\n3129:\t\t\tfor (ac = 0; ac \u003c IEEE80211_NUM_ACS; ac++)\n3130:\t\t\t\tsinfo-\u003etx_packets += sta-\u003edeflink.tx_stats.packets[ac];\n3131:\t\t\tsinfo-\u003efilled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);\n3132:\t\t}\n3133:\t\n3134:\t\tif (!(sinfo-\u003efilled \u0026 (BIT_ULL(NL80211_STA_INFO_RX_BYTES64) |\n3135:\t\t\t\t BIT_ULL(NL80211_STA_INFO_RX_BYTES)))) {\n3136:\t\t\tsinfo-\u003erx_bytes += sta_get_stats_bytes(\u0026sta-\u003edeflink.rx_stats);\n3137:\t\n3138:\t\t\tif (sta-\u003edeflink.pcpu_rx_stats) {\n3139:\t\t\t\tfor_each_possible_cpu(cpu) {\n"
} |
| 49/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 58472 output: 37 thoughts: 36 Thoughts: Okay, let's dive into this. Here's how I'd approach this task, as if these were my internal thoughts: **Tracing the Source of `sinfo->sta_flags`** Alright, the objective is to understand the origin and population of `sinfo->sta_flags`. A good starting point is the function mentioned, `sta_set_sinfo`. That's where the information should be set. Now, I'll need to locate the definition of that function, and I suspect it will be in `sta_info.c`. That's the most logical place given the file naming and what I know of the codebase. I will go there. |
| 50/3 | 2026/09/23 10:52 | tool | grepper |
0mArgs:{
"Expression": "sta_flags",
"PathPrefix": "net/mac80211/sta_info.c"
}Results: {
"Output": "net/mac80211/sta_info.c=3079=void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,\n--\nnet/mac80211/sta_info.c-3279-\nnet/mac80211/sta_info.c:3280:\tsinfo-\u003esta_flags.set = 0;\nnet/mac80211/sta_info.c:3281:\tsinfo-\u003esta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |\nnet/mac80211/sta_info.c-3282-\t\t\t\tBIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |\n--\nnet/mac80211/sta_info.c-3288-\tif (test_sta_flag(sta, WLAN_STA_AUTHORIZED))\nnet/mac80211/sta_info.c:3289:\t\tsinfo-\u003esta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);\nnet/mac80211/sta_info.c-3290-\tif (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))\nnet/mac80211/sta_info.c:3291:\t\tsinfo-\u003esta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);\nnet/mac80211/sta_info.c-3292-\tif (sta-\u003esta.wme)\nnet/mac80211/sta_info.c:3293:\t\tsinfo-\u003esta_flags.set |= BIT(NL80211_STA_FLAG_WME);\nnet/mac80211/sta_info.c-3294-\tif (test_sta_flag(sta, WLAN_STA_MFP))\nnet/mac80211/sta_info.c:3295:\t\tsinfo-\u003esta_flags.set |= BIT(NL80211_STA_FLAG_MFP);\nnet/mac80211/sta_info.c-3296-\tif (test_sta_flag(sta, WLAN_STA_AUTH))\nnet/mac80211/sta_info.c:3297:\t\tsinfo-\u003esta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);\nnet/mac80211/sta_info.c-3298-\tif (test_sta_flag(sta, WLAN_STA_ASSOC))\nnet/mac80211/sta_info.c:3299:\t\tsinfo-\u003esta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);\nnet/mac80211/sta_info.c-3300-\tif (test_sta_flag(sta, WLAN_STA_TDLS_PEER))\nnet/mac80211/sta_info.c:3301:\t\tsinfo-\u003esta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);\nnet/mac80211/sta_info.c-3302-\n"
} |
| 51/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 59517 output: 40 thoughts: 320 Thoughts: **Debugging Key Configuration in mac80211** Okay, so `sinfo->sta_flags` is definitely initialized correctly, with `.set = 0` and the bitmask all set up. Now, I need to focus on these debugfs changes. I see the additions: `KEY_CONF_FILE_NAMED(conf_flags, flags, X)` and `KEY_CONF_FILE(link_id, D)`. My immediate concern is whether `key->conf.flags` or `key->conf.link_id` are uninitialized when `ieee80211_debugfs_key_add(key)` gets called. That's the critical question here. To answer that, I need to trace back how `key` is allocated and initialized. Let's start with `ieee80211_key_alloc`. I need to understand the lifecycle of that `struct ieee80211_key` to determine if there's a potential initialization gap. I'll need to follow the allocation and any subsequent initialization to see what's happening to those new fields added for debugfs. |
| 52/3 | 2026/09/23 10:52 | tool | grepper |
0mArgs:{
"Expression": "ieee80211_key_alloc",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/cfg.c=613=static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,\n--\nnet/mac80211/cfg.c-655-\nnet/mac80211/cfg.c:656:\tkey = ieee80211_key_alloc(params-\u003ecipher, key_idx, params-\u003ekey_len,\nnet/mac80211/cfg.c-657-\t\t\t\t params-\u003ekey, params-\u003eseq_len, params-\u003eseq);\n--\nnet/mac80211/key.c=605=struct ieee80211_key *\nnet/mac80211/key.c:606:ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,\nnet/mac80211/key.c-607-\t\t const u8 *key_data,\n--\nnet/mac80211/key.c=1404=ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,\n--\nnet/mac80211/key.c-1464-\nnet/mac80211/key.c:1465:\tkey = ieee80211_key_alloc(prev_key-\u003econf.cipher, idx,\nnet/mac80211/key.c-1466-\t\t\t\t prev_key-\u003econf.keylen, key_data,\n--\nnet/mac80211/key.h=141=struct ieee80211_key *\nnet/mac80211/key.h:142:ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,\nnet/mac80211/key.h-143-\t\t const u8 *key_data,\n"
} |
| 53/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 60642 output: 40 thoughts: 32 Thoughts: Here's my analysis of the provided text, rendered in the first person, assuming an expert user: **Diving into the 802.11 Key Allocation** Okay, let's get down to brass tacks. I need to refresh my memory, or perhaps just verify a hunch, about how key allocation is handled within the mac80211 framework. Specifically, I'm going to head directly into the `ieee80211_key_alloc` function. I remember it being in `net/mac80211/key.c`, and that's where I'll begin my investigation. Time to dissect this key allocation process. I'm keen to understand the finer points of its implementation. |
| 54/3 | 2026/09/23 10:52 | tool | read-file |
0mArgs:{
"File": "net/mac80211/key.c",
"FirstLine": 605,
"LineCount": 40
}Results: {
"Contents": " 605:\tstruct ieee80211_key *\n 606:\tieee80211_key_alloc(u32 cipher, int idx, size_t key_len,\n 607:\t\t\t const u8 *key_data,\n 608:\t\t\t size_t seq_len, const u8 *seq)\n 609:\t{\n 610:\t\tstruct ieee80211_key *key;\n 611:\t\tint i, j, err;\n 612:\t\n 613:\t\tif (WARN_ON(idx \u003c 0 ||\n 614:\t\t\t idx \u003e= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +\n 615:\t\t\t NUM_DEFAULT_BEACON_KEYS))\n 616:\t\t\treturn ERR_PTR(-EINVAL);\n 617:\t\n 618:\t\tkey = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);\n 619:\t\tif (!key)\n 620:\t\t\treturn ERR_PTR(-ENOMEM);\n 621:\t\n 622:\t\t/*\n 623:\t\t * Default to software encryption; we'll later upload the\n 624:\t\t * key to the hardware if possible.\n 625:\t\t */\n 626:\t\tkey-\u003econf.flags = 0;\n 627:\t\tkey-\u003eflags = 0;\n 628:\t\n 629:\t\tkey-\u003econf.link_id = -1;\n 630:\t\tkey-\u003econf.cipher = cipher;\n 631:\t\tkey-\u003econf.keyidx = idx;\n 632:\t\tkey-\u003econf.keylen = key_len;\n 633:\t\tswitch (cipher) {\n 634:\t\tcase WLAN_CIPHER_SUITE_WEP40:\n 635:\t\tcase WLAN_CIPHER_SUITE_WEP104:\n 636:\t\t\tkey-\u003econf.iv_len = IEEE80211_WEP_IV_LEN;\n 637:\t\t\tkey-\u003econf.icv_len = IEEE80211_WEP_ICV_LEN;\n 638:\t\t\tbreak;\n 639:\t\tcase WLAN_CIPHER_SUITE_TKIP:\n 640:\t\t\tkey-\u003econf.iv_len = IEEE80211_TKIP_IV_LEN;\n 641:\t\t\tkey-\u003econf.icv_len = IEEE80211_TKIP_ICV_LEN;\n 642:\t\t\tif (seq) {\n 643:\t\t\t\tfor (i = 0; i \u003c IEEE80211_NUM_TIDS; i++) {\n 644:\t\t\t\t\tkey-\u003eu.tkip.rx[i].iv32 =\n"
} |
| 55/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 61595 output: 32 thoughts: 1174 Thoughts: **Analyzing Key Indexing and Capability Information in mac80211** Okay, first things first, I'm initializing a key struct with `kzalloc`. Everything's zeroed, `link_id` is explicitly set to -1, and `flags` are set to 0. Standard stuff. But wait, hold on... line 613 of `ieee80211_key_alloc` is calling `WARN_ON` on the `idx`. It's checking if `idx` is within the bounds of a particular key table. The check is: `idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + NUM_DEFAULT_BEACON_KEYS`. Let's unpack that. `NUM_DEFAULT_KEYS` is 4, `NUM_DEFAULT_MGMT_KEYS` is 2, and `NUM_DEFAULT_BEACON_KEYS` is 2. So the upper bound is 8. Now, let's zoom in on CIGTK (Controlled Information Group Transient Key) handling. In `nl80211_parse_key`, it checks if the `idx` for CIGTK keys is within the range 0-1 (`k->idx < 0 || k->idx > 1`). That matches `NUM_CTRL_KEYS`, which is 2. So, we're dealing with `cigtk[0]` and `cigtk[1]`. But wait, when we *lookup* a key in `ieee80211_lookup_key`, there's a check for `cigtk && key_idx < NUM_CTRL_KEYS` in both the STA case and *non-STA* case (`link->cigtk[key_idx]`). The question now is, is that check also present for the *non-STA* case? Let's trace it down through `cfg80211_valid_key_idx`. It does a check there for `key_idx >= 2`, which is what's being done in `nl80211_parse_key`. If it's out of bounds, it returns false. The driver is checking twice (both `cfg80211_valid_key_idx` and `nl80211_parse_key`) so it should never access out of bounds arrays, but it doesn't hurt to be sure. Also, any out-of-bounds access is almost certainly going to trigger KASAN anyway. Okay, let's shift gears and look at how CIP (Controlled Information Protocol) capabilities are handled, specifically `ieee80211_put_cip_cap` in `net/mac80211/util.c`. This function is adding a 4-byte element (EID, len, extended EID, and capabilities) to an 802.11 management frame. The bytes are *explicitly* initialized, which is good. Finally, checking `parse.c`, when parsing incoming frames, the code extracts the CIP capabilities element using `elems->cip_cap = data;`. `elems` is a `struct ieee802_11_elems`, so now to check where that's being allocated and used, I should check the usages. |
| 56/3 | 2026/09/23 10:52 | tool | grepper |
0mArgs:{
"Expression": "cip_cap",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/cfg.c=2278=static int sta_link_apply_parameters(struct ieee80211_local *local,\n--\nnet/mac80211/cfg.c-2308-\t\t\treturn -EINVAL;\nnet/mac80211/cfg.c:2309:\t\tif (sta-\u003esta.cip \u0026\u0026 !params-\u003ecip_cap_set)\nnet/mac80211/cfg.c-2310-\t\t\treturn -EINVAL;\n--\nnet/mac80211/cfg.c-2432-\nnet/mac80211/cfg.c:2433:\tif (params-\u003ecip_cap_set)\nnet/mac80211/cfg.c:2434:\t\tlink_sta-\u003epub-\u003ecip_cap = params-\u003ecip_cap;\nnet/mac80211/cfg.c-2435-\n--\nnet/mac80211/ieee80211_i.h=1813=struct ieee802_11_elems {\n--\nnet/mac80211/ieee80211_i.h-1882-\tconst struct ieee80211_uhr_operation *uhr_operation;\nnet/mac80211/ieee80211_i.h:1883:\tconst struct ieee80211_cip_cap *cip_cap;\nnet/mac80211/ieee80211_i.h-1884-\n--\nnet/mac80211/ieee80211_i.h=2782=void ieee80211_put_reg_conn(struct ieee80211_sub_if_data *sdata,\nnet/mac80211/ieee80211_i.h-2783-\t\t\t struct sk_buff *skb);\nnet/mac80211/ieee80211_i.h:2784:int ieee80211_put_cip_cap(struct sk_buff *skb,\nnet/mac80211/ieee80211_i.h-2785-\t\t\t struct ieee80211_sub_if_data *sdata);\n--\nnet/mac80211/mlme.c=2152=ieee80211_add_link_elems(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/mlme.c-2341-\tif (link_id == assoc_data-\u003eassoc_link_id \u0026\u0026 assoc_data-\u003ecip)\nnet/mac80211/mlme.c:2342:\t\tieee80211_put_cip_cap(skb, sdata);\nnet/mac80211/mlme.c-2343-\n--\nnet/mac80211/mlme.c=5859=static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,\n--\nnet/mac80211/mlme.c-6282-\tif (assoc_data-\u003ecip) {\nnet/mac80211/mlme.c:6283:\t\tif (elems-\u003ecip_cap) {\nnet/mac80211/mlme.c:6284:\t\t\tlink_sta-\u003epub-\u003ecip_cap = elems-\u003ecip_cap-\u003ev;\nnet/mac80211/mlme.c-6285-\t\t} else {\n--\nnet/mac80211/parse.c=72=ieee80211_parse_extension_element(u32 *crc,\n--\nnet/mac80211/parse.c-208-\tcase WLAN_EID_EXT_CIP_CAPA:\nnet/mac80211/parse.c:209:\t\tif (len \u003e= sizeof(*elems-\u003ecip_cap))\nnet/mac80211/parse.c:210:\t\t\telems-\u003ecip_cap = data;\nnet/mac80211/parse.c-211-\t\tbreak;\n--\nnet/mac80211/util.c=4658=int ieee80211_put_uhr_cap(struct sk_buff *skb,\n--\nnet/mac80211/util.c-4682-\nnet/mac80211/util.c:4683:int ieee80211_put_cip_cap(struct sk_buff *skb,\nnet/mac80211/util.c-4684-\t\t\t struct ieee80211_sub_if_data *sdata)\n--\nnet/mac80211/util.c-4688-\t\t\t\t\t ieee80211_vif_type_p2p(\u0026sdata-\u003evif));\nnet/mac80211/util.c:4689:\tu8 cip_capabilities = ift_ext_capa ? ift_ext_capa-\u003ecip_capabilities : 0;\nnet/mac80211/util.c-4690-\n--\nnet/mac80211/util.c-4696-\tskb_put_u8(skb, WLAN_EID_EXT_CIP_CAPA);\nnet/mac80211/util.c:4697:\tskb_put_u8(skb, cip_capabilities);\nnet/mac80211/util.c-4698-\n"
} |
| 57/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 64979 output: 40 thoughts: 35 Thoughts: Okay, let's dive into this. Here's how I'd approach understanding the `elems` parsing process, based on those thoughts: **Analyzing Element Parsing in `parse.c`** Alright, my first step is to get right into the heart of the matter. I need to understand exactly how the `elems` data is handled. So, I'm going to jump straight into `parse.c` and zero in on the function that's likely doing the heavy lifting – `ieee80211_parse_elems`. That function's name strongly suggests it's the key to figuring out the parsing and allocation of that `elems` data. I'll need to see how it's structured to fully understand the process. |
| 58/3 | 2026/09/23 10:52 | tool | grepper |
0mError:no matches Args: {
"Expression": "ieee80211_parse_elems",
"PathPrefix": "net/mac80211/"
}Results: {
"error": "no matches"
} |
| 59/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 65228 output: 42 thoughts: 28 Thoughts: Okay, here's my summary, presented as a stream of thought: **Tracing the Caller of a Key Function** Alright, let's get down to it. I need to pinpoint where `ieee80211_parse_extension_element` is actually being called within `parse.c`. This is a critical function, no doubt parsing extension elements in the 802.11 frame, and understanding its usage is key to understanding the overall parsing logic. Time to fire up the tools and trace this one down. I'll start with the source code and then see if there is any other way I can approach this. A good understanding of where the function is called will make the code easier to follow. |
| 60/3 | 2026/09/23 10:52 | tool | grepper |
0mArgs:{
"Expression": "ieee80211_parse_extension_element",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/parse.c=71=static void\nnet/mac80211/parse.c:72:ieee80211_parse_extension_element(u32 *crc,\nnet/mac80211/parse.c-73-\t\t\t\t const struct element *elem,\n--\nnet/mac80211/parse.c=315=_ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,\n--\nnet/mac80211/parse.c-769-\t\tcase WLAN_EID_EXTENSION:\nnet/mac80211/parse.c:770:\t\t\tieee80211_parse_extension_element(calc_crc ?\nnet/mac80211/parse.c-771-\t\t\t\t\t\t\t\t\u0026crc : NULL,\n"
} |
| 61/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 65686 output: 42 thoughts: 2643 Thoughts: **Analyzing CIGTK Key Management in mac80211** Okay, let's break this down. My primary focus is on how CIGTK (Cipher-based Integrity Protection with Group Temporal Key) keys are handled within the mac80211 framework, specifically in relation to multi-link operation (MLO) or other multi-interface situations where the `link_id` plays a critical role. First, I see the basic structure: `_ieee802_11_parse_elems_full` parses elements and ensures that the data being read from the packet buffer is safe. This part seems straightforward, handling the initial parsing. Now, I'm diving deeper into the `nl80211_get_key` and `ieee80211_get_key` functions. I observe that the `key_idx` and `type` (specifically `NL80211_KEYTYPE_CIGTK`) determine how a key is looked up. Crucially, `cfg80211_valid_key_idx` is called *before* the key lookup, enforcing a check that the index is valid. In the case of CIGTK, it checks `key_idx < 2`. This confirms the constraint imposed by `NUM_CTRL_KEYS`. The core of the lookup happens in `ieee80211_lookup_key`. This function handles different key types and the presence of a MAC address. It looks up the key in the station's (`sta`) context, if one is provided. The `link_id` is significant here. If a link ID is specified, then the lookup attempts to retrieve a `link_sta` (the link-specific station data), indicating a multi-link context. In this context, CIGTK keys are accessed through `link_sta->cigtk[key_idx]`. When no MAC is passed, the lookup relies on `link->cigtk[key_idx]`. I'm zeroing in on this `link_sta->cigtk[key_idx]` access. Since `key_idx` can only be 0 or 1, and `cfg80211_valid_key_idx` is checked beforehand, there *shouldn't* be any out-of-bounds access. However, I want to ensure that this constraint is consistently upheld throughout the code, especially within `ieee80211_add_key`. It checks if it's CIGTK to sets the `IEEE80211_KEY_FLAG_CIP` flag. I then followed the execution path into `ieee80211_key_link`, which links the key to a station or a link. This function contains the actual assignment of the key pointers to their respective places (`link_sta->cigtk[idx]`) and a pointer dereference occurs, with old and new key pointers. I can see the potential for a race condition or a use-after-free situation if key management isn't carefully synchronized. `ieee80211_key_replace` manages replacing the key and, critically, uses `rcu_assign_pointer` to safely update pointers, which is good. It assigns to the `cigtk` array when it's CIGTK. Finally, I investigate `ieee80211_free_sta_keys`. This function frees the CIGTK keys associated with a station. The loop iterates through the `cigtk` array (`sta->deflink.cigtk`), which confirms that `key_idx` value is bounded by the array size (2 in this case). It replaces the key with `NULL` before destroying it which prevents use-after-free. So, summing up my assessment, I can see that the code explicitly checks the `key_idx` value, ensuring it stays within the valid range for CIGTK keys (0 or 1). There is an array of size 2, and the bounds are explicitly checked. The pointers are handled with RCU, to make sure it's safe. Therefore, the risk of an out-of-bounds write is low, as long as the validation in `cfg80211_valid_key_idx` is consistently enforced. However, I need to look closer at the interaction between concurrent operations on the `link_sta` data, particularly with MLO, to ensure no race conditions during key addition, deletion, and retrieval, and if those validation functions are correctly used across the kernel. |
| 62/3 | 2026/09/23 10:52 | tool | grepper |
0mArgs:{
"Expression": "ieee80211_free_sta_keys",
"PathPrefix": "net/mac80211/"
}Results: {
"Output": "net/mac80211/key.c=1168=void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,\n--\nnet/mac80211/key.c-1214-\nnet/mac80211/key.c:1215:void ieee80211_free_sta_keys(struct ieee80211_local *local,\nnet/mac80211/key.c-1216-\t\t\t struct sta_info *sta)\n--\nnet/mac80211/key.h=165=void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,\nnet/mac80211/key.h-166-\t\t\t bool force_synchronize);\nnet/mac80211/key.h:167:void ieee80211_free_sta_keys(struct ieee80211_local *local,\nnet/mac80211/key.h-168-\t\t\t struct sta_info *sta);\n--\nnet/mac80211/sta_info.c=1543=static void __sta_info_destroy_part2(struct sta_info *sta, bool recalc)\n--\nnet/mac80211/sta_info.c-1577-\t/* now keys can no longer be reached */\nnet/mac80211/sta_info.c:1578:\tieee80211_free_sta_keys(local, sta);\nnet/mac80211/sta_info.c-1579-\n"
} |
| 63/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 69799 output: 41 thoughts: 41 Thoughts: Okay, let's dive into this. I'm going to take a look at the `ieee80211_free_sta_keys` function. Specifically, I'm focusing on its implementation around line 1215 in `net/mac80211/key.c`. This is where the core logic for freeing station keys within the mac80211 framework is handled. I want to understand how it's implemented and how it integrates with the overall key management scheme. I'm interested in how it manages and releases resources associated with a particular station, and any potential implications for security, performance, or overall stability of the wireless link. My goal is to grasp the mechanics of key cleanup when a station disconnects or when keys are refreshed. Understanding the details of this function will clarify the delicate balance between key management, secure communications, and efficient use of resources. |
| 64/3 | 2026/09/23 10:52 | tool | read-file |
0mArgs:{
"File": "net/mac80211/key.c",
"FirstLine": 1210,
"LineCount": 45
}Results: {
"Contents": "1210:\t\t\t\tWARN_ON_ONCE(vlan-\u003ecrypto_tx_tailroom_needed_cnt ||\n1211:\t\t\t\t\t vlan-\u003ecrypto_tx_tailroom_pending_dec);\n1212:\t\t}\n1213:\t}\n1214:\t\n1215:\tvoid ieee80211_free_sta_keys(struct ieee80211_local *local,\n1216:\t\t\t\t struct sta_info *sta)\n1217:\t{\n1218:\t\tstruct ieee80211_key *key;\n1219:\t\tint i;\n1220:\t\n1221:\t\tlockdep_assert_wiphy(local-\u003ehw.wiphy);\n1222:\t\n1223:\t\tfor (i = 0; i \u003c ARRAY_SIZE(sta-\u003edeflink.gtk); i++) {\n1224:\t\t\tkey = wiphy_dereference(local-\u003ehw.wiphy, sta-\u003edeflink.gtk[i]);\n1225:\t\t\tif (!key)\n1226:\t\t\t\tcontinue;\n1227:\t\t\tieee80211_key_replace(key-\u003esdata, NULL, key-\u003esta,\n1228:\t\t\t\t\t key-\u003econf.flags, key, NULL);\n1229:\t\t\t__ieee80211_key_destroy(key, key-\u003esdata-\u003evif.type ==\n1230:\t\t\t\t\t\tNL80211_IFTYPE_STATION);\n1231:\t\t}\n1232:\t\n1233:\t\tfor (i = 0; i \u003c ARRAY_SIZE(sta-\u003edeflink.cigtk); i++) {\n1234:\t\t\tkey = wiphy_dereference(local-\u003ehw.wiphy, sta-\u003edeflink.cigtk[i]);\n1235:\t\t\tif (!key)\n1236:\t\t\t\tcontinue;\n1237:\t\t\tieee80211_key_replace(key-\u003esdata, NULL, key-\u003esta,\n1238:\t\t\t\t\t key-\u003econf.flags, key, NULL);\n1239:\t\t\t__ieee80211_key_destroy(key, key-\u003esdata-\u003evif.type ==\n1240:\t\t\t\t\t\tNL80211_IFTYPE_STATION);\n1241:\t\t}\n1242:\t\n1243:\t\tfor (i = 0; i \u003c NUM_DEFAULT_KEYS; i++) {\n1244:\t\t\tkey = wiphy_dereference(local-\u003ehw.wiphy, sta-\u003eptk[i]);\n1245:\t\t\tif (!key)\n1246:\t\t\t\tcontinue;\n1247:\t\t\tieee80211_key_replace(key-\u003esdata, NULL, key-\u003esta,\n1248:\t\t\t\t\t key-\u003econf.flags, key, NULL);\n1249:\t\t\t__ieee80211_key_destroy(key, key-\u003esdata-\u003evif.type ==\n1250:\t\t\t\t\t\tNL80211_IFTYPE_STATION);\n1251:\t\t}\n1252:\t}\n1253:\t\n1254:\tvoid ieee80211_delayed_tailroom_dec(struct wiphy *wiphy,\n"
} |
| 65/3 | 2026/09/23 10:52 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 70903 output: 41 thoughts: 833 Thoughts: **Analyzing Potential Key Management Issues** Okay, so I'm digging into this `ieee80211_free_sta_keys` function, and it's looping through `sta->deflink.cigtk` in the exact same manner as `sta->deflink.gtk`. My initial thought is that if there *were* any use-after-free or memory leaks here, KASAN would likely have flagged it by now. That's a point in favor of the code's safety, but I need to be thorough. Now, let's turn our attention to `ieee80211_gtk_rekey_add`. The signature looks standard enough: it takes the usual suspects - the vif, index, key data, length, link ID, and crucially, a `cigtk` flag. I'm focusing on the recent changes in `ieee80211_gtk_rekey_add`, specifically these lines. I'm noting the logic that determines which key array (`gtk` or `cigtk`) to access. The conditional logic is: if `cigtk` is true, use `cigtk[idx]`, otherwise use `gtk[idx]`. There is an early return in case of a problem, but it seems unlikely. It's using `wiphy_dereference`, which is good; it's the right mechanism. The `WARN_ON` check for `cigtk && idx >= NUM_CTRL_KEYS` seems sensible. But let's look closer, especially at the `prev_key` assignment. If neither `cigtk[idx]` nor `cigtk[idx ^ 1]` exists, `prev_key` *remains* NULL. I'm now zeroing in on what happens when `prev_key` is actually NULL. The code jumps in an `if (!prev_key)` conditional. I see it starts looping through NUM_DEFAULT_KEYS, and then proceeds. I'll read from lines 1400-1440. Hmm. I need to understand that path. There's a potential NULL dereference there, and I need to see how that's handled. Is there a race condition? Is `prev_key` ever legitimately NULL, and if so, how is it handled down the line? I need to analyze how the code proceeds to see if any potential security vulnerabilities arise. |
| 66/3 | 2026/09/23 10:53 | tool | read-file |
0mArgs:{
"File": "net/mac80211/key.c",
"FirstLine": 1415,
"LineCount": 40
}Results: {
"Contents": "1415:\t\t\tsdata_dereference(sdata-\u003elink[link_id], sdata);\n1416:\t\n1417:\t\tif (WARN_ON(!link_data))\n1418:\t\t\treturn ERR_PTR(-EINVAL);\n1419:\t\n1420:\t\tif (WARN_ON(!local-\u003ewowlan))\n1421:\t\t\treturn ERR_PTR(-EINVAL);\n1422:\t\n1423:\t\tif (WARN_ON(vif-\u003etype != NL80211_IFTYPE_STATION))\n1424:\t\t\treturn ERR_PTR(-EINVAL);\n1425:\t\n1426:\t\tif (WARN_ON(idx \u003e= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +\n1427:\t\t\t NUM_DEFAULT_BEACON_KEYS))\n1428:\t\t\treturn ERR_PTR(-EINVAL);\n1429:\t\n1430:\t\tif (WARN_ON(cigtk \u0026\u0026 idx \u003e= NUM_CTRL_KEYS))\n1431:\t\t\treturn ERR_PTR(-EINVAL);\n1432:\t\n1433:\t\tif (cigtk)\n1434:\t\t\tprev_key = wiphy_dereference(local-\u003ehw.wiphy,\n1435:\t\t\t\t\t\t link_data-\u003ecigtk[idx]);\n1436:\t\telse\n1437:\t\t\tprev_key = wiphy_dereference(local-\u003ehw.wiphy,\n1438:\t\t\t\t\t\t link_data-\u003egtk[idx]);\n1439:\t\tif (!prev_key) {\n1440:\t\t\tif (cigtk) {\n1441:\t\t\t\tprev_key = wiphy_dereference(local-\u003ehw.wiphy,\n1442:\t\t\t\t\t\t\t link_data-\u003ecigtk[idx ^ 1]);\n1443:\t\t\t} else if (idx \u003c NUM_DEFAULT_KEYS) {\n1444:\t\t\t\tfor (int i = 0; i \u003c NUM_DEFAULT_KEYS; i++) {\n1445:\t\t\t\t\tif (i == idx)\n1446:\t\t\t\t\t\tcontinue;\n1447:\t\t\t\t\tprev_key = wiphy_dereference(local-\u003ehw.wiphy,\n1448:\t\t\t\t\t\t\t\t link_data-\u003egtk[i]);\n1449:\t\t\t\t\tif (prev_key)\n1450:\t\t\t\t\t\tbreak;\n1451:\t\t\t\t}\n1452:\t\t\t} else {\n1453:\t\t\t\t/* For IGTK we have 4 and 5 and for BIGTK - 6 and 7 */\n1454:\t\t\t\tprev_key = wiphy_dereference(local-\u003ehw.wiphy,\n"
} |
| 67/3 | 2026/09/23 10:53 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 72968 output: 41 thoughts: 16 Thoughts: Okay, here's my interpretation of reading lines 1455-1475, expressed as a first-person summary, keeping in mind my expert perspective: **Delving into the specifics of lines 1455-1475** Alright, I need to get a handle on what's being presented here. Focusing in on lines 1455-1475... I'm immediately looking for the key arguments being advanced, the evidence presented, and how it all hangs together conceptually. Given my experience, I'm expecting a certain level of rigor in this section - hopefully a clearly defined thesis, well-supported claims, and a logical progression of thought. My intuition tells me to be alert to any subtle implications that might be masked by the surface-level language. I'm going to start by identifying the core claim or proposition at the heart of these lines, and then carefully dissect the supporting details, looking for any potential weaknesses or areas that warrant a deeper dive. The phrasing could be loaded, so I'll be sure to read between the lines, noting anything that might be an assumption instead of a concrete claim. This part is a crucial segment for understanding the overall trajectory of the work, and the degree to which it is convincing. |
| 68/3 | 2026/09/23 10:53 | tool | read-file |
0mArgs:{
"File": "net/mac80211/key.c",
"FirstLine": 1455,
"LineCount": 25
}Results: {
"Contents": "1455:\t\t\t\t\t\t\t link_data-\u003egtk[idx ^ 1]);\n1456:\t\t\t}\n1457:\t\t}\n1458:\t\n1459:\t\tif (WARN_ON(!prev_key))\n1460:\t\t\treturn ERR_PTR(-EINVAL);\n1461:\t\n1462:\t\tif (WARN_ON(key_len \u003c prev_key-\u003econf.keylen))\n1463:\t\t\treturn ERR_PTR(-EINVAL);\n1464:\t\n1465:\t\tkey = ieee80211_key_alloc(prev_key-\u003econf.cipher, idx,\n1466:\t\t\t\t\t prev_key-\u003econf.keylen, key_data,\n1467:\t\t\t\t\t 0, NULL);\n1468:\t\tif (IS_ERR(key))\n1469:\t\t\treturn ERR_CAST(key);\n1470:\t\n1471:\t\tif (sdata-\u003eu.mgd.mfp != IEEE80211_MFP_DISABLED)\n1472:\t\t\tkey-\u003econf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;\n1473:\t\n1474:\t\tif (prev_key-\u003econf.flags \u0026 IEEE80211_KEY_FLAG_CIP)\n1475:\t\t\tkey-\u003econf.flags |= IEEE80211_KEY_FLAG_CIP;\n1476:\t\n1477:\t\tkey-\u003econf.link_id = link_data-\u003elink_id;\n1478:\t\n1479:\t\terr = ieee80211_key_link(key, link_data, NULL);\n"
} |
| 69/3 | 2026/09/23 10:53 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 73722 output: 44 thoughts: 284 Thoughts: **Analyzing the `nl80211_associate` Function** Okay, so I'm digging into this code, starting with that check `if (WARN_ON(!prev_key)) return ERR_PTR(-EINVAL);`. Seems like a pretty standard NULL check for `prev_key`, good defensive programming. Now, I'm shifting focus to `nl80211_associate`. I need to understand how the `req` variable is handled within this function. I'll need to figure out how and where this struct is allocated. Right now, I'm at line 13320 or so, and I've quickly noted a check for `NL80211_ATTR_ASSOC_CIP`. If that flag is set, there's a call to `cfg80211_cigtk_supported`. Interesting. I'll have to investigate that function to see how it works. And also, how the result is used to set the `ASSOC_REQ_CIP` flag if the check is passed. So, looks like `req.flags` is being updated based on the attribute's presence. I need to keep in mind, however, the original question. Where is `req` allocated? I'll continue to examine the function to determine that. |
| 70/3 | 2026/09/23 10:53 | tool | grepper |
0mArgs:{
"Expression": "struct cfg80211_assoc_request req",
"PathPrefix": "net/wireless/nl80211.c"
}Results: {
"Output": "net/wireless/nl80211.c=13237=static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)\n--\nnet/wireless/nl80211.c-13240-\tstruct net_device *dev = info-\u003euser_ptr[1];\nnet/wireless/nl80211.c:13241:\tstruct cfg80211_assoc_request req = {};\nnet/wireless/nl80211.c-13242-\tconst u8 *ap_addr, *ssid;\n"
} |
| 71/3 | 2026/09/23 10:53 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 74492 output: 46 thoughts: 1428 Thoughts: **Analyzing CIP Support in mac80211 and wil6210** Okay, so I'm digging into how Cipher-based Integrity Protection (CIP) is handled, and I'm starting from the basics, looking at the `struct cfg80211_assoc_request req` which is zero-initialized. I've noted that `assoc_data->cip` flag gets set in `ieee80211_mgd_assoc` based on the request flags. Now, I'm checking the calculations of Information Elements (IEs) sizes and I've found an interesting addition in `ieee80211_send_assoc`. It includes the conditional addition of the CIP capabilities IE size (4 bytes) if `assoc_data->cip` is set. Further, in `ieee80211_add_link_elems`, CIP capabilities are added based on the association link ID and if `assoc_data->cip` is true. The association process, as seen in `ieee80211_assoc_config_link`, retrieves `cip_cap` from the elements if `assoc_data->cip` is set, and it includes some sanity checking. Finally, `ieee80211_assoc_success` sets `sta->sta.cip` to `assoc_data->cip`. So the basic support is present. I'm now diving into the data structures in `sta_info.h`. I've observed the addition of `struct ieee80211_key __rcu *cigtk[NUM_CTRL_KEYS]` in `struct link_sta_info`, `struct ieee80211_link_data`, and `struct ieee80211_link_sta`. There's also `u8 cip_cap` in `ieee80211_link_sta` and `bool cip` in `ieee80211_sta`. This indicates that CIP support is reflected in the key management and station information. I've confirmed that these structures are allocated with `kzalloc`, meaning they are zero-initialized. I'm now checking the tracepoints, specifically `trace_rdev_add_key`, `trace_rdev_get_key`, and `trace_rdev_del_key`. The `pairwise` variable has been replaced by `type` in the tracing data, which is stored in `__entry->type`. This indicates a change in how key types are handled in the tracing mechanism. Now, my attention is on the `wil6210` driver, specifically `wil_cfg80211_del_key`, where the `pairwise` argument is replaced by the `type` argument, an `enum nl80211_key_type`. The call to `wil_detect_key_usage` now uses the `type` to determine if it's a pairwise key. Aha! There's something in `wil_cfg80211_ap_recovery`. Here, I see that `NL80211_KEYTYPE_PAIRWISE` is explicitly passed. This is weird since, in the surrounding code, the `type` argument is used to signal the key type. Why is this hardcoded here? I need to investigate the `wil_cfg80211_ap_recovery` and other related functions more closely to understand the implications of this. I must figure out what implications the hardcoded `NL80211_KEYTYPE_PAIRWISE` has and if it impacts the implementation of CIP. |
| 72/3 | 2026/09/23 10:53 | tool | grepper |
0mArgs:{
"Expression": "wil_cfg80211_ap_recovery",
"PathPrefix": "drivers/net/wireless/ath/wil6210/"
}Results: {
"Output": "drivers/net/wireless/ath/wil6210/cfg80211.c=1932=static int _wil_cfg80211_start_ap(struct wiphy *wiphy,\n--\ndrivers/net/wireless/ath/wil6210/cfg80211.c-2030-\ndrivers/net/wireless/ath/wil6210/cfg80211.c:2031:void wil_cfg80211_ap_recovery(struct wil6210_priv *wil)\ndrivers/net/wireless/ath/wil6210/cfg80211.c-2032-{\n--\ndrivers/net/wireless/ath/wil6210/main.c=525=static void wil_fw_error_worker(struct work_struct *work)\n--\ndrivers/net/wireless/ath/wil6210/main.c-585-\t\tmutex_unlock(\u0026wil-\u003emutex);\ndrivers/net/wireless/ath/wil6210/main.c:586:\t\twil_cfg80211_ap_recovery(wil);\ndrivers/net/wireless/ath/wil6210/main.c-587-\t\tmutex_lock(\u0026wil-\u003emutex);\n--\ndrivers/net/wireless/ath/wil6210/wil6210.h=1318=int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,\n--\ndrivers/net/wireless/ath/wil6210/wil6210.h-1320-\t\t\t u64 cookie);\ndrivers/net/wireless/ath/wil6210/wil6210.h:1321:void wil_cfg80211_ap_recovery(struct wil6210_priv *wil);\ndrivers/net/wireless/ath/wil6210/wil6210.h-1322-int wil_cfg80211_iface_combinations_from_fw(\n"
} |
| 73/3 | 2026/09/23 10:53 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 77267 output: 51 thoughts: 43 Thoughts: Okay, let's dive into this. I'm going to take a look at the `wil_cfg80211_ap_recovery` function, and it's located right in the heart of things, in `drivers/net/wireless/ath/wil6210/cfg80211.c`. So, *that* suggests it's intimately involved with the cfg80211 interface, which is the standard user-space communication mechanism for wireless devices within the Linux kernel. Given the naming convention and location, I can already make some inferences. It's almost certainly responsible for handling the recovery of an Access Point (AP) mode operation, specifically tailored for the Wil6210 chipset. It's likely involved in situations where the AP mode encounters some kind of error or disruption, potentially a hardware fault, a driver issue, or even a regulatory constraint change. The "recovery" aspect indicates it's designed to bring the AP back to a functional state after a problem has occurred, perhaps by resetting the hardware, re-initializing certain parameters, or even notifying user-space applications of the situation. I'm going to start by looking for any clues that this function might have. I need to understand its function signatures and how it is used, which are the main points to consider, and how this function interplays with other parts of the driver. I need to identify the exact trigger for recovery, the steps taken during the recovery process, and any error handling or logging involved. Knowing those parts will illuminate the potential vulnerabilities this function might encounter. I need to pinpoint the areas for concern, and any potential areas for improvement. Let's see what's what. |
| 74/3 | 2026/09/23 10:53 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/ath/wil6210/cfg80211.c",
"FirstLine": 2060,
"LineCount": 30
}Results: {
"Contents": "2060:\t\t\t\t\t\t vif-\u003essid, vif-\u003essid_len,\n2061:\t\t\t\t\t\t vif-\u003eprivacy, vif-\u003ebi,\n2062:\t\t\t\t\t\t vif-\u003echannel,\n2063:\t\t\t\t\t\t vif-\u003ewmi_edmg_channel, \u0026bcon,\n2064:\t\t\t\t\t\t vif-\u003ehidden_ssid, vif-\u003epbss);\n2065:\t\t\tif (rc) {\n2066:\t\t\t\twil_err(wil, \"vif %d recovery failed (%d)\\n\", i, rc);\n2067:\t\t\t\tcontinue;\n2068:\t\t\t}\n2069:\t\n2070:\t\t\tif (!vif-\u003eprivacy || vif-\u003egtk_len == 0)\n2071:\t\t\t\tcontinue;\n2072:\t\n2073:\t\t\tkey_params.key = vif-\u003egtk;\n2074:\t\t\tkey_params.key_len = vif-\u003egtk_len;\n2075:\t\t\tkey_params.seq_len = IEEE80211_GCMP_PN_LEN;\n2076:\t\t\trc = wil_cfg80211_add_key(wiphy, vif_to_wdev(vif), -1,\n2077:\t\t\t\t\t\t vif-\u003egtk_index,\n2078:\t\t\t\t\t\t NL80211_KEYTYPE_PAIRWISE,\n2079:\t\t\t\t\t\t NULL, \u0026key_params);\n2080:\t\t\tif (rc)\n2081:\t\t\t\twil_err(wil, \"vif %d recovery add key failed (%d)\\n\",\n2082:\t\t\t\t\ti, rc);\n2083:\t\t}\n2084:\t}\n2085:\t\n2086:\tstatic int wil_cfg80211_change_beacon(struct wiphy *wiphy,\n2087:\t\t\t\t\t struct net_device *ndev,\n2088:\t\t\t\t\t struct cfg80211_ap_update *params)\n2089:\t{\n"
} |
| 75/3 | 2026/09/23 10:53 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 78227 output: 41 thoughts: 360 Thoughts: **Analyzing the Impact of a Key Type Change in `wil_cfg80211_ap_recovery`**
Okay, so I'm looking at this code in `wil_cfg80211_ap_recovery`. Previously, a `false` value was passed, which seems to have mapped to `pairwise = false` based on context, since this appears to be associated with GTK handling. Now, the author's changed it to `NL80211_KEYTYPE_PAIRWISE` instead of `NL80211_KEYTYPE_GROUP`. I need to figure out the implications of this change, so let me delve into the `wil_cfg80211_add_key` function.
Inside `wil_cfg80211_add_key`, I see that the `type` variable is the key here. The function uses a simple check: `pairwise = type == NL80211_KEYTYPE_PAIRWISE;`. This sets the `pairwise` boolean. That makes sense. I can now see how `pairwise` affects the flow within the function. Looking at the code:
```c
static int wil_cfg80211_add_key(struct wiphy *wiphy,
struct wireless_dev *wdev, int link_id,
u8 key_index,
enum nl80211_key_type type,
const u8 *mac_addr,
struct key_params *params)
{
int rc;
bool pairwise = type == NL80211_KEYTYPE_PAIRWISE;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
enum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);
struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif->mid,
key_usage,
mac_addr);
```
The next part that's critical is this `wil_detect_key_usage(wdev, pairwise)` call. That function's return value determines `key_usage`, which is then passed to `wil_find_sta_by_key_usage`. So, I really need to examine the logic inside `wil_detect_key_usage` and `wil_find_sta_by_key_usage`. These functions will tell me how this `pairwise` boolean, which is derived from the key type change, affects the key usage and station lookup process. I need to understand how the system determines *how* the key is used, and which station it is associated with.
|
| 76/3 | 2026/09/23 10:53 | tool | grepper |
0mArgs:{
"Expression": "wil_detect_key_usage",
"PathPrefix": "drivers/net/wireless/ath/wil6210/"
}Results: {
"Output": "drivers/net/wireless/ath/wil6210/cfg80211.c=1496=static int wil_cfg80211_set_channel(struct wiphy *wiphy,\n--\ndrivers/net/wireless/ath/wil6210/cfg80211.c-1506-\ndrivers/net/wireless/ath/wil6210/cfg80211.c:1507:static enum wmi_key_usage wil_detect_key_usage(struct wireless_dev *wdev,\ndrivers/net/wireless/ath/wil6210/cfg80211.c-1508-\t\t\t\t\t bool pairwise)\n--\ndrivers/net/wireless/ath/wil6210/cfg80211.c=1621=static int wil_cfg80211_add_key(struct wiphy *wiphy,\n--\ndrivers/net/wireless/ath/wil6210/cfg80211.c-1631-\tstruct wil6210_vif *vif = wdev_to_vif(wil, wdev);\ndrivers/net/wireless/ath/wil6210/cfg80211.c:1632:\tenum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise);\ndrivers/net/wireless/ath/wil6210/cfg80211.c-1633-\tstruct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif-\u003emid,\n--\ndrivers/net/wireless/ath/wil6210/cfg80211.c=1698=static int wil_cfg80211_del_key(struct wiphy *wiphy,\n--\ndrivers/net/wireless/ath/wil6210/cfg80211.c-1706-\tenum wmi_key_usage key_usage =\ndrivers/net/wireless/ath/wil6210/cfg80211.c:1707:\t\twil_detect_key_usage(wdev, type == NL80211_KEYTYPE_PAIRWISE);\ndrivers/net/wireless/ath/wil6210/cfg80211.c-1708-\tstruct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif-\u003emid,\n"
} |
| 77/3 | 2026/09/23 10:53 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 79861 output: 51 thoughts: 18 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and presented as if it were my own internal monologue: **Diving into `wil_detect_key_usage`** Alright, time to get to the heart of the matter. My initial thought process is to zero in on the `wil_detect_key_usage` function. That name immediately suggests it's crucial for understanding how we're identifying and handling potential security vulnerabilities related to key usage. I'm going to want to understand its implementation thoroughly, likely by reading its code directly. Crucially, I'm not just going to read *that* function in isolation. I need context. I'll need to see the lines surrounding `wil_detect_key_usage` – the functions that call it, the data it consumes, the data it produces. I'll need the "before" and "after" picture to really grasp its purpose and impact. This will involve understanding the control flow surrounding this particular function. No shortcuts, just a deep dive. |
| 78/3 | 2026/09/23 10:53 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/ath/wil6210/cfg80211.c",
"FirstLine": 1505,
"LineCount": 45
}Results: {
"Contents": "1505:\t}\n1506:\t\n1507:\tstatic enum wmi_key_usage wil_detect_key_usage(struct wireless_dev *wdev,\n1508:\t\t\t\t\t\t bool pairwise)\n1509:\t{\n1510:\t\tstruct wil6210_priv *wil = wdev_to_wil(wdev);\n1511:\t\tenum wmi_key_usage rc;\n1512:\t\n1513:\t\tif (pairwise) {\n1514:\t\t\trc = WMI_KEY_USE_PAIRWISE;\n1515:\t\t} else {\n1516:\t\t\tswitch (wdev-\u003eiftype) {\n1517:\t\t\tcase NL80211_IFTYPE_STATION:\n1518:\t\t\tcase NL80211_IFTYPE_P2P_CLIENT:\n1519:\t\t\t\trc = WMI_KEY_USE_RX_GROUP;\n1520:\t\t\t\tbreak;\n1521:\t\t\tcase NL80211_IFTYPE_AP:\n1522:\t\t\tcase NL80211_IFTYPE_P2P_GO:\n1523:\t\t\t\trc = WMI_KEY_USE_TX_GROUP;\n1524:\t\t\t\tbreak;\n1525:\t\t\tdefault:\n1526:\t\t\t\t/* TODO: Rx GTK or Tx GTK? */\n1527:\t\t\t\twil_err(wil, \"Can't determine GTK type\\n\");\n1528:\t\t\t\trc = WMI_KEY_USE_RX_GROUP;\n1529:\t\t\t\tbreak;\n1530:\t\t\t}\n1531:\t\t}\n1532:\t\twil_dbg_misc(wil, \"detect_key_usage: -\u003e %s\\n\", key_usage_str[rc]);\n1533:\t\n1534:\t\treturn rc;\n1535:\t}\n1536:\t\n1537:\tstatic struct wil_sta_info *\n1538:\twil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid,\n1539:\t\t\t\t enum wmi_key_usage key_usage, const u8 *mac_addr)\n1540:\t{\n1541:\t\tint cid = -EINVAL;\n1542:\t\n1543:\t\tif (key_usage == WMI_KEY_USE_TX_GROUP)\n1544:\t\t\treturn NULL; /* not needed */\n1545:\t\n1546:\t\t/* supplicant provides Rx group key in STA mode with NULL MAC address */\n1547:\t\tif (mac_addr)\n1548:\t\t\tcid = wil_find_cid(wil, mid, mac_addr);\n1549:\t\telse if (key_usage == WMI_KEY_USE_RX_GROUP)\n"
} |
| 79/3 | 2026/09/23 10:53 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 80882 output: 51 thoughts: 169 Thoughts: **Analyzing the STA Key Finding Logic** Okay, let's break this down. I'm looking at `wil_find_sta_by_key_usage` and trying to understand its behavior. The code first checks for `WMI_KEY_USE_TX_GROUP` and immediately returns `NULL` – that makes sense, as the context suggests it's not a relevant case here. Now, the interesting part. If `mac_addr` is provided, it attempts to find a Client ID (CID) using `wil_find_cid`. However, what happens when `mac_addr` is `NULL`? It appears there's special handling for the `WMI_KEY_USE_RX_GROUP` scenario when `mac_addr` is `NULL`. I'm going to set that one aside for the moment. My question is, what happens if `key_usage` is `WMI_KEY_USE_PAIRWISE` *and* `mac_addr` is `NULL`? The ellipsis suggests there's some other logic that handles this specific combination, but the code doesn't explicitly reveal what that might be. I need to delve deeper into the code to understand the implications of this condition. I'm guessing that this particular combination of parameters might represent a specific edge case. I need to figure out what, exactly, is going on. |
| 80/3 | 2026/09/23 10:53 | tool | read-file |
0mArgs:{
"File": "drivers/net/wireless/ath/wil6210/cfg80211.c",
"FirstLine": 1545,
"LineCount": 35
}Results: {
"Contents": "1545:\t\n1546:\t\t/* supplicant provides Rx group key in STA mode with NULL MAC address */\n1547:\t\tif (mac_addr)\n1548:\t\t\tcid = wil_find_cid(wil, mid, mac_addr);\n1549:\t\telse if (key_usage == WMI_KEY_USE_RX_GROUP)\n1550:\t\t\tcid = wil_find_cid_by_idx(wil, mid, 0);\n1551:\t\tif (cid \u003c 0) {\n1552:\t\t\twil_err(wil, \"No CID for %pM %s\\n\", mac_addr,\n1553:\t\t\t\tkey_usage_str[key_usage]);\n1554:\t\t\treturn ERR_PTR(cid);\n1555:\t\t}\n1556:\t\n1557:\t\treturn \u0026wil-\u003esta[cid];\n1558:\t}\n1559:\t\n1560:\tvoid wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,\n1561:\t\t\t struct wil_sta_info *cs,\n1562:\t\t\t struct key_params *params)\n1563:\t{\n1564:\t\tstruct wil_tid_crypto_rx_single *cc;\n1565:\t\tint tid;\n1566:\t\n1567:\t\tif (!cs)\n1568:\t\t\treturn;\n1569:\t\n1570:\t\tswitch (key_usage) {\n1571:\t\tcase WMI_KEY_USE_STORE_PTK:\n1572:\t\tcase WMI_KEY_USE_PAIRWISE:\n1573:\t\t\tfor (tid = 0; tid \u003c WIL_STA_TID_NUM; tid++) {\n1574:\t\t\t\tcc = \u0026cs-\u003etid_crypto_rx[tid].key_id[key_index];\n1575:\t\t\t\tif (params-\u003eseq)\n1576:\t\t\t\t\tmemcpy(cc-\u003epn, params-\u003eseq,\n1577:\t\t\t\t\t IEEE80211_GCMP_PN_LEN);\n1578:\t\t\t\telse\n1579:\t\t\t\t\tmemset(cc-\u003epn, 0, IEEE80211_GCMP_PN_LEN);\n"
} |
| 81/3 | 2026/09/23 10:53 | llm | kmsan-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 81977 output: 501 thoughts: 3223 Thoughts: **KMSAN Assessment: No Need for KMSAN** Okay, here's my assessment of whether KMSAN is necessary for this patch series. My initial dive showed some interesting code around CIP (Ciphering), key management, and station configuration within the wireless networking stack. I looked closely at various code paths and scrutinized potential areas where uninitialized memory reads might occur, particularly in relation to the new CIP functionality. First, I examined a few minor bugs and how they are handled, like the `-EINVAL` returned when `mac_addr` is `NULL` when dealing with pairwise keys, or key deletion logic. The important thing to understand here is that KASAN (Kernel AddressSanitizer) or similar standard bug detectors already take care of those. Then, I focused on data structures sent to user space via netlink. The `NL80211_ATTR_CIP_CAPABILITIES` attribute seemed like the most probable candidate for an uninitialized read, especially with this new CIP support. However, after tracing how it's populated, I confirmed that the underlying `wiphy_iftype_ext_capab` structure is consistently initialized. I'm satisfied that this path is safe. I checked debugfs, tracepoints, and other areas where data is presented externally. Next, I looked at conditional logic, especially branching that depends on potentially uninitialized variables. I traced the data flow, paying close attention to the initialization of structures like `params` in functions like `nl80211_set_station` and `nl80211_new_station`. A key area to check: are there any `memset` or explicit assignments used? I saw that these structures are *always* initialized using `memset` or explicit initialization. Any code paths that could lead to uninitialized memory access are thoroughly guarded. I also thoroughly checked data structure allocations, especially those that involve structures containing new fields related to CIP functionality. After carefully tracing the memory allocations of things like `link_sta_info->cigtk`, `ieee80211_sta->cip`, etc., it became clear that `kzalloc` is used, guaranteeing zero-initialization. Finally, I checked for cases where buffer lengths or bounds are modified in such a way that existing memory might become accessible. After a close look at the 802.11 frame insertion and other potentially problematic data, the conclusion is clear: this patch doesn't introduce any new risks from a bounds-check perspective. Based on this analysis, I'm confident that these changes do not introduce or expose any new risks of uninitialized memory reads that would be detectable *only* by KMSAN. All risks are covered by the standard detectors (KASAN, LOCKDEP, etc.), and the requirements for triggering a KMSAN check have not been met. Thus, `NeedsKMSAN=false`. I am prepared to justify my reasoning. |
| 82/3 | 2026/09/23 10:53 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch series introduces support for the Control Integrity Protocol (CIP) and Control Integrity Group Temporal Keys (CIGTK) in cfg80211/mac80211, updating the cfg80211 add_key/del_key/get_key operations across wireless drivers to use an enum nl80211_key_type instead of a boolean pairwise flag.\n\nAnalysis regarding KMSAN vs KASAN applicability:\n1. Kernel data exposed to userspace: The new netlink attribute NL80211_ATTR_CIP_CAPABILITIES sends a single u8 from wiphy_iftype_ext_capab. These capability structures are statically allocated in driver rodata/BSS and thus zero-initialized. Station parameters and request structs in nl80211 handlers (such as nl80211_set_station, nl80211_new_station, nl80211_add_mod_link_station, and nl80211_associate) are explicitly zero-initialized with memset(\u0026params, 0, sizeof(params)) or struct initializer = {}.\n2. Data structures in mac80211: New fields (such as cigtk pointers, cip flag, and cip_cap) reside within structures (ieee80211_link_data, link_sta_info, sta_info, ieee80211_key) that are dynamically allocated with kzalloc.\n3. Parsing and bounds: Frame parsing for the new CIP capability element validates element length (len \u003e= sizeof(*elems-\u003ecip_cap)) before referencing payload bytes, and new packet generation via ieee80211_put_cip_cap initializes all four bytes added to the skb. Key indices for CIGTK are validated against NUM_CTRL_KEYS (2) in nl80211 and cfg80211 before use.\n4. Any potential memory corruption, out-of-bounds array access, or reference count / lifetime issues with key objects are fully covered by standard KASAN.\n\nNo uninitialized memory reads or information leak risks are introduced. Spawning a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch series introduces support for the Control Integrity Protocol (CIP) and Control Integrity Group Temporal Keys (CIGTK) in cfg80211/mac80211, updating the cfg80211 add_key/del_key/get_key operations across wireless drivers to use an enum nl80211_key_type instead of a boolean pairwise flag.\n\nAnalysis regarding KMSAN vs KASAN applicability:\n1. Kernel data exposed to userspace: The new netlink attribute NL80211_ATTR_CIP_CAPABILITIES sends a single u8 from wiphy_iftype_ext_capab. These capability structures are statically allocated in driver rodata/BSS and thus zero-initialized. Station parameters and request structs in nl80211 handlers (such as nl80211_set_station, nl80211_new_station, nl80211_add_mod_link_station, and nl80211_associate) are explicitly zero-initialized with memset(\u0026params, 0, sizeof(params)) or struct initializer = {}.\n2. Data structures in mac80211: New fields (such as cigtk pointers, cip flag, and cip_cap) reside within structures (ieee80211_link_data, link_sta_info, sta_info, ieee80211_key) that are dynamically allocated with kzalloc.\n3. Parsing and bounds: Frame parsing for the new CIP capability element validates element length (len \u003e= sizeof(*elems-\u003ecip_cap)) before referencing payload bytes, and new packet generation via ieee80211_put_cip_cap initializes all four bytes added to the skb. Key indices for CIGTK are validated against NUM_CTRL_KEYS (2) in nl80211 and cfg80211 before use.\n4. Any potential memory corruption, out-of-bounds array access, or reference count / lifetime issues with key objects are fully covered by standard KASAN.\n\nNo uninitialized memory reads or information leak risks are introduced. Spawning 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) |
|---|