From: Dan Williams Date: Sat, 26 May 2007 03:01:24 +0000 (-0400) Subject: [PATCH] libertas: Make WPA work through supplicant handshake X-Git-Tag: v2.6.22-rc5~44^2~2^2~15 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=90a42210f275e1f828eb6c08bf8252c2d6a774e0;p=linux-2.6 [PATCH] libertas: Make WPA work through supplicant handshake 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 Signed-off-by: John W. Linville --- diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 48fc6d171d..2ee38a25ad 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -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; } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 53ac28e3ec..8da788e2ec 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -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: diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index ec16cd08ae..3da1efdf1a 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -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 diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 40dd08018b..2edc10c332 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -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;