@ -1,6 +1,6 @@
--- a/include/net/cfg80211.h
--- a/include/net/cfg80211.h
+++ b/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 *ssid;
u8 *bssid;
u8 *bssid;
struct ieee80211_channel *channel;
struct ieee80211_channel *channel;
@ -8,7 +8,7 @@
u8 *ie;
u8 *ie;
u8 ssid_len, ie_len;
u8 ssid_len, ie_len;
u16 beacon_interval;
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 *bssid,
const u8 *ssid, size_t ssid_len,
const u8 *ssid, size_t ssid_len,
u16 capa_mask, u16 capa_val);
u16 capa_mask, u16 capa_val);
@ -21,9 +21,147 @@
static inline struct cfg80211_bss *
static inline struct cfg80211_bss *
cfg80211_get_ibss(struct wiphy *wiphy,
cfg80211_get_ibss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
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
--- a/net/mac80211/ieee80211_i.h
+++ b/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 ssid_len, ie_len;
u8 *ie;
u8 *ie;
struct ieee80211_channel *channel;
struct ieee80211_channel *channel;
@ -31,7 +169,7 @@
unsigned long ibss_join_req;
unsigned long ibss_join_req;
/* probe response/beacon for IBSS */
/* probe response/beacon for IBSS */
@@ -1121,6 +112 2,7 @@ void ieee80211_ibss_notify_scan_complete
@@ -1151,6 +115 2,7 @@ void ieee80211_ibss_notify_scan_complete
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
struct sta_info *ieee80211_ibss_add_sta(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,
u8 *bssid, u8 *addr, u32 supp_rates,
@ -39,7 +177,7 @@
gfp_t gfp);
gfp_t gfp);
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
struct cfg80211_ibss_params *params);
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,
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
const u8 *ids, int n_ids, size_t offset);
const u8 *ids, int n_ids, size_t offset);
size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, 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 */
/* internal work items */
void ieee80211_work_init(struct ieee80211_local *local);
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,
bool ieee80211_set_channel_type(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type chantype);
enum nl80211_channel_type chantype);
@ -63,7 +201,7 @@
#define debug_noinline noinline
#define debug_noinline noinline
--- a/net/mac80211/util.c
--- a/net/mac80211/util.c
+++ b/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;
offset = noffset;
}
}
@ -89,10 +227,10 @@
/*
/*
* If adding more here, adjust code in main.c
* If adding more here, adjust code in main.c
@@ -1464,3 +1449,100 @@ size_t ieee80211_ie_split_vendor(const u
@@ -1548,3 +1533,100 @@ void ieee80211_disable_rssi_reports(stru
_ieee80211_enable_rssi_reports(sdata, 0, 0);
return pos;
}
}
EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
+
+
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+ u16 cap)
+ u16 cap)
@ -192,7 +330,7 @@
+}
+}
--- a/net/mac80211/work.c
--- a/net/mac80211/work.c
+++ b/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;
u8 *pos;
u32 flags = channel->flags;
u32 flags = channel->flags;
u16 cap = sband->ht_cap.cap;
u16 cap = sband->ht_cap.cap;
@ -200,7 +338,7 @@
if (!sband->ht_cap.ht_supported)
if (!sband->ht_cap.ht_supported)
return;
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 */
/* reserve and fill IE */
@ -236,124 +374,6 @@
}
}
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
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
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -84,6 +84,8 @@ static void ieee80211_send_addba_request
@@ -84,6 +84,8 @@ static void ieee80211_send_addba_request
@ -388,7 +408,84 @@
IEEE80211_STYPE_ACTION);
IEEE80211_STYPE_ACTION);
--- a/net/mac80211/ibss.c
--- a/net/mac80211/ibss.c
+++ b/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,
static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
const u8 *bssid, const int beacon_int,
const u8 *bssid, const int beacon_int,
struct ieee80211_channel *chan,
struct ieee80211_channel *chan,
@ -396,24 +493,30 @@
const u32 basic_rates,
const u32 basic_rates,
const u16 capability, u64 tsf)
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;
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+ /* entering a legacy IBSS. Use given HT configuration. */
+ /* entering a legacy IBSS. Use given HT configuration. */
+ if (channel_type == NL80211_CHAN_NO_HT)
+ if (channel_type == NL80211_CHAN_NO_HT)
+ channel_type = ifibss->channel_type;
+ channel_type = ifibss->channel_type;
+
local->oper_channel = chan;
local->oper_channel = chan;
- WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
- 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);
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
sband = local->hw.wiphy->bands[chan->band];
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),
memcpy(skb_put(skb, ifibss->ie_len),
ifibss->ie, 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) {
+ if (channel_type != NL80211_CHAN_NO_HT && sband->ht_cap.ht_supported) {
+ pos = skb_put(skb, 4 +
+ pos = skb_put(skb, 4 +
+ sizeof(struct ieee80211_ht_cap) +
+ sizeof(struct ieee80211_ht_cap) +
@ -428,7 +531,7 @@
if (local->hw.queues >= 4) {
if (local->hw.queues >= 4) {
pos = skb_put(skb, 9);
pos = skb_put(skb, 9);
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*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;
u32 basic_rates;
int i, j;
int i, j;
u16 beacon_int = cbss->beacon_interval;
u16 beacon_int = cbss->beacon_interval;
@ -437,7 +540,7 @@
lockdep_assert_held(&sdata->u.ibss.mtx);
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
}
}
}
}
@ -445,6 +548,14 @@
+ if (ht_info_ie)
+ if (ht_info_ie)
+ channel_type = ieee80211_ht_info_to_channel_type(
+ channel_type = ieee80211_ht_info_to_channel_type(
+ (struct ieee80211_ht_info *) (ht_info_ie + 2));
+ (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,
__ieee80211_sta_join_ibss(sdata, cbss->bssid,
beacon_int,
beacon_int,
@ -453,7 +564,7 @@
basic_rates,
basic_rates,
cbss->capability,
cbss->capability,
cbss->tsf);
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
} else
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
mgmt->sa, supp_rates,
mgmt->sa, supp_rates,
@ -467,62 +578,21 @@
+ if (elems->wmm_info)
+ if (elems->wmm_info)
+ set_sta_flags(sta, WLAN_STA_WME);
+ set_sta_flags(sta, WLAN_STA_WME);
+
+
+ /* remote station uses ht */
+ if (elems->ht_info_elem) {
+ if (elems->ht_info_elem) {
+ struct ieee80211_supported_band *sband =
+ ieee80211_update_ht_elems(sdata, mgmt,
+ local->hw.wiphy->bands[channel->band];
+ elems->ht_info_elem);
+ enum nl80211_channel_type channel_type;
+ ieee80211_ht_cap_ie_to_sta_ht_cap(
+
+ local->hw.wiphy->bands[
+ channel_type =
+ local->oper_channel->band],
+ ieee80211_ht_info_to_channel_type(
+ elems->ht_cap_elem,
+ elems->ht_info_elem);
+ &sta->sta.ht_cap);
+ 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();
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);
ieee80211_sta_join_ibss(sdata, bss);
supp_rates = ieee80211_sta_get_rates(local, elems, band);
supp_rates = ieee80211_sta_get_rates(local, elems, band);
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
@ -531,7 +601,7 @@
}
}
put_bss:
put_bss:
@@ -417,7 +49 5,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.
* must be callable in atomic context.
*/
*/
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
@ -541,7 +611,7 @@
gfp_t gfp)
gfp_t gfp)
{
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
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 |
sta->sta.supp_rates[band] = supp_rates |
ieee80211_mandatory_rates(local, band);
ieee80211_mandatory_rates(local, band);
@ -553,7 +623,7 @@
rate_control_rate_init(sta);
rate_control_rate_init(sta);
/* If it fails, maybe we raced another insertion? */
/* 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;
sdata->drop_unencrypted = 0;
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
__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;
chan = ifibss->channel;
if (!is_zero_ether_addr(ifibss->bssid))
if (!is_zero_ether_addr(ifibss->bssid))
bssid = ifibss->bssid;
bssid = ifibss->bssid;
@ -577,7 +647,7 @@
if (cbss) {
if (cbss) {
struct ieee80211_bss *bss;
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;
struct sk_buff *skb;
skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
@ -597,7 +667,7 @@
params->ie_len);
params->ie_len);
if (!skb)
if (!skb)
return -ENOMEM;
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->vif.bss_conf.beacon_int = params->beacon_interval;
sdata->u.ibss.channel = params->channel;
sdata->u.ibss.channel = params->channel;
@ -607,15 +677,17 @@
/* fix ourselves to that channel now already */
/* fix ourselves to that channel now already */
if (params->channel_fixed) {
if (params->channel_fixed) {
sdata->local->oper_channel = params->channel;
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));
- NL80211_CHAN_NO_HT));
+ params->channel_type));
+ if(!ieee80211_set_channel_type(sdata->local, sdata,
+ params->channel_type))
+ return -EINVAL;
}
}
if (params->ie) {
if (params->ie) {
--- a/net/mac80211/rx.c
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2138,7 +213 8,8 @@ ieee80211_rx_h_action(struct ieee80211_r
@@ -2148,7 +214 8,8 @@ ieee80211_rx_h_action(struct ieee80211_r
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_AP &&
@ -625,7 +697,7 @@
break;
break;
/* verify action_code is present */
/* 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
else
rate_idx = status->rate_idx;
rate_idx = status->rate_idx;
rx->sta = ieee80211_ibss_add_sta(sdata, bssid,
rx->sta = ieee80211_ibss_add_sta(sdata, bssid,
@ -635,3 +707,14 @@
}
}
break;
break;
case NL80211_IFTYPE_MESH_POINT:
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);