Skip to content

Commit

Permalink
mac80211: allow drivers to access key sequence counter
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Jul 8, 2011
1 parent 9e26297 commit 3ea542d
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 2 deletions.
60 changes: 60 additions & 0 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -2591,6 +2591,66 @@ void ieee80211_get_tkip_p1k(struct ieee80211_key_conf *keyconf,
void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
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
* @vif: virtual interface the rekeying was done on
Expand Down
74 changes: 74 additions & 0 deletions net/mac80211/key.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
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);
5 changes: 3 additions & 2 deletions net/mac80211/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define CCMP_PN_LEN 6
#define TKIP_IV_LEN 8
#define TKIP_ICV_LEN 4
#define CMAC_PN_LEN 6

#define NUM_RX_DATA_QUEUES 16

Expand Down Expand Up @@ -89,13 +90,13 @@ struct ieee80211_key {
* frames and the last counter is used with Robust
* 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;
u32 replays; /* dot11RSNAStatsCCMPReplays */
} ccmp;
struct {
atomic64_t tx_pn;
u8 rx_pn[6];
u8 rx_pn[CMAC_PN_LEN];
struct crypto_cipher *tfm;
u32 replays; /* dot11RSNAStatsCMACReplays */
u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
Expand Down

0 comments on commit 3ea542d

Please sign in to comment.