|
@@ -1201,7 +1201,8 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
|
|
return max_offs;
|
|
return max_offs;
|
|
}
|
|
}
|
|
|
|
|
|
-static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
|
|
|
|
|
|
+static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm,
|
|
|
|
+ struct ieee80211_vif *vif,
|
|
struct ieee80211_sta *sta)
|
|
struct ieee80211_sta *sta)
|
|
{
|
|
{
|
|
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
@@ -1218,8 +1219,21 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
|
|
* station ID, then use AP's station ID.
|
|
* station ID, then use AP's station ID.
|
|
*/
|
|
*/
|
|
if (vif->type == NL80211_IFTYPE_STATION &&
|
|
if (vif->type == NL80211_IFTYPE_STATION &&
|
|
- mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT)
|
|
|
|
- return mvmvif->ap_sta_id;
|
|
|
|
|
|
+ mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
|
|
|
|
+ u8 sta_id = mvmvif->ap_sta_id;
|
|
|
|
+
|
|
|
|
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
|
|
|
|
+ lockdep_is_held(&mvm->mutex));
|
|
|
|
+ /*
|
|
|
|
+ * It is possible that the 'sta' parameter is NULL,
|
|
|
|
+ * for example when a GTK is removed - the sta_id will then
|
|
|
|
+ * be the AP ID, and no station was passed by mac80211.
|
|
|
|
+ */
|
|
|
|
+ if (IS_ERR_OR_NULL(sta))
|
|
|
|
+ return IWL_MVM_STATION_COUNT;
|
|
|
|
+
|
|
|
|
+ return sta_id;
|
|
|
|
+ }
|
|
|
|
|
|
return IWL_MVM_STATION_COUNT;
|
|
return IWL_MVM_STATION_COUNT;
|
|
}
|
|
}
|
|
@@ -1227,7 +1241,8 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
|
|
static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
|
static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
|
struct iwl_mvm_sta *mvm_sta,
|
|
struct iwl_mvm_sta *mvm_sta,
|
|
struct ieee80211_key_conf *keyconf, bool mcast,
|
|
struct ieee80211_key_conf *keyconf, bool mcast,
|
|
- u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags)
|
|
|
|
|
|
+ u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags,
|
|
|
|
+ u8 key_offset)
|
|
{
|
|
{
|
|
struct iwl_mvm_add_sta_key_cmd cmd = {};
|
|
struct iwl_mvm_add_sta_key_cmd cmd = {};
|
|
__le16 key_flags;
|
|
__le16 key_flags;
|
|
@@ -1269,7 +1284,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
|
if (mcast)
|
|
if (mcast)
|
|
key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
|
|
key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
|
|
|
|
|
|
- cmd.key_offset = keyconf->hw_key_idx;
|
|
|
|
|
|
+ cmd.key_offset = key_offset;
|
|
cmd.key_flags = key_flags;
|
|
cmd.key_flags = key_flags;
|
|
cmd.sta_id = sta_id;
|
|
cmd.sta_id = sta_id;
|
|
|
|
|
|
@@ -1360,6 +1375,7 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_sta *sta,
|
|
struct ieee80211_sta *sta,
|
|
struct ieee80211_key_conf *keyconf,
|
|
struct ieee80211_key_conf *keyconf,
|
|
|
|
+ u8 key_offset,
|
|
bool mcast)
|
|
bool mcast)
|
|
{
|
|
{
|
|
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
|
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
|
@@ -1375,17 +1391,17 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
|
ieee80211_get_key_rx_seq(keyconf, 0, &seq);
|
|
ieee80211_get_key_rx_seq(keyconf, 0, &seq);
|
|
ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
|
|
ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
|
|
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
|
|
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
|
|
- seq.tkip.iv32, p1k, 0);
|
|
|
|
|
|
+ seq.tkip.iv32, p1k, 0, key_offset);
|
|
break;
|
|
break;
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
case WLAN_CIPHER_SUITE_CCMP:
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
case WLAN_CIPHER_SUITE_WEP40:
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
case WLAN_CIPHER_SUITE_WEP104:
|
|
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
|
|
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
|
|
- 0, NULL, 0);
|
|
|
|
|
|
+ 0, NULL, 0, key_offset);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
|
|
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
|
|
- 0, NULL, 0);
|
|
|
|
|
|
+ 0, NULL, 0, key_offset);
|
|
}
|
|
}
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
@@ -1433,7 +1449,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_sta *sta,
|
|
struct ieee80211_sta *sta,
|
|
struct ieee80211_key_conf *keyconf,
|
|
struct ieee80211_key_conf *keyconf,
|
|
- bool have_key_offset)
|
|
|
|
|
|
+ u8 key_offset)
|
|
{
|
|
{
|
|
bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
|
|
bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
|
|
u8 sta_id;
|
|
u8 sta_id;
|
|
@@ -1443,7 +1459,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
|
lockdep_assert_held(&mvm->mutex);
|
|
lockdep_assert_held(&mvm->mutex);
|
|
|
|
|
|
/* Get the station id from the mvm local station table */
|
|
/* Get the station id from the mvm local station table */
|
|
- sta_id = iwl_mvm_get_key_sta_id(vif, sta);
|
|
|
|
|
|
+ sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
|
|
if (sta_id == IWL_MVM_STATION_COUNT) {
|
|
if (sta_id == IWL_MVM_STATION_COUNT) {
|
|
IWL_ERR(mvm, "Failed to find station id\n");
|
|
IWL_ERR(mvm, "Failed to find station id\n");
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -1470,18 +1486,25 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
|
if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
|
|
if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- if (!have_key_offset) {
|
|
|
|
- /*
|
|
|
|
- * The D3 firmware hardcodes the PTK offset to 0, so we have to
|
|
|
|
- * configure it there. As a result, this workaround exists to
|
|
|
|
- * let the caller set the key offset (hw_key_idx), see d3.c.
|
|
|
|
- */
|
|
|
|
- keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm);
|
|
|
|
- if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
|
|
|
|
|
|
+ /* If the key_offset is not pre-assigned, we need to find a
|
|
|
|
+ * new offset to use. In normal cases, the offset is not
|
|
|
|
+ * pre-assigned, but during HW_RESTART we want to reuse the
|
|
|
|
+ * same indices, so we pass them when this function is called.
|
|
|
|
+ *
|
|
|
|
+ * In D3 entry, we need to hardcoded the indices (because the
|
|
|
|
+ * firmware hardcodes the PTK offset to 0). In this case, we
|
|
|
|
+ * need to make sure we don't overwrite the hw_key_idx in the
|
|
|
|
+ * keyconf structure, because otherwise we cannot configure
|
|
|
|
+ * the original ones back when resuming.
|
|
|
|
+ */
|
|
|
|
+ if (key_offset == STA_KEY_IDX_INVALID) {
|
|
|
|
+ key_offset = iwl_mvm_set_fw_key_idx(mvm);
|
|
|
|
+ if (key_offset == STA_KEY_IDX_INVALID)
|
|
return -ENOSPC;
|
|
return -ENOSPC;
|
|
|
|
+ keyconf->hw_key_idx = key_offset;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, mcast);
|
|
|
|
|
|
+ ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, mcast);
|
|
if (ret) {
|
|
if (ret) {
|
|
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
|
|
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
|
|
goto end;
|
|
goto end;
|
|
@@ -1495,7 +1518,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
|
*/
|
|
*/
|
|
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
|
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
|
|
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
|
|
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
|
|
- ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, !mcast);
|
|
|
|
|
|
+ ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf,
|
|
|
|
+ key_offset, !mcast);
|
|
if (ret) {
|
|
if (ret) {
|
|
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
|
|
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
|
|
__iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
|
|
__iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
|
|
@@ -1521,7 +1545,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
|
|
lockdep_assert_held(&mvm->mutex);
|
|
lockdep_assert_held(&mvm->mutex);
|
|
|
|
|
|
/* Get the station id from the mvm local station table */
|
|
/* Get the station id from the mvm local station table */
|
|
- sta_id = iwl_mvm_get_key_sta_id(vif, sta);
|
|
|
|
|
|
+ sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
|
|
|
|
|
|
IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
|
|
IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
|
|
keyconf->keyidx, sta_id);
|
|
keyconf->keyidx, sta_id);
|
|
@@ -1547,24 +1571,6 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- /*
|
|
|
|
- * It is possible that the 'sta' parameter is NULL, and thus
|
|
|
|
- * there is a need to retrieve the sta from the local station table,
|
|
|
|
- * for example when a GTK is removed (where the sta_id will then be
|
|
|
|
- * the AP ID, and no station was passed by mac80211.)
|
|
|
|
- */
|
|
|
|
- if (!sta) {
|
|
|
|
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
|
|
|
|
- lockdep_is_held(&mvm->mutex));
|
|
|
|
- if (!sta) {
|
|
|
|
- IWL_ERR(mvm, "Invalid station id\n");
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
|
|
|
|
- return -EINVAL;
|
|
|
|
-
|
|
|
|
ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
|
|
ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
@@ -1584,7 +1590,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
|
|
u16 *phase1key)
|
|
u16 *phase1key)
|
|
{
|
|
{
|
|
struct iwl_mvm_sta *mvm_sta;
|
|
struct iwl_mvm_sta *mvm_sta;
|
|
- u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta);
|
|
|
|
|
|
+ u8 sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
|
|
bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
|
|
bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
|
|
|
|
|
|
if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
|
|
if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
|
|
@@ -1602,7 +1608,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
|
|
|
|
|
|
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
|
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
|
iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
|
|
iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
|
|
- iv32, phase1key, CMD_ASYNC);
|
|
|
|
|
|
+ iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx);
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
}
|
|
}
|
|
|
|
|