Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 90a42210 authored by Dan Williams's avatar Dan Williams Committed by John W. Linville
Browse files

[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: default avatarDan Williams <dcbw@redhat.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 45f43de8
Loading
Loading
Loading
Loading
+10 −10
Original line number Diff line number Diff line
@@ -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;
}
+24 −24
Original line number Diff line number Diff line
@@ -232,22 +232,25 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv,

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) +
	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));
	                        + (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:
+0 −2
Original line number Diff line number Diff line
@@ -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
+64 −28
Original line number Diff line number Diff line
@@ -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 */
			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;