]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/mac80211/key.c
Merge tag 'mac80211-next-for-davem-2019-04-26' of git://git.kernel.org/pub/scm/linux...
[linux.git] / net / mac80211 / key.c
index 37e372896230a08c6a9214f88ce54e7ad823d352..20bf9db7a3886de7601fabd0e0ff2c721e54e30e 100644 (file)
@@ -140,6 +140,12 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                 * so clear that flag now to avoid trying to remove
                 * it again later.
                 */
+               if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
+                   !(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
+                                        IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
+                                        IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
+                       increment_tailroom_need_count(sdata);
+
                key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
                return -EINVAL;
        }
@@ -179,9 +185,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
        if (!ret) {
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
-               if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
-                                          IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
+               if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
+                                        IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
+                                        IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
                        decrease_tailroom_need_count(sdata, 1);
 
                WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
@@ -242,9 +248,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
        sta = key->sta;
        sdata = key->sdata;
 
-       if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
-                                  IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
+       if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
+                                IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
+                                IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
                increment_tailroom_need_count(sdata);
 
        key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
@@ -258,9 +264,24 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                          sta ? sta->sta.addr : bcast_addr, ret);
 }
 
+int ieee80211_set_tx_key(struct ieee80211_key *key)
+{
+       struct sta_info *sta = key->sta;
+       struct ieee80211_local *local = key->local;
+       struct ieee80211_key *old;
+
+       assert_key_lock(local);
+
+       old = key_mtx_dereference(local, sta->ptk[sta->ptk_idx]);
+       sta->ptk_idx = key->conf.keyidx;
+       ieee80211_check_fast_xmit(sta);
+
+       return 0;
+}
+
 static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
                                    struct ieee80211_key *new_key,
-                                   bool ptk0rekey)
+                                   bool pairwise)
 {
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_local *local;
@@ -277,8 +298,9 @@ static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
        assert_key_lock(old_key->local);
        sta = old_key->sta;
 
-       /* PTK only using key ID 0 needs special handling on rekey */
-       if (new_key && sta && ptk0rekey) {
+       /* Unicast rekey without Extended Key ID needs special handling */
+       if (new_key && sta && pairwise &&
+           rcu_access_pointer(sta->ptk[sta->ptk_idx]) == old_key) {
                local = old_key->local;
                sdata = old_key->sdata;
 
@@ -394,10 +416,6 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
 
        if (old) {
                idx = old->conf.keyidx;
-               /* TODO: proper implement and test "Extended Key ID for
-                * Individually Addressed Frames" from IEEE 802.11-2016.
-                * Till then always assume only key ID 0 is used for
-                * pairwise keys.*/
                ret = ieee80211_hw_key_replace(old, new, pairwise);
        } else {
                /* new must be provided in case old is not */
@@ -414,15 +432,20 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
        if (sta) {
                if (pairwise) {
                        rcu_assign_pointer(sta->ptk[idx], new);
-                       sta->ptk_idx = idx;
-                       if (new) {
+                       if (new &&
+                           !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) {
+                               sta->ptk_idx = idx;
                                clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
                                ieee80211_check_fast_xmit(sta);
                        }
                } else {
                        rcu_assign_pointer(sta->gtk[idx], new);
                }
-               if (new)
+               /* Only needed for transition from no key -> key.
+                * Still triggers unnecessary when using Extended Key ID
+                * and installing the second key ID the first time.
+                */
+               if (new && !old)
                        ieee80211_check_fast_rx(sta);
        } else {
                defunikey = old &&
@@ -738,16 +761,34 @@ int ieee80211_key_link(struct ieee80211_key *key,
         * can cause warnings to appear.
         */
        bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
-       int ret;
+       int ret = -EOPNOTSUPP;
 
        mutex_lock(&sdata->local->key_mtx);
 
-       if (sta && pairwise)
+       if (sta && pairwise) {
+               struct ieee80211_key *alt_key;
+
                old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
-       else if (sta)
+               alt_key = key_mtx_dereference(sdata->local, sta->ptk[idx ^ 1]);
+
+               /* The rekey code assumes that the old and new key are using
+                * the same cipher. Enforce the assumption for pairwise keys.
+                */
+               if (key &&
+                   ((alt_key && alt_key->conf.cipher != key->conf.cipher) ||
+                    (old_key && old_key->conf.cipher != key->conf.cipher)))
+                       goto out;
+       } else if (sta) {
                old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
-       else
+       } else {
                old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
+       }
+
+       /* Non-pairwise keys must also not switch the cipher on rekey */
+       if (!pairwise) {
+               if (key && old_key && old_key->conf.cipher != key->conf.cipher)
+                       goto out;
+       }
 
        /*
         * Silently accept key re-installation without really installing the
@@ -1187,9 +1228,9 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
        if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
                key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 
-               if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
-                                          IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
+               if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
+                                        IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
+                                        IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
                        increment_tailroom_need_count(key->sdata);
        }