diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-06-24 19:53:22 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2011-06-24 19:53:22 +0000 |
commit | 9a1ca00d394b0b7e4e52c976dbd2428fd912ab2c (patch) | |
tree | 3705d13db9a9a43840f47669772a58a33bc14974 /package/mac80211/patches | |
parent | 753d0657bbde0b6055363f551900b348e1c51349 (diff) | |
download | master-187ad058-9a1ca00d394b0b7e4e52c976dbd2428fd912ab2c.tar.gz master-187ad058-9a1ca00d394b0b7e4e52c976dbd2428fd912ab2c.tar.bz2 master-187ad058-9a1ca00d394b0b7e4e52c976dbd2428fd912ab2c.zip |
mac80211: add the work-in-progress IBSS HT patch, with some minor fixes
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@27277 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/mac80211/patches')
-rw-r--r-- | package/mac80211/patches/310-ibss_ht.patch | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/package/mac80211/patches/310-ibss_ht.patch b/package/mac80211/patches/310-ibss_ht.patch new file mode 100644 index 0000000000..1518afd3d0 --- /dev/null +++ b/package/mac80211/patches/310-ibss_ht.patch @@ -0,0 +1,637 @@ +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -1038,6 +1038,7 @@ struct cfg80211_ibss_params { + u8 *ssid; + u8 *bssid; + struct ieee80211_channel *channel; ++ enum nl80211_channel_type channel_type; + u8 *ie; + u8 ssid_len, ie_len; + u16 beacon_interval; +@@ -2539,6 +2540,12 @@ struct cfg80211_bss *cfg80211_get_bss(st + const u8 *bssid, + const u8 *ssid, size_t ssid_len, + u16 capa_mask, u16 capa_val); ++struct cfg80211_bss *cfg80211_get_bss_ht(struct wiphy *wiphy, ++ struct ieee80211_channel *channel, ++ const u8 *bssid, ++ const u8 *ssid, size_t ssid_len, ++ u16 capa_mask, u16 capa_val, ++ enum nl80211_channel_type channel_type); + static inline struct cfg80211_bss * + cfg80211_get_ibss(struct wiphy *wiphy, + struct ieee80211_channel *channel, +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -439,6 +439,7 @@ struct ieee80211_if_ibss { + u8 ssid_len, ie_len; + u8 *ie; + struct ieee80211_channel *channel; ++ enum nl80211_channel_type channel_type; + + unsigned long ibss_join_req; + /* probe response/beacon for IBSS */ +@@ -1121,6 +1122,7 @@ void ieee80211_ibss_notify_scan_complete + void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); + struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, + u8 *bssid, u8 *addr, u32 supp_rates, ++ struct ieee80211_ht_cap *ht_cap, + gfp_t gfp); + int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, + struct cfg80211_ibss_params *params); +@@ -1373,6 +1375,12 @@ void ieee80211_recalc_smps(struct ieee80 + size_t ieee80211_ie_split(const u8 *ies, size_t ielen, + const u8 *ids, int n_ids, size_t offset); + size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); ++u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, ++ u16 cap); ++u8 *ieee80211_ie_build_ht_info(u8 *pos, ++ struct ieee80211_sta_ht_cap *ht_cap, ++ struct ieee80211_channel *channel, ++ enum nl80211_channel_type channel_type); + + /* internal work items */ + void ieee80211_work_init(struct ieee80211_local *local); +@@ -1401,6 +1409,8 @@ ieee80211_get_channel_mode(struct ieee80 + bool ieee80211_set_channel_type(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + enum nl80211_channel_type chantype); ++enum nl80211_channel_type ieee80211_ht_info_to_channel_type( ++ struct ieee80211_ht_info *ht_info); + + #ifdef CONFIG_MAC80211_NOINLINE + #define debug_noinline noinline +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -1007,23 +1007,8 @@ int ieee80211_build_preq_ies(struct ieee + offset = noffset; + } + +- if (sband->ht_cap.ht_supported) { +- u16 cap = sband->ht_cap.cap; +- __le16 tmp; +- +- *pos++ = WLAN_EID_HT_CAPABILITY; +- *pos++ = sizeof(struct ieee80211_ht_cap); +- memset(pos, 0, sizeof(struct ieee80211_ht_cap)); +- tmp = cpu_to_le16(cap); +- memcpy(pos, &tmp, sizeof(u16)); +- pos += sizeof(u16); +- *pos++ = sband->ht_cap.ampdu_factor | +- (sband->ht_cap.ampdu_density << +- IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); +- memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); +- pos += sizeof(sband->ht_cap.mcs); +- pos += 2 + 4 + 1; /* ext info, BF cap, antsel */ +- } ++ if (sband->ht_cap.ht_supported) ++ pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap); + + /* + * If adding more here, adjust code in main.c +@@ -1464,3 +1449,100 @@ size_t ieee80211_ie_split_vendor(const u + + return pos; + } ++ ++u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, ++ u16 cap) ++{ ++ __le16 tmp; ++ ++ *pos++ = WLAN_EID_HT_CAPABILITY; ++ *pos++ = sizeof(struct ieee80211_ht_cap); ++ memset(pos, 0, sizeof(struct ieee80211_ht_cap)); ++ ++ /* capability flags */ ++ tmp = cpu_to_le16(cap); ++ memcpy(pos, &tmp, sizeof(u16)); ++ pos += sizeof(u16); ++ ++ /* AMPDU parameters */ ++ *pos++ = sband->ht_cap.ampdu_factor | ++ (sband->ht_cap.ampdu_density << ++ IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); ++ ++ /* MCS set */ ++ memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); ++ pos += sizeof(sband->ht_cap.mcs); ++ ++ /* extended capabilities */ ++ pos += sizeof(__le16); ++ ++ /* BF capabilities */ ++ pos += sizeof(__le32); ++ ++ /* antenna selection */ ++ pos += sizeof(u8); ++ ++ return pos; ++} ++ ++u8 *ieee80211_ie_build_ht_info(u8 *pos, ++ struct ieee80211_sta_ht_cap *ht_cap, ++ struct ieee80211_channel *channel, ++ enum nl80211_channel_type channel_type) ++{ ++ struct ieee80211_ht_info *ht_info; ++ /* Build HT Information */ ++ *pos++ = WLAN_EID_HT_INFORMATION; ++ *pos++ = sizeof(struct ieee80211_ht_info); ++ ht_info = (struct ieee80211_ht_info *)pos; ++ ht_info->control_chan = ++ ieee80211_frequency_to_channel(channel->center_freq); ++ switch (channel_type) { ++ case NL80211_CHAN_HT40MINUS: ++ ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; ++ break; ++ case NL80211_CHAN_HT40PLUS: ++ ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; ++ break; ++ case NL80211_CHAN_HT20: ++ default: ++ ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; ++ break; ++ } ++ if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ++ ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; ++ ht_info->operation_mode = 0x0000; ++ ht_info->stbc_param = 0x0000; ++ ++ /* It seems that Basic MCS set and Supported MCS set ++ are identical for the first 10 bytes */ ++ memset(&ht_info->basic_set, 0, 16); ++ memcpy(&ht_info->basic_set, &ht_cap->mcs, 10); ++ ++ return pos + sizeof(struct ieee80211_ht_info); ++} ++ ++enum nl80211_channel_type ieee80211_ht_info_to_channel_type( ++ struct ieee80211_ht_info *ht_info) ++{ ++ enum nl80211_channel_type channel_type; ++ ++ if (!ht_info) ++ return NL80211_CHAN_NO_HT; ++ ++ switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { ++ case IEEE80211_HT_PARAM_CHA_SEC_NONE: ++ channel_type = NL80211_CHAN_HT20; ++ break; ++ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: ++ channel_type = NL80211_CHAN_HT40PLUS; ++ break; ++ case IEEE80211_HT_PARAM_CHA_SEC_BELOW: ++ channel_type = NL80211_CHAN_HT40MINUS; ++ break; ++ default: ++ channel_type = NL80211_CHAN_NO_HT; ++ } ++ ++ return channel_type; ++} +--- a/net/mac80211/work.c ++++ b/net/mac80211/work.c +@@ -117,7 +117,6 @@ static void ieee80211_add_ht_ie(struct s + u8 *pos; + u32 flags = channel->flags; + u16 cap = sband->ht_cap.cap; +- __le16 tmp; + + if (!sband->ht_cap.ht_supported) + return; +@@ -168,34 +167,8 @@ static void ieee80211_add_ht_ie(struct s + } + + /* reserve and fill IE */ +- + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); +- *pos++ = WLAN_EID_HT_CAPABILITY; +- *pos++ = sizeof(struct ieee80211_ht_cap); +- memset(pos, 0, sizeof(struct ieee80211_ht_cap)); +- +- /* capability flags */ +- tmp = cpu_to_le16(cap); +- memcpy(pos, &tmp, sizeof(u16)); +- pos += sizeof(u16); +- +- /* AMPDU parameters */ +- *pos++ = sband->ht_cap.ampdu_factor | +- (sband->ht_cap.ampdu_density << +- IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); +- +- /* MCS set */ +- memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); +- pos += sizeof(sband->ht_cap.mcs); +- +- /* extended capabilities */ +- pos += sizeof(__le16); +- +- /* BF capabilities */ +- pos += sizeof(__le32); +- +- /* antenna selection */ +- pos += sizeof(u8); ++ ieee80211_ie_build_ht_cap(pos, sband, cap); + } + + static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -365,6 +365,18 @@ struct cfg80211_bss *cfg80211_get_bss(st + const u8 *ssid, size_t ssid_len, + u16 capa_mask, u16 capa_val) + { ++ return cfg80211_get_bss_ht(wiphy, channel, bssid, ssid, ssid_len, ++ capa_mask, capa_val, NL80211_CHAN_NO_HT); ++} ++EXPORT_SYMBOL(cfg80211_get_bss); ++ ++struct cfg80211_bss *cfg80211_get_bss_ht(struct wiphy *wiphy, ++ struct ieee80211_channel *channel, ++ const u8 *bssid, ++ const u8 *ssid, size_t ssid_len, ++ u16 capa_mask, u16 capa_val, ++ enum nl80211_channel_type channel_type) ++{ + struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); + struct cfg80211_internal_bss *bss, *res = NULL; + unsigned long now = jiffies; +@@ -374,8 +386,27 @@ struct cfg80211_bss *cfg80211_get_bss(st + list_for_each_entry(bss, &dev->bss_list, list) { + if ((bss->pub.capability & capa_mask) != capa_val) + continue; +- if (channel && bss->pub.channel != channel) +- continue; ++ if (channel) { ++ if (bss->pub.channel != channel) ++ continue; ++ if (channel_type == NL80211_CHAN_HT40MINUS || ++ channel_type == NL80211_CHAN_HT40PLUS) { ++ struct ieee80211_ht_info *ht_info; ++ ht_info = (struct ieee80211_ht_info *) ++ ieee80211_bss_get_ie(&bss->pub, ++ WLAN_EID_HT_INFORMATION); ++ if (!ht_info) ++ continue; ++ if (channel_type == NL80211_CHAN_HT40MINUS && ++ !(ht_info->ht_param & ++ IEEE80211_HT_PARAM_CHA_SEC_BELOW)) ++ continue; ++ if (channel_type == NL80211_CHAN_HT40PLUS && ++ !(ht_info->ht_param & ++ IEEE80211_HT_PARAM_CHA_SEC_ABOVE)) ++ continue; ++ } ++ } + /* Don't get expired BSS structs */ + if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) && + !atomic_read(&bss->hold)) +@@ -392,7 +423,7 @@ struct cfg80211_bss *cfg80211_get_bss(st + return NULL; + return &res->pub; + } +-EXPORT_SYMBOL(cfg80211_get_bss); ++EXPORT_SYMBOL(cfg80211_get_bss_ht); + + struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, + struct ieee80211_channel *channel, +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -4282,13 +4282,42 @@ static int nl80211_join_ibss(struct sk_b + ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + } + +- ibss.channel = ieee80211_get_channel(wiphy, +- nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); ++ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { ++ enum nl80211_channel_type channel_type; ++ ++ channel_type = nla_get_u32( ++ info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); ++ if (channel_type != NL80211_CHAN_NO_HT && ++ channel_type != NL80211_CHAN_HT20 && ++ channel_type != NL80211_CHAN_HT40PLUS && ++ channel_type != NL80211_CHAN_HT40MINUS) ++ return -EINVAL; ++ ibss.channel_type = channel_type; ++ } else { ++ ibss.channel_type = NL80211_CHAN_NO_HT; ++ } ++ ++ ibss.channel = rdev_freq_to_chan(rdev, ++ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), ++ ibss.channel_type); ++ + if (!ibss.channel || ++ ibss.channel->flags & IEEE80211_CHAN_PASSIVE_SCAN || + ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || + ibss.channel->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + ++#if 0 ++ if ((ibss.channel_type == NL80211_CHAN_HT40PLUS || ++ ibss.channel_type == NL80211_CHAN_HT40MINUS) && ++ !can_beacon_sec_chan(&rdev->wiphy, ibss.chan, ibss.channel_type)) { ++ printk(KERN_DEBUG ++ "cfg80211: Secondary channel not " ++ "allowed to initiate communication\n"); ++ return -EINVAL; ++ } ++#endif ++ + ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; + ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; + +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -178,6 +178,8 @@ static void ieee80211_send_addba_resp(st + memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); + else if (sdata->vif.type == NL80211_IFTYPE_WDS) + memcpy(mgmt->bssid, da, ETH_ALEN); ++ else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) ++ memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN); + + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); +--- a/net/mac80211/agg-tx.c ++++ b/net/mac80211/agg-tx.c +@@ -84,6 +84,8 @@ static void ieee80211_send_addba_request + memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); ++ else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) ++ memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN); + + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); +@@ -400,7 +402,8 @@ int ieee80211_start_tx_ba_session(struct + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_AP && +- sdata->vif.type != NL80211_IFTYPE_WDS) ++ sdata->vif.type != NL80211_IFTYPE_WDS && ++ sdata->vif.type != NL80211_IFTYPE_ADHOC) + return -EINVAL; + + if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) { +--- a/net/mac80211/ht.c ++++ b/net/mac80211/ht.c +@@ -203,6 +203,8 @@ void ieee80211_send_delba(struct ieee802 + memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); ++ else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) ++ memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN); + + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); +--- a/net/mac80211/ibss.c ++++ b/net/mac80211/ibss.c +@@ -64,6 +64,7 @@ static void ieee80211_rx_mgmt_auth_ibss( + static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, + const u8 *bssid, const int beacon_int, + struct ieee80211_channel *chan, ++ enum nl80211_channel_type channel_type, + const u32 basic_rates, + const u16 capability, u64 tsf) + { +@@ -104,8 +105,12 @@ static void __ieee80211_sta_join_ibss(st + + sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; + ++ /* entering a legacy IBSS. Use given HT configuration. */ ++ if (channel_type == NL80211_CHAN_NO_HT) ++ channel_type = ifibss->channel_type; ++ + local->oper_channel = chan; +- WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT)); ++ WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type)); + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + + sband = local->hw.wiphy->bands[chan->band]; +@@ -171,6 +176,17 @@ static void __ieee80211_sta_join_ibss(st + memcpy(skb_put(skb, ifibss->ie_len), + ifibss->ie, ifibss->ie_len); + ++ if (channel_type != NL80211_CHAN_NO_HT && 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, 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; +@@ -219,6 +235,8 @@ static void ieee80211_sta_join_ibss(stru + u32 basic_rates; + int i, j; + u16 beacon_int = cbss->beacon_interval; ++ const u8 *ht_info_ie; ++ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + + lockdep_assert_held(&sdata->u.ibss.mtx); + +@@ -242,9 +260,15 @@ static void ieee80211_sta_join_ibss(stru + } + } + ++ ht_info_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_INFORMATION); ++ if (ht_info_ie) ++ channel_type = ieee80211_ht_info_to_channel_type( ++ (struct ieee80211_ht_info *) (ht_info_ie + 2)); ++ + __ieee80211_sta_join_ibss(sdata, cbss->bssid, + beacon_int, + cbss->channel, ++ channel_type, + basic_rates, + cbss->capability, + cbss->tsf); +@@ -310,11 +334,65 @@ static void ieee80211_rx_bss_info(struct + } else + sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, + mgmt->sa, supp_rates, +- GFP_ATOMIC); ++ elems->ht_cap_elem, GFP_ATOMIC); + } + +- if (sta && elems->wmm_info) +- set_sta_flags(sta, WLAN_STA_WME); ++ if (sta) { ++ if (elems->wmm_info) ++ set_sta_flags(sta, WLAN_STA_WME); ++ ++ if (elems->ht_info_elem) { ++ struct ieee80211_supported_band *sband = ++ local->hw.wiphy->bands[channel->band]; ++ enum nl80211_channel_type channel_type; ++ ++ channel_type = ++ ieee80211_ht_info_to_channel_type( ++ elems->ht_info_elem); ++ if (channel_type != local->_oper_channel_type) { ++ struct sk_buff *skb = ++ sdata->u.ibss.presp; ++ struct sk_buff *nskb; ++ u8 *ht_ie; ++ ++ nskb = skb_copy(skb, GFP_ATOMIC); ++ ht_ie = (u8 *) cfg80211_find_ie( ++ WLAN_EID_HT_CAPABILITY, ++ nskb->data + 24 + ++ sizeof(mgmt->u.beacon), ++ nskb->len - 24 - ++ sizeof(mgmt->u.beacon)); ++ ++ if (!ht_ie) ++ ht_ie = skb_put(nskb, 4 + ++ sizeof(struct ieee80211_ht_cap) + ++ sizeof(struct ieee80211_ht_info)); ++ ht_ie = ieee80211_ie_build_ht_cap(ht_ie, ++ sband, ++ sband->ht_cap.cap); ++ ht_ie = ieee80211_ie_build_ht_info( ++ ht_ie, ++ &sband->ht_cap, ++ channel, ++ channel_type); ++ sdata->u.ibss.presp = nskb; ++ kfree_skb(skb); ++ ++ local->_oper_channel_type = ++ channel_type; ++ WARN_ON(!ieee80211_set_channel_type( ++ local, ++ sdata, ++ channel_type)); ++ ieee80211_hw_config(local, ++ IEEE80211_CONF_CHANGE_CHANNEL); ++ } ++ ieee80211_ht_cap_ie_to_sta_ht_cap(sband, ++ elems->ht_cap_elem, ++ &sta->sta.ht_cap); ++ ++ } ++ } + + rcu_read_unlock(); + } +@@ -404,7 +482,7 @@ static void ieee80211_rx_bss_info(struct + ieee80211_sta_join_ibss(sdata, bss); + supp_rates = ieee80211_sta_get_rates(local, elems, band); + ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, +- supp_rates, GFP_KERNEL); ++ supp_rates, elems->ht_cap_elem, GFP_KERNEL); + } + + put_bss: +@@ -417,7 +495,8 @@ static void ieee80211_rx_bss_info(struct + * must be callable in atomic context. + */ + struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, +- u8 *bssid,u8 *addr, u32 supp_rates, ++ u8 *bssid, u8 *addr, u32 supp_rates, ++ struct ieee80211_ht_cap *ht_cap, + gfp_t gfp) + { + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; +@@ -458,6 +537,11 @@ struct sta_info *ieee80211_ibss_add_sta( + sta->sta.supp_rates[band] = supp_rates | + ieee80211_mandatory_rates(local, band); + ++ /* fill in ht rates */ ++ if (ht_cap) ++ ieee80211_ht_cap_ie_to_sta_ht_cap(local->hw.wiphy->bands[band], ++ ht_cap, &sta->sta.ht_cap); ++ + rate_control_rate_init(sta); + + /* If it fails, maybe we raced another insertion? */ +@@ -556,8 +640,8 @@ static void ieee80211_sta_create_ibss(st + sdata->drop_unencrypted = 0; + + __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, +- ifibss->channel, ifibss->basic_rates, +- capability, 0); ++ ifibss->channel, ifibss->channel_type, ++ ifibss->basic_rates, capability, 0); + } + + /* +@@ -594,10 +678,10 @@ static void ieee80211_sta_find_ibss(stru + chan = ifibss->channel; + if (!is_zero_ether_addr(ifibss->bssid)) + bssid = ifibss->bssid; +- cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, ++ cbss = cfg80211_get_bss_ht(local->hw.wiphy, chan, bssid, + ifibss->ssid, ifibss->ssid_len, + WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY, +- capability); ++ capability, ifibss->channel_type); + + if (cbss) { + struct ieee80211_bss *bss; +@@ -896,10 +980,15 @@ int ieee80211_ibss_join(struct ieee80211 + struct sk_buff *skb; + + 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; +@@ -920,13 +1009,14 @@ int ieee80211_ibss_join(struct ieee80211 + 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)); ++ params->channel_type)); + } + + if (params->ie) { +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -2138,7 +2138,8 @@ ieee80211_rx_h_action(struct ieee80211_r + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_AP && +- sdata->vif.type != NL80211_IFTYPE_WDS) ++ sdata->vif.type != NL80211_IFTYPE_WDS && ++ sdata->vif.type != NL80211_IFTYPE_ADHOC) + break; + + /* verify action_code is present */ +@@ -2654,7 +2655,8 @@ static int prepare_for_handlers(struct i + else + rate_idx = status->rate_idx; + rx->sta = ieee80211_ibss_add_sta(sdata, bssid, +- hdr->addr2, BIT(rate_idx), GFP_ATOMIC); ++ hdr->addr2, BIT(rate_idx), NULL, ++ GFP_ATOMIC); + } + break; + case NL80211_IFTYPE_MESH_POINT: |