int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) { struct iwm_umac_tx_key_id tx_key_id; int ret; ret = iwm_check_profile(iwm); if (ret < 0) return ret; /* */ if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) || iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X || iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK) return 0; tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - sizeof(struct iwm_umac_wifi_if)); tx_key_id.key_idx = key_idx; return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); }
int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, struct iwm_key *key) { int ret; u8 cmd[64], *sta_addr, *key_data, key_len; s8 key_idx; u16 cmd_size = 0; struct iwm_umac_key_hdr *key_hdr = &key->hdr; struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd; struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd; struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; if (set_tx_key) iwm->default_key = key; /* * We check if our current profile is valid. * If not, we dont push the key, we just cache them, * so that with the next siwsessid call, the keys * will be actually pushed. */ if (!remove) { ret = iwm_check_profile(iwm); if (ret < 0) return ret; } sta_addr = key->hdr.mac; key_data = key->key; key_len = key->key_len; key_idx = key->hdr.key_idx; if (!remove) { IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n", key_idx, set_tx_key); IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n", iwm->umac_profile->sec.mcast_cipher, iwm->umac_profile->sec.ucast_cipher); IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n", iwm->umac_profile->sec.auth_type, iwm->umac_profile->sec.flags); switch (key->alg) { case UMAC_CIPHER_TYPE_WEP_40: wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; wep40->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - sizeof(struct iwm_umac_wifi_if)); memcpy(&wep40->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep40->key, key_data, key_len); wep40->static_key = 1; cmd_size = sizeof(struct iwm_umac_key_wep40); break; case UMAC_CIPHER_TYPE_WEP_104: wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; wep104->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - sizeof(struct iwm_umac_wifi_if)); memcpy(&wep104->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep104->key, key_data, key_len); wep104->static_key = 1; cmd_size = sizeof(struct iwm_umac_key_wep104); break; case UMAC_CIPHER_TYPE_CCMP: key_hdr->key_idx++; ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; ccmp->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) - sizeof(struct iwm_umac_wifi_if)); memcpy(&ccmp->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(ccmp->key, key_data, key_len); if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) memcpy(ccmp->iv_count, key->rx_seq, 6); cmd_size = sizeof(struct iwm_umac_key_ccmp); break; case UMAC_CIPHER_TYPE_TKIP: key_hdr->key_idx++; tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; tkip->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_tkip) - sizeof(struct iwm_umac_wifi_if)); memcpy(&tkip->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE); memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE, IWM_TKIP_MIC_SIZE); memcpy(tkip->mic_rx_key, key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, IWM_TKIP_MIC_SIZE); if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) memcpy(ccmp->iv_count, key->rx_seq, 6); cmd_size = sizeof(struct iwm_umac_key_tkip); break; default: return -ENOTSUPP; } if ((key->alg == UMAC_CIPHER_TYPE_CCMP) || (key->alg == UMAC_CIPHER_TYPE_TKIP)) /* * UGLY_UGLY_UGLY * Copied HACK from the MWG driver. * Without it, the key is set before the second * EAPOL frame is sent, and the latter is thus * encrypted. */ schedule_timeout_interruptible(usecs_to_jiffies(300)); ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); if (ret < 0) goto err; /* * We need a default key only if it is set and * if we're doing WEP. */ if (iwm->default_key == key && ((key->alg == UMAC_CIPHER_TYPE_WEP_40) || (key->alg == UMAC_CIPHER_TYPE_WEP_104))) { ret = iwm_set_tx_key(iwm, key_idx); if (ret < 0) goto err; } } else { struct iwm_umac_key_remove key_remove; key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; key_remove.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_remove) - sizeof(struct iwm_umac_wifi_if)); memcpy(&key_remove.key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); ret = iwm_send_wifi_if_cmd(iwm, &key_remove, sizeof(struct iwm_umac_key_remove), 1); if (ret < 0) return ret; iwm->keys[key_idx].in_use = 0; } return 0; err: kfree(key); return ret; }
int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) { int ret = 0; u8 cmd[64], *sta_addr, *key_data, key_len; s8 key_idx; u16 cmd_size = 0; struct iwm_umac_key_hdr *key_hdr = &key->hdr; struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd; struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd; struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; if (!remove) { ret = iwm_check_profile(iwm); if (ret < 0) return ret; } sta_addr = key->hdr.mac; key_data = key->key; key_len = key->key_len; key_idx = key->hdr.key_idx; if (!remove) { u8 auth_type = iwm->umac_profile->sec.auth_type; IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx); IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n", iwm->umac_profile->sec.mcast_cipher, iwm->umac_profile->sec.ucast_cipher); IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n", iwm->umac_profile->sec.auth_type, iwm->umac_profile->sec.flags); switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; wep40->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - sizeof(struct iwm_umac_wifi_if)); memcpy(&wep40->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep40->key, key_data, key_len); wep40->static_key = !!((auth_type != UMAC_AUTH_TYPE_8021X) && (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); cmd_size = sizeof(struct iwm_umac_key_wep40); break; case WLAN_CIPHER_SUITE_WEP104: wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; wep104->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - sizeof(struct iwm_umac_wifi_if)); memcpy(&wep104->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep104->key, key_data, key_len); wep104->static_key = !!((auth_type != UMAC_AUTH_TYPE_8021X) && (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); cmd_size = sizeof(struct iwm_umac_key_wep104); break; case WLAN_CIPHER_SUITE_CCMP: key_hdr->key_idx++; ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; ccmp->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) - sizeof(struct iwm_umac_wifi_if)); memcpy(&ccmp->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(ccmp->key, key_data, key_len); if (key->seq_len) memcpy(ccmp->iv_count, key->seq, key->seq_len); cmd_size = sizeof(struct iwm_umac_key_ccmp); break; case WLAN_CIPHER_SUITE_TKIP: key_hdr->key_idx++; tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; tkip->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_tkip) - sizeof(struct iwm_umac_wifi_if)); memcpy(&tkip->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE); memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE, IWM_TKIP_MIC_SIZE); memcpy(tkip->mic_rx_key, key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, IWM_TKIP_MIC_SIZE); if (key->seq_len) memcpy(ccmp->iv_count, key->seq, key->seq_len); cmd_size = sizeof(struct iwm_umac_key_tkip); break; default: return -ENOTSUPP; } if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) || (key->cipher == WLAN_CIPHER_SUITE_CCMP)) /* */ schedule_timeout_interruptible(usecs_to_jiffies(300)); ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); } else { struct iwm_umac_key_remove key_remove; IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx); key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; key_remove.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_remove) - sizeof(struct iwm_umac_wifi_if)); memcpy(&key_remove.key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); ret = iwm_send_wifi_if_cmd(iwm, &key_remove, sizeof(struct iwm_umac_key_remove), 1); if (ret) return ret; iwm->keys[key_idx].key_len = 0; } return ret; }