mac80211: allow drivers to access key sequence counter
In order to implement GTK rekeying, the device needs to be able to encrypt frames with the right PN/IV and check the PN/IV in RX frames. To be able to tell it about all those counters, we need to be able to get them from mac80211, this adds the required API. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Родитель
9e26297a56
Коммит
3ea542d3c2
|
@ -2591,6 +2591,66 @@ void ieee80211_get_tkip_p1k(struct ieee80211_key_conf *keyconf,
|
||||||
void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
|
void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
|
||||||
struct sk_buff *skb, u8 *p2k);
|
struct sk_buff *skb, u8 *p2k);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ieee80211_key_seq - key sequence counter
|
||||||
|
*
|
||||||
|
* @tkip: TKIP data, containing IV32 and IV16 in host byte order
|
||||||
|
* @ccmp: PN data, most significant byte first (big endian,
|
||||||
|
* reverse order than in packet)
|
||||||
|
* @aes_cmac: PN data, most significant byte first (big endian,
|
||||||
|
* reverse order than in packet)
|
||||||
|
*/
|
||||||
|
struct ieee80211_key_seq {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u32 iv32;
|
||||||
|
u16 iv16;
|
||||||
|
} tkip;
|
||||||
|
struct {
|
||||||
|
u8 pn[6];
|
||||||
|
} ccmp;
|
||||||
|
struct {
|
||||||
|
u8 pn[6];
|
||||||
|
} aes_cmac;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_get_key_tx_seq - get key TX sequence counter
|
||||||
|
*
|
||||||
|
* @keyconf: the parameter passed with the set key
|
||||||
|
* @seq: buffer to receive the sequence data
|
||||||
|
*
|
||||||
|
* This function allows a driver to retrieve the current TX IV/PN
|
||||||
|
* for the given key. It must not be called if IV generation is
|
||||||
|
* offloaded to the device.
|
||||||
|
*
|
||||||
|
* Note that this function may only be called when no TX processing
|
||||||
|
* can be done concurrently, for example when queues are stopped
|
||||||
|
* and the stop has been synchronized.
|
||||||
|
*/
|
||||||
|
void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
|
||||||
|
struct ieee80211_key_seq *seq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_get_key_rx_seq - get key RX sequence counter
|
||||||
|
*
|
||||||
|
* @keyconf: the parameter passed with the set key
|
||||||
|
* @tid: The TID, or -1 for the management frame value (CCMP only);
|
||||||
|
* the value on TID 0 is also used for non-QoS frames. For
|
||||||
|
* CMAC, only TID 0 is valid.
|
||||||
|
* @seq: buffer to receive the sequence data
|
||||||
|
*
|
||||||
|
* This function allows a driver to retrieve the current RX IV/PNs
|
||||||
|
* for the given key. It must not be called if IV checking is done
|
||||||
|
* by the device and not by mac80211.
|
||||||
|
*
|
||||||
|
* Note that this function may only be called when no RX processing
|
||||||
|
* can be done concurrently.
|
||||||
|
*/
|
||||||
|
void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
|
||||||
|
int tid, struct ieee80211_key_seq *seq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying
|
* ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying
|
||||||
* @vif: virtual interface the rekeying was done on
|
* @vif: virtual interface the rekeying was done on
|
||||||
|
|
|
@ -626,3 +626,77 @@ void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
|
||||||
cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp);
|
cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
|
EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
|
||||||
|
|
||||||
|
void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
|
||||||
|
struct ieee80211_key_seq *seq)
|
||||||
|
{
|
||||||
|
struct ieee80211_key *key;
|
||||||
|
u64 pn64;
|
||||||
|
|
||||||
|
if (WARN_ON(!(keyconf->flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
key = container_of(keyconf, struct ieee80211_key, conf);
|
||||||
|
|
||||||
|
switch (key->conf.cipher) {
|
||||||
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
|
seq->tkip.iv32 = key->u.tkip.tx.iv32;
|
||||||
|
seq->tkip.iv16 = key->u.tkip.tx.iv16;
|
||||||
|
break;
|
||||||
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
|
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:
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
WARN_ON(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_get_key_tx_seq);
|
||||||
|
|
||||||
|
void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
|
||||||
|
int tid, struct ieee80211_key_seq *seq)
|
||||||
|
{
|
||||||
|
struct ieee80211_key *key;
|
||||||
|
const u8 *pn;
|
||||||
|
|
||||||
|
key = container_of(keyconf, struct ieee80211_key, conf);
|
||||||
|
|
||||||
|
switch (key->conf.cipher) {
|
||||||
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
|
if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES))
|
||||||
|
return;
|
||||||
|
seq->tkip.iv32 = key->u.tkip.rx[tid].iv32;
|
||||||
|
seq->tkip.iv16 = key->u.tkip.rx[tid].iv16;
|
||||||
|
break;
|
||||||
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
|
if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES))
|
||||||
|
return;
|
||||||
|
if (tid < 0)
|
||||||
|
pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES];
|
||||||
|
else
|
||||||
|
pn = key->u.ccmp.rx_pn[tid];
|
||||||
|
memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN);
|
||||||
|
break;
|
||||||
|
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||||
|
if (WARN_ON(tid != 0))
|
||||||
|
return;
|
||||||
|
pn = key->u.aes_cmac.rx_pn;
|
||||||
|
memcpy(seq->aes_cmac.pn, pn, CMAC_PN_LEN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_get_key_rx_seq);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#define CCMP_PN_LEN 6
|
#define CCMP_PN_LEN 6
|
||||||
#define TKIP_IV_LEN 8
|
#define TKIP_IV_LEN 8
|
||||||
#define TKIP_ICV_LEN 4
|
#define TKIP_ICV_LEN 4
|
||||||
|
#define CMAC_PN_LEN 6
|
||||||
|
|
||||||
#define NUM_RX_DATA_QUEUES 16
|
#define NUM_RX_DATA_QUEUES 16
|
||||||
|
|
||||||
|
@ -89,13 +90,13 @@ struct ieee80211_key {
|
||||||
* frames and the last counter is used with Robust
|
* frames and the last counter is used with Robust
|
||||||
* Management frames.
|
* Management frames.
|
||||||
*/
|
*/
|
||||||
u8 rx_pn[NUM_RX_DATA_QUEUES + 1][6];
|
u8 rx_pn[NUM_RX_DATA_QUEUES + 1][CCMP_PN_LEN];
|
||||||
struct crypto_cipher *tfm;
|
struct crypto_cipher *tfm;
|
||||||
u32 replays; /* dot11RSNAStatsCCMPReplays */
|
u32 replays; /* dot11RSNAStatsCCMPReplays */
|
||||||
} ccmp;
|
} ccmp;
|
||||||
struct {
|
struct {
|
||||||
atomic64_t tx_pn;
|
atomic64_t tx_pn;
|
||||||
u8 rx_pn[6];
|
u8 rx_pn[CMAC_PN_LEN];
|
||||||
struct crypto_cipher *tfm;
|
struct crypto_cipher *tfm;
|
||||||
u32 replays; /* dot11RSNAStatsCMACReplays */
|
u32 replays; /* dot11RSNAStatsCMACReplays */
|
||||||
u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
|
u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче