aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2018-01-25 05:44:24 -0500
committerKalle Valo <kvalo@codeaurora.org>2018-01-26 04:20:52 -0500
commit30ce7f4456ae40e970d9e82fe63c5e55147af0c0 (patch)
tree06b61298712b3cc88b4fbcbaff9d72fc04576655
parent3675302de8e946b9f8db44f55abbac1742f95706 (diff)
mt76: validate rx CCMP PN
Apparently hardware does not perform CCMP PN validation in hardware, so we need to take care of this in the driver. This is important for protecting against replay attacks. Since validation of fragmented frames is more complex, the CCMP header for those is preserved. To keep the counter in sync, the first fragment is verified by both mt76 and mac80211, and all other fragments only by mac80211. Signed-off-by: Felix Fietkau <nbd@nbd.name> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c65
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_init.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_mac.c61
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2_main.c1
5 files changed, 125 insertions, 16 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 77f1be161009..5fcb2deb89a2 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -384,6 +384,27 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
384} 384}
385EXPORT_SYMBOL_GPL(mt76_get_survey); 385EXPORT_SYMBOL_GPL(mt76_get_survey);
386 386
387void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
388 struct ieee80211_key_conf *key)
389{
390 struct ieee80211_key_seq seq;
391 int i;
392
393 wcid->rx_check_pn = false;
394
395 if (!key)
396 return;
397
398 if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
399 wcid->rx_check_pn = true;
400
401 for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
402 ieee80211_get_key_rx_seq(key, i, &seq);
403 memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
404 }
405}
406EXPORT_SYMBOL(mt76_wcid_key_setup);
407
387static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) 408static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
388{ 409{
389 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 410 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
@@ -410,6 +431,45 @@ static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
410 return wcid_to_sta(mstat.wcid); 431 return wcid_to_sta(mstat.wcid);
411} 432}
412 433
434static int
435mt76_check_ccmp_pn(struct sk_buff *skb)
436{
437 struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
438 struct mt76_wcid *wcid = status->wcid;
439 struct ieee80211_hdr *hdr;
440 int ret;
441
442 if (!(status->flag & RX_FLAG_DECRYPTED))
443 return 0;
444
445 if (!wcid || !wcid->rx_check_pn)
446 return 0;
447
448 if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
449 /*
450 * Validate the first fragment both here and in mac80211
451 * All further fragments will be validated by mac80211 only.
452 */
453 hdr = (struct ieee80211_hdr *) skb->data;
454 if (ieee80211_is_frag(hdr) &&
455 !ieee80211_is_first_frag(hdr->frame_control))
456 return 0;
457 }
458
459 BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
460 ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
461 sizeof(status->iv));
462 if (ret <= 0)
463 return -EINVAL; /* replay */
464
465 memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
466
467 if (status->flag & RX_FLAG_IV_STRIPPED)
468 status->flag |= RX_FLAG_PN_VALIDATED;
469
470 return 0;
471}
472
413void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 473void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
414 int queue) 474 int queue)
415{ 475{
@@ -421,6 +481,11 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
421 napi = &dev->napi[queue]; 481 napi = &dev->napi[queue];
422 482
423 while ((skb = __skb_dequeue(frames)) != NULL) { 483 while ((skb = __skb_dequeue(frames)) != NULL) {
484 if (mt76_check_ccmp_pn(skb)) {
485 dev_kfree_skb(skb);
486 continue;
487 }
488
424 sta = mt76_rx_convert(skb); 489 sta = mt76_rx_convert(skb);
425 ieee80211_rx_napi(dev->hw, sta, skb, napi); 490 ieee80211_rx_napi(dev->hw, sta, skb, napi);
426 } 491 }
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index af98bc65c2e1..129015c9d116 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -131,6 +131,9 @@ struct mt76_wcid {
131 131
132 u8 sta:1; 132 u8 sta:1;
133 133
134 u8 rx_check_pn;
135 u8 rx_key_pn[IEEE80211_NUM_TIDS][6];
136
134 __le16 tx_rate; 137 __le16 tx_rate;
135 bool tx_rate_set; 138 bool tx_rate_set;
136 u8 tx_rate_nss; 139 u8 tx_rate_nss;
@@ -279,12 +282,14 @@ struct mt76_rx_status {
279 282
280 unsigned long reorder_time; 283 unsigned long reorder_time;
281 284
282 u8 aggr; 285 u8 iv[6];
286
287 u8 aggr:1;
283 u8 tid; 288 u8 tid;
284 u16 seqno; 289 u16 seqno;
285 290
286 u32 flag;
287 u16 freq; 291 u16 freq;
292 u32 flag;
288 u8 enc_flags; 293 u8 enc_flags;
289 u8 encoding:2, bw:3; 294 u8 encoding:2, bw:3;
290 u8 rate_idx; 295 u8 rate_idx;
@@ -413,6 +418,9 @@ int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid,
413 u16 ssn, u8 size); 418 u16 ssn, u8 size);
414void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid); 419void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid);
415 420
421void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
422 struct ieee80211_key_conf *key);
423
416/* internal */ 424/* internal */
417void mt76_tx_free(struct mt76_dev *dev); 425void mt76_tx_free(struct mt76_dev *dev);
418void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t); 426void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
index 1e34b578b151..1b00ae4465a2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_init.c
@@ -131,7 +131,7 @@ mt76_write_mac_initvals(struct mt76x2_dev *dev)
131 { MT_RX_FILTR_CFG, 0x00015f97 }, 131 { MT_RX_FILTR_CFG, 0x00015f97 },
132 { MT_LEGACY_BASIC_RATE, 0x0000017f }, 132 { MT_LEGACY_BASIC_RATE, 0x0000017f },
133 { MT_HT_BASIC_RATE, 0x00004003 }, 133 { MT_HT_BASIC_RATE, 0x00004003 },
134 { MT_PN_PAD_MODE, 0x00000002 }, 134 { MT_PN_PAD_MODE, 0x00000003 },
135 { MT_TXOP_HLDR_ET, 0x00000002 }, 135 { MT_TXOP_HLDR_ET, 0x00000002 },
136 { 0xa44, 0x00000000 }, 136 { 0xa44, 0x00000000 },
137 { MT_HEADER_TRANS_CTRL_REG, 0x00000000 }, 137 { MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c
index f56a8f459fe6..6c30b5eaa9ca 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mac.c
@@ -257,12 +257,16 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
257 txwi->len_ctl = cpu_to_le16(skb->len); 257 txwi->len_ctl = cpu_to_le16(skb->len);
258} 258}
259 259
260static void mt76x2_remove_hdr_pad(struct sk_buff *skb) 260static void mt76x2_remove_hdr_pad(struct sk_buff *skb, int len)
261{ 261{
262 int len = ieee80211_get_hdrlen_from_skb(skb); 262 int hdrlen;
263 263
264 memmove(skb->data + 2, skb->data, len); 264 if (!len)
265 skb_pull(skb, 2); 265 return;
266
267 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
268 memmove(skb->data + len, skb->data, hdrlen);
269 skb_pull(skb, len);
266} 270}
267 271
268static struct mt76_wcid * 272static struct mt76_wcid *
@@ -287,28 +291,59 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
287{ 291{
288 struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; 292 struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
289 struct mt76x2_rxwi *rxwi = rxi; 293 struct mt76x2_rxwi *rxwi = rxi;
294 u32 rxinfo = le32_to_cpu(rxwi->rxinfo);
290 u32 ctl = le32_to_cpu(rxwi->ctl); 295 u32 ctl = le32_to_cpu(rxwi->ctl);
291 u16 rate = le16_to_cpu(rxwi->rate); 296 u16 rate = le16_to_cpu(rxwi->rate);
292 u16 tid_sn = le16_to_cpu(rxwi->tid_sn); 297 u16 tid_sn = le16_to_cpu(rxwi->tid_sn);
293 bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST); 298 bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST);
299 int pad_len = 0;
300 u8 pn_len;
294 u8 wcid; 301 u8 wcid;
295 int len; 302 int len;
296 303
304 if (rxinfo & MT_RXINFO_L2PAD)
305 pad_len += 2;
306
307 if (rxinfo & MT_RXINFO_DECRYPT) {
308 status->flag |= RX_FLAG_DECRYPTED;
309 status->flag |= RX_FLAG_MMIC_STRIPPED;
310 status->flag |= RX_FLAG_MIC_STRIPPED;
311 status->flag |= RX_FLAG_IV_STRIPPED;
312 }
313
297 wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); 314 wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl);
298 status->wcid = mt76x2_rx_get_sta_wcid(dev, wcid, unicast); 315 status->wcid = mt76x2_rx_get_sta_wcid(dev, wcid, unicast);
299 316
300 if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) 317 len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
301 mt76x2_remove_hdr_pad(skb); 318 pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo);
319 if (pn_len) {
320 int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len;
321 u8 *data = skb->data + offset;
322
323 status->iv[0] = data[7];
324 status->iv[1] = data[6];
325 status->iv[2] = data[5];
326 status->iv[3] = data[4];
327 status->iv[4] = data[1];
328 status->iv[5] = data[0];
329
330 /*
331 * Driver CCMP validation can't deal with fragments.
332 * Let mac80211 take care of it.
333 */
334 if (rxinfo & MT_RXINFO_FRAG) {
335 status->flag &= ~RX_FLAG_IV_STRIPPED;
336 } else {
337 pad_len += pn_len << 2;
338 len -= pn_len << 2;
339 }
340 }
341
342 mt76x2_remove_hdr_pad(skb, pad_len);
302 343
303 if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_BA)) 344 if (rxinfo & MT_RXINFO_BA)
304 status->aggr = true; 345 status->aggr = true;
305 346
306 if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
307 status->flag |= RX_FLAG_DECRYPTED;
308 status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
309 }
310
311 len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
312 if (WARN_ON_ONCE(len > skb->len)) 347 if (WARN_ON_ONCE(len > skb->len))
313 return -EINVAL; 348 return -EINVAL;
314 349
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
index 08fe804c6a43..bf26284b9989 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c
@@ -371,6 +371,7 @@ mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
371 371
372 key = NULL; 372 key = NULL;
373 } 373 }
374 mt76_wcid_key_setup(&dev->mt76, wcid, key);
374 375
375 if (!msta) { 376 if (!msta) {
376 if (key || wcid->hw_key_idx == idx) { 377 if (key || wcid->hw_key_idx == idx) {