diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-08-11 13:52:27 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2011-08-11 13:52:27 +0000 |
commit | 400f75a1b657eceb5e661adb5bf56c2498b4a2ff (patch) | |
tree | 1d85da294b86812834c0c0ba2c7ef076e866bbdb /package/mac80211/patches/310-ibss_ht.patch | |
parent | ce2ced73118dfd1dab21392f91cda19f005f949d (diff) | |
download | upstream-400f75a1b657eceb5e661adb5bf56c2498b4a2ff.tar.gz upstream-400f75a1b657eceb5e661adb5bf56c2498b4a2ff.tar.bz2 upstream-400f75a1b657eceb5e661adb5bf56c2498b4a2ff.zip |
mac80211: update to 2011-08-10
SVN-Revision: 27958
Diffstat (limited to 'package/mac80211/patches/310-ibss_ht.patch')
-rw-r--r-- | package/mac80211/patches/310-ibss_ht.patch | 479 |
1 files changed, 281 insertions, 198 deletions
diff --git a/package/mac80211/patches/310-ibss_ht.patch b/package/mac80211/patches/310-ibss_ht.patch index 1518afd3d0..0a770d22d3 100644 --- a/package/mac80211/patches/310-ibss_ht.patch +++ b/package/mac80211/patches/310-ibss_ht.patch @@ -1,6 +1,6 @@ --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h -@@ -1038,6 +1038,7 @@ struct cfg80211_ibss_params { +@@ -1045,6 +1045,7 @@ struct cfg80211_ibss_params { u8 *ssid; u8 *bssid; struct ieee80211_channel *channel; @@ -8,7 +8,7 @@ u8 *ie; u8 ssid_len, ie_len; u16 beacon_interval; -@@ -2539,6 +2540,12 @@ struct cfg80211_bss *cfg80211_get_bss(st +@@ -2478,6 +2479,12 @@ struct cfg80211_bss *cfg80211_get_bss(st const u8 *bssid, const u8 *ssid, size_t ssid_len, u16 capa_mask, u16 capa_val); @@ -21,9 +21,147 @@ static inline struct cfg80211_bss * cfg80211_get_ibss(struct wiphy *wiphy, struct ieee80211_channel *channel, +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -4351,13 +4351,41 @@ 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) ++ ibss.channel->flags & IEEE80211_CHAN_RADAR) + return -EINVAL; + ++ /* Both channels should be able to initiate communication */ ++ if ((ibss.channel_type == NL80211_CHAN_HT40PLUS || ++ ibss.channel_type == NL80211_CHAN_HT40MINUS) && ++ !can_beacon_sec_chan(&rdev->wiphy, ibss.channel, ++ ibss.channel_type)) { ++ printk(KERN_DEBUG ++ "cfg80211: Secondary channel not " ++ "allowed to initiate communication\n"); ++ return -EINVAL; ++ } ++ + ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; + ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; + +--- a/net/wireless/chan.c ++++ b/net/wireless/chan.c +@@ -44,7 +44,7 @@ rdev_freq_to_chan(struct cfg80211_regist + return chan; + } + +-static bool can_beacon_sec_chan(struct wiphy *wiphy, ++bool can_beacon_sec_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) + { +@@ -75,6 +75,7 @@ static bool can_beacon_sec_chan(struct w + + return true; + } ++EXPORT_SYMBOL(can_beacon_sec_chan); + + int cfg80211_set_freq(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, int freq, +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -441,6 +441,9 @@ cfg80211_can_add_interface(struct cfg802 + struct ieee80211_channel * + rdev_freq_to_chan(struct cfg80211_registered_device *rdev, + int freq, enum nl80211_channel_type channel_type); ++bool can_beacon_sec_chan(struct wiphy *wiphy, ++ struct ieee80211_channel *chan, ++ enum nl80211_channel_type channel_type); + int cfg80211_set_freq(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, int freq, + enum nl80211_channel_type channel_type); +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -365,6 +365,19 @@ struct cfg80211_bss *cfg80211_get_bss(st + const u8 *ssid, size_t ssid_len, + u16 capa_mask, u16 capa_val) + { ++ /* call HT version with no HT requirements */ ++ 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 require_ht) ++{ + struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); + struct cfg80211_internal_bss *bss, *res = NULL; + unsigned long now = jiffies; +@@ -374,8 +387,26 @@ 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 (require_ht != NL80211_CHAN_NO_HT) { ++ 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 (require_ht == NL80211_CHAN_HT40MINUS && ++ !(ht_info->ht_param & ++ IEEE80211_HT_PARAM_CHA_SEC_BELOW)) ++ continue; ++ if (require_ht == 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/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h -@@ -439,6 +439,7 @@ struct ieee80211_if_ibss { +@@ -464,6 +464,7 @@ struct ieee80211_if_ibss { u8 ssid_len, ie_len; u8 *ie; struct ieee80211_channel *channel; @@ -31,7 +169,7 @@ unsigned long ibss_join_req; /* probe response/beacon for IBSS */ -@@ -1121,6 +1122,7 @@ void ieee80211_ibss_notify_scan_complete +@@ -1151,6 +1152,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, @@ -39,7 +177,7 @@ 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 +@@ -1405,6 +1407,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); @@ -52,7 +190,7 @@ /* internal work items */ void ieee80211_work_init(struct ieee80211_local *local); -@@ -1401,6 +1409,8 @@ ieee80211_get_channel_mode(struct ieee80 +@@ -1433,6 +1441,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); @@ -63,7 +201,7 @@ #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 +@@ -1008,23 +1008,8 @@ int ieee80211_build_preq_ies(struct ieee offset = noffset; } @@ -89,10 +227,10 @@ /* * If adding more here, adjust code in main.c -@@ -1464,3 +1449,100 @@ size_t ieee80211_ie_split_vendor(const u - - return pos; +@@ -1548,3 +1533,100 @@ void ieee80211_disable_rssi_reports(stru + _ieee80211_enable_rssi_reports(sdata, 0, 0); } + EXPORT_SYMBOL(ieee80211_disable_rssi_reports); + +u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband, + u16 cap) @@ -192,7 +330,7 @@ +} --- a/net/mac80211/work.c +++ b/net/mac80211/work.c -@@ -117,7 +117,6 @@ static void ieee80211_add_ht_ie(struct s +@@ -118,7 +118,6 @@ static void ieee80211_add_ht_ie(struct s u8 *pos; u32 flags = channel->flags; u16 cap = sband->ht_cap.cap; @@ -200,7 +338,7 @@ if (!sband->ht_cap.ht_supported) return; -@@ -168,34 +167,8 @@ static void ieee80211_add_ht_ie(struct s +@@ -169,34 +168,8 @@ static void ieee80211_add_ht_ie(struct s } /* reserve and fill IE */ @@ -236,124 +374,6 @@ } 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 @@ -388,7 +408,84 @@ IEEE80211_STYPE_ACTION); --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c -@@ -64,6 +64,7 @@ static void ieee80211_rx_mgmt_auth_ibss( +@@ -35,6 +35,76 @@ + + #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 + ++static bool ieee80211_can_use_ext_chan(struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_channel *channel, ++ enum nl80211_channel_type channel_type) ++{ ++ /* check if we are legally allowed to use HT extension channel */ ++ if ((channel_type == NL80211_CHAN_HT40PLUS) || ++ (channel_type == NL80211_CHAN_HT40MINUS)) { ++ int sec_freq = channel->center_freq + ++ (channel_type == NL80211_CHAN_HT40PLUS ? 20 : -20); ++ struct ieee80211_channel *sec_chan = ++ ieee80211_get_channel(sdata->wdev.wiphy, sec_freq); ++ if (!sec_chan || sec_chan->flags & (IEEE80211_CHAN_DISABLED | ++ IEEE80211_CHAN_PASSIVE_SCAN | ++ IEEE80211_CHAN_NO_IBSS | ++ IEEE80211_CHAN_RADAR)) { ++ return false; ++ } ++ } ++ return true; ++} ++ ++static void ieee80211_update_ht_elems(struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_mgmt *mgmt, ++ struct ieee80211_ht_info *ht_info) ++{ ++ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_supported_band *sband = ++ local->hw.wiphy->bands[local->oper_channel->band]; ++ enum nl80211_channel_type channel_type = ++ ieee80211_ht_info_to_channel_type(ht_info); ++ ++ if (!ieee80211_can_use_ext_chan(sdata, local->oper_channel, channel_type)) ++ channel_type = NL80211_CHAN_HT20; ++ ++ if (channel_type != local->_oper_channel_type) { ++ struct sk_buff *skb = rcu_dereference_protected( ++ sdata->u.ibss.presp, ++ lockdep_is_held(&ifibss->mtx)); ++ struct sk_buff *nskb; ++ u8 *ht_ie; ++ ++ /* update HT IE. If not yet existing, create one */ ++ nskb = skb_copy(skb, GFP_ATOMIC); ++ ht_ie = (u8 *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ++ (const u8 *)(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, ++ local->oper_channel, channel_type); ++ rcu_assign_pointer(sdata->u.ibss.presp, nskb); ++ kfree_skb(skb); ++ ++ if(!ieee80211_set_channel_type(local, sdata, channel_type)) { ++ channel_type = NL80211_CHAN_HT20; ++ WARN_ON(!ieee80211_set_channel_type(local, sdata, ++ channel_type)); ++ } ++ ++ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); ++ } ++ ++} + + static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, +@@ -64,6 +134,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, @@ -396,24 +493,30 @@ const u32 basic_rates, const u16 capability, u64 tsf) { -@@ -104,8 +105,12 @@ static void __ieee80211_sta_join_ibss(st +@@ -104,8 +175,17 @@ 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)); ++ ++ /* if phy is on a different extension channel, setting ht40 will fail */ ++ if (!ieee80211_set_channel_type(local, sdata, channel_type)) { ++ channel_type = NL80211_CHAN_HT20; ++ 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 +@@ -171,6 +251,18 @@ static void __ieee80211_sta_join_ibss(st memcpy(skb_put(skb, ifibss->ie_len), ifibss->ie, ifibss->ie_len); ++ /* add HT capability and information IEs */ + if (channel_type != NL80211_CHAN_NO_HT && sband->ht_cap.ht_supported) { + pos = skb_put(skb, 4 + + sizeof(struct ieee80211_ht_cap) + @@ -428,7 +531,7 @@ 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 +@@ -219,6 +311,8 @@ static void ieee80211_sta_join_ibss(stru u32 basic_rates; int i, j; u16 beacon_int = cbss->beacon_interval; @@ -437,7 +540,7 @@ lockdep_assert_held(&sdata->u.ibss.mtx); -@@ -242,9 +260,15 @@ static void ieee80211_sta_join_ibss(stru +@@ -242,9 +336,23 @@ static void ieee80211_sta_join_ibss(stru } } @@ -446,6 +549,14 @@ + channel_type = ieee80211_ht_info_to_channel_type( + (struct ieee80211_ht_info *) (ht_info_ie + 2)); + ++ if (!ieee80211_can_use_ext_chan(sdata, cbss->channel, channel_type)) { ++ channel_type = NL80211_CHAN_HT20; ++#ifdef CONFIG_MAC80211_IBSS_DEBUG ++ printk(KERN_DEBUG "%s: IBSS not allowed on secondary channel\n", ++ sdata->name); ++#endif ++ } ++ __ieee80211_sta_join_ibss(sdata, cbss->bssid, beacon_int, cbss->channel, @@ -453,7 +564,7 @@ basic_rates, cbss->capability, cbss->tsf); -@@ -310,11 +334,65 @@ static void ieee80211_rx_bss_info(struct +@@ -310,11 +418,24 @@ static void ieee80211_rx_bss_info(struct } else sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates, @@ -467,62 +578,21 @@ + if (elems->wmm_info) + set_sta_flags(sta, WLAN_STA_WME); + ++ /* remote station uses ht */ + 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); -+ ++ ieee80211_update_ht_elems(sdata, mgmt, ++ elems->ht_info_elem); ++ ieee80211_ht_cap_ie_to_sta_ht_cap( ++ local->hw.wiphy->bands[ ++ local->oper_channel->band], ++ elems->ht_cap_elem, ++ &sta->sta.ht_cap); + } + } rcu_read_unlock(); } -@@ -404,7 +482,7 @@ static void ieee80211_rx_bss_info(struct +@@ -404,7 +525,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, @@ -531,7 +601,7 @@ } put_bss: -@@ -417,7 +495,8 @@ static void ieee80211_rx_bss_info(struct +@@ -417,7 +538,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, @@ -541,7 +611,7 @@ gfp_t gfp) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; -@@ -458,6 +537,11 @@ struct sta_info *ieee80211_ibss_add_sta( +@@ -458,6 +580,11 @@ struct sta_info *ieee80211_ibss_add_sta( sta->sta.supp_rates[band] = supp_rates | ieee80211_mandatory_rates(local, band); @@ -553,7 +623,7 @@ rate_control_rate_init(sta); /* If it fails, maybe we raced another insertion? */ -@@ -556,8 +640,8 @@ static void ieee80211_sta_create_ibss(st +@@ -556,8 +683,8 @@ static void ieee80211_sta_create_ibss(st sdata->drop_unencrypted = 0; __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, @@ -564,7 +634,7 @@ } /* -@@ -594,10 +678,10 @@ static void ieee80211_sta_find_ibss(stru +@@ -594,10 +721,10 @@ static void ieee80211_sta_find_ibss(stru chan = ifibss->channel; if (!is_zero_ether_addr(ifibss->bssid)) bssid = ifibss->bssid; @@ -577,7 +647,7 @@ if (cbss) { struct ieee80211_bss *bss; -@@ -896,10 +980,15 @@ int ieee80211_ibss_join(struct ieee80211 +@@ -896,10 +1023,15 @@ int ieee80211_ibss_join(struct ieee80211 struct sk_buff *skb; skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + @@ -597,7 +667,7 @@ params->ie_len); if (!skb) return -ENOMEM; -@@ -920,13 +1009,14 @@ int ieee80211_ibss_join(struct ieee80211 +@@ -920,13 +1052,15 @@ int ieee80211_ibss_join(struct ieee80211 sdata->vif.bss_conf.beacon_int = params->beacon_interval; sdata->u.ibss.channel = params->channel; @@ -607,15 +677,17 @@ /* 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, +- WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata, - NL80211_CHAN_NO_HT)); -+ params->channel_type)); ++ if(!ieee80211_set_channel_type(sdata->local, sdata, ++ params->channel_type)) ++ return -EINVAL; } if (params->ie) { --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c -@@ -2138,7 +2138,8 @@ ieee80211_rx_h_action(struct ieee80211_r +@@ -2148,7 +2148,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 && @@ -625,7 +697,7 @@ break; /* verify action_code is present */ -@@ -2654,7 +2655,8 @@ static int prepare_for_handlers(struct i +@@ -2666,7 +2667,8 @@ static int prepare_for_handlers(struct i else rate_idx = status->rate_idx; rx->sta = ieee80211_ibss_add_sta(sdata, bssid, @@ -635,3 +707,14 @@ } break; case NL80211_IFTYPE_MESH_POINT: +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -186,6 +186,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); |