Skip to content

Commit f8079d4

Browse files
elpjmberg-intel
authored andcommitted
mac80211: move TKIP TX IVs to public part of key struct
Some drivers/devices might want to set the IVs by themselves (and still let mac80211 generate MMIC). Specifically, this is needed when the device does offloading at certain times, and the driver has to make sure that the IVs of new tx frames (from the host) are synchronized with IVs that were potentially used during the offloading. Similarly to CCMP, move the TX IVs of TKIP keys to the public part of the key struct, and export a function to add the IV right into the crypto header. The public tx_pn field is defined as atomic64, so define TKIP_PN_TO_IV16/32 helper macros to convert it to iv16/32 when needed. Since the iv32 used for the p1k cache is taken directly from the frame, we can safely remove iv16/32 from being protected by tkip.txlock. Signed-off-by: Eliad Peller <[email protected]> Signed-off-by: Emmanuel Grumbach <[email protected]> Signed-off-by: Johannes Berg <[email protected]>
1 parent 109843b commit f8079d4

File tree

8 files changed

+60
-41
lines changed

8 files changed

+60
-41
lines changed

include/net/mac80211.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,9 +1521,8 @@ enum ieee80211_key_flags {
15211521
* wants to be given when a frame is transmitted and needs to be
15221522
* encrypted in hardware.
15231523
* @cipher: The key's cipher suite selector.
1524-
* @tx_pn: PN used for TX on non-TKIP keys, may be used by the driver
1525-
* as well if it needs to do software PN assignment by itself
1526-
* (e.g. due to TSO)
1524+
* @tx_pn: PN used for TX keys, may be used by the driver as well if it
1525+
* needs to do software PN assignment by itself (e.g. due to TSO)
15271526
* @flags: key flags, see &enum ieee80211_key_flags.
15281527
* @keyidx: the key index (0-3)
15291528
* @keylen: key material length
@@ -1549,6 +1548,9 @@ struct ieee80211_key_conf {
15491548

15501549
#define IEEE80211_MAX_PN_LEN 16
15511550

1551+
#define TKIP_PN_TO_IV16(pn) ((u16)(pn & 0xffff))
1552+
#define TKIP_PN_TO_IV32(pn) ((u32)((pn >> 16) & 0xffffffff))
1553+
15521554
/**
15531555
* struct ieee80211_key_seq - key sequence counter
15541556
*
@@ -4446,6 +4448,21 @@ void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf,
44464448
void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
44474449
struct sk_buff *skb, u8 *p2k);
44484450

4451+
/**
4452+
* ieee80211_tkip_add_iv - write TKIP IV and Ext. IV to pos
4453+
*
4454+
* @pos: start of crypto header
4455+
* @keyconf: the parameter passed with the set key
4456+
* @pn: PN to add
4457+
*
4458+
* Returns: pointer to the octet following IVs (i.e. beginning of
4459+
* the packet payload)
4460+
*
4461+
* This function writes the tkip IV value to pos (which should
4462+
* point to the crypto header)
4463+
*/
4464+
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn);
4465+
44494466
/**
44504467
* ieee80211_get_key_tx_seq - get key TX sequence counter
44514468
*

net/mac80211/cfg.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,9 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
339339

340340
switch (key->conf.cipher) {
341341
case WLAN_CIPHER_SUITE_TKIP:
342-
iv32 = key->u.tkip.tx.iv32;
343-
iv16 = key->u.tkip.tx.iv16;
342+
pn64 = atomic64_read(&key->conf.tx_pn);
343+
iv32 = TKIP_PN_TO_IV32(pn64);
344+
iv16 = TKIP_PN_TO_IV16(pn64);
344345

345346
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
346347
!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {

net/mac80211/debugfs_key.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,10 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
132132
len = scnprintf(buf, sizeof(buf), "\n");
133133
break;
134134
case WLAN_CIPHER_SUITE_TKIP:
135+
pn = atomic64_read(&key->conf.tx_pn);
135136
len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
136-
key->u.tkip.tx.iv32,
137-
key->u.tkip.tx.iv16);
137+
TKIP_PN_TO_IV32(pn),
138+
TKIP_PN_TO_IV16(pn));
138139
break;
139140
case WLAN_CIPHER_SUITE_CCMP:
140141
case WLAN_CIPHER_SUITE_CCMP_256:

net/mac80211/key.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -945,8 +945,9 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
945945

946946
switch (key->conf.cipher) {
947947
case WLAN_CIPHER_SUITE_TKIP:
948-
seq->tkip.iv32 = key->u.tkip.tx.iv32;
949-
seq->tkip.iv16 = key->u.tkip.tx.iv16;
948+
pn64 = atomic64_read(&key->conf.tx_pn);
949+
seq->tkip.iv32 = TKIP_PN_TO_IV32(pn64);
950+
seq->tkip.iv16 = TKIP_PN_TO_IV16(pn64);
950951
break;
951952
case WLAN_CIPHER_SUITE_CCMP:
952953
case WLAN_CIPHER_SUITE_CCMP_256:
@@ -1039,8 +1040,8 @@ void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
10391040

10401041
switch (key->conf.cipher) {
10411042
case WLAN_CIPHER_SUITE_TKIP:
1042-
key->u.tkip.tx.iv32 = seq->tkip.iv32;
1043-
key->u.tkip.tx.iv16 = seq->tkip.iv16;
1043+
pn64 = (u64)seq->tkip.iv16 | ((u64)seq->tkip.iv32 << 16);
1044+
atomic64_set(&key->conf.tx_pn, pn64);
10441045
break;
10451046
case WLAN_CIPHER_SUITE_CCMP:
10461047
case WLAN_CIPHER_SUITE_CCMP_256:

net/mac80211/key.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,17 @@ enum ieee80211_internal_tkip_state {
4444
};
4545

4646
struct tkip_ctx {
47-
u32 iv32; /* current iv32 */
48-
u16 iv16; /* current iv16 */
4947
u16 p1k[5]; /* p1k cache */
5048
u32 p1k_iv32; /* iv32 for which p1k computed */
5149
enum ieee80211_internal_tkip_state state;
5250
};
5351

