2010-05-12 21:07:52

by Benoit Papillault

[permalink] [raw]
Subject: [PATCH] cfg80211: Parse channel_type in NL80211_CMD_JOIN_IBSS

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 b44a2e5..5ead439 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 aaa1aad..039c13f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3879,6 +3879,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));
@@ -3900,6 +3901,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);
@@ -3933,11 +3945,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



2010-05-12 21:16:09

by Benoit Papillault

[permalink] [raw]
Subject: [PATCH] mac80211: Move part of the MLME code to helper functions

We moved code parsing the HT Operation IE to get the associated channel
type and the HT Capabilities IE generation code to util.c. This is a
preliminary step that will be used by HT IBSS code later.

Signed-off-by: Benoit Papillault <[email protected]>
---
net/mac80211/ieee80211_i.h | 12 +++
net/mac80211/mlme.c | 20 +-----
net/mac80211/util.c | 179 ++++++++++++++++++++++++++++++++++++++------
net/mac80211/work.c | 96 -----------------------
4 files changed, 170 insertions(+), 137 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 69e7f41..742e12b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1215,6 +1215,18 @@ 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);

+enum nl80211_channel_type ieee80211_channel_type_from_ht_info(
+ struct ieee80211_local *local,
+ struct ieee80211_ht_info *hti, u16 ap_ht_cap_flags);
+
+void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_channel *channel,
+ enum ieee80211_smps_mode smps);
+
+u8 *ieee80211_add_ht_cap(u8 *pos,
+ struct ieee80211_supported_band *sband);
+
/* internal work items */
void ieee80211_work_init(struct ieee80211_local *local);
void ieee80211_add_work(struct ieee80211_work *wk);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 3093e46..55d96a6 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -155,24 +155,8 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
enable_ht = false;

if (enable_ht) {
- channel_type = NL80211_CHAN_HT20;
-
- if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
- (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
- (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
- switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
- case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- if (!(local->hw.conf.channel->flags &
- IEEE80211_CHAN_NO_HT40PLUS))
- channel_type = NL80211_CHAN_HT40PLUS;
- break;
- case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- if (!(local->hw.conf.channel->flags &
- IEEE80211_CHAN_NO_HT40MINUS))
- channel_type = NL80211_CHAN_HT40MINUS;
- break;
- }
- }
+ channel_type = ieee80211_channel_type_from_ht_info(local,
+ hti, ap_ht_cap_flags);
}

if (local->tmp_channel)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5b79d55..4a76fa5 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -965,29 +965,7 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
offset = noffset;
}

- 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 */
- }
+ pos = ieee80211_add_ht_cap(pos, sband);

