summaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorLuca Coelho <luciano.coelho@intel.com>2018-06-09 02:14:44 -0400
committerJohannes Berg <johannes.berg@intel.com>2018-06-18 16:40:32 -0400
commit41cbb0f5a29592874355e4159489eb08337cd50e (patch)
treeee56f9b9754452ae89a6f9b89efc63d2c360a50a /net/mac80211/rx.c
parentb8042b3da925f390c1482bf9dc0898dc0b3ea7b5 (diff)
mac80211: add support for HE
Add support for HE in mac80211 conforming with P802.11ax_D1.4. Johannes: Fix another bug with the buf_size comparison in agg-rx.c. Signed-off-by: Liad Kaufman <liad.kaufman@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Ilan Peer <ilan.peer@intel.com> Signed-off-by: Ido Yariv <idox.yariv@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c127
1 files changed, 125 insertions, 2 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 756ba176db1e..a16ba568e2a3 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -175,6 +175,20 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
175 len += 12; 175 len += 12;
176 } 176 }
177 177
178 if (status->encoding == RX_ENC_HE &&
179 status->flag & RX_FLAG_RADIOTAP_HE) {
180 len = ALIGN(len, 2);
181 len += 12;
182 BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) != 12);
183 }
184
185 if (status->encoding == RX_ENC_HE &&
186 status->flag & RX_FLAG_RADIOTAP_HE_MU) {
187 len = ALIGN(len, 2);
188 len += 12;
189 BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12);
190 }
191
178 if (status->chains) { 192 if (status->chains) {
179 /* antenna and antenna signal fields */ 193 /* antenna and antenna signal fields */
180 len += 2 * hweight8(status->chains); 194 len += 2 * hweight8(status->chains);
@@ -263,6 +277,19 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
263 int mpdulen, chain; 277 int mpdulen, chain;
264 unsigned long chains = status->chains; 278 unsigned long chains = status->chains;
265 struct ieee80211_vendor_radiotap rtap = {}; 279 struct ieee80211_vendor_radiotap rtap = {};
280 struct ieee80211_radiotap_he he = {};
281 struct ieee80211_radiotap_he_mu he_mu = {};
282
283 if (status->flag & RX_FLAG_RADIOTAP_HE) {
284 he = *(struct ieee80211_radiotap_he *)skb->data;
285 skb_pull(skb, sizeof(he));
286 WARN_ON_ONCE(status->encoding != RX_ENC_HE);
287 }
288
289 if (status->flag & RX_FLAG_RADIOTAP_HE_MU) {
290 he_mu = *(struct ieee80211_radiotap_he_mu *)skb->data;
291 skb_pull(skb, sizeof(he_mu));
292 }
266 293
267 if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { 294 if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
268 rtap = *(struct ieee80211_vendor_radiotap *)skb->data; 295 rtap = *(struct ieee80211_vendor_radiotap *)skb->data;
@@ -520,6 +547,89 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
520 *pos++ = flags; 547 *pos++ = flags;
521 } 548 }
522 549
550 if (status->encoding == RX_ENC_HE &&
551 status->flag & RX_FLAG_RADIOTAP_HE) {
552#define HE_PREP(f, val) cpu_to_le16(FIELD_PREP(IEEE80211_RADIOTAP_HE_##f, val))
553
554 if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) {
555 he.data6 |= HE_PREP(DATA6_NSTS,
556 FIELD_GET(RX_ENC_FLAG_STBC_MASK,
557 status->enc_flags));
558 he.data3 |= HE_PREP(DATA3_STBC, 1);
559 } else {
560 he.data6 |= HE_PREP(DATA6_NSTS, status->nss);
561 }
562
563#define CHECK_GI(s) \
564 BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_GI_##s != \
565 (int)NL80211_RATE_INFO_HE_GI_##s)
566
567 CHECK_GI(0_8);
568 CHECK_GI(1_6);
569 CHECK_GI(3_2);
570
571 he.data3 |= HE_PREP(DATA3_DATA_MCS, status->rate_idx);
572 he.data3 |= HE_PREP(DATA3_DATA_DCM, status->he_dcm);
573 he.data3 |= HE_PREP(DATA3_CODING,
574 !!(status->enc_flags & RX_ENC_FLAG_LDPC));
575
576 he.data5 |= HE_PREP(DATA5_GI, status->he_gi);
577
578 switch (status->bw) {
579 case RATE_INFO_BW_20:
580 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
581 IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ);
582 break;
583 case RATE_INFO_BW_40:
584 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
585 IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ);
586 break;
587 case RATE_INFO_BW_80:
588 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
589 IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ);
590 break;
591 case RATE_INFO_BW_160:
592 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
593 IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ);
594 break;
595 case RATE_INFO_BW_HE_RU:
596#define CHECK_RU_ALLOC(s) \
597 BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_##s##T != \
598 NL80211_RATE_INFO_HE_RU_ALLOC_##s + 4)
599
600 CHECK_RU_ALLOC(26);
601 CHECK_RU_ALLOC(52);
602 CHECK_RU_ALLOC(106);
603 CHECK_RU_ALLOC(242);
604 CHECK_RU_ALLOC(484);
605 CHECK_RU_ALLOC(996);
606 CHECK_RU_ALLOC(2x996);
607
608 he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
609 status->he_ru + 4);
610 break;
611 default:
612 WARN_ONCE(1, "Invalid SU BW %d\n", status->bw);
613 }
614
615 /* ensure 2 byte alignment */
616 while ((pos - (u8 *)rthdr) & 1)
617 pos++;
618 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE);
619 memcpy(pos, &he, sizeof(he));
620 pos += sizeof(he);
621 }
622
623 if (status->encoding == RX_ENC_HE &&
624 status->flag & RX_FLAG_RADIOTAP_HE_MU) {
625 /* ensure 2 byte alignment */
626 while ((pos - (u8 *)rthdr) & 1)
627 pos++;
628 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE_MU);
629 memcpy(pos, &he_mu, sizeof(he_mu));
630 pos += sizeof(he_mu);
631 }
632
523 for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { 633 for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
524 *pos++ = status->chain_signal[chain]; 634 *pos++ = status->chain_signal[chain];
525 *pos++ = chain; 635 *pos++ = chain;
@@ -613,6 +723,12 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
613 rcu_dereference(local->monitor_sdata); 723 rcu_dereference(local->monitor_sdata);
614 bool only_monitor = false; 724 bool only_monitor = false;
615 725
726 if (status->flag & RX_FLAG_RADIOTAP_HE)
727 rtap_space += sizeof(struct ieee80211_radiotap_he);
728
729 if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
730 rtap_space += sizeof(struct ieee80211_radiotap_he_mu);
731
616 if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { 732 if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) {
617 struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; 733 struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data;
618 734
@@ -3386,8 +3502,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
3386 status = IEEE80211_SKB_RXCB((rx->skb)); 3502 status = IEEE80211_SKB_RXCB((rx->skb));
3387 3503
3388 sband = rx->local->hw.wiphy->bands[status->band]; 3504 sband = rx->local->hw.wiphy->bands[status->band];
3389 if (!(status->encoding == RX_ENC_HT) && 3505 if (status->encoding == RX_ENC_LEGACY)
3390 !(status->encoding == RX_ENC_VHT))
3391 rate = &sband->bitrates[status->rate_idx]; 3506 rate = &sband->bitrates[status->rate_idx];
3392 3507
3393 ieee80211_rx_cooked_monitor(rx, rate); 3508 ieee80211_rx_cooked_monitor(rx, rate);
@@ -4386,6 +4501,14 @@ void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
4386 status->rate_idx, status->nss)) 4501 status->rate_idx, status->nss))
4387 goto drop; 4502 goto drop;
4388 break; 4503 break;
4504 case RX_ENC_HE:
4505 if (WARN_ONCE(status->rate_idx > 11 ||
4506 !status->nss ||
4507 status->nss > 8,
4508 "Rate marked as an HE rate but data is invalid: MCS: %d, NSS: %d\n",
4509 status->rate_idx, status->nss))
4510 goto drop;
4511 break;
4389 default: 4512 default:
4390 WARN_ON_ONCE(1); 4513 WARN_ON_ONCE(1);
4391 /* fall through */ 4514 /* fall through */