[PATCH] libertas: Make WPA work through supplicant handshake
authorDan Williams <dcbw@redhat.com>
Sat, 26 May 2007 03:01:24 +0000 (23:01 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 11 Jun 2007 18:28:44 +0000 (14:28 -0400)
Fix WPA so it works up through the supplicant 4-Way handshake process.
Doesn't successfully pass traffic yet; may be problems installing
the GTK to the firmware.

- RSN needs to be enabled before the association command is sent
- Use keys from the association request not the adapter structure
- cmd_act_mac_strict_protection_enable != IW_AUTH_DROP_UNENCRYPTED
- Fix network filtering logic in is_network_compatible() WPA helpers

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/scan.c
drivers/net/wireless/libertas/wext.c

index 48fc6d1..2ee38a2 100644 (file)
@@ -347,7 +347,17 @@ static int assoc_helper_secinfo(wlan_private *priv,
                sizeof(struct wlan_802_11_security));
 
        ret = libertas_set_mac_packet_filter(priv);
+       if (ret)
+               goto out;
 
+       /* enable/disable RSN */
+       ret = libertas_prepare_and_send_command(priv,
+                                   cmd_802_11_enable_rsn,
+                                   cmd_act_set,
+                                   cmd_option_waitforrsp,
+                                   0, assoc_req);
+
+out:
        lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
        return ret;
 }
@@ -360,22 +370,12 @@ static int assoc_helper_wpa_keys(wlan_private *priv,
 
        lbs_deb_enter(LBS_DEB_ASSOC);
 
-       /* enable/Disable RSN */
-       ret = libertas_prepare_and_send_command(priv,
-                                   cmd_802_11_enable_rsn,
-                                   cmd_act_set,
-                                   cmd_option_waitforrsp,
-                                   0, assoc_req);
-       if (ret)
-               goto out;
-
        ret = libertas_prepare_and_send_command(priv,
                                    cmd_802_11_key_material,
                                    cmd_act_set,
                                    cmd_option_waitforrsp,
                                    0, assoc_req);
 
-out:
        lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
        return ret;
 }
index 53ac28e..8da788e 100644 (file)
@@ -232,22 +232,25 @@ done:
 
 static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
                                      struct cmd_ds_command *cmd,
-                                     u16 cmd_action)
+                                     u16 cmd_action,
+                                     void * pdata_buf)
 {
        struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
-       wlan_adapter *adapter = priv->adapter;
+       struct assoc_request * assoc_req = pdata_buf;
+
+       lbs_deb_enter(LBS_DEB_CMD);
 
        cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
-       cmd->size =
-           cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) +
-                            S_DS_GEN);
+       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) +
+                               S_DS_GEN);
        penableRSN->action = cpu_to_le16(cmd_action);
-       if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+       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);
        }
 
+       lbs_deb_leave(LBS_DEB_CMD);
        return 0;
 }
 
@@ -258,14 +261,12 @@ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
        pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
 
        if (pkey->flags & KEY_INFO_WPA_ENABLED) {
-               pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED);
-       } else {
-               pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED);
+               pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
        }
-
        if (pkey->flags & KEY_INFO_WPA_UNICAST) {
                pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
-       } else if (pkey->flags & KEY_INFO_WPA_MCAST) {
+       }
+       if (pkey->flags & KEY_INFO_WPA_MCAST) {
                pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
        }
 
@@ -283,9 +284,9 @@ static int wlan_cmd_802_11_key_material(wlan_private * priv,
                                        u16 cmd_action,
                                        u32 cmd_oid, void *pdata_buf)
 {
-       wlan_adapter *adapter = priv->adapter;
        struct cmd_ds_802_11_key_material *pkeymaterial =
            &cmd->params.keymaterial;
+       struct assoc_request * assoc_req = pdata_buf;
        int ret = 0;
        int index = 0;
 
@@ -295,29 +296,28 @@ static int wlan_cmd_802_11_key_material(wlan_private * priv,
        pkeymaterial->action = cpu_to_le16(cmd_action);
 
        if (cmd_action == cmd_act_get) {
-               cmd->size = cpu_to_le16(  S_DS_GEN
-                                            + sizeof (pkeymaterial->action));
+               cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
                ret = 0;
                goto done;
        }
 
        memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
 
-       if (adapter->wpa_unicast_key.len) {
+       if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
                set_one_wpa_key(&pkeymaterial->keyParamSet[index],
-                               &adapter->wpa_unicast_key);
+                               &assoc_req->wpa_unicast_key);
                index++;
        }
 
-       if (adapter->wpa_mcast_key.len) {
+       if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
                set_one_wpa_key(&pkeymaterial->keyParamSet[index],
-                               &adapter->wpa_mcast_key);
+                               &assoc_req->wpa_mcast_key);
                index++;
        }
 
        cmd->size = cpu_to_le16(  S_DS_GEN
-                                    + sizeof (pkeymaterial->action)
-                                    + index * sizeof(struct MrvlIEtype_keyParamSet));
+                               + sizeof (pkeymaterial->action)
+                               + (index * sizeof(struct MrvlIEtype_keyParamSet)));
 
        ret = 0;
 
@@ -1302,13 +1302,13 @@ int libertas_prepare_and_send_command(wlan_private * priv,
                break;
 
        case cmd_802_11_enable_rsn:
-               ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action);
+               ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
+                               pdata_buf);
                break;
 
        case cmd_802_11_key_material:
-               ret = wlan_cmd_802_11_key_material(priv, cmdptr,
-                                                  cmd_action, cmd_oid,
-                                                  pdata_buf);
+               ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action,
+                               cmd_oid, pdata_buf);
                break;
 
        case cmd_802_11_pairwise_tsc:
index ec16cd0..3da1efd 100644 (file)
@@ -99,7 +99,6 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo,
 {
        if (  !secinfo->wep_enabled
           && secinfo->WPAenabled
-          && !secinfo->WPA2enabled
           && (match_bss->wpa_ie[0] == WPA_IE)
           /* privacy bit may NOT be set in some APs like LinkSys WRT54G
              && bss->privacy */
@@ -113,7 +112,6 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo,
                        struct bss_descriptor * match_bss)
 {
        if (  !secinfo->wep_enabled
-          && !secinfo->WPAenabled
           && secinfo->WPA2enabled
           && (match_bss->rsn_ie[0] == WPA2_IE)
           /* privacy bit may NOT be set in some APs like LinkSys WRT54G
index 40dd080..2edc10c 100644 (file)
@@ -1498,6 +1498,8 @@ static void disable_wep(struct assoc_request *assoc_req)
 {
        int i;
 
+       lbs_deb_enter(LBS_DEB_WEXT);
+
        /* Set Open System auth mode */
        assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
 
@@ -1508,6 +1510,27 @@ static void disable_wep(struct assoc_request *assoc_req)
 
        set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
        set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+
+       lbs_deb_leave(LBS_DEB_WEXT);
+}
+
+static void disable_wpa(struct assoc_request *assoc_req)
+{
+       lbs_deb_enter(LBS_DEB_WEXT);
+
+       memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct WLAN_802_11_KEY));
+       assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
+       set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+
+       memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct WLAN_802_11_KEY));
+       assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
+       set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+
+       assoc_req->secinfo.WPAenabled = 0;
+       assoc_req->secinfo.WPA2enabled = 0;
+       set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+
+       lbs_deb_leave(LBS_DEB_WEXT);
 }
 
 /**
@@ -1540,6 +1563,7 @@ static int wlan_set_encode(struct net_device *dev,
 
        if (dwrq->flags & IW_ENCODE_DISABLED) {
                disable_wep (assoc_req);
+               disable_wpa (assoc_req);
                goto out;
        }
 
@@ -1641,6 +1665,7 @@ static int wlan_get_encodeext(struct net_device *dev,
                if (   adapter->secinfo.wep_enabled
                    && !adapter->secinfo.WPAenabled
                    && !adapter->secinfo.WPA2enabled) {
+                       /* WEP */
                        ext->alg = IW_ENCODE_ALG_WEP;
                        ext->key_len = adapter->wep_keys[index].len;
                        key = &adapter->wep_keys[index].key[0];