/*
* If adding more here, adjust code in main.c
@@ -1389,3 +1367,158 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)

return pos;
}
+
+enum nl80211_channel_type ieee80211_channel_type_from_ht_info(
+ struct ieee80211_local *local,
+ struct ieee80211_ht_info *hti, u16 ap_ht_cap_flags)
+{
+ struct ieee80211_supported_band *sband;
+ enum nl80211_channel_type channel_type = NL80211_CHAN_HT20;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+ (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
+ (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
+ switch (hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ if (!(local->hw.conf.channel->flags &
+ IEEE80211_CHAN_NO_HT40PLUS))
+ channel_type = NL80211_CHAN_HT40PLUS;
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ if (!(local->hw.conf.channel->flags &
+ IEEE80211_CHAN_NO_HT40MINUS))
+ channel_type = NL80211_CHAN_HT40MINUS;
+ break;
+ }
+ }
+
+ return channel_type;
+}
+
+u8 *ieee80211_add_ht_cap(u8 *pos,
+ struct ieee80211_supported_band *sband)
+{
+ 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 */
+ }
+
+ return pos;
+}
+
+void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_channel *channel,
+ enum ieee80211_smps_mode smps)
+{
+ struct ieee80211_ht_info *ht_info;
+ u8 *pos;
+ u32 flags = channel->flags;
+ u16 cap = sband->ht_cap.cap;
+ __le16 tmp;
+
+ if (!sband->ht_cap.ht_supported)
+ return;
+
+ if (!ht_info_ie)
+ return;
+
+ if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
+ return;
+
+ ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
+
+ /* determine capability flags */
+
+ if (ieee80211_disable_40mhz_24ghz &&
+ sband->band == IEEE80211_BAND_2GHZ) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+
+ switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ }
+
+ /* set SM PS mode properly */
+ cap &= ~IEEE80211_HT_CAP_SM_PS;
+ switch (smps) {
+ case IEEE80211_SMPS_AUTOMATIC:
+ case IEEE80211_SMPS_NUM_MODES:
+ WARN_ON(1);
+ case IEEE80211_SMPS_OFF:
+ cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
+ IEEE80211_HT_CAP_SM_PS_SHIFT;
+ break;
+ case IEEE80211_SMPS_STATIC:
+ cap |= WLAN_HT_CAP_SM_PS_STATIC <<
+ IEEE80211_HT_CAP_SM_PS_SHIFT;
+ break;
+ case IEEE80211_SMPS_DYNAMIC:
+ cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
+ IEEE80211_HT_CAP_SM_PS_SHIFT;
+ break;
+ }
+
+ /* 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);
+}
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 3dd0760..df6940d 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -101,102 +101,6 @@ static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,

/* frame sending functions */

-static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
- struct ieee80211_supported_band *sband,
- struct ieee80211_channel *channel,
- enum ieee80211_smps_mode smps)
-{
- struct ieee80211_ht_info *ht_info;
- u8 *pos;
- u32 flags = channel->flags;
- u16 cap = sband->ht_cap.cap;
- __le16 tmp;
-
- if (!sband->ht_cap.ht_supported)
- return;
-
- if (!ht_info_ie)
- return;
-
- if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
- return;
-
- ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
-
- /* determine capability flags */
-
- if (ieee80211_disable_40mhz_24ghz &&
- sband->band == IEEE80211_BAND_2GHZ) {
- cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- cap &= ~IEEE80211_HT_CAP_SGI_40;
- }
-
- switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
- case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
- cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- cap &= ~IEEE80211_HT_CAP_SGI_40;
- }
- break;
- case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
- cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- cap &= ~IEEE80211_HT_CAP_SGI_40;
- }
- break;
- }
-
- /* set SM PS mode properly */
- cap &= ~IEEE80211_HT_CAP_SM_PS;
- switch (smps) {
- case IEEE80211_SMPS_AUTOMATIC:
- case IEEE80211_SMPS_NUM_MODES:
- WARN_ON(1);
- case IEEE80211_SMPS_OFF:
- cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
- IEEE80211_HT_CAP_SM_PS_SHIFT;
- break;
- case IEEE80211_SMPS_STATIC:
- cap |= WLAN_HT_CAP_SM_PS_STATIC <<
- IEEE80211_HT_CAP_SM_PS_SHIFT;
- break;
- case IEEE80211_SMPS_DYNAMIC:
- cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
- IEEE80211_HT_CAP_SM_PS_SHIFT;
- break;
- }
-
- /* 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);
-}
-
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_work *wk)
{
--
1.5.6.5


2010-05-12 21:07:52

by Benoit Papillault

[permalink] [raw]
Subject: [PATCH] mac80211: Use struct ieee80211_ht_cap to build HT Capabilities IE

Instead of writing the HT Capabilities IE byte after byte, we use the
existing ieee80211_ht_cap structure.

Signed-off-by: Benoit Papillault <[email protected]>
---
net/mac80211/util.c | 55 +++++++++++++++++++++++++--------------------------
1 files changed, 27 insertions(+), 28 deletions(-)

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 4a76fa5..047acb8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1402,7 +1402,7 @@ u8 *ieee80211_add_ht_cap(u8 *pos,
{
if (sband->ht_cap.ht_supported) {
u16 cap = sband->ht_cap.cap;
- __le16 tmp;
+ struct ieee80211_ht_cap ht_cap;

if (ieee80211_disable_40mhz_24ghz &&
sband->band == IEEE80211_BAND_2GHZ) {
@@ -1410,18 +1410,20 @@ u8 *ieee80211_add_ht_cap(u8 *pos,
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 |
+ 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);
- 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 */
+ 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);
}

