[PATCH] libertas: fix WPA associations by handling ENABLE_RSN correctly
authorDan Williams <dcbw@redhat.com>
Mon, 18 Jun 2007 16:01:12 +0000 (12:01 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 28 Jun 2007 11:48:47 +0000 (07:48 -0400)
Don't clobber the firmware's internal state machine by setting
ENABLE_RSN more than once during the 4-way handshake.  Check what
the ENABLE_RSN status is and only set if it should be changed.

Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/hostcmd.h

index f67efa0..afd5617 100644 (file)
@@ -323,6 +323,8 @@ static int assoc_helper_secinfo(wlan_private *priv,
 {
        wlan_adapter *adapter = priv->adapter;
        int ret = 0;
+       u32 do_wpa;
+       u32 rsn = 0;
 
        lbs_deb_enter(LBS_DEB_ASSOC);
 
@@ -333,12 +335,34 @@ static int assoc_helper_secinfo(wlan_private *priv,
        if (ret)
                goto out;
 
-       /* enable/disable RSN */
+       /* If RSN is already enabled, don't try to enable it again, since
+        * ENABLE_RSN resets internal state machines and will clobber the
+        * 4-way WPA handshake.
+        */
+
+       /* Get RSN enabled/disabled */
        ret = libertas_prepare_and_send_command(priv,
                                    cmd_802_11_enable_rsn,
                                    cmd_act_set,
                                    cmd_option_waitforrsp,
-                                   0, assoc_req);
+                                   0, &rsn);
+       if (ret) {
+               lbs_deb_assoc("Failed to get RSN status: %d", ret);
+               goto out;
+       }
+
+       /* Don't re-enable RSN if it's already enabled */
+       do_wpa = (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled);
+       if (do_wpa == rsn)
+               goto out;
+
+       /* Set RSN enabled/disabled */
+       rsn = do_wpa;
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_enable_rsn,
+                                   cmd_act_set,
+                                   cmd_option_waitforrsp,
+                                   0, &rsn);
 
 out:
        lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
index 124e029..13f6528 100644 (file)
@@ -228,17 +228,19 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
                                      void * pdata_buf)
 {
        struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
-       struct assoc_request * assoc_req = pdata_buf;
+       u32 * enable = pdata_buf;
 
        lbs_deb_enter(LBS_DEB_CMD);
 
        cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
        cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
        penableRSN->action = cpu_to_le16(cmd_action);
-       if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
-               penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
-       } else {
-               penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
+
+       if (cmd_action == cmd_act_set) {
+               if (*enable)
+                       penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+               else
+                       penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
        }
 
        lbs_deb_leave(LBS_DEB_CMD);
index 0c3b9a5..6ac0d47 100644 (file)
@@ -537,6 +537,24 @@ static int wlan_ret_get_log(wlan_private * priv,
        return 0;
 }
 
+static int libertas_ret_802_11_enable_rsn(wlan_private * priv,
+                                          struct cmd_ds_command *resp)
+{
+       struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn;
+       wlan_adapter *adapter = priv->adapter;
+       u32 * pdata_buf = adapter->cur_cmd->pdata_buf;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       if (enable_rsn->action == cpu_to_le16(cmd_act_get)) {
+               if (pdata_buf)
+                       *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
+       }
+
+       lbs_deb_enter(LBS_DEB_CMD);
+       return 0;
+}
+
 static inline int handle_cmd_response(u16 respcmd,
                                      struct cmd_ds_command *resp,
                                      wlan_private *priv)
@@ -610,7 +628,10 @@ static inline int handle_cmd_response(u16 respcmd,
        case cmd_ret_802_11_authenticate:
        case cmd_ret_802_11_radio_control:
        case cmd_ret_802_11_beacon_stop:
+               break;
+
        case cmd_ret_802_11_enable_rsn:
+               ret = libertas_ret_802_11_enable_rsn(priv, resp);
                break;
 
        case cmd_ret_802_11_data_rate:
index 3acf939..09b898f 100644 (file)
@@ -503,7 +503,7 @@ struct cmd_ds_802_11_ad_hoc_join {
 struct cmd_ds_802_11_enable_rsn {
        __le16 action;
        __le16 enable;
-};
+} __attribute__ ((packed));
 
 struct MrvlIEtype_keyParamSet {
        /* type ID */