/* * 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; }
/* * 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; }