linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC v2 0/5] orinoco: use cfg80211 for key manipulation
@ 2009-08-19  0:04 David Kilroy
  2009-08-19  0:04 ` [RFC 1/5] orinoco: add cfg80211 connect and disconnect David Kilroy
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: David Kilroy @ 2009-08-19  0:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, David Kilroy

This series basically works (at least after the last patch is applied)
with wpa_supplicant in wext mode.

I had tested with wpa_supplicant in nl80211 mode, but hadn't realised
it wasn't using connect - I'll need to pick up Zhu Yis' patch and redo
some testing.

Anyway, the nl80211 interface has a small hole which patch 5 partially
papers over. I'm not that happy with the way it hijacks the AUTH/ASSOC
state machine, but it works.

Other outstanding issues:
 - It looks like I haven't quite got the connect_roamed callback right:
   I've got a WARNING I need to investigate in my logs
 - On disconnecting and reconnecting the card I have to restart
   wpa_supplicant for things to work. I'm guessing I have to look at
   driver shutdown, and ensure we send a disconnected event.

Dave.

---
David Kilroy (5):
  orinoco: add cfg80211 connect and disconnect
  orinoco: add cfg80211 join_ibss and leave_ibss
  orinoco: implement cfg80211 key manipulation functions
  orinoco: do WE via cfg80211
  cfg80211: scan before connect if we don't have the bss

 drivers/net/wireless/orinoco/cfg.c     |  497 ++++++++++++++++++++++
 drivers/net/wireless/orinoco/main.c    |  172 +++++----
 drivers/net/wireless/orinoco/orinoco.h |    1 +
 drivers/net/wireless/orinoco/wext.c    |  726 +-------------------------------
 net/wireless/sme.c                     |  150 +++++--
 5 files changed, 717 insertions(+), 829 deletions(-)


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

* [RFC 1/5] orinoco: add cfg80211 connect and disconnect
  2009-08-19  0:04 [RFC v2 0/5] orinoco: use cfg80211 for key manipulation David Kilroy
@ 2009-08-19  0:04 ` David Kilroy
  2009-08-19  0:04 ` [RFC 2/5] orinoco: add cfg80211 join_ibss and leave_ibss David Kilroy
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: David Kilroy @ 2009-08-19  0:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, David Kilroy

Basic station mode support.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/cfg.c     |  244 ++++++++++++++++++++++++++++++++
 drivers/net/wireless/orinoco/main.c    |  164 ++++++++++++----------
 drivers/net/wireless/orinoco/orinoco.h |    1 +
 3 files changed, 333 insertions(+), 76 deletions(-)

diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 27f2d33..09b38e9 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -196,8 +196,252 @@ static int orinoco_set_channel(struct wiphy *wiphy,
 	return err;
 }
 
+/* Helper to ensure all keys are valid for the current encoding
+   algorithm */
+static void orinoco_set_encoding(struct orinoco_private *priv,
+				 enum orinoco_alg encoding)
+{
+	if (priv->encode_alg &&
+	    priv->encode_alg != encoding) {
+		int i;
+
+		for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
+			kfree(priv->keys[i].key);
+			kfree(priv->keys[i].seq);
+			priv->keys[i].key = NULL;
+			priv->keys[i].seq = NULL;
+			priv->keys[i].key_len = 0;
+			priv->keys[i].seq_len = 0;
+			priv->keys[i].cipher = 0;
+		}
+
+		if (priv->encode_alg == ORINOCO_ALG_TKIP &&
+		    priv->has_wpa) {
+			(void) orinoco_clear_tkip_key(priv, i);
+			(void) orinoco_clear_tkip_key(priv, i);
+			(void) orinoco_clear_tkip_key(priv, i);
+			(void) orinoco_clear_tkip_key(priv, i);
+		} else if (priv->encode_alg == ORINOCO_ALG_WEP)
+			__orinoco_hw_setup_wepkeys(priv);
+	}
+	priv->encode_alg = encoding;
+}
+
+/* Helper routine to record keys
+ * Do not call from interrupt context */
+static int orinoco_set_key(struct orinoco_private *priv, int index,
+			   enum orinoco_alg alg, const u8 *key, int key_len,
+			   const u8 *seq, int seq_len)
+{
+	kzfree(priv->keys[index].key);
+	kzfree(priv->keys[index].seq);
+
+	if (key_len) {
+		priv->keys[index].key = kzalloc(key_len, GFP_KERNEL);
+		if (!priv->keys[index].key)
+			goto nomem;
+	} else
+		priv->keys[index].key = NULL;
+
+	if (seq_len) {
+		priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL);
+		if (!priv->keys[index].seq)
+			goto free_key;
+	} else
+		priv->keys[index].seq = NULL;
+
+	priv->keys[index].key_len = key_len;
+	priv->keys[index].seq_len = seq_len;
+
+	if (key_len)
+		memcpy(priv->keys[index].key, key, key_len);
+	if (seq_len)
+		memcpy(priv->keys[index].seq, seq, seq_len);
+
+
+	switch (alg) {
+	case ORINOCO_ALG_TKIP:
+		priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
+		break;
+
+	case ORINOCO_ALG_WEP:
+		priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
+			WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
+		break;
+
+	case ORINOCO_ALG_NONE:
+	default:
+		priv->keys[index].cipher = 0;
+		break;
+	}
+
+	return 0;
+
+free_key:
+	kfree(priv->keys[index].key);
+	priv->keys[index].key = NULL;
+
+nomem:
+	priv->keys[index].key_len = 0;
+	priv->keys[index].seq_len = 0;
+	priv->keys[index].cipher = 0;
+
+	return -ENOMEM;
+}
+
+/* Setup channel, SSID and BSSID */
+static int __orinoco_connect(struct wiphy *wiphy,
+			     struct ieee80211_channel *channel,
+			     const u8 *bssid, const u8 *ssid,
+			     u8 ssid_len)
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+
+	if (channel) {
+		int chan;
+
+		chan = ieee80211_freq_to_dsss_chan(channel->center_freq);
+
+		if ((chan > 0) && (chan < NUM_CHANNELS) &&
+		    (priv->channel_mask & (1 << chan)))
+			priv->channel = chan;
+	}
+
+	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+	if (ssid)
+		memcpy(priv->desired_essid, ssid, ssid_len);
+
+	if (bssid) {
+		/* Intersil firmware hangs if you try to roam manually
+		 * without an SSID set. We should always get one in
+		 * this call, but just check.
+		 */
+		BUG_ON(ssid_len == 0);
+
+		memcpy(priv->desired_bssid, bssid, ETH_ALEN);
+		priv->bssid_fixed = 1;
+	} else {
+		memset(priv->desired_bssid, 0, ETH_ALEN);
+		priv->bssid_fixed = 0;
+	}
+
+	return 0;
+}
+
+static int orinoco_connect(struct wiphy *wiphy, struct net_device *dev,
+			   struct cfg80211_connect_params *sme)
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+	enum orinoco_alg encode_alg;
+	unsigned long lock;
+	int err;
+
+	if (orinoco_lock(priv, &lock) != 0)
+		return -EBUSY;
+
+	/* Setup the requested parameters in priv. If the card is not
+	 * capable, then the driver will just ignore the settings that
+	 * it can't do. */
+	err = __orinoco_connect(wiphy, sme->channel, sme->bssid,
+				sme->ssid, sme->ssid_len);
+	if (err)
+		goto out;
+
+	switch (sme->auth_type) {
+	case NL80211_AUTHTYPE_OPEN_SYSTEM:
+		priv->wep_restrict = 0;
+		break;
+	case NL80211_AUTHTYPE_SHARED_KEY:
+		priv->wep_restrict = 1;
+		break;
+	default:
+		/* Can't handle anything else */
+		err = -EINVAL;
+		goto out;
+	}
+
+	switch (sme->crypto.cipher_group) {
+	case WLAN_CIPHER_SUITE_TKIP:
+		encode_alg = ORINOCO_ALG_TKIP;
+		priv->wpa_enabled = 1;
+		break;
+
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		encode_alg = ORINOCO_ALG_WEP;
+		priv->wpa_enabled = 0;
+		break;
+
+	default:
+		encode_alg = ORINOCO_ALG_NONE;
+		priv->wpa_enabled = 0;
+	}
+
+	orinoco_set_encoding(priv, encode_alg);
+
+	/* What are we supposed to do with multiple AKM suites? */
+	if (sme->crypto.n_akm_suites > 0)
+		priv->key_mgmt = sme->crypto.akm_suites[0] & 7;
+
+	/* Finally, set WEP key */
+	if (encode_alg == ORINOCO_ALG_WEP) {
+		err = orinoco_set_key(priv, sme->key_idx, encode_alg,
+				      &sme->key[0], sme->key_len, NULL, 0);
+		if (err)
+			goto out;
+
+		priv->tx_key = sme->key_idx;
+	}
+
+	/* Enable cfg80211 notification */
+	priv->connect_commanded = 1;
+
+	err = orinoco_commit(priv);
+
+out:
+	orinoco_unlock(priv, &lock);
+
+	return err;
+}
+
+static int orinoco_disconnect(struct wiphy *wiphy, struct net_device *dev,
+			      u16 reason_code)
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+	unsigned long lock;
+	u8 addr[ETH_ALEN];
+	int err;
+
+	if (orinoco_lock(priv, &lock) != 0)
+		return -EBUSY;
+
+	memset(priv->desired_bssid, 0, ETH_ALEN);
+	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+	err = orinoco_hw_get_current_bssid(priv, &addr[0]);
+
+	if (!err) {
+		err = orinoco_hw_disassociate(priv, &addr[0],
+					      reason_code);
+	}
+
+	priv->wpa_enabled = 0;
+
+	/* Disable cfg80211 notification */
+	priv->connect_commanded = 0;
+
+	if (err)
+		err = orinoco_commit(priv);
+
+	orinoco_unlock(priv, &lock);
+
+	return err;
+}
+
 const struct cfg80211_ops orinoco_cfg_ops = {
 	.change_virtual_intf = orinoco_change_vif,
 	.set_channel = orinoco_set_channel,
 	.scan = orinoco_scan,
+	.connect = orinoco_connect,
+	.disconnect = orinoco_disconnect,
 };
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 2c7dc65..5542173 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -1188,98 +1188,109 @@ static void orinoco_join_ap(struct work_struct *work)
 	kfree(buf);
 }
 
-/* Send new BSSID to userspace */
-static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
-{
-	struct net_device *dev = priv->ndev;
-	struct hermes *hw = &priv->hw;
-	union iwreq_data wrqu;
-	int err;
-
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
-	if (err != 0)
-		return;
-
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
-	/* Send event to user space */
-	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
+static void orinoco_send_wevents(struct work_struct *work)
 {
-	struct net_device *dev = priv->ndev;
-	struct hermes *hw = &priv->hw;
-	union iwreq_data wrqu;
+	struct orinoco_private *priv =
+		container_of(work, struct orinoco_private, wevent_work);
+	hermes_t *hw = &priv->hw;
+	unsigned long flags;
+	u8 req_buf[88];
+	u8 resp_buf[88];
+	u8 bssid[ETH_ALEN];
+	size_t req_len = 0;
+	size_t resp_len = 0;
+	u8 *req_ie = NULL;
+	u8 *resp_ie = NULL;
+	enum nl80211_iftype  iw_mode;
+	u16 linkstatus;
 	int err;
-	u8 buf[88];
-	u8 *ie;
 
-	if (!priv->has_wpa)
+	if (orinoco_lock(priv, &flags) != 0)
 		return;
 
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
-			      sizeof(buf), NULL, &buf);
-	if (err != 0)
-		return;
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+			      ETH_ALEN, NULL, &bssid[0]);
+	if (err)
+		goto out;
 
-	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
-	if (ie) {
-		int rem = sizeof(buf) - (ie - &buf[0]);
-		wrqu.data.length = ie[1] + 2;
-		if (wrqu.data.length > rem)
-			wrqu.data.length = rem;
+	if (priv->has_wpa) {
+		err = hermes_read_ltv(hw, USER_BAP,
+				      HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+				      sizeof(req_buf), NULL, &req_buf);
+		if (!err) {
+			req_ie = orinoco_get_wpa_ie(req_buf,
+						    sizeof(req_buf));
+			if (req_ie) {
+				int rem = sizeof(req_buf) -
+					(req_ie - &req_buf[0]);
+				req_len = req_ie[1] + 2;
+				if (req_len > rem)
+					req_len = rem;
+			}
+		}
 
-		if (wrqu.data.length)
-			/* Send event to user space */
-			wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
+		err = hermes_read_ltv(hw, USER_BAP,
+				      HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+				      sizeof(resp_buf), NULL, &resp_buf);
+		if (!err) {
+			resp_ie = orinoco_get_wpa_ie(resp_buf,
+						     sizeof(resp_buf));
+			if (resp_ie) {
+				int rem = sizeof(resp_buf) -
+					(resp_ie - &resp_buf[0]);
+				resp_len = resp_ie[1] + 2;
+				if (resp_len > rem)
+					resp_len = rem;
+			}
+		}
 	}
-}
-
-static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
-{
-	struct net_device *dev = priv->ndev;
-	struct hermes *hw = &priv->hw;
-	union iwreq_data wrqu;
-	int err;
-	u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
-	u8 *ie;
 
-	if (!priv->has_wpa)
-		return;
+	iw_mode = priv->iw_mode;
+	linkstatus = priv->last_linkstatus;
 
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
-			      sizeof(buf), NULL, &buf);
-	if (err != 0)
-		return;
+	if (!priv->connect_commanded)
+		goto out;
 
-	ie = orinoco_get_wpa_ie(buf, sizeof(buf));
-	if (ie) {
-		int rem = sizeof(buf) - (ie - &buf[0]);
-		wrqu.data.length = ie[1] + 2;
-		if (wrqu.data.length > rem)
-			wrqu.data.length = rem;
+	orinoco_unlock(priv, &flags);
 
-		if (wrqu.data.length)
-			/* Send event to user space */
-			wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
-	}
-}
+	switch (iw_mode) {
+	case NL80211_IFTYPE_STATION:
 
-static void orinoco_send_wevents(struct work_struct *work)
-{
-	struct orinoco_private *priv =
-		container_of(work, struct orinoco_private, wevent_work);
-	unsigned long flags;
+		switch (linkstatus) {
+		case HERMES_LINKSTATUS_CONNECTED:
+		case HERMES_LINKSTATUS_AP_IN_RANGE:
+			cfg80211_connect_result(priv->ndev, bssid,
+						req_ie, req_len,
+						resp_ie, resp_len,
+						WLAN_STATUS_SUCCESS,
+						GFP_KERNEL);
+			break;
 
-	if (orinoco_lock(priv, &flags) != 0)
-		return;
+		case HERMES_LINKSTATUS_DISCONNECTED:
+		case HERMES_LINKSTATUS_NOT_CONNECTED:
+		case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
+		case HERMES_LINKSTATUS_AP_CHANGE:
+			cfg80211_roamed(priv->ndev, bssid, req_ie, req_len,
+					resp_ie, resp_len, GFP_KERNEL);
+			break;
 
-	orinoco_send_assocreqie_wevent(priv);
-	orinoco_send_assocrespie_wevent(priv);
-	orinoco_send_bssid_wevent(priv);
+		case HERMES_LINKSTATUS_ASSOC_FAILED:
+			cfg80211_connect_result(priv->ndev, bssid,
+						req_ie, req_len,
+						resp_ie, resp_len,
+						WLAN_STATUS_ASSOC_DENIED_UNSPEC,
+						GFP_KERNEL);
+			break;
+		}
+		break;
+	case NL80211_IFTYPE_ADHOC:
+	case NL80211_IFTYPE_MONITOR:
+	default:
+		break;
+	}
 
+	return;
+ out:
 	orinoco_unlock(priv, &flags);
 }
 
@@ -2050,6 +2061,7 @@ int orinoco_init(struct orinoco_private *priv)
 	set_port_type(priv);
 	priv->channel = 0; /* use firmware default */
 
+	priv->connect_commanded = 0;
 	priv->promiscuous = 0;
 	priv->encode_alg = ORINOCO_ALG_NONE;
 	priv->tx_key = 0;
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 9ac6f1d..57ce581 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -78,6 +78,7 @@ struct orinoco_private {
 
 	/* driver state */
 	int open;
+	int connect_commanded;
 	u16 last_linkstatus;
 	struct work_struct join_work;
 	struct work_struct wevent_work;
-- 
1.6.3.3


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

* [RFC 2/5] orinoco: add cfg80211 join_ibss and leave_ibss
  2009-08-19  0:04 [RFC v2 0/5] orinoco: use cfg80211 for key manipulation David Kilroy
  2009-08-19  0:04 ` [RFC 1/5] orinoco: add cfg80211 connect and disconnect David Kilroy
@ 2009-08-19  0:04 ` David Kilroy
  2009-08-19  0:04 ` [RFC 3/5] orinoco: implement cfg80211 key manipulation functions David Kilroy
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: David Kilroy @ 2009-08-19  0:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, David Kilroy

Basic ad-hoc support.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/cfg.c  |   57 +++++++++++++++++++++++++++++++++++
 drivers/net/wireless/orinoco/main.c |   12 +++++++
 2 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 09b38e9..253cb4e 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -438,10 +438,67 @@ static int orinoco_disconnect(struct wiphy *wiphy, struct net_device *dev,
 	return err;
 }
 
+static int orinoco_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+			     struct cfg80211_ibss_params *params)
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+	unsigned long lock;
+	int err;
+
+	if (orinoco_lock(priv, &lock) != 0)
+		return -EBUSY;
+
+	/* Setup the requested parameters in priv. If the card is not
+	 * capable, then the driver will just ignore the settings that
+	 * it can't do. */
+
+	err = __orinoco_connect(wiphy, params->channel, params->bssid,
+				params->ssid, params->ssid_len);
+	if (err)
+		goto out;
+
+	/* Ignore information elements and beacon interval */
+
+	/* Enable cfg80211 notification */
+	priv->connect_commanded = 1;
+
+	err = orinoco_commit(priv);
+ out:
+	orinoco_unlock(priv, &lock);
+
+	return err;
+}
+
+static int orinoco_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+	unsigned long lock;
+	int err;
+
+	if (orinoco_lock(priv, &lock) != 0)
+		return -EBUSY;
+
+	/* Do we need to disassociate as well? */
+
+	memset(priv->desired_bssid, 0, ETH_ALEN);
+	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+	/* Disable cfg80211 notification */
+	priv->connect_commanded = 0;
+
+	err = orinoco_commit(priv);
+
+	orinoco_unlock(priv, &lock);
+
+	return err;
+}
+
 const struct cfg80211_ops orinoco_cfg_ops = {
 	.change_virtual_intf = orinoco_change_vif,
 	.set_channel = orinoco_set_channel,
 	.scan = orinoco_scan,
 	.connect = orinoco_connect,
 	.disconnect = orinoco_disconnect,
+	.join_ibss = orinoco_join_ibss,
+	.leave_ibss = orinoco_leave_ibss,
 };
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 5542173..78ef22e 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -1283,7 +1283,19 @@ static void orinoco_send_wevents(struct work_struct *work)
 			break;
 		}
 		break;
+
 	case NL80211_IFTYPE_ADHOC:
+		switch (linkstatus) {
+		case HERMES_LINKSTATUS_CONNECTED:
+		case HERMES_LINKSTATUS_AP_IN_RANGE:
+			cfg80211_ibss_joined(priv->ndev, bssid, GFP_KERNEL);
+			break;
+
+		default:
+			break;
+		}
+		break;
+
 	case NL80211_IFTYPE_MONITOR:
 	default:
 		break;
-- 
1.6.3.3


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

* [RFC 3/5] orinoco: implement cfg80211 key manipulation functions
  2009-08-19  0:04 [RFC v2 0/5] orinoco: use cfg80211 for key manipulation David Kilroy
  2009-08-19  0:04 ` [RFC 1/5] orinoco: add cfg80211 connect and disconnect David Kilroy
  2009-08-19  0:04 ` [RFC 2/5] orinoco: add cfg80211 join_ibss and leave_ibss David Kilroy
@ 2009-08-19  0:04 ` David Kilroy
  2009-08-19  0:04 ` [RFC 4/5] orinoco: do WE via cfg80211 David Kilroy
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: David Kilroy @ 2009-08-19  0:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, David Kilroy

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/cfg.c |  196 ++++++++++++++++++++++++++++++++++++
 1 files changed, 196 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index 253cb4e..07775b6 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -493,6 +493,198 @@ static int orinoco_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 	return err;
 }
 
+static int orinoco_add_key(struct wiphy *wiphy, struct net_device *dev,
+			   u8 key_index, const u8 *mac_addr,
+			   struct key_params *params)
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+	int err = 0;
+	unsigned long lock;
+	enum orinoco_alg alg = ORINOCO_ALG_NONE;
+	int key_len;
+
+	if (key_index >= ORINOCO_MAX_KEYS)
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &lock) != 0)
+		return -EBUSY;
+
+	switch (params->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+		alg = ORINOCO_ALG_WEP;
+
+		if (!priv->has_wep)
+			err = -EOPNOTSUPP;
+
+		if (params->key_len > ORINOCO_MAX_KEY_SIZE)
+			err = -E2BIG;
+		else if (params->key_len > SMALL_KEY_SIZE)
+			key_len = LARGE_KEY_SIZE;
+		else if (params->key_len > 0)
+			key_len = SMALL_KEY_SIZE;
+		else
+			err = -EINVAL;
+
+		break;
+
+	case WLAN_CIPHER_SUITE_TKIP:
+		alg = ORINOCO_ALG_TKIP;
+
+		if (!priv->has_wpa)
+			err = -EOPNOTSUPP;
+		else if (params->key_len < WLAN_KEY_LEN_TKIP)
+			err = -EINVAL;
+
+		key_len = WLAN_KEY_LEN_TKIP;
+		break;
+
+	case WLAN_CIPHER_SUITE_CCMP:
+	case WLAN_CIPHER_SUITE_AES_CMAC:
+	default:
+		err = -EOPNOTSUPP;
+	}
+
+	if (err)
+		goto out;
+
+	/* Ensure existing keys are of the same cipher suite */
+	orinoco_set_encoding(priv, alg);
+
+	err = orinoco_set_key(priv, key_index, alg,
+			      params->key, params->key_len,
+			      params->seq, params->seq_len);
+	if (err)
+		goto out;
+
+	if (alg == ORINOCO_ALG_TKIP) {
+		/* If this is a pairwise key, assume it is the transmit key */
+		int set_tx = 0;
+		if (mac_addr) {
+			priv->tx_key = key_index;
+			set_tx = 1;
+		}
+		err = __orinoco_hw_set_tkip_key(priv, key_index, set_tx,
+						priv->keys[key_index].key,
+						priv->keys[key_index].seq,
+						priv->keys[key_index].seq_len,
+						NULL, 0);
+	}
+
+	err = __orinoco_hw_setup_enc(priv);
+
+ out:
+	orinoco_unlock(priv, &lock);
+
+	return err;
+}
+
+static int orinoco_get_key(struct wiphy *wiphy, struct net_device *dev,
+			   u8 key_index, const u8 *mac_addr, void *cookie,
+			   void (*callback)(void *cookie, struct key_params*))
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+	struct key_params params;
+	u8 key[WLAN_KEY_LEN_TKIP];
+	u8 tsc[ORINOCO_SEQ_LEN];
+	unsigned long lock;
+	int err = 0;
+
+	if (key_index >= ORINOCO_MAX_KEYS)
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &lock) != 0)
+		return -EBUSY;
+
+	/* Take a copy of the key info */
+	memcpy(&key, priv->keys[key_index].key, priv->keys[key_index].key_len);
+
+	params.cipher = priv->keys[key_index].cipher;
+	params.key = &key[0];
+	params.key_len = priv->keys[key_index].key_len;
+
+	if (params.cipher == WLAN_CIPHER_SUITE_TKIP) {
+		/* Populate the current TSC */
+		orinoco_hw_get_tkip_iv(priv, key_index, &tsc[0]);
+		params.seq = &tsc[0];
+		params.seq_len = ORINOCO_SEQ_LEN;
+	} else {
+		params.seq = NULL;
+		params.seq_len = 0;
+	}
+
+	orinoco_unlock(priv, &lock);
+
+	callback(cookie, &params);
+
+	return err;
+}
+
+static int orinoco_del_key(struct wiphy *wiphy, struct net_device *dev,
+			   u8 key_index, const u8 *mac_addr)
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+	int err = 0;
+	unsigned long lock;
+
+	if (key_index >= ORINOCO_MAX_KEYS)
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &lock) != 0)
+		return -EBUSY;
+
+	kzfree(priv->keys[key_index].key);
+	kzfree(priv->keys[key_index].seq);
+	priv->keys[key_index].key = NULL;
+	priv->keys[key_index].seq = NULL;
+	priv->keys[key_index].key_len = 0;
+	priv->keys[key_index].seq_len = 0;
+	priv->keys[key_index].cipher = 0;
+
+	if (priv->has_wpa &&
+	    priv->keys[key_index].cipher == WLAN_CIPHER_SUITE_TKIP)
+		err = orinoco_clear_tkip_key(priv, key_index);
+
+	err = __orinoco_hw_setup_enc(priv);
+
+	orinoco_unlock(priv, &lock);
+
+	return err;
+}
+
+static int orinoco_set_default_key(struct wiphy *wiphy,
+				   struct net_device *netdev,
+				   u8 key_index)
+{
+	struct orinoco_private *priv = wiphy_priv(wiphy);
+	int err = 0;
+	unsigned long lock;
+
+	if (key_index >= ORINOCO_MAX_KEYS)
+		return -EINVAL;
+
+	if (orinoco_lock(priv, &lock) != 0)
+		return -EBUSY;
+
+	priv->tx_key = key_index;
+
+	if (priv->has_wpa &&
+	    priv->keys[key_index].cipher == WLAN_CIPHER_SUITE_TKIP)
+		err = __orinoco_hw_set_tkip_key(priv, key_index, 1,
+						priv->keys[key_index].key,
+						priv->keys[key_index].seq,
+						priv->keys[key_index].seq_len,
+						NULL, 0);
+	else if (priv->encode_alg == ORINOCO_ALG_WEP)
+		err = __orinoco_hw_setup_wepkeys(priv);
+	else
+		err = -EINVAL;
+
+	orinoco_unlock(priv, &lock);
+
+	return err;
+}
+
 const struct cfg80211_ops orinoco_cfg_ops = {
 	.change_virtual_intf = orinoco_change_vif,
 	.set_channel = orinoco_set_channel,
@@ -501,4 +693,8 @@ const struct cfg80211_ops orinoco_cfg_ops = {
 	.disconnect = orinoco_disconnect,
 	.join_ibss = orinoco_join_ibss,
 	.leave_ibss = orinoco_leave_ibss,
+	.add_key = orinoco_add_key,
+	.get_key = orinoco_get_key,
+	.del_key = orinoco_del_key,
+	.set_default_key = orinoco_set_default_key,
 };
-- 
1.6.3.3


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

* [RFC 4/5] orinoco: do WE via cfg80211
  2009-08-19  0:04 [RFC v2 0/5] orinoco: use cfg80211 for key manipulation David Kilroy
                   ` (2 preceding siblings ...)
  2009-08-19  0:04 ` [RFC 3/5] orinoco: implement cfg80211 key manipulation functions David Kilroy
@ 2009-08-19  0:04 ` David Kilroy
  2009-08-19  0:04 ` [RFC 5/5] cfg80211: scan before connect if we don't have the bss David Kilroy
  2009-08-31 17:59 ` [RFC v2 0/5] orinoco: use cfg80211 for key manipulation John W. Linville
  5 siblings, 0 replies; 16+ messages in thread
From: David Kilroy @ 2009-08-19  0:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, David Kilroy

Now that the driver supports both station and ad-hoc modes in cfg80211,
we can point the WE handlers at the cfg80211 versions.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 drivers/net/wireless/orinoco/wext.c |  726 +----------------------------------
 1 files changed, 11 insertions(+), 715 deletions(-)

diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 7698fdd..264c76f 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -22,67 +22,6 @@
 
 #define MAX_RID_LEN 1024
 
-/* Helper routine to record keys
- * Do not call from interrupt context */
-static int orinoco_set_key(struct orinoco_private *priv, int index,
-			   enum orinoco_alg alg, const u8 *key, int key_len,
-			   const u8 *seq, int seq_len)
-{
-	kzfree(priv->keys[index].key);
-	kzfree(priv->keys[index].seq);
-
-	if (key_len) {
-		priv->keys[index].key = kzalloc(key_len, GFP_KERNEL);
-		if (!priv->keys[index].key)
-			goto nomem;
-	} else
-		priv->keys[index].key = NULL;
-
-	if (seq_len) {
-		priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL);
-		if (!priv->keys[index].seq)
-			goto free_key;
-	} else
-		priv->keys[index].seq = NULL;
-
-	priv->keys[index].key_len = key_len;
-	priv->keys[index].seq_len = seq_len;
-
-	if (key_len)
-		memcpy(priv->keys[index].key, key, key_len);
-	if (seq_len)
-		memcpy(priv->keys[index].seq, seq, seq_len);
-
-	switch (alg) {
-	case ORINOCO_ALG_TKIP:
-		priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
-		break;
-
-	case ORINOCO_ALG_WEP:
-		priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
-			WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
-		break;
-
-	case ORINOCO_ALG_NONE:
-	default:
-		priv->keys[index].cipher = 0;
-		break;
-	}
-
-	return 0;
-
-free_key:
-	kfree(priv->keys[index].key);
-	priv->keys[index].key = NULL;
-
-nomem:
-	priv->keys[index].key_len = 0;
-	priv->keys[index].seq_len = 0;
-	priv->keys[index].cipher = 0;
-
-	return -ENOMEM;
-}
-
 static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
 {
 	struct orinoco_private *priv = ndev_priv(dev);
@@ -149,274 +88,6 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
 /* Wireless extensions                                              */
 /********************************************************************/
 
-static int orinoco_ioctl_setwap(struct net_device *dev,
-				struct iw_request_info *info,
-				struct sockaddr *ap_addr,
-				char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	int err = -EINPROGRESS;		/* Call commit handler */
-	unsigned long flags;
-	static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-	static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	/* Enable automatic roaming - no sanity checks are needed */
-	if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
-	    memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
-		priv->bssid_fixed = 0;
-		memset(priv->desired_bssid, 0, ETH_ALEN);
-
-		/* "off" means keep existing connection */
-		if (ap_addr->sa_data[0] == 0) {
-			__orinoco_hw_set_wap(priv);
-			err = 0;
-		}
-		goto out;
-	}
-
-	if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
-		printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
-		       "support manual roaming\n",
-		       dev->name);
-		err = -EOPNOTSUPP;
-		goto out;
-	}
-
-	if (priv->iw_mode != NL80211_IFTYPE_STATION) {
-		printk(KERN_WARNING "%s: Manual roaming supported only in "
-		       "managed mode\n", dev->name);
-		err = -EOPNOTSUPP;
-		goto out;
-	}
-
-	/* Intersil firmware hangs without Desired ESSID */
-	if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
-	    strlen(priv->desired_essid) == 0) {
-		printk(KERN_WARNING "%s: Desired ESSID must be set for "
-		       "manual roaming\n", dev->name);
-		err = -EOPNOTSUPP;
-		goto out;
-	}
-
-	/* Finally, enable manual roaming */
-	priv->bssid_fixed = 1;
-	memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
-
- out:
-	orinoco_unlock(priv, &flags);
-	return err;
-}
-
-static int orinoco_ioctl_getwap(struct net_device *dev,
-				struct iw_request_info *info,
-				struct sockaddr *ap_addr,
-				char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-
-	int err = 0;
-	unsigned long flags;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	ap_addr->sa_family = ARPHRD_ETHER;
-	err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
-
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_setiwencode(struct net_device *dev,
-				     struct iw_request_info *info,
-				     struct iw_point *erq,
-				     char *keybuf)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
-	int setindex = priv->tx_key;
-	enum orinoco_alg encode_alg = priv->encode_alg;
-	int restricted = priv->wep_restrict;
-	int err = -EINPROGRESS;		/* Call commit handler */
-	unsigned long flags;
-
-	if (!priv->has_wep)
-		return -EOPNOTSUPP;
-
-	if (erq->pointer) {
-		/* We actually have a key to set - check its length */
-		if (erq->length > LARGE_KEY_SIZE)
-			return -E2BIG;
-
-		if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
-			return -E2BIG;
-	}
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	/* Clear any TKIP key we have */
-	if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
-		(void) orinoco_clear_tkip_key(priv, setindex);
-
-	if (erq->length > 0) {
-		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
-			index = priv->tx_key;
-
-		/* Switch on WEP if off */
-		if (encode_alg != ORINOCO_ALG_WEP) {
-			setindex = index;
-			encode_alg = ORINOCO_ALG_WEP;
-		}
-	} else {
-		/* Important note : if the user do "iwconfig eth0 enc off",
-		 * we will arrive there with an index of -1. This is valid
-		 * but need to be taken care off... Jean II */
-		if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
-			if ((index != -1) || (erq->flags == 0)) {
-				err = -EINVAL;
-				goto out;
-			}
-		} else {
-			/* Set the index : Check that the key is valid */
-			if (priv->keys[index].key_len == 0) {
-				err = -EINVAL;
-				goto out;
-			}
-			setindex = index;
-		}
-	}
-
-	if (erq->flags & IW_ENCODE_DISABLED)
-		encode_alg = ORINOCO_ALG_NONE;
-	if (erq->flags & IW_ENCODE_OPEN)
-		restricted = 0;
-	if (erq->flags & IW_ENCODE_RESTRICTED)
-		restricted = 1;
-
-	if (erq->pointer && erq->length > 0) {
-		err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
-				      erq->length, NULL, 0);
-	}
-	priv->tx_key = setindex;
-
-	/* Try fast key change if connected and only keys are changed */
-	if ((priv->encode_alg == encode_alg) &&
-	    (priv->wep_restrict == restricted) &&
-	    netif_carrier_ok(dev)) {
-		err = __orinoco_hw_setup_wepkeys(priv);
-		/* No need to commit if successful */
-		goto out;
-	}
-
-	priv->encode_alg = encode_alg;
-	priv->wep_restrict = restricted;
-
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_getiwencode(struct net_device *dev,
-				     struct iw_request_info *info,
-				     struct iw_point *erq,
-				     char *keybuf)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
-	unsigned long flags;
-
-	if (!priv->has_wep)
-		return -EOPNOTSUPP;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
-		index = priv->tx_key;
-
-	erq->flags = 0;
-	if (!priv->encode_alg)
-		erq->flags |= IW_ENCODE_DISABLED;
-	erq->flags |= index + 1;
-
-	if (priv->wep_restrict)
-		erq->flags |= IW_ENCODE_RESTRICTED;
-	else
-		erq->flags |= IW_ENCODE_OPEN;
-
-	erq->length = priv->keys[index].key_len;
-
-	memcpy(keybuf, priv->keys[index].key, erq->length);
-
-	orinoco_unlock(priv, &flags);
-	return 0;
-}
-
-static int orinoco_ioctl_setessid(struct net_device *dev,
-				  struct iw_request_info *info,
-				  struct iw_point *erq,
-				  char *essidbuf)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	unsigned long flags;
-
-	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
-	 * anyway... - Jean II */
-
-	/* Hum... Should not use Wireless Extension constant (may change),
-	 * should use our own... - Jean II */
-	if (erq->length > IW_ESSID_MAX_SIZE)
-		return -E2BIG;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	/* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
-	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
-
-	/* If not ANY, get the new ESSID */
-	if (erq->flags)
-		memcpy(priv->desired_essid, essidbuf, erq->length);
-
-	orinoco_unlock(priv, &flags);
-
-	return -EINPROGRESS;		/* Call commit handler */
-}
-
-static int orinoco_ioctl_getessid(struct net_device *dev,
-				  struct iw_request_info *info,
-				  struct iw_point *erq,
-				  char *essidbuf)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	int active;
-	int err = 0;
-	unsigned long flags;
-
-	if (netif_running(dev)) {
-		err = orinoco_hw_get_essid(priv, &active, essidbuf);
-		if (err < 0)
-			return err;
-		erq->length = err;
-	} else {
-		if (orinoco_lock(priv, &flags) != 0)
-			return -EBUSY;
-		memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
-		erq->length = strlen(priv->desired_essid);
-		orinoco_unlock(priv, &flags);
-	}
-
-	erq->flags = 1;
-
-	return 0;
-}
-
 static int orinoco_ioctl_setfreq(struct net_device *dev,
 				 struct iw_request_info *info,
 				 struct iw_freq *frq,
@@ -827,379 +498,6 @@ static int orinoco_ioctl_getpower(struct net_device *dev,
 	return err;
 }
 
-static int orinoco_ioctl_set_encodeext(struct net_device *dev,
-				       struct iw_request_info *info,
-				       union iwreq_data *wrqu,
-				       char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	struct iw_point *encoding = &wrqu->encoding;
-	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-	int idx, alg = ext->alg, set_key = 1;
-	unsigned long flags;
-	int err = -EINVAL;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	/* Determine and validate the key index */
-	idx = encoding->flags & IW_ENCODE_INDEX;
-	if (idx) {
-		if ((idx < 1) || (idx > 4))
-			goto out;
-		idx--;
-	} else
-		idx = priv->tx_key;
-
-	if (encoding->flags & IW_ENCODE_DISABLED)
-		alg = IW_ENCODE_ALG_NONE;
-
-	if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
-		/* Clear any TKIP TX key we had */
-		(void) orinoco_clear_tkip_key(priv, priv->tx_key);
-	}
-
-	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
-		priv->tx_key = idx;
-		set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
-			   (ext->key_len > 0)) ? 1 : 0;
-	}
-
-	if (set_key) {
-		/* Set the requested key first */
-		switch (alg) {
-		case IW_ENCODE_ALG_NONE:
-			priv->encode_alg = ORINOCO_ALG_NONE;
-			err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
-					      NULL, 0, NULL, 0);
-			break;
-
-		case IW_ENCODE_ALG_WEP:
-			if (ext->key_len <= 0)
-				goto out;
-
-			priv->encode_alg = ORINOCO_ALG_WEP;
-			err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
-					      ext->key, ext->key_len, NULL, 0);
-			break;
-
-		case IW_ENCODE_ALG_TKIP:
-		{
-			u8 *tkip_iv = NULL;
-
-			if (!priv->has_wpa ||
-			    (ext->key_len > sizeof(struct orinoco_tkip_key)))
-				goto out;
-
-			priv->encode_alg = ORINOCO_ALG_TKIP;
-
-			if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
-				tkip_iv = &ext->rx_seq[0];
-
-			err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
-					      ext->key, ext->key_len, tkip_iv,
-					      ORINOCO_SEQ_LEN);
-
-			err = __orinoco_hw_set_tkip_key(priv, idx,
-				 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
-				 priv->keys[idx].key,
-				 tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
-			if (err)
-				printk(KERN_ERR "%s: Error %d setting TKIP key"
-				       "\n", dev->name, err);
-
-			goto out;
-		}
-		default:
-			goto out;
-		}
-	}
-	err = -EINPROGRESS;
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_get_encodeext(struct net_device *dev,
-				       struct iw_request_info *info,
-				       union iwreq_data *wrqu,
-				       char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	struct iw_point *encoding = &wrqu->encoding;
-	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-	int idx, max_key_len;
-	unsigned long flags;
-	int err;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	err = -EINVAL;
-	max_key_len = encoding->length - sizeof(*ext);
-	if (max_key_len < 0)
-		goto out;
-
-	idx = encoding->flags & IW_ENCODE_INDEX;
-	if (idx) {
-		if ((idx < 1) || (idx > 4))
-			goto out;
-		idx--;
-	} else
-		idx = priv->tx_key;
-
-	encoding->flags = idx + 1;
-	memset(ext, 0, sizeof(*ext));
-
-	switch (priv->encode_alg) {
-	case ORINOCO_ALG_NONE:
-		ext->alg = IW_ENCODE_ALG_NONE;
-		ext->key_len = 0;
-		encoding->flags |= IW_ENCODE_DISABLED;
-		break;
-	case ORINOCO_ALG_WEP:
-		ext->alg = IW_ENCODE_ALG_WEP;
-		ext->key_len = min(priv->keys[idx].key_len, max_key_len);
-		memcpy(ext->key, priv->keys[idx].key, ext->key_len);
-		encoding->flags |= IW_ENCODE_ENABLED;
-		break;
-	case ORINOCO_ALG_TKIP:
-		ext->alg = IW_ENCODE_ALG_TKIP;
-		ext->key_len = min(priv->keys[idx].key_len, max_key_len);
-		memcpy(ext->key, priv->keys[idx].key, ext->key_len);
-		encoding->flags |= IW_ENCODE_ENABLED;
-		break;
-	}
-
-	err = 0;
- out:
-	orinoco_unlock(priv, &flags);
-
-	return err;
-}
-
-static int orinoco_ioctl_set_auth(struct net_device *dev,
-				  struct iw_request_info *info,
-				  union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	hermes_t *hw = &priv->hw;
-	struct iw_param *param = &wrqu->param;
-	unsigned long flags;
-	int ret = -EINPROGRESS;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	switch (param->flags & IW_AUTH_INDEX) {
-	case IW_AUTH_WPA_VERSION:
-	case IW_AUTH_CIPHER_PAIRWISE:
-	case IW_AUTH_CIPHER_GROUP:
-	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-	case IW_AUTH_PRIVACY_INVOKED:
-	case IW_AUTH_DROP_UNENCRYPTED:
-		/*
-		 * orinoco does not use these parameters
-		 */
-		break;
-
-	case IW_AUTH_KEY_MGMT:
-		/* wl_lkm implies value 2 == PSK for Hermes I
-		 * which ties in with WEXT
-		 * no other hints tho :(
-		 */
-		priv->key_mgmt = param->value;
-		break;
-
-	case IW_AUTH_TKIP_COUNTERMEASURES:
-		/* When countermeasures are enabled, shut down the
-		 * card; when disabled, re-enable the card. This must
-		 * take effect immediately.
-		 *
-		 * TODO: Make sure that the EAPOL message is getting
-		 *       out before card disabled
-		 */
-		if (param->value) {
-			priv->tkip_cm_active = 1;
-			ret = hermes_enable_port(hw, 0);
-		} else {
-			priv->tkip_cm_active = 0;
-			ret = hermes_disable_port(hw, 0);
-		}
-		break;
-
-	case IW_AUTH_80211_AUTH_ALG:
-		if (param->value & IW_AUTH_ALG_SHARED_KEY)
-			priv->wep_restrict = 1;
-		else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
-			priv->wep_restrict = 0;
-		else
-			ret = -EINVAL;
-		break;
-
-	case IW_AUTH_WPA_ENABLED:
-		if (priv->has_wpa) {
-			priv->wpa_enabled = param->value ? 1 : 0;
-		} else {
-			if (param->value)
-				ret = -EOPNOTSUPP;
-			/* else silently accept disable of WPA */
-			priv->wpa_enabled = 0;
-		}
-		break;
-
-	default:
-		ret = -EOPNOTSUPP;
-	}
-
-	orinoco_unlock(priv, &flags);
-	return ret;
-}
-
-static int orinoco_ioctl_get_auth(struct net_device *dev,
-				  struct iw_request_info *info,
-				  union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	struct iw_param *param = &wrqu->param;
-	unsigned long flags;
-	int ret = 0;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	switch (param->flags & IW_AUTH_INDEX) {
-	case IW_AUTH_KEY_MGMT:
-		param->value = priv->key_mgmt;
-		break;
-
-	case IW_AUTH_TKIP_COUNTERMEASURES:
-		param->value = priv->tkip_cm_active;
-		break;
-
-	case IW_AUTH_80211_AUTH_ALG:
-		if (priv->wep_restrict)
-			param->value = IW_AUTH_ALG_SHARED_KEY;
-		else
-			param->value = IW_AUTH_ALG_OPEN_SYSTEM;
-		break;
-
-	case IW_AUTH_WPA_ENABLED:
-		param->value = priv->wpa_enabled;
-		break;
-
-	default:
-		ret = -EOPNOTSUPP;
-	}
-
-	orinoco_unlock(priv, &flags);
-	return ret;
-}
-
-static int orinoco_ioctl_set_genie(struct net_device *dev,
-				   struct iw_request_info *info,
-				   union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	u8 *buf;
-	unsigned long flags;
-
-	/* cut off at IEEE80211_MAX_DATA_LEN */
-	if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
-	    (wrqu->data.length && (extra == NULL)))
-		return -EINVAL;
-
-	if (wrqu->data.length) {
-		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
-		if (buf == NULL)
-			return -ENOMEM;
-
-		memcpy(buf, extra, wrqu->data.length);
-	} else
-		buf = NULL;
-
-	if (orinoco_lock(priv, &flags) != 0) {
-		kfree(buf);
-		return -EBUSY;
-	}
-
-	kfree(priv->wpa_ie);
-	priv->wpa_ie = buf;
-	priv->wpa_ie_len = wrqu->data.length;
-
-	if (priv->wpa_ie) {
-		/* Looks like wl_lkm wants to check the auth alg, and
-		 * somehow pass it to the firmware.
-		 * Instead it just calls the key mgmt rid
-		 *   - we do this in set auth.
-		 */
-	}
-
-	orinoco_unlock(priv, &flags);
-	return 0;
-}
-
-static int orinoco_ioctl_get_genie(struct net_device *dev,
-				   struct iw_request_info *info,
-				   union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	unsigned long flags;
-	int err = 0;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
-		wrqu->data.length = 0;
-		goto out;
-	}
-
-	if (wrqu->data.length < priv->wpa_ie_len) {
-		err = -E2BIG;
-		goto out;
-	}
-
-	wrqu->data.length = priv->wpa_ie_len;
-	memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
-
-out:
-	orinoco_unlock(priv, &flags);
-	return err;
-}
-
-static int orinoco_ioctl_set_mlme(struct net_device *dev,
-				  struct iw_request_info *info,
-				  union iwreq_data *wrqu, char *extra)
-{
-	struct orinoco_private *priv = ndev_priv(dev);
-	struct iw_mlme *mlme = (struct iw_mlme *)extra;
-	unsigned long flags;
-	int ret = 0;
-
-	if (orinoco_lock(priv, &flags) != 0)
-		return -EBUSY;
-
-	switch (mlme->cmd) {
-	case IW_MLME_DEAUTH:
-		/* silently ignore */
-		break;
-
-	case IW_MLME_DISASSOC:
-
-		ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
-					      mlme->reason_code);
-		break;
-
-	default:
-		ret = -EOPNOTSUPP;
-	}
-
-	orinoco_unlock(priv, &flags);
-	return ret;
-}
-
 static int orinoco_ioctl_getretry(struct net_device *dev,
 				  struct iw_request_info *info,
 				  struct iw_param *rrq,
@@ -1521,12 +819,12 @@ static const iw_handler	orinoco_handler[] = {
 	STD_IW_HANDLER(SIOCGIWSPY,	iw_handler_get_spy),
 	STD_IW_HANDLER(SIOCSIWTHRSPY,	iw_handler_set_thrspy),
 	STD_IW_HANDLER(SIOCGIWTHRSPY,	iw_handler_get_thrspy),
-	STD_IW_HANDLER(SIOCSIWAP,	orinoco_ioctl_setwap),
-	STD_IW_HANDLER(SIOCGIWAP,	orinoco_ioctl_getwap),
+	STD_IW_HANDLER(SIOCSIWAP,	cfg80211_wext_siwap),
+	STD_IW_HANDLER(SIOCGIWAP,	cfg80211_wext_giwap),
 	STD_IW_HANDLER(SIOCSIWSCAN,	cfg80211_wext_siwscan),
 	STD_IW_HANDLER(SIOCGIWSCAN,	cfg80211_wext_giwscan),
-	STD_IW_HANDLER(SIOCSIWESSID,	orinoco_ioctl_setessid),
-	STD_IW_HANDLER(SIOCGIWESSID,	orinoco_ioctl_getessid),
+	STD_IW_HANDLER(SIOCSIWESSID,	cfg80211_wext_siwessid),
+	STD_IW_HANDLER(SIOCGIWESSID,	cfg80211_wext_giwessid),
 	STD_IW_HANDLER(SIOCSIWRATE,	orinoco_ioctl_setrate),
 	STD_IW_HANDLER(SIOCGIWRATE,	orinoco_ioctl_getrate),
 	STD_IW_HANDLER(SIOCSIWRTS,	orinoco_ioctl_setrts),
@@ -1534,17 +832,15 @@ static const iw_handler	orinoco_handler[] = {
 	STD_IW_HANDLER(SIOCSIWFRAG,	orinoco_ioctl_setfrag),
 	STD_IW_HANDLER(SIOCGIWFRAG,	orinoco_ioctl_getfrag),
 	STD_IW_HANDLER(SIOCGIWRETRY,	orinoco_ioctl_getretry),
-	STD_IW_HANDLER(SIOCSIWENCODE,	orinoco_ioctl_setiwencode),
-	STD_IW_HANDLER(SIOCGIWENCODE,	orinoco_ioctl_getiwencode),
+	STD_IW_HANDLER(SIOCSIWENCODE,	cfg80211_wext_siwencode),
+	STD_IW_HANDLER(SIOCGIWENCODE,	cfg80211_wext_giwencode),
 	STD_IW_HANDLER(SIOCSIWPOWER,	orinoco_ioctl_setpower),
 	STD_IW_HANDLER(SIOCGIWPOWER,	orinoco_ioctl_getpower),
-	STD_IW_HANDLER(SIOCSIWGENIE,	orinoco_ioctl_set_genie),
-	STD_IW_HANDLER(SIOCGIWGENIE,	orinoco_ioctl_get_genie),
-	STD_IW_HANDLER(SIOCSIWMLME,	orinoco_ioctl_set_mlme),
-	STD_IW_HANDLER(SIOCSIWAUTH,	orinoco_ioctl_set_auth),
-	STD_IW_HANDLER(SIOCGIWAUTH,	orinoco_ioctl_get_auth),
-	STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
-	STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
+	STD_IW_HANDLER(SIOCSIWGENIE,	cfg80211_wext_siwgenie),
+	STD_IW_HANDLER(SIOCSIWMLME,	cfg80211_wext_siwmlme),
+	STD_IW_HANDLER(SIOCSIWAUTH,	cfg80211_wext_siwauth),
+	STD_IW_HANDLER(SIOCGIWAUTH,	cfg80211_wext_giwauth),
+	STD_IW_HANDLER(SIOCSIWENCODEEXT, cfg80211_wext_siwencodeext),
 };
 
 
-- 
1.6.3.3


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

* [RFC 5/5] cfg80211: scan before connect if we don't have the bss
  2009-08-19  0:04 [RFC v2 0/5] orinoco: use cfg80211 for key manipulation David Kilroy
                   ` (3 preceding siblings ...)
  2009-08-19  0:04 ` [RFC 4/5] orinoco: do WE via cfg80211 David Kilroy
@ 2009-08-19  0:04 ` David Kilroy
  2009-08-19  7:48   ` Johannes Berg
  2009-08-31 17:59 ` [RFC v2 0/5] orinoco: use cfg80211 for key manipulation John W. Linville
  5 siblings, 1 reply; 16+ messages in thread
From: David Kilroy @ 2009-08-19  0:04 UTC (permalink / raw)
  To: linux-wireless; +Cc: orinoco-devel, David Kilroy

The connect_result callback relies on cfg80211 having the bss
information (via beacons/probes). For a fullmac driver, this information
is only likely to be present after a scan. Userspace is not guaranteed
to scan before connecting (e.g. wpa_supplicant ap_scan=2 in wext mode),
so before calling ->connect do an explicit ->scan if we don't have the
bss in our list.

Signed-off-by: David Kilroy <kilroyd@googlemail.com>
---
 net/wireless/sme.c |  150 ++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 110 insertions(+), 40 deletions(-)

diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 9ddc00e..6dc7981 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -26,11 +26,13 @@ struct cfg80211_conn {
 		CFG80211_CONN_AUTHENTICATING,
 		CFG80211_CONN_ASSOCIATE_NEXT,
 		CFG80211_CONN_ASSOCIATING,
+		CFG80211_CONN_DELAYED_CONNECT,
 	} state;
 	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
 	u8 *ie;
 	size_t ie_len;
 	bool auto_auth, prev_bssid_valid;
+	bool connect_after_scan;
 };
 
 
@@ -148,6 +150,19 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
 					       NULL, 0,
 					       WLAN_REASON_DEAUTH_LEAVING);
 		return err;
+	case CFG80211_CONN_DELAYED_CONNECT:
+		BUG_ON(!rdev->ops->connect);
+		err = rdev->ops->connect(&rdev->wiphy, wdev->netdev,
+					 &wdev->conn->params);
+		kfree(wdev->conn->ie);
+		kfree(wdev->conn);
+		wdev->conn = NULL;
+		if (err) {
+			wdev->connect_keys = NULL;
+			wdev->sme_state = CFG80211_SME_IDLE;
+			wdev->ssid_len = 0;
+		}
+		return err;
 	default:
 		return 0;
 	}
@@ -234,6 +249,12 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
 	    wdev->conn->state != CFG80211_CONN_SCAN_AGAIN)
 		return;
 
+	if (wdev->conn->connect_after_scan) {
+		wdev->conn->state = CFG80211_CONN_DELAYED_CONNECT;
+		schedule_work(&rdev->conn_work);
+		return;
+	}
+
 	if (!cfg80211_get_conn_bss(wdev)) {
 		/* not found */
 		if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
@@ -655,6 +676,52 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
 }
 EXPORT_SYMBOL(cfg80211_disconnected);
 
+static int cfg80211_conn_clone(struct wireless_dev *wdev,
+			       struct cfg80211_connect_params *connect)
+{
+	if (WARN_ON(wdev->conn))
+		return -EINPROGRESS;
+
+	wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
+	if (!wdev->conn)
+		return -ENOMEM;
+
+	memcpy(&wdev->conn->params, connect, sizeof(*connect));
+	if (connect->bssid) {
+		wdev->conn->params.bssid = wdev->conn->bssid;
+		memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
+	}
+
+	if (connect->ie) {
+		wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
+					 GFP_KERNEL);
+		wdev->conn->params.ie = wdev->conn->ie;
+		if (!wdev->conn->ie) {
+			kfree(wdev->conn);
+			wdev->conn = NULL;
+			return -ENOMEM;
+		}
+	}
+
+	if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
+		wdev->conn->auto_auth = true;
+		/* start with open system ... should mostly work */
+		wdev->conn->params.auth_type =
+			NL80211_AUTHTYPE_OPEN_SYSTEM;
+	} else {
+		wdev->conn->auto_auth = false;
+	}
+
+	memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
+	wdev->ssid_len = connect->ssid_len;
+	wdev->conn->params.ssid = wdev->ssid;
+	wdev->conn->params.ssid_len = connect->ssid_len;
+
+	wdev->conn->connect_after_scan = false;
+
+	return 0;
+}
+
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
 		       struct cfg80211_connect_params *connect,
@@ -710,46 +777,12 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 		if (!rdev->ops->auth || !rdev->ops->assoc)
 			return -EOPNOTSUPP;
 
-		if (WARN_ON(wdev->conn))
-			return -EINPROGRESS;
-
-		wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
-		if (!wdev->conn)
-			return -ENOMEM;
-
 		/*
 		 * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
 		 */
-		memcpy(&wdev->conn->params, connect, sizeof(*connect));
-		if (connect->bssid) {
-			wdev->conn->params.bssid = wdev->conn->bssid;
-			memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
-		}
-
-		if (connect->ie) {
-			wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
-						GFP_KERNEL);
-			wdev->conn->params.ie = wdev->conn->ie;
-			if (!wdev->conn->ie) {
-				kfree(wdev->conn);
-				wdev->conn = NULL;
-				return -ENOMEM;
-			}
-		}
-
-		if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
-			wdev->conn->auto_auth = true;
-			/* start with open system ... should mostly work */
-			wdev->conn->params.auth_type =
-				NL80211_AUTHTYPE_OPEN_SYSTEM;
-		} else {
-			wdev->conn->auto_auth = false;
-		}
-
-		memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
-		wdev->ssid_len = connect->ssid_len;
-		wdev->conn->params.ssid = wdev->ssid;
-		wdev->conn->params.ssid_len = connect->ssid_len;
+		err = cfg80211_conn_clone(wdev, connect);
+		if (err)
+			return err;
 
 		/* don't care about result -- but fill bssid & channel */
 		if (!wdev->conn->params.bssid || !wdev->conn->params.channel)
@@ -791,18 +824,55 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 
 		return err;
 	} else {
+		struct cfg80211_bss *bss;
+
 		wdev->sme_state = CFG80211_SME_CONNECTING;
 		wdev->connect_keys = connkeys;
+
+		bss = cfg80211_get_bss(wdev->wiphy, NULL, connect->bssid,
+				       connect->ssid, connect->ssid_len,
+				       WLAN_CAPABILITY_ESS,
+				       WLAN_CAPABILITY_ESS);
+		if (!bss) {
+			/* We don't have a matching BSS.
+			 *
+			 * This means __connect_result will fail,
+			 * unless the driver provides scan results
+			 * between now and then. So do an explicit
+			 * scan, and try connect later.
+			 */
+			err = cfg80211_conn_clone(wdev, connect);
+			if (!err) {
+				wdev->conn->connect_after_scan = true;
+				err = cfg80211_conn_scan(wdev);
+
+				if (!err)
+					return 0;
+			}
+
+			/* Failed to clone (or scan), so we can't
+			 * delay the connect. Free everything up and
+			 * go ahead with the connect */
+			if (wdev->conn)
+				kfree(wdev->conn->ie);
+			kfree(wdev->conn);
+			wdev->conn = NULL;
+
+		} else {
+			cfg80211_put_bss(bss);
+
+			memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
+			wdev->ssid_len = connect->ssid_len;
+		}
+
 		err = rdev->ops->connect(&rdev->wiphy, dev, connect);
 		if (err) {
 			wdev->connect_keys = NULL;
 			wdev->sme_state = CFG80211_SME_IDLE;
+			wdev->ssid_len = 0;
 			return err;
 		}
 
-		memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
-		wdev->ssid_len = connect->ssid_len;
-
 		return 0;
 	}
 }
-- 
1.6.3.3


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

* Re: [RFC 5/5] cfg80211: scan before connect if we don't have the bss
  2009-08-19  0:04 ` [RFC 5/5] cfg80211: scan before connect if we don't have the bss David Kilroy
@ 2009-08-19  7:48   ` Johannes Berg
  2009-08-19 19:30     ` Dave
  0 siblings, 1 reply; 16+ messages in thread
From: Johannes Berg @ 2009-08-19  7:48 UTC (permalink / raw)
  To: David Kilroy; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 1584 bytes --]

On Wed, 2009-08-19 at 01:04 +0100, David Kilroy wrote:

> @@ -791,18 +824,55 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
>  
>  		return err;
>  	} else {
> +		struct cfg80211_bss *bss;
> +
>  		wdev->sme_state = CFG80211_SME_CONNECTING;
>  		wdev->connect_keys = connkeys;
> +
> +		bss = cfg80211_get_bss(wdev->wiphy, NULL, connect->bssid,
> +				       connect->ssid, connect->ssid_len,
> +				       WLAN_CAPABILITY_ESS,
> +				       WLAN_CAPABILITY_ESS);

Hmm. What if the bssid isn't set? Then the card might select a different
BSS than the one we have on the scan list.


> +			/* Failed to clone (or scan), so we can't
> +			 * delay the connect. Free everything up and
> +			 * go ahead with the connect */
> +			if (wdev->conn)
> +				kfree(wdev->conn->ie);
> +			kfree(wdev->conn);
> +			wdev->conn = NULL;

and that would then run into the warning and the problem anyway? Better
to just reject with -ENOMEM I think? Also, I really don't think you
should use wdev->conn anywhere in this code path, because some code
looks at that to figure out whether or not the cfg80211 SME is used.

> +		} else {
> +			cfg80211_put_bss(bss);

>  		err = rdev->ops->connect(&rdev->wiphy, dev, connect);

And it's all racy too -- by the time the driver calls connect_result(),
the BSS might have expired after it was found here now.

I don't think this is really feasible to implement in cfg80211. Couldn't
the driver do a probe to the BSS that the device selected, and report
that before the connect result?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [RFC 5/5] cfg80211: scan before connect if we don't have the bss
  2009-08-19  7:48   ` Johannes Berg
@ 2009-08-19 19:30     ` Dave
  2009-08-19 19:37       ` Johannes Berg
  2009-08-20  6:39       ` Jussi Kivilinna
  0 siblings, 2 replies; 16+ messages in thread
From: Dave @ 2009-08-19 19:30 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

Johannes Berg wrote:
> On Wed, 2009-08-19 at 01:04 +0100, David Kilroy wrote:
>> @@ -791,18 +824,55 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
>> +		bss = cfg80211_get_bss(wdev->wiphy, NULL, connect->bssid,
>> +				       connect->ssid, connect->ssid_len,
>> +				       WLAN_CAPABILITY_ESS,
>> +				       WLAN_CAPABILITY_ESS);
> 
> Hmm. What if the bssid isn't set? Then the card might select a different
> BSS than the one we have on the scan list.

That's correct. For the Agere driver that's also true when bssid is set
- we can't specify which AP the firmware connects to.

>> +			/* Failed to clone (or scan), so we can't
>> +			 * delay the connect. Free everything up and
>> +			 * go ahead with the connect */
>> +			if (wdev->conn)
>> +				kfree(wdev->conn->ie);
>> +			kfree(wdev->conn);
>> +			wdev->conn = NULL;
> 
> and that would then run into the warning and the problem anyway? Better
> to just reject with -ENOMEM I think? Also, I really don't think you
> should use wdev->conn anywhere in this code path, because some code
> looks at that to figure out whether or not the cfg80211 SME is used.

I thought that might be the case.

>> +		} else {
>> +			cfg80211_put_bss(bss);
> 
>>  		err = rdev->ops->connect(&rdev->wiphy, dev, connect);
> 
> And it's all racy too -- by the time the driver calls connect_result(),
> the BSS might have expired after it was found here now.

Agreed, but with a 15s expiry period I wouldn't expect this to be a
problem in practice.

> I don't think this is really feasible to implement in cfg80211.

cfg80211 seemed like the appropriate place because it avoids different
(fullmac) drivers having to re-implement this.

> Couldn't
> the driver do a probe to the BSS that the device selected, and report
> that before the connect result?

Yes, that's possible. If we went this way it would make sense to encode
this in the interface by changing the cfg80211_connect_result prototype to:

void cfg80211_connect_result(struct net_device *dev,
                             const struct bss *bss,
			     const u8 *req_ie, size_t req_ie_len,
			     const u8 *resp_ie, size_t resp_ie_len,
			     u16 status, gfp_t gfp);

So on connecting:

 * the driver has to call cfg80211_get_bss() to get the bss pointer.

 * if it is not available, scan/probe to get the information, call
cfg80211_inform_bss(), and then use the returned pointer in the
cfg80211_connect_result call.

This means the driver may have to hold onto the IE info to use after the
scan returns.

Another alternative is for cfg80211_connect_result to trigger the scan
if it doesn't have the bss, and only complete the connect when the scan
returns. I think I like the sound of this best.



Dave.

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

* Re: [RFC 5/5] cfg80211: scan before connect if we don't have the bss
  2009-08-19 19:30     ` Dave
@ 2009-08-19 19:37       ` Johannes Berg
  2009-08-20 18:01         ` Dave
  2009-08-20  6:39       ` Jussi Kivilinna
  1 sibling, 1 reply; 16+ messages in thread
From: Johannes Berg @ 2009-08-19 19:37 UTC (permalink / raw)
  To: Dave; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 2732 bytes --]

On Wed, 2009-08-19 at 20:30 +0100, Dave wrote:

> > Hmm. What if the bssid isn't set? Then the card might select a different
> > BSS than the one we have on the scan list.
> 
> That's correct. For the Agere driver that's also true when bssid is set
> - we can't specify which AP the firmware connects to.

Ok. We may want a feature flag for the latter case so we know what's
going on, and reject a BSSID setting.

> >> +		} else {
> >> +			cfg80211_put_bss(bss);
> > 
> >>  		err = rdev->ops->connect(&rdev->wiphy, dev, connect);
> > 
> > And it's all racy too -- by the time the driver calls connect_result(),
> > the BSS might have expired after it was found here now.
> 
> Agreed, but with a 15s expiry period I wouldn't expect this to be a
> problem in practice.

Well, the user could scan, take 12 seconds to pick out the AP manually,
enter the paramters in another 2.5 seconds, and then it would already
happen, I think?

> > I don't think this is really feasible to implement in cfg80211.
> 
> cfg80211 seemed like the appropriate place because it avoids different
> (fullmac) drivers having to re-implement this.

True.

> > Couldn't
> > the driver do a probe to the BSS that the device selected, and report
> > that before the connect result?
> 
> Yes, that's possible. If we went this way it would make sense to encode
> this in the interface by changing the cfg80211_connect_result prototype to:
> 
> void cfg80211_connect_result(struct net_device *dev,
>                              const struct bss *bss,
> 			     const u8 *req_ie, size_t req_ie_len,
> 			     const u8 *resp_ie, size_t resp_ie_len,
> 			     u16 status, gfp_t gfp);
> 
> So on connecting:
> 
>  * the driver has to call cfg80211_get_bss() to get the bss pointer.
> 
>  * if it is not available, scan/probe to get the information, call
> cfg80211_inform_bss(), and then use the returned pointer in the
> cfg80211_connect_result call.
> 
> This means the driver may have to hold onto the IE info to use after the
> scan returns.

Indeed, that would work, although it seems somewhat pointless to pass
around the BSS pointer and require the driver to do the lookup, but it
nicely avoids any races that we have even now.

> Another alternative is for cfg80211_connect_result to trigger the scan
> if it doesn't have the bss, and only complete the connect when the scan
> returns. I think I like the sound of this best.

Good option too, though then it would be useful to pass the channel
pointer if available to scan only on that channel. Of course, if it
still can't be found things are really amiss and we should probably
disconnect and send a failed event to userspace.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [RFC 5/5] cfg80211: scan before connect if we don't have the bss
  2009-08-19 19:30     ` Dave
  2009-08-19 19:37       ` Johannes Berg
@ 2009-08-20  6:39       ` Jussi Kivilinna
  1 sibling, 0 replies; 16+ messages in thread
From: Jussi Kivilinna @ 2009-08-20  6:39 UTC (permalink / raw)
  To: Dave; +Cc: Johannes Berg, linux-wireless

Quoting Dave <kilroyd@googlemail.com>:

>
> Another alternative is for cfg80211_connect_result to trigger the scan
> if it doesn't have the bss, and only complete the connect when the scan
> returns. I think I like the sound of this best.
>

This sounds best, as with rndis, driver can get currently connected  
bss from device and scan isn't required.

-Jussi


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

* Re: [RFC 5/5] cfg80211: scan before connect if we don't have the bss
  2009-08-19 19:37       ` Johannes Berg
@ 2009-08-20 18:01         ` Dave
  0 siblings, 0 replies; 16+ messages in thread
From: Dave @ 2009-08-20 18:01 UTC (permalink / raw)
  To: Johannes Berg; +Cc: jussi.kivilinna, linux-wireless

Johannes Berg wrote:
> On Wed, 2009-08-19 at 20:30 +0100, Dave wrote:
>>> Hmm. What if the bssid isn't set? Then the card might select a different
>>> BSS than the one we have on the scan list.
>> That's correct. For the Agere driver that's also true when bssid is set
>> - we can't specify which AP the firmware connects to.
> 
> Ok. We may want a feature flag for the latter case so we know what's
> going on, and reject a BSSID setting.

I'll look into that.

>>> And it's all racy too -- by the time the driver calls connect_result(),
>>> the BSS might have expired after it was found here now.
>> Agreed, but with a 15s expiry period I wouldn't expect this to be a
>> problem in practice.
> 
> Well, the user could scan, take 12 seconds to pick out the AP manually,
> enter the paramters in another 2.5 seconds, and then it would already
> happen, I think?

As usual, you're right :)

>> Another alternative is for cfg80211_connect_result to trigger the scan
>> if it doesn't have the bss, and only complete the connect when the scan
>> returns. I think I like the sound of this best.

johannes said:
> Good option too, though then it would be useful to pass the channel
> pointer if available to scan only on that channel. Of course, if it
> still can't be found things are really amiss and we should probably
> disconnect and send a failed event to userspace.

Jussi said:
> This sounds best, as with rndis, driver can get currently connected
> bss from device and scan isn't required.

OK, I'll chase this option and see where it goes.


Regards,

Dave.

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

* Re: [RFC v2 0/5] orinoco: use cfg80211 for key manipulation
  2009-08-19  0:04 [RFC v2 0/5] orinoco: use cfg80211 for key manipulation David Kilroy
                   ` (4 preceding siblings ...)
  2009-08-19  0:04 ` [RFC 5/5] cfg80211: scan before connect if we don't have the bss David Kilroy
@ 2009-08-31 17:59 ` John W. Linville
  2009-09-12 23:54   ` Dave Kilroy
  5 siblings, 1 reply; 16+ messages in thread
From: John W. Linville @ 2009-08-31 17:59 UTC (permalink / raw)
  To: David Kilroy; +Cc: linux-wireless, orinoco-devel

On Wed, Aug 19, 2009 at 01:04:08AM +0100, David Kilroy wrote:
> This series basically works (at least after the last patch is applied)
> with wpa_supplicant in wext mode.
> 
> I had tested with wpa_supplicant in nl80211 mode, but hadn't realised
> it wasn't using connect - I'll need to pick up Zhu Yis' patch and redo
> some testing.
> 
> Anyway, the nl80211 interface has a small hole which patch 5 partially
> papers over. I'm not that happy with the way it hijacks the AUTH/ASSOC
> state machine, but it works.
> 
> Other outstanding issues:
>  - It looks like I haven't quite got the connect_roamed callback right:
>    I've got a WARNING I need to investigate in my logs
>  - On disconnecting and reconnecting the card I have to restart
>    wpa_supplicant for things to work. I'm guessing I have to look at
>    driver shutdown, and ensure we send a disconnected event.
> 
> Dave.

Any word on this series?  Time is short for 2.6.32...

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

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

* Re: [RFC v2 0/5] orinoco: use cfg80211 for key manipulation
  2009-08-31 17:59 ` [RFC v2 0/5] orinoco: use cfg80211 for key manipulation John W. Linville
@ 2009-09-12 23:54   ` Dave Kilroy
  2009-10-23 19:05     ` Dave
  0 siblings, 1 reply; 16+ messages in thread
From: Dave Kilroy @ 2009-09-12 23:54 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, orinoco-devel

On Tue, Sep 1, 2009 at 5:59 AM, John W. Linville <linville@tuxdriver.com> wrote:
> On Wed, Aug 19, 2009 at 01:04:08AM +0100, David Kilroy wrote:
>> This series basically works (at least after the last patch is applied)
>
> Any word on this series?  Time is short for 2.6.32...

I'm on holiday right now, but will be back in a week.

I don't recall off the top of my head where I was at, but I suspect
there's still some restructuring I need to do. I guess this'll miss
2.6.32 :(



Dave.

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

* Re: [RFC v2 0/5] orinoco: use cfg80211 for key manipulation
  2009-09-12 23:54   ` Dave Kilroy
@ 2009-10-23 19:05     ` Dave
  2009-10-26 13:17       ` Only device wlan1 but no connection Fritz!WLAN USB stick N2.4 Ed Vaessen
  0 siblings, 1 reply; 16+ messages in thread
From: Dave @ 2009-10-23 19:05 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless

Dave Kilroy wrote:
> On Tue, Sep 1, 2009 at 5:59 AM, John W. Linville <linville@tuxdriver.com> wrote:
>> On Wed, Aug 19, 2009 at 01:04:08AM +0100, David Kilroy wrote:
>>> This series basically works (at least after the last patch is applied)

>> Any word on this series?  Time is short for 2.6.32...
> 
> I'm on holiday right now, but will be back in a week.

FYI I haven't had much time to look at this lately, and will definitely
not be able to do anything with it in the next month. So this will
probably slip another release.

Current status: I've addressed Johannes' comments, and reworked things
so cfg80211 would scan if it doesn't find the bss struct after
connecting. Unfortunately it's not working and I haven't found the time
for a proper debugging session.


Dave.

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

* Only device wlan1 but no connection Fritz!WLAN USB stick N2.4
  2009-10-23 19:05     ` Dave
@ 2009-10-26 13:17       ` Ed Vaessen
  2009-10-26 14:57         ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Ed Vaessen @ 2009-10-26 13:17 UTC (permalink / raw)
  To: linux-wireless

I have a Fritz!Box Fon WLAN 7170 as router and try to connect wireless to
it with the Fritz!WLAN USB N2.4 stick using the compat-wireless software.
Without succes so far.

Software: yesterdays bleeding edge tarball: compat-wireless-2.6.tar.bz2
Kernel: Ubuntu 9.04 2.6.28-16-generic
PC: Athec L51A10
Firmware: ar9170.fw put in /lib/firmware

The software compiles without problem and installs the driver after reboot:

sudo lsmod | grep 9170 gives:
ar9170usb 63624 0
led_class 12036 1 ar9170usb
ath 17024 1 ar9170usb
mac80211 218160 1 ar9170usb
cfg80211 135240 3 ar9170usb,ath,mac80211

After inserting the usb stick, this is shown in /var/log/messages

Oct 25 15:37:00 vaessen-laptop kernel: [ 301.480049] usb 1-1: new high
speed USB device using ehci_hcd and address 5
Oct 25 15:37:00 vaessen-laptop kernel: [ 301.643507] usb 1-1:
configuration #1 chosen from 1 choice
Oct 25 15:37:00 vaessen-laptop kernel: [ 301.702461] Initializing USB Mass
Storage driver...
Oct 25 15:37:00 vaessen-laptop kernel: [ 301.702650] scsi4 : SCSI
emulation for USB Mass Storage devices
Oct 25 15:37:00 vaessen-laptop kernel: [ 301.702803] usbcore: registered
new interface driver usb-storage
Oct 25 15:37:00 vaessen-laptop kernel: [ 301.702808] USB Mass Storage
support registered.
Oct 25 15:37:05 vaessen-laptop kernel: [ 306.709252] scsi 4:0:0:0: CD-ROM
FRITZ! WLAN selfinstall 1.00 PQ: 0 ANSI: 0 CCS
Oct 25 15:37:05 vaessen-laptop kernel: [ 306.722276] sr1: scsi3-mmc drive:
52x/52x cd/rw xa/form2 cdda tray
Oct 25 15:37:05 vaessen-laptop kernel: [ 306.723067] sr 4:0:0:0: Attached
scsi generic sg2 type 5

Oct 25 15:38:38 vaessen-laptop kernel: [ 399.349605] usb 1-1: USB
disconnect, address 5
Oct 25 15:38:39 vaessen-laptop kernel: [ 400.608057] usb 1-1: new high
speed USB device using ehci_hcd and address 6
Oct 25 15:38:39 vaessen-laptop kernel: [ 400.771795] usb 1-1:
configuration #1 chosen from 1 choice
Oct 25 15:38:39 vaessen-laptop kernel: [ 400.888063] usb 1-1: reset high
speed USB device using ehci_hcd and address 6
Oct 25 15:38:40 vaessen-laptop kernel: [ 402.044043] usb 1-1: firmware:
requesting ar9170.fw
Oct 25 15:38:41 vaessen-laptop kernel: [ 402.465806] Registered led
device: ar9170-phy1::tx
Oct 25 15:38:41 vaessen-laptop kernel: [ 402.465846] Registered led
device: ar9170-phy1::assoc
Oct 25 15:38:41 vaessen-laptop kernel: [ 402.465851] usb 1-1: Atheros
AR9170 is registered as 'phy1'
Oct 25 15:38:41 vaessen-laptop kernel: [ 402.471136] udev: renamed network
interface wlan0 to wlan1

It seems the firmware is installed.
Command iwconfig:

lo no wireless extensions.

eth0 no wireless extensions.

pan0 no wireless extensions.

wlan1 IEEE 802.11bg Mode:Managed Access Point: Not-Associated
Tx-Power=0 dBm
Retry long limit:7 RTS thrff Fragment thrff
Power Managementff

Command sudo lshw -C network gives for the wireless this information:

*-network:1 DISABLED
description: Wireless interface
physical id: 2
bus info: usb@1:1
logical name: wlan1
serial: 00:1f:3f:09:2d:40
capabilities: ethernet physical wireless
configuration: broadcast=yes driver=ar9170usb
driverversion=2.6.28-16-generic firmware=N/A link=yes multicast=yes
wireless=IEEE 802.11bg

This 'firmware=N/A' puzzles me.

I used System->Administration->Network Tools but cannot ping the Fritz!Box
router
The interface information says that wireless interface wlan1 is inactive.

How do I make it active?



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

* Re: Only device wlan1 but no connection Fritz!WLAN USB stick N2.4
  2009-10-26 13:17       ` Only device wlan1 but no connection Fritz!WLAN USB stick N2.4 Ed Vaessen
@ 2009-10-26 14:57         ` Luis R. Rodriguez
  0 siblings, 0 replies; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-10-26 14:57 UTC (permalink / raw)
  To: Ed Vaessen; +Cc: linux-wireless

On Mon, Oct 26, 2009 at 6:17 AM, Ed Vaessen <evaessen@xs4all.nl> wrote:
> I have a Fritz!Box Fon WLAN 7170 as router and try to connect wireless to
> it with the Fritz!WLAN USB N2.4 stick using the compat-wireless software.
> Without succes so far.

> Oct 25 15:38:38 vaessen-laptop kernel: [ 399.349605] usb 1-1: USB
> disconnect, address 5
> Oct 25 15:38:39 vaessen-laptop kernel: [ 400.608057] usb 1-1: new high
> speed USB device using ehci_hcd and address 6
> Oct 25 15:38:39 vaessen-laptop kernel: [ 400.771795] usb 1-1:
> configuration #1 chosen from 1 choice
> Oct 25 15:38:39 vaessen-laptop kernel: [ 400.888063] usb 1-1: reset high
> speed USB device using ehci_hcd and address 6
> Oct 25 15:38:40 vaessen-laptop kernel: [ 402.044043] usb 1-1: firmware:
> requesting ar9170.fw
> Oct 25 15:38:41 vaessen-laptop kernel: [ 402.465806] Registered led
> device: ar9170-phy1::tx
> Oct 25 15:38:41 vaessen-laptop kernel: [ 402.465846] Registered led
> device: ar9170-phy1::assoc
> Oct 25 15:38:41 vaessen-laptop kernel: [ 402.465851] usb 1-1: Atheros
> AR9170 is registered as 'phy1'
> Oct 25 15:38:41 vaessen-laptop kernel: [ 402.471136] udev: renamed network
> interface wlan0 to wlan1
>
> It seems the firmware is installed.
> Command iwconfig:
>
> lo no wireless extensions.
>
> eth0 no wireless extensions.
>
> pan0 no wireless extensions.
>
> wlan1 IEEE 802.11bg Mode:Managed Access Point: Not-Associated
> Tx-Power=0 dBm
> Retry long limit:7 RTS thrff Fragment thrff
> Power Managementff
>
> Command sudo lshw -C network gives for the wireless this information:
>
> *-network:1 DISABLED
> description: Wireless interface
> physical id: 2
> bus info: usb@1:1
> logical name: wlan1
> serial: 00:1f:3f:09:2d:40
> capabilities: ethernet physical wireless
> configuration: broadcast=yes driver=ar9170usb
> driverversion=2.6.28-16-generic firmware=N/A link=yes multicast=yes
> wireless=IEEE 802.11bg
>
> This 'firmware=N/A' puzzles me.

That's probably from ethtool, and since John added ethtool support all
we would need to do I think is tag the firmware name on the wiphy
struct (wiphy->fw_version). But we haven't added that yet to ar9170.

> I used System->Administration->Network Tools but cannot ping the Fritz!Box
> router
> The interface information says that wireless interface wlan1 is inactive.
>
> How do I make it active?

Bring the interface up first:

ip link set dev wlan1 up

Then use iw to scan for example

  Luis

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

end of thread, other threads:[~2009-10-26 14:57 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-19  0:04 [RFC v2 0/5] orinoco: use cfg80211 for key manipulation David Kilroy
2009-08-19  0:04 ` [RFC 1/5] orinoco: add cfg80211 connect and disconnect David Kilroy
2009-08-19  0:04 ` [RFC 2/5] orinoco: add cfg80211 join_ibss and leave_ibss David Kilroy
2009-08-19  0:04 ` [RFC 3/5] orinoco: implement cfg80211 key manipulation functions David Kilroy
2009-08-19  0:04 ` [RFC 4/5] orinoco: do WE via cfg80211 David Kilroy
2009-08-19  0:04 ` [RFC 5/5] cfg80211: scan before connect if we don't have the bss David Kilroy
2009-08-19  7:48   ` Johannes Berg
2009-08-19 19:30     ` Dave
2009-08-19 19:37       ` Johannes Berg
2009-08-20 18:01         ` Dave
2009-08-20  6:39       ` Jussi Kivilinna
2009-08-31 17:59 ` [RFC v2 0/5] orinoco: use cfg80211 for key manipulation John W. Linville
2009-09-12 23:54   ` Dave Kilroy
2009-10-23 19:05     ` Dave
2009-10-26 13:17       ` Only device wlan1 but no connection Fritz!WLAN USB stick N2.4 Ed Vaessen
2009-10-26 14:57         ` Luis R. Rodriguez

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).