52+
struct tkip_ctx_rx {
53+
struct tkip_ctx ctx;
54+
u32 iv32; /* current iv32 */
55+
u16 iv16; /* current iv16 */
56+
};
57+
5458
struct ieee80211_key {
5559
struct ieee80211_local *local;
5660
struct ieee80211_sub_if_data *sdata;
@@ -71,7 +75,7 @@ struct ieee80211_key {
7175
struct tkip_ctx tx;
7276

7377
/* last received RSC */
74-
struct tkip_ctx rx[IEEE80211_NUM_TIDS];
78+
struct tkip_ctx_rx rx[IEEE80211_NUM_TIDS];
7579

7680
/* number of mic failures */
7781
u32 mic_failures;

net/mac80211/tkip.c

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright 2002-2004, Instant802 Networks, Inc.
33
* Copyright 2005, Devicescape Software, Inc.
4+
* Copyright (C) 2016 Intel Deutschland GmbH
45
*
56
* This program is free software; you can redistribute it and/or modify
67
* it under the terms of the GNU General Public License version 2 as
@@ -142,15 +143,14 @@ static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx,
142143
/* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
143144
* of the IV. Returns pointer to the octet following IVs (i.e., beginning of
144145
* the packet payload). */
145-
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key)
146+
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn)
146147
{
147-
lockdep_assert_held(&key->u.tkip.txlock);
148-
149-
pos = write_tkip_iv(pos, key->u.tkip.tx.iv16);
150-
*pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
151-
put_unaligned_le32(key->u.tkip.tx.iv32, pos);
148+
pos = write_tkip_iv(pos, TKIP_PN_TO_IV16(pn));
149+
*pos++ = (keyconf->keyidx << 6) | (1 << 5) /* Ext IV */;
150+
put_unaligned_le32(TKIP_PN_TO_IV32(pn), pos);
152151
return pos + 4;
153152
}
153+
EXPORT_SYMBOL_GPL(ieee80211_tkip_add_iv);
154154

