|
@@ -77,6 +77,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|
|
struct cfg80211_bss *bss;
|
|
|
u32 bss_change;
|
|
|
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
|
|
|
+ enum nl80211_channel_type channel_type;
|
|
|
|
|
|
lockdep_assert_held(&ifibss->mtx);
|
|
|
|
|
@@ -105,8 +106,16 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|
|
|
|
|
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
|
|
|
|
|
|
- local->oper_channel = chan;
|
|
|
- WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
|
|
|
+ channel_type = ifibss->channel_type;
|
|
|
+ if (channel_type > NL80211_CHAN_HT20 &&
|
|
|
+ !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
|
|
|
+ channel_type = NL80211_CHAN_HT20;
|
|
|
+ if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
|
|
|
+ /* can only fail due to HT40+/- mismatch */
|
|
|
+ channel_type = NL80211_CHAN_HT20;
|
|
|
+ WARN_ON(!ieee80211_set_channel_type(local, sdata,
|
|
|
+ NL80211_CHAN_HT20));
|
|
|
+ }
|
|
|
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
|
|
|
|
|
sband = local->hw.wiphy->bands[chan->band];
|
|
@@ -172,6 +181,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|
|
memcpy(skb_put(skb, ifibss->ie_len),
|
|
|
ifibss->ie, ifibss->ie_len);
|
|
|
|
|
|
+ /* add HT capability and information IEs */
|
|
|
+ if (channel_type && sband->ht_cap.ht_supported) {
|
|
|
+ pos = skb_put(skb, 4 +
|
|
|
+ sizeof(struct ieee80211_ht_cap) +
|
|
|
+ sizeof(struct ieee80211_ht_info));
|
|
|
+ pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
|
|
|
+ sband->ht_cap.cap);
|
|
|
+ pos = ieee80211_ie_build_ht_info(pos,
|
|
|
+ &sband->ht_cap,
|
|
|
+ chan,
|
|
|
+ channel_type);
|
|
|
+ }
|
|
|
+
|
|
|
if (local->hw.queues >= 4) {
|
|
|
pos = skb_put(skb, 9);
|
|
|
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
|
@@ -195,6 +217,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|
|
bss_change |= BSS_CHANGED_BEACON;
|
|
|
bss_change |= BSS_CHANGED_BEACON_ENABLED;
|
|
|
bss_change |= BSS_CHANGED_BASIC_RATES;
|
|
|
+ bss_change |= BSS_CHANGED_HT;
|
|
|
bss_change |= BSS_CHANGED_IBSS;
|
|
|
sdata->vif.bss_conf.ibss_joined = true;
|
|
|
ieee80211_bss_info_change_notify(sdata, bss_change);
|
|
@@ -268,6 +291,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|
|
u64 beacon_timestamp, rx_timestamp;
|
|
|
u32 supp_rates = 0;
|
|
|
enum ieee80211_band band = rx_status->band;
|
|
|
+ struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
|
|
|
+ bool rates_updated = false;
|
|
|
|
|
|
if (elems->ds_params && elems->ds_params_len == 1)
|
|
|
freq = ieee80211_channel_to_frequency(elems->ds_params[0],
|
|
@@ -307,7 +332,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|
|
prev_rates,
|
|
|
sta->sta.supp_rates[band]);
|
|
|
#endif
|
|
|
- rate_control_rate_init(sta);
|
|
|
+ rates_updated = true;
|
|
|
}
|
|
|
} else
|
|
|
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
|
|
@@ -318,6 +343,39 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|
|
if (sta && elems->wmm_info)
|
|
|
set_sta_flag(sta, WLAN_STA_WME);
|
|
|
|
|
|
+ if (sta && elems->ht_info_elem && elems->ht_cap_elem &&
|
|
|
+ sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
|
|
|
+ /* we both use HT */
|
|
|
+ struct ieee80211_sta_ht_cap sta_ht_cap_new;
|
|
|
+ enum nl80211_channel_type channel_type =
|
|
|
+ ieee80211_ht_info_to_channel_type(
|
|
|
+ elems->ht_info_elem);
|
|
|
+
|
|
|
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
|
|
+ elems->ht_cap_elem,
|
|
|
+ &sta_ht_cap_new);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * fall back to HT20 if we don't use or use
|
|
|
+ * the other extension channel
|
|
|
+ */
|
|
|
+ if ((channel_type == NL80211_CHAN_HT40MINUS ||
|
|
|
+ channel_type == NL80211_CHAN_HT40PLUS) &&
|
|
|
+ channel_type != sdata->u.ibss.channel_type)
|
|
|
+ sta_ht_cap_new.cap &=
|
|
|
+ ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
|
|
+
|
|
|
+ if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new,
|
|
|
+ sizeof(sta_ht_cap_new))) {
|
|
|
+ memcpy(&sta->sta.ht_cap, &sta_ht_cap_new,
|
|
|
+ sizeof(sta_ht_cap_new));
|
|
|
+ rates_updated = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sta && rates_updated)
|
|
|
+ rate_control_rate_init(sta);
|
|
|
+
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
|
|
|
@@ -899,10 +957,15 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
|
|
u32 changed = 0;
|
|
|
|
|
|
skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
|
|
|
- 36 /* bitrates */ +
|
|
|
- 34 /* SSID */ +
|
|
|
- 3 /* DS params */ +
|
|
|
- 4 /* IBSS params */ +
|
|
|
+ sizeof(struct ieee80211_hdr_3addr) +
|
|
|
+ 12 /* struct ieee80211_mgmt.u.beacon */ +
|
|
|
+ 2 + IEEE80211_MAX_SSID_LEN /* max SSID */ +
|
|
|
+ 2 + 8 /* max Supported Rates */ +
|
|
|
+ 3 /* max DS params */ +
|
|
|
+ 4 /* IBSS params */ +
|
|
|
+ 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
|
|
|
+ 2 + sizeof(struct ieee80211_ht_cap) +
|
|
|
+ 2 + sizeof(struct ieee80211_ht_info) +
|
|
|
params->ie_len);
|
|
|
if (!skb)
|
|
|
return -ENOMEM;
|
|
@@ -923,13 +986,15 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
|
|
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
|
|
|
|
|
|
sdata->u.ibss.channel = params->channel;
|
|
|
+ sdata->u.ibss.channel_type = params->channel_type;
|
|
|
sdata->u.ibss.fixed_channel = params->channel_fixed;
|
|
|
|
|
|
/* fix ourselves to that channel now already */
|
|
|
if (params->channel_fixed) {
|
|
|
sdata->local->oper_channel = params->channel;
|
|
|
- WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
|
|
|
- NL80211_CHAN_NO_HT));
|
|
|
+ if (!ieee80211_set_channel_type(sdata->local, sdata,
|
|
|
+ params->channel_type))
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
if (params->ie) {
|