These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / mac80211 / vht.c
index 80694d5..c38b2f0 100644 (file)
@@ -120,6 +120,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
        struct ieee80211_sta_vht_cap own_cap;
        u32 cap_info, i;
+       bool have_80mhz;
 
        memset(vht_cap, 0, sizeof(*vht_cap));
 
@@ -129,6 +130,20 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
        if (!vht_cap_ie || !sband->vht_cap.vht_supported)
                return;
 
+       /* Allow VHT if at least one channel on the sband supports 80 MHz */
+       have_80mhz = false;
+       for (i = 0; i < sband->n_channels; i++) {
+               if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED |
+                                               IEEE80211_CHAN_NO_80MHZ))
+                       continue;
+
+               have_80mhz = true;
+               break;
+       }
+
+       if (!have_80mhz)
+               return;
+
        /*
         * A VHT STA must support 40 MHz, but if we verify that here
         * then we break a few things - some APs (e.g. Netgear R6300v2
@@ -308,11 +323,15 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        enum ieee80211_sta_rx_bandwidth bw;
+       enum nl80211_chan_width bss_width = sdata->vif.bss_conf.chandef.width;
 
-       bw = ieee80211_chan_width_to_rx_bw(sdata->vif.bss_conf.chandef.width);
-       bw = min(bw, ieee80211_sta_cap_rx_bw(sta));
+       bw = ieee80211_sta_cap_rx_bw(sta);
        bw = min(bw, sta->cur_max_bandwidth);
 
+       /* do not cap the BW of TDLS WIDER_BW peers by the bss */
+       if (!test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW))
+               bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width));
+
        return bw;
 }
 
@@ -359,7 +378,7 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta)
 
 u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                  struct sta_info *sta, u8 opmode,
-                                 enum ieee80211_band band, bool nss_only)
+                                 enum ieee80211_band band)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
@@ -382,9 +401,6 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                changed |= IEEE80211_RC_NSS_CHANGED;
        }
 
-       if (nss_only)
-               return changed;
-
        switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
@@ -411,14 +427,39 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 
 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                 struct sta_info *sta, u8 opmode,
-                                enum ieee80211_band band, bool nss_only)
+                                enum ieee80211_band band)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
 
-       u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode,
-                                                   band, nss_only);
+       u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band);
 
        if (changed > 0)
                rate_control_rate_update(local, sband, sta, changed);
 }
+
+void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
+                                    u16 vht_mask[NL80211_VHT_NSS_MAX])
+{
+       int i;
+       u16 mask, cap = le16_to_cpu(vht_cap);
+
+       for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
+               mask = (cap >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+               switch (mask) {
+               case IEEE80211_VHT_MCS_SUPPORT_0_7:
+                       vht_mask[i] = 0x00FF;
+                       break;
+               case IEEE80211_VHT_MCS_SUPPORT_0_8:
+                       vht_mask[i] = 0x01FF;
+                       break;
+               case IEEE80211_VHT_MCS_SUPPORT_0_9:
+                       vht_mask[i] = 0x03FF;
+                       break;
+               case IEEE80211_VHT_MCS_NOT_SUPPORTED:
+               default:
+                       vht_mask[i] = 0;
+                       break;
+               }
+       }
+}