diff options
author | Luca Coelho <luciano.coelho@intel.com> | 2018-06-09 02:14:44 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2018-06-18 16:40:32 -0400 |
commit | 41cbb0f5a29592874355e4159489eb08337cd50e (patch) | |
tree | ee56f9b9754452ae89a6f9b89efc63d2c360a50a /net/mac80211/rx.c | |
parent | b8042b3da925f390c1482bf9dc0898dc0b3ea7b5 (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.c | 127 |
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 */ |