The channel_type field is filled by iw and parse by cfg80211 before
being sent to mac80211 for instance (we also check if the specified
channel is capable of ht40+, ht40- or ht20). This information is needed
to properly configure an HT IBSS.
It requires a patch to iw to fill this field.
Signed-off-by: Benoit Papillault <[email protected]>
---
include/net/cfg80211.h | 1 +
net/wireless/nl80211.c | 20 ++++++++++++++++----
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7d10c01..93e5558 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -806,6 +806,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;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 01da83d..0a82623 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3792,6 +3792,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_ibss_params ibss;
struct wiphy *wiphy;
struct cfg80211_cached_keys *connkeys = NULL;
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
int err;
memset(&ibss, 0, sizeof(ibss));
@@ -3813,6 +3814,17 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
+ if (info->attrs[NL80211_ATTR_WIPHY_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;
+
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
@@ -3846,11 +3858,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
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]));
+ ibss.channel = rdev_freq_to_chan(rdev,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+ channel_type);
if (!ibss.channel ||
- ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
- ibss.channel->flags & IEEE80211_CHAN_DISABLED) {
+ ibss.channel->flags & IEEE80211_CHAN_NO_IBSS) {
err = -EINVAL;
goto out;
}
--
1.5.6.5
On Sat, 2010-05-08 at 01:01 +0200, Benoit Papillault wrote:
> > It would be helpful if you were to rebase over my patch that adds the
> > channel type tracking.
>
> Your patches are now in wireless-testing, so I am doing it at the moment.
Thanks.
> >> + if (channel_type != NL80211_CHAN_NO_HT&&
> >> + sband->ht_cap.ht_supported) {
> >
> > You shouldn't be able to get here with an HT channel but !ht_supported,
> > no? Or is that to support the case where you have HT only on one band?
>
> Good point. I think there are several cases here :
>
> - a non-HT STA is joining an HT IBSS (we need to check 802.11n-2009 to
> see how it's supposed to be handled). In this case channel_type could be
> ht40+ and ht_supported = false
Hmm, true.
> - an HT STA is joining a non-HT IBSS. It's clear in this case that no HT
> IE should be sent, which is catched by (channel_type !=
> NL80211_CHAN_NO_HT) condition.
Right.
> Could we examine those cases in a follow up patch?
Well what do we actually need to do then?
> >> +}
> >> +
> >> +int ieee80211_add_ht_info(u8 **ppos,
> >> + struct ieee80211_supported_band *sband,
> >> + struct ieee80211_channel *channel,
> >> + enum nl80211_channel_type channel_type)
> >
> > what's wrong with ieee80211_add_ht_ie()
>
> Seems it's close to what I'm doing, but not entirely the same. I will
> read it. If applicable, should I move ieee80211_add_ht_ie to util.c (and
> declaration to ieee80211_i.h) then ?
Yes.
Also I just noticed that there's a TODO item in rx.c when we receive an
HT frame from a peer we don't know about yet. Not sure what to do there,
but you'll need to look at it.
johannes
On Wed, 2010-05-12 at 23:02 +0200, Benoit Papillault wrote:
> I thought again about 2 HT STA joining a non-HT IBSS. If we want those 2
> STA to be able to send/receive HT frames then they must know each other
> capabilities. So HT Capabilities should be sent if ht_supported = true,
> even if channel_type is CHAN_NO_HT
That has interesting protection requirements. How do we take care of
those?
> I did some patch in this area in my tree. Basically, the peer STA is
> created only on beacon/probe response since only those frames contains
> peer capabilities. Any frames received before is simply ignored.
I'll let you discuss that with Bruno. I think we may need to "upgrade"
to HT on receiving that, rather than leaving us without connectivity to
that peer.
johannes
On Thu, 2010-05-06 at 00:36 +0200, Benoit Papillault wrote:
> When an HT IBSS is configured, we add HT Information and HT Capabilities
> IE to beacons & probe responses. This is done according to channel_type
> transmitted by iw/cfg80211.
>
> v2: Added helpers to build HT Capability & HT Information IE
This line belongs after the --- so it's not part of the commit log.
> local->oper_channel = chan;
> - local->oper_channel_type = NL80211_CHAN_NO_HT;
> + local->oper_channel_type = channel_type;
It would be helpful if you were to rebase over my patch that adds the
channel type tracking.
> @@ -165,6 +169,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
> memcpy(pos, &supp_rates[8], rates);
> }
>
> + if (channel_type != NL80211_CHAN_NO_HT &&
> + sband->ht_cap.ht_supported) {
You shouldn't be able to get here with an HT channel but !ht_supported,
no? Or is that to support the case where you have HT only on one band?
> + }
> +
trailing whitespace
> @@ -202,6 +214,9 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
> u32 basic_rates;
> int i, j;
> u16 beacon_int = cbss->beacon_interval;
> + const u8 * ht_info_ie;
CodingStyle.
> @@ -223,9 +238,28 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
> }
> }
>
> + /* parse HT Information IE, if present */
> + ht_info_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_INFORMATION);
> + if (ht_info_ie) {
> + ht_info = (const struct ieee80211_ht_info *)(ht_info_ie + 2);
> + switch (ht_info->ht_param
> + & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
The parser in mlme.c looks different. Please see there and also make it
a helper function.
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -404,6 +404,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 */
> @@ -1193,6 +1194,15 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
> u16 transaction, u16 auth_alg,
> u8 *extra, size_t extra_len, const u8 *bssid,
> const u8 *key, u8 key_len, u8 key_idx);
> +
> +int ieee80211_add_ht_cap(u8 **ppos,
> + struct ieee80211_supported_band *sband);
The length is fixed anyway, so how about just passing in
...(u8 *buffer, ... sband)
> +int ieee80211_add_ht_info(u8 **ppos,
> + struct ieee80211_supported_band *sband,
> + struct ieee80211_channel *channel,
> + enum nl80211_channel_type channel_type);
same here.
> --- a/net/mac80211/util.c
> +++ b/net/mac80211/util.c
> @@ -898,6 +898,82 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
> ieee80211_tx_skb(sdata, skb);
> }
>
> +int ieee80211_add_ht_cap(u8 **ppos,
> + struct ieee80211_supported_band *sband)
> +{
Actually ... please split up the patches.
1) pure code moving from the mlme code to helper functions
2) helper function rewrite using the structures, like you did
3) this patch
> + u16 cap = sband->ht_cap.cap;
> + struct ieee80211_ht_cap ht_cap;
> + u8 *pos = *ppos;
> +
> + if (ieee80211_disable_40mhz_24ghz &&
> + sband->band == IEEE80211_BAND_2GHZ) {
> + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
> + cap &= ~IEEE80211_HT_CAP_SGI_40;
> + }
> +
> + ht_cap.cap_info = cpu_to_le16(cap);
> + ht_cap.ampdu_params_info = sband->ht_cap.ampdu_factor |
> + (sband->ht_cap.ampdu_density <<
> + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
> + ht_cap.mcs = sband->ht_cap.mcs;
> + ht_cap.extended_ht_cap_info = cpu_to_le16(0);
> + ht_cap.tx_BF_cap_info = cpu_to_le32(0);
> + ht_cap.antenna_selection_info = 0;
> +
> + /* HT Capabilities element */
> + *pos++ = WLAN_EID_HT_CAPABILITY;
> + *pos++ = sizeof(struct ieee80211_ht_cap);
> + memcpy(pos, &ht_cap, sizeof(struct ieee80211_ht_cap));
> + pos += sizeof(struct ieee80211_ht_cap);
> +
> + *ppos = pos;
> +
> + return 1;
oh and get rid of the entirely useless return value.
> +}
> +
> +int ieee80211_add_ht_info(u8 **ppos,
> + struct ieee80211_supported_band *sband,
> + struct ieee80211_channel *channel,
> + enum nl80211_channel_type channel_type)
what's wrong with ieee80211_add_ht_ie()
Some more effort please! Patches with such _basic_ errors are no fun to
review!
johannes
Le 11/05/2010 12:48, Johannes Berg a écrit :
> On Sat, 2010-05-08 at 01:01 +0200, Benoit Papillault wrote:
>
>>> It would be helpful if you were to rebase over my patch that adds the
>>> channel type tracking.
>>
>> Your patches are now in wireless-testing, so I am doing it at the moment.
>
> Thanks.
>
>>>> + if (channel_type != NL80211_CHAN_NO_HT&&
>>>> + sband->ht_cap.ht_supported) {
>>>
>>> You shouldn't be able to get here with an HT channel but !ht_supported,
>>> no? Or is that to support the case where you have HT only on one band?
>>
>> Good point. I think there are several cases here :
>>
>> - a non-HT STA is joining an HT IBSS (we need to check 802.11n-2009 to
>> see how it's supposed to be handled). In this case channel_type could be
>> ht40+ and ht_supported = false
>
> Hmm, true.
>
>> - an HT STA is joining a non-HT IBSS. It's clear in this case that no HT
>> IE should be sent, which is catched by (channel_type !=
>> NL80211_CHAN_NO_HT) condition.
>
> Right.
>
>> Could we examine those cases in a follow up patch?
>
> Well what do we actually need to do then?
I thought again about 2 HT STA joining a non-HT IBSS. If we want those 2
STA to be able to send/receive HT frames then they must know each other
capabilities. So HT Capabilities should be sent if ht_supported = true,
even if channel_type is CHAN_NO_HT
>
>>>> +}
>>>> +
>>>> +int ieee80211_add_ht_info(u8 **ppos,
>>>> + struct ieee80211_supported_band *sband,
>>>> + struct ieee80211_channel *channel,
>>>> + enum nl80211_channel_type channel_type)
>>>
>>> what's wrong with ieee80211_add_ht_ie()
>>
>> Seems it's close to what I'm doing, but not entirely the same. I will
>> read it. If applicable, should I move ieee80211_add_ht_ie to util.c (and
>> declaration to ieee80211_i.h) then ?
>
> Yes.
Done. I still keep both ieee80211_add_ht_ie and ieee80211_add_ht_cap.
What is done in ieee80211_add_ht_ie is only required for an HT AP, not
an HT IBSS STA. I guess we should pass "sdata" to those functions before
merging them.
>
> Also I just noticed that there's a TODO item in rx.c when we receive an
> HT frame from a peer we don't know about yet. Not sure what to do there,
> but you'll need to look at it.
I did some patch in this area in my tree. Basically, the peer STA is
created only on beacon/probe response since only those frames contains
peer capabilities. Any frames received before is simply ignored.
>
> johannes
>
>
Regards,
Benoit
On Thursday 13 May 2010 06:02:23 Benoit Papillault wrote:
> > Also I just noticed that there's a TODO item in rx.c when we receive an
> > HT frame from a peer we don't know about yet. Not sure what to do there,
> > but you'll need to look at it.
>
> I did some patch in this area in my tree. Basically, the peer STA is
> created only on beacon/probe response since only those frames contains
> peer capabilities. Any frames received before is simply ignored.
i think the same applies to non-HT. when we receive a frame from a STA we
haven't seen a beacon from yet, we just mark the rate at which we received the
frame and can use that for a reply. later, when we receive a beacon, the rate-
set is updated. i guess the same can be done for HT and i'd argue that it
should be done like this in order to be able to communicate even though we
have not received a beacon from that particular STA yet - there are some
reasons why the beacon might not have reached us:
* the STA might have deferred beacon sending for a few intervals as part of
the normal beacon backoff
* the beacon might have been lost due to interference
* or the other STA might be a buggy implementation which doesn't send IBSS
beacons for a while, like some madwifi versions.
in any case the ability to communicate is more important than a complete rate-
set...
bruno
Le 13/05/2010 02:47, Bruno Randolf a écrit :
> On Thursday 13 May 2010 06:02:23 Benoit Papillault wrote:
>>> Also I just noticed that there's a TODO item in rx.c when we receive an
>>> HT frame from a peer we don't know about yet. Not sure what to do there,
>>> but you'll need to look at it.
>>
>> I did some patch in this area in my tree. Basically, the peer STA is
>> created only on beacon/probe response since only those frames contains
>> peer capabilities. Any frames received before is simply ignored.
>
> i think the same applies to non-HT. when we receive a frame from a STA we
> haven't seen a beacon from yet, we just mark the rate at which we received the
> frame and can use that for a reply. later, when we receive a beacon, the rate-
> set is updated. i guess the same can be done for HT and i'd argue that it
> should be done like this in order to be able to communicate even though we
> have not received a beacon from that particular STA yet - there are some
> reasons why the beacon might not have reached us:
>
> * the STA might have deferred beacon sending for a few intervals as part of
> the normal beacon backoff
>
> * the beacon might have been lost due to interference
>
> * or the other STA might be a buggy implementation which doesn't send IBSS
> beacons for a while, like some madwifi versions.
>
> in any case the ability to communicate is more important than a complete rate-
> set...
>
> bruno
>
Hi Bruno,
I understand your concern. It's a bit of chicken egg problem since to
communicate properly we don't to know the rateset. Requiring beacons
would have push some pressure on people to fix them, but anyway, I
understand your concern.
Currently, the HT rateset (MCS) does not seem to be properly populated
in IBSS (the rate control only mentioned 1 - 54 Mbits rates...). I think
we need to define a "basic profile" that will be used up to the point we
receive a beacon from this STA.
I will check that soon.
Regards,
Benoit
Le 06/05/2010 08:40, Johannes Berg a écrit :
> On Thu, 2010-05-06 at 00:36 +0200, Benoit Papillault wrote:
>> When an HT IBSS is configured, we add HT Information and HT Capabilities
>> IE to beacons& probe responses. This is done according to channel_type
>> transmitted by iw/cfg80211.
>>
>> v2: Added helpers to build HT Capability& HT Information IE
>
> This line belongs after the --- so it's not part of the commit log.
>
>> local->oper_channel = chan;
>> - local->oper_channel_type = NL80211_CHAN_NO_HT;
>> + local->oper_channel_type = channel_type;
>
> It would be helpful if you were to rebase over my patch that adds the
> channel type tracking.
Your patches are now in wireless-testing, so I am doing it at the moment.
>
>> @@ -165,6 +169,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
>> memcpy(pos,&supp_rates[8], rates);
>> }
>>
>> + if (channel_type != NL80211_CHAN_NO_HT&&
>> + sband->ht_cap.ht_supported) {
>
> You shouldn't be able to get here with an HT channel but !ht_supported,
> no? Or is that to support the case where you have HT only on one band?
Good point. I think there are several cases here :
- a non-HT STA is joining an HT IBSS (we need to check 802.11n-2009 to
see how it's supposed to be handled). In this case channel_type could be
ht40+ and ht_supported = false
- an HT STA is joining a non-HT IBSS. It's clear in this case that no HT
IE should be sent, which is catched by (channel_type !=
NL80211_CHAN_NO_HT) condition.
Could we examine those cases in a follow up patch?
>
>> + }
>> +
>
> trailing whitespace
>
>> @@ -202,6 +214,9 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
>> u32 basic_rates;
>> int i, j;
>> u16 beacon_int = cbss->beacon_interval;
>> + const u8 * ht_info_ie;
>
> CodingStyle.
>
>> @@ -223,9 +238,28 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
>> }
>> }
>>
>> + /* parse HT Information IE, if present */
>> + ht_info_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_INFORMATION);
>> + if (ht_info_ie) {
>> + ht_info = (const struct ieee80211_ht_info *)(ht_info_ie + 2);
>> + switch (ht_info->ht_param
>> + & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
>
> The parser in mlme.c looks different. Please see there and also make it
> a helper function.
Thanks. I did not notice.
>
>> --- a/net/mac80211/ieee80211_i.h
>> +++ b/net/mac80211/ieee80211_i.h
>> @@ -404,6 +404,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 */
>> @@ -1193,6 +1194,15 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
>> u16 transaction, u16 auth_alg,
>> u8 *extra, size_t extra_len, const u8 *bssid,
>> const u8 *key, u8 key_len, u8 key_idx);
>> +
>> +int ieee80211_add_ht_cap(u8 **ppos,
>> + struct ieee80211_supported_band *sband);
>
> The length is fixed anyway, so how about just passing in
> ...(u8 *buffer, ... sband)
>
>> +int ieee80211_add_ht_info(u8 **ppos,
>> + struct ieee80211_supported_band *sband,
>> + struct ieee80211_channel *channel,
>> + enum nl80211_channel_type channel_type);
>
> same here.
>
>> --- a/net/mac80211/util.c
>> +++ b/net/mac80211/util.c
>> @@ -898,6 +898,82 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
>> ieee80211_tx_skb(sdata, skb);
>> }
>>
>> +int ieee80211_add_ht_cap(u8 **ppos,
>> + struct ieee80211_supported_band *sband)
>> +{
>
> Actually ... please split up the patches.
>
> 1) pure code moving from the mlme code to helper functions
> 2) helper function rewrite using the structures, like you did
> 3) this patch
>
>> + u16 cap = sband->ht_cap.cap;
>> + struct ieee80211_ht_cap ht_cap;
>> + u8 *pos = *ppos;
>> +
>> + if (ieee80211_disable_40mhz_24ghz&&
>> + sband->band == IEEE80211_BAND_2GHZ) {
>> + cap&= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
>> + cap&= ~IEEE80211_HT_CAP_SGI_40;
>> + }
>> +
>> + ht_cap.cap_info = cpu_to_le16(cap);
>> + ht_cap.ampdu_params_info = sband->ht_cap.ampdu_factor |
>> + (sband->ht_cap.ampdu_density<<
>> + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
>> + ht_cap.mcs = sband->ht_cap.mcs;
>> + ht_cap.extended_ht_cap_info = cpu_to_le16(0);
>> + ht_cap.tx_BF_cap_info = cpu_to_le32(0);
>> + ht_cap.antenna_selection_info = 0;
>> +
>> + /* HT Capabilities element */
>> + *pos++ = WLAN_EID_HT_CAPABILITY;
>> + *pos++ = sizeof(struct ieee80211_ht_cap);
>> + memcpy(pos,&ht_cap, sizeof(struct ieee80211_ht_cap));
>> + pos += sizeof(struct ieee80211_ht_cap);
>> +
>> + *ppos = pos;
>> +
>> + return 1;
>
> oh and get rid of the entirely useless return value.
Let's do so.
>
>> +}
>> +
>> +int ieee80211_add_ht_info(u8 **ppos,
>> + struct ieee80211_supported_band *sband,
>> + struct ieee80211_channel *channel,
>> + enum nl80211_channel_type channel_type)
>
> what's wrong with ieee80211_add_ht_ie()
Seems it's close to what I'm doing, but not entirely the same. I will
read it. If applicable, should I move ieee80211_add_ht_ie to util.c (and
declaration to ieee80211_i.h) then ?
>
> Some more effort please! Patches with such _basic_ errors are no fun to
> review!
I will try to do better next time, sorry about that.
>
> johannes
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
When an HT IBSS is configured, we add HT Information and HT Capabilities
IE to beacons & probe responses. This is done according to channel_type
transmitted by iw/cfg80211.
v2: Added helpers to build HT Capability & HT Information IE
Signed-off-by: Benoit Papillault <[email protected]>
---
net/mac80211/ibss.c | 64 +++++++++++++++++++++++++---
net/mac80211/ieee80211_i.h | 10 ++++
net/mac80211/util.c | 98 ++++++++++++++++++++++++++++++++++---------
3 files changed, 144 insertions(+), 28 deletions(-)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b72ee64..2371d69 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -64,6 +64,7 @@ static void ieee80211_rx_mgmt_auth_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,
struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type,
const u32 basic_rates,
const u16 capability, u64 tsf)
{
@@ -103,7 +104,7 @@ 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;
- local->oper_channel_type = NL80211_CHAN_NO_HT;
+ local->oper_channel_type = channel_type;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
sband = local->hw.wiphy->bands[chan->band];
@@ -118,7 +119,10 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
*pos++ = basic | (u8) (rate / 5);
}
- /* Build IBSS probe response */
+ /*
+ * Build IBSS probe response template (this template is also used
+ * when sending beacon, see ieee80211_beacon_get_tim())
+ */
mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon));
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
@@ -165,6 +169,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
memcpy(pos, &supp_rates[8], rates);
}
+ if (channel_type != NL80211_CHAN_NO_HT &&
+ sband->ht_cap.ht_supported) {
+ pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
+ ieee80211_add_ht_cap(&pos, sband);
+ pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_info));
+ ieee80211_add_ht_info(&pos, sband, chan, channel_type);
+ }
+
if (ifibss->ie_len)
memcpy(skb_put(skb, ifibss->ie_len),
ifibss->ie, ifibss->ie_len);
@@ -202,6 +214,9 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
u32 basic_rates;
int i, j;
u16 beacon_int = cbss->beacon_interval;
+ const u8 * ht_info_ie;
+ const struct ieee80211_ht_info *ht_info;
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
if (beacon_int < 10)
beacon_int = 10;
@@ -223,9 +238,28 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
}
}
+ /* parse HT Information IE, if present */
+ ht_info_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_INFORMATION);
+ if (ht_info_ie) {
+ ht_info = (const struct ieee80211_ht_info *)(ht_info_ie + 2);
+ 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;
+ }
+ }
+
__ieee80211_sta_join_ibss(sdata, cbss->bssid,
beacon_int,
cbss->channel,
+ channel_type,
basic_rates,
cbss->capability,
cbss->tsf);
@@ -529,7 +563,8 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
sdata->drop_unencrypted = 0;
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
- ifibss->channel, 3, /* first two are basic */
+ ifibss->channel, ifibss->channel_type,
+ 3, /* first two are basic */
capability, 0);
}
@@ -906,6 +941,7 @@ 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 */
@@ -921,11 +957,25 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.ie_len = params->ie_len;
}
+ /*
+ * Allocate IBSS probe response template (see
+ * __ieee80211_sta_join_ibss for the needed size). According to IEEE
+ * 802.11-2007 10.4.4.2, there is only 20 possibles values. We
+ * support up IEEE80211_MAX_SUPP_RATES (currently 32) : so 8 for
+ * Supported Rates and IEEE80211_MAX_SUPP_RATES-8 for Extended
+ * Supported Rates
+ */
+
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) /* max Ext Rates */ +
+ 2 + sizeof(struct ieee80211_ht_cap) +
+ 2 + sizeof(struct ieee80211_ht_info) +
params->ie_len);
if (!skb)
return -ENOMEM;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c8077a3..b3a5d3c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -404,6 +404,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 */
@@ -1193,6 +1194,15 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
u8 *extra, size_t extra_len, const u8 *bssid,
const u8 *key, u8 key_len, u8 key_idx);
+
+int ieee80211_add_ht_cap(u8 **ppos,
+ struct ieee80211_supported_band *sband);
+
+int ieee80211_add_ht_info(u8 **ppos,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type);
+
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
const u8 *ie, size_t ie_len,
enum ieee80211_band band);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 2b75b4f..cc08411 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -898,6 +898,82 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb(sdata, skb);
}
+int ieee80211_add_ht_cap(u8 **ppos,
+ struct ieee80211_supported_band *sband)
+{
+ u16 cap = sband->ht_cap.cap;
+ struct ieee80211_ht_cap ht_cap;
+ u8 *pos = *ppos;
+
+ if (ieee80211_disable_40mhz_24ghz &&
+ sband->band == IEEE80211_BAND_2GHZ) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+
+ ht_cap.cap_info = cpu_to_le16(cap);
+ ht_cap.ampdu_params_info = sband->ht_cap.ampdu_factor |
+ (sband->ht_cap.ampdu_density <<
+ IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+ ht_cap.mcs = sband->ht_cap.mcs;
+ ht_cap.extended_ht_cap_info = cpu_to_le16(0);
+ ht_cap.tx_BF_cap_info = cpu_to_le32(0);
+ ht_cap.antenna_selection_info = 0;
+
+ /* HT Capabilities element */
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_ht_cap);
+ memcpy(pos, &ht_cap, sizeof(struct ieee80211_ht_cap));
+ pos += sizeof(struct ieee80211_ht_cap);
+
+ *ppos = pos;
+
+ return 1;
+}
+
+int ieee80211_add_ht_info(u8 **ppos,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type)
+{
+ struct ieee80211_ht_info ht_info;
+ u8 *pos = *ppos;
+
+ ht_info.control_chan =
+ ieee80211_frequency_to_channel(channel->center_freq);
+ ht_info.ht_param = 0;
+ switch (channel_type) {
+ case NL80211_CHAN_NO_HT: /* to make compiler happy */
+ case NL80211_CHAN_HT20:
+ ht_info.ht_param |= IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ break;
+ 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;
+ }
+ if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+ ht_info.ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
+ ht_info.operation_mode = cpu_to_le16(0);
+ ht_info.stbc_param = cpu_to_le16(0);
+ /* 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, &sband->ht_cap.mcs, 10);
+
+ /* HT Information element */
+ *pos++ = WLAN_EID_HT_INFORMATION;
+ *pos++ = sizeof(struct ieee80211_ht_info);
+ memcpy(pos, &ht_info, sizeof(struct ieee80211_ht_info));
+ pos += sizeof(struct ieee80211_ht_info);
+
+ *ppos = pos;
+
+ return 1;
+}
+
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
const u8 *ie, size_t ie_len,
enum ieee80211_band band)
@@ -966,27 +1042,7 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
}
if (sband->ht_cap.ht_supported) {
- u16 cap = sband->ht_cap.cap;
- __le16 tmp;
-
- if (ieee80211_disable_40mhz_24ghz &&
- sband->band == IEEE80211_BAND_2GHZ) {
- cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- cap &= ~IEEE80211_HT_CAP_SGI_40;
- }
-
- *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 */
+ ieee80211_add_ht_cap(&pos, sband);
}
/*
--
1.5.6.5