mac80211: support drivers reporting VHT RX
authorJohannes Berg <johannes.berg@intel.com>
Fri, 9 Nov 2012 14:07:02 +0000 (15:07 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 26 Nov 2012 11:42:59 +0000 (12:42 +0100)
Add support to mac80211 for having drivers report
received VHT MCS information.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/rx.c
net/mac80211/sta_info.h
net/mac80211/util.c

index 6af51328dcd14fa416674629f597b7ab4fa3d564..598ea215fc3b458a48a0f926aaed988c04eaebb1 100644 (file)
@@ -717,7 +717,11 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  *     (including FCS) was received.
  * @RX_FLAG_SHORTPRE: Short preamble was used for this frame
  * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
+ * @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index
  * @RX_FLAG_40MHZ: HT40 (40 MHz) was used
+ * @RX_FLAG_80MHZ: 80 MHz was used
+ * @RX_FLAG_80P80MHZ: 80+80 MHz was used
+ * @RX_FLAG_160MHZ: 160 MHz was used
  * @RX_FLAG_SHORT_GI: Short guard interval was used
  * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present.
  *     Valid only for data frames (mainly A-MPDU)
@@ -760,6 +764,10 @@ enum mac80211_rx_flags {
        RX_FLAG_AMPDU_DELIM_CRC_ERROR   = BIT(19),
        RX_FLAG_AMPDU_DELIM_CRC_KNOWN   = BIT(20),
        RX_FLAG_MACTIME_END             = BIT(21),
+       RX_FLAG_VHT                     = BIT(22),
+       RX_FLAG_80MHZ                   = BIT(23),
+       RX_FLAG_80P80MHZ                = BIT(24),
+       RX_FLAG_160MHZ                  = BIT(25),
 };
 
 /**
@@ -780,7 +788,8 @@ enum mac80211_rx_flags {
  *     @IEEE80211_HW_SIGNAL_*
  * @antenna: antenna used
  * @rate_idx: index of data rate into band's supported rates or MCS index if
- *     HT rates are use (RX_FLAG_HT)
+ *     HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
+ * @vht_nss: number of streams (VHT only)
  * @flag: %RX_FLAG_*
  * @rx_flags: internal RX flags for mac80211
  * @ampdu_reference: A-MPDU reference number, must be a different value for
@@ -803,6 +812,7 @@ struct ieee80211_rx_status {
        u16 vendor_radiotap_len;
        u16 freq;
        u8 rate_idx;
+       u8 vht_nss;
        u8 rx_flags;
        u8 band;
        u8 antenna;
index b9702d16d608eadea90b528d64b9d991375775c9..0b9de4fa54a6cb708ea4f3f18c5a1942175ae51c 100644 (file)
@@ -374,7 +374,8 @@ static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, in
 {
        enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata);
 
-       if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
+       if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
+           !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) {
                struct ieee80211_supported_band *sband;
                sband = sta->local->hw.wiphy->bands[band];
                rate->legacy = sband->bitrates[idx].bitrate;
@@ -444,13 +445,32 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
 
        sinfo->rxrate.flags = 0;
-       if (sta->last_rx_rate_flag & RX_FLAG_HT)
+       if (sta->last_rx_rate_flag & RX_FLAG_HT) {
                sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
+               sinfo->rxrate.mcs = sta->last_rx_rate_idx;
+       } else if (sta->last_rx_rate_flag & RX_FLAG_VHT) {
+               sinfo->rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
+               sinfo->rxrate.nss = sta->last_rx_rate_vht_nss;
+               sinfo->rxrate.mcs = sta->last_rx_rate_idx;
+       } else {
+               struct ieee80211_supported_band *sband;
+
+               sband = sta->local->hw.wiphy->bands[
+                               ieee80211_get_sdata_band(sta->sdata)];
+               sinfo->rxrate.legacy =
+                       sband->bitrates[sta->last_rx_rate_idx].bitrate;
+       }
+
        if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
                sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
        if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
                sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-       rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx);
+       if (sta->last_rx_rate_flag & RX_FLAG_80MHZ)
+               sinfo->rxrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+       if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ)
+               sinfo->rxrate.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
+       if (sta->last_rx_rate_flag & RX_FLAG_160MHZ)
+               sinfo->rxrate.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
 
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
index b2ae2baefc9a3673ec51eb8e0c0f7486dca0d890..825f33cf7bbc81834dca8e143674a0be31c74547 100644 (file)
@@ -193,7 +193,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        pos++;
 
        /* IEEE80211_RADIOTAP_RATE */
-       if (!rate || status->flag & RX_FLAG_HT) {
+       if (!rate || status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) {
                /*
                 * Without rate information don't add it. If we have,
                 * MCS information is a separate field in radiotap,
@@ -213,7 +213,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        if (status->band == IEEE80211_BAND_5GHZ)
                put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
                                   pos);
-       else if (status->flag & RX_FLAG_HT)
+       else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
                put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
                                   pos);
        else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
@@ -1356,6 +1356,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                        if (ieee80211_is_data(hdr->frame_control)) {
                                sta->last_rx_rate_idx = status->rate_idx;
                                sta->last_rx_rate_flag = status->flag;
+                               sta->last_rx_rate_vht_nss = status->vht_nss;
                        }
                }
        } else if (!is_multicast_ether_addr(hdr->addr1)) {
@@ -1367,6 +1368,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                if (ieee80211_is_data(hdr->frame_control)) {
                        sta->last_rx_rate_idx = status->rate_idx;
                        sta->last_rx_rate_flag = status->flag;
+                       sta->last_rx_rate_vht_nss = status->vht_nss;
                }
        }
 
@@ -2710,7 +2712,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
                status = IEEE80211_SKB_RXCB((rx->skb));
 
                sband = rx->local->hw.wiphy->bands[status->band];
-               if (!(status->flag & RX_FLAG_HT))
+               if (!(status->flag & RX_FLAG_HT) &&
+                   !(status->flag & RX_FLAG_VHT))
                        rate = &sband->bitrates[status->rate_idx];
 
                ieee80211_rx_cooked_monitor(rx, rate);
@@ -2877,8 +2880,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
                        status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
                } else if (!rx->sta) {
                        int rate_idx;
-                       if (status->flag & RX_FLAG_HT)
-                               rate_idx = 0; /* TODO: HT rates */
+                       if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
+                               rate_idx = 0; /* TODO: HT/VHT rates */
                        else
                                rate_idx = status->rate_idx;
                        ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
@@ -3154,6 +3157,13 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                                 status->rate_idx,
                                 status->rate_idx))
                                goto drop;
+               } else if (status->flag & RX_FLAG_VHT) {
+                       if (WARN_ONCE(status->rate_idx > 9 ||
+                                     !status->vht_nss ||
+                                     status->vht_nss > 8,
+                                     "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n",
+                                     status->rate_idx, status->vht_nss))
+                               goto drop;
                } else {
                        if (WARN_ON(status->rate_idx >= sband->n_bitrates))
                                goto drop;
index 2b2d5aac2bb10b16cb738407eb4ae95eeb7cd4dd..6835cea4e40248b43bdfdcbb0a7413271b5e4b95 100644 (file)
@@ -227,6 +227,7 @@ struct sta_ampdu_mlme {
  *     "the" transmit rate
  * @last_rx_rate_idx: rx status rate index of the last data packet
  * @last_rx_rate_flag: rx status flag of the last data packet
+ * @last_rx_rate_vht_nss: rx status nss of last data packet
  * @lock: used for locking all fields that require locking, see comments
  *     in the header file.
  * @drv_unblock_wk: used for driver PS unblocking
@@ -343,7 +344,8 @@ struct sta_info {
        unsigned long tx_fragments;
        struct ieee80211_tx_rate last_tx_rate;
        int last_rx_rate_idx;
-       int last_rx_rate_flag;
+       u32 last_rx_rate_flag;
+       u8 last_rx_rate_vht_nss;
        u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
 
        /*
index 3b3dd32f121f89b4f413e4065ffdd0fa33c70cb9..dc7f6b264593d90879a2836a3e95833f635e4b21 100644 (file)
@@ -2069,6 +2069,20 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
                        ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
                if (status->flag & RX_FLAG_SHORT_GI)
                        ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
+       } else if (status->flag & RX_FLAG_VHT) {
+               ri.flags |= RATE_INFO_FLAGS_VHT_MCS;
+               ri.mcs = status->rate_idx;
+               ri.nss = status->vht_nss;
+               if (status->flag & RX_FLAG_40MHZ)
+                       ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+               if (status->flag & RX_FLAG_80MHZ)
+                       ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+               if (status->flag & RX_FLAG_80P80MHZ)
+                       ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
+               if (status->flag & RX_FLAG_160MHZ)
+                       ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+               if (status->flag & RX_FLAG_SHORT_GI)
+                       ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
        } else {
                struct ieee80211_supported_band *sband;