From: Johannes Berg For NAN data, the supplicant may derive and install GTKs to transmit with. As multicast data encryption is supported only with firmware versions that support adding NAN multicast data station, allow GTK installation only with such FW versions. Otherwise, do not install the GTK to the device. For NAN management, there are no GTKs, but there are IGTKs and BIGTKs, which need to be installed for the NAN broadcast and NAN management stations. This is supported only with firmware versions that allow adding NAN broadcast station and NAN management station. Handle both of these cases by adjusting the station mask appropriately, returning a zero station mask for the GTK and allowing that to not be an error/warning message. Signed-off-by: Johannes Berg Co-developed-by: Ilan Peer Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit --- .../net/wireless/intel/iwlwifi/mld/iface.c | 2 + .../net/wireless/intel/iwlwifi/mld/iface.h | 3 ++ drivers/net/wireless/intel/iwlwifi/mld/key.c | 50 +++++++++++++++++-- .../net/wireless/intel/iwlwifi/mld/mac80211.c | 1 - drivers/net/wireless/intel/iwlwifi/mld/sta.c | 8 ++- 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c index 399efeb469f6..2b837c6fa5fe 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c @@ -66,6 +66,8 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif) iwl_mld_free_internal_sta(mld, &mld_vif->nan.bcast_sta); if (mld_vif->nan.mgmt_sta.sta_id != IWL_INVALID_STA) iwl_mld_free_internal_sta(mld, &mld_vif->nan.mgmt_sta); + + mld_vif->nan.tx_igtk = NULL; } if (vif->type == NL80211_IFTYPE_NAN_DATA && diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h index c6a7588df1fa..bc6f45ff76f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.h @@ -160,6 +160,8 @@ struct iwl_mld_emlsr { * @nan.mgmt_sta: internal station used for NAN management frames, e.g., SDFs * and NAFs. * @nan.mcast_data_sta: internal station used for multicast NAN Data frames. + * @nan.tx_igtk: TX IGTK key for NAN, tracked separately since NAN does not + * use the vif links. */ struct iwl_mld_vif { /* Add here fields that need clean up on restart */ @@ -189,6 +191,7 @@ struct iwl_mld_vif { struct iwl_mld_int_sta bcast_sta; struct iwl_mld_int_sta mgmt_sta; struct iwl_mld_int_sta mcast_data_sta; + struct ieee80211_key_conf *tx_igtk; } nan; struct iwl_mld_emlsr emlsr; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.c b/drivers/net/wireless/intel/iwlwifi/mld/key.c index 151e35b851f7..a6454d90d0e3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/key.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/key.c @@ -63,6 +63,40 @@ static u32 iwl_mld_get_key_sta_mask(struct iwl_mld *mld, lockdep_assert_wiphy(mld->wiphy); + if (vif->type == NL80211_IFTYPE_NAN_DATA && !sta) { + /* Older firmware versions do not support transmission of + * multicast data frames. + */ + if (!iwl_mld_nan_use_nan_stations(mld)) + return 0; + + if (WARN_ON(mld_vif->nan.mcast_data_sta.sta_id == + IWL_INVALID_STA)) + return 0; + + return BIT(mld_vif->nan.mcast_data_sta.sta_id); + } + + if (vif->type == NL80211_IFTYPE_NAN && !sta) { + /* Older firmware versions do not support installation of + * IGTK/BIGTK keys. + */ + if (!iwl_mld_nan_use_nan_stations(mld)) + return 0; + + if (WARN_ON(mld_vif->nan.bcast_sta.sta_id == IWL_INVALID_STA || + mld_vif->nan.mgmt_sta.sta_id == IWL_INVALID_STA)) + return 0; + + if (key->keyidx >= 4 && key->keyidx <= 5) + return BIT(mld_vif->nan.mgmt_sta.sta_id); + + if (key->keyidx >= 6 && key->keyidx <= 7) + return BIT(mld_vif->nan.bcast_sta.sta_id); + + return 0; + } + /* AP group keys are per link and should be on the mcast/bcast STA */ if (vif->type == NL80211_IFTYPE_AP && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { @@ -204,7 +238,7 @@ iwl_mld_get_igtk_ptr(struct ieee80211_vif *vif, return &mld_sta->deflink.rx_igtk; } - return &mld_vif->deflink.tx_igtk; + return &mld_vif->nan.tx_igtk; case NL80211_IFTYPE_AP: mld_link = iwl_mld_link_dereference_check(mld_vif, link_id); if (WARN_ON(!mld_link)) @@ -254,8 +288,16 @@ int iwl_mld_add_key(struct iwl_mld *mld, lockdep_assert_wiphy(mld->wiphy); - if (!sta_mask) + if (!sta_mask) { + /* for NAN (GTK) indicate SW-only, it's not used at all */ + if (vif->type == NL80211_IFTYPE_NAN_DATA && !sta && + !iwl_mld_nan_use_nan_stations(mld)) + return 1; + + /* otherwise that's not valid */ + IWL_WARN(mld, "empty STA mask for key %d\n", key->keyidx); return -EINVAL; + } igtk_ptr = iwl_mld_get_igtk_ptr(vif, sta, key); if (igtk_ptr) { @@ -270,8 +312,10 @@ int iwl_mld_add_key(struct iwl_mld *mld, } ret = iwl_mld_add_key_to_fw(mld, sta_mask, key_flags, key); - if (ret) + if (ret) { + IWL_WARN(mld, "failed to add key to FW (%d)\n", ret); return ret; + } if (igtk_ptr) { WARN_ON(*igtk_ptr); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index b6df09812dae..9736b43155d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -2248,7 +2248,6 @@ static int iwl_mld_set_key_add(struct iwl_mld *mld, ret = iwl_mld_add_key(mld, vif, sta, key); if (ret) { - IWL_WARN(mld, "set key failed (%d)\n", ret); if (ptk_pn) { RCU_INIT_POINTER(mld_sta->ptk_pn[keyidx], NULL); kfree(ptk_pn); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c index cd13238ed613..77eeeed66116 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c @@ -1089,8 +1089,14 @@ iwl_mld_set_internal_sta_to_fw(struct iwl_mld *mld, * On the other hand, FW will never check this flag during RX since * an AP/GO doesn't receive protected broadcast management frames. * So, we can set it unconditionally. + * + * For NAN stations associated with a NAN Device, the MFP bit must be + * set to 1, as otherwise the FW will assert when a key associated with + * these stations would be added. */ - if (internal_sta->sta_type == STATION_TYPE_BCAST_MGMT) + if (internal_sta->sta_type == STATION_TYPE_BCAST_MGMT || + internal_sta->sta_type == STATION_TYPE_NAN_BCAST || + internal_sta->sta_type == STATION_TYPE_NAN_MGMT) cmd.mfp = cpu_to_le32(1); if (addr) { -- 2.34.1