diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/mac80211/aes_cmac.c | 34 | ||||
| -rw-r--r-- | net/mac80211/aes_cmac.h | 5 | ||||
| -rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
| -rw-r--r-- | net/mac80211/debugfs_key.c | 4 | ||||
| -rw-r--r-- | net/mac80211/key.c | 14 | ||||
| -rw-r--r-- | net/mac80211/main.c | 13 | ||||
| -rw-r--r-- | net/mac80211/rx.c | 21 | ||||
| -rw-r--r-- | net/mac80211/tx.c | 3 | ||||
| -rw-r--r-- | net/mac80211/wpa.c | 92 | ||||
| -rw-r--r-- | net/mac80211/wpa.h | 4 |
10 files changed, 171 insertions, 21 deletions
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index 9b9009f99551..4192806be3d3 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c | |||
| @@ -18,8 +18,8 @@ | |||
| 18 | #include "key.h" | 18 | #include "key.h" |
| 19 | #include "aes_cmac.h" | 19 | #include "aes_cmac.h" |
| 20 | 20 | ||
| 21 | #define AES_CMAC_KEY_LEN 16 | ||
| 22 | #define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ | 21 | #define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ |
| 22 | #define CMAC_TLEN_256 16 /* CMAC TLen = 128 bits (16 octets) */ | ||
| 23 | #define AAD_LEN 20 | 23 | #define AAD_LEN 20 |
| 24 | 24 | ||
| 25 | 25 | ||
| @@ -35,9 +35,9 @@ static void gf_mulx(u8 *pad) | |||
| 35 | pad[AES_BLOCK_SIZE - 1] ^= 0x87; | 35 | pad[AES_BLOCK_SIZE - 1] ^= 0x87; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | 38 | static void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, | |
| 39 | static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, | 39 | const u8 *addr[], const size_t *len, u8 *mac, |
| 40 | const u8 *addr[], const size_t *len, u8 *mac) | 40 | size_t mac_len) |
| 41 | { | 41 | { |
| 42 | u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; | 42 | u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; |
| 43 | const u8 *pos, *end; | 43 | const u8 *pos, *end; |
| @@ -88,7 +88,7 @@ static void aes_128_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, | |||
| 88 | for (i = 0; i < AES_BLOCK_SIZE; i++) | 88 | for (i = 0; i < AES_BLOCK_SIZE; i++) |
| 89 | pad[i] ^= cbc[i]; | 89 | pad[i] ^= cbc[i]; |
| 90 | crypto_cipher_encrypt_one(tfm, pad, pad); | 90 | crypto_cipher_encrypt_one(tfm, pad, pad); |
| 91 | memcpy(mac, pad, CMAC_TLEN); | 91 | memcpy(mac, pad, mac_len); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | 94 | ||
| @@ -107,17 +107,35 @@ void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, | |||
| 107 | addr[2] = zero; | 107 | addr[2] = zero; |
| 108 | len[2] = CMAC_TLEN; | 108 | len[2] = CMAC_TLEN; |
| 109 | 109 | ||
| 110 | aes_128_cmac_vector(tfm, 3, addr, len, mic); | 110 | aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad, | ||
| 114 | const u8 *data, size_t data_len, u8 *mic) | ||
| 115 | { | ||
| 116 | const u8 *addr[3]; | ||
| 117 | size_t len[3]; | ||
| 118 | u8 zero[CMAC_TLEN_256]; | ||
| 119 | |||
| 120 | memset(zero, 0, CMAC_TLEN_256); | ||
| 121 | addr[0] = aad; | ||
| 122 | len[0] = AAD_LEN; | ||
| 123 | addr[1] = data; | ||
| 124 | len[1] = data_len - CMAC_TLEN_256; | ||
| 125 | addr[2] = zero; | ||
| 126 | len[2] = CMAC_TLEN_256; | ||
| 127 | |||
| 128 | aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN_256); | ||
| 129 | } | ||
| 113 | 130 | ||
| 114 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]) | 131 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[], |
| 132 | size_t key_len) | ||
| 115 | { | 133 | { |
| 116 | struct crypto_cipher *tfm; | 134 | struct crypto_cipher *tfm; |
| 117 | 135 | ||
| 118 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | 136 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); |
| 119 | if (!IS_ERR(tfm)) | 137 | if (!IS_ERR(tfm)) |
| 120 | crypto_cipher_setkey(tfm, key, AES_CMAC_KEY_LEN); | 138 | crypto_cipher_setkey(tfm, key, key_len); |
| 121 | 139 | ||
| 122 | return tfm; | 140 | return tfm; |
| 123 | } | 141 | } |
diff --git a/net/mac80211/aes_cmac.h b/net/mac80211/aes_cmac.h index 0ce6487af795..3702041f44fd 100644 --- a/net/mac80211/aes_cmac.h +++ b/net/mac80211/aes_cmac.h | |||
| @@ -11,9 +11,12 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/crypto.h> | 12 | #include <linux/crypto.h> |
| 13 | 13 | ||
| 14 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]); | 14 | struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[], |
| 15 | size_t key_len); | ||
| 15 | void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, | 16 | void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, |
| 16 | const u8 *data, size_t data_len, u8 *mic); | 17 | const u8 *data, size_t data_len, u8 *mic); |
| 18 | void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad, | ||
| 19 | const u8 *data, size_t data_len, u8 *mic); | ||
| 17 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); | 20 | void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); |
| 18 | 21 | ||
| 19 | #endif /* AES_CMAC_H */ | 22 | #endif /* AES_CMAC_H */ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ef84441c119c..b7e528bbecce 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -164,6 +164,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 164 | case WLAN_CIPHER_SUITE_CCMP: | 164 | case WLAN_CIPHER_SUITE_CCMP: |
| 165 | case WLAN_CIPHER_SUITE_CCMP_256: | 165 | case WLAN_CIPHER_SUITE_CCMP_256: |
| 166 | case WLAN_CIPHER_SUITE_AES_CMAC: | 166 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 167 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 167 | case WLAN_CIPHER_SUITE_GCMP: | 168 | case WLAN_CIPHER_SUITE_GCMP: |
| 168 | case WLAN_CIPHER_SUITE_GCMP_256: | 169 | case WLAN_CIPHER_SUITE_GCMP_256: |
| 169 | break; | 170 | break; |
| @@ -362,6 +363,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 362 | params.seq_len = 6; | 363 | params.seq_len = 6; |
| 363 | break; | 364 | break; |
| 364 | case WLAN_CIPHER_SUITE_AES_CMAC: | 365 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 366 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 365 | pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); | 367 | pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); |
| 366 | seq[0] = pn64; | 368 | seq[0] = pn64; |
| 367 | seq[1] = pn64 >> 8; | 369 | seq[1] = pn64 >> 8; |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 64de07b16092..d1b60eb014a8 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
| @@ -101,6 +101,7 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, | |||
| 101 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); | 101 | (u8)(pn >> 16), (u8)(pn >> 8), (u8)pn); |
| 102 | break; | 102 | break; |
| 103 | case WLAN_CIPHER_SUITE_AES_CMAC: | 103 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 104 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 104 | pn = atomic64_read(&key->u.aes_cmac.tx_pn); | 105 | pn = atomic64_read(&key->u.aes_cmac.tx_pn); |
| 105 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", | 106 | len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", |
| 106 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), | 107 | (u8)(pn >> 40), (u8)(pn >> 32), (u8)(pn >> 24), |
| @@ -153,6 +154,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
| 153 | len = p - buf; | 154 | len = p - buf; |
| 154 | break; | 155 | break; |
| 155 | case WLAN_CIPHER_SUITE_AES_CMAC: | 156 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 157 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 156 | rpn = key->u.aes_cmac.rx_pn; | 158 | rpn = key->u.aes_cmac.rx_pn; |
| 157 | p += scnprintf(p, sizeof(buf)+buf-p, | 159 | p += scnprintf(p, sizeof(buf)+buf-p, |
| 158 | "%02x%02x%02x%02x%02x%02x\n", | 160 | "%02x%02x%02x%02x%02x%02x\n", |
| @@ -191,6 +193,7 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf, | |||
| 191 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); | 193 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); |
| 192 | break; | 194 | break; |
| 193 | case WLAN_CIPHER_SUITE_AES_CMAC: | 195 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 196 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 194 | len = scnprintf(buf, sizeof(buf), "%u\n", | 197 | len = scnprintf(buf, sizeof(buf), "%u\n", |
| 195 | key->u.aes_cmac.replays); | 198 | key->u.aes_cmac.replays); |
| 196 | break; | 199 | break; |
| @@ -214,6 +217,7 @@ static ssize_t key_icverrors_read(struct file *file, char __user *userbuf, | |||
| 214 | 217 | ||
| 215 | switch (key->conf.cipher) { | 218 | switch (key->conf.cipher) { |
| 216 | case WLAN_CIPHER_SUITE_AES_CMAC: | 219 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 220 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 217 | len = scnprintf(buf, sizeof(buf), "%u\n", | 221 | len = scnprintf(buf, sizeof(buf), "%u\n", |
| 218 | key->u.aes_cmac.icverrors); | 222 | key->u.aes_cmac.icverrors); |
| 219 | break; | 223 | break; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 83c61085c3f0..7ceea9d9fcd2 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
| @@ -165,6 +165,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
| 165 | case WLAN_CIPHER_SUITE_CCMP: | 165 | case WLAN_CIPHER_SUITE_CCMP: |
| 166 | case WLAN_CIPHER_SUITE_CCMP_256: | 166 | case WLAN_CIPHER_SUITE_CCMP_256: |
| 167 | case WLAN_CIPHER_SUITE_AES_CMAC: | 167 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 168 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 168 | case WLAN_CIPHER_SUITE_GCMP: | 169 | case WLAN_CIPHER_SUITE_GCMP: |
| 169 | case WLAN_CIPHER_SUITE_GCMP_256: | 170 | case WLAN_CIPHER_SUITE_GCMP_256: |
| 170 | /* all of these we can do in software - if driver can */ | 171 | /* all of these we can do in software - if driver can */ |
| @@ -417,8 +418,12 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
| 417 | } | 418 | } |
| 418 | break; | 419 | break; |
| 419 | case WLAN_CIPHER_SUITE_AES_CMAC: | 420 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 421 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 420 | key->conf.iv_len = 0; | 422 | key->conf.iv_len = 0; |
| 421 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | 423 | if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
| 424 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | ||
| 425 | else | ||
| 426 | key->conf.icv_len = sizeof(struct ieee80211_mmie_16); | ||
| 422 | if (seq) | 427 | if (seq) |
| 423 | for (j = 0; j < IEEE80211_CMAC_PN_LEN; j++) | 428 | for (j = 0; j < IEEE80211_CMAC_PN_LEN; j++) |
| 424 | key->u.aes_cmac.rx_pn[j] = | 429 | key->u.aes_cmac.rx_pn[j] = |
| @@ -428,7 +433,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
| 428 | * it does not need to be initialized for every packet. | 433 | * it does not need to be initialized for every packet. |
| 429 | */ | 434 | */ |
| 430 | key->u.aes_cmac.tfm = | 435 | key->u.aes_cmac.tfm = |
| 431 | ieee80211_aes_cmac_key_setup(key_data); | 436 | ieee80211_aes_cmac_key_setup(key_data, key_len); |
| 432 | if (IS_ERR(key->u.aes_cmac.tfm)) { | 437 | if (IS_ERR(key->u.aes_cmac.tfm)) { |
| 433 | err = PTR_ERR(key->u.aes_cmac.tfm); | 438 | err = PTR_ERR(key->u.aes_cmac.tfm); |
| 434 | kfree(key); | 439 | kfree(key); |
| @@ -481,6 +486,7 @@ static void ieee80211_key_free_common(struct ieee80211_key *key) | |||
| 481 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 486 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
| 482 | break; | 487 | break; |
| 483 | case WLAN_CIPHER_SUITE_AES_CMAC: | 488 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 489 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 484 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 490 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
| 485 | break; | 491 | break; |
| 486 | case WLAN_CIPHER_SUITE_GCMP: | 492 | case WLAN_CIPHER_SUITE_GCMP: |
| @@ -804,6 +810,7 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
| 804 | seq->ccmp.pn[0] = pn64 >> 40; | 810 | seq->ccmp.pn[0] = pn64 >> 40; |
| 805 | break; | 811 | break; |
| 806 | case WLAN_CIPHER_SUITE_AES_CMAC: | 812 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 813 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 807 | pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); | 814 | pn64 = atomic64_read(&key->u.aes_cmac.tx_pn); |
| 808 | seq->ccmp.pn[5] = pn64; | 815 | seq->ccmp.pn[5] = pn64; |
| 809 | seq->ccmp.pn[4] = pn64 >> 8; | 816 | seq->ccmp.pn[4] = pn64 >> 8; |
| @@ -854,6 +861,7 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
| 854 | memcpy(seq->ccmp.pn, pn, IEEE80211_CCMP_PN_LEN); | 861 | memcpy(seq->ccmp.pn, pn, IEEE80211_CCMP_PN_LEN); |
| 855 | break; | 862 | break; |
| 856 | case WLAN_CIPHER_SUITE_AES_CMAC: | 863 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 864 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 857 | if (WARN_ON(tid != 0)) | 865 | if (WARN_ON(tid != 0)) |
| 858 | return; | 866 | return; |
| 859 | pn = key->u.aes_cmac.rx_pn; | 867 | pn = key->u.aes_cmac.rx_pn; |
| @@ -897,6 +905,7 @@ void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf, | |||
| 897 | atomic64_set(&key->u.ccmp.tx_pn, pn64); | 905 | atomic64_set(&key->u.ccmp.tx_pn, pn64); |
| 898 | break; | 906 | break; |
| 899 | case WLAN_CIPHER_SUITE_AES_CMAC: | 907 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 908 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 900 | pn64 = (u64)seq->aes_cmac.pn[5] | | 909 | pn64 = (u64)seq->aes_cmac.pn[5] | |
| 901 | ((u64)seq->aes_cmac.pn[4] << 8) | | 910 | ((u64)seq->aes_cmac.pn[4] << 8) | |
| 902 | ((u64)seq->aes_cmac.pn[3] << 16) | | 911 | ((u64)seq->aes_cmac.pn[3] << 16) | |
| @@ -948,6 +957,7 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
| 948 | memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN); | 957 | memcpy(pn, seq->ccmp.pn, IEEE80211_CCMP_PN_LEN); |
| 949 | break; | 958 | break; |
| 950 | case WLAN_CIPHER_SUITE_AES_CMAC: | 959 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 960 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 951 | if (WARN_ON(tid != 0)) | 961 | if (WARN_ON(tid != 0)) |
| 952 | return; | 962 | return; |
| 953 | pn = key->u.aes_cmac.rx_pn; | 963 | pn = key->u.aes_cmac.rx_pn; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index a5ad2d5bb29b..053a17c5023a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -671,7 +671,8 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
| 671 | WLAN_CIPHER_SUITE_GCMP_256, | 671 | WLAN_CIPHER_SUITE_GCMP_256, |
| 672 | 672 | ||
| 673 | /* keep last -- depends on hw flags! */ | 673 | /* keep last -- depends on hw flags! */ |
| 674 | WLAN_CIPHER_SUITE_AES_CMAC | 674 | WLAN_CIPHER_SUITE_AES_CMAC, |
| 675 | WLAN_CIPHER_SUITE_BIP_CMAC_256, | ||
| 675 | }; | 676 | }; |
| 676 | 677 | ||
| 677 | if (local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL || | 678 | if (local->hw.flags & IEEE80211_HW_SW_CRYPTO_CONTROL || |
| @@ -710,7 +711,7 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
| 710 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 711 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
| 711 | 712 | ||
| 712 | if (!have_mfp) | 713 | if (!have_mfp) |
| 713 | local->hw.wiphy->n_cipher_suites--; | 714 | local->hw.wiphy->n_cipher_suites -= 2; |
| 714 | 715 | ||
| 715 | if (!have_wep) { | 716 | if (!have_wep) { |
| 716 | local->hw.wiphy->cipher_suites += 2; | 717 | local->hw.wiphy->cipher_suites += 2; |
| @@ -736,9 +737,9 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
| 736 | if (have_wep) | 737 | if (have_wep) |
| 737 | n_suites += 2; | 738 | n_suites += 2; |
| 738 | 739 | ||
| 739 | /* check if we have AES_CMAC */ | 740 | /* check if we have AES_CMAC, BIP-CMAC-256 */ |
| 740 | if (have_mfp) | 741 | if (have_mfp) |
| 741 | n_suites++; | 742 | n_suites += 2; |
| 742 | 743 | ||
| 743 | suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); | 744 | suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); |
| 744 | if (!suites) | 745 | if (!suites) |
| @@ -755,8 +756,10 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | |||
| 755 | suites[w++] = WLAN_CIPHER_SUITE_WEP104; | 756 | suites[w++] = WLAN_CIPHER_SUITE_WEP104; |
| 756 | } | 757 | } |
| 757 | 758 | ||
| 758 | if (have_mfp) | 759 | if (have_mfp) { |
| 759 | suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; | 760 | suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; |
| 761 | suites[w++] = WLAN_CIPHER_SUITE_BIP_CMAC_256; | ||
| 762 | } | ||
| 760 | 763 | ||
| 761 | for (r = 0; r < local->hw.n_cipher_schemes; r++) | 764 | for (r = 0; r < local->hw.n_cipher_schemes; r++) |
| 762 | suites[w++] = cs[r].cipher; | 765 | suites[w++] = cs[r].cipher; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e8c6ba5ce70b..93ebc9525478 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -647,6 +647,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
| 647 | { | 647 | { |
| 648 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; | 648 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; |
| 649 | struct ieee80211_mmie *mmie; | 649 | struct ieee80211_mmie *mmie; |
| 650 | struct ieee80211_mmie_16 *mmie16; | ||
| 650 | 651 | ||
| 651 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) | 652 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) |
| 652 | return -1; | 653 | return -1; |
| @@ -656,11 +657,18 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
| 656 | 657 | ||
| 657 | mmie = (struct ieee80211_mmie *) | 658 | mmie = (struct ieee80211_mmie *) |
| 658 | (skb->data + skb->len - sizeof(*mmie)); | 659 | (skb->data + skb->len - sizeof(*mmie)); |
| 659 | if (mmie->element_id != WLAN_EID_MMIE || | 660 | if (mmie->element_id == WLAN_EID_MMIE && |
| 660 | mmie->length != sizeof(*mmie) - 2) | 661 | mmie->length == sizeof(*mmie) - 2) |
| 661 | return -1; | 662 | return le16_to_cpu(mmie->key_id); |
| 662 | 663 | ||
| 663 | return le16_to_cpu(mmie->key_id); | 664 | mmie16 = (struct ieee80211_mmie_16 *) |
| 665 | (skb->data + skb->len - sizeof(*mmie16)); | ||
| 666 | if (skb->len >= 24 + sizeof(*mmie16) && | ||
| 667 | mmie16->element_id == WLAN_EID_MMIE && | ||
| 668 | mmie16->length == sizeof(*mmie16) - 2) | ||
| 669 | return le16_to_cpu(mmie16->key_id); | ||
| 670 | |||
| 671 | return -1; | ||
| 664 | } | 672 | } |
| 665 | 673 | ||
| 666 | static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, | 674 | static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, |
| @@ -1660,6 +1668,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
| 1660 | case WLAN_CIPHER_SUITE_AES_CMAC: | 1668 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 1661 | result = ieee80211_crypto_aes_cmac_decrypt(rx); | 1669 | result = ieee80211_crypto_aes_cmac_decrypt(rx); |
| 1662 | break; | 1670 | break; |
| 1671 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 1672 | result = ieee80211_crypto_aes_cmac_256_decrypt(rx); | ||
| 1673 | break; | ||
| 1663 | case WLAN_CIPHER_SUITE_GCMP: | 1674 | case WLAN_CIPHER_SUITE_GCMP: |
| 1664 | case WLAN_CIPHER_SUITE_GCMP_256: | 1675 | case WLAN_CIPHER_SUITE_GCMP_256: |
| 1665 | result = ieee80211_crypto_gcmp_decrypt(rx); | 1676 | result = ieee80211_crypto_gcmp_decrypt(rx); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index be57e0afd019..909c27be1fdc 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -639,6 +639,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
| 639 | ieee80211_is_mgmt(hdr->frame_control); | 639 | ieee80211_is_mgmt(hdr->frame_control); |
| 640 | break; | 640 | break; |
| 641 | case WLAN_CIPHER_SUITE_AES_CMAC: | 641 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 642 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 642 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 643 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
| 643 | tx->key = NULL; | 644 | tx->key = NULL; |
| 644 | break; | 645 | break; |
| @@ -1021,6 +1022,8 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
| 1021 | tx, IEEE80211_CCMP_256_MIC_LEN); | 1022 | tx, IEEE80211_CCMP_256_MIC_LEN); |
| 1022 | case WLAN_CIPHER_SUITE_AES_CMAC: | 1023 | case WLAN_CIPHER_SUITE_AES_CMAC: |
| 1023 | return ieee80211_crypto_aes_cmac_encrypt(tx); | 1024 | return ieee80211_crypto_aes_cmac_encrypt(tx); |
| 1025 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | ||
| 1026 | return ieee80211_crypto_aes_cmac_256_encrypt(tx); | ||
| 1024 | case WLAN_CIPHER_SUITE_GCMP: | 1027 | case WLAN_CIPHER_SUITE_GCMP: |
| 1025 | case WLAN_CIPHER_SUITE_GCMP_256: | 1028 | case WLAN_CIPHER_SUITE_GCMP_256: |
| 1026 | return ieee80211_crypto_gcmp_encrypt(tx); | 1029 | return ieee80211_crypto_gcmp_encrypt(tx); |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index ae654de9782a..549af118de9f 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
| @@ -955,6 +955,48 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) | |||
| 955 | return TX_CONTINUE; | 955 | return TX_CONTINUE; |
| 956 | } | 956 | } |
| 957 | 957 | ||
| 958 | ieee80211_tx_result | ||
| 959 | ieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx) | ||
| 960 | { | ||
| 961 | struct sk_buff *skb; | ||
| 962 | struct ieee80211_tx_info *info; | ||
| 963 | struct ieee80211_key *key = tx->key; | ||
| 964 | struct ieee80211_mmie_16 *mmie; | ||
| 965 | u8 aad[20]; | ||
| 966 | u64 pn64; | ||
| 967 | |||
| 968 | if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) | ||
| 969 | return TX_DROP; | ||
| 970 | |||
| 971 | skb = skb_peek(&tx->skbs); | ||
| 972 | |||
| 973 | info = IEEE80211_SKB_CB(skb); | ||
| 974 | |||
| 975 | if (info->control.hw_key) | ||
| 976 | return TX_CONTINUE; | ||
| 977 | |||
| 978 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) | ||
| 979 | return TX_DROP; | ||
| 980 | |||
| 981 | mmie = (struct ieee80211_mmie_16 *)skb_put(skb, sizeof(*mmie)); | ||
| 982 | mmie->element_id = WLAN_EID_MMIE; | ||
| 983 | mmie->length = sizeof(*mmie) - 2; | ||
| 984 | mmie->key_id = cpu_to_le16(key->conf.keyidx); | ||
| 985 | |||
| 986 | /* PN = PN + 1 */ | ||
| 987 | pn64 = atomic64_inc_return(&key->u.aes_cmac.tx_pn); | ||
| 988 | |||
| 989 | bip_ipn_set64(mmie->sequence_number, pn64); | ||
| 990 | |||
| 991 | bip_aad(skb, aad); | ||
| 992 | |||
| 993 | /* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128) | ||
| 994 | */ | ||
| 995 | ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, | ||
| 996 | skb->data + 24, skb->len - 24, mmie->mic); | ||
| 997 | |||
| 998 | return TX_CONTINUE; | ||
| 999 | } | ||
| 958 | 1000 | ||
| 959 | ieee80211_rx_result | 1001 | ieee80211_rx_result |
| 960 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) | 1002 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) |
| @@ -1006,6 +1048,56 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx) | |||
| 1006 | return RX_CONTINUE; | 1048 | return RX_CONTINUE; |
| 1007 | } | 1049 | } |
| 1008 | 1050 | ||
| 1051 | ieee80211_rx_result | ||
| 1052 | ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx) | ||
| 1053 | { | ||
| 1054 | struct sk_buff *skb = rx->skb; | ||
| 1055 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
| 1056 | struct ieee80211_key *key = rx->key; | ||
| 1057 | struct ieee80211_mmie_16 *mmie; | ||
| 1058 | u8 aad[20], mic[16], ipn[6]; | ||
| 1059 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
| 1060 | |||
| 1061 | if (!ieee80211_is_mgmt(hdr->frame_control)) | ||
| 1062 | return RX_CONTINUE; | ||
| 1063 | |||
| 1064 | /* management frames are already linear */ | ||
| 1065 | |||
| 1066 | if (skb->len < 24 + sizeof(*mmie)) | ||
| 1067 | return RX_DROP_UNUSABLE; | ||
| 1068 | |||
| 1069 | mmie = (struct ieee80211_mmie_16 *) | ||
| 1070 | (skb->data + skb->len - sizeof(*mmie)); | ||
| 1071 | if (mmie->element_id != WLAN_EID_MMIE || | ||
| 1072 | mmie->length != sizeof(*mmie) - 2) | ||
| 1073 | return RX_DROP_UNUSABLE; /* Invalid MMIE */ | ||
| 1074 | |||
| 1075 | bip_ipn_swap(ipn, mmie->sequence_number); | ||
| 1076 | |||
| 1077 | if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) { | ||
| 1078 | key->u.aes_cmac.replays++; | ||
| 1079 | return RX_DROP_UNUSABLE; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | if (!(status->flag & RX_FLAG_DECRYPTED)) { | ||
| 1083 | /* hardware didn't decrypt/verify MIC */ | ||
| 1084 | bip_aad(skb, aad); | ||
| 1085 | ieee80211_aes_cmac_256(key->u.aes_cmac.tfm, aad, | ||
| 1086 | skb->data + 24, skb->len - 24, mic); | ||
| 1087 | if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) { | ||
| 1088 | key->u.aes_cmac.icverrors++; | ||
| 1089 | return RX_DROP_UNUSABLE; | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | memcpy(key->u.aes_cmac.rx_pn, ipn, 6); | ||
| 1094 | |||
| 1095 | /* Remove MMIE */ | ||
| 1096 | skb_trim(skb, skb->len - sizeof(*mmie)); | ||
| 1097 | |||
| 1098 | return RX_CONTINUE; | ||
| 1099 | } | ||
| 1100 | |||
| 1009 | ieee80211_tx_result | 1101 | ieee80211_tx_result |
| 1010 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | 1102 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) |
| 1011 | { | 1103 | { |
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 43e109f27a89..06b7f167a176 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h | |||
| @@ -32,8 +32,12 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx, | |||
| 32 | 32 | ||
| 33 | ieee80211_tx_result | 33 | ieee80211_tx_result |
| 34 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx); | 34 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx); |
| 35 | ieee80211_tx_result | ||
| 36 | ieee80211_crypto_aes_cmac_256_encrypt(struct ieee80211_tx_data *tx); | ||
| 35 | ieee80211_rx_result | 37 | ieee80211_rx_result |
| 36 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); | 38 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); |
| 39 | ieee80211_rx_result | ||
| 40 | ieee80211_crypto_aes_cmac_256_decrypt(struct ieee80211_rx_data *rx); | ||
| 37 | ieee80211_tx_result | 41 | ieee80211_tx_result |
| 38 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); | 42 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); |
| 39 | ieee80211_rx_result | 43 | ieee80211_rx_result |
