From 2103dec14792be2c2194a454630b01120d30e5cb Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 8 Jul 2013 16:55:53 +0200 Subject: mac80211: select and adjust bitrates according to channel mode The various components accessing the bitrates table must use consider the used channel bandwidth to select only available rates or calculate the bitrate correctly. There are some rates in reduced bandwidth modes which can't be represented as multiples of 500kbps, like 2.25 MBit/s in 5 MHz mode. The standard suggests to round up to the next multiple of 500kbps, just do that in mac80211 as well. Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer [make rate unsigned in ieee80211_add_tx_radiotap_header(), squash fix] Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'net/mac80211/scan.c') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1b122a79b0d8..819d0956eb3b 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -204,10 +204,29 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) ieee80211_rx_bss_put(local, bss); } +static void +ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef, + enum nl80211_bss_scan_width scan_width) +{ + memset(chandef, 0, sizeof(*chandef)); + switch (scan_width) { + case NL80211_BSS_CHAN_WIDTH_5: + chandef->width = NL80211_CHAN_WIDTH_5; + break; + case NL80211_BSS_CHAN_WIDTH_10: + chandef->width = NL80211_CHAN_WIDTH_10; + break; + default: + chandef->width = NL80211_CHAN_WIDTH_20_NOHT; + break; + } +} + /* return false if no more work */ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) { struct cfg80211_scan_request *req = local->scan_req; + struct cfg80211_chan_def chandef; enum ieee80211_band band; int i, ielen, n_chans; @@ -229,11 +248,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) } while (!n_chans); local->hw_scan_req->n_channels = n_chans; + ieee80211_prepare_scan_chandef(&chandef, req->scan_width); ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, local->hw_scan_ies_bufsize, req->ie, req->ie_len, band, - req->rates[band], 0); + req->rates[band], &chandef); local->hw_scan_req->ie_len = ielen; local->hw_scan_req->no_cck = req->no_cck; @@ -912,6 +932,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_sched_scan_ies sched_scan_ies = {}; + struct cfg80211_chan_def chandef; int ret, i, iebufsz; iebufsz = 2 + IEEE80211_MAX_SSID_LEN + @@ -939,10 +960,12 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, goto out_free; } + ieee80211_prepare_scan_chandef(&chandef, req->scan_width); + sched_scan_ies.len[i] = ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], iebufsz, req->ie, req->ie_len, - i, (u32) -1, 0); + i, (u32) -1, &chandef); } ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); -- cgit v1.2.3 From 7ca15a0ae865067aac8d36e27e0acbe4a8f1e70a Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 8 Jul 2013 16:55:56 +0200 Subject: mac80211: allow scanning for 5/10 MHz channels in IBSS Use a chandef instead of just the channel for scanning, and enable 5/10 Mhz scanning for IBSS mode. Also reporting is changed to the new inform_bss functions. Signed-off-by: Simon Wunderlich Signed-off-by: Mathias Kretschmer Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'net/mac80211/scan.c') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 819d0956eb3b..08afe74b98f4 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -66,6 +66,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, struct cfg80211_bss *cbss; struct ieee80211_bss *bss; int clen, srlen; + enum nl80211_bss_scan_width scan_width; s32 signal = 0; if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) @@ -73,8 +74,15 @@ ieee80211_bss_info_update(struct ieee80211_local *local, else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) signal = (rx_status->signal * 100) / local->hw.max_signal; - cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, - mgmt, len, signal, GFP_ATOMIC); + 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; + + cbss = cfg80211_inform_bss_width_frame(local->hw.wiphy, channel, + scan_width, mgmt, len, signal, + GFP_ATOMIC); if (!cbss) return NULL; @@ -300,7 +308,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, rcu_assign_pointer(local->scan_sdata, NULL); local->scanning = 0; - local->scan_channel = NULL; + local->scan_chandef.chan = NULL; /* Set power back to normal operating levels. */ ieee80211_hw_config(local, 0); @@ -635,11 +643,34 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, { int skip; struct ieee80211_channel *chan; + enum nl80211_bss_scan_width oper_scan_width; skip = 0; chan = local->scan_req->channels[local->scan_channel_idx]; - local->scan_channel = chan; + local->scan_chandef.chan = chan; + local->scan_chandef.center_freq1 = chan->center_freq; + local->scan_chandef.center_freq2 = 0; + switch (local->scan_req->scan_width) { + case NL80211_BSS_CHAN_WIDTH_5: + local->scan_chandef.width = NL80211_CHAN_WIDTH_5; + break; + case NL80211_BSS_CHAN_WIDTH_10: + local->scan_chandef.width = NL80211_CHAN_WIDTH_10; + break; + case NL80211_BSS_CHAN_WIDTH_20: + /* If scanning on oper channel, use whatever channel-type + * is currently in use. + */ + oper_scan_width = cfg80211_chandef_to_scan_width( + &local->_oper_chandef); + if (chan == local->_oper_chandef.chan && + oper_scan_width == local->scan_req->scan_width) + local->scan_chandef = local->_oper_chandef; + else + local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; + break; + } if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) skip = 1; @@ -679,7 +710,7 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local, unsigned long *next_delay) { /* switch back to the operating channel */ - local->scan_channel = NULL; + local->scan_chandef.chan = NULL; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); /* disable PS */ @@ -821,7 +852,8 @@ 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 *chan, + enum nl80211_bss_scan_width scan_width) { struct ieee80211_local *local = sdata->local; int ret = -EBUSY; @@ -871,6 +903,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, local->int_scan_req->ssids = &local->scan_ssid; local->int_scan_req->n_ssids = 1; + local->int_scan_req->scan_width = scan_width; memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); local->int_scan_req->ssids[0].ssid_len = ssid_len; -- cgit v1.2.3