Exemplo n.º 1
0
/*
 * This function prepares command to set/get/reset network key(s).
 *
 * Preparation includes -
 *      - Setting command ID, action and proper size
 *      - Setting WEP keys, WAPI keys or WPA keys along with required
 *        encryption (TKIP, AES) (as required)
 *      - Ensuring correct endian-ness
 */
static int
mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
				struct host_cmd_ds_command *cmd,
				u16 cmd_action, u32 cmd_oid,
				struct mwifiex_ds_encrypt_key *enc_key)
{
	struct host_cmd_ds_802_11_key_material *key_material =
		&cmd->params.key_material;
	u16 key_param_len = 0;
	int ret = 0;
	const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
	key_material->action = cpu_to_le16(cmd_action);

	if (cmd_action == HostCmd_ACT_GEN_GET) {
		cmd->size =
			cpu_to_le16(sizeof(key_material->action) + S_DS_GEN);
		return ret;
	}

	if (!enc_key) {
		memset(&key_material->key_param_set, 0,
		       (NUM_WEP_KEYS *
			sizeof(struct mwifiex_ie_type_key_param_set)));
		ret = mwifiex_set_keyparamset_wep(priv,
						  &key_material->key_param_set,
						  &key_param_len);
		cmd->size = cpu_to_le16(key_param_len +
				    sizeof(key_material->action) + S_DS_GEN);
		return ret;
	} else
		memset(&key_material->key_param_set, 0,
		       sizeof(struct mwifiex_ie_type_key_param_set));
	if (enc_key->is_wapi_key) {
		dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
		key_material->key_param_set.key_type_id =
			cpu_to_le16(KEY_TYPE_ID_WAPI);
		if (cmd_oid == KEY_INFO_ENABLED)
			key_material->key_param_set.key_info =
				cpu_to_le16(KEY_ENABLED);
		else
			key_material->key_param_set.key_info =
				cpu_to_le16(!KEY_ENABLED);

		key_material->key_param_set.key[0] = enc_key->key_index;
		if (!priv->sec_info.wapi_key_on)
			key_material->key_param_set.key[1] = 1;
		else
			/* set 0 when re-key */
			key_material->key_param_set.key[1] = 0;

		if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) {
			/* WAPI pairwise key: unicast */
			key_material->key_param_set.key_info |=
				cpu_to_le16(KEY_UNICAST);
		} else {	/* WAPI group key: multicast */
			key_material->key_param_set.key_info |=
				cpu_to_le16(KEY_MCAST);
			priv->sec_info.wapi_key_on = true;
		}

		key_material->key_param_set.type =
			cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
		key_material->key_param_set.key_len =
			cpu_to_le16(WAPI_KEY_LEN);
		memcpy(&key_material->key_param_set.key[2],
		       enc_key->key_material, enc_key->key_len);
		memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
		       enc_key->wapi_rxpn, WAPI_RXPN_LEN);
		key_material->key_param_set.length =
			cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);

		key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
				 sizeof(struct mwifiex_ie_types_header);
		cmd->size = cpu_to_le16(key_param_len +
				sizeof(key_material->action) + S_DS_GEN);
		return ret;
	}
	if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
		dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
		key_material->key_param_set.key_type_id =
			cpu_to_le16(KEY_TYPE_ID_AES);
		if (cmd_oid == KEY_INFO_ENABLED)
			key_material->key_param_set.key_info =
				cpu_to_le16(KEY_ENABLED);
		else
			key_material->key_param_set.key_info =
				cpu_to_le16(!KEY_ENABLED);

		if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
				/* AES pairwise key: unicast */
			key_material->key_param_set.key_info |=
				cpu_to_le16(KEY_UNICAST);
		else		/* AES group key: multicast */
			key_material->key_param_set.key_info |=
				cpu_to_le16(KEY_MCAST);
	} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
		dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
		key_material->key_param_set.key_type_id =
			cpu_to_le16(KEY_TYPE_ID_TKIP);
		key_material->key_param_set.key_info =
			cpu_to_le16(KEY_ENABLED);

		if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
				/* TKIP pairwise key: unicast */
			key_material->key_param_set.key_info |=
				cpu_to_le16(KEY_UNICAST);
		else		/* TKIP group key: multicast */
			key_material->key_param_set.key_info |=
				cpu_to_le16(KEY_MCAST);
	}

	if (key_material->key_param_set.key_type_id) {
		key_material->key_param_set.type =
			cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
		key_material->key_param_set.key_len =
			cpu_to_le16((u16) enc_key->key_len);
		memcpy(key_material->key_param_set.key, enc_key->key_material,
		       enc_key->key_len);
		key_material->key_param_set.length =
			cpu_to_le16((u16) enc_key->key_len +
				    KEYPARAMSET_FIXED_LEN);

		key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN)
				      + sizeof(struct mwifiex_ie_types_header);

		cmd->size = cpu_to_le16(key_param_len +
				    sizeof(key_material->action) + S_DS_GEN);
	}

	return ret;
}
Exemplo n.º 2
0
Arquivo: sta_cmd.c Projeto: mbgg/linux
/*
 * This function prepares command to set/get/reset network key(s).
 *
 * Preparation includes -
 *      - Setting command ID, action and proper size
 *      - Setting WEP keys, WAPI keys or WPA keys along with required
 *        encryption (TKIP, AES) (as required)
 *      - Ensuring correct endian-ness
 */
