1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/*
2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * WPA/RSN - Shared functions for supplicant and authenticator
3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify
6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as
7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation.
8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license.
11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details.
13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h"
16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h"
18b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/md5.h"
19b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/sha1.h"
20b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/sha256.h"
21b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/aes_wrap.h"
22b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/crypto.h"
23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "ieee802_11_defs.h"
24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "defs.h"
25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "wpa_common.h"
26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @key: EAPOL-Key Key Confirmation Key (KCK)
31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @buf: Pointer to the beginning of the EAPOL header (version field)
33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, -1 on failure
36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * to be cleared (all zeroes) when calling this function.
39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * description of the Key MIC calculation. It includes packet data from the
42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * happened during final editing of the standard and the correct behavior is
44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * defined in the last draft (IEEE 802.11i/D10).
45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		      u8 *mic)
48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 hash[SHA1_MAC_LEN];
50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	switch (ver) {
52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		hmac_md5(key, 16, buf, len, mic);
54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		hmac_sha1(key, 16, buf, len, hash);
57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(mic, hash, MD5_MAC_LEN);
58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		break;
59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return omac1_aes_128(key, buf, len, mic);
62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	default:
64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmk: Pairwise master key
74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmk_len: Length of PMK
75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @label: Label to use in derivation
76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @addr1: AA or SA
77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @addr2: SA or AA
78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @nonce1: ANonce or SNonce
79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @nonce2: SNonce or ANonce
80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ptk: Buffer for pairwise transient key
81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ptk_len: Length of PTK
82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @use_sha256: Whether to use SHA256-based KDF
83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * PTK = PRF-X(PMK, "Pairwise key expansion",
86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *             Min(AA, SA) || Max(AA, SA) ||
87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * STK = PRF-X(SMK, "Peer key expansion",
90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *             Min(INonce, PNonce) || Max(INonce, PNonce))
92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    const u8 *addr1, const u8 *addr2,
95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    const u8 *nonce1, const u8 *nonce2,
96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		    u8 *ptk, size_t ptk_len, int use_sha256)
97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data, addr1, ETH_ALEN);
102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data, addr2, ETH_ALEN);
105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  WPA_NONCE_LEN);
112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else {
113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			  WPA_NONCE_LEN);
116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W
119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (use_sha256)
120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   ptk, ptk_len);
122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	else
123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */
124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 ptk_len);
126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   MAC2STR(addr1), MAC2STR(addr2));
129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211R
135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	       const u8 *ftie, size_t ftie_len,
138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	       const u8 *rsnie, size_t rsnie_len,
139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	       const u8 *ric, size_t ric_len, u8 *mic)
140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *buf, *pos;
142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t buf_len;
143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	buf = os_malloc(buf_len);
146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (buf == NULL)
147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = buf;
150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, sta_addr, ETH_ALEN);
151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += ETH_ALEN;
152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, ap_addr, ETH_ALEN);
153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += ETH_ALEN;
154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*pos++ = transaction_seqnum;
155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (rsnie) {
156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(pos, rsnie, rsnie_len);
157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += rsnie_len;
158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (mdie) {
160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(pos, mdie, mdie_len);
161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += mdie_len;
162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ftie) {
164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		struct rsn_ftie *_ftie;
165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(pos, ftie, ftie_len);
166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (ftie_len < 2 + sizeof(*_ftie)) {
167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			os_free(buf);
168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		_ftie = (struct rsn_ftie *) (pos + 2);
171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += ftie_len;
173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ric) {
175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_memcpy(pos, ric, ric_len);
176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += ric_len;
177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		os_free(buf);
182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_free(buf);
186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211R */
190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifndef CONFIG_NO_WPA2
193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int rsn_selector_to_bitfield(const u8 *s)
194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_CIPHER_NONE;
197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_CIPHER_WEP40;
199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_CIPHER_TKIP;
201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_CIPHER_CCMP;
203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_CIPHER_WEP104;
205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W
206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_CIPHER_AES_128_CMAC;
208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */
209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int rsn_key_mgmt_to_bitfield(const u8 *s)
214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X;
217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_KEY_MGMT_PSK;
219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211R
220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_KEY_MGMT_FT_IEEE8021X;
222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_KEY_MGMT_FT_PSK;
224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211R */
225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W
226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_KEY_MGMT_IEEE8021X_SHA256;
228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return WPA_KEY_MGMT_PSK_SHA256;
230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */
231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_NO_WPA2 */
234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_parse_wpa_ie_rsn - Parse RSN IE
238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @rsn_ie: Buffer containing RSN IE
239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @data: Pointer to structure that will be filled in with parsed data
241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 on success, <0 on failure
242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			 struct wpa_ie_data *data)
245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifndef CONFIG_NO_WPA2
247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const struct rsn_ie_hdr *hdr;
248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *pos;
249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int left;
250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	int i, count;
251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memset(data, 0, sizeof(*data));
253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->proto = WPA_PROTO_RSN;
254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->pairwise_cipher = WPA_CIPHER_CCMP;
255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->group_cipher = WPA_CIPHER_CCMP;
256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->capabilities = 0;
258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->pmkid = NULL;
259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->num_pmkid = 0;
260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W
261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* CONFIG_IEEE80211W */
263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	data->mgmt_group_cipher = 0;
264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */
265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (rsn_ie_len == 0) {
267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		/* No RSN IE - fail silently */
268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   __func__, (unsigned long) rsn_ie_len);
274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -1;
275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	hdr = (const struct rsn_ie_hdr *) rsn_ie;
278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (hdr->elem_id != WLAN_EID_RSN ||
280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    hdr->len != rsn_ie_len - 2 ||
281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   __func__);
284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -2;
285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = (const u8 *) (hdr + 1);
288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	left = rsn_ie_len - sizeof(*hdr);
289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (left >= RSN_SELECTOR_LEN) {
291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->group_cipher = rsn_selector_to_bitfield(pos);
292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W
293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "cipher", __func__);
296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */
299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += RSN_SELECTOR_LEN;
300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		left -= RSN_SELECTOR_LEN;
301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (left > 0) {
302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   __func__, left);
304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -3;
305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (left >= 2) {
308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->pairwise_cipher = 0;
309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		count = WPA_GET_LE16(pos);
310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 2;
311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		left -= 2;
312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "count %u left %u", __func__, count, left);
315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -4;
316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		for (i = 0; i < count; i++) {
318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos += RSN_SELECTOR_LEN;
320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			left -= RSN_SELECTOR_LEN;
321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W
323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "pairwise cipher", __func__);
326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -1;
327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */
329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (left == 1) {
330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   __func__);
332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -5;
333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (left >= 2) {
336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->key_mgmt = 0;
337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		count = WPA_GET_LE16(pos);
338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 2;
339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		left -= 2;
340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "count %u left %u", __func__, count, left);
343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -6;
344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		for (i = 0; i < count; i++) {
346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos += RSN_SELECTOR_LEN;
348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			left -= RSN_SELECTOR_LEN;
349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	} else if (left == 1) {
351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   __func__);
353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return -7;
354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (left >= 2) {
357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->capabilities = WPA_GET_LE16(pos);
358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 2;
359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		left -= 2;
360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (left >= 2) {
363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->num_pmkid = WPA_GET_LE16(pos);
364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += 2;
365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		left -= 2;
366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (left < (int) data->num_pmkid * PMKID_LEN) {
367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "(num_pmkid=%lu left=%d)",
369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   __func__, (unsigned long) data->num_pmkid,
370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   left);
371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->num_pmkid = 0;
372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -9;
373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		} else {
374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			data->pmkid = pos;
375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			pos += data->num_pmkid * PMKID_LEN;
376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			left -= data->num_pmkid * PMKID_LEN;
377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W
381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (left >= 4) {
382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   "group cipher 0x%x", __func__,
386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt				   data->mgmt_group_cipher);
387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			return -10;
388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		}
389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		pos += RSN_SELECTOR_LEN;
390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		left -= RSN_SELECTOR_LEN;
391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */
393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (left > 0) {
395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			   __func__, left);
397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	}
398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return 0;
400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* CONFIG_NO_WPA2 */
401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	return -1;
402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_NO_WPA2 */
403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211R
407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.3
412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       const u8 *ssid, size_t ssid_len,
415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *pos, r0_key_data[48], hash[32];
421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *addr[2];
422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len[2];
423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 *                       SSIDlength || SSID || MDID || R0KHlength ||
427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 *                       R0KH-ID || S0KH-ID)
428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * XXKey is either the second 256 bits of MSK or PSK.
429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * PMK-R0 = L(R0-Key-Data, 0, 256)
430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		return;
434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = buf;
435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*pos++ = ssid_len;
436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, ssid, ssid_len);
437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += ssid_len;
438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += MOBILITY_DOMAIN_ID_LEN;
440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	*pos++ = r0kh_id_len;
441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, r0kh_id, r0kh_id_len);
442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += r0kh_id_len;
443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, s0kh_id, ETH_ALEN);
444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += ETH_ALEN;
445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		   r0_key_data, sizeof(r0_key_data));
448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[0] = (const u8 *) "FT-R0N";
454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[0] = 6;
455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[1] = r0_key_data + PMK_LEN;
456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[1] = 16;
457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sha256_vector(2, addr, len, hash);
459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_derive_pmk_r1_name - Derive PMKR1Name
465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.4
467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt			    const u8 *s1kh_id, u8 *pmk_r1_name)
470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 hash[32];
472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *addr[4];
473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len[4];
474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 *                                  R1KH-ID || S1KH-ID))
478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[0] = (const u8 *) "FT-R1N";
480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[0] = 6;
481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[1] = pmk_r0_name;
482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[1] = WPA_PMK_NAME_LEN;
483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[2] = r1kh_id;
484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[2] = FT_R1KH_ID_LEN;
485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[3] = s1kh_id;
486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[3] = ETH_ALEN;
487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sha256_vector(4, addr, len, hash);
489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.4
497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       const u8 *r1kh_id, const u8 *s1kh_id,
500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       u8 *pmk_r1, u8 *pmk_r1_name)
501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *pos;
504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = buf;
507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += FT_R1KH_ID_LEN;
509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, s1kh_id, ETH_ALEN);
510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += ETH_ALEN;
511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/**
519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *
521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * IEEE Std 802.11r-2008 - 8.5.1.5.5
522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */
523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       const u8 *sta_addr, const u8 *bssid,
525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       const u8 *pmk_r1_name,
526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt		       u8 *ptk, size_t ptk_len, u8 *ptk_name)
527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{
528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	u8 *pos, hash[32];
530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	const u8 *addr[6];
531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	size_t len[6];
532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 *                  BSSID || STA-ADDR)
536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos = buf;
538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, snonce, WPA_NONCE_LEN);
539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += WPA_NONCE_LEN;
540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, anonce, WPA_NONCE_LEN);
541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += WPA_NONCE_LEN;
542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, bssid, ETH_ALEN);
543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += ETH_ALEN;
544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(pos, sta_addr, ETH_ALEN);
545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	pos += ETH_ALEN;
546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	/*
550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 *                                ANonce || BSSID || STA-ADDR))
552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	 */
553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[0] = pmk_r1_name;
554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[0] = WPA_PMK_NAME_LEN;
555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[1] = (const u8 *) "FT-PTKN";
556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[1] = 7;
557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[2] = snonce;
558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[2] = WPA_NONCE_LEN;
559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[3] = anonce;
560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[3] = WPA_NONCE_LEN;
561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[4] = bssid;
562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[4] = ETH_ALEN;
563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	addr[5] = sta_addr;
564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	len[5] = ETH_ALEN;
565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	sha256_vector(6, addr, len, hash);
567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}
569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt
570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211R */
571