diff options
author | Javier Cardona <javier@cozybit.com> | 2008-09-23 13:48:06 -0700 |
---|---|---|
committer | Deepak Saxena <dsaxena@laptop.org> | 2008-09-23 14:59:45 -0700 |
commit | f10b654367d7065d50e7d5e3649933453cea3102 (patch) | |
tree | 85e81dde0297a3b2526dfa4eef305bd207f53871 | |
parent | 38b5fedf917fc36d68f9712541d46dbccb4d7cb1 (diff) | |
download | lwn-f10b654367d7065d50e7d5e3649933453cea3102.tar.gz lwn-f10b654367d7065d50e7d5e3649933453cea3102.zip |
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.c | 72 |
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); |