2015-03-09 06:59:08

by Janusz Dziedzic

[permalink] [raw]
Subject: [PATCHv2 1/3] mac80211: IBSS fix scan request

In case of wide bandwidth scan all channels we have
in chandef. For example in case of 80MHz bandwidth
we have four possible control channels.

Signed-off-by: Janusz Dziedzic <[email protected]>
---
net/mac80211/ibss.c | 81 ++++++++++++++++++++++++++++++++++++++++++++--
net/mac80211/ieee80211_i.h | 3 +-
net/mac80211/scan.c | 25 ++++++++------
3 files changed, 97 insertions(+), 12 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index ee93d7d..650e69c 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1258,7 +1258,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)

scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len,
- NULL, scan_width);
+ NULL, 0, scan_width);
}

static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
@@ -1297,6 +1297,76 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
capability, 0, true);
}

+static unsigned ibss_setup_channels(struct wiphy *wiphy,
+ struct ieee80211_channel **channels,
+ unsigned int channels_max,
+ u32 center_freq, u32 width)
+{
+ struct ieee80211_channel *chan = NULL;
+ unsigned int n_chan = 0;
+ u32 start_freq, end_freq, freq;
+
+ if (width <= 20) {
+ start_freq = center_freq;
+ end_freq = center_freq;
+ } else {
+ start_freq = center_freq - width/2 + 10;
+ end_freq = center_freq + width/2 - 10;
+ }
+
+ for (freq = start_freq; freq <= end_freq; freq += 20) {
+ chan = ieee80211_get_channel(wiphy, freq);
+ if (!chan)
+ continue;
+ if (n_chan >= channels_max)
+ return n_chan;
+
+ channels[n_chan] = chan;
+ n_chan++;
+ }
+
+ return n_chan;
+}
+
+static unsigned int
+ieee80211_ibss_setup_scan_channels(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef,
+ struct ieee80211_channel **channels,
+ unsigned int channels_max)
+{
+ unsigned int n_chan = 0;
+ u32 width, cf1, cf2 = 0;
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_40:
+ width = 40;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ cf2 = chandef->center_freq2;
+ /* fall through */
+ case NL80211_CHAN_WIDTH_80:
+ width = 80;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ width = 160;
+ break;
+ default:
+ width = 20;
+ break;
+ }
+
+ cf1 = chandef->center_freq1;
+
+ n_chan = ibss_setup_channels(wiphy, channels, channels_max, cf1, width);
+
+ if (cf2)
+ n_chan += ibss_setup_channels(wiphy, &channels[n_chan],
+ channels_max - n_chan, cf2,
+ width);
+
+ return n_chan;
+}
+
/*
* This function is called with state == IEEE80211_IBSS_MLME_SEARCH
*/
@@ -1362,11 +1432,18 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
/* Selected IBSS not found in current scan results - try to scan */
if (time_after(jiffies, ifibss->last_scan_completed +
IEEE80211_SCAN_INTERVAL)) {
+ struct ieee80211_channel *channels[8];
+ unsigned int num;
+
sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");

+ num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
+ &ifibss->chandef,
+ channels,
+ ARRAY_SIZE(channels));
scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
ieee80211_request_ibss_scan(sdata, ifibss->ssid,
- ifibss->ssid_len, chan,
+ ifibss->ssid_len, channels, num,
scan_width);
} else {
int interval = IEEE80211_SCAN_INTERVAL;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 486a790..856f88d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1542,7 +1542,8 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata);
void ieee80211_scan_work(struct work_struct *work);
int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
const u8 *ssid, u8 ssid_len,
- struct ieee80211_channel *chan,
+ struct ieee80211_channel **channels,
+ unsigned int n_channels,
enum nl80211_bss_scan_width scan_width);
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
struct cfg80211_scan_request *req);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 05f0d71..7bb6a93 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -928,11 +928,12 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,

int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
const u8 *ssid, u8 ssid_len,
- struct ieee80211_channel *chan,
+ struct ieee80211_channel **channels,
+ unsigned int n_channels,
enum nl80211_bss_scan_width scan_width)
{
struct ieee80211_local *local = sdata->local;
- int ret = -EBUSY;
+ int ret = -EBUSY, i, n_ch = 0;
enum ieee80211_band band;

mutex_lock(&local->mtx);
@@ -942,9 +943,8 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
goto unlock;

/* fill internal scan request */
- if (!chan) {
- int i, max_n;
- int n_ch = 0;
+ if (!channels) {
+ int max_n;

for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!local->hw.wiphy->bands[band])
@@ -969,12 +969,19 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,

local->int_scan_req->n_channels = n_ch;
} else {
- if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR |
- IEEE80211_CHAN_DISABLED)))
+ for (i = 0; i < n_channels; i++) {
+ if (channels[i]->flags & (IEEE80211_CHAN_NO_IR |
+ IEEE80211_CHAN_DISABLED))
+ continue;
+
+ local->int_scan_req->channels[n_ch] = channels[i];
+ n_ch++;
+ }
+
+ if (WARN_ON_ONCE(n_ch == 0))
goto unlock;

