++
++
++static void show_set_key_error(struct prism2_hostapd_param *param)
++{
++ switch (param->u.crypt.err) {
++ case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
++ wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
++ param->u.crypt.alg);
++ wpa_printf(MSG_INFO, "You may need to load kernel module to "
++ "register that algorithm.");
++ wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
++ "WEP.");
++ break;
++ case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
++ wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
++ MAC2STR(param->sta_addr));
++ break;
++ case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
++ wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
++ break;
++ case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
++ wpa_printf(MSG_INFO, "Key setting failed.");
++ break;
++ case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
++ wpa_printf(MSG_INFO, "TX key index setting failed.");
++ break;
++ case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
++ wpa_printf(MSG_INFO, "Card configuration failed.");
++ break;
++ }
++}
++
++
++static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
++ enum wpa_alg alg, const u8 *addr,
++ int key_idx, int set_tx,
++ const u8 *seq, size_t seq_len,
++ const u8 *key, size_t key_len)
++{
++ struct hostap_driver_data *drv = priv;
++ struct prism2_hostapd_param *param;
++ u8 *buf;
++ size_t blen;
++ int ret = 0;
++ char *alg_name;
++
++ switch (alg) {
++ case WPA_ALG_NONE:
++ alg_name = "none";
++ break;
++ case WPA_ALG_WEP:
++ alg_name = "WEP";
++ break;
++ case WPA_ALG_TKIP:
++ alg_name = "TKIP";
++ break;
++ case WPA_ALG_CCMP:
++ alg_name = "CCMP";
++ break;
++ default:
++ return -1;
++ }
++
++ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
++ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
++ (unsigned long) seq_len, (unsigned long) key_len);
++
++ if (seq_len > 8)
++ return -2;
++
++ blen = sizeof(*param) + key_len;
++ buf = os_zalloc(blen);
++ if (buf == NULL)
++ return -1;
++
++ param = (struct prism2_hostapd_param *) buf;
++ param->cmd = PRISM2_SET_ENCRYPTION;
++ /* TODO: In theory, STA in client mode can use five keys; four default
++ * keys for receiving (with keyidx 0..3) and one individual key for
++ * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
++ * keyidx 0 is reserved for this unicast use and default keys can only
++ * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
++ * This should be fine for more or less all cases, but for completeness
++ * sake, the driver could be enhanced to support the missing key. */
++ if (addr == NULL)
++ os_memset(param->sta_addr, 0xff, ETH_ALEN);
++ else
++ os_memcpy(param->sta_addr, addr, ETH_ALEN);
++ os_strlcpy((char *) param->u.crypt.alg, alg_name,
++ HOSTAP_CRYPT_ALG_NAME_LEN);
++ param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
++ param->u.crypt.idx = key_idx;
++ if (seq)
++ os_memcpy(param->u.crypt.seq, seq, seq_len);
++ param->u.crypt.key_len = key_len;
++ os_memcpy((u8 *) (param + 1), key, key_len);
++
++ if (wpa_hostapd_ioctl(drv, param, blen, 1)) {
++ wpa_printf(MSG_WARNING, "Failed to set encryption.");
++ show_set_key_error(param);
++ ret = -1;
++ }
++ os_free(buf);
++
++ return ret;
++}