@@ -1648,8 +1673,27 @@ static int wlan_get_encodeext(struct net_device *dev,
                           && (adapter->secinfo.WPAenabled ||
                               adapter->secinfo.WPA2enabled)) {
                        /* WPA */
-                       ext->alg = IW_ENCODE_ALG_TKIP;
-                       ext->key_len = 0;
+                       struct WLAN_802_11_KEY * pkey = NULL;
+
+                       if (   adapter->wpa_mcast_key.len
+                           && (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
+                               pkey = &adapter->wpa_mcast_key;
+                       else if (   adapter->wpa_unicast_key.len
+                                && (adapter->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
+                               pkey = &adapter->wpa_unicast_key;
+
+                       if (pkey) {
+                               if (pkey->type == KEY_TYPE_ID_AES) {
+                                       ext->alg = IW_ENCODE_ALG_CCMP;
+                               } else {
+                                       ext->alg = IW_ENCODE_ALG_TKIP;
+                               }
+                               ext->key_len = pkey->len;
+                               key = &pkey->key[0];
+                       } else {
+                               ext->alg = IW_ENCODE_ALG_TKIP;
+                               ext->key_len = 0;
+                       }
                } else {
                        goto out;
                }
@@ -1704,6 +1748,7 @@ static int wlan_set_encodeext(struct net_device *dev,
 
        if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
                disable_wep (assoc_req);
+               disable_wpa (assoc_req);
        } else if (alg == IW_ENCODE_ALG_WEP) {
                u16 is_default = 0, index, set_tx_key = 0;
 
@@ -1739,7 +1784,6 @@ static int wlan_set_encodeext(struct net_device *dev,
                        set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
                if (set_tx_key)
                        set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
-
        } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
                struct WLAN_802_11_KEY * pkey;
 
@@ -1756,28 +1800,35 @@ static int wlan_set_encodeext(struct net_device *dev,
                                goto out;
                }
 
-               if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+               if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
                        pkey = &assoc_req->wpa_mcast_key;
-               else
+                       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 WLAN_802_11_KEY));
                memcpy(pkey->key, ext->key, ext->key_len);
                pkey->len = ext->key_len;
-               pkey->flags = KEY_INFO_WPA_ENABLED;
+               if (pkey->len)
+                       pkey->flags |= KEY_INFO_WPA_ENABLED;
 
+               /* Do this after zeroing key structure */
                if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
                        pkey->flags |= KEY_INFO_WPA_MCAST;
-                       set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
                } else {
                        pkey->flags |= KEY_INFO_WPA_UNICAST;
-                       set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
                }
 
-               if (alg == IW_ENCODE_ALG_TKIP)
+               if (alg == IW_ENCODE_ALG_TKIP) {
                        pkey->type = KEY_TYPE_ID_TKIP;
-               else if (alg == IW_ENCODE_ALG_CCMP)
+               } else if (alg == IW_ENCODE_ALG_CCMP) {
                        pkey->type = KEY_TYPE_ID_AES;
+               } else {
+                       ret = -EINVAL;
+                       goto out;
+               }
 
                /* If WPA isn't enabled yet, do that now */
                if (   assoc_req->secinfo.WPAenabled == 0
@@ -1904,6 +1955,7 @@ static int wlan_set_auth(struct net_device *dev,
        case IW_AUTH_CIPHER_PAIRWISE:
        case IW_AUTH_CIPHER_GROUP:
        case IW_AUTH_KEY_MGMT:
+       case IW_AUTH_DROP_UNENCRYPTED:
                /*
                 * libertas does not use these parameters
                 */
@@ -1913,6 +1965,7 @@ static int wlan_set_auth(struct net_device *dev,
                if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
                        assoc_req->secinfo.WPAenabled = 0;
                        assoc_req->secinfo.WPA2enabled = 0;
+                       disable_wpa (assoc_req);
                }
                if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
                        assoc_req->secinfo.WPAenabled = 1;
@@ -1927,17 +1980,6 @@ static int wlan_set_auth(struct net_device *dev,
                updated = 1;
                break;
 
-       case IW_AUTH_DROP_UNENCRYPTED:
-               if (dwrq->value) {
-                       adapter->currentpacketfilter |=
-                           cmd_act_mac_strict_protection_enable;
-               } else {
-                       adapter->currentpacketfilter &=
-                           ~cmd_act_mac_strict_protection_enable;
-               }
-               updated = 1;
-               break;
-
        case IW_AUTH_80211_AUTH_ALG:
                if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
                        assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
@@ -1963,6 +2005,7 @@ static int wlan_set_auth(struct net_device *dev,
                } else {
                        assoc_req->secinfo.WPAenabled = 0;
                        assoc_req->secinfo.WPA2enabled = 0;
+                       disable_wpa (assoc_req);
                }
                updated = 1;
                break;
@@ -2008,13 +2051,6 @@ static int wlan_get_auth(struct net_device *dev,
                        dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
                break;
 
-       case IW_AUTH_DROP_UNENCRYPTED:
-               dwrq->value = 0;
-               if (adapter->currentpacketfilter &
-                   cmd_act_mac_strict_protection_enable)
-                       dwrq->value = 1;
-               break;
-
        case IW_AUTH_80211_AUTH_ALG:
                dwrq->value = adapter->secinfo.auth_mode;
                break;