mac80211: add VHT support for IBSS
authorJanusz.Dziedzic@tieto.com <Janusz.Dziedzic@tieto.com>
Fri, 20 Mar 2015 05:37:01 +0000 (06:37 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 30 Mar 2015 08:48:26 +0000 (10:48 +0200)
Add VHT support for IBSS. Drivers could activate
this feature by setting NL80211_EXT_FEATURE_VHT_IBSS
flag.

Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/mesh_plink.c
net/mac80211/util.c

index ff630be2ca750182fabfce3ea363a44cd24d7928..7a76ce639d58d6071681551e916f0125cf376212 100644 (file)
@@ -252,8 +252,6 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
                break;
        }
 
-       if (bw != sta->sta.bandwidth)
-               changed = true;
        sta->sta.bandwidth = bw;
 
        sta->cur_max_bandwidth =
index 8f8391e008ed585f0d0862a533bf809c937c03f8..52d629d5e79705d02768c22c6e1f69e15ae4c20c 100644 (file)
@@ -188,6 +188,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
                 */
                pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
                                                 chandef, 0);
+
+               /* add VHT capability and information IEs */
+               if (chandef->width != NL80211_CHAN_WIDTH_20 &&
+                   chandef->width != NL80211_CHAN_WIDTH_40 &&
+                   sband->vht_cap.vht_supported) {
+                       pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
+                                                        sband->vht_cap.cap);
+                       pos = ieee80211_ie_build_vht_oper(pos, &sband->vht_cap,
+                                                         chandef);
+               }
        }
 
        if (local->hw.queues >= IEEE80211_NUM_ACS)
@@ -415,6 +425,11 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                                        NL80211_CHAN_WIDTH_20_NOHT);
                chandef.width = sdata->u.ibss.chandef.width;
                break;
+       case NL80211_CHAN_WIDTH_80:
+       case NL80211_CHAN_WIDTH_160:
+               chandef = sdata->u.ibss.chandef;
+               chandef.chan = cbss->channel;
+               break;
        default:
                /* fall back to 20 MHz for unsupported modes */
                cfg80211_chandef_create(&chandef, cbss->channel,
@@ -1026,24 +1041,40 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
                /* we both use HT */
                struct ieee80211_ht_cap htcap_ie;
                struct cfg80211_chan_def chandef;
+               enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
 
                ieee80211_ht_oper_to_chandef(channel,
                                             elems->ht_operation,
                                             &chandef);
 
                memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
-
-               /*
-                * fall back to HT20 if we don't use or use
-                * the other extension channel
-                */
-               if (chandef.center_freq1 != sdata->u.ibss.chandef.center_freq1)
-                       htcap_ie.cap_info &=
-                               cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
                rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                                                   &htcap_ie,
                                                                   sta);
+
+               if (elems->vht_operation && elems->vht_cap_elem &&
+                   sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20 &&
+                   sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_40) {
+                       /* we both use VHT */
+                       struct ieee80211_vht_cap cap_ie;
+                       struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
+
+                       ieee80211_vht_oper_to_chandef(channel,
+                                                     elems->vht_operation,
+                                                     &chandef);
+                       memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
+                       ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
+                                                           &cap_ie, sta);
+                       if (memcmp(&cap, &sta->sta.vht_cap, sizeof(cap)))
+                               rates_updated |= true;
+               }
+
+               if (bw != sta->sta.bandwidth)
+                       rates_updated |= true;
+
+               if (!cfg80211_chandef_compatible(&sdata->u.ibss.chandef,
+                                                &chandef))
+                       WARN_ON_ONCE(1);
        }
 
        if (sta && rates_updated) {
index 3331c62b443359ab3a0a0d726b93aa6549ed8f0e..81340abb3876d53a44ddd7324e30f511942887a4 100644 (file)
@@ -1960,6 +1960,9 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
 void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
                                  const struct ieee80211_ht_operation *ht_oper,
                                  struct cfg80211_chan_def *chandef);
+void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
+                                  const struct ieee80211_vht_operation *oper,
+                                  struct cfg80211_chan_def *chandef);
 u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
 
 int __must_check
index 8465c055a3711c6aa739c560c238de9acc0af2c2..60d737f144e37563ebfaa9f7c82efafc3e2c9135 100644 (file)
@@ -382,6 +382,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
        enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
        struct ieee80211_supported_band *sband;
        u32 rates, basic_rates = 0, changed = 0;
+       enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
 
        sband = local->hw.wiphy->bands[band];
        rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates);
@@ -401,6 +402,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
                                              elems->ht_cap_elem, sta))
                changed |= IEEE80211_RC_BW_CHANGED;
 
+       if (bw != sta->sta.bandwidth)
+               changed |= IEEE80211_RC_BW_CHANGED;
+
        /* HT peer is operating 20MHz-only */
        if (elems->ht_operation &&
            !(elems->ht_operation->ht_param &
index e664b28821a2e571b2ce6f5e6963cf8fd5d75485..256647cb1d24b5525d8bf6101182871e82120b62 100644 (file)
@@ -2440,6 +2440,39 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
        cfg80211_chandef_create(chandef, control_chan, channel_type);
 }
 
+void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
+                                  const struct ieee80211_vht_operation *oper,
+                                  struct cfg80211_chan_def *chandef)
+{
+       if (!oper)
+               return;
+
+       chandef->chan = control_chan;
+
+       switch (oper->chan_width) {
+       case IEEE80211_VHT_CHANWIDTH_USE_HT:
+               break;
+       case IEEE80211_VHT_CHANWIDTH_80MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_80;
+               break;
+       case IEEE80211_VHT_CHANWIDTH_160MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_160;
+               break;
+       case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_80P80;
+               break;
+       default:
+               break;
+       }
+
+       chandef->center_freq1 =
+               ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
+                                              control_chan->band);
+       chandef->center_freq2 =
+               ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
+                                              control_chan->band);
+}
+
 int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
                             const struct ieee80211_supported_band *sband,
                             const u8 *srates, int srates_len, u32 *rates)