mac80111: Add GCMP and GCMP-256 ciphers

This allows mac80211 to configure GCMP and GCMP-256 to the driver and
also use software-implementation within mac80211 when the driver does
not support this with hardware accelaration.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
[remove a spurious newline]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Jouni Malinen 2015-01-24 19:52:06 +02:00 committed by Johannes Berg
parent cfcf1682c4
commit 00b9cfa3ff
14 changed files with 492 additions and 9 deletions

View file

@ -24,6 +24,7 @@
#include "debugfs_key.h"
#include "aes_ccm.h"
#include "aes_cmac.h"
#include "aes_gcm.h"
/**
@ -163,6 +164,8 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
/* all of these we can do in software - if driver can */
if (ret == 1)
return 0;
@ -412,6 +415,25 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
return ERR_PTR(err);
}
break;
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
key->conf.iv_len = IEEE80211_GCMP_HDR_LEN;
key->conf.icv_len = IEEE80211_GCMP_MIC_LEN;
for (i = 0; seq && i < IEEE80211_NUM_TIDS + 1; i++)
for (j = 0; j < IEEE80211_GCMP_PN_LEN; j++)
key->u.gcmp.rx_pn[i][j] =
seq[IEEE80211_GCMP_PN_LEN - j - 1];
/* Initialize AES key state here as an optimization so that
* it does not need to be initialized for every packet.
*/
key->u.gcmp.tfm = ieee80211_aes_gcm_key_setup_encrypt(key_data,
key_len);
if (IS_ERR(key->u.gcmp.tfm)) {
err = PTR_ERR(key->u.gcmp.tfm);
kfree(key);
return ERR_PTR(err);
}
break;
default:
if (cs) {
size_t len = (seq_len > MAX_PN_LEN) ?
@ -433,10 +455,18 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
static void ieee80211_key_free_common(struct ieee80211_key *key)
{
if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
switch (key->conf.cipher) {
case WLAN_CIPHER_SUITE_CCMP:
ieee80211_aes_key_free(key->u.ccmp.tfm);
if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
break;
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
ieee80211_aes_gcm_key_free(key->u.gcmp.tfm);
break;
}
kzfree(key);
}
@ -760,6 +790,16 @@ 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);
}
@ -796,6 +836,16 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
pn = key->u.aes_cmac.rx_pn;
memcpy(seq->aes_cmac.pn, pn, IEEE80211_CMAC_PN_LEN);
break;
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
return;
if (tid < 0)
pn = key->u.gcmp.rx_pn[IEEE80211_NUM_TIDS];
else
pn = key->u.gcmp.rx_pn[tid];
memcpy(seq->gcmp.pn, pn, IEEE80211_GCMP_PN_LEN);
break;
}
}
EXPORT_SYMBOL(ieee80211_get_key_rx_seq);
@ -831,6 +881,16 @@ void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
((u64)seq->aes_cmac.pn[0] << 40);
atomic64_set(&key->u.aes_cmac.tx_pn, pn64);
break;
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);
break;
default:
WARN_ON(1);
break;
@ -868,6 +928,16 @@ void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
pn = key->u.aes_cmac.rx_pn;
memcpy(pn, seq->aes_cmac.pn, IEEE80211_CMAC_PN_LEN);
break;
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
return;
if (tid < 0)
pn = key->u.gcmp.rx_pn[IEEE80211_NUM_TIDS];
else
pn = key->u.gcmp.rx_pn[tid];
memcpy(pn, seq->gcmp.pn, IEEE80211_GCMP_PN_LEN);
break;
default:
WARN_ON(1);
break;