return pos;
@@ -1436,7 +1438,7 @@ void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
u8 *pos;
u32 flags = channel->flags;
u16 cap = sband->ht_cap.cap;
- __le16 tmp;
+ struct ieee80211_ht_cap ht_cap;

if (!sband->ht_cap.ht_supported)
return;
@@ -1492,33 +1494,30 @@ void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
break;
}

- /* 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);
+ ht_cap.cap_info = cpu_to_le16(cap);

/* AMPDU parameters */
- *pos++ = sband->ht_cap.ampdu_factor |
+ ht_cap.ampdu_params_info = 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);
+ ht_cap.mcs = sband->ht_cap.mcs;

/* extended capabilities */
- pos += sizeof(__le16);
+ ht_cap.extended_ht_cap_info = cpu_to_le16(0);

/* BF capabilities */
- pos += sizeof(__le32);
+ ht_cap.tx_BF_cap_info = cpu_to_le32(0);

/* antenna selection */
- pos += sizeof(u8);
+ ht_cap.antenna_selection_info = 0;
+
+ /* reserve and fill IE */
+ pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
+
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_ht_cap);
+ memcpy(pos, &ht_cap, sizeof(struct ieee80211_ht_cap));
}
--
1.5.6.5


2010-05-14 13:56:23

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH] mac80211: Add HT IE to IBSS beacons and probe responses


> @@ -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;
> - 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);

This is incorrect .. you need to fall back to HT20 when HT40 fails, like
mlme.c does.

> /* 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));
> }

Same here.

> u16 transaction, u16 auth_alg,
> u8 *extra, size_t extra_len, const u8 *bssid,
> const u8 *key, u8 key_len, u8 key_idx);
> +
> +u8 *ieee80211_add_ht_cap(u8 *pos,
> + struct ieee80211_supported_band *sband);
> +
> +u8 *ieee80211_add_ht_info(u8 *pos,
> + struct ieee80211_supported_band *sband,
> + struct ieee80211_channel *channel,
> + enum nl80211_channel_type channel_type);
> +
> +enum nl80211_channel_type ieee80211_channel_type_from_ht_info(
> + struct ieee80211_local *local,
> + struct ieee80211_ht_info *hti, u16 ap_ht_cap_flags);
> +
> int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
> const u8 *ie, size_t ie_len,
> enum ieee80211_band band);

Didn't you just do this in the first patch??

johannes


2010-05-12 21:16:09

by Benoit Papillault

[permalink] [raw]
Subject: [PATCH] mac80211: Add HT IE to IBSS beacons and probe responses

When an HT IBSS is configured, we add HT Capabilities and HT Operation
IE to beacons and probe responses. This is done according to
channel_type transmitted by iw/cfg80211.

Signed-off-by: Benoit Papillault <[email protected]>
---
net/mac80211/ibss.c | 67 ++++++++++++++++++++++++++++++++++++++-----
net/mac80211/ieee80211_i.h | 14 +++++++++
net/mac80211/util.c | 40 ++++++++++++++++++++++++++
3 files changed, 113 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b2cc1fd..288f512 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;
- 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];
@@ -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,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
memcpy(pos, &supp_rates[8], rates);
}

+ if (sband->ht_cap.ht_supported) {
+ pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
+ ieee80211_add_ht_cap(pos, sband);
+ }
+
+ if (channel_type != NL80211_CHAN_NO_HT &&
+ sband->ht_cap.ht_supported) {
+ 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 +217,8 @@ 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_cap_ie, *ht_info_ie;
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;

if (beacon_int < 10)
beacon_int = 10;
@@ -223,9 +240,27 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
}
}

+ /* parse HT Capabilities & Information IE, if present */
+ ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
+ ht_info_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_INFORMATION);
+ if (ht_cap_ie && ht_info_ie) {
+ struct ieee80211_ht_cap *ht_cap;
+ struct ieee80211_ht_info *ht_info;
+ struct ieee80211_sta_ht_cap sta_ht_cap;
+
+ ht_cap = (struct ieee80211_ht_cap *)(ht_cap_ie + 2);
+ ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
+
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sband, ht_cap, &sta_ht_cap);
+
+ channel_type = ieee80211_channel_type_from_ht_info(
+ sdata->local, ht_info, sta_ht_cap.cap);
+ }
+
__ieee80211_sta_join_ibss(sdata, cbss->bssid,
beacon_int,
cbss->channel,
+ channel_type,
basic_rates,
cbss->capability,
cbss->tsf);
@@ -529,7 +564,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,13 +942,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.beacon_int = params->beacon_interval;

