mac80211: pass all probe request IEs to driver
Instead of just passing the cfg80211-requested IEs, pass the locally generated ones as well. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
18a8365992
commit
de95a54b1a
7 changed files with 123 additions and 56 deletions
|
@ -503,7 +503,7 @@ struct cfg80211_scan_request {
|
|||
int n_ssids;
|
||||
struct ieee80211_channel **channels;
|
||||
u32 n_channels;
|
||||
u8 *ie;
|
||||
const u8 *ie;
|
||||
size_t ie_len;
|
||||
|
||||
/* internal */
|
||||
|
|
|
@ -1330,11 +1330,14 @@ enum ieee80211_ampdu_mlme_action {
|
|||
* the scan state machine in stack. The scan must honour the channel
|
||||
* configuration done by the regulatory agent in the wiphy's
|
||||
* registered bands. The hardware (or the driver) needs to make sure
|
||||
* that power save is disabled. When the scan finishes,
|
||||
* ieee80211_scan_completed() must be called; note that it also must
|
||||
* be called when the scan cannot finish because the hardware is
|
||||
* turned off! Anything else is a bug! Returns a negative error code
|
||||
* which will be seen in userspace.
|
||||
* that power save is disabled.
|
||||
* The @req ie/ie_len members are rewritten by mac80211 to contain the
|
||||
* entire IEs after the SSID, so that drivers need not look at these
|
||||
* at all but just send them after the SSID -- mac80211 includes the
|
||||
* (extended) supported rates and HT information (where applicable).
|
||||
* When the scan finishes, ieee80211_scan_completed() must be called;
|
||||
* note that it also must be called when the scan cannot finish due to
|
||||
* any error unless this callback returned a negative error code.
|
||||
*
|
||||
* @sw_scan_start: Notifier function that is called just before a software scan
|
||||
* is started. Can be NULL, if the driver doesn't need this notification.
|
||||
|
|
|
@ -671,7 +671,10 @@ struct ieee80211_local {
|
|||
struct cfg80211_scan_request int_scan_req;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
struct ieee80211_channel *scan_channel;
|
||||
const u8 *orig_ies;
|
||||
int orig_ies_len;
|
||||
int scan_channel_idx;
|
||||
int scan_ies_len;
|
||||
|
||||
enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
|
||||
unsigned long last_scan_completed;
|
||||
|
@ -1090,9 +1093,11 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
|||
u16 transaction, u16 auth_alg,
|
||||
u8 *extra, size_t extra_len,
|
||||
const u8 *bssid, int encrypt);
|
||||
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
||||
const u8 *ie, size_t ie_len);
|
||||
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
||||
u8 *ssid, size_t ssid_len,
|
||||
u8 *ie, size_t ie_len);
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len);
|
||||
|
||||
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
const size_t supp_rates_len,
|
||||
|
|
|
@ -729,22 +729,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
|
||||
wiphy->privid = mac80211_wiphy_privid;
|
||||
|
||||
if (!ops->hw_scan) {
|
||||
/* For hw_scan, driver needs to set these up. */
|
||||
wiphy->max_scan_ssids = 4;
|
||||
|
||||
/* we support a maximum of 32 rates in cfg80211 */
|
||||
wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN
|
||||
- 2 - 32 /* SSID */
|
||||
- 4 - 32 /* (ext) supp rates */;
|
||||
|
||||
}
|
||||
|
||||
/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
|
||||
wiphy->bss_priv_size = sizeof(struct ieee80211_bss) -
|
||||
sizeof(struct cfg80211_bss);
|
||||
|
||||
local = wiphy_priv(wiphy);
|
||||
|
||||
local->hw.wiphy = wiphy;
|
||||
|
||||
local->hw.priv = (char *)local +
|
||||
|
@ -831,7 +821,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
enum ieee80211_band band;
|
||||
struct net_device *mdev;
|
||||
struct ieee80211_master_priv *mpriv;
|
||||
int channels, i, j;
|
||||
int channels, i, j, max_bitrates;
|
||||
|
||||
/*
|
||||
* generic code guarantees at least one band,
|
||||
|
@ -839,18 +829,23 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
* that hw.conf.channel is assigned
|
||||
*/
|
||||
channels = 0;
|
||||
max_bitrates = 0;
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
if (sband && !local->oper_channel) {
|
||||
if (!sband)
|
||||
continue;
|
||||
if (!local->oper_channel) {
|
||||
/* init channel we're on */
|
||||
local->hw.conf.channel =
|
||||
local->oper_channel =
|
||||
local->scan_channel = &sband->channels[0];
|
||||
}
|
||||
if (sband)
|
||||
channels += sband->n_channels;
|
||||
channels += sband->n_channels;
|
||||
|
||||
if (max_bitrates < sband->n_bitrates)
|
||||
max_bitrates = sband->n_bitrates;
|
||||
}
|
||||
|
||||
local->int_scan_req.n_channels = channels;
|
||||
|
@ -870,6 +865,30 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
|
||||
local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
|
||||
|
||||
/*
|
||||
* Calculate scan IE length -- we need this to alloc
|
||||
* memory and to subtract from the driver limit. It
|
||||
* includes the (extended) supported rates and HT
|
||||
* information -- SSID is the driver's responsibility.
|
||||
*/
|
||||
local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */
|
||||
|
||||
if (!local->ops->hw_scan) {
|
||||
/* For hw_scan, driver needs to set these up. */
|
||||
local->hw.wiphy->max_scan_ssids = 4;
|
||||
local->hw.wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the driver supports any scan IEs, then assume the
|
||||
* limit includes the IEs mac80211 will add, otherwise
|
||||
* leave it at zero and let the driver sort it out; we
|
||||
* still pass our IEs to the driver but userspace will
|
||||
* not be allowed to in that case.
|
||||
*/
|
||||
if (local->hw.wiphy->max_scan_ie_len)
|
||||
local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
|
||||
|
||||
result = wiphy_register(local->hw.wiphy);
|
||||
if (result < 0)
|
||||
goto fail_wiphy_register;
|
||||
|
|
|
@ -285,6 +285,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|||
if (WARN_ON(!local->scan_req))
|
||||
return;
|
||||
|
||||
if (local->hw_scanning) {
|
||||
kfree(local->scan_req->ie);
|
||||
local->scan_req->ie = local->orig_ies;
|
||||
local->scan_req->ie_len = local->orig_ies_len;
|
||||
}
|
||||
|
||||
if (local->scan_req != &local->int_scan_req)
|
||||
cfg80211_scan_done(local->scan_req, aborted);
|
||||
local->scan_req = NULL;
|
||||
|
@ -457,12 +463,28 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
|
|||
}
|
||||
|
||||
if (local->ops->hw_scan) {
|
||||
int rc;
|
||||
u8 *ies;
|
||||
int rc, ielen;
|
||||
|
||||
ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN +
|
||||
local->scan_ies_len + req->ie_len, GFP_KERNEL);
|
||||
if (!ies)
|
||||
return -ENOMEM;
|
||||
|
||||
ielen = ieee80211_build_preq_ies(local, ies,
|
||||
req->ie, req->ie_len);
|
||||
local->orig_ies = req->ie;
|
||||
local->orig_ies_len = req->ie_len;
|
||||
req->ie = ies;
|
||||
req->ie_len = ielen;
|
||||
|
||||
local->hw_scanning = true;
|
||||
rc = local->ops->hw_scan(local_to_hw(local), req);
|
||||
if (rc) {
|
||||
local->hw_scanning = false;
|
||||
kfree(ies);
|
||||
req->ie_len = local->orig_ies_len;
|
||||
req->ie = local->orig_ies;
|
||||
return rc;
|
||||
}
|
||||
local->scan_sdata = scan_sdata;
|
||||
|
|
|
@ -831,16 +831,57 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_tx_skb(sdata, skb, encrypt);
|
||||
}
|
||||
|
||||
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
||||
const u8 *ie, size_t ie_len)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
u8 *pos, *supp_rates_len, *esupp_rates_len = NULL;
|
||||
int i;
|
||||
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
pos = buffer;
|
||||
|
||||
*pos++ = WLAN_EID_SUPP_RATES;
|
||||
supp_rates_len = pos;
|
||||
*pos++ = 0;
|
||||
|
||||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
struct ieee80211_rate *rate = &sband->bitrates[i];
|
||||
|
||||
if (esupp_rates_len) {
|
||||
*esupp_rates_len += 1;
|
||||
} else if (*supp_rates_len == 8) {
|
||||
*pos++ = WLAN_EID_EXT_SUPP_RATES;
|
||||
esupp_rates_len = pos;
|
||||
*pos++ = 1;
|
||||
} else
|
||||
*supp_rates_len += 1;
|
||||
|
||||
*pos++ = rate->bitrate / 5;
|
||||
}
|
||||
|
||||
/*
|
||||
* If adding more here, adjust code in main.c
|
||||
* that calculates local->scan_ies_len.
|
||||
*/
|
||||
|
||||
if (ie) {
|
||||
memcpy(pos, ie, ie_len);
|
||||
pos += ie_len;
|
||||
}
|
||||
|
||||
return pos - buffer;
|
||||
}
|
||||
|
||||
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
||||
u8 *ssid, size_t ssid_len,
|
||||
u8 *ie, size_t ie_len)
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
u8 *pos, *supp_rates, *esupp_rates = NULL;
|
||||
int i;
|
||||
u8 *pos;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
|
||||
ie_len);
|
||||
|
@ -867,33 +908,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
|
|||
*pos++ = WLAN_EID_SSID;
|
||||
*pos++ = ssid_len;
|
||||
memcpy(pos, ssid, ssid_len);
|
||||
pos += ssid_len;
|
||||
|
||||
supp_rates = skb_put(skb, 2);
|
||||
supp_rates[0] = WLAN_EID_SUPP_RATES;
|
||||
supp_rates[1] = 0;
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
|
||||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
struct ieee80211_rate *rate = &sband->bitrates[i];
|
||||
if (esupp_rates) {
|
||||
pos = skb_put(skb, 1);
|
||||
esupp_rates[1]++;
|
||||
} else if (supp_rates[1] == 8) {
|
||||
esupp_rates = skb_put(skb, 3);
|
||||
esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
|
||||
esupp_rates[1] = 1;
|
||||
pos = &esupp_rates[2];
|
||||
} else {
|
||||
pos = skb_put(skb, 1);
|
||||
supp_rates[1]++;
|
||||
}
|
||||
*pos = rate->bitrate / 5;
|
||||
}
|
||||
|
||||
/* if adding more here, adjust max_scan_ie_len */
|
||||
|
||||
if (ie)
|
||||
memcpy(skb_put(skb, ie_len), ie, ie_len);
|
||||
skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len));
|
||||
|
||||
ieee80211_tx_skb(sdata, skb, 0);
|
||||
}
|
||||
|
|
|
@ -2597,7 +2597,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
if (info->attrs[NL80211_ATTR_IE]) {
|
||||
request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
||||
memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]),
|
||||
memcpy((void *)request->ie,
|
||||
nla_data(info->attrs[NL80211_ATTR_IE]),
|
||||
request->ie_len);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue