Example #1
0
static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
			   u8 *aad, size_t *aad_len, u8 *nonce)
{
	u16 fc, stype, seq;
	int qos = 0, addr4 = 0;
	u8 *pos;

	nonce[0] = 0;

	fc = le_to_host16(hdr->frame_control);
	stype = WLAN_FC_GET_STYPE(fc);
	if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
	    (WLAN_FC_TODS | WLAN_FC_FROMDS))
		addr4 = 1;

	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
		fc &= ~0x0070; /* Mask subtype bits */
		if (stype & 0x08) {
			const u8 *qc;
			qos = 1;
			fc &= ~WLAN_FC_ORDER;
			qc = (const u8 *) (hdr + 1);
			if (addr4)
				qc += ETH_ALEN;
			nonce[0] = qc[0] & 0x0f;
		}
	} else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
		nonce[0] |= 0x10; /* Management */

	fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
	fc |= WLAN_FC_ISWEP;
	WPA_PUT_LE16(aad, fc);
	pos = aad + 2;
	os_memcpy(pos, hdr->addr1, 3 * ETH_ALEN);
	pos += 3 * ETH_ALEN;
	seq = le_to_host16(hdr->seq_ctrl);
	seq &= ~0xfff0; /* Mask Seq#; do not modify Frag# */
	WPA_PUT_LE16(pos, seq);
	pos += 2;

	os_memcpy(pos, hdr + 1, addr4 * ETH_ALEN + qos * 2);
	pos += addr4 * ETH_ALEN;
	if (qos) {
		pos[0] &= ~0x70;
		if (1 /* FIX: either device has SPP A-MSDU Capab = 0 */)
			pos[0] &= ~0x80;
		pos++;
		*pos++ = 0x00;
	}

	*aad_len = pos - aad;

	os_memcpy(nonce + 1, hdr->addr2, ETH_ALEN);
	nonce[7] = data[7]; /* PN5 */
	nonce[8] = data[6]; /* PN4 */
	nonce[9] = data[5]; /* PN3 */
	nonce[10] = data[4]; /* PN2 */
	nonce[11] = data[1]; /* PN1 */
	nonce[12] = data[0]; /* PN0 */
}
Example #2
0
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
{
	if (len < 2 + 5)
		return eid;

#ifdef CONFIG_TESTING_OPTIONS
	if (hapd->conf->bss_load_test_set) {
		*eid++ = WLAN_EID_BSS_LOAD;
		*eid++ = 5;
		os_memcpy(eid, hapd->conf->bss_load_test, 5);
		eid += 5;
		return eid;
	}
#endif /* CONFIG_TESTING_OPTIONS */
	if (hapd->conf->bss_load_update_period) {
		*eid++ = WLAN_EID_BSS_LOAD;
		*eid++ = 5;
		WPA_PUT_LE16(eid, hapd->num_sta);
		eid += 2;
		*eid++ = hapd->iface->channel_utilization;
		WPA_PUT_LE16(eid, 0); /* no available admission capabity */
		eid += 2;
	}
	return eid;
}
Example #3
0
static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
			       int pairwise_cipher, int group_cipher,
			       int key_mgmt)
{
	u8 *pos, *len;
	u32 suite;

	if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
	    2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
		return -1;

	pos = wpa_ie;
	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
	len = pos++; /* to be filled */
	WPA_PUT_BE24(pos, OUI_WFA);
	pos += 3;
	*pos++ = HS20_OSEN_OUI_TYPE;

	/* Group Data Cipher Suite */
	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
	if (suite == 0) {
		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
			   group_cipher);
		return -1;
	}
	RSN_SELECTOR_PUT(pos, suite);
	pos += RSN_SELECTOR_LEN;

	/* Pairwise Cipher Suite Count and List */
	WPA_PUT_LE16(pos, 1);
	pos += 2;
	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
	if (suite == 0 ||
	    (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
	     pairwise_cipher != WPA_CIPHER_NONE)) {
		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
			   pairwise_cipher);
		return -1;
	}
	RSN_SELECTOR_PUT(pos, suite);
	pos += RSN_SELECTOR_LEN;

	/* AKM Suite Count and List */
	WPA_PUT_LE16(pos, 1);
	pos += 2;
	RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
	pos += RSN_SELECTOR_LEN;

	*len = pos - len - 1;

	WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);

	return pos - wpa_ie;
}
Example #4
0
int hostapd_update_time_adv(struct hostapd_data *hapd)
{
	const int elen = 2 + 1 + 10 + 5 + 1;
	struct os_time t;
	struct os_tm tm;
	u8 *pos;

	if (hapd->conf->time_advertisement != 2)
		return 0;

	if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
		return -1;

	if (!hapd->time_adv) {
		hapd->time_adv = wpabuf_alloc(elen);
		if (hapd->time_adv == NULL)
			return -1;
		pos = wpabuf_put(hapd->time_adv, elen);
	} else
		pos = wpabuf_mhead_u8(hapd->time_adv);

	*pos++ = WLAN_EID_TIME_ADVERTISEMENT;
	*pos++ = 1 + 10 + 5 + 1;

	*pos++ = 2; /* UTC time at which the TSF timer is 0 */

	/* Time Value at TSF 0 */
	/* FIX: need to calculate this based on the current TSF value */
	WPA_PUT_LE16(pos, tm.year); /* Year */
	pos += 2;
	*pos++ = tm.month; /* Month */
	*pos++ = tm.day; /* Day of month */
	*pos++ = tm.hour; /* Hours */
	*pos++ = tm.min; /* Minutes */
	*pos++ = tm.sec; /* Seconds */
	WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
	pos += 2;
	*pos++ = 0; /* Reserved */

	/* Time Error */
	/* TODO: fill in an estimate on the error */
	*pos++ = 0;
	*pos++ = 0;
	*pos++ = 0;
	*pos++ = 0;
	*pos++ = 0;

	*pos++ = hapd->time_update_counter++;

	return 0;
}
Example #5
0
u8 * bip_protect(const u8 *igtk, u8 *frame, size_t len, u8 *ipn, int keyid,
		 size_t *prot_len)
{
	u8 *prot, *pos, *buf;
	u8 mic[16];
	u16 fc;
	struct ieee80211_hdr *hdr;
	size_t plen;

	plen = len + 18;
	prot = os_malloc(plen);
	if (prot == NULL)
		return NULL;
	os_memcpy(prot, frame, len);
	pos = prot + len;
	*pos++ = WLAN_EID_MMIE;
	*pos++ = 16;
	WPA_PUT_LE16(pos, keyid);
	pos += 2;
	os_memcpy(pos, ipn, 6);
	pos += 6;
	os_memset(pos, 0, 8); /* MIC */

	buf = os_malloc(plen + 20 - 24);
	if (buf == NULL) {
		os_free(prot);
		return NULL;
	}

	/* BIP AAD: FC(masked) A1 A2 A3 */
	hdr = (struct ieee80211_hdr *) frame;
	fc = le_to_host16(hdr->frame_control);
	fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
	WPA_PUT_LE16(buf, fc);
	os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
	os_memcpy(buf + 20, prot + 24, plen - 24);
	wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, plen + 20 - 24);
	/* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
	if (omac1_aes_128(igtk, buf, plen + 20 - 24, mic) < 0) {
		os_free(prot);
		os_free(buf);
		return NULL;
	}
	os_free(buf);

	os_memcpy(pos, mic, 8);
	wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8);

	*prot_len = plen;
	return prot;
}
Example #6
0
/**
 * sha384_prf_bits - IEEE Std 802.11ac-2013, 11.6.1.7.2 Key derivation function
 * @key: Key for KDF
 * @key_len: Length of the key in bytes
 * @label: A unique label for each purpose of the PRF
 * @data: Extra data to bind into the key
 * @data_len: Length of the data
 * @buf: Buffer for the generated pseudo-random key
 * @buf_len: Number of bits of key to generate
 *
 * This function is used to derive new, cryptographically separate keys from a
 * given key. If the requested buf_len is not divisible by eight, the least
 * significant 1-7 bits of the last octet in the output are not part of the
 * requested output.
 */
void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
		     const u8 *data, size_t data_len, u8 *buf,
		     size_t buf_len_bits)
{
	u16 counter = 1;
	size_t pos, plen;
	u8 hash[SHA384_MAC_LEN];
	const u8 *addr[4];
	size_t len[4];
	u8 counter_le[2], length_le[2];
	size_t buf_len = (buf_len_bits + 7) / 8;

	addr[0] = counter_le;
	len[0] = 2;
	addr[1] = (u8 *) label;
	len[1] = os_strlen(label);
	addr[2] = data;
	len[2] = data_len;
	addr[3] = length_le;
	len[3] = sizeof(length_le);

	WPA_PUT_LE16(length_le, buf_len_bits);
	pos = 0;
	while (pos < buf_len) {
		plen = buf_len - pos;
		WPA_PUT_LE16(counter_le, counter);
		if (plen >= SHA384_MAC_LEN) {
			hmac_sha384_vector(key, key_len, 4, addr, len,
					   &buf[pos]);
			pos += SHA384_MAC_LEN;
		} else {
			hmac_sha384_vector(key, key_len, 4, addr, len, hash);
			os_memcpy(&buf[pos], hash, plen);
			pos += plen;
			break;
		}
		counter++;
	}

	/*
	 * Mask out unused bits in the last octet if it does not use all the
	 * bits.
	 */
	if (buf_len_bits % 8) {
		u8 mask = 0xff << (8 - buf_len_bits % 8);
		buf[pos - 1] &= mask;
	}

	os_memset(hash, 0, sizeof(hash));
}
Example #7
0
u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
{
	u8 *len;
	u16 capab;

	if (!hapd->conf->osen)
		return eid;

	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
	len = eid++; /* to be filled */
	WPA_PUT_BE24(eid, OUI_WFA);
	eid += 3;
	*eid++ = HS20_OSEN_OUI_TYPE;

	/* Group Data Cipher Suite */
	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
	eid += RSN_SELECTOR_LEN;

	/* Pairwise Cipher Suite Count and List */
	WPA_PUT_LE16(eid, 1);
	eid += 2;
	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
	eid += RSN_SELECTOR_LEN;

	/* AKM Suite Count and List */
	WPA_PUT_LE16(eid, 1);
	eid += 2;
	RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
	eid += RSN_SELECTOR_LEN;

	/* RSN Capabilities */
	capab = 0;
	if (hapd->conf->wmm_enabled) {
		/* 4 PTKSA replay counters when using WMM */
		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
	}
#ifdef CONFIG_IEEE80211W
	if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
		capab |= WPA_CAPABILITY_MFPC;
		if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
			capab |= WPA_CAPABILITY_MFPR;
	}
#endif /* CONFIG_IEEE80211W */
	WPA_PUT_LE16(eid, capab);
	eid += 2;

	*len = eid - len - 1;

	return eid;
}
Example #8
0
/**
 * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5A.3)
 * @key: Key for PRF
 * @key_len: Length of the key in bytes
 * @label: A unique label for each purpose of the PRF
 * @data: Extra data to bind into the key
 * @data_len: Length of the data
 * @buf: Buffer for the generated pseudo-random key
 * @buf_len: Number of bytes of key to generate
 *
 * This function is used to derive new, cryptographically separate keys from a
 * given key.
 */
void sha256_prf(const u8 *key, size_t key_len, const char *label,
		const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
	u16 counter = 0;
	size_t pos, plen;
	u8 hash[SHA256_MAC_LEN];
	const u8 *addr[3];
	size_t len[3];
	u8 counter_le[2];

	addr[0] = counter_le;
	len[0] = 2;
	addr[1] = (u8 *) label;
	len[1] = strlen(label) + 1;
	addr[2] = data;
	len[2] = data_len;

	pos = 0;
	while (pos < buf_len) {
		plen = buf_len - pos;
		WPA_PUT_LE16(counter_le, counter);
		if (plen >= SHA256_MAC_LEN) {
			hmac_sha256_vector(key, key_len, 3, addr, len,
					   &buf[pos]);
			pos += SHA256_MAC_LEN;
		} else {
			hmac_sha256_vector(key, key_len, 3, addr, len, hash);
			memcpy(&buf[pos], hash, plen);
			break;
		}
		counter++;
	}
}
Example #9
0
/**
 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
 * @password: 0-to-256-unicode-char Password (IN; UTF-8)
 * @password_len: Length of password
 * @password_hash: 16-octet PasswordHash (IN)
 * @pw_block: 516-byte PwBlock (OUT)
 * Returns: 0 on success, -1 on failure
 */
int encrypt_pw_block_with_password_hash(
	const u8 *password, size_t password_len,
	const u8 *password_hash, u8 *pw_block)
{
	size_t ucs2_len, offset;
	u8 *pos;

	os_memset(pw_block, 0, PWBLOCK_LEN);

	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
		return -1;

	if (ucs2_len > 256)
		return -1;

	offset = (256 - ucs2_len) * 2;
	if (offset != 0) {
		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
		if (os_get_random(pw_block, offset) < 0)
			return -1;
	}
	/*
	 * PasswordLength is 4 octets, but since the maximum password length is
	 * 256, only first two (in little endian byte order) can be non-zero.
	 */
	pos = &pw_block[2 * 256];
	WPA_PUT_LE16(pos, password_len * 2);
	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
	return 0;
}
Example #10
0
static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
				 const u8 *current_ap, const u8 *sta_addr,
				 const u8 *body, size_t len)
{
	struct wpa_state_machine *sm;
	u16 status;
	u8 *resp_ies, *pos;
	size_t resp_ies_len, rlen;
	struct ft_rrb_frame *frame;

	sm = wpa_ft_add_sta(wpa_auth, sta_addr);
	if (sm == NULL) {
		wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on "
			   "RRB Request");
		return -1;
	}

	wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);

	status = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
					 &resp_ies_len);

	wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
		   " CurrentAP=" MACSTR " status=%d",
		   MAC2STR(sm->addr), MAC2STR(current_ap), status);
	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);

	/* RRB - Forward action frame response to the Current AP */

	/*
	 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
	 * Status_Code[2] FT Request action frame body[variable]
	 */
	rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;

	frame = os_malloc(sizeof(*frame) + rlen);
	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
	frame->packet_type = FT_PACKET_RESPONSE;
	frame->action_length = host_to_le16(rlen);
	os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
	pos = (u8 *) (frame + 1);
	*pos++ = WLAN_ACTION_FT;
	*pos++ = 2; /* Action: Response */
	os_memcpy(pos, sta_addr, ETH_ALEN);
	pos += ETH_ALEN;
	os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
	pos += ETH_ALEN;
	WPA_PUT_LE16(pos, status);
	pos += 2;
	if (resp_ies) {
		os_memcpy(pos, resp_ies, resp_ies_len);
		os_free(resp_ies);
	}

	wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
			sizeof(*frame) + rlen);
	os_free(frame);

	return 0;
}
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
{
	u8 *group_info;
	struct wpabuf *ie;
	struct p2p_group_member *m;
	u8 *len;

	ie = wpabuf_alloc(257);
	if (ie == NULL)
		return NULL;

	len = p2p_buf_add_ie_hdr(ie);

	p2p_group_add_common_ies(group, ie);
	p2p_group_add_noa(ie, group->noa);

	/* P2P Device Info */
	p2p_buf_add_device_info(ie, group->p2p, NULL);

	/* P2P Group Info */
	group_info = wpabuf_put(ie, 0);
	wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO);
	wpabuf_put_le16(ie, 0); /* Length to be filled */
	for (m = group->members; m; m = m->next)
		p2p_client_info(ie, m);
	WPA_PUT_LE16(group_info + 1,
		     (u8 *) wpabuf_put(ie, 0) - group_info - 3);

	p2p_buf_update_ie_hdr(ie, len);
	return ie;
}
Example #12
0
/**
 * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
 * @password: 0-to-256-unicode-char Password (IN; ASCII)
 * @password_len: Length of password
 * @password_hash: 16-octet PasswordHash (IN)
 * @pw_block: 516-byte PwBlock (OUT)
 * Returns: 0 on success, -1 on failure
 */
int encrypt_pw_block_with_password_hash(
        const u8 *password, size_t password_len,
        const u8 *password_hash, u8 *pw_block)
{
    size_t i, offset;
    u8 *pos;

    if (password_len > 256)
        return -1;

    os_memset(pw_block, 0, PWBLOCK_LEN);
    offset = (256 - password_len) * 2;
    if (os_get_random(pw_block, offset) < 0)
        return -1;
    for (i = 0; i < password_len; i++)
        pw_block[offset + i * 2] = password[i];
    /*
     * PasswordLength is 4 octets, but since the maximum password length is
     * 256, only first two (in little endian byte order) can be non-zero.
     */
    pos = &pw_block[2 * 256];
    WPA_PUT_LE16(pos, password_len * 2);
    rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
    return 0;
}
Example #13
0
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
{
	u8 *pos = eid;

#ifdef CONFIG_WNM
	if (hapd->conf->ap_max_inactivity > 0) {
		unsigned int val;
		*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
		*pos++ = 3;
		val = hapd->conf->ap_max_inactivity;
		if (val > 68000)
			val = 68000;
		val *= 1000;
		val /= 1024;
		if (val == 0)
			val = 1;
		if (val > 65535)
			val = 65535;
		WPA_PUT_LE16(pos, val);
		pos += 2;
		*pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
	}
#endif /* CONFIG_WNM */

	return pos;
}
Example #14
0
/**
 * gas_anqp_set_len - Set Query Request/Response Length
 * @buf: GAS message
 *
 * This function is used to update the Query Request/Response Length field once
 * the payload has been filled.
 */
void gas_anqp_set_len(struct wpabuf *buf)
{
	u8 action;
	size_t offset;
	u8 *len;

	if (buf == NULL || wpabuf_len(buf) < 2)
		return;

	action = *(wpabuf_head_u8(buf) + 1);
	switch (action) {
	case WLAN_PA_GAS_INITIAL_REQ:
		offset = 3 + 4;
		break;
	case WLAN_PA_GAS_INITIAL_RESP:
		offset = 7 + 4;
		break;
	case WLAN_PA_GAS_COMEBACK_RESP:
		offset = 8 + 4;
		break;
	default:
		return;
	}

	if (wpabuf_len(buf) < offset + 2)
		return;

	len = wpabuf_mhead_u8(buf) + offset;
	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
}
Example #15
0
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
	u8 *subelem, *pos;
	struct wpa_group *gsm = sm->group;
	size_t subelem_len;

	/* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
	 * Key[16+8] */
	subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
	subelem = os_zalloc(subelem_len);
	if (subelem == NULL)
		return NULL;

	pos = subelem;
	*pos++ = FTIE_SUBELEM_IGTK;
	*pos++ = subelem_len - 2;
	WPA_PUT_LE16(pos, gsm->GN_igtk);
	pos += 2;
	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
	pos += 6;
	*pos++ = WPA_IGTK_LEN;
	if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
		     gsm->IGTK[gsm->GN_igtk - 4], pos)) {
		os_free(subelem);
		return NULL;
	}

	*len = subelem_len;
	return subelem;
}
Example #16
0
static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
					     u16 comeback_delay,
					     u16 update_indic,
					     const struct wpabuf *tlvs)
{
	struct wpabuf *buf;
	u8 *len_pos, *len_pos2;

	buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0));
	if (buf == NULL)
		return NULL;

	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
	wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
	wpabuf_put_u8(buf, dialog_token);
	wpabuf_put_le16(buf, status_code);
	wpabuf_put_le16(buf, comeback_delay);

	/* Advertisement Protocol IE */
	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
	wpabuf_put_u8(buf, 2); /* Length */
	wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
	wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */

	/* Query Response */
	len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */

	if (tlvs) {
		/* NQP Query Response Frame */
		wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
		len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
		wpabuf_put_be24(buf, OUI_WFA);
		wpabuf_put_u8(buf, P2P_OUI_TYPE);
		 /* Service Update Indicator */
		wpabuf_put_le16(buf, update_indic);
		wpabuf_put_buf(buf, tlvs);

		WPA_PUT_LE16(len_pos2,
			     (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
	}

	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);

	return buf;
}
Example #17
0
/**
 * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
 * @utf8_string: UTF-8 string (IN)
 * @utf8_string_len: Length of utf8_string (IN)
 * @ucs2_buffer: UCS-2 buffer (OUT)
 * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
 * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
 * Returns: 0 on success, -1 on failure
 */
static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
                        u8 *ucs2_buffer, size_t ucs2_buffer_size,
                        size_t *ucs2_string_size)
{
	size_t i, j;

	for (i = 0, j = 0; i < utf8_string_len; i++) {
		u8 c = utf8_string[i];
		if (j >= ucs2_buffer_size) {
			/* input too long */
			return -1;
		}
		if (c <= 0x7F) {
			WPA_PUT_LE16(ucs2_buffer + j, c);
			j += 2;
		} else if (i == utf8_string_len - 1 ||
			   j >= ucs2_buffer_size - 1) {
			/* incomplete surrogate */
			return -1;
		} else {
			u8 c2 = utf8_string[++i];
			if ((c & 0xE0) == 0xC0) {
				/* two-byte encoding */
				WPA_PUT_LE16(ucs2_buffer + j,
					     ((c & 0x1F) << 6) | (c2 & 0x3F));
				j += 2;
			} else if (i == utf8_string_len ||
				   j >= ucs2_buffer_size - 1) {
				/* incomplete surrogate */
				return -1;
			} else {
				/* three-byte encoding */
				u8 c3 = utf8_string[++i];
				WPA_PUT_LE16(ucs2_buffer + j,
					     ((c & 0xF) << 12) |
					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
				j += 2;
			}
		}
	}

	if (ucs2_string_size)
		*ucs2_string_size = j / 2;
	return 0;
}
Example #18
0
void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
			     struct p2p_device *peer)
{
	u8 *len;
	u16 methods;
	size_t nlen, i;

	/* P2P Device Info */
	wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO);
	len = wpabuf_put(buf, 2); /* IE length to be filled */

	/* P2P Device address */
	wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);

	/* Config Methods */
	methods = 0;
	if (peer && peer->wps_method != WPS_NOT_READY) {
		if (peer->wps_method == WPS_PBC)
			methods |= WPS_CONFIG_PUSHBUTTON;
		else if (peer->wps_method == WPS_PIN_DISPLAY ||
			 peer->wps_method == WPS_PIN_KEYPAD) {
			methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
			methods |= WPS_CONFIG_P2PS;
		}
	} else if (p2p->cfg->config_methods) {
		methods |= p2p->cfg->config_methods &
			(WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
			 WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS);
	} else {
		methods |= WPS_CONFIG_PUSHBUTTON;
		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
		methods |= WPS_CONFIG_P2PS;
	}
	wpabuf_put_be16(buf, methods);

	/* Primary Device Type */
	wpabuf_put_data(buf, p2p->cfg->pri_dev_type,
			sizeof(p2p->cfg->pri_dev_type));

	/* Number of Secondary Device Types */
	wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types);

	/* Secondary Device Type List */
	for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
		wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i],
				WPS_DEV_TYPE_LEN);

	/* Device Name */
	nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0;
	wpabuf_put_be16(buf, ATTR_DEV_NAME);
	wpabuf_put_be16(buf, nlen);
	wpabuf_put_data(buf, p2p->cfg->dev_name, nlen);

	/* Update attribute length */
	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
	wpa_printf(MSG_DEBUG, "P2P: * Device Info");
}
Example #19
0
static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
	u8 *subelem;
	struct wpa_group *gsm = sm->group;
	size_t subelem_len, pad_len;
	const u8 *key;
	size_t key_len;
	u8 keybuf[32];

	key_len = gsm->GTK_len;
	if (key_len > sizeof(keybuf))
		return NULL;

	/*
	 * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
	 * than 16 bytes.
	 */
	pad_len = key_len % 8;
	if (pad_len)
		pad_len = 8 - pad_len;
	if (key_len + pad_len < 16)
		pad_len += 8;
	if (pad_len) {
		os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
		os_memset(keybuf + key_len, 0, pad_len);
		keybuf[key_len] = 0xdd;
		key_len += pad_len;
		key = keybuf;
	} else
		key = gsm->GTK[gsm->GN - 1];

	/*
	 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
	 * Key[5..32].
	 */
	subelem_len = 13 + key_len + 8;
	subelem = os_zalloc(subelem_len);
	if (subelem == NULL)
		return NULL;

	subelem[0] = FTIE_SUBELEM_GTK;
	subelem[1] = 11 + key_len + 8;
	/* Key ID in B0-B1 of Key Info */
	WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
	subelem[4] = gsm->GTK_len;
	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
	if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
		os_free(subelem);
		return NULL;
	}

	*len = subelem_len;
	return subelem;
}
static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
				  u8 minor_reason_code, const u8 *addr)
{
	struct ieee80211_mgmt *mgmt;
	int ret;
	u8 *pos;

	if (hapd->driver->send_frame == NULL)
		return -1;

	mgmt = os_zalloc(sizeof(*mgmt) + 100);
	if (mgmt == NULL)
		return -1;

	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
		" with minor reason code %u (stype=%u (%s))",
		MAC2STR(addr), minor_reason_code, stype,
		fc2str(mgmt->frame_control));

	os_memcpy(mgmt->da, addr, ETH_ALEN);
	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
	if (stype == WLAN_FC_STYPE_DEAUTH) {
		mgmt->u.deauth.reason_code =
			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
		pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
	} else {
		mgmt->u.disassoc.reason_code =
			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
		pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
	}

	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
	*pos++ = 4 + 3 + 1;
	WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
	pos += 4;

	*pos++ = P2P_ATTR_MINOR_REASON_CODE;
	WPA_PUT_LE16(pos, 1);
	pos += 2;
	*pos++ = minor_reason_code;

	ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
				       pos - (u8 *) mgmt, 1);
	os_free(mgmt);

	return ret < 0 ? -1 : 0;
}
Example #21
0
static struct wpabuf * p2p_build_sd_query(u16 update_indic,
					  struct wpabuf *tlvs)
{
	struct wpabuf *buf;
	u8 *len_pos, *len_pos2;

	buf = wpabuf_alloc(1000 + wpabuf_len(tlvs));
	if (buf == NULL)
		return NULL;

	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
	wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
	wpabuf_put_u8(buf, 0); /* Dialog Token */

	/* Advertisement Protocol IE */
	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
	wpabuf_put_u8(buf, 2); /* Length */
	wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */
	wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */

	/* Query Request */
	len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */

	/* NQP Query Request Frame */
	wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
	len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
	wpabuf_put_be24(buf, OUI_WFA);
	wpabuf_put_u8(buf, P2P_OUI_TYPE);
	wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
	wpabuf_put_buf(buf, tlvs);

	WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);

	return buf;
}
Example #22
0
int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
		   size_t r0kh_id_len,
		   const u8 *anonce, const u8 *snonce,
		   u8 *buf, size_t len, const u8 *subelem,
		   size_t subelem_len)
{
	u8 *pos = buf, *ielen;
	struct rsn_ftie *hdr;

	if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
	    subelem_len)
		return -1;

	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
	ielen = pos++;

	hdr = (struct rsn_ftie *) pos;
	os_memset(hdr, 0, sizeof(*hdr));
	pos += sizeof(*hdr);
	WPA_PUT_LE16(hdr->mic_control, 0);
	if (anonce)
		os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
	if (snonce)
		os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);

	/* Optional Parameters */
	*pos++ = FTIE_SUBELEM_R1KH_ID;
	*pos++ = FT_R1KH_ID_LEN;
	os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
	pos += FT_R1KH_ID_LEN;

	if (r0kh_id) {
		*pos++ = FTIE_SUBELEM_R0KH_ID;
		*pos++ = r0kh_id_len;
		os_memcpy(pos, r0kh_id, r0kh_id_len);
		pos += r0kh_id_len;
	}

	if (subelem) {
		os_memcpy(pos, subelem, subelem_len);
		pos += subelem_len;
	}

	*ielen = pos - buf - 2;

	return pos - buf;
}
Example #23
0
static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
						   u16 status_code,
						   u16 update_indic,
						   const u8 *data, size_t len,
						   u8 frag_id, u8 more,
						   u16 total_len)
{
	struct wpabuf *buf;
	u8 *len_pos;

	buf = wpabuf_alloc(1000 + len);
	if (buf == NULL)
		return NULL;

	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
	wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP);
	wpabuf_put_u8(buf, dialog_token);
	wpabuf_put_le16(buf, status_code);
	wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
	wpabuf_put_le16(buf, 0); /* Comeback Delay */

	/* Advertisement Protocol IE */
	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
	wpabuf_put_u8(buf, 2); /* Length */
	wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
	wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */

	/* Query Response */
	len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */

	if (frag_id == 0) {
		/* NQP Query Response Frame */
		wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
		wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
		wpabuf_put_be24(buf, OUI_WFA);
		wpabuf_put_u8(buf, P2P_OUI_TYPE);
		/* Service Update Indicator */
		wpabuf_put_le16(buf, update_indic);
	}

	wpabuf_put_data(buf, data, len);

	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);

	return buf;
}
Example #24
0
/**
 * encrypt_pw_block_with_password_hash - EncryptPwBlobkWithPasswordHash() - RFC 2759, Sect. 8.10
 * @password: 0-to-256-unicode-char Password (IN)
 * @password_len: Length of password
 * @password_hash: 16-octet PasswordHash (IN)
 * @pw_block: 516-byte PwBlock (OUT)
 */
static void encrypt_pw_block_with_password_hash(
	const u8 *password, size_t password_len,
	const u8 *password_hash, u8 *pw_block)
{
	size_t i, offset;
	u8 *pos;

	if (password_len > 256)
		return;

	memset(pw_block, 0, PWBLOCK_LEN);
	offset = (256 - password_len) * 2;
	for (i = 0; i < password_len; i++)
		pw_block[offset + i * 2] = password[i];
	pos = &pw_block[2 * 256];
	WPA_PUT_LE16(pos, password_len * 2);
	rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
}
Example #25
0
u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid)
{
	u8 bitmap;
	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
	*eid++ = 4 + 3 + 1;
	WPA_PUT_BE24(eid, OUI_WFA);
	eid += 3;
	*eid++ = P2P_OUI_TYPE;

	*eid++ = P2P_ATTR_MANAGEABILITY;
	WPA_PUT_LE16(eid, 1);
	eid += 2;
	bitmap = P2P_MAN_DEVICE_MANAGEMENT;
	if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION)
		bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED;
	bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL;
	*eid++ = bitmap;

	return eid;
}
Example #26
0
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
{
	u8 conf;
	if (!hapd->conf->hs20)
		return eid;
	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
	*eid++ = 7;
	WPA_PUT_BE24(eid, OUI_WFA);
	eid += 3;
	*eid++ = HS20_INDICATION_OUI_TYPE;
	conf = HS20_VERSION; /* Release Number */
	conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
	if (hapd->conf->disable_dgaf)
		conf |= HS20_DGAF_DISABLED;
	*eid++ = conf;
	WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
	eid += 2;

	return eid;
}
Example #27
0
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
{
	u8 *group_info;
	struct wpabuf *p2p_subelems, *ie;
	struct p2p_group_member *m;
	size_t extra = 0;

#ifdef CONFIG_WIFI_DISPLAY
	if (group->wfd_ie)
		extra += wpabuf_len(group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */

	p2p_subelems = wpabuf_alloc(500 + extra);
	if (p2p_subelems == NULL)
		return NULL;

#ifdef CONFIG_WIFI_DISPLAY
	if (group->wfd_ie)
		wpabuf_put_buf(p2p_subelems, group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */

	p2p_group_add_common_ies(group, p2p_subelems);
	p2p_group_add_noa(p2p_subelems, group->noa);

	/* P2P Device Info */
	p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);

	/* P2P Group Info */
	group_info = wpabuf_put(p2p_subelems, 0);
	wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
	wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
	for (m = group->members; m; m = m->next)
		p2p_client_info(p2p_subelems, m);
	WPA_PUT_LE16(group_info + 1,
		     (u8 *) wpabuf_put(p2p_subelems, 0) - group_info - 3);

	ie = p2p_group_encaps_probe_resp(p2p_subelems);
	wpabuf_free(p2p_subelems);

	return ie;
}
Example #28
0
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
{
	struct wpabuf *p2p_subelems, *ie;
	struct p2p_group_member *m;

	p2p_subelems = wpabuf_alloc(500);
	if (p2p_subelems == NULL)
		return NULL;

	p2p_group_add_common_ies(group, p2p_subelems);
	p2p_group_add_noa(p2p_subelems, group->noa);

	/* P2P Device Info */
	p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);

	/* P2P Group Info: Only when at least one P2P Client is connected */
	if (group->members) {
		u8 *group_info;
		group_info = wpabuf_put(p2p_subelems, 0);
		wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
		wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
		for (m = group->members; m; m = m->next)
			p2p_client_info(p2p_subelems, m);
		WPA_PUT_LE16(group_info + 1,
			     (u8 *) wpabuf_put(p2p_subelems, 0) - group_info -
			     3);
	}

	ie = p2p_group_encaps_probe_resp(p2p_subelems);
	wpabuf_free(p2p_subelems);

#ifdef CONFIG_WIFI_DISPLAY
	if (group->wfd_ie) {
		struct wpabuf *wfd = wpabuf_dup(group->wfd_ie);
		ie = wpabuf_concat(wfd, ie);
	}
#endif /* CONFIG_WIFI_DISPLAY */

	return ie;
}
Example #29
0
void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
			      struct p2p_channels *chan)
{
	u8 *len;
	size_t i;

	/* Channel List */
	wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST);
	len = wpabuf_put(buf, 2); /* IE length to be filled */
	wpabuf_put_data(buf, country, 3); /* Country String */

	for (i = 0; i < chan->reg_classes; i++) {
		struct p2p_reg_class *c = &chan->reg_class[i];
		wpabuf_put_u8(buf, c->reg_class);
		wpabuf_put_u8(buf, c->channels);
		wpabuf_put_data(buf, c->channel, c->channels);
	}

	/* Update attribute length */
	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
	wpa_printf(MSG_DEBUG, "P2P: * Channel List");
}
Example #30
0
static int wpa_supplicant_process_smk_m2(
	struct wpa_sm *sm, const unsigned char *src_addr,
	const struct wpa_eapol_key *key, size_t extra_len, int ver)
{
	struct wpa_peerkey *peerkey;
	struct wpa_eapol_ie_parse kde;
	struct wpa_ie_data ie;
	int cipher;
	struct rsn_ie_hdr *hdr;
	u8 *pos;

	wpa_printf(MSG_DEBUG, "RSN: Received SMK M2");

	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
		wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for "
			   "the current network");
		return -1;
	}

	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
	    0) {
		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
		return -1;
	}

	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
	    kde.mac_addr_len < ETH_ALEN) {
		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
			   "SMK M2");
		return -1;
	}

	wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR,
		   MAC2STR(kde.mac_addr));

	if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) {
		wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK "
			   "M2");
		return -1;
	}

	if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
		wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2");
		return -1;
	}

	cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
	if (cipher & WPA_CIPHER_CCMP) {
		wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
		cipher = WPA_CIPHER_CCMP;
	} else if (cipher & WPA_CIPHER_TKIP) {
		wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
		cipher = WPA_CIPHER_TKIP;
	} else {
		wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
		wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
					      STK_MUI_SMK, STK_ERR_CPHR_NS,
					      ver);
		return -1;
	}

	/* TODO: find existing entry and if found, use that instead of adding
	 * a new one; how to handle the case where both ends initiate at the
	 * same time? */
	peerkey = os_zalloc(sizeof(*peerkey));
	if (peerkey == NULL)
		return -1;
	os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
	os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
	peerkey->rsnie_i_len = kde.rsn_ie_len;
	peerkey->cipher = cipher;
#ifdef CONFIG_IEEE80211W
	if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
			   WPA_KEY_MGMT_PSK_SHA256))
		peerkey->use_sha256 = 1;
#endif /* CONFIG_IEEE80211W */

	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
			"WPA: Failed to get random data for PNonce");
		wpa_supplicant_peerkey_free(sm, peerkey);
		return -1;
	}

	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p;
	hdr->elem_id = WLAN_EID_RSN;
	WPA_PUT_LE16(hdr->version, RSN_VERSION);
	pos = (u8 *) (hdr + 1);
	/* Group Suite can be anything for SMK RSN IE; receiver will just
	 * ignore it. */
	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
	pos += RSN_SELECTOR_LEN;
	/* Include only the selected cipher in pairwise cipher suite */
	WPA_PUT_LE16(pos, 1);
	pos += 2;
	if (cipher == WPA_CIPHER_CCMP)
		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
	else if (cipher == WPA_CIPHER_TKIP)
		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
	pos += RSN_SELECTOR_LEN;

	hdr->len = (pos - peerkey->rsnie_p) - 2;
	peerkey->rsnie_p_len = pos - peerkey->rsnie_p;
	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
		    peerkey->rsnie_p, peerkey->rsnie_p_len);

	wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey);

	peerkey->next = sm->peerkey;
	sm->peerkey = peerkey;

	return 0;
}