sdata->u.ibss.channel = params->channel;
+ sdata->u.ibss.channel_type = params->channel_type;
sdata->u.ibss.fixed_channel = params->channel_fixed;

/* fix ourselves to that channel now already */
if (params->channel_fixed) {
sdata->local->oper_channel = params->channel;
WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
- NL80211_CHAN_NO_HT));
+ params->channel_type));
}

if (params->ie) {
@@ -922,11 +959,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 742e12b..78c4716 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,19 @@ 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);
+
+u8 *ieee80211_add_ht_cap(u8 *pos,
+ struct ieee80211_supported_band *sband);
+
+u8 *ieee80211_add_ht_info(u8 *pos,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type);
+
+enum nl80211_channel_type ieee80211_channel_type_from_ht_info(
+ struct ieee80211_local *local,
+ struct ieee80211_ht_info *hti, u16 ap_ht_cap_flags);
+
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 047acb8..78c43b8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -898,6 +898,46 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb(sdata, skb);
}

+u8 *ieee80211_add_ht_info(u8 *pos,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type)
+{
+ struct ieee80211_ht_info ht_info;
+
+ 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);
+
+ return pos;
+}
+
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
const u8 *ie, size_t ie_len,
enum ieee80211_band band)
--
1.5.6.5


2010-05-13 06:02:35

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH] cfg80211: Parse channel_type in NL80211_CMD_JOIN_IBSS

On Thu, 2010-05-13 at 09:56 +0900, Bruno Randolf wrote:
> On Thursday 13 May 2010 06:07:37 Benoit Papillault wrote:
> > 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.

> do you think this could also be used to configure "pure G" channels? remember
> the discussion we had about the basic rate set in IBSS? if we could use this
> to configure the channel as "pure G" we could use a basic rate set with higher
> rates (ERP mandatory rates: 1, 2, 5.5, 11, 6, 12, 24). i still need this
> feature in order to configure higher-thruput G-only IBSS...

No, that would be a basic/mandatory rateset configuration for a regular
20MHz channel.

johannes


2010-05-13 00:56:36

by Bruno Randolf

[permalink] [raw]
Subject: Re: [PATCH] cfg80211: Parse channel_type in NL80211_CMD_JOIN_IBSS

On Thursday 13 May 2010 06:07:37 Benoit Papillault wrote:
> 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 b44a2e5..5ead439 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 aaa1aad..039c13f 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -3879,6 +3879,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));
> @@ -3900,6 +3901,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);
> @@ -3933,11 +3945,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;
> }

do you think this could also be used to configure "pure G" channels? remember
the discussion we had about the basic rate set in IBSS? if we could use this
to configure the channel as "pure G" we could use a basic rate set with higher
rates (ERP mandatory rates: 1, 2, 5.5, 11, 6, 12, 24). i still need this
feature in order to configure higher-thruput G-only IBSS...

bruno