Merge tag 'mac80211-next-for-davem-2015-08-14' into next
[linux-drm-fsl-dcu.git] / drivers / net / wireless / iwlwifi / mvm / sta.c
index 3d2fbf1bc22656b9f68ff22dda7be43ba11862b6..df216cd0c98f4659d1c00d7d07c8adb31c8244c6 100644 (file)
@@ -1148,18 +1148,31 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
 static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
 {
-       int i;
+       int i, max = -1, max_offs = -1;
 
        lockdep_assert_held(&mvm->mutex);
 
-       i = find_first_zero_bit(mvm->fw_key_table, STA_KEY_MAX_NUM);
+       /* Pick the unused key offset with the highest 'deleted'
+        * counter. Every time a key is deleted, all the counters
+        * are incremented and the one that was just deleted is
+        * reset to zero. Thus, the highest counter is the one
+        * that was deleted longest ago. Pick that one.
+        */
+       for (i = 0; i < STA_KEY_MAX_NUM; i++) {
+               if (test_bit(i, mvm->fw_key_table))
+                       continue;
+               if (mvm->fw_key_deleted[i] > max) {
+                       max = mvm->fw_key_deleted[i];
+                       max_offs = i;
+               }
+       }
 
-       if (i == STA_KEY_MAX_NUM)
+       if (max_offs < 0)
                return STA_KEY_IDX_INVALID;
 
-       __set_bit(i, mvm->fw_key_table);
+       __set_bit(max_offs, mvm->fw_key_table);
 
-       return i;
+       return max_offs;
 }
 
 static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
@@ -1399,6 +1412,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
        u8 sta_id;
        int ret;
+       static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0};
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -1465,7 +1479,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
 end:
        IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
                      keyconf->cipher, keyconf->keylen, keyconf->keyidx,
-                     sta->addr, ret);
+                     sta ? sta->addr : zero_addr, ret);
        return ret;
 }
 
@@ -1476,7 +1490,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
 {
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
        u8 sta_id;
-       int ret;
+       int ret, i;
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -1495,6 +1509,13 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
                return -ENOENT;
        }
 
+       /* track which key was deleted last */
+       for (i = 0; i < STA_KEY_MAX_NUM; i++) {
+               if (mvm->fw_key_deleted[i] < U8_MAX)
+                       mvm->fw_key_deleted[i]++;
+       }
+       mvm->fw_key_deleted[keyconf->hw_key_idx] = 0;
+
        if (sta_id == IWL_MVM_STATION_COUNT) {
                IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");
                return 0;
@@ -1658,9 +1679,8 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
 
-int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
-                         struct iwl_rx_cmd_buffer *rxb,
-                         struct iwl_device_cmd *cmd)
+void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
+                          struct iwl_rx_cmd_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_mvm_eosp_notification *notif = (void *)pkt->data;
@@ -1668,15 +1688,13 @@ int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
        u32 sta_id = le32_to_cpu(notif->sta_id);
 
        if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT))
-               return 0;
+               return;
 
        rcu_read_lock();
        sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
        if (!IS_ERR_OR_NULL(sta))
                ieee80211_sta_eosp(sta);
        rcu_read_unlock();
-
-       return 0;
 }
 
 void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm,