summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier Cardona <javier@cozybit.com>2008-09-23 13:48:06 -0700
committerDeepak Saxena <dsaxena@laptop.org>2008-09-23 14:59:45 -0700
commitf10b654367d7065d50e7d5e3649933453cea3102 (patch)
tree85e81dde0297a3b2526dfa4eef305bd207f53871
parent38b5fedf917fc36d68f9712541d46dbccb4d7cb1 (diff)
downloadlwn-765.tar.gz
lwn-765.zip
libertas: Execute WPA key installation in ioctl context767766765
WPA key installation must happen as soon as possible after the 4-way handshake or the EPOL-GTK frame cannot be decrypted and gets dropped. This patch executes WPA key installation in ioctl context instead of deferring the task to the association worker. In a previous patch I had tried to reduce the WPA key installation delay by forcing immediate execution of the association thread, but that may cause incomplete association requests. Signed-off-by: Javier Cardona <javier@cozybit.com>
-rw-r--r--drivers/net/wireless/libertas/wext.c72
1 files changed, 45 insertions, 27 deletions
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index fd151afa00b5..da8179d78314 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -30,14 +30,6 @@ static inline void lbs_postpone_association_work(struct lbs_private *priv)
queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
}
-static inline void lbs_do_association_work(struct lbs_private *priv)
-{
- if (priv->surpriseremoved)
- return;
- cancel_delayed_work(&priv->assoc_work);
- queue_delayed_work(priv->work_thread, &priv->assoc_work, 0);
-}
-
static inline void lbs_cancel_association_work(struct lbs_private *priv)
{
cancel_delayed_work(&priv->assoc_work);
@@ -1498,6 +1490,42 @@ out:
return ret;
}
+/*
+ * WPA requires key installation to happen immediately after
+ * the 4-way handshake. We cannot defer key installation to
+ * the association worker.
+ * */
+static int install_wpa_key_now(struct lbs_private *priv, struct enc_key *pkey)
+{
+ int ret = 0;
+ uint16_t rsn = 0;
+
+ /* disable_wep() does a proper WEP key removal, but it is deferred.
+ Here we just do the minimal necessary so we can successfully install
+ the WPA key.
+ */
+ if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE) {
+ struct assoc_request ignored;
+ lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, &ignored);
+ priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
+ lbs_set_mac_control(priv);
+ }
+
+
+ /* Get RSN disabled/enabled, in failure assume it's off */
+ lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
+
+ if (!rsn) { /* Enable rsn only if needed */
+ rsn = !rsn;
+ ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &rsn);
+ }
+
+ if (!ret)
+ ret = lbs_set_key_material(priv, pkey);
+
+ return ret;
+}
+
/**
* @brief Set Encryption key Extended (WPA/802.1x and WEP)
*
@@ -1583,10 +1611,8 @@ static int lbs_set_encodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
pkey = &assoc_req->wpa_mcast_key;
- set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
} else {
pkey = &assoc_req->wpa_unicast_key;
- set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
}
memset(pkey, 0, sizeof (struct enc_key));
@@ -1613,29 +1639,21 @@ static int lbs_set_encodeext(struct net_device *dev,
&& assoc_req->secinfo.WPA2enabled == 0) {
assoc_req->secinfo.WPAenabled = 1;
assoc_req->secinfo.WPA2enabled = 1;
- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
}
- /* Only disable wep if necessary: can't waste time here. */
- if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE)
- disable_wep(assoc_req);
+ disable_wep(assoc_req);
+ mutex_unlock(&priv->lock);
+ ret = install_wpa_key_now(priv, pkey);
+ mutex_lock(&priv->lock);
+
}
out:
- if (ret == 0) {
- /* 802.1x and WPA rekeying must happen as quickly as possible,
- * especially during the 4-way handshake; thus if in
- * infrastructure mode, and either (a) 802.1x is enabled or
- * (b) WPA is being used, set the key right away.
- */
- if (assoc_req->mode == IW_MODE_INFRA &&
- ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP))) {
- lbs_do_association_work(priv);
- } else
- lbs_postpone_association_work(priv);
- } else {
+ if (ret == 0)
+ lbs_postpone_association_work(priv);
+ else
lbs_cancel_association_work(priv);
- }
+
mutex_unlock(&priv->lock);
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);