linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] mac80211/cfg80211 scan improvements
@ 2009-03-31 10:12 Johannes Berg
  2009-03-31 10:12 ` [PATCH v3 1/3] cfg80211: introduce scan IE limit attribute Johannes Berg
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Johannes Berg @ 2009-03-31 10:12 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, j

We currently don't tell userspace what the max IE length is,
fix that. We also have hw_scan build the probe request, which
is not necessary, mac80211 can do that.

I have, but will submit over a different channel, a patch to
fix up iwlwifi to support proper scanning after this series.

johannes


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v3 1/3] cfg80211: introduce scan IE limit attribute
  2009-03-31 10:12 [PATCH v3 0/3] mac80211/cfg80211 scan improvements Johannes Berg
@ 2009-03-31 10:12 ` Johannes Berg
  2009-03-31 10:12 ` [PATCH v3 2/3] mac80211: pass all probe request IEs to driver Johannes Berg
  2009-03-31 10:12 ` [PATCH v3 3/3] mac80211: include HT capabilities in probe request Johannes Berg
  2 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2009-03-31 10:12 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, j

This patch introduces a new attribute for a wiphy that tells
userspace how long the information elements added to a probe
request frame can be at most. It also updates the at76 to
advertise that it cannot support that, and, for now until I
can fix that, iwlwifi too.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 drivers/net/wireless/at76c50x-usb.c     |    1 +
 drivers/net/wireless/iwlwifi/iwl-core.c |    1 +
 include/linux/nl80211.h                 |    4 ++++
 include/net/wireless.h                  |    1 +
 net/mac80211/main.c                     |   13 ++++++++++++-
 net/mac80211/util.c                     |    2 ++
 net/wireless/nl80211.c                  |    7 +++++++
 7 files changed, 28 insertions(+), 1 deletion(-)