static int
mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
				struct host_cmd_ds_command *cmd,
				u16 cmd_action, u32 cmd_oid,
				struct mwifiex_ds_encrypt_key *enc_key)
{
	struct host_cmd_ds_802_11_key_material *key_material =
		&cmd->params.key_material;
	struct host_cmd_tlv_mac_addr *tlv_mac;
	u16 key_param_len = 0, cmd_size;
	int ret = 0;

	cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
	key_material->action = cpu_to_le16(cmd_action);

	if (cmd_action == HostCmd_ACT_GEN_GET) {
		cmd->size =
			cpu_to_le16(sizeof(key_material->action) + S_DS_GEN);
		return ret;
	}

	if (!enc_key) {
		memset(&key_material->key_param_set, 0,
		       (NUM_WEP_KEYS *
			sizeof(struct mwifiex_ie_type_key_param_set)));
		ret = mwifiex_set_keyparamset_wep(priv,
						  &key_material->key_param_set,
						  &key_param_len);
		cmd->size = cpu_to_le16(key_param_len +
				    sizeof(key_material->action) + S_DS_GEN);
		return ret;
	} else
		memset(&key_material->key_param_set, 0,
		       sizeof(struct mwifiex_ie_type_key_param_set));
	if (enc_key->is_wapi_key) {
		dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
		key_material->key_param_set.key_type_id =
						cpu_to_le16(KEY_TYPE_ID_WAPI);
		if (cmd_oid == KEY_INFO_ENABLED)
			key_material->key_param_set.key_info =
						cpu_to_le16(KEY_ENABLED);
		else
			key_material->key_param_set.key_info =
						cpu_to_le16(!KEY_ENABLED);

		key_material->key_param_set.key[0] = enc_key->key_index;
		if (!priv->sec_info.wapi_key_on)
			key_material->key_param_set.key[1] = 1;
		else
			/* set 0 when re-key */
			key_material->key_param_set.key[1] = 0;

		if (!is_broadcast_ether_addr(enc_key->mac_addr)) {
			/* WAPI pairwise key: unicast */
			key_material->key_param_set.key_info |=
				cpu_to_le16(KEY_UNICAST);
		} else {	/* WAPI group key: multicast */
			key_material->key_param_set.key_info |=
				cpu_to_le16(KEY_MCAST);
			priv->sec_info.wapi_key_on = true;
		}

		key_material->key_param_set.type =
					cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
		key_material->key_param_set.key_len =
						cpu_to_le16(WAPI_KEY_LEN);
		memcpy(&key_material->key_param_set.key[2],
		       enc_key->key_material, enc_key->key_len);
		memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
		       enc_key->pn, PN_LEN);
		key_material->key_param_set.length =
			cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);

		key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
				 sizeof(struct mwifiex_ie_types_header);
		cmd->size = cpu_to_le16(sizeof(key_material->action)
					+ S_DS_GEN +  key_param_len);
		return ret;
	}
	if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
		if (enc_key->is_igtk_key) {
			dev_dbg(priv->adapter->dev, "cmd: CMAC_AES\n");
			key_material->key_param_set.key_type_id =
					cpu_to_le16(KEY_TYPE_ID_AES_CMAC);
			if (cmd_oid == KEY_INFO_ENABLED)
				key_material->key_param_set.key_info =
						cpu_to_le16(KEY_ENABLED);
			else
				key_material->key_param_set.key_info =
						cpu_to_le16(!KEY_ENABLED);

			key_material->key_param_set.key_info |=
							cpu_to_le16(KEY_IGTK);
		} else {
			dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
			key_material->key_param_set.key_type_id =
						cpu_to_le16(KEY_TYPE_ID_AES);
			if (cmd_oid == KEY_INFO_ENABLED)
				key_material->key_param_set.key_info =
						cpu_to_le16(KEY_ENABLED);
			else
				key_material->key_param_set.key_info =
						cpu_to_le16(!KEY_ENABLED);

			if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
				/* AES pairwise key: unicast */
				key_material->key_param_set.key_info |=
						cpu_to_le16(KEY_UNICAST);
			else	/* AES group key: multicast */
				key_material->key_param_set.key_info |=
							cpu_to_le16(KEY_MCAST);
		}
	} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
		dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
		key_material->key_param_set.key_type_id =
						cpu_to_le16(KEY_TYPE_ID_TKIP);
		key_material->key_param_set.key_info =
						cpu_to_le16(KEY_ENABLED);

		if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
				/* TKIP pairwise key: unicast */
			key_material->key_param_set.key_info |=
						cpu_to_le16(KEY_UNICAST);
		else		/* TKIP group key: multicast */
			key_material->key_param_set.key_info |=
							cpu_to_le16(KEY_MCAST);
	}

	if (key_material->key_param_set.key_type_id) {
		key_material->key_param_set.type =
					cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
		key_material->key_param_set.key_len =
					cpu_to_le16((u16) enc_key->key_len);
		memcpy(key_material->key_param_set.key, enc_key->key_material,
		       enc_key->key_len);
		key_material->key_param_set.length =
			cpu_to_le16((u16) enc_key->key_len +
				    KEYPARAMSET_FIXED_LEN);

		key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
				+ sizeof(struct mwifiex_ie_types_header);

		if (le16_to_cpu(key_material->key_param_set.key_type_id) ==
							KEY_TYPE_ID_AES_CMAC) {
			struct mwifiex_cmac_param *param =
					(void *)key_material->key_param_set.key;

			memcpy(param->ipn, enc_key->pn, IGTK_PN_LEN);
			memcpy(param->key, enc_key->key_material,
			       WLAN_KEY_LEN_AES_CMAC);

			key_param_len = sizeof(struct mwifiex_cmac_param);
			key_material->key_param_set.key_len =
						cpu_to_le16(key_param_len);
			key_param_len += KEYPARAMSET_FIXED_LEN;
			key_material->key_param_set.length =
						cpu_to_le16(key_param_len);
			key_param_len += sizeof(struct mwifiex_ie_types_header);
		}

		cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
					+ key_param_len);

		if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
			tlv_mac = (void *)((u8 *)&key_material->key_param_set +
					   key_param_len);
			tlv_mac->tlv.type = cpu_to_le16(TLV_TYPE_STA_MAC_ADDR);
			tlv_mac->tlv.len = cpu_to_le16(ETH_ALEN);
			memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN);
			cmd_size = key_param_len + S_DS_GEN +
				   sizeof(key_material->action) +
				   sizeof(struct host_cmd_tlv_mac_addr);
		} else {
			cmd_size = key_param_len + S_DS_GEN +
				   sizeof(key_material->action);
		}
		cmd->size = cpu_to_le16(cmd_size);
	}

	return ret;
}