af_mpls: fix undefined reference to ip6_route_output
[cascardo/linux.git] / net / mac80211 / key.c
index a907f2d..b22df3a 100644 (file)
@@ -66,12 +66,15 @@ update_vlan_tailroom_need_count(struct ieee80211_sub_if_data *sdata, int delta)
        if (sdata->vif.type != NL80211_IFTYPE_AP)
                return;
 
-       mutex_lock(&sdata->local->mtx);
+       /* crypto_tx_tailroom_needed_cnt is protected by this */
+       assert_key_lock(sdata->local);
+
+       rcu_read_lock();
 
-       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+       list_for_each_entry_rcu(vlan, &sdata->u.ap.vlans, u.vlan.list)
                vlan->crypto_tx_tailroom_needed_cnt += delta;
 
-       mutex_unlock(&sdata->local->mtx);
+       rcu_read_unlock();
 }
 
 static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
@@ -95,6 +98,8 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
         * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
         */
 
+       assert_key_lock(sdata->local);
+
        update_vlan_tailroom_need_count(sdata, 1);
 
        if (!sdata->crypto_tx_tailroom_needed_cnt++) {
@@ -109,6 +114,8 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
 static void decrease_tailroom_need_count(struct ieee80211_sub_if_data *sdata,
                                         int delta)
 {
+       assert_key_lock(sdata->local);
+
        WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt < delta);
 
        update_vlan_tailroom_need_count(sdata, -delta);
@@ -147,7 +154,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
         * is supported; if not, return.
         */
        if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
-           !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK))
+           !ieee80211_hw_check(&key->local->hw, SUPPORTS_PER_STA_GTK))
                goto out_unsupported;
 
        if (sta && !sta->uploaded)
@@ -201,7 +208,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                /* all of these we can do in software - if driver can */
                if (ret == 1)
                        return 0;
-               if (key->local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL)
+               if (ieee80211_hw_check(&key->local->hw, SW_CRYPTO_CONTROL))
                        return -EINVAL;
                return 0;
        default:
@@ -256,6 +263,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
 
        if (uni) {
                rcu_assign_pointer(sdata->default_unicast_key, key);
+               ieee80211_check_fast_xmit_iface(sdata);
                drv_set_default_unicast_key(sdata->local, sdata, idx);
        }
 
@@ -325,6 +333,7 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
                if (pairwise) {
                        rcu_assign_pointer(sta->ptk[idx], new);
                        sta->ptk_idx = idx;
+                       ieee80211_check_fast_xmit(sta);
                } else {
                        rcu_assign_pointer(sta->gtk[idx], new);
                        sta->gtk_idx = idx;
@@ -510,15 +519,17 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                break;
        default:
                if (cs) {
-                       size_t len = (seq_len > MAX_PN_LEN) ?
-                                               MAX_PN_LEN : seq_len;
+                       if (seq_len && seq_len != cs->pn_len) {
+                               kfree(key);
+                               return ERR_PTR(-EINVAL);
+                       }
 
                        key->conf.iv_len = cs->hdr_len;
                        key->conf.icv_len = cs->mic_len;
                        for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
-                               for (j = 0; j < len; j++)
+                               for (j = 0; j < seq_len; j++)
                                        key->u.gen.rx_pn[i][j] =
-                                                       seq[len - j - 1];
+                                                       seq[seq_len - j - 1];
                        key->flags |= KEY_FLAG_CIPHER_SCHEME;
                }
        }
@@ -892,27 +903,19 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
                break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
-               pn64 = atomic64_read(&key->u.ccmp.tx_pn);
-               seq->ccmp.pn[5] = pn64;
-               seq->ccmp.pn[4] = pn64 >> 8;
-               seq->ccmp.pn[3] = pn64 >> 16;
-               seq->ccmp.pn[2] = pn64 >> 24;
-               seq->ccmp.pn[1] = pn64 >> 32;
-               seq->ccmp.pn[0] = pn64 >> 40;
-               break;
        case WLAN_CIPHER_SUITE_AES_CMAC:
        case WLAN_CIPHER_SUITE_BIP_CMAC_256:
-               pn64 = atomic64_read(&key->u.aes_cmac.tx_pn);
-               seq->ccmp.pn[5] = pn64;
-               seq->ccmp.pn[4] = pn64 >> 8;
-               seq->ccmp.pn[3] = pn64 >> 16;
-               seq->ccmp.pn[2] = pn64 >> 24;
-               seq->ccmp.pn[1] = pn64 >> 32;
-               seq->ccmp.pn[0] = pn64 >> 40;
-               break;
+               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
+                            offsetof(typeof(*seq), aes_cmac));
        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
