aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2010-06-11 13:27:33 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-15 16:00:49 -0400
commit9190252c952a33efa1ceff4ef35188f8a27b81cb (patch)
treef6c7473c919e7a3f0ff7c1b6543da44f8c338d02
parent05e48e8e437148298f4673e1efe81f9ead5f41d7 (diff)
mac80211: Use a separate CCMP PN receive counter for management frames
When management frame protection (IEEE 802.11w) is used, we must use a separate counter for tracking received CCMP packet number for the management frames. The previously used NUM_RX_DATA_QUEUESth queue was shared with data frames when QoS was not used and that can cause problems in detecting replays incorrectly for robust management frames. Add a new counter just for robust management frames to avoid this issue. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/debugfs_key.c2
-rw-r--r--net/mac80211/key.c2
-rw-r--r--net/mac80211/key.h8
-rw-r--r--net/mac80211/rx.c9
-rw-r--r--net/mac80211/wpa.c8
5 files changed, 22 insertions, 7 deletions
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 97c9e46e859e..fa5e76e658ef 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -143,7 +143,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
143 len = p - buf; 143 len = p - buf;
144 break; 144 break;
145 case ALG_CCMP: 145 case ALG_CCMP:
146 for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { 146 for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) {
147 rpn = key->u.ccmp.rx_pn[i]; 147 rpn = key->u.ccmp.rx_pn[i];
148 p += scnprintf(p, sizeof(buf)+buf-p, 148 p += scnprintf(p, sizeof(buf)+buf-p,
149 "%02x%02x%02x%02x%02x%02x\n", 149 "%02x%02x%02x%02x%02x%02x\n",
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index d0d9001a4a6a..50d1cff23d8e 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -273,7 +273,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
273 key->conf.iv_len = CCMP_HDR_LEN; 273 key->conf.iv_len = CCMP_HDR_LEN;
274 key->conf.icv_len = CCMP_MIC_LEN; 274 key->conf.icv_len = CCMP_MIC_LEN;
275 if (seq) { 275 if (seq) {
276 for (i = 0; i < NUM_RX_DATA_QUEUES; i++) 276 for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++)
277 for (j = 0; j < CCMP_PN_LEN; j++) 277 for (j = 0; j < CCMP_PN_LEN; j++)
278 key->u.ccmp.rx_pn[i][j] = 278 key->u.ccmp.rx_pn[i][j] =
279 seq[CCMP_PN_LEN - j - 1]; 279 seq[CCMP_PN_LEN - j - 1];
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 9996e3be6e63..a3849fa3fce8 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -77,7 +77,13 @@ struct ieee80211_key {
77 } tkip; 77 } tkip;
78 struct { 78 struct {
79 u8 tx_pn[6]; 79 u8 tx_pn[6];
80 u8 rx_pn[NUM_RX_DATA_QUEUES][6]; 80 /*
81 * Last received packet number. The first
82 * NUM_RX_DATA_QUEUES counters are used with Data
83 * frames and the last counter is used with Robust
84 * Management frames.
85 */
86 u8 rx_pn[NUM_RX_DATA_QUEUES + 1][6];
81 struct crypto_cipher *tfm; 87 struct crypto_cipher *tfm;
82 u32 replays; /* dot11RSNAStatsCCMPReplays */ 88 u32 replays; /* dot11RSNAStatsCCMPReplays */
83 /* scratch buffers for virt_to_page() (crypto API) */ 89 /* scratch buffers for virt_to_page() (crypto API) */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1594ebe80a4f..1f76352caa9e 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1267,11 +1267,13 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
1267 rx->queue, &(rx->skb)); 1267 rx->queue, &(rx->skb));
1268 if (rx->key && rx->key->conf.alg == ALG_CCMP && 1268 if (rx->key && rx->key->conf.alg == ALG_CCMP &&
1269 ieee80211_has_protected(fc)) { 1269 ieee80211_has_protected(fc)) {
1270 int queue = ieee80211_is_mgmt(fc) ?
1271 NUM_RX_DATA_QUEUES : rx->queue;
1270 /* Store CCMP PN so that we can verify that the next 1272 /* Store CCMP PN so that we can verify that the next
1271 * fragment has a sequential PN value. */ 1273 * fragment has a sequential PN value. */
1272 entry->ccmp = 1; 1274 entry->ccmp = 1;
1273 memcpy(entry->last_pn, 1275 memcpy(entry->last_pn,
1274 rx->key->u.ccmp.rx_pn[rx->queue], 1276 rx->key->u.ccmp.rx_pn[queue],
1275 CCMP_PN_LEN); 1277 CCMP_PN_LEN);
1276 } 1278 }
1277 return RX_QUEUED; 1279 return RX_QUEUED;
@@ -1291,6 +1293,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
1291 if (entry->ccmp) { 1293 if (entry->ccmp) {
1292 int i; 1294 int i;
1293 u8 pn[CCMP_PN_LEN], *rpn; 1295 u8 pn[CCMP_PN_LEN], *rpn;
1296 int queue;
1294 if (!rx->key || rx->key->conf.alg != ALG_CCMP) 1297 if (!rx->key || rx->key->conf.alg != ALG_CCMP)
1295 return RX_DROP_UNUSABLE; 1298 return RX_DROP_UNUSABLE;
1296 memcpy(pn, entry->last_pn, CCMP_PN_LEN); 1299 memcpy(pn, entry->last_pn, CCMP_PN_LEN);
@@ -1299,7 +1302,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
1299 if (pn[i]) 1302 if (pn[i])
1300 break; 1303 break;
1301 } 1304 }
1302 rpn = rx->key->u.ccmp.rx_pn[rx->queue]; 1305 queue = ieee80211_is_mgmt(fc) ?
1306 NUM_RX_DATA_QUEUES : rx->queue;
1307 rpn = rx->key->u.ccmp.rx_pn[queue];
1303 if (memcmp(pn, rpn, CCMP_PN_LEN)) 1308 if (memcmp(pn, rpn, CCMP_PN_LEN))
1304 return RX_DROP_UNUSABLE; 1309 return RX_DROP_UNUSABLE;
1305 memcpy(entry->last_pn, pn, CCMP_PN_LEN); 1310 memcpy(entry->last_pn, pn, CCMP_PN_LEN);
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 0adbcc941ac9..a14e67707476 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -436,6 +436,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
436 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 436 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
437 u8 pn[CCMP_PN_LEN]; 437 u8 pn[CCMP_PN_LEN];
438 int data_len; 438 int data_len;
439 int queue;
439 440
440 hdrlen = ieee80211_hdrlen(hdr->frame_control); 441 hdrlen = ieee80211_hdrlen(hdr->frame_control);
441 442
@@ -453,7 +454,10 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
453 454
454 ccmp_hdr2pn(pn, skb->data + hdrlen); 455 ccmp_hdr2pn(pn, skb->data + hdrlen);
455 456
456 if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) { 457 queue = ieee80211_is_mgmt(hdr->frame_control) ?
458 NUM_RX_DATA_QUEUES : rx->queue;
459
460 if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) {
457 key->u.ccmp.replays++; 461 key->u.ccmp.replays++;
458 return RX_DROP_UNUSABLE; 462 return RX_DROP_UNUSABLE;
459 } 463 }
@@ -470,7 +474,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
470 return RX_DROP_UNUSABLE; 474 return RX_DROP_UNUSABLE;
471 } 475 }
472 476
473 memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN); 477 memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN);
474 478
475 /* Remove CCMP header and MIC */ 479 /* Remove CCMP header and MIC */
476 skb_trim(skb, skb->len - CCMP_MIC_LEN); 480 skb_trim(skb, skb->len - CCMP_MIC_LEN);