- local->int_scan_req->channels[0] = chan;
- local->int_scan_req->n_channels = 1;
+ local->int_scan_req->n_channels = n_ch;
}

local->int_scan_req->ssids = &local->scan_ssid;
--
1.9.1



2015-03-17 10:06:02

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] mac80211: IBSS fix scan request

On Mon, 2015-03-09 at 07:58 +0100, Janusz Dziedzic wrote:
> In case of wide bandwidth scan all channels we have
> in chandef. For example in case of 80MHz bandwidth
> we have four possible control channels.

I think you misunderstood - this doesn't really say *why* either.

It should probably say something like

If channels wider than 20 MHz are used by IBSS, scan all channels in the
chandef to be able to find neighboring IBSS networks that use the same
overall channel but a different control channel.

no?

johannes


2015-03-17 10:08:16

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCHv2 3/3] mac80211: add VHT support for IBSS

On Mon, 2015-03-09 at 07:58 +0100, Janusz Dziedzic wrote:
> Add VHT support for IBSS. Drivers could activate
> this feature by setting NL80211_EXT_FEATURE_VHT_IBSS
> flag.

I'm assuming this needs patch 1 to go in first, so am not applying this.
If I'm wrong let me know, or just resend with the changed patch 1.

johannes


2015-03-09 06:59:10

by Janusz Dziedzic

[permalink] [raw]
Subject: [PATCHv2 3/3] mac80211: add VHT support for IBSS

Add VHT support for IBSS. Drivers could activate
this feature by setting NL80211_EXT_FEATURE_VHT_IBSS
flag.

Signed-off-by: Janusz Dziedzic <[email protected]>
---
net/mac80211/ht.c | 2 --
net/mac80211/ibss.c | 50 +++++++++++++++++++++++++++++++++++++---------
net/mac80211/ieee80211_i.h | 3 +++
net/mac80211/mesh_plink.c | 4 ++++
net/mac80211/util.c | 33 ++++++++++++++++++++++++++++++
5 files changed, 81 insertions(+), 11 deletions(-)

diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index ff630be..7a76ce6 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -252,8 +252,6 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
break;
}

- if (bw != sta->sta.bandwidth)
- changed = true;
sta->sta.bandwidth = bw;

sta->cur_max_bandwidth =
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 4299973..f415fff 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -188,6 +188,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
*/
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
chandef, 0);
+
+ /* add VHT capability and information IEs */
+ if (chandef->width != NL80211_CHAN_WIDTH_20 &&
+ chandef->width != NL80211_CHAN_WIDTH_40 &&
+ sband->vht_cap.vht_supported) {
+ pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
+ sband->vht_cap.cap);
+ pos = ieee80211_ie_build_vht_oper(pos, &sband->vht_cap,
+ chandef);
+ }
}

if (local->hw.queues >= IEEE80211_NUM_ACS)
@@ -417,6 +427,11 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
NL80211_CHAN_WIDTH_20_NOHT);
chandef.width = sdata->u.ibss.chandef.width;
break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_160:
+ chandef = sdata->u.ibss.chandef;
+ chandef.chan = cbss->channel;
+ break;
default:
/* fall back to 20 MHz for unsupported modes */
cfg80211_chandef_create(&chandef, cbss->channel,
@@ -1028,24 +1043,41 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
/* we both use HT */
struct ieee80211_ht_cap htcap_ie;
struct cfg80211_chan_def chandef;
+ enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;

ieee80211_ht_oper_to_chandef(channel,
elems->ht_operation,
&chandef);

memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
-
- /*
- * fall back to HT20 if we don't use or use
- * the other extension channel
- */
- if (chandef.center_freq1 != sdata->u.ibss.chandef.center_freq1)
- htcap_ie.cap_info &=
- cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
&htcap_ie,
sta);
+
+ if (elems->vht_operation && elems->vht_cap_elem &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20 &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_40) {
+ /* we both use VHT */
+ struct ieee80211_vht_cap cap_ie;
+ struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
+
+ ieee80211_vht_oper_to_chandef(channel,
+ elems->vht_operation,
+ &chandef);
+ memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
+ ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
+ &cap_ie, sta);
+ if (memcmp(&cap, &sta->sta.vht_cap, sizeof(cap)))
+ rates_updated |= true;
+ }
+
+ if (bw != sta->sta.bandwidth)
+ rates_updated |= true;
+
+ if (!cfg80211_chandef_compatible(&sdata->u.ibss.chandef,
+ &chandef))
+ ibss_dbg(sdata, "%pM incompatible chandef\n",
+ sta->sta.addr);
}