-               pn64 = atomic64_read(&key->u.aes_gmac.tx_pn);
+               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
+                            offsetof(typeof(*seq), aes_gmac));
+       case WLAN_CIPHER_SUITE_GCMP:
+       case WLAN_CIPHER_SUITE_GCMP_256:
+               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
+                            offsetof(typeof(*seq), gcmp));
+               pn64 = atomic64_read(&key->conf.tx_pn);
                seq->ccmp.pn[5] = pn64;
                seq->ccmp.pn[4] = pn64 >> 8;
                seq->ccmp.pn[3] = pn64 >> 16;
@@ -920,16 +923,6 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
                seq->ccmp.pn[1] = pn64 >> 32;
                seq->ccmp.pn[0] = pn64 >> 40;
                break;
-       case WLAN_CIPHER_SUITE_GCMP:
-       case WLAN_CIPHER_SUITE_GCMP_256:
-               pn64 = atomic64_read(&key->u.gcmp.tx_pn);
-               seq->gcmp.pn[5] = pn64;
-               seq->gcmp.pn[4] = pn64 >> 8;
-               seq->gcmp.pn[3] = pn64 >> 16;
-               seq->gcmp.pn[2] = pn64 >> 24;
-               seq->gcmp.pn[1] = pn64 >> 32;
-               seq->gcmp.pn[0] = pn64 >> 40;
-               break;
        default:
                WARN_ON(1);
        }
@@ -1004,43 +997,25 @@ void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
                break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
-               pn64 = (u64)seq->ccmp.pn[5] |
-                      ((u64)seq->ccmp.pn[4] << 8) |
-                      ((u64)seq->ccmp.pn[3] << 16) |
-                      ((u64)seq->ccmp.pn[2] << 24) |
-                      ((u64)seq->ccmp.pn[1] << 32) |
-                      ((u64)seq->ccmp.pn[0] << 40);
-               atomic64_set(&key->u.ccmp.tx_pn, pn64);
-               break;
        case WLAN_CIPHER_SUITE_AES_CMAC:
        case WLAN_CIPHER_SUITE_BIP_CMAC_256:
-               pn64 = (u64)seq->aes_cmac.pn[5] |
-                      ((u64)seq->aes_cmac.pn[4] << 8) |
-                      ((u64)seq->aes_cmac.pn[3] << 16) |
-                      ((u64)seq->aes_cmac.pn[2] << 24) |
-                      ((u64)seq->aes_cmac.pn[1] << 32) |
-                      ((u64)seq->aes_cmac.pn[0] << 40);
-               atomic64_set(&key->u.aes_cmac.tx_pn, pn64);
-               break;
+               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
+                            offsetof(typeof(*seq), aes_cmac));
        case WLAN_CIPHER_SUITE_BIP_GMAC_128:
        case WLAN_CIPHER_SUITE_BIP_GMAC_256:
-               pn64 = (u64)seq->aes_gmac.pn[5] |
-                      ((u64)seq->aes_gmac.pn[4] << 8) |
-                      ((u64)seq->aes_gmac.pn[3] << 16) |
-                      ((u64)seq->aes_gmac.pn[2] << 24) |
-                      ((u64)seq->aes_gmac.pn[1] << 32) |
-                      ((u64)seq->aes_gmac.pn[0] << 40);
-               atomic64_set(&key->u.aes_gmac.tx_pn, pn64);
-               break;
+               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
+                            offsetof(typeof(*seq), aes_gmac));
        case WLAN_CIPHER_SUITE_GCMP:
        case WLAN_CIPHER_SUITE_GCMP_256:
-               pn64 = (u64)seq->gcmp.pn[5] |
-                      ((u64)seq->gcmp.pn[4] << 8) |
-                      ((u64)seq->gcmp.pn[3] << 16) |
-                      ((u64)seq->gcmp.pn[2] << 24) |
-                      ((u64)seq->gcmp.pn[1] << 32) |
-                      ((u64)seq->gcmp.pn[0] << 40);
-               atomic64_set(&key->u.gcmp.tx_pn, pn64);
+               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
+                            offsetof(typeof(*seq), gcmp));
+               pn64 = (u64)seq->ccmp.pn[5] |
+                      ((u64)seq->ccmp.pn[4] << 8) |
+                      ((u64)seq->ccmp.pn[3] << 16) |
+                      ((u64)seq->ccmp.pn[2] << 24) |
+                      ((u64)seq->ccmp.pn[1] << 32) |
+                      ((u64)seq->ccmp.pn[0] << 40);
+               atomic64_set(&key->conf.tx_pn, pn64);
                break;
        default:
                WARN_ON(1);