--- wireless-testing.orig/include/net/wireless.h	2009-03-31 11:42:22.000000000 +0200
+++ wireless-testing/include/net/wireless.h	2009-03-31 11:48:50.000000000 +0200
@@ -222,6 +222,7 @@ struct wiphy {
 
 	int bss_priv_size;
 	u8 max_scan_ssids;
+	u16 max_scan_ie_len;
 
 	/* If multiple wiphys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee80211_ptr, you won't
--- wireless-testing.orig/net/wireless/nl80211.c	2009-03-31 11:42:22.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-03-31 11:48:50.000000000 +0200
@@ -151,6 +151,8 @@ static int nl80211_send_wiphy(struct sk_
 	NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
 	NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
 		   dev->wiphy.max_scan_ssids);
+	NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
+		    dev->wiphy.max_scan_ie_len);
 
 	nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
 	if (!nl_modes)
@@ -2492,6 +2494,11 @@ static int nl80211_trigger_scan(struct s
 	else
 		ie_len = 0;
 
+	if (ie_len > wiphy->max_scan_ie_len) {
+		err = -EINVAL;
+		goto out;
+	}
+
 	request = kzalloc(sizeof(*request)
 			+ sizeof(*ssid) * n_ssids
 			+ sizeof(channel) * n_channels
--- wireless-testing.orig/include/linux/nl80211.h	2009-03-31 11:42:22.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h	2009-03-31 11:48:50.000000000 +0200
@@ -380,6 +380,8 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
  *	a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
+ *	that can be added to a scan request
  *
  * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
  * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -492,6 +494,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_AUTH_TYPE,
 	NL80211_ATTR_REASON_CODE,
 
+	NL80211_ATTR_MAX_SCAN_IE_LEN,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
--- wireless-testing.orig/net/mac80211/main.c	2009-03-31 11:48:49.000000000 +0200
+++ wireless-testing/net/mac80211/main.c	2009-03-31 11:48:50.000000000 +0200
@@ -724,7 +724,18 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 		return NULL;
 
 	wiphy->privid = mac80211_wiphy_privid;
-	wiphy->max_scan_ssids = 4;
+
+	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);
--- wireless-testing.orig/net/mac80211/util.c	2009-03-31 11:48:49.000000000 +0200
+++ wireless-testing/net/mac80211/util.c	2009-03-31 11:48:50.000000000 +0200
@@ -891,6 +891,8 @@ void ieee80211_send_probe_req(struct iee
 		*pos = rate->bitrate / 5;
 	}
 
+	/* if adding more here, adjust max_scan_ie_len */
+
 	if (ie)
 		memcpy(skb_put(skb, ie_len), ie, ie_len);
 
--- wireless-testing.orig/drivers/net/wireless/at76c50x-usb.c	2009-03-31 11:42:22.000000000 +0200
+++ wireless-testing/drivers/net/wireless/at76c50x-usb.c	2009-03-31 11:48:50.000000000 +0200
@@ -2248,6 +2248,7 @@ static int at76_init_new_device(struct a
 
 	/* mac80211 initialisation */
 	priv->hw->wiphy->max_scan_ssids = 1;
+	priv->hw->wiphy->max_scan_ie_len = 0;
 	priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 	priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
 	priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-core.c	2009-03-31 11:42:22.000000000 +0200
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-core.c	2009-03-31 11:48:50.000000000 +0200
@@ -1306,6 +1306,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
 
 	hw->wiphy->custom_regulatory = true;
 	hw->wiphy->max_scan_ssids = 1;
+	hw->wiphy->max_scan_ie_len = 0; /* XXX for now */
 
 	/* Default value; 4 EDCA QOS priorities */
 	hw->queues = 4;

-- 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v3 2/3] mac80211: pass all probe request IEs to driver
  2009-03-31 10:12 [PATCH v3 0/3] mac80211/cfg80211 scan improvements Johannes Berg
  2009-03-31 10:12 ` [PATCH v3 1/3] cfg80211: introduce scan IE limit attribute Johannes Berg
@ 2009-03-31 10:12 ` Johannes Berg
  2009-04-01  9:58   ` [PATCH v4 " Johannes Berg
  2009-03-31 10:12 ` [PATCH v3 3/3] mac80211: include HT capabilities in probe request Johannes Berg
  2 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2009-03-31 10:12 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, j

Instead of just passing the cfg80211-requested IEs, pass
the locally generated ones as well.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
v2: * assume wiphy->max_scan_ie_len contains the limit *including*
      the IEs mac80211 passes (since the driver cannot know how long
      those will be) and adjust the driver's limit accordingly
    * keep track of original IEs and hand back the pristine cfg80211
      request structure
    * mark the IE pointer const in the request struct
v3: * move code to correct place (register_hw)
    * calculate upper limit for userspace scan IEs more accurately

 include/net/cfg80211.h     |    2 -
 include/net/mac80211.h     |   13 ++++---
 net/mac80211/ieee80211_i.h |    9 +++--
 net/mac80211/main.c        |   49 +++++++++++++++++++--------
 net/mac80211/scan.c        |   24 +++++++++++++
 net/mac80211/util.c        |   79 +++++++++++++++++++++++++++------------------
 net/wireless/nl80211.c     |    3 +
 7 files changed, 123 insertions(+), 56 deletions(-)

--- wireless-testing.orig/include/net/mac80211.h	2009-03-31 11:42:15.000000000 +0200
+++ wireless-testing/include/net/mac80211.h	2009-03-31 11:48:51.000000000 +0200
@@ -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.
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-03-31 11:42:15.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-03-31 11:48:51.000000000 +0200
@@ -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;
@@ -1093,9 +1096,11 @@ void ieee80211_send_auth(struct ieee8021
 			 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,
--- wireless-testing.orig/net/mac80211/util.c	2009-03-31 11:48:50.000000000 +0200
+++ wireless-testing/net/mac80211/util.c	2009-03-31 11:48:51.000000000 +0200
@@ -832,16 +832,57 @@ void ieee80211_send_auth(struct ieee8021
 	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);
@@ -868,33 +909,9 @@ void ieee80211_send_probe_req(struct iee
 	*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);
 }
--- wireless-testing.orig/net/mac80211/main.c	2009-03-31 11:48:50.000000000 +0200
+++ wireless-testing/net/mac80211/main.c	2009-03-31 11:48:51.000000000 +0200
@@ -725,22 +725,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 
 	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 +
@@ -827,7 +817,7 @@ int ieee80211_register_hw(struct ieee802
 	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,
@@ -835,18 +825,23 @@ int ieee80211_register_hw(struct ieee802
 	 * 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;
@@ -866,6 +861,30 @@ int ieee80211_register_hw(struct ieee802
 	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;
--- wireless-testing.orig/net/mac80211/scan.c	2009-03-31 11:48:49.000000000 +0200
+++ wireless-testing/net/mac80211/scan.c	2009-03-31 11:48:51.000000000 +0200
@@ -286,6 +286,12 @@ void ieee80211_scan_completed(struct iee
 	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;
@@ -456,12 +462,28 @@ int ieee80211_start_scan(struct ieee8021
 	}
 
 	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 = drv_hw_scan(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;
--- wireless-testing.orig/include/net/cfg80211.h	2009-03-31 11:42:15.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h	2009-03-31 11:48:51.000000000 +0200
@@ -504,7 +504,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 */
--- wireless-testing.orig/net/wireless/nl80211.c	2009-03-31 11:48:50.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-03-31 11:48:51.000000000 +0200
@@ -2561,7 +2561,8 @@ static int nl80211_trigger_scan(struct s
 
 	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);
 	}
 

-- 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v3 3/3] mac80211: include HT capabilities in probe request
  2009-03-31 10:12 [PATCH v3 0/3] mac80211/cfg80211 scan improvements Johannes Berg
  2009-03-31 10:12 ` [PATCH v3 1/3] cfg80211: introduce scan IE limit attribute Johannes Berg
  2009-03-31 10:12 ` [PATCH v3 2/3] mac80211: pass all probe request IEs to driver Johannes Berg
@ 2009-03-31 10:12 ` Johannes Berg
  2 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2009-03-31 10:12 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, j

Include the HT capabilities in the probe request frame.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
v2: fix the HT IE

 net/mac80211/main.c |    5 +++++
 net/mac80211/util.c |   16 ++++++++++++++++
 2 files changed, 21 insertions(+)

--- wireless-testing.orig/net/mac80211/util.c	2009-03-31 11:48:51.000000000 +0200
+++ wireless-testing/net/mac80211/util.c	2009-03-31 11:48:51.000000000 +0200
@@ -862,6 +862,22 @@ int ieee80211_build_preq_ies(struct ieee
 		*pos++ = rate->bitrate / 5;
 	}
 
+	if (sband->ht_cap.ht_supported) {
+		__le16 tmp = cpu_to_le16(sband->ht_cap.cap);
+
+		*pos++ = WLAN_EID_HT_CAPABILITY;
+		*pos++ = sizeof(struct ieee80211_ht_cap);
+		memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+		memcpy(pos, &tmp, sizeof(u16));
+		pos += sizeof(u16);
+		/* TODO: needs a define here for << 2 */
+		*pos++ = sband->ht_cap.ampdu_factor |
+			 (sband->ht_cap.ampdu_density << 2);
+		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 */
+	}
+
 	/*
 	 * If adding more here, adjust code in main.c
 	 * that calculates local->scan_ies_len.
--- wireless-testing.orig/net/mac80211/main.c	2009-03-31 11:48:51.000000000 +0200
+++ wireless-testing/net/mac80211/main.c	2009-03-31 11:48:51.000000000 +0200
@@ -818,6 +818,7 @@ int ieee80211_register_hw(struct ieee802
 	struct net_device *mdev;
 	struct ieee80211_master_priv *mpriv;
 	int channels, i, j, max_bitrates;
+	bool supp_ht;
 
 	/*
 	 * generic code guarantees at least one band,
@@ -826,6 +827,7 @@ int ieee80211_register_hw(struct ieee802
 	 */
 	channels = 0;
 	max_bitrates = 0;
+	supp_ht = false;
 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 		struct ieee80211_supported_band *sband;
 
@@ -842,6 +844,7 @@ int ieee80211_register_hw(struct ieee802
 
 		if (max_bitrates < sband->n_bitrates)
 			max_bitrates = sband->n_bitrates;
+		supp_ht = supp_ht || sband->ht_cap.ht_supported;
 	}
 
 	local->int_scan_req.n_channels = channels;
@@ -868,6 +871,8 @@ int ieee80211_register_hw(struct ieee802
 	 * information -- SSID is the driver's responsibility.
 	 */
 	local->scan_ies_len = 4 + max_bitrates; /* (ext) supp rates */
+	if (supp_ht)
+		local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap);
 
 	if (!local->ops->hw_scan) {
 		/* For hw_scan, driver needs to set these up. */

-- 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 2/3] mac80211: pass all probe request IEs to driver
  2009-03-31 10:12 ` [PATCH v3 2/3] mac80211: pass all probe request IEs to driver Johannes Berg
@ 2009-04-01  9:58   ` Johannes Berg
  0 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2009-04-01  9:58 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless, j

Instead of just passing the cfg80211-requested IEs, pass
the locally generated ones as well.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
v2: * assume wiphy->max_scan_ie_len contains the limit *including*
      the IEs mac80211 passes (since the driver cannot know how long
      those will be) and adjust the driver's limit accordingly
    * keep track of original IEs and hand back the pristine cfg80211
      request structure
    * mark the IE pointer const in the request struct
v3: * move code to correct place (register_hw)
    * calculate upper limit for userspace scan IEs more accurately
v4: * apply w/o op dbg patch

 include/net/cfg80211.h     |    2 -
 include/net/mac80211.h     |   13 ++++---
 net/mac80211/ieee80211_i.h |    9 +++--
 net/mac80211/main.c        |   49 +++++++++++++++++++--------
 net/mac80211/scan.c        |   24 +++++++++++++
 net/mac80211/util.c        |   79 +++++++++++++++++++++++++++------------------
 net/wireless/nl80211.c     |    3 +
 7 files changed, 123 insertions(+), 56 deletions(-)

--- wireless-testing.orig/include/net/mac80211.h	2009-04-01 11:55:50.000000000 +0200
+++ wireless-testing/include/net/mac80211.h	2009-04-01 11:56:47.000000000 +0200
@@ -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.
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-04-01 11:55:49.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-04-01 11:56:47.000000000 +0200
@@ -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;
@@ -1093,9 +1096,11 @@ void ieee80211_send_auth(struct ieee8021
 			 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,
--- wireless-testing.orig/net/mac80211/util.c	2009-04-01 11:56:02.000000000 +0200
+++ wireless-testing/net/mac80211/util.c	2009-04-01 11:56:47.000000000 +0200
@@ -831,16 +831,57 @@ void ieee80211_send_auth(struct ieee8021
 	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 iee
 	*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);
 }
--- wireless-testing.orig/net/mac80211/main.c	2009-04-01 11:56:02.000000000 +0200
+++ wireless-testing/net/mac80211/main.c	2009-04-01 11:56:47.000000000 +0200
@@ -729,22 +729,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 
 	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 ieee802
 	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 ieee802
 	 * 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 ieee802
 	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;
--- wireless-testing.orig/net/mac80211/scan.c	2009-04-01 11:55:51.000000000 +0200
+++ wireless-testing/net/mac80211/scan.c	2009-04-01 11:56:47.000000000 +0200
@@ -285,6 +285,12 @@ void ieee80211_scan_completed(struct iee
 	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 ieee8021
 	}
 
 	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;
--- wireless-testing.orig/include/net/cfg80211.h	2009-04-01 11:55:50.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h	2009-04-01 11:56:47.000000000 +0200
@@ -504,7 +504,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 */
--- wireless-testing.orig/net/wireless/nl80211.c	2009-04-01 11:56:02.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-04-01 11:56:47.000000000 +0200
@@ -2561,7 +2561,8 @@ static int nl80211_trigger_scan(struct s
 
 	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);
 	}
 



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2009-04-01  9:59 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-31 10:12 [PATCH v3 0/3] mac80211/cfg80211 scan improvements Johannes Berg
2009-03-31 10:12 ` [PATCH v3 1/3] cfg80211: introduce scan IE limit attribute Johannes Berg
2009-03-31 10:12 ` [PATCH v3 2/3] mac80211: pass all probe request IEs to driver Johannes Berg
2009-04-01  9:58   ` [PATCH v4 " Johannes Berg
2009-03-31 10:12 ` [PATCH v3 3/3] mac80211: include HT capabilities in probe request Johannes Berg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).