if (sta && rates_updated) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 856f88d..faddd1a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1970,6 +1970,9 @@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
const struct ieee80211_ht_operation *ht_oper,
struct cfg80211_chan_def *chandef);
+void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
+ const struct ieee80211_vht_operation *oper,
+ struct cfg80211_chan_def *chandef);
u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);

int __must_check
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 8465c05..60d737f 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -382,6 +382,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_supported_band *sband;
u32 rates, basic_rates = 0, changed = 0;
+ enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;

sband = local->hw.wiphy->bands[band];
rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates);
@@ -401,6 +402,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
elems->ht_cap_elem, sta))
changed |= IEEE80211_RC_BW_CHANGED;

+ if (bw != sta->sta.bandwidth)
+ changed |= IEEE80211_RC_BW_CHANGED;
+
/* HT peer is operating 20MHz-only */
if (elems->ht_operation &&
!(elems->ht_operation->ht_param &
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 37d85d3..3ff6adf 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2428,6 +2428,39 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
cfg80211_chandef_create(chandef, control_chan, channel_type);
}

+void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
+ const struct ieee80211_vht_operation *oper,
+ struct cfg80211_chan_def *chandef)
+{
+ if (!oper)
+ return;
+
+ chandef->chan = control_chan;
+
+ switch (oper->chan_width) {
+ case IEEE80211_VHT_CHANWIDTH_USE_HT:
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_80;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_160MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_160;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+ chandef->width = NL80211_CHAN_WIDTH_80P80;
+ break;
+ default:
+ break;
+ }
+
+ chandef->center_freq1 =
+ ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
+ control_chan->band);
+ chandef->center_freq2 =
+ ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
+ control_chan->band);
+}
+
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
const struct ieee80211_supported_band *sband,
const u8 *srates, int srates_len, u32 *rates)
--
1.9.1


2015-03-17 10:06:50

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCHv2 2/3] mac80211: ibss refactor ieee80211_rx_bss_info

On Mon, 2015-03-09 at 07:58 +0100, Janusz Dziedzic wrote:
> Put station specific code in ieee80211_update_sta_info
> function.

Applied.

johannes


2015-03-09 06:59:09

by Janusz Dziedzic

[permalink] [raw]
Subject: [PATCHv2 2/3] mac80211: ibss refactor ieee80211_rx_bss_info

Put station specific code in ieee80211_update_sta_info
function.

Signed-off-by: Janusz Dziedzic <[email protected]>
---
net/mac80211/ibss.c | 186 ++++++++++++++++++++++++++++------------------------
1 file changed, 100 insertions(+), 86 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 650e69c..4299973 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -965,6 +965,105 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0);
}

