All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.