struct iwl_mld_wowlan_status *wowlan_status;
};
+struct iwl_mld_rsc_resume_iter_data {
+ struct iwl_mld *mld;
+ const struct iwl_wowlan_all_rsc_tsc_v5 *notif;
+ int queue;
+};
+
struct iwl_mld_suspend_key_iter_data {
struct iwl_wowlan_rsc_tsc_params_cmd *rsc;
bool have_rsc;
iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld,
struct iwl_mld_wowlan_status *wowlan_status,
const struct iwl_wowlan_gtk_status *gtk_data,
- const struct iwl_wowlan_all_rsc_tsc_v5 *sc)
+ const struct iwl_wowlan_all_rsc_tsc_v5 *sc,
+ int rsc_notif_ver)
{
int status_idx = 0;
wowlan_status->gtk[status_idx].id =
wowlan_status->gtk[status_idx].flags &
IWL_WOWLAN_GTK_IDX_MASK;
- /* The rsc for both gtk keys are stored in gtk[0]->sc->mcast_rsc
- * The gtk ids can be any two numbers between 0 and 3,
- * the id_map maps between the key id and the index in sc->mcast
- */
- rsc_idx =
- sc->mcast_key_id_map[wowlan_status->gtk[status_idx].id];
- iwl_mld_convert_gtk_resume_seq(&wowlan_status->gtk[status_idx],
- sc, rsc_idx);
+ /* If RSC_NOTIF is not supported */
+ if (rsc_notif_ver == IWL_FW_CMD_VER_UNKNOWN) {
+ /* The rsc for both gtk keys are stored in
+ * gtk[0]->sc->mcast_rsc. The gtk ids can be any two
+ * numbers between 0 and 3, the id_map maps between the
+ * key id and the index in sc->mcast
+ */
+ rsc_idx =
+ sc->mcast_key_id_map[wowlan_status->gtk[status_idx].id];
+ iwl_mld_convert_gtk_resume_seq(&wowlan_status->gtk[status_idx],
+ sc, rsc_idx);
+ }
if (key_status == IWL_WOWLAN_STATUS_NEW_KEY) {
memcpy(wowlan_status->gtk[status_idx].key,
PROT_OFFLOAD_GROUP,
WOWLAN_INFO_NOTIFICATION,
IWL_FW_CMD_VER_UNKNOWN);
+ int rsc_notif_ver = iwl_fw_lookup_notif_ver(mld->fw,
+ DATA_PATH_GROUP,
+ RSC_NOTIF,
+ IWL_FW_CMD_VER_UNKNOWN);
if (wowlan_info_ver == 5) {
/* v5 format - validate before conversion */
return true;
iwl_mld_convert_gtk_resume_data(mld, wowlan_status, notif->gtk,
- ¬if->gtk[0].sc);
- iwl_mld_convert_ptk_resume_seq(mld, wowlan_status, ¬if->gtk[0].sc);
+ ¬if->gtk[0].sc, rsc_notif_ver);
+ if (rsc_notif_ver == IWL_FW_CMD_VER_UNKNOWN)
+ iwl_mld_convert_ptk_resume_seq(mld, wowlan_status,
+ ¬if->gtk[0].sc);
/* only one igtk is passed by FW */
iwl_mld_convert_igtk_resume_data(wowlan_status, ¬if->igtk[0]);
iwl_mld_convert_bigtk_resume_data(wowlan_status, notif->bigtk);
struct iwl_mld_resume_key_iter_data *data = _data;
struct iwl_mld_wowlan_status *wowlan_status = data->wowlan_status;
u8 status_idx;
-
- if (key->keyidx >= 0 && key->keyidx <= 3) {
+ int rsc_notif_ver = iwl_fw_lookup_notif_ver(data->mld->fw,
+ DATA_PATH_GROUP,
+ RSC_NOTIF,
+ IWL_FW_CMD_VER_UNKNOWN);
+
+ /* If RSC_NOTIF is not supported */
+ if (rsc_notif_ver == IWL_FW_CMD_VER_UNKNOWN &&
+ key->keyidx >= 0 && key->keyidx <= 3) {
/* PTK */
if (sta) {
iwl_mld_update_ptk_rx_seq(data->mld, wowlan_status,
}
}
+static void
+iwl_mld_rsc_update_key_iter(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ void *_data)
+{
+ struct iwl_mld_rsc_resume_iter_data *data = _data;
+ struct ieee80211_key_seq seq;
+
+ if (key->keyidx > 3)
+ return;
+
+ if (sta) {
+ /* PTK */
+ BUILD_BUG_ON(ARRAY_SIZE(data->notif->ucast_rsc) !=
+ IWL_MAX_TID_COUNT);
+
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ /* TKIP: just update key sequences */
+ for (int tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+ iwl_mld_le64_to_tkip_seq(data->notif->ucast_rsc[tid],
+ &seq);
+ ieee80211_set_key_rx_seq(key, tid, &seq);
+ }
+ } else {
+ struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+ struct iwl_mld_ptk_pn *mld_ptk_pn =
+ rcu_dereference_wiphy(data->mld->wiphy,
+ mld_sta->ptk_pn[key->keyidx]);
+
+ if (WARN_ON(!mld_ptk_pn))
+ return;
+
+ if (WARN_ON(data->queue >=
+ data->mld->trans->info.num_rxqs))
+ return;
+
+ for (int tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+ iwl_mld_le64_to_aes_seq(data->notif->ucast_rsc[tid],
+ &seq);
+ ieee80211_set_key_rx_seq(key, tid, &seq);
+ memcpy(mld_ptk_pn->q[data->queue].pn[tid],
+ seq.ccmp.pn,
+ IEEE80211_CCMP_PN_LEN);
+ }
+ }
+
+ IWL_DEBUG_WOWLAN(data->mld,
+ "Updated PTK RSC for key %d on queue %d\n",
+ key->keyidx, data->queue);
+ } else {
+ /* GTK */
+ int rsc_idx = data->notif->mcast_key_id_map[key->keyidx];
+
+ if (rsc_idx == IWL_MCAST_KEY_MAP_INVALID)
+ return;
+
+ if (IWL_FW_CHECK(data->mld,
+ rsc_idx >= ARRAY_SIZE(data->notif->mcast_rsc),
+ "Invalid mcast key mapping: %d for key %d\n",
+ rsc_idx, key->keyidx))
+ return;
+
+ for (int tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+ __le64 rsc =
+ data->notif->mcast_rsc[rsc_idx][tid];
+
+ if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
+ iwl_mld_le64_to_tkip_seq(rsc, &seq);
+ else
+ iwl_mld_le64_to_aes_seq(rsc, &seq);
+ ieee80211_set_key_rx_seq(key, tid, &seq);
+ }
+
+ IWL_DEBUG_WOWLAN(data->mld,
+ "Updated GTK %d RSC (rsc_idx %d) on queue %d\n",
+ key->keyidx, rsc_idx, data->queue);
+ }
+}
+
+void
+iwl_mld_process_rsc_notification(struct iwl_mld *mld,
+ struct ieee80211_vif *vif,
+ const struct iwl_wowlan_all_rsc_tsc_v5 *notif,
+ int queue)
+{
+ struct iwl_mld_rsc_resume_iter_data iter_data = {
+ .mld = mld,
+ .notif = notif,
+ .queue = queue,
+ };
+
+ /* Iterate through all active keys and update RSC */
+ ieee80211_iter_keys_rcu(mld->hw, vif,
+ iwl_mld_rsc_update_key_iter,
+ &iter_data);
+}
+
static void
iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
struct iwl_mld *mld,