+static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ struct ieee80211_rx_status *rx_status,
+ struct ieee802_11_elems *elems,
+ struct ieee80211_channel *channel)
+{
+ struct sta_info *sta;
+ enum ieee80211_band band = rx_status->band;
+ enum nl80211_bss_scan_width scan_width;
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
+ bool rates_updated = false;
+ u32 supp_rates = 0;
+
+ if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ return;
+
+ if (!ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid))
+ return;
+
+ rcu_read_lock();
+ sta = sta_info_get(sdata, mgmt->sa);
+
+ if (elems->supp_rates) {
+ supp_rates = ieee80211_sta_get_rates(sdata, elems,
+ band, NULL);
+ if (sta) {
+ u32 prev_rates;
+
+ prev_rates = sta->sta.supp_rates[band];
+ /* make sure mandatory rates are always added */
+ scan_width = NL80211_BSS_CHAN_WIDTH_20;
+ if (rx_status->flag & RX_FLAG_5MHZ)
+ scan_width = NL80211_BSS_CHAN_WIDTH_5;
+ if (rx_status->flag & RX_FLAG_10MHZ)
+ scan_width = NL80211_BSS_CHAN_WIDTH_10;
+
+ sta->sta.supp_rates[band] = supp_rates |
+ ieee80211_mandatory_rates(sband, scan_width);
+ if (sta->sta.supp_rates[band] != prev_rates) {
+ ibss_dbg(sdata,
+ "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
+ sta->sta.addr, prev_rates,
+ sta->sta.supp_rates[band]);
+ rates_updated = true;
+ }
+ } else {
+ rcu_read_unlock();
+ sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
+ mgmt->sa, supp_rates);
+ }
+ }
+
+ if (sta && elems->wmm_info)
+ sta->sta.wme = true;
+
+ if (sta && elems->ht_operation && elems->ht_cap_elem &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 &&
+ sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) {
+ /* we both use HT */
+ struct ieee80211_ht_cap htcap_ie;
+ struct cfg80211_chan_def chandef;
+
+ ieee80211_ht_oper_to_chandef(channel,
+ elems->ht_operation,
+ &chandef);
+
+ memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
+
+ /*
+ * fall back to HT20 if we don't use or use
+ * the other extension channel
+ */
+ if (chandef.center_freq1 != sdata->u.ibss.chandef.center_freq1)
+ htcap_ie.cap_info &=
+ cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+
+ rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
+ &htcap_ie,
+ sta);
+ }
+
+ if (sta && rates_updated) {
+ u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
+ u8 rx_nss = sta->sta.rx_nss;
+
+ /* Force rx_nss recalculation */
+ sta->sta.rx_nss = 0;
+ rate_control_rate_init(sta);
+ if (sta->sta.rx_nss != rx_nss)
+ changed |= IEEE80211_RC_NSS_CHANGED;
+
+ drv_sta_rc_update(local, sdata, &sta->sta, changed);
+ }
+
+ rcu_read_unlock();
+}
+
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len,
struct ieee80211_rx_status *rx_status,
@@ -973,101 +1072,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct cfg80211_bss *cbss;
struct ieee80211_bss *bss;
- struct sta_info *sta;
struct ieee80211_channel *channel;
u64 beacon_timestamp, rx_timestamp;
u32 supp_rates = 0;
enum ieee80211_band band = rx_status->band;
- enum nl80211_bss_scan_width scan_width;
- struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
- bool rates_updated = false;

channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
if (!channel)
return;

- if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
- ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid)) {
-
- rcu_read_lock();
- sta = sta_info_get(sdata, mgmt->sa);
-
- if (elems->supp_rates) {
- supp_rates = ieee80211_sta_get_rates(sdata, elems,
- band, NULL);
- if (sta) {
- u32 prev_rates;
-
- prev_rates = sta->sta.supp_rates[band];
- /* make sure mandatory rates are always added */
- scan_width = NL80211_BSS_CHAN_WIDTH_20;
- if (rx_status->flag & RX_FLAG_5MHZ)
- scan_width = NL80211_BSS_CHAN_WIDTH_5;
- if (rx_status->flag & RX_FLAG_10MHZ)
- scan_width = NL80211_BSS_CHAN_WIDTH_10;
-
- sta->sta.supp_rates[band] = supp_rates |
- ieee80211_mandatory_rates(sband,
- scan_width);
- if (sta->sta.supp_rates[band] != prev_rates) {
- ibss_dbg(sdata,
- "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
- sta->sta.addr, prev_rates,
- sta->sta.supp_rates[band]);
- rates_updated = true;
- }
- } else {
- rcu_read_unlock();
- sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
- mgmt->sa, supp_rates);
- }
- }
-
- if (sta && elems->wmm_info)
- sta->sta.wme = true;
-
- if (sta && elems->ht_operation && elems->ht_cap_elem &&
- sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
- sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 &&
- sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) {
- /* we both use HT */
- struct ieee80211_ht_cap htcap_ie;
- struct cfg80211_chan_def chandef;
-
- ieee80211_ht_oper_to_chandef(channel,
- elems->ht_operation,
- &chandef);
-
- memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
-
- /*
- * fall back to HT20 if we don't use or use
- * the other extension channel
- */
- if (chandef.center_freq1 !=
- sdata->u.ibss.chandef.center_freq1)
- htcap_ie.cap_info &=
- cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
- rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(
- sdata, sband, &htcap_ie, sta);
- }
-
- if (sta && rates_updated) {
- u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
- u8 rx_nss = sta->sta.rx_nss;
-
- /* Force rx_nss recalculation */
- sta->sta.rx_nss = 0;
- rate_control_rate_init(sta);
- if (sta->sta.rx_nss != rx_nss)
- changed |= IEEE80211_RC_NSS_CHANGED;
-
- drv_sta_rc_update(local, sdata, &sta->sta, changed);
- }
-
- rcu_read_unlock();
- }
+ ieee80211_update_sta_info(sdata, mgmt, len, rx_status, elems, channel);

bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
channel);
--
1.9.1