155155
static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32)
156156
{
@@ -250,6 +250,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
250250
u8 rc4key[16], keyid, *pos = payload;
251251
int res;
252252
const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
253+
struct tkip_ctx_rx *rx_ctx = &key->u.tkip.rx[queue];
253254

254255
if (payload_len < 12)
255256
return -1;
@@ -265,37 +266,36 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
265266
if ((keyid >> 6) != key->conf.keyidx)
266267
return TKIP_DECRYPT_INVALID_KEYIDX;
267268

268-
if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&
269-
(iv32 < key->u.tkip.rx[queue].iv32 ||
270-
(iv32 == key->u.tkip.rx[queue].iv32 &&
271-
iv16 <= key->u.tkip.rx[queue].iv16)))
269+
if (rx_ctx->ctx.state != TKIP_STATE_NOT_INIT &&
270+
(iv32 < rx_ctx->iv32 ||
271+
(iv32 == rx_ctx->iv32 && iv16 <= rx_ctx->iv16)))
272272
return TKIP_DECRYPT_REPLAY;
273273

274274
if (only_iv) {
275275
res = TKIP_DECRYPT_OK;
276-
key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
276+
rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED;
277277
goto done;
278278
}
279279

280-
if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT ||
281-
key->u.tkip.rx[queue].iv32 != iv32) {
280+
if (rx_ctx->ctx.state == TKIP_STATE_NOT_INIT ||
281+
rx_ctx->iv32 != iv32) {
282282
/* IV16 wrapped around - perform TKIP phase 1 */
283-
tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
283+
tkip_mixing_phase1(tk, &rx_ctx->ctx, ta, iv32);
284284
}
285285
if (key->local->ops->update_tkip_key &&
286286
key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
287-
key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) {
287+
rx_ctx->ctx.state != TKIP_STATE_PHASE1_HW_UPLOADED) {
288288
struct ieee80211_sub_if_data *sdata = key->sdata;
289289

290290
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
291291
sdata = container_of(key->sdata->bss,
292292
struct ieee80211_sub_if_data, u.ap);
293293
drv_update_tkip_key(key->local, sdata, &key->conf, key->sta,
294-
iv32, key->u.tkip.rx[queue].p1k);
295-
key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
294+
iv32, rx_ctx->ctx.p1k);
295+
rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED;
296296
}
297297

298-
tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
298+
tkip_mixing_phase2(tk, &rx_ctx->ctx, iv16, rc4key);
299299

300300
res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
301301
done:

net/mac80211/tkip.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
#include <linux/crypto.h>
1414
#include "key.h"
1515

16-
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key);
17-
1816
int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
1917
struct ieee80211_key *key,
2018
struct sk_buff *skb,

net/mac80211/wpa.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright 2002-2004, Instant802 Networks, Inc.
33
* Copyright 2008, Jouni Malinen <[email protected]>
4+
* Copyright (C) 2016 Intel Deutschland GmbH
45
*
56
* This program is free software; you can redistribute it and/or modify
67
* it under the terms of the GNU General Public License version 2 as
@@ -183,14 +184,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
183184
return RX_DROP_UNUSABLE;
184185
}
185186

186-
187187
static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
188188
{
189189
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
190190
struct ieee80211_key *key = tx->key;
191191
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
192192
unsigned int hdrlen;
193193
int len, tail;
194+
u64 pn;
194195
u8 *pos;
195196

196197
if (info->control.hw_key &&
@@ -222,12 +223,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
222223
return 0;
223224

224225
/* Increase IV for the frame */
225-
spin_lock(&key->u.tkip.txlock);
226-
key->u.tkip.tx.iv16++;
227-
if (key->u.tkip.tx.iv16 == 0)
228-
key->u.tkip.tx.iv32++;
229-
pos = ieee80211_tkip_add_iv(pos, key);
230-
spin_unlock(&key->u.tkip.txlock);
226+
pn = atomic64_inc_return(&key->conf.tx_pn);
227+
pos = ieee80211_tkip_add_iv(pos, &key->conf, pn);
231228

232229
/* hwaccel - with software IV */
233230
if (info->control.hw_key)

0 commit comments

Comments
 (0)