13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * hostapd - IEEE 802.11r - Fast BSS Transition
3*a1157835SDaniel Fojt  * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "utils/includes.h"
103ff40c12SJohn Marino 
113ff40c12SJohn Marino #include "utils/common.h"
12*a1157835SDaniel Fojt #include "utils/eloop.h"
13*a1157835SDaniel Fojt #include "utils/list.h"
143ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
153ff40c12SJohn Marino #include "common/ieee802_11_common.h"
16*a1157835SDaniel Fojt #include "common/ocv.h"
17*a1157835SDaniel Fojt #include "drivers/driver.h"
18*a1157835SDaniel Fojt #include "crypto/aes.h"
19*a1157835SDaniel Fojt #include "crypto/aes_siv.h"
203ff40c12SJohn Marino #include "crypto/aes_wrap.h"
21*a1157835SDaniel Fojt #include "crypto/sha384.h"
223ff40c12SJohn Marino #include "crypto/random.h"
233ff40c12SJohn Marino #include "ap_config.h"
243ff40c12SJohn Marino #include "ieee802_11.h"
253ff40c12SJohn Marino #include "wmm.h"
263ff40c12SJohn Marino #include "wpa_auth.h"
273ff40c12SJohn Marino #include "wpa_auth_i.h"
28*a1157835SDaniel Fojt #include "pmksa_cache_auth.h"
293ff40c12SJohn Marino 
303ff40c12SJohn Marino 
31*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R_AP
32*a1157835SDaniel Fojt 
33*a1157835SDaniel Fojt const unsigned int ftRRBseqTimeout = 10;
34*a1157835SDaniel Fojt const unsigned int ftRRBmaxQueueLen = 100;
35*a1157835SDaniel Fojt 
36*a1157835SDaniel Fojt 
37*a1157835SDaniel Fojt static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
38*a1157835SDaniel Fojt 				     const u8 *current_ap, const u8 *sta_addr,
39*a1157835SDaniel Fojt 				     u16 status, const u8 *resp_ies,
40*a1157835SDaniel Fojt 				     size_t resp_ies_len);
41*a1157835SDaniel Fojt static void ft_finish_pull(struct wpa_state_machine *sm);
42*a1157835SDaniel Fojt static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx);
43*a1157835SDaniel Fojt static void wpa_ft_rrb_seq_timeout(void *eloop_ctx, void *timeout_ctx);
44*a1157835SDaniel Fojt 
45*a1157835SDaniel Fojt struct tlv_list {
46*a1157835SDaniel Fojt 	u16 type;
47*a1157835SDaniel Fojt 	size_t len;
48*a1157835SDaniel Fojt 	const u8 *data;
49*a1157835SDaniel Fojt };
50*a1157835SDaniel Fojt 
51*a1157835SDaniel Fojt 
52*a1157835SDaniel Fojt /**
53*a1157835SDaniel Fojt  * wpa_ft_rrb_decrypt - Decrypt FT RRB message
54*a1157835SDaniel Fojt  * @key: AES-SIV key for AEAD
55*a1157835SDaniel Fojt  * @key_len: Length of key in octets
56*a1157835SDaniel Fojt  * @enc: Pointer to encrypted TLVs
57*a1157835SDaniel Fojt  * @enc_len: Length of encrypted TLVs in octets
58*a1157835SDaniel Fojt  * @auth: Pointer to authenticated TLVs
59*a1157835SDaniel Fojt  * @auth_len: Length of authenticated TLVs in octets
60*a1157835SDaniel Fojt  * @src_addr: MAC address of the frame sender
61*a1157835SDaniel Fojt  * @type: Vendor-specific subtype of the RRB frame (FT_PACKET_*)
62*a1157835SDaniel Fojt  * @plain: Pointer to return the pointer to the allocated plaintext buffer;
63*a1157835SDaniel Fojt  *	needs to be freed by the caller if not NULL;
64*a1157835SDaniel Fojt  *	will only be returned on success
65*a1157835SDaniel Fojt  * @plain_len: Pointer to return the length of the allocated plaintext buffer
66*a1157835SDaniel Fojt  *	in octets
67*a1157835SDaniel Fojt  * Returns: 0 on success, -1 on error
68*a1157835SDaniel Fojt  */
wpa_ft_rrb_decrypt(const u8 * key,const size_t key_len,const u8 * enc,size_t enc_len,const u8 * auth,const size_t auth_len,const u8 * src_addr,u8 type,u8 ** plain,size_t * plain_size)69*a1157835SDaniel Fojt static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len,
70*a1157835SDaniel Fojt 			      const u8 *enc, size_t enc_len,
71*a1157835SDaniel Fojt 			      const u8 *auth, const size_t auth_len,
72*a1157835SDaniel Fojt 			      const u8 *src_addr, u8 type,
73*a1157835SDaniel Fojt 			      u8 **plain, size_t *plain_size)
74*a1157835SDaniel Fojt {
75*a1157835SDaniel Fojt 	const u8 *ad[3] = { src_addr, auth, &type };
76*a1157835SDaniel Fojt 	size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
77*a1157835SDaniel Fojt 
78*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
79*a1157835SDaniel Fojt 		   MAC2STR(src_addr), type);
80*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypt using key", key, key_len);
81*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs", enc, enc_len);
82*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
83*a1157835SDaniel Fojt 
84*a1157835SDaniel Fojt 	if (!key) { /* skip decryption */
85*a1157835SDaniel Fojt 		*plain = os_memdup(enc, enc_len);
86*a1157835SDaniel Fojt 		if (enc_len > 0 && !*plain)
87*a1157835SDaniel Fojt 			goto err;
88*a1157835SDaniel Fojt 
89*a1157835SDaniel Fojt 		*plain_size = enc_len;
90*a1157835SDaniel Fojt 
91*a1157835SDaniel Fojt 		return 0;
92*a1157835SDaniel Fojt 	}
93*a1157835SDaniel Fojt 
94*a1157835SDaniel Fojt 	*plain = NULL;
95*a1157835SDaniel Fojt 
96*a1157835SDaniel Fojt 	/* SIV overhead */
97*a1157835SDaniel Fojt 	if (enc_len < AES_BLOCK_SIZE)
98*a1157835SDaniel Fojt 		goto err;
99*a1157835SDaniel Fojt 
100*a1157835SDaniel Fojt 	*plain = os_zalloc(enc_len - AES_BLOCK_SIZE);
101*a1157835SDaniel Fojt 	if (!*plain)
102*a1157835SDaniel Fojt 		goto err;
103*a1157835SDaniel Fojt 
104*a1157835SDaniel Fojt 	if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
105*a1157835SDaniel Fojt 			    *plain) < 0) {
106*a1157835SDaniel Fojt 		if (enc_len < AES_BLOCK_SIZE + 2)
107*a1157835SDaniel Fojt 			goto err;
108*a1157835SDaniel Fojt 
109*a1157835SDaniel Fojt 		/* Try to work around Ethernet devices that add extra
110*a1157835SDaniel Fojt 		 * two octet padding even if the frame is longer than
111*a1157835SDaniel Fojt 		 * the minimum Ethernet frame. */
112*a1157835SDaniel Fojt 		enc_len -= 2;
113*a1157835SDaniel Fojt 		if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len,
114*a1157835SDaniel Fojt 				    *plain) < 0)
115*a1157835SDaniel Fojt 			goto err;
116*a1157835SDaniel Fojt 	}
117*a1157835SDaniel Fojt 
118*a1157835SDaniel Fojt 	*plain_size = enc_len - AES_BLOCK_SIZE;
119*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypted TLVs",
120*a1157835SDaniel Fojt 			*plain, *plain_size);
121*a1157835SDaniel Fojt 	return 0;
122*a1157835SDaniel Fojt err:
123*a1157835SDaniel Fojt 	os_free(*plain);
124*a1157835SDaniel Fojt 	*plain = NULL;
125*a1157835SDaniel Fojt 	*plain_size = 0;
126*a1157835SDaniel Fojt 
127*a1157835SDaniel Fojt 	wpa_printf(MSG_ERROR, "FT(RRB): Failed to decrypt");
128*a1157835SDaniel Fojt 
129*a1157835SDaniel Fojt 	return -1;
130*a1157835SDaniel Fojt }
131*a1157835SDaniel Fojt 
132*a1157835SDaniel Fojt 
133*a1157835SDaniel Fojt /* get first tlv record in packet matching type
134*a1157835SDaniel Fojt  * @data (decrypted) packet
135*a1157835SDaniel Fojt  * @return 0 on success else -1
136*a1157835SDaniel Fojt  */
wpa_ft_rrb_get_tlv(const u8 * plain,size_t plain_len,u16 type,size_t * tlv_len,const u8 ** tlv_data)137*a1157835SDaniel Fojt static int wpa_ft_rrb_get_tlv(const u8 *plain, size_t plain_len,
138*a1157835SDaniel Fojt 			      u16 type, size_t *tlv_len, const u8 **tlv_data)
139*a1157835SDaniel Fojt {
140*a1157835SDaniel Fojt 	const struct ft_rrb_tlv *f;
141*a1157835SDaniel Fojt 	size_t left;
142*a1157835SDaniel Fojt 	le16 type16;
143*a1157835SDaniel Fojt 	size_t len;
144*a1157835SDaniel Fojt 
145*a1157835SDaniel Fojt 	left = plain_len;
146*a1157835SDaniel Fojt 	type16 = host_to_le16(type);
147*a1157835SDaniel Fojt 
148*a1157835SDaniel Fojt 	while (left >= sizeof(*f)) {
149*a1157835SDaniel Fojt 		f = (const struct ft_rrb_tlv *) plain;
150*a1157835SDaniel Fojt 
151*a1157835SDaniel Fojt 		left -= sizeof(*f);
152*a1157835SDaniel Fojt 		plain += sizeof(*f);
153*a1157835SDaniel Fojt 		len = le_to_host16(f->len);
154*a1157835SDaniel Fojt 
155*a1157835SDaniel Fojt 		if (left < len) {
156*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "FT: RRB message truncated");
157*a1157835SDaniel Fojt 			break;
158*a1157835SDaniel Fojt 		}
159*a1157835SDaniel Fojt 
160*a1157835SDaniel Fojt 		if (f->type == type16) {
161*a1157835SDaniel Fojt 			*tlv_len = len;
162*a1157835SDaniel Fojt 			*tlv_data = plain;
163*a1157835SDaniel Fojt 			return 0;
164*a1157835SDaniel Fojt 		}
165*a1157835SDaniel Fojt 
166*a1157835SDaniel Fojt 		left -= len;
167*a1157835SDaniel Fojt 		plain += len;
168*a1157835SDaniel Fojt 	}
169*a1157835SDaniel Fojt 
170*a1157835SDaniel Fojt 	return -1;
171*a1157835SDaniel Fojt }
172*a1157835SDaniel Fojt 
173*a1157835SDaniel Fojt 
wpa_ft_rrb_dump(const u8 * plain,const size_t plain_len)174*a1157835SDaniel Fojt static void wpa_ft_rrb_dump(const u8 *plain, const size_t plain_len)
175*a1157835SDaniel Fojt {
176*a1157835SDaniel Fojt 	const struct ft_rrb_tlv *f;
177*a1157835SDaniel Fojt 	size_t left;
178*a1157835SDaniel Fojt 	size_t len;
179*a1157835SDaniel Fojt 
180*a1157835SDaniel Fojt 	left = plain_len;
181*a1157835SDaniel Fojt 
182*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: RRB dump message");
183*a1157835SDaniel Fojt 	while (left >= sizeof(*f)) {
184*a1157835SDaniel Fojt 		f = (const struct ft_rrb_tlv *) plain;
185*a1157835SDaniel Fojt 
186*a1157835SDaniel Fojt 		left -= sizeof(*f);
187*a1157835SDaniel Fojt 		plain += sizeof(*f);
188*a1157835SDaniel Fojt 		len = le_to_host16(f->len);
189*a1157835SDaniel Fojt 
190*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: RRB TLV type = %d, len = %zu",
191*a1157835SDaniel Fojt 			   le_to_host16(f->type), len);
192*a1157835SDaniel Fojt 
193*a1157835SDaniel Fojt 		if (left < len) {
194*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
195*a1157835SDaniel Fojt 				   "FT: RRB message truncated: left %zu bytes, need %zu",
196*a1157835SDaniel Fojt 				   left, len);
197*a1157835SDaniel Fojt 			break;
198*a1157835SDaniel Fojt 		}
199*a1157835SDaniel Fojt 
200*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FT: RRB TLV data", plain, len);
201*a1157835SDaniel Fojt 
202*a1157835SDaniel Fojt 		left -= len;
203*a1157835SDaniel Fojt 		plain += len;
204*a1157835SDaniel Fojt 	}
205*a1157835SDaniel Fojt 
206*a1157835SDaniel Fojt 	if (left > 0)
207*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FT: RRB TLV padding", plain, left);
208*a1157835SDaniel Fojt 
209*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: RRB dump message end");
210*a1157835SDaniel Fojt }
211*a1157835SDaniel Fojt 
212*a1157835SDaniel Fojt 
cmp_int(const void * a,const void * b)213*a1157835SDaniel Fojt static int cmp_int(const void *a, const void *b)
214*a1157835SDaniel Fojt {
215*a1157835SDaniel Fojt 	int x, y;
216*a1157835SDaniel Fojt 
217*a1157835SDaniel Fojt 	x = *((int *) a);
218*a1157835SDaniel Fojt 	y = *((int *) b);
219*a1157835SDaniel Fojt 	return x - y;
220*a1157835SDaniel Fojt }
221*a1157835SDaniel Fojt 
222*a1157835SDaniel Fojt 
wpa_ft_rrb_get_tlv_vlan(const u8 * plain,const size_t plain_len,struct vlan_description * vlan)223*a1157835SDaniel Fojt static int wpa_ft_rrb_get_tlv_vlan(const u8 *plain, const size_t plain_len,
224*a1157835SDaniel Fojt 				   struct vlan_description *vlan)
225*a1157835SDaniel Fojt {
226*a1157835SDaniel Fojt 	struct ft_rrb_tlv *f;
227*a1157835SDaniel Fojt 	size_t left;
228*a1157835SDaniel Fojt 	size_t len;
229*a1157835SDaniel Fojt 	int taggedidx;
230*a1157835SDaniel Fojt 	int vlan_id;
231*a1157835SDaniel Fojt 	int type;
232*a1157835SDaniel Fojt 
233*a1157835SDaniel Fojt 	left = plain_len;
234*a1157835SDaniel Fojt 	taggedidx = 0;
235*a1157835SDaniel Fojt 	os_memset(vlan, 0, sizeof(*vlan));
236*a1157835SDaniel Fojt 
237*a1157835SDaniel Fojt 	while (left >= sizeof(*f)) {
238*a1157835SDaniel Fojt 		f = (struct ft_rrb_tlv *) plain;
239*a1157835SDaniel Fojt 
240*a1157835SDaniel Fojt 		left -= sizeof(*f);
241*a1157835SDaniel Fojt 		plain += sizeof(*f);
242*a1157835SDaniel Fojt 
243*a1157835SDaniel Fojt 		len = le_to_host16(f->len);
244*a1157835SDaniel Fojt 		type = le_to_host16(f->type);
245*a1157835SDaniel Fojt 
246*a1157835SDaniel Fojt 		if (left < len) {
247*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "FT: RRB message truncated");
248*a1157835SDaniel Fojt 			return -1;
249*a1157835SDaniel Fojt 		}
250*a1157835SDaniel Fojt 
251*a1157835SDaniel Fojt 		if (type != FT_RRB_VLAN_UNTAGGED && type != FT_RRB_VLAN_TAGGED)
252*a1157835SDaniel Fojt 			goto skip;
253*a1157835SDaniel Fojt 
254*a1157835SDaniel Fojt 		if (type == FT_RRB_VLAN_UNTAGGED && len != sizeof(le16)) {
255*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
256*a1157835SDaniel Fojt 				   "FT: RRB VLAN_UNTAGGED invalid length");
257*a1157835SDaniel Fojt 			return -1;
258*a1157835SDaniel Fojt 		}
259*a1157835SDaniel Fojt 
260*a1157835SDaniel Fojt 		if (type == FT_RRB_VLAN_TAGGED && len % sizeof(le16) != 0) {
261*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
262*a1157835SDaniel Fojt 				   "FT: RRB VLAN_TAGGED invalid length");
263*a1157835SDaniel Fojt 			return -1;
264*a1157835SDaniel Fojt 		}
265*a1157835SDaniel Fojt 
266*a1157835SDaniel Fojt 		while (len >= sizeof(le16)) {
267*a1157835SDaniel Fojt 			vlan_id = WPA_GET_LE16(plain);
268*a1157835SDaniel Fojt 			plain += sizeof(le16);
269*a1157835SDaniel Fojt 			left -= sizeof(le16);
270*a1157835SDaniel Fojt 			len -= sizeof(le16);
271*a1157835SDaniel Fojt 
272*a1157835SDaniel Fojt 			if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) {
273*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
274*a1157835SDaniel Fojt 					   "FT: RRB VLAN ID invalid %d",
275*a1157835SDaniel Fojt 					   vlan_id);
276*a1157835SDaniel Fojt 				continue;
277*a1157835SDaniel Fojt 			}
278*a1157835SDaniel Fojt 
279*a1157835SDaniel Fojt 			if (type == FT_RRB_VLAN_UNTAGGED)
280*a1157835SDaniel Fojt 				vlan->untagged = vlan_id;
281*a1157835SDaniel Fojt 
282*a1157835SDaniel Fojt 			if (type == FT_RRB_VLAN_TAGGED &&
283*a1157835SDaniel Fojt 			    taggedidx < MAX_NUM_TAGGED_VLAN) {
284*a1157835SDaniel Fojt 				vlan->tagged[taggedidx] = vlan_id;
285*a1157835SDaniel Fojt 				taggedidx++;
286*a1157835SDaniel Fojt 			} else if (type == FT_RRB_VLAN_TAGGED) {
287*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG, "FT: RRB too many VLANs");
288*a1157835SDaniel Fojt 			}
289*a1157835SDaniel Fojt 		}
290*a1157835SDaniel Fojt 
291*a1157835SDaniel Fojt 	skip:
292*a1157835SDaniel Fojt 		left -= len;
293*a1157835SDaniel Fojt 		plain += len;
294*a1157835SDaniel Fojt 	}
295*a1157835SDaniel Fojt 
296*a1157835SDaniel Fojt 	if (taggedidx)
297*a1157835SDaniel Fojt 		qsort(vlan->tagged, taggedidx, sizeof(int), cmp_int);
298*a1157835SDaniel Fojt 
299*a1157835SDaniel Fojt 	vlan->notempty = vlan->untagged || vlan->tagged[0];
300*a1157835SDaniel Fojt 
301*a1157835SDaniel Fojt 	return 0;
302*a1157835SDaniel Fojt }
303*a1157835SDaniel Fojt 
304*a1157835SDaniel Fojt 
wpa_ft_tlv_len(const struct tlv_list * tlvs)305*a1157835SDaniel Fojt static size_t wpa_ft_tlv_len(const struct tlv_list *tlvs)
306*a1157835SDaniel Fojt {
307*a1157835SDaniel Fojt 	size_t tlv_len = 0;
308*a1157835SDaniel Fojt 	int i;
309*a1157835SDaniel Fojt 
310*a1157835SDaniel Fojt 	if (!tlvs)
311*a1157835SDaniel Fojt 		return 0;
312*a1157835SDaniel Fojt 
313*a1157835SDaniel Fojt 	for (i = 0; tlvs[i].type != FT_RRB_LAST_EMPTY; i++) {
314*a1157835SDaniel Fojt 		tlv_len += sizeof(struct ft_rrb_tlv);
315*a1157835SDaniel Fojt 		tlv_len += tlvs[i].len;
316*a1157835SDaniel Fojt 	}
317*a1157835SDaniel Fojt 
318*a1157835SDaniel Fojt 	return tlv_len;
319*a1157835SDaniel Fojt }
320*a1157835SDaniel Fojt 
321*a1157835SDaniel Fojt 
wpa_ft_tlv_lin(const struct tlv_list * tlvs,u8 * start,u8 * endpos)322*a1157835SDaniel Fojt static size_t wpa_ft_tlv_lin(const struct tlv_list *tlvs, u8 *start,
323*a1157835SDaniel Fojt 			     u8 *endpos)
324*a1157835SDaniel Fojt {
325*a1157835SDaniel Fojt 	int i;
326*a1157835SDaniel Fojt 	size_t tlv_len;
327*a1157835SDaniel Fojt 	struct ft_rrb_tlv *hdr;
328*a1157835SDaniel Fojt 	u8 *pos;
329*a1157835SDaniel Fojt 
330*a1157835SDaniel Fojt 	if (!tlvs)
331*a1157835SDaniel Fojt 		return 0;
332*a1157835SDaniel Fojt 
333*a1157835SDaniel Fojt 	tlv_len = 0;
334*a1157835SDaniel Fojt 	pos = start;
335*a1157835SDaniel Fojt 	for (i = 0; tlvs[i].type != FT_RRB_LAST_EMPTY; i++) {
336*a1157835SDaniel Fojt 		if (tlv_len + sizeof(*hdr) > (size_t) (endpos - start))
337*a1157835SDaniel Fojt 			return tlv_len;
338*a1157835SDaniel Fojt 		tlv_len += sizeof(*hdr);
339*a1157835SDaniel Fojt 		hdr = (struct ft_rrb_tlv *) pos;
340*a1157835SDaniel Fojt 		hdr->type = host_to_le16(tlvs[i].type);
341*a1157835SDaniel Fojt 		hdr->len = host_to_le16(tlvs[i].len);
342*a1157835SDaniel Fojt 		pos = start + tlv_len;
343*a1157835SDaniel Fojt 
344*a1157835SDaniel Fojt 		if (tlv_len + tlvs[i].len > (size_t) (endpos - start))
345*a1157835SDaniel Fojt 			return tlv_len;
346*a1157835SDaniel Fojt 		if (tlvs[i].len == 0)
347*a1157835SDaniel Fojt 			continue;
348*a1157835SDaniel Fojt 		tlv_len += tlvs[i].len;
349*a1157835SDaniel Fojt 		os_memcpy(pos, tlvs[i].data, tlvs[i].len);
350*a1157835SDaniel Fojt 		pos = start + tlv_len;
351*a1157835SDaniel Fojt 	}
352*a1157835SDaniel Fojt 
353*a1157835SDaniel Fojt 	return tlv_len;
354*a1157835SDaniel Fojt }
355*a1157835SDaniel Fojt 
356*a1157835SDaniel Fojt 
wpa_ft_vlan_len(const struct vlan_description * vlan)357*a1157835SDaniel Fojt static size_t wpa_ft_vlan_len(const struct vlan_description *vlan)
358*a1157835SDaniel Fojt {
359*a1157835SDaniel Fojt 	size_t tlv_len = 0;
360*a1157835SDaniel Fojt 	int i;
361*a1157835SDaniel Fojt 
362*a1157835SDaniel Fojt 	if (!vlan || !vlan->notempty)
363*a1157835SDaniel Fojt 		return 0;
364*a1157835SDaniel Fojt 
365*a1157835SDaniel Fojt 	if (vlan->untagged) {
366*a1157835SDaniel Fojt 		tlv_len += sizeof(struct ft_rrb_tlv);
367*a1157835SDaniel Fojt 		tlv_len += sizeof(le16);
368*a1157835SDaniel Fojt 	}
369*a1157835SDaniel Fojt 	if (vlan->tagged[0])
370*a1157835SDaniel Fojt 		tlv_len += sizeof(struct ft_rrb_tlv);
371*a1157835SDaniel Fojt 	for (i = 0; i < MAX_NUM_TAGGED_VLAN && vlan->tagged[i]; i++)
372*a1157835SDaniel Fojt 		tlv_len += sizeof(le16);
373*a1157835SDaniel Fojt 
374*a1157835SDaniel Fojt 	return tlv_len;
375*a1157835SDaniel Fojt }
376*a1157835SDaniel Fojt 
377*a1157835SDaniel Fojt 
wpa_ft_vlan_lin(const struct vlan_description * vlan,u8 * start,u8 * endpos)378*a1157835SDaniel Fojt static size_t wpa_ft_vlan_lin(const struct vlan_description *vlan,
379*a1157835SDaniel Fojt 			      u8 *start, u8 *endpos)
380*a1157835SDaniel Fojt {
381*a1157835SDaniel Fojt 	size_t tlv_len;
382*a1157835SDaniel Fojt 	int i, len;
383*a1157835SDaniel Fojt 	struct ft_rrb_tlv *hdr;
384*a1157835SDaniel Fojt 	u8 *pos = start;
385*a1157835SDaniel Fojt 
386*a1157835SDaniel Fojt 	if (!vlan || !vlan->notempty)
387*a1157835SDaniel Fojt 		return 0;
388*a1157835SDaniel Fojt 
389*a1157835SDaniel Fojt 	tlv_len = 0;
390*a1157835SDaniel Fojt 	if (vlan->untagged) {
391*a1157835SDaniel Fojt 		tlv_len += sizeof(*hdr);
392*a1157835SDaniel Fojt 		if (start + tlv_len > endpos)
393*a1157835SDaniel Fojt 			return tlv_len;
394*a1157835SDaniel Fojt 		hdr = (struct ft_rrb_tlv *) pos;
395*a1157835SDaniel Fojt 		hdr->type = host_to_le16(FT_RRB_VLAN_UNTAGGED);
396*a1157835SDaniel Fojt 		hdr->len = host_to_le16(sizeof(le16));
397*a1157835SDaniel Fojt 		pos = start + tlv_len;
398*a1157835SDaniel Fojt 
399*a1157835SDaniel Fojt 		tlv_len += sizeof(le16);
400*a1157835SDaniel Fojt 		if (start + tlv_len > endpos)
401*a1157835SDaniel Fojt 			return tlv_len;
402*a1157835SDaniel Fojt 		WPA_PUT_LE16(pos, vlan->untagged);
403*a1157835SDaniel Fojt 		pos = start + tlv_len;
404*a1157835SDaniel Fojt 	}
405*a1157835SDaniel Fojt 
406*a1157835SDaniel Fojt 	if (!vlan->tagged[0])
407*a1157835SDaniel Fojt 		return tlv_len;
408*a1157835SDaniel Fojt 
409*a1157835SDaniel Fojt 	tlv_len += sizeof(*hdr);
410*a1157835SDaniel Fojt 	if (start + tlv_len > endpos)
411*a1157835SDaniel Fojt 		return tlv_len;
412*a1157835SDaniel Fojt 	hdr = (struct ft_rrb_tlv *) pos;
413*a1157835SDaniel Fojt 	hdr->type = host_to_le16(FT_RRB_VLAN_TAGGED);
414*a1157835SDaniel Fojt 	len = 0; /* len is computed below */
415*a1157835SDaniel Fojt 	pos = start + tlv_len;
416*a1157835SDaniel Fojt 
417*a1157835SDaniel Fojt 	for (i = 0; i < MAX_NUM_TAGGED_VLAN && vlan->tagged[i]; i++) {
418*a1157835SDaniel Fojt 		tlv_len += sizeof(le16);
419*a1157835SDaniel Fojt 		if (start + tlv_len > endpos)
420*a1157835SDaniel Fojt 			break;
421*a1157835SDaniel Fojt 		len += sizeof(le16);
422*a1157835SDaniel Fojt 		WPA_PUT_LE16(pos, vlan->tagged[i]);
423*a1157835SDaniel Fojt 		pos = start + tlv_len;
424*a1157835SDaniel Fojt 	}
425*a1157835SDaniel Fojt 
426*a1157835SDaniel Fojt 	hdr->len = host_to_le16(len);
427*a1157835SDaniel Fojt 
428*a1157835SDaniel Fojt 	return tlv_len;
429*a1157835SDaniel Fojt }
430*a1157835SDaniel Fojt 
431*a1157835SDaniel Fojt 
wpa_ft_rrb_lin(const struct tlv_list * tlvs1,const struct tlv_list * tlvs2,const struct vlan_description * vlan,u8 ** plain,size_t * plain_len)432*a1157835SDaniel Fojt static int wpa_ft_rrb_lin(const struct tlv_list *tlvs1,
433*a1157835SDaniel Fojt 			  const struct tlv_list *tlvs2,
434*a1157835SDaniel Fojt 			  const struct vlan_description *vlan,
435*a1157835SDaniel Fojt 			  u8 **plain, size_t *plain_len)
436*a1157835SDaniel Fojt {
437*a1157835SDaniel Fojt 	u8 *pos, *endpos;
438*a1157835SDaniel Fojt 	size_t tlv_len;
439*a1157835SDaniel Fojt 
440*a1157835SDaniel Fojt 	tlv_len = wpa_ft_tlv_len(tlvs1);
441*a1157835SDaniel Fojt 	tlv_len += wpa_ft_tlv_len(tlvs2);
442*a1157835SDaniel Fojt 	tlv_len += wpa_ft_vlan_len(vlan);
443*a1157835SDaniel Fojt 
444*a1157835SDaniel Fojt 	*plain_len = tlv_len;
445*a1157835SDaniel Fojt 	*plain = os_zalloc(tlv_len);
446*a1157835SDaniel Fojt 	if (!*plain) {
447*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "FT: Failed to allocate plaintext");
448*a1157835SDaniel Fojt 		goto err;
449*a1157835SDaniel Fojt 	}
450*a1157835SDaniel Fojt 
451*a1157835SDaniel Fojt 	pos = *plain;
452*a1157835SDaniel Fojt 	endpos = *plain + tlv_len;
453*a1157835SDaniel Fojt 	pos += wpa_ft_tlv_lin(tlvs1, pos, endpos);
454*a1157835SDaniel Fojt 	pos += wpa_ft_tlv_lin(tlvs2, pos, endpos);
455*a1157835SDaniel Fojt 	pos += wpa_ft_vlan_lin(vlan, pos, endpos);
456*a1157835SDaniel Fojt 
457*a1157835SDaniel Fojt 	/* sanity check */
458*a1157835SDaniel Fojt 	if (pos != endpos) {
459*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "FT: Length error building RRB");
460*a1157835SDaniel Fojt 		goto err;
461*a1157835SDaniel Fojt 	}
462*a1157835SDaniel Fojt 
463*a1157835SDaniel Fojt 	return 0;
464*a1157835SDaniel Fojt 
465*a1157835SDaniel Fojt err:
466*a1157835SDaniel Fojt 	os_free(*plain);
467*a1157835SDaniel Fojt 	*plain = NULL;
468*a1157835SDaniel Fojt 	*plain_len = 0;
469*a1157835SDaniel Fojt 	return -1;
470*a1157835SDaniel Fojt }
471*a1157835SDaniel Fojt 
472*a1157835SDaniel Fojt 
wpa_ft_rrb_encrypt(const u8 * key,const size_t key_len,const u8 * plain,const size_t plain_len,const u8 * auth,const size_t auth_len,const u8 * src_addr,u8 type,u8 * enc)473*a1157835SDaniel Fojt static int wpa_ft_rrb_encrypt(const u8 *key, const size_t key_len,
474*a1157835SDaniel Fojt 			      const u8 *plain, const size_t plain_len,
475*a1157835SDaniel Fojt 			      const u8 *auth, const size_t auth_len,
476*a1157835SDaniel Fojt 			      const u8 *src_addr, u8 type, u8 *enc)
477*a1157835SDaniel Fojt {
478*a1157835SDaniel Fojt 	const u8 *ad[3] = { src_addr, auth, &type };
479*a1157835SDaniel Fojt 	size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) };
480*a1157835SDaniel Fojt 
481*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u",
482*a1157835SDaniel Fojt 		   MAC2STR(src_addr), type);
483*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT(RRB): plaintext message",
484*a1157835SDaniel Fojt 			plain, plain_len);
485*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT(RRB): encrypt using key", key, key_len);
486*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len);
487*a1157835SDaniel Fojt 
488*a1157835SDaniel Fojt 	if (!key) {
489*a1157835SDaniel Fojt 		/* encryption not needed, return plaintext as packet */
490*a1157835SDaniel Fojt 		os_memcpy(enc, plain, plain_len);
491*a1157835SDaniel Fojt 	} else if (aes_siv_encrypt(key, key_len, plain, plain_len,
492*a1157835SDaniel Fojt 				   3, ad, ad_len, enc) < 0) {
493*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "FT: Failed to encrypt RRB-OUI message");
494*a1157835SDaniel Fojt 		return -1;
495*a1157835SDaniel Fojt 	}
496*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs",
497*a1157835SDaniel Fojt 		    enc, plain_len + AES_BLOCK_SIZE);
498*a1157835SDaniel Fojt 
499*a1157835SDaniel Fojt 	return 0;
500*a1157835SDaniel Fojt }
501*a1157835SDaniel Fojt 
502*a1157835SDaniel Fojt 
503*a1157835SDaniel Fojt /**
504*a1157835SDaniel Fojt  * wpa_ft_rrb_build - Build and encrypt an FT RRB message
505*a1157835SDaniel Fojt  * @key: AES-SIV key for AEAD
506*a1157835SDaniel Fojt  * @key_len: Length of key in octets
507*a1157835SDaniel Fojt  * @tlvs_enc0: First set of to-be-encrypted TLVs
508*a1157835SDaniel Fojt  * @tlvs_enc1: Second set of to-be-encrypted TLVs
509*a1157835SDaniel Fojt  * @tlvs_auth: Set of to-be-authenticated TLVs
510*a1157835SDaniel Fojt  * @src_addr: MAC address of the frame sender
511*a1157835SDaniel Fojt  * @type: Vendor-specific subtype of the RRB frame (FT_PACKET_*)
512*a1157835SDaniel Fojt  * @packet Pointer to return the pointer to the allocated packet buffer;
513*a1157835SDaniel Fojt  *         needs to be freed by the caller if not null;
514*a1157835SDaniel Fojt  *         will only be returned on success
515*a1157835SDaniel Fojt  * @packet_len: Pointer to return the length of the allocated buffer in octets
516*a1157835SDaniel Fojt  * Returns: 0 on success, -1 on error
517*a1157835SDaniel Fojt  */
wpa_ft_rrb_build(const u8 * key,const size_t key_len,const struct tlv_list * tlvs_enc0,const struct tlv_list * tlvs_enc1,const struct tlv_list * tlvs_auth,const struct vlan_description * vlan,const u8 * src_addr,u8 type,u8 ** packet,size_t * packet_len)518*a1157835SDaniel Fojt static int wpa_ft_rrb_build(const u8 *key, const size_t key_len,
519*a1157835SDaniel Fojt 			    const struct tlv_list *tlvs_enc0,
520*a1157835SDaniel Fojt 			    const struct tlv_list *tlvs_enc1,
521*a1157835SDaniel Fojt 			    const struct tlv_list *tlvs_auth,
522*a1157835SDaniel Fojt 			    const struct vlan_description *vlan,
523*a1157835SDaniel Fojt 			    const u8 *src_addr, u8 type,
524*a1157835SDaniel Fojt 			    u8 **packet, size_t *packet_len)
525*a1157835SDaniel Fojt {
526*a1157835SDaniel Fojt 	u8 *plain = NULL, *auth = NULL, *pos, *tmp;
527*a1157835SDaniel Fojt 	size_t plain_len = 0, auth_len = 0;
528*a1157835SDaniel Fojt 	int ret = -1;
529*a1157835SDaniel Fojt 	size_t pad_len = 0;
530*a1157835SDaniel Fojt 
531*a1157835SDaniel Fojt 	*packet = NULL;
532*a1157835SDaniel Fojt 	if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len) < 0)
533*a1157835SDaniel Fojt 		goto out;
534*a1157835SDaniel Fojt 
535*a1157835SDaniel Fojt 	if (wpa_ft_rrb_lin(tlvs_auth, NULL, NULL, &auth, &auth_len) < 0)
536*a1157835SDaniel Fojt 		goto out;
537*a1157835SDaniel Fojt 
538*a1157835SDaniel Fojt 	*packet_len = sizeof(u16) + auth_len + plain_len;
539*a1157835SDaniel Fojt 	if (key)
540*a1157835SDaniel Fojt 		*packet_len += AES_BLOCK_SIZE;
541*a1157835SDaniel Fojt #define RRB_MIN_MSG_LEN 64
542*a1157835SDaniel Fojt 	if (*packet_len < RRB_MIN_MSG_LEN) {
543*a1157835SDaniel Fojt 		pad_len = RRB_MIN_MSG_LEN - *packet_len;
544*a1157835SDaniel Fojt 		if (pad_len < sizeof(struct ft_rrb_tlv))
545*a1157835SDaniel Fojt 			pad_len = sizeof(struct ft_rrb_tlv);
546*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
547*a1157835SDaniel Fojt 			   "FT: Pad message to minimum Ethernet frame length (%d --> %d)",
548*a1157835SDaniel Fojt 			   (int) *packet_len, (int) (*packet_len + pad_len));
549*a1157835SDaniel Fojt 		*packet_len += pad_len;
550*a1157835SDaniel Fojt 		tmp = os_realloc(auth, auth_len + pad_len);
551*a1157835SDaniel Fojt 		if (!tmp)
552*a1157835SDaniel Fojt 			goto out;
553*a1157835SDaniel Fojt 		auth = tmp;
554*a1157835SDaniel Fojt 		pos = auth + auth_len;
555*a1157835SDaniel Fojt 		WPA_PUT_LE16(pos, FT_RRB_LAST_EMPTY);
556*a1157835SDaniel Fojt 		pos += 2;
557*a1157835SDaniel Fojt 		WPA_PUT_LE16(pos, pad_len - sizeof(struct ft_rrb_tlv));
558*a1157835SDaniel Fojt 		pos += 2;
559*a1157835SDaniel Fojt 		os_memset(pos, 0, pad_len - sizeof(struct ft_rrb_tlv));
560*a1157835SDaniel Fojt 		auth_len += pad_len;
561*a1157835SDaniel Fojt 
562*a1157835SDaniel Fojt 	}
563*a1157835SDaniel Fojt 	*packet = os_zalloc(*packet_len);
564*a1157835SDaniel Fojt 	if (!*packet)
565*a1157835SDaniel Fojt 		goto out;
566*a1157835SDaniel Fojt 
567*a1157835SDaniel Fojt 	pos = *packet;
568*a1157835SDaniel Fojt 	WPA_PUT_LE16(pos, auth_len);
569*a1157835SDaniel Fojt 	pos += 2;
570*a1157835SDaniel Fojt 	os_memcpy(pos, auth, auth_len);
571*a1157835SDaniel Fojt 	pos += auth_len;
572*a1157835SDaniel Fojt 	if (wpa_ft_rrb_encrypt(key, key_len, plain, plain_len, auth,
573*a1157835SDaniel Fojt 			       auth_len, src_addr, type, pos) < 0)
574*a1157835SDaniel Fojt 		goto out;
575*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", *packet, *packet_len);
576*a1157835SDaniel Fojt 
577*a1157835SDaniel Fojt 	ret = 0;
578*a1157835SDaniel Fojt 
579*a1157835SDaniel Fojt out:
580*a1157835SDaniel Fojt 	bin_clear_free(plain, plain_len);
581*a1157835SDaniel Fojt 	os_free(auth);
582*a1157835SDaniel Fojt 
583*a1157835SDaniel Fojt 	if (ret) {
584*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "FT: Failed to build RRB-OUI message");
585*a1157835SDaniel Fojt 		os_free(*packet);
586*a1157835SDaniel Fojt 		*packet = NULL;
587*a1157835SDaniel Fojt 		*packet_len = 0;
588*a1157835SDaniel Fojt 	}
589*a1157835SDaniel Fojt 
590*a1157835SDaniel Fojt 	return ret;
591*a1157835SDaniel Fojt }
592*a1157835SDaniel Fojt 
593*a1157835SDaniel Fojt 
594*a1157835SDaniel Fojt #define RRB_GET_SRC(srcfield, type, field, txt, checklength) do { \
595*a1157835SDaniel Fojt 	if (wpa_ft_rrb_get_tlv(srcfield, srcfield##_len, type, \
596*a1157835SDaniel Fojt 				&f_##field##_len, &f_##field) < 0 || \
597*a1157835SDaniel Fojt 	    (checklength > 0 && ((size_t) checklength) != f_##field##_len)) { \
598*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "FT: Missing required " #field \
599*a1157835SDaniel Fojt 			   " in %s from " MACSTR, txt, MAC2STR(src_addr)); \
600*a1157835SDaniel Fojt 		wpa_ft_rrb_dump(srcfield, srcfield##_len); \
601*a1157835SDaniel Fojt 		goto out; \
602*a1157835SDaniel Fojt 	} \
603*a1157835SDaniel Fojt } while (0)
604*a1157835SDaniel Fojt 
605*a1157835SDaniel Fojt #define RRB_GET(type, field, txt, checklength) \
606*a1157835SDaniel Fojt 	RRB_GET_SRC(plain, type, field, txt, checklength)
607*a1157835SDaniel Fojt #define RRB_GET_AUTH(type, field, txt, checklength) \
608*a1157835SDaniel Fojt 	RRB_GET_SRC(auth, type, field, txt, checklength)
609*a1157835SDaniel Fojt 
610*a1157835SDaniel Fojt #define RRB_GET_OPTIONAL_SRC(srcfield, type, field, txt, checklength) do { \
611*a1157835SDaniel Fojt 	if (wpa_ft_rrb_get_tlv(srcfield, srcfield##_len, type, \
612*a1157835SDaniel Fojt 				&f_##field##_len, &f_##field) < 0 || \
613*a1157835SDaniel Fojt 	    (checklength > 0 && ((size_t) checklength) != f_##field##_len)) { \
614*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Missing optional " #field \
615*a1157835SDaniel Fojt 			   " in %s from " MACSTR, txt, MAC2STR(src_addr)); \
616*a1157835SDaniel Fojt 		f_##field##_len = 0; \
617*a1157835SDaniel Fojt 		f_##field = NULL; \
618*a1157835SDaniel Fojt 	} \
619*a1157835SDaniel Fojt } while (0)
620*a1157835SDaniel Fojt 
621*a1157835SDaniel Fojt #define RRB_GET_OPTIONAL(type, field, txt, checklength) \
622*a1157835SDaniel Fojt 	RRB_GET_OPTIONAL_SRC(plain, type, field, txt, checklength)
623*a1157835SDaniel Fojt #define RRB_GET_OPTIONAL_AUTH(type, field, txt, checklength) \
624*a1157835SDaniel Fojt 	RRB_GET_OPTIONAL_SRC(auth, type, field, txt, checklength)
6253ff40c12SJohn Marino 
wpa_ft_rrb_send(struct wpa_authenticator * wpa_auth,const u8 * dst,const u8 * data,size_t data_len)6263ff40c12SJohn Marino static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
6273ff40c12SJohn Marino 			   const u8 *data, size_t data_len)
6283ff40c12SJohn Marino {
629*a1157835SDaniel Fojt 	if (wpa_auth->cb->send_ether == NULL)
6303ff40c12SJohn Marino 		return -1;
6313ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst));
632*a1157835SDaniel Fojt 	return wpa_auth->cb->send_ether(wpa_auth->cb_ctx, dst, ETH_P_RRB,
6333ff40c12SJohn Marino 					data, data_len);
6343ff40c12SJohn Marino }
6353ff40c12SJohn Marino 
6363ff40c12SJohn Marino 
wpa_ft_rrb_oui_send(struct wpa_authenticator * wpa_auth,const u8 * dst,u8 oui_suffix,const u8 * data,size_t data_len)637*a1157835SDaniel Fojt static int wpa_ft_rrb_oui_send(struct wpa_authenticator *wpa_auth,
638*a1157835SDaniel Fojt 			       const u8 *dst, u8 oui_suffix,
639*a1157835SDaniel Fojt 			       const u8 *data, size_t data_len)
640*a1157835SDaniel Fojt {
641*a1157835SDaniel Fojt 	if (!wpa_auth->cb->send_oui)
642*a1157835SDaniel Fojt 		return -1;
643*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR " (len=%u)",
644*a1157835SDaniel Fojt 		   oui_suffix, MAC2STR(dst), (unsigned int) data_len);
645*a1157835SDaniel Fojt 	return wpa_auth->cb->send_oui(wpa_auth->cb_ctx, dst, oui_suffix, data,
646*a1157835SDaniel Fojt 				      data_len);
647*a1157835SDaniel Fojt }
648*a1157835SDaniel Fojt 
649*a1157835SDaniel Fojt 
wpa_ft_action_send(struct wpa_authenticator * wpa_auth,const u8 * dst,const u8 * data,size_t data_len)6503ff40c12SJohn Marino static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
6513ff40c12SJohn Marino 			      const u8 *dst, const u8 *data, size_t data_len)
6523ff40c12SJohn Marino {
653*a1157835SDaniel Fojt 	if (wpa_auth->cb->send_ft_action == NULL)
6543ff40c12SJohn Marino 		return -1;
655*a1157835SDaniel Fojt 	return wpa_auth->cb->send_ft_action(wpa_auth->cb_ctx, dst,
6563ff40c12SJohn Marino 					    data, data_len);
6573ff40c12SJohn Marino }
6583ff40c12SJohn Marino 
6593ff40c12SJohn Marino 
wpa_ft_get_psk(struct wpa_authenticator * wpa_auth,const u8 * addr,const u8 * p2p_dev_addr,const u8 * prev_psk)660*a1157835SDaniel Fojt static const u8 * wpa_ft_get_psk(struct wpa_authenticator *wpa_auth,
661*a1157835SDaniel Fojt 				 const u8 *addr, const u8 *p2p_dev_addr,
662*a1157835SDaniel Fojt 				 const u8 *prev_psk)
663*a1157835SDaniel Fojt {
664*a1157835SDaniel Fojt 	if (wpa_auth->cb->get_psk == NULL)
665*a1157835SDaniel Fojt 		return NULL;
666*a1157835SDaniel Fojt 	return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
667*a1157835SDaniel Fojt 				     prev_psk, NULL, NULL);
668*a1157835SDaniel Fojt }
669*a1157835SDaniel Fojt 
670*a1157835SDaniel Fojt 
6713ff40c12SJohn Marino static struct wpa_state_machine *
wpa_ft_add_sta(struct wpa_authenticator * wpa_auth,const u8 * sta_addr)6723ff40c12SJohn Marino wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
6733ff40c12SJohn Marino {
674*a1157835SDaniel Fojt 	if (wpa_auth->cb->add_sta == NULL)
6753ff40c12SJohn Marino 		return NULL;
676*a1157835SDaniel Fojt 	return wpa_auth->cb->add_sta(wpa_auth->cb_ctx, sta_addr);
677*a1157835SDaniel Fojt }
678*a1157835SDaniel Fojt 
679*a1157835SDaniel Fojt 
wpa_ft_set_vlan(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,struct vlan_description * vlan)680*a1157835SDaniel Fojt static int wpa_ft_set_vlan(struct wpa_authenticator *wpa_auth,
681*a1157835SDaniel Fojt 			   const u8 *sta_addr, struct vlan_description *vlan)
682*a1157835SDaniel Fojt {
683*a1157835SDaniel Fojt 	if (!wpa_auth->cb->set_vlan)
684*a1157835SDaniel Fojt 		return -1;
685*a1157835SDaniel Fojt 	return wpa_auth->cb->set_vlan(wpa_auth->cb_ctx, sta_addr, vlan);
686*a1157835SDaniel Fojt }
687*a1157835SDaniel Fojt 
688*a1157835SDaniel Fojt 
wpa_ft_get_vlan(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,struct vlan_description * vlan)689*a1157835SDaniel Fojt static int wpa_ft_get_vlan(struct wpa_authenticator *wpa_auth,
690*a1157835SDaniel Fojt 			   const u8 *sta_addr, struct vlan_description *vlan)
691*a1157835SDaniel Fojt {
692*a1157835SDaniel Fojt 	if (!wpa_auth->cb->get_vlan)
693*a1157835SDaniel Fojt 		return -1;
694*a1157835SDaniel Fojt 	return wpa_auth->cb->get_vlan(wpa_auth->cb_ctx, sta_addr, vlan);
695*a1157835SDaniel Fojt }
696*a1157835SDaniel Fojt 
697*a1157835SDaniel Fojt 
698*a1157835SDaniel Fojt static int
wpa_ft_set_identity(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,const u8 * identity,size_t identity_len)699*a1157835SDaniel Fojt wpa_ft_set_identity(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
700*a1157835SDaniel Fojt 		    const u8 *identity, size_t identity_len)
701*a1157835SDaniel Fojt {
702*a1157835SDaniel Fojt 	if (!wpa_auth->cb->set_identity)
703*a1157835SDaniel Fojt 		return -1;
704*a1157835SDaniel Fojt 	return wpa_auth->cb->set_identity(wpa_auth->cb_ctx, sta_addr, identity,
705*a1157835SDaniel Fojt 					  identity_len);
706*a1157835SDaniel Fojt }
707*a1157835SDaniel Fojt 
708*a1157835SDaniel Fojt 
709*a1157835SDaniel Fojt static size_t
wpa_ft_get_identity(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,const u8 ** buf)710*a1157835SDaniel Fojt wpa_ft_get_identity(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
711*a1157835SDaniel Fojt 		    const u8 **buf)
712*a1157835SDaniel Fojt {
713*a1157835SDaniel Fojt 	*buf = NULL;
714*a1157835SDaniel Fojt 	if (!wpa_auth->cb->get_identity)
715*a1157835SDaniel Fojt 		return 0;
716*a1157835SDaniel Fojt 	return wpa_auth->cb->get_identity(wpa_auth->cb_ctx, sta_addr, buf);
717*a1157835SDaniel Fojt }
718*a1157835SDaniel Fojt 
719*a1157835SDaniel Fojt 
720*a1157835SDaniel Fojt static int
wpa_ft_set_radius_cui(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,const u8 * radius_cui,size_t radius_cui_len)721*a1157835SDaniel Fojt wpa_ft_set_radius_cui(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
722*a1157835SDaniel Fojt 		      const u8 *radius_cui, size_t radius_cui_len)
723*a1157835SDaniel Fojt {
724*a1157835SDaniel Fojt 	if (!wpa_auth->cb->set_radius_cui)
725*a1157835SDaniel Fojt 		return -1;
726*a1157835SDaniel Fojt 	return wpa_auth->cb->set_radius_cui(wpa_auth->cb_ctx, sta_addr,
727*a1157835SDaniel Fojt 					    radius_cui, radius_cui_len);
728*a1157835SDaniel Fojt }
729*a1157835SDaniel Fojt 
730*a1157835SDaniel Fojt 
731*a1157835SDaniel Fojt static size_t
wpa_ft_get_radius_cui(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,const u8 ** buf)732*a1157835SDaniel Fojt wpa_ft_get_radius_cui(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
733*a1157835SDaniel Fojt 		      const u8 **buf)
734*a1157835SDaniel Fojt {
735*a1157835SDaniel Fojt 	*buf = NULL;
736*a1157835SDaniel Fojt 	if (!wpa_auth->cb->get_radius_cui)
737*a1157835SDaniel Fojt 		return 0;
738*a1157835SDaniel Fojt 	return wpa_auth->cb->get_radius_cui(wpa_auth->cb_ctx, sta_addr, buf);
739*a1157835SDaniel Fojt }
740*a1157835SDaniel Fojt 
741*a1157835SDaniel Fojt 
742*a1157835SDaniel Fojt static void
wpa_ft_set_session_timeout(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,int session_timeout)743*a1157835SDaniel Fojt wpa_ft_set_session_timeout(struct wpa_authenticator *wpa_auth,
744*a1157835SDaniel Fojt 			    const u8 *sta_addr, int session_timeout)
745*a1157835SDaniel Fojt {
746*a1157835SDaniel Fojt 	if (!wpa_auth->cb->set_session_timeout)
747*a1157835SDaniel Fojt 		return;
748*a1157835SDaniel Fojt 	wpa_auth->cb->set_session_timeout(wpa_auth->cb_ctx, sta_addr,
749*a1157835SDaniel Fojt 					  session_timeout);
750*a1157835SDaniel Fojt }
751*a1157835SDaniel Fojt 
752*a1157835SDaniel Fojt 
753*a1157835SDaniel Fojt static int
wpa_ft_get_session_timeout(struct wpa_authenticator * wpa_auth,const u8 * sta_addr)754*a1157835SDaniel Fojt wpa_ft_get_session_timeout(struct wpa_authenticator *wpa_auth,
755*a1157835SDaniel Fojt 			    const u8 *sta_addr)
756*a1157835SDaniel Fojt {
757*a1157835SDaniel Fojt 	if (!wpa_auth->cb->get_session_timeout)
758*a1157835SDaniel Fojt 		return 0;
759*a1157835SDaniel Fojt 	return wpa_auth->cb->get_session_timeout(wpa_auth->cb_ctx, sta_addr);
7603ff40c12SJohn Marino }
7613ff40c12SJohn Marino 
7623ff40c12SJohn Marino 
wpa_ft_add_tspec(struct wpa_authenticator * wpa_auth,const u8 * sta_addr,u8 * tspec_ie,size_t tspec_ielen)7633ff40c12SJohn Marino static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
7643ff40c12SJohn Marino 			    const u8 *sta_addr,
7653ff40c12SJohn Marino 			    u8 *tspec_ie, size_t tspec_ielen)
7663ff40c12SJohn Marino {
767*a1157835SDaniel Fojt 	if (wpa_auth->cb->add_tspec == NULL) {
7683ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
7693ff40c12SJohn Marino 		return -1;
7703ff40c12SJohn Marino 	}
771*a1157835SDaniel Fojt 	return wpa_auth->cb->add_tspec(wpa_auth->cb_ctx, sta_addr, tspec_ie,
7723ff40c12SJohn Marino 				       tspec_ielen);
7733ff40c12SJohn Marino }
7743ff40c12SJohn Marino 
7753ff40c12SJohn Marino 
776*a1157835SDaniel Fojt #ifdef CONFIG_OCV
wpa_channel_info(struct wpa_authenticator * wpa_auth,struct wpa_channel_info * ci)777*a1157835SDaniel Fojt static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
778*a1157835SDaniel Fojt 			       struct wpa_channel_info *ci)
779*a1157835SDaniel Fojt {
780*a1157835SDaniel Fojt 	if (!wpa_auth->cb->channel_info)
781*a1157835SDaniel Fojt 		return -1;
782*a1157835SDaniel Fojt 	return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
783*a1157835SDaniel Fojt }
784*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
785*a1157835SDaniel Fojt 
786*a1157835SDaniel Fojt 
wpa_write_mdie(struct wpa_auth_config * conf,u8 * buf,size_t len)7873ff40c12SJohn Marino int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
7883ff40c12SJohn Marino {
7893ff40c12SJohn Marino 	u8 *pos = buf;
7903ff40c12SJohn Marino 	u8 capab;
7913ff40c12SJohn Marino 	if (len < 2 + sizeof(struct rsn_mdie))
7923ff40c12SJohn Marino 		return -1;
7933ff40c12SJohn Marino 
7943ff40c12SJohn Marino 	*pos++ = WLAN_EID_MOBILITY_DOMAIN;
7953ff40c12SJohn Marino 	*pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
7963ff40c12SJohn Marino 	os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
7973ff40c12SJohn Marino 	pos += MOBILITY_DOMAIN_ID_LEN;
7983ff40c12SJohn Marino 	capab = 0;
7993ff40c12SJohn Marino 	if (conf->ft_over_ds)
8003ff40c12SJohn Marino 		capab |= RSN_FT_CAPAB_FT_OVER_DS;
8013ff40c12SJohn Marino 	*pos++ = capab;
8023ff40c12SJohn Marino 
8033ff40c12SJohn Marino 	return pos - buf;
8043ff40c12SJohn Marino }
8053ff40c12SJohn Marino 
8063ff40c12SJohn Marino 
wpa_write_ftie(struct wpa_auth_config * conf,int use_sha384,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)807*a1157835SDaniel Fojt int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
808*a1157835SDaniel Fojt 		   const u8 *r0kh_id, size_t r0kh_id_len,
8093ff40c12SJohn Marino 		   const u8 *anonce, const u8 *snonce,
8103ff40c12SJohn Marino 		   u8 *buf, size_t len, const u8 *subelem,
8113ff40c12SJohn Marino 		   size_t subelem_len)
8123ff40c12SJohn Marino {
8133ff40c12SJohn Marino 	u8 *pos = buf, *ielen;
814*a1157835SDaniel Fojt 	size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
815*a1157835SDaniel Fojt 		sizeof(struct rsn_ftie);
8163ff40c12SJohn Marino 
817*a1157835SDaniel Fojt 	if (len < 2 + hdrlen + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
8183ff40c12SJohn Marino 	    subelem_len)
8193ff40c12SJohn Marino 		return -1;
8203ff40c12SJohn Marino 
8213ff40c12SJohn Marino 	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
8223ff40c12SJohn Marino 	ielen = pos++;
8233ff40c12SJohn Marino 
824*a1157835SDaniel Fojt 	if (use_sha384) {
825*a1157835SDaniel Fojt 		struct rsn_ftie_sha384 *hdr = (struct rsn_ftie_sha384 *) pos;
826*a1157835SDaniel Fojt 
8273ff40c12SJohn Marino 		os_memset(hdr, 0, sizeof(*hdr));
8283ff40c12SJohn Marino 		pos += sizeof(*hdr);
8293ff40c12SJohn Marino 		WPA_PUT_LE16(hdr->mic_control, 0);
8303ff40c12SJohn Marino 		if (anonce)
8313ff40c12SJohn Marino 			os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
8323ff40c12SJohn Marino 		if (snonce)
8333ff40c12SJohn Marino 			os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
834*a1157835SDaniel Fojt 	} else {
835*a1157835SDaniel Fojt 		struct rsn_ftie *hdr = (struct rsn_ftie *) pos;
836*a1157835SDaniel Fojt 
837*a1157835SDaniel Fojt 		os_memset(hdr, 0, sizeof(*hdr));
838*a1157835SDaniel Fojt 		pos += sizeof(*hdr);
839*a1157835SDaniel Fojt 		WPA_PUT_LE16(hdr->mic_control, 0);
840*a1157835SDaniel Fojt 		if (anonce)
841*a1157835SDaniel Fojt 			os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
842*a1157835SDaniel Fojt 		if (snonce)
843*a1157835SDaniel Fojt 			os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
844*a1157835SDaniel Fojt 	}
8453ff40c12SJohn Marino 
8463ff40c12SJohn Marino 	/* Optional Parameters */
8473ff40c12SJohn Marino 	*pos++ = FTIE_SUBELEM_R1KH_ID;
8483ff40c12SJohn Marino 	*pos++ = FT_R1KH_ID_LEN;
8493ff40c12SJohn Marino 	os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
8503ff40c12SJohn Marino 	pos += FT_R1KH_ID_LEN;
8513ff40c12SJohn Marino 
8523ff40c12SJohn Marino 	if (r0kh_id) {
8533ff40c12SJohn Marino 		*pos++ = FTIE_SUBELEM_R0KH_ID;
8543ff40c12SJohn Marino 		*pos++ = r0kh_id_len;
8553ff40c12SJohn Marino 		os_memcpy(pos, r0kh_id, r0kh_id_len);
8563ff40c12SJohn Marino 		pos += r0kh_id_len;
8573ff40c12SJohn Marino 	}
8583ff40c12SJohn Marino 
8593ff40c12SJohn Marino 	if (subelem) {
8603ff40c12SJohn Marino 		os_memcpy(pos, subelem, subelem_len);
8613ff40c12SJohn Marino 		pos += subelem_len;
8623ff40c12SJohn Marino 	}
8633ff40c12SJohn Marino 
8643ff40c12SJohn Marino 	*ielen = pos - buf - 2;
8653ff40c12SJohn Marino 
8663ff40c12SJohn Marino 	return pos - buf;
8673ff40c12SJohn Marino }
8683ff40c12SJohn Marino 
8693ff40c12SJohn Marino 
870*a1157835SDaniel Fojt /* A packet to be handled after seq response */
871*a1157835SDaniel Fojt struct ft_remote_item {
872*a1157835SDaniel Fojt 	struct dl_list list;
873*a1157835SDaniel Fojt 
874*a1157835SDaniel Fojt 	u8 nonce[FT_RRB_NONCE_LEN];
875*a1157835SDaniel Fojt 	struct os_reltime nonce_ts;
876*a1157835SDaniel Fojt 
877*a1157835SDaniel Fojt 	u8 src_addr[ETH_ALEN];
878*a1157835SDaniel Fojt 	u8 *enc;
879*a1157835SDaniel Fojt 	size_t enc_len;
880*a1157835SDaniel Fojt 	u8 *auth;
881*a1157835SDaniel Fojt 	size_t auth_len;
882*a1157835SDaniel Fojt 	int (*cb)(struct wpa_authenticator *wpa_auth,
883*a1157835SDaniel Fojt 		  const u8 *src_addr,
884*a1157835SDaniel Fojt 		  const u8 *enc, size_t enc_len,
885*a1157835SDaniel Fojt 		  const u8 *auth, size_t auth_len,
886*a1157835SDaniel Fojt 		  int no_defer);
887*a1157835SDaniel Fojt };
888*a1157835SDaniel Fojt 
889*a1157835SDaniel Fojt 
wpa_ft_rrb_seq_free(struct ft_remote_item * item)890*a1157835SDaniel Fojt static void wpa_ft_rrb_seq_free(struct ft_remote_item *item)
891*a1157835SDaniel Fojt {
892*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpa_ft_rrb_seq_timeout, ELOOP_ALL_CTX, item);
893*a1157835SDaniel Fojt 	dl_list_del(&item->list);
894*a1157835SDaniel Fojt 	bin_clear_free(item->enc, item->enc_len);
895*a1157835SDaniel Fojt 	os_free(item->auth);
896*a1157835SDaniel Fojt 	os_free(item);
897*a1157835SDaniel Fojt }
898*a1157835SDaniel Fojt 
899*a1157835SDaniel Fojt 
wpa_ft_rrb_seq_flush(struct wpa_authenticator * wpa_auth,struct ft_remote_seq * rkh_seq,int cb)900*a1157835SDaniel Fojt static void wpa_ft_rrb_seq_flush(struct wpa_authenticator *wpa_auth,
901*a1157835SDaniel Fojt 				 struct ft_remote_seq *rkh_seq, int cb)
902*a1157835SDaniel Fojt {
903*a1157835SDaniel Fojt 	struct ft_remote_item *item, *n;
904*a1157835SDaniel Fojt 
905*a1157835SDaniel Fojt 	dl_list_for_each_safe(item, n, &rkh_seq->rx.queue,
906*a1157835SDaniel Fojt 			      struct ft_remote_item, list) {
907*a1157835SDaniel Fojt 		if (cb && item->cb)
908*a1157835SDaniel Fojt 			item->cb(wpa_auth, item->src_addr, item->enc,
909*a1157835SDaniel Fojt 				 item->enc_len, item->auth, item->auth_len, 1);
910*a1157835SDaniel Fojt 		wpa_ft_rrb_seq_free(item);
911*a1157835SDaniel Fojt 	}
912*a1157835SDaniel Fojt }
913*a1157835SDaniel Fojt 
914*a1157835SDaniel Fojt 
wpa_ft_rrb_seq_timeout(void * eloop_ctx,void * timeout_ctx)915*a1157835SDaniel Fojt static void wpa_ft_rrb_seq_timeout(void *eloop_ctx, void *timeout_ctx)
916*a1157835SDaniel Fojt {
917*a1157835SDaniel Fojt 	struct ft_remote_item *item = timeout_ctx;
918*a1157835SDaniel Fojt 
919*a1157835SDaniel Fojt 	wpa_ft_rrb_seq_free(item);
920*a1157835SDaniel Fojt }
921*a1157835SDaniel Fojt 
922*a1157835SDaniel Fojt 
923*a1157835SDaniel Fojt static int
wpa_ft_rrb_seq_req(struct wpa_authenticator * wpa_auth,struct ft_remote_seq * rkh_seq,const u8 * src_addr,const u8 * f_r0kh_id,size_t f_r0kh_id_len,const u8 * f_r1kh_id,const u8 * key,size_t key_len,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,int (* cb)(struct wpa_authenticator * wpa_auth,const u8 * src_addr,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,int no_defer))924*a1157835SDaniel Fojt wpa_ft_rrb_seq_req(struct wpa_authenticator *wpa_auth,
925*a1157835SDaniel Fojt 		   struct ft_remote_seq *rkh_seq, const u8 *src_addr,
926*a1157835SDaniel Fojt 		   const u8 *f_r0kh_id, size_t f_r0kh_id_len,
927*a1157835SDaniel Fojt 		   const u8 *f_r1kh_id, const u8 *key, size_t key_len,
928*a1157835SDaniel Fojt 		   const u8 *enc, size_t enc_len,
929*a1157835SDaniel Fojt 		   const u8 *auth, size_t auth_len,
930*a1157835SDaniel Fojt 		   int (*cb)(struct wpa_authenticator *wpa_auth,
931*a1157835SDaniel Fojt 			     const u8 *src_addr,
932*a1157835SDaniel Fojt 			     const u8 *enc, size_t enc_len,
933*a1157835SDaniel Fojt 			     const u8 *auth, size_t auth_len,
934*a1157835SDaniel Fojt 			     int no_defer))
935*a1157835SDaniel Fojt {
936*a1157835SDaniel Fojt 	struct ft_remote_item *item = NULL;
937*a1157835SDaniel Fojt 	u8 *packet = NULL;
938*a1157835SDaniel Fojt 	size_t packet_len;
939*a1157835SDaniel Fojt 	struct tlv_list seq_req_auth[] = {
940*a1157835SDaniel Fojt 		{ .type = FT_RRB_NONCE, .len = FT_RRB_NONCE_LEN,
941*a1157835SDaniel Fojt 		  .data = NULL /* to be filled: item->nonce */ },
942*a1157835SDaniel Fojt 		{ .type = FT_RRB_R0KH_ID, .len = f_r0kh_id_len,
943*a1157835SDaniel Fojt 		  .data = f_r0kh_id },
944*a1157835SDaniel Fojt 		{ .type = FT_RRB_R1KH_ID, .len = FT_R1KH_ID_LEN,
945*a1157835SDaniel Fojt 		  .data = f_r1kh_id },
946*a1157835SDaniel Fojt 		{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
947*a1157835SDaniel Fojt 	};
948*a1157835SDaniel Fojt 
949*a1157835SDaniel Fojt 	if (dl_list_len(&rkh_seq->rx.queue) >= ftRRBmaxQueueLen) {
950*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Sequence number queue too long");
951*a1157835SDaniel Fojt 		goto err;
952*a1157835SDaniel Fojt 	}
953*a1157835SDaniel Fojt 
954*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
955*a1157835SDaniel Fojt 		   MAC2STR(src_addr));
956*a1157835SDaniel Fojt 	item = os_zalloc(sizeof(*item));
957*a1157835SDaniel Fojt 	if (!item)
958*a1157835SDaniel Fojt 		goto err;
959*a1157835SDaniel Fojt 
960*a1157835SDaniel Fojt 	os_memcpy(item->src_addr, src_addr, ETH_ALEN);
961*a1157835SDaniel Fojt 	item->cb = cb;
962*a1157835SDaniel Fojt 
963*a1157835SDaniel Fojt 	if (random_get_bytes(item->nonce, FT_RRB_NONCE_LEN) < 0) {
964*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Seq num nonce: out of random bytes");
965*a1157835SDaniel Fojt 		goto err;
966*a1157835SDaniel Fojt 	}
967*a1157835SDaniel Fojt 
968*a1157835SDaniel Fojt 	if (os_get_reltime(&item->nonce_ts) < 0)
969*a1157835SDaniel Fojt 		goto err;
970*a1157835SDaniel Fojt 
971*a1157835SDaniel Fojt 	if (enc && enc_len > 0) {
972*a1157835SDaniel Fojt 		item->enc = os_memdup(enc, enc_len);
973*a1157835SDaniel Fojt 		item->enc_len = enc_len;
974*a1157835SDaniel Fojt 		if (!item->enc)
975*a1157835SDaniel Fojt 			goto err;
976*a1157835SDaniel Fojt 	}
977*a1157835SDaniel Fojt 
978*a1157835SDaniel Fojt 	if (auth && auth_len > 0) {
979*a1157835SDaniel Fojt 		item->auth = os_memdup(auth, auth_len);
980*a1157835SDaniel Fojt 		item->auth_len = auth_len;
981*a1157835SDaniel Fojt 		if (!item->auth)
982*a1157835SDaniel Fojt 			goto err;
983*a1157835SDaniel Fojt 	}
984*a1157835SDaniel Fojt 
985*a1157835SDaniel Fojt 	eloop_register_timeout(ftRRBseqTimeout, 0, wpa_ft_rrb_seq_timeout,
986*a1157835SDaniel Fojt 			       wpa_auth, item);
987*a1157835SDaniel Fojt 
988*a1157835SDaniel Fojt 	seq_req_auth[0].data = item->nonce;
989*a1157835SDaniel Fojt 
990*a1157835SDaniel Fojt 	if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_req_auth, NULL,
991*a1157835SDaniel Fojt 			     wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_REQ,
992*a1157835SDaniel Fojt 			     &packet, &packet_len) < 0) {
993*a1157835SDaniel Fojt 		item = NULL; /* some other seq resp might still accept this */
994*a1157835SDaniel Fojt 		goto err;
995*a1157835SDaniel Fojt 	}
996*a1157835SDaniel Fojt 
997*a1157835SDaniel Fojt 	dl_list_add(&rkh_seq->rx.queue, &item->list);
998*a1157835SDaniel Fojt 
999*a1157835SDaniel Fojt 	wpa_ft_rrb_oui_send(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_REQ,
1000*a1157835SDaniel Fojt 			    packet, packet_len);
1001*a1157835SDaniel Fojt 
1002*a1157835SDaniel Fojt 	os_free(packet);
1003*a1157835SDaniel Fojt 
1004*a1157835SDaniel Fojt 	return 0;
1005*a1157835SDaniel Fojt err:
1006*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Failed to send sequence number request");
1007*a1157835SDaniel Fojt 	if (item) {
1008*a1157835SDaniel Fojt 		os_free(item->auth);
1009*a1157835SDaniel Fojt 		bin_clear_free(item->enc, item->enc_len);
1010*a1157835SDaniel Fojt 		os_free(item);
1011*a1157835SDaniel Fojt 	}
1012*a1157835SDaniel Fojt 
1013*a1157835SDaniel Fojt 	return -1;
1014*a1157835SDaniel Fojt }
1015*a1157835SDaniel Fojt 
1016*a1157835SDaniel Fojt 
1017*a1157835SDaniel Fojt #define FT_RRB_SEQ_OK    0
1018*a1157835SDaniel Fojt #define FT_RRB_SEQ_DROP  1
1019*a1157835SDaniel Fojt #define FT_RRB_SEQ_DEFER 2
1020*a1157835SDaniel Fojt 
1021*a1157835SDaniel Fojt static int
wpa_ft_rrb_seq_chk(struct ft_remote_seq * rkh_seq,const u8 * src_addr,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,const char * msgtype,int no_defer)1022*a1157835SDaniel Fojt wpa_ft_rrb_seq_chk(struct ft_remote_seq *rkh_seq, const u8 *src_addr,
1023*a1157835SDaniel Fojt 		   const u8 *enc, size_t enc_len,
1024*a1157835SDaniel Fojt 		   const u8 *auth, size_t auth_len,
1025*a1157835SDaniel Fojt 		   const char *msgtype, int no_defer)
1026*a1157835SDaniel Fojt {
1027*a1157835SDaniel Fojt 	const u8 *f_seq;
1028*a1157835SDaniel Fojt 	size_t f_seq_len;
1029*a1157835SDaniel Fojt 	const struct ft_rrb_seq *msg_both;
1030*a1157835SDaniel Fojt 	u32 msg_seq, msg_off, rkh_off;
1031*a1157835SDaniel Fojt 	struct os_reltime now;
1032*a1157835SDaniel Fojt 	unsigned int i;
1033*a1157835SDaniel Fojt 
1034*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_SEQ, seq, msgtype, sizeof(*msg_both));
1035*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: sequence number", f_seq, f_seq_len);
1036*a1157835SDaniel Fojt 	msg_both = (const struct ft_rrb_seq *) f_seq;
1037*a1157835SDaniel Fojt 
1038*a1157835SDaniel Fojt 	if (rkh_seq->rx.num_last == 0) {
1039*a1157835SDaniel Fojt 		/* first packet from remote */
1040*a1157835SDaniel Fojt 		goto defer;
1041*a1157835SDaniel Fojt 	}
1042*a1157835SDaniel Fojt 
1043*a1157835SDaniel Fojt 	if (le_to_host32(msg_both->dom) != rkh_seq->rx.dom) {
1044*a1157835SDaniel Fojt 		/* remote might have rebooted */
1045*a1157835SDaniel Fojt 		goto defer;
1046*a1157835SDaniel Fojt 	}
1047*a1157835SDaniel Fojt 
1048*a1157835SDaniel Fojt 	if (os_get_reltime(&now) == 0) {
1049*a1157835SDaniel Fojt 		u32 msg_ts_now_remote, msg_ts_off;
1050*a1157835SDaniel Fojt 		struct os_reltime now_remote;
1051*a1157835SDaniel Fojt 
1052*a1157835SDaniel Fojt 		os_reltime_sub(&now, &rkh_seq->rx.time_offset, &now_remote);
1053*a1157835SDaniel Fojt 		msg_ts_now_remote = now_remote.sec;
1054*a1157835SDaniel Fojt 		msg_ts_off = le_to_host32(msg_both->ts) -
1055*a1157835SDaniel Fojt 			(msg_ts_now_remote - ftRRBseqTimeout);
1056*a1157835SDaniel Fojt 		if (msg_ts_off > 2 * ftRRBseqTimeout)
1057*a1157835SDaniel Fojt 			goto defer;
1058*a1157835SDaniel Fojt 	}
1059*a1157835SDaniel Fojt 
1060*a1157835SDaniel Fojt 	msg_seq = le_to_host32(msg_both->seq);
1061*a1157835SDaniel Fojt 	rkh_off = rkh_seq->rx.last[rkh_seq->rx.offsetidx];
1062*a1157835SDaniel Fojt 	msg_off = msg_seq - rkh_off;
1063*a1157835SDaniel Fojt 	if (msg_off > 0xC0000000)
1064*a1157835SDaniel Fojt 		goto out; /* too old message, drop it */
1065*a1157835SDaniel Fojt 
1066*a1157835SDaniel Fojt 	if (msg_off <= 0x40000000) {
1067*a1157835SDaniel Fojt 		for (i = 0; i < rkh_seq->rx.num_last; i++) {
1068*a1157835SDaniel Fojt 			if (rkh_seq->rx.last[i] == msg_seq)
1069*a1157835SDaniel Fojt 				goto out; /* duplicate message, drop it */
1070*a1157835SDaniel Fojt 		}
1071*a1157835SDaniel Fojt 
1072*a1157835SDaniel Fojt 		return FT_RRB_SEQ_OK;
1073*a1157835SDaniel Fojt 	}
1074*a1157835SDaniel Fojt 
1075*a1157835SDaniel Fojt defer:
1076*a1157835SDaniel Fojt 	if (no_defer)
1077*a1157835SDaniel Fojt 		goto out;
1078*a1157835SDaniel Fojt 
1079*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Possibly invalid sequence number in %s from "
1080*a1157835SDaniel Fojt 		   MACSTR, msgtype, MAC2STR(src_addr));
1081*a1157835SDaniel Fojt 
1082*a1157835SDaniel Fojt 	return FT_RRB_SEQ_DEFER;
1083*a1157835SDaniel Fojt out:
1084*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Invalid sequence number in %s from " MACSTR,
1085*a1157835SDaniel Fojt 		   msgtype, MAC2STR(src_addr));
1086*a1157835SDaniel Fojt 
1087*a1157835SDaniel Fojt 	return FT_RRB_SEQ_DROP;
1088*a1157835SDaniel Fojt }
1089*a1157835SDaniel Fojt 
1090*a1157835SDaniel Fojt 
1091*a1157835SDaniel Fojt static void
wpa_ft_rrb_seq_accept(struct wpa_authenticator * wpa_auth,struct ft_remote_seq * rkh_seq,const u8 * src_addr,const u8 * auth,size_t auth_len,const char * msgtype)1092*a1157835SDaniel Fojt wpa_ft_rrb_seq_accept(struct wpa_authenticator *wpa_auth,
1093*a1157835SDaniel Fojt 		      struct ft_remote_seq *rkh_seq, const u8 *src_addr,
1094*a1157835SDaniel Fojt 		      const u8 *auth, size_t auth_len,
1095*a1157835SDaniel Fojt 		      const char *msgtype)
1096*a1157835SDaniel Fojt {
1097*a1157835SDaniel Fojt 	const u8 *f_seq;
1098*a1157835SDaniel Fojt 	size_t f_seq_len;
1099*a1157835SDaniel Fojt 	const struct ft_rrb_seq *msg_both;
1100*a1157835SDaniel Fojt 	u32 msg_seq, msg_off, min_off, rkh_off;
1101*a1157835SDaniel Fojt 	int minidx = 0;
1102*a1157835SDaniel Fojt 	unsigned int i;
1103*a1157835SDaniel Fojt 
1104*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_SEQ, seq, msgtype, sizeof(*msg_both));
1105*a1157835SDaniel Fojt 	msg_both = (const struct ft_rrb_seq *) f_seq;
1106*a1157835SDaniel Fojt 
1107*a1157835SDaniel Fojt 	msg_seq = le_to_host32(msg_both->seq);
1108*a1157835SDaniel Fojt 
1109*a1157835SDaniel Fojt 	if (rkh_seq->rx.num_last < FT_REMOTE_SEQ_BACKLOG) {
1110*a1157835SDaniel Fojt 		rkh_seq->rx.last[rkh_seq->rx.num_last] = msg_seq;
1111*a1157835SDaniel Fojt 		rkh_seq->rx.num_last++;
1112*a1157835SDaniel Fojt 		return;
1113*a1157835SDaniel Fojt 	}
1114*a1157835SDaniel Fojt 
1115*a1157835SDaniel Fojt 	rkh_off = rkh_seq->rx.last[rkh_seq->rx.offsetidx];
1116*a1157835SDaniel Fojt 	for (i = 0; i < rkh_seq->rx.num_last; i++) {
1117*a1157835SDaniel Fojt 		msg_off = rkh_seq->rx.last[i] - rkh_off;
1118*a1157835SDaniel Fojt 		min_off = rkh_seq->rx.last[minidx] - rkh_off;
1119*a1157835SDaniel Fojt 		if (msg_off < min_off && i != rkh_seq->rx.offsetidx)
1120*a1157835SDaniel Fojt 			minidx = i;
1121*a1157835SDaniel Fojt 	}
1122*a1157835SDaniel Fojt 	rkh_seq->rx.last[rkh_seq->rx.offsetidx] = msg_seq;
1123*a1157835SDaniel Fojt 	rkh_seq->rx.offsetidx = minidx;
1124*a1157835SDaniel Fojt 
1125*a1157835SDaniel Fojt 	return;
1126*a1157835SDaniel Fojt out:
1127*a1157835SDaniel Fojt 	/* RRB_GET_AUTH should never fail here as
1128*a1157835SDaniel Fojt 	 * wpa_ft_rrb_seq_chk() verified FT_RRB_SEQ presence. */
1129*a1157835SDaniel Fojt 	wpa_printf(MSG_ERROR, "FT: %s() failed", __func__);
1130*a1157835SDaniel Fojt }
1131*a1157835SDaniel Fojt 
1132*a1157835SDaniel Fojt 
wpa_ft_new_seq(struct ft_remote_seq * rkh_seq,struct ft_rrb_seq * f_seq)1133*a1157835SDaniel Fojt static int wpa_ft_new_seq(struct ft_remote_seq *rkh_seq,
1134*a1157835SDaniel Fojt 			  struct ft_rrb_seq *f_seq)
1135*a1157835SDaniel Fojt {
1136*a1157835SDaniel Fojt 	struct os_reltime now;
1137*a1157835SDaniel Fojt 
1138*a1157835SDaniel Fojt 	if (os_get_reltime(&now) < 0)
1139*a1157835SDaniel Fojt 		return -1;
1140*a1157835SDaniel Fojt 
1141*a1157835SDaniel Fojt 	if (!rkh_seq->tx.dom) {
1142*a1157835SDaniel Fojt 		if (random_get_bytes((u8 *) &rkh_seq->tx.seq,
1143*a1157835SDaniel Fojt 				     sizeof(rkh_seq->tx.seq))) {
1144*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
1145*a1157835SDaniel Fojt 				   "FT: Failed to get random data for sequence number initialization");
1146*a1157835SDaniel Fojt 			rkh_seq->tx.seq = now.usec;
1147*a1157835SDaniel Fojt 		}
1148*a1157835SDaniel Fojt 		if (random_get_bytes((u8 *) &rkh_seq->tx.dom,
1149*a1157835SDaniel Fojt 				     sizeof(rkh_seq->tx.dom))) {
1150*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
1151*a1157835SDaniel Fojt 				   "FT: Failed to get random data for sequence number initialization");
1152*a1157835SDaniel Fojt 			rkh_seq->tx.dom = now.usec;
1153*a1157835SDaniel Fojt 		}
1154*a1157835SDaniel Fojt 		rkh_seq->tx.dom |= 1;
1155*a1157835SDaniel Fojt 	}
1156*a1157835SDaniel Fojt 
1157*a1157835SDaniel Fojt 	f_seq->dom = host_to_le32(rkh_seq->tx.dom);
1158*a1157835SDaniel Fojt 	f_seq->seq = host_to_le32(rkh_seq->tx.seq);
1159*a1157835SDaniel Fojt 	f_seq->ts = host_to_le32(now.sec);
1160*a1157835SDaniel Fojt 
1161*a1157835SDaniel Fojt 	rkh_seq->tx.seq++;
1162*a1157835SDaniel Fojt 
1163*a1157835SDaniel Fojt 	return 0;
1164*a1157835SDaniel Fojt }
1165*a1157835SDaniel Fojt 
1166*a1157835SDaniel Fojt 
11673ff40c12SJohn Marino struct wpa_ft_pmk_r0_sa {
1168*a1157835SDaniel Fojt 	struct dl_list list;
1169*a1157835SDaniel Fojt 	u8 pmk_r0[PMK_LEN_MAX];
1170*a1157835SDaniel Fojt 	size_t pmk_r0_len;
11713ff40c12SJohn Marino 	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
11723ff40c12SJohn Marino 	u8 spa[ETH_ALEN];
11733ff40c12SJohn Marino 	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
1174*a1157835SDaniel Fojt 	struct vlan_description *vlan;
1175*a1157835SDaniel Fojt 	os_time_t expiration; /* 0 for no expiration */
1176*a1157835SDaniel Fojt 	u8 *identity;
1177*a1157835SDaniel Fojt 	size_t identity_len;
1178*a1157835SDaniel Fojt 	u8 *radius_cui;
1179*a1157835SDaniel Fojt 	size_t radius_cui_len;
1180*a1157835SDaniel Fojt 	os_time_t session_timeout; /* 0 for no expiration */
1181*a1157835SDaniel Fojt 	/* TODO: radius_class, EAP type */
11823ff40c12SJohn Marino 	int pmk_r1_pushed;
11833ff40c12SJohn Marino };
11843ff40c12SJohn Marino 
11853ff40c12SJohn Marino struct wpa_ft_pmk_r1_sa {
1186*a1157835SDaniel Fojt 	struct dl_list list;
1187*a1157835SDaniel Fojt 	u8 pmk_r1[PMK_LEN_MAX];
1188*a1157835SDaniel Fojt 	size_t pmk_r1_len;
11893ff40c12SJohn Marino 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
11903ff40c12SJohn Marino 	u8 spa[ETH_ALEN];
11913ff40c12SJohn Marino 	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
1192*a1157835SDaniel Fojt 	struct vlan_description *vlan;
1193*a1157835SDaniel Fojt 	u8 *identity;
1194*a1157835SDaniel Fojt 	size_t identity_len;
1195*a1157835SDaniel Fojt 	u8 *radius_cui;
1196*a1157835SDaniel Fojt 	size_t radius_cui_len;
1197*a1157835SDaniel Fojt 	os_time_t session_timeout; /* 0 for no expiration */
1198*a1157835SDaniel Fojt 	/* TODO: radius_class, EAP type */
11993ff40c12SJohn Marino };
12003ff40c12SJohn Marino 
12013ff40c12SJohn Marino struct wpa_ft_pmk_cache {
1202*a1157835SDaniel Fojt 	struct dl_list pmk_r0; /* struct wpa_ft_pmk_r0_sa */
1203*a1157835SDaniel Fojt 	struct dl_list pmk_r1; /* struct wpa_ft_pmk_r1_sa */
12043ff40c12SJohn Marino };
12053ff40c12SJohn Marino 
1206*a1157835SDaniel Fojt 
1207*a1157835SDaniel Fojt static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx);
1208*a1157835SDaniel Fojt static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx);
1209*a1157835SDaniel Fojt 
1210*a1157835SDaniel Fojt 
wpa_ft_free_pmk_r0(struct wpa_ft_pmk_r0_sa * r0)1211*a1157835SDaniel Fojt static void wpa_ft_free_pmk_r0(struct wpa_ft_pmk_r0_sa *r0)
1212*a1157835SDaniel Fojt {
1213*a1157835SDaniel Fojt 	if (!r0)
1214*a1157835SDaniel Fojt 		return;
1215*a1157835SDaniel Fojt 
1216*a1157835SDaniel Fojt 	dl_list_del(&r0->list);
1217*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
1218*a1157835SDaniel Fojt 
1219*a1157835SDaniel Fojt 	os_memset(r0->pmk_r0, 0, PMK_LEN_MAX);
1220*a1157835SDaniel Fojt 	os_free(r0->vlan);
1221*a1157835SDaniel Fojt 	os_free(r0->identity);
1222*a1157835SDaniel Fojt 	os_free(r0->radius_cui);
1223*a1157835SDaniel Fojt 	os_free(r0);
1224*a1157835SDaniel Fojt }
1225*a1157835SDaniel Fojt 
1226*a1157835SDaniel Fojt 
wpa_ft_expire_pmk_r0(void * eloop_ctx,void * timeout_ctx)1227*a1157835SDaniel Fojt static void wpa_ft_expire_pmk_r0(void *eloop_ctx, void *timeout_ctx)
1228*a1157835SDaniel Fojt {
1229*a1157835SDaniel Fojt 	struct wpa_ft_pmk_r0_sa *r0 = eloop_ctx;
1230*a1157835SDaniel Fojt 	struct os_reltime now;
1231*a1157835SDaniel Fojt 	int expires_in;
1232*a1157835SDaniel Fojt 	int session_timeout;
1233*a1157835SDaniel Fojt 
1234*a1157835SDaniel Fojt 	os_get_reltime(&now);
1235*a1157835SDaniel Fojt 
1236*a1157835SDaniel Fojt 	if (!r0)
1237*a1157835SDaniel Fojt 		return;
1238*a1157835SDaniel Fojt 
1239*a1157835SDaniel Fojt 	expires_in = r0->expiration - now.sec;
1240*a1157835SDaniel Fojt 	session_timeout = r0->session_timeout - now.sec;
1241*a1157835SDaniel Fojt 	/* conditions to remove from cache:
1242*a1157835SDaniel Fojt 	 * a) r0->expiration is set and hit
1243*a1157835SDaniel Fojt 	 * -or-
1244*a1157835SDaniel Fojt 	 * b) r0->session_timeout is set and hit
1245*a1157835SDaniel Fojt 	 */
1246*a1157835SDaniel Fojt 	if ((!r0->expiration || expires_in > 0) &&
1247*a1157835SDaniel Fojt 	    (!r0->session_timeout || session_timeout > 0)) {
1248*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR,
1249*a1157835SDaniel Fojt 			   "FT: %s() called for non-expired entry %p",
1250*a1157835SDaniel Fojt 			   __func__, r0);
1251*a1157835SDaniel Fojt 		eloop_cancel_timeout(wpa_ft_expire_pmk_r0, r0, NULL);
1252*a1157835SDaniel Fojt 		if (r0->expiration && expires_in > 0)
1253*a1157835SDaniel Fojt 			eloop_register_timeout(expires_in + 1, 0,
1254*a1157835SDaniel Fojt 					       wpa_ft_expire_pmk_r0, r0, NULL);
1255*a1157835SDaniel Fojt 		if (r0->session_timeout && session_timeout > 0)
1256*a1157835SDaniel Fojt 			eloop_register_timeout(session_timeout + 1, 0,
1257*a1157835SDaniel Fojt 					       wpa_ft_expire_pmk_r0, r0, NULL);
1258*a1157835SDaniel Fojt 		return;
1259*a1157835SDaniel Fojt 	}
1260*a1157835SDaniel Fojt 
1261*a1157835SDaniel Fojt 	wpa_ft_free_pmk_r0(r0);
1262*a1157835SDaniel Fojt }
1263*a1157835SDaniel Fojt 
1264*a1157835SDaniel Fojt 
wpa_ft_free_pmk_r1(struct wpa_ft_pmk_r1_sa * r1)1265*a1157835SDaniel Fojt static void wpa_ft_free_pmk_r1(struct wpa_ft_pmk_r1_sa *r1)
1266*a1157835SDaniel Fojt {
1267*a1157835SDaniel Fojt 	if (!r1)
1268*a1157835SDaniel Fojt 		return;
1269*a1157835SDaniel Fojt 
1270*a1157835SDaniel Fojt 	dl_list_del(&r1->list);
1271*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpa_ft_expire_pmk_r1, r1, NULL);
1272*a1157835SDaniel Fojt 
1273*a1157835SDaniel Fojt 	os_memset(r1->pmk_r1, 0, PMK_LEN_MAX);
1274*a1157835SDaniel Fojt 	os_free(r1->vlan);
1275*a1157835SDaniel Fojt 	os_free(r1->identity);
1276*a1157835SDaniel Fojt 	os_free(r1->radius_cui);
1277*a1157835SDaniel Fojt 	os_free(r1);
1278*a1157835SDaniel Fojt }
1279*a1157835SDaniel Fojt 
1280*a1157835SDaniel Fojt 
wpa_ft_expire_pmk_r1(void * eloop_ctx,void * timeout_ctx)1281*a1157835SDaniel Fojt static void wpa_ft_expire_pmk_r1(void *eloop_ctx, void *timeout_ctx)
1282*a1157835SDaniel Fojt {
1283*a1157835SDaniel Fojt 	struct wpa_ft_pmk_r1_sa *r1 = eloop_ctx;
1284*a1157835SDaniel Fojt 
1285*a1157835SDaniel Fojt 	wpa_ft_free_pmk_r1(r1);
1286*a1157835SDaniel Fojt }
1287*a1157835SDaniel Fojt 
1288*a1157835SDaniel Fojt 
wpa_ft_pmk_cache_init(void)12893ff40c12SJohn Marino struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
12903ff40c12SJohn Marino {
12913ff40c12SJohn Marino 	struct wpa_ft_pmk_cache *cache;
12923ff40c12SJohn Marino 
12933ff40c12SJohn Marino 	cache = os_zalloc(sizeof(*cache));
1294*a1157835SDaniel Fojt 	if (cache) {
1295*a1157835SDaniel Fojt 		dl_list_init(&cache->pmk_r0);
1296*a1157835SDaniel Fojt 		dl_list_init(&cache->pmk_r1);
1297*a1157835SDaniel Fojt 	}
12983ff40c12SJohn Marino 
12993ff40c12SJohn Marino 	return cache;
13003ff40c12SJohn Marino }
13013ff40c12SJohn Marino 
13023ff40c12SJohn Marino 
wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache * cache)13033ff40c12SJohn Marino void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
13043ff40c12SJohn Marino {
13053ff40c12SJohn Marino 	struct wpa_ft_pmk_r0_sa *r0, *r0prev;
13063ff40c12SJohn Marino 	struct wpa_ft_pmk_r1_sa *r1, *r1prev;
13073ff40c12SJohn Marino 
1308*a1157835SDaniel Fojt 	dl_list_for_each_safe(r0, r0prev, &cache->pmk_r0,
1309*a1157835SDaniel Fojt 			      struct wpa_ft_pmk_r0_sa, list)
1310*a1157835SDaniel Fojt 		wpa_ft_free_pmk_r0(r0);
13113ff40c12SJohn Marino 
1312*a1157835SDaniel Fojt 	dl_list_for_each_safe(r1, r1prev, &cache->pmk_r1,
1313*a1157835SDaniel Fojt 			      struct wpa_ft_pmk_r1_sa, list)
1314*a1157835SDaniel Fojt 		wpa_ft_free_pmk_r1(r1);
13153ff40c12SJohn Marino 
13163ff40c12SJohn Marino 	os_free(cache);
13173ff40c12SJohn Marino }
13183ff40c12SJohn Marino 
13193ff40c12SJohn Marino 
wpa_ft_store_pmk_r0(struct wpa_authenticator * wpa_auth,const u8 * spa,const u8 * pmk_r0,size_t pmk_r0_len,const u8 * pmk_r0_name,int pairwise,const struct vlan_description * vlan,int expires_in,int session_timeout,const u8 * identity,size_t identity_len,const u8 * radius_cui,size_t radius_cui_len)13203ff40c12SJohn Marino static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
13213ff40c12SJohn Marino 			       const u8 *spa, const u8 *pmk_r0,
1322*a1157835SDaniel Fojt 			       size_t pmk_r0_len,
1323*a1157835SDaniel Fojt 			       const u8 *pmk_r0_name, int pairwise,
1324*a1157835SDaniel Fojt 			       const struct vlan_description *vlan,
1325*a1157835SDaniel Fojt 			       int expires_in, int session_timeout,
1326*a1157835SDaniel Fojt 			       const u8 *identity, size_t identity_len,
1327*a1157835SDaniel Fojt 			       const u8 *radius_cui, size_t radius_cui_len)
13283ff40c12SJohn Marino {
13293ff40c12SJohn Marino 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
13303ff40c12SJohn Marino 	struct wpa_ft_pmk_r0_sa *r0;
1331*a1157835SDaniel Fojt 	struct os_reltime now;
13323ff40c12SJohn Marino 
1333*a1157835SDaniel Fojt 	/* TODO: add limit on number of entries in cache */
1334*a1157835SDaniel Fojt 	os_get_reltime(&now);
13353ff40c12SJohn Marino 
13363ff40c12SJohn Marino 	r0 = os_zalloc(sizeof(*r0));
13373ff40c12SJohn Marino 	if (r0 == NULL)
13383ff40c12SJohn Marino 		return -1;
13393ff40c12SJohn Marino 
1340*a1157835SDaniel Fojt 	os_memcpy(r0->pmk_r0, pmk_r0, pmk_r0_len);
1341*a1157835SDaniel Fojt 	r0->pmk_r0_len = pmk_r0_len;
13423ff40c12SJohn Marino 	os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
13433ff40c12SJohn Marino 	os_memcpy(r0->spa, spa, ETH_ALEN);
13443ff40c12SJohn Marino 	r0->pairwise = pairwise;
1345*a1157835SDaniel Fojt 	if (expires_in > 0)
1346*a1157835SDaniel Fojt 		r0->expiration = now.sec + expires_in;
1347*a1157835SDaniel Fojt 	if (vlan && vlan->notempty) {
1348*a1157835SDaniel Fojt 		r0->vlan = os_zalloc(sizeof(*vlan));
1349*a1157835SDaniel Fojt 		if (!r0->vlan) {
1350*a1157835SDaniel Fojt 			bin_clear_free(r0, sizeof(*r0));
1351*a1157835SDaniel Fojt 			return -1;
1352*a1157835SDaniel Fojt 		}
1353*a1157835SDaniel Fojt 		*r0->vlan = *vlan;
1354*a1157835SDaniel Fojt 	}
1355*a1157835SDaniel Fojt 	if (identity) {
1356*a1157835SDaniel Fojt 		r0->identity = os_malloc(identity_len);
1357*a1157835SDaniel Fojt 		if (r0->identity) {
1358*a1157835SDaniel Fojt 			os_memcpy(r0->identity, identity, identity_len);
1359*a1157835SDaniel Fojt 			r0->identity_len = identity_len;
1360*a1157835SDaniel Fojt 		}
1361*a1157835SDaniel Fojt 	}
1362*a1157835SDaniel Fojt 	if (radius_cui) {
1363*a1157835SDaniel Fojt 		r0->radius_cui = os_malloc(radius_cui_len);
1364*a1157835SDaniel Fojt 		if (r0->radius_cui) {
1365*a1157835SDaniel Fojt 			os_memcpy(r0->radius_cui, radius_cui, radius_cui_len);
1366*a1157835SDaniel Fojt 			r0->radius_cui_len = radius_cui_len;
1367*a1157835SDaniel Fojt 		}
1368*a1157835SDaniel Fojt 	}
1369*a1157835SDaniel Fojt 	if (session_timeout > 0)
1370*a1157835SDaniel Fojt 		r0->session_timeout = now.sec + session_timeout;
13713ff40c12SJohn Marino 
1372*a1157835SDaniel Fojt 	dl_list_add(&cache->pmk_r0, &r0->list);
1373*a1157835SDaniel Fojt 	if (expires_in > 0)
1374*a1157835SDaniel Fojt 		eloop_register_timeout(expires_in + 1, 0, wpa_ft_expire_pmk_r0,
1375*a1157835SDaniel Fojt 				       r0, NULL);
1376*a1157835SDaniel Fojt 	if (session_timeout > 0)
1377*a1157835SDaniel Fojt 		eloop_register_timeout(session_timeout + 1, 0,
1378*a1157835SDaniel Fojt 				       wpa_ft_expire_pmk_r0, r0, NULL);
13793ff40c12SJohn Marino 
13803ff40c12SJohn Marino 	return 0;
13813ff40c12SJohn Marino }
13823ff40c12SJohn Marino 
13833ff40c12SJohn Marino 
wpa_ft_fetch_pmk_r0(struct wpa_authenticator * wpa_auth,const u8 * spa,const u8 * pmk_r0_name,const struct wpa_ft_pmk_r0_sa ** r0_out)13843ff40c12SJohn Marino static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
13853ff40c12SJohn Marino 			       const u8 *spa, const u8 *pmk_r0_name,
1386*a1157835SDaniel Fojt 			       const struct wpa_ft_pmk_r0_sa **r0_out)
13873ff40c12SJohn Marino {
13883ff40c12SJohn Marino 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
13893ff40c12SJohn Marino 	struct wpa_ft_pmk_r0_sa *r0;
1390*a1157835SDaniel Fojt 	struct os_reltime now;
13913ff40c12SJohn Marino 
1392*a1157835SDaniel Fojt 	os_get_reltime(&now);
1393*a1157835SDaniel Fojt 	dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
13943ff40c12SJohn Marino 		if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
1395*a1157835SDaniel Fojt 		    os_memcmp_const(r0->pmk_r0_name, pmk_r0_name,
1396*a1157835SDaniel Fojt 				    WPA_PMK_NAME_LEN) == 0) {
1397*a1157835SDaniel Fojt 			*r0_out = r0;
13983ff40c12SJohn Marino 			return 0;
13993ff40c12SJohn Marino 		}
14003ff40c12SJohn Marino 	}
14013ff40c12SJohn Marino 
1402*a1157835SDaniel Fojt 	*r0_out = NULL;
14033ff40c12SJohn Marino 	return -1;
14043ff40c12SJohn Marino }
14053ff40c12SJohn Marino 
14063ff40c12SJohn Marino 
wpa_ft_store_pmk_r1(struct wpa_authenticator * wpa_auth,const u8 * spa,const u8 * pmk_r1,size_t pmk_r1_len,const u8 * pmk_r1_name,int pairwise,const struct vlan_description * vlan,int expires_in,int session_timeout,const u8 * identity,size_t identity_len,const u8 * radius_cui,size_t radius_cui_len)14073ff40c12SJohn Marino static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
14083ff40c12SJohn Marino 			       const u8 *spa, const u8 *pmk_r1,
1409*a1157835SDaniel Fojt 			       size_t pmk_r1_len,
1410*a1157835SDaniel Fojt 			       const u8 *pmk_r1_name, int pairwise,
1411*a1157835SDaniel Fojt 			       const struct vlan_description *vlan,
1412*a1157835SDaniel Fojt 			       int expires_in, int session_timeout,
1413*a1157835SDaniel Fojt 			       const u8 *identity, size_t identity_len,
1414*a1157835SDaniel Fojt 			       const u8 *radius_cui, size_t radius_cui_len)
14153ff40c12SJohn Marino {
14163ff40c12SJohn Marino 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
1417*a1157835SDaniel Fojt 	int max_expires_in = wpa_auth->conf.r1_max_key_lifetime;
14183ff40c12SJohn Marino 	struct wpa_ft_pmk_r1_sa *r1;
1419*a1157835SDaniel Fojt 	struct os_reltime now;
14203ff40c12SJohn Marino 
1421*a1157835SDaniel Fojt 	/* TODO: limit on number of entries in cache */
1422*a1157835SDaniel Fojt 	os_get_reltime(&now);
1423*a1157835SDaniel Fojt 
1424*a1157835SDaniel Fojt 	if (max_expires_in && (max_expires_in < expires_in || expires_in == 0))
1425*a1157835SDaniel Fojt 		expires_in = max_expires_in;
14263ff40c12SJohn Marino 
14273ff40c12SJohn Marino 	r1 = os_zalloc(sizeof(*r1));
14283ff40c12SJohn Marino 	if (r1 == NULL)
14293ff40c12SJohn Marino 		return -1;
14303ff40c12SJohn Marino 
1431*a1157835SDaniel Fojt 	os_memcpy(r1->pmk_r1, pmk_r1, pmk_r1_len);
1432*a1157835SDaniel Fojt 	r1->pmk_r1_len = pmk_r1_len;
14333ff40c12SJohn Marino 	os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
14343ff40c12SJohn Marino 	os_memcpy(r1->spa, spa, ETH_ALEN);
14353ff40c12SJohn Marino 	r1->pairwise = pairwise;
1436*a1157835SDaniel Fojt 	if (vlan && vlan->notempty) {
1437*a1157835SDaniel Fojt 		r1->vlan = os_zalloc(sizeof(*vlan));
1438*a1157835SDaniel Fojt 		if (!r1->vlan) {
1439*a1157835SDaniel Fojt 			bin_clear_free(r1, sizeof(*r1));
1440*a1157835SDaniel Fojt 			return -1;
1441*a1157835SDaniel Fojt 		}
1442*a1157835SDaniel Fojt 		*r1->vlan = *vlan;
1443*a1157835SDaniel Fojt 	}
1444*a1157835SDaniel Fojt 	if (identity) {
1445*a1157835SDaniel Fojt 		r1->identity = os_malloc(identity_len);
1446*a1157835SDaniel Fojt 		if (r1->identity) {
1447*a1157835SDaniel Fojt 			os_memcpy(r1->identity, identity, identity_len);
1448*a1157835SDaniel Fojt 			r1->identity_len = identity_len;
1449*a1157835SDaniel Fojt 		}
1450*a1157835SDaniel Fojt 	}
1451*a1157835SDaniel Fojt 	if (radius_cui) {
1452*a1157835SDaniel Fojt 		r1->radius_cui = os_malloc(radius_cui_len);
1453*a1157835SDaniel Fojt 		if (r1->radius_cui) {
1454*a1157835SDaniel Fojt 			os_memcpy(r1->radius_cui, radius_cui, radius_cui_len);
1455*a1157835SDaniel Fojt 			r1->radius_cui_len = radius_cui_len;
1456*a1157835SDaniel Fojt 		}
1457*a1157835SDaniel Fojt 	}
1458*a1157835SDaniel Fojt 	if (session_timeout > 0)
1459*a1157835SDaniel Fojt 		r1->session_timeout = now.sec + session_timeout;
14603ff40c12SJohn Marino 
1461*a1157835SDaniel Fojt 	dl_list_add(&cache->pmk_r1, &r1->list);
1462*a1157835SDaniel Fojt 
1463*a1157835SDaniel Fojt 	if (expires_in > 0)
1464*a1157835SDaniel Fojt 		eloop_register_timeout(expires_in + 1, 0, wpa_ft_expire_pmk_r1,
1465*a1157835SDaniel Fojt 				       r1, NULL);
1466*a1157835SDaniel Fojt 	if (session_timeout > 0)
1467*a1157835SDaniel Fojt 		eloop_register_timeout(session_timeout + 1, 0,
1468*a1157835SDaniel Fojt 				       wpa_ft_expire_pmk_r1, r1, NULL);
14693ff40c12SJohn Marino 
14703ff40c12SJohn Marino 	return 0;
14713ff40c12SJohn Marino }
14723ff40c12SJohn Marino 
14733ff40c12SJohn Marino 
wpa_ft_fetch_pmk_r1(struct wpa_authenticator * wpa_auth,const u8 * spa,const u8 * pmk_r1_name,u8 * pmk_r1,size_t * pmk_r1_len,int * pairwise,struct vlan_description * vlan,const u8 ** identity,size_t * identity_len,const u8 ** radius_cui,size_t * radius_cui_len,int * session_timeout)14743ff40c12SJohn Marino static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
14753ff40c12SJohn Marino 			       const u8 *spa, const u8 *pmk_r1_name,
1476*a1157835SDaniel Fojt 			       u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
1477*a1157835SDaniel Fojt 			       struct vlan_description *vlan,
1478*a1157835SDaniel Fojt 			       const u8 **identity, size_t *identity_len,
1479*a1157835SDaniel Fojt 			       const u8 **radius_cui, size_t *radius_cui_len,
1480*a1157835SDaniel Fojt 			       int *session_timeout)
14813ff40c12SJohn Marino {
14823ff40c12SJohn Marino 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
14833ff40c12SJohn Marino 	struct wpa_ft_pmk_r1_sa *r1;
1484*a1157835SDaniel Fojt 	struct os_reltime now;
14853ff40c12SJohn Marino 
1486*a1157835SDaniel Fojt 	os_get_reltime(&now);
1487*a1157835SDaniel Fojt 
1488*a1157835SDaniel Fojt 	dl_list_for_each(r1, &cache->pmk_r1, struct wpa_ft_pmk_r1_sa, list) {
14893ff40c12SJohn Marino 		if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
1490*a1157835SDaniel Fojt 		    os_memcmp_const(r1->pmk_r1_name, pmk_r1_name,
1491*a1157835SDaniel Fojt 				    WPA_PMK_NAME_LEN) == 0) {
1492*a1157835SDaniel Fojt 			os_memcpy(pmk_r1, r1->pmk_r1, r1->pmk_r1_len);
1493*a1157835SDaniel Fojt 			*pmk_r1_len = r1->pmk_r1_len;
14943ff40c12SJohn Marino 			if (pairwise)
14953ff40c12SJohn Marino 				*pairwise = r1->pairwise;
1496*a1157835SDaniel Fojt 			if (vlan && r1->vlan)
1497*a1157835SDaniel Fojt 				*vlan = *r1->vlan;
1498*a1157835SDaniel Fojt 			if (vlan && !r1->vlan)
1499*a1157835SDaniel Fojt 				os_memset(vlan, 0, sizeof(*vlan));
1500*a1157835SDaniel Fojt 			if (identity && identity_len) {
1501*a1157835SDaniel Fojt 				*identity = r1->identity;
1502*a1157835SDaniel Fojt 				*identity_len = r1->identity_len;
1503*a1157835SDaniel Fojt 			}
1504*a1157835SDaniel Fojt 			if (radius_cui && radius_cui_len) {
1505*a1157835SDaniel Fojt 				*radius_cui = r1->radius_cui;
1506*a1157835SDaniel Fojt 				*radius_cui_len = r1->radius_cui_len;
1507*a1157835SDaniel Fojt 			}
1508*a1157835SDaniel Fojt 			if (session_timeout && r1->session_timeout > now.sec)
1509*a1157835SDaniel Fojt 				*session_timeout = r1->session_timeout -
1510*a1157835SDaniel Fojt 					now.sec;
1511*a1157835SDaniel Fojt 			else if (session_timeout && r1->session_timeout)
1512*a1157835SDaniel Fojt 				*session_timeout = 1;
1513*a1157835SDaniel Fojt 			else if (session_timeout)
1514*a1157835SDaniel Fojt 				*session_timeout = 0;
1515*a1157835SDaniel Fojt 			return 0;
1516*a1157835SDaniel Fojt 		}
1517*a1157835SDaniel Fojt 	}
1518*a1157835SDaniel Fojt 
1519*a1157835SDaniel Fojt 	return -1;
1520*a1157835SDaniel Fojt }
1521*a1157835SDaniel Fojt 
1522*a1157835SDaniel Fojt 
wpa_ft_rrb_init_r0kh_seq(struct ft_remote_r0kh * r0kh)1523*a1157835SDaniel Fojt static int wpa_ft_rrb_init_r0kh_seq(struct ft_remote_r0kh *r0kh)
1524*a1157835SDaniel Fojt {
1525*a1157835SDaniel Fojt 	if (r0kh->seq)
1526*a1157835SDaniel Fojt 		return 0;
1527*a1157835SDaniel Fojt 
1528*a1157835SDaniel Fojt 	r0kh->seq = os_zalloc(sizeof(*r0kh->seq));
1529*a1157835SDaniel Fojt 	if (!r0kh->seq) {
1530*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Failed to allocate r0kh->seq");
1531*a1157835SDaniel Fojt 		return -1;
1532*a1157835SDaniel Fojt 	}
1533*a1157835SDaniel Fojt 
1534*a1157835SDaniel Fojt 	dl_list_init(&r0kh->seq->rx.queue);
1535*a1157835SDaniel Fojt 
15363ff40c12SJohn Marino 	return 0;
15373ff40c12SJohn Marino }
15383ff40c12SJohn Marino 
15393ff40c12SJohn Marino 
wpa_ft_rrb_lookup_r0kh(struct wpa_authenticator * wpa_auth,const u8 * f_r0kh_id,size_t f_r0kh_id_len,struct ft_remote_r0kh ** r0kh_out,struct ft_remote_r0kh ** r0kh_wildcard)1540*a1157835SDaniel Fojt static void wpa_ft_rrb_lookup_r0kh(struct wpa_authenticator *wpa_auth,
1541*a1157835SDaniel Fojt 				   const u8 *f_r0kh_id, size_t f_r0kh_id_len,
1542*a1157835SDaniel Fojt 				   struct ft_remote_r0kh **r0kh_out,
1543*a1157835SDaniel Fojt 				   struct ft_remote_r0kh **r0kh_wildcard)
15443ff40c12SJohn Marino {
15453ff40c12SJohn Marino 	struct ft_remote_r0kh *r0kh;
15463ff40c12SJohn Marino 
1547*a1157835SDaniel Fojt 	*r0kh_wildcard = NULL;
1548*a1157835SDaniel Fojt 	*r0kh_out = NULL;
1549*a1157835SDaniel Fojt 
1550*a1157835SDaniel Fojt 	if (wpa_auth->conf.r0kh_list)
1551*a1157835SDaniel Fojt 		r0kh = *wpa_auth->conf.r0kh_list;
1552*a1157835SDaniel Fojt 	else
1553*a1157835SDaniel Fojt 		r0kh = NULL;
1554*a1157835SDaniel Fojt 	for (; r0kh; r0kh = r0kh->next) {
1555*a1157835SDaniel Fojt 		if (r0kh->id_len == 1 && r0kh->id[0] == '*')
1556*a1157835SDaniel Fojt 			*r0kh_wildcard = r0kh;
1557*a1157835SDaniel Fojt 		if (f_r0kh_id && r0kh->id_len == f_r0kh_id_len &&
1558*a1157835SDaniel Fojt 		    os_memcmp_const(f_r0kh_id, r0kh->id, f_r0kh_id_len) == 0)
1559*a1157835SDaniel Fojt 			*r0kh_out = r0kh;
15603ff40c12SJohn Marino 	}
1561*a1157835SDaniel Fojt 
1562*a1157835SDaniel Fojt 	if (!*r0kh_out && !*r0kh_wildcard)
1563*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: No matching R0KH found");
1564*a1157835SDaniel Fojt 
1565*a1157835SDaniel Fojt 	if (*r0kh_out && wpa_ft_rrb_init_r0kh_seq(*r0kh_out) < 0)
1566*a1157835SDaniel Fojt 		*r0kh_out = NULL;
1567*a1157835SDaniel Fojt }
1568*a1157835SDaniel Fojt 
1569*a1157835SDaniel Fojt 
wpa_ft_rrb_init_r1kh_seq(struct ft_remote_r1kh * r1kh)1570*a1157835SDaniel Fojt static int wpa_ft_rrb_init_r1kh_seq(struct ft_remote_r1kh *r1kh)
1571*a1157835SDaniel Fojt {
1572*a1157835SDaniel Fojt 	if (r1kh->seq)
1573*a1157835SDaniel Fojt 		return 0;
1574*a1157835SDaniel Fojt 
1575*a1157835SDaniel Fojt 	r1kh->seq = os_zalloc(sizeof(*r1kh->seq));
1576*a1157835SDaniel Fojt 	if (!r1kh->seq) {
1577*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Failed to allocate r1kh->seq");
15783ff40c12SJohn Marino 		return -1;
1579*a1157835SDaniel Fojt 	}
1580*a1157835SDaniel Fojt 
1581*a1157835SDaniel Fojt 	dl_list_init(&r1kh->seq->rx.queue);
1582*a1157835SDaniel Fojt 
1583*a1157835SDaniel Fojt 	return 0;
1584*a1157835SDaniel Fojt }
1585*a1157835SDaniel Fojt 
1586*a1157835SDaniel Fojt 
wpa_ft_rrb_lookup_r1kh(struct wpa_authenticator * wpa_auth,const u8 * f_r1kh_id,struct ft_remote_r1kh ** r1kh_out,struct ft_remote_r1kh ** r1kh_wildcard)1587*a1157835SDaniel Fojt static void wpa_ft_rrb_lookup_r1kh(struct wpa_authenticator *wpa_auth,
1588*a1157835SDaniel Fojt 				   const u8 *f_r1kh_id,
1589*a1157835SDaniel Fojt 				   struct ft_remote_r1kh **r1kh_out,
1590*a1157835SDaniel Fojt 				   struct ft_remote_r1kh **r1kh_wildcard)
1591*a1157835SDaniel Fojt {
1592*a1157835SDaniel Fojt 	struct ft_remote_r1kh *r1kh;
1593*a1157835SDaniel Fojt 
1594*a1157835SDaniel Fojt 	*r1kh_wildcard = NULL;
1595*a1157835SDaniel Fojt 	*r1kh_out = NULL;
1596*a1157835SDaniel Fojt 
1597*a1157835SDaniel Fojt 	if (wpa_auth->conf.r1kh_list)
1598*a1157835SDaniel Fojt 		r1kh = *wpa_auth->conf.r1kh_list;
1599*a1157835SDaniel Fojt 	else
1600*a1157835SDaniel Fojt 		r1kh = NULL;
1601*a1157835SDaniel Fojt 	for (; r1kh; r1kh = r1kh->next) {
1602*a1157835SDaniel Fojt 		if (is_zero_ether_addr(r1kh->addr) &&
1603*a1157835SDaniel Fojt 		    is_zero_ether_addr(r1kh->id))
1604*a1157835SDaniel Fojt 			*r1kh_wildcard = r1kh;
1605*a1157835SDaniel Fojt 		if (f_r1kh_id &&
1606*a1157835SDaniel Fojt 		    os_memcmp_const(r1kh->id, f_r1kh_id, FT_R1KH_ID_LEN) == 0)
1607*a1157835SDaniel Fojt 			*r1kh_out = r1kh;
1608*a1157835SDaniel Fojt 	}
1609*a1157835SDaniel Fojt 
1610*a1157835SDaniel Fojt 	if (!*r1kh_out && !*r1kh_wildcard)
1611*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: No matching R1KH found");
1612*a1157835SDaniel Fojt 
1613*a1157835SDaniel Fojt 	if (*r1kh_out && wpa_ft_rrb_init_r1kh_seq(*r1kh_out) < 0)
1614*a1157835SDaniel Fojt 		*r1kh_out = NULL;
1615*a1157835SDaniel Fojt }
1616*a1157835SDaniel Fojt 
1617*a1157835SDaniel Fojt 
wpa_ft_rrb_check_r0kh(struct wpa_authenticator * wpa_auth,const u8 * f_r0kh_id,size_t f_r0kh_id_len)1618*a1157835SDaniel Fojt static int wpa_ft_rrb_check_r0kh(struct wpa_authenticator *wpa_auth,
1619*a1157835SDaniel Fojt 				 const u8 *f_r0kh_id, size_t f_r0kh_id_len)
1620*a1157835SDaniel Fojt {
1621*a1157835SDaniel Fojt 	if (f_r0kh_id_len != wpa_auth->conf.r0_key_holder_len ||
1622*a1157835SDaniel Fojt 	    os_memcmp_const(f_r0kh_id, wpa_auth->conf.r0_key_holder,
1623*a1157835SDaniel Fojt 			    f_r0kh_id_len) != 0)
1624*a1157835SDaniel Fojt 		return -1;
1625*a1157835SDaniel Fojt 
1626*a1157835SDaniel Fojt 	return 0;
1627*a1157835SDaniel Fojt }
1628*a1157835SDaniel Fojt 
1629*a1157835SDaniel Fojt 
wpa_ft_rrb_check_r1kh(struct wpa_authenticator * wpa_auth,const u8 * f_r1kh_id)1630*a1157835SDaniel Fojt static int wpa_ft_rrb_check_r1kh(struct wpa_authenticator *wpa_auth,
1631*a1157835SDaniel Fojt 				 const u8 *f_r1kh_id)
1632*a1157835SDaniel Fojt {
1633*a1157835SDaniel Fojt 	if (os_memcmp_const(f_r1kh_id, wpa_auth->conf.r1_key_holder,
1634*a1157835SDaniel Fojt 			    FT_R1KH_ID_LEN) != 0)
1635*a1157835SDaniel Fojt 		return -1;
1636*a1157835SDaniel Fojt 
1637*a1157835SDaniel Fojt 	return 0;
1638*a1157835SDaniel Fojt }
1639*a1157835SDaniel Fojt 
1640*a1157835SDaniel Fojt 
wpa_ft_rrb_del_r0kh(void * eloop_ctx,void * timeout_ctx)1641*a1157835SDaniel Fojt static void wpa_ft_rrb_del_r0kh(void *eloop_ctx, void *timeout_ctx)
1642*a1157835SDaniel Fojt {
1643*a1157835SDaniel Fojt 	struct wpa_authenticator *wpa_auth = eloop_ctx;
1644*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh, *prev = NULL;
1645*a1157835SDaniel Fojt 
1646*a1157835SDaniel Fojt 	if (!wpa_auth->conf.r0kh_list)
1647*a1157835SDaniel Fojt 		return;
1648*a1157835SDaniel Fojt 
1649*a1157835SDaniel Fojt 	for (r0kh = *wpa_auth->conf.r0kh_list; r0kh; r0kh = r0kh->next) {
1650*a1157835SDaniel Fojt 		if (r0kh == timeout_ctx)
1651*a1157835SDaniel Fojt 			break;
1652*a1157835SDaniel Fojt 		prev = r0kh;
1653*a1157835SDaniel Fojt 	}
1654*a1157835SDaniel Fojt 	if (!r0kh)
1655*a1157835SDaniel Fojt 		return;
1656*a1157835SDaniel Fojt 	if (prev)
1657*a1157835SDaniel Fojt 		prev->next = r0kh->next;
1658*a1157835SDaniel Fojt 	else
1659*a1157835SDaniel Fojt 		*wpa_auth->conf.r0kh_list = r0kh->next;
1660*a1157835SDaniel Fojt 	if (r0kh->seq)
1661*a1157835SDaniel Fojt 		wpa_ft_rrb_seq_flush(wpa_auth, r0kh->seq, 0);
1662*a1157835SDaniel Fojt 	os_free(r0kh->seq);
1663*a1157835SDaniel Fojt 	os_free(r0kh);
1664*a1157835SDaniel Fojt }
1665*a1157835SDaniel Fojt 
1666*a1157835SDaniel Fojt 
wpa_ft_rrb_r0kh_replenish(struct wpa_authenticator * wpa_auth,struct ft_remote_r0kh * r0kh,int timeout)1667*a1157835SDaniel Fojt static void wpa_ft_rrb_r0kh_replenish(struct wpa_authenticator *wpa_auth,
1668*a1157835SDaniel Fojt 				      struct ft_remote_r0kh *r0kh, int timeout)
1669*a1157835SDaniel Fojt {
1670*a1157835SDaniel Fojt 	if (timeout > 0)
1671*a1157835SDaniel Fojt 		eloop_replenish_timeout(timeout, 0, wpa_ft_rrb_del_r0kh,
1672*a1157835SDaniel Fojt 					wpa_auth, r0kh);
1673*a1157835SDaniel Fojt }
1674*a1157835SDaniel Fojt 
1675*a1157835SDaniel Fojt 
wpa_ft_rrb_r0kh_timeout(struct wpa_authenticator * wpa_auth,struct ft_remote_r0kh * r0kh,int timeout)1676*a1157835SDaniel Fojt static void wpa_ft_rrb_r0kh_timeout(struct wpa_authenticator *wpa_auth,
1677*a1157835SDaniel Fojt 				    struct ft_remote_r0kh *r0kh, int timeout)
1678*a1157835SDaniel Fojt {
1679*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpa_ft_rrb_del_r0kh, wpa_auth, r0kh);
1680*a1157835SDaniel Fojt 
1681*a1157835SDaniel Fojt 	if (timeout > 0)
1682*a1157835SDaniel Fojt 		eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r0kh,
1683*a1157835SDaniel Fojt 				       wpa_auth, r0kh);
1684*a1157835SDaniel Fojt }
1685*a1157835SDaniel Fojt 
1686*a1157835SDaniel Fojt 
1687*a1157835SDaniel Fojt static struct ft_remote_r0kh *
wpa_ft_rrb_add_r0kh(struct wpa_authenticator * wpa_auth,struct ft_remote_r0kh * r0kh_wildcard,const u8 * src_addr,const u8 * r0kh_id,size_t id_len,int timeout)1688*a1157835SDaniel Fojt wpa_ft_rrb_add_r0kh(struct wpa_authenticator *wpa_auth,
1689*a1157835SDaniel Fojt 		    struct ft_remote_r0kh *r0kh_wildcard,
1690*a1157835SDaniel Fojt 		    const u8 *src_addr, const u8 *r0kh_id, size_t id_len,
1691*a1157835SDaniel Fojt 		    int timeout)
1692*a1157835SDaniel Fojt {
1693*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh;
1694*a1157835SDaniel Fojt 
1695*a1157835SDaniel Fojt 	if (!wpa_auth->conf.r0kh_list)
1696*a1157835SDaniel Fojt 		return NULL;
1697*a1157835SDaniel Fojt 
1698*a1157835SDaniel Fojt 	r0kh = os_zalloc(sizeof(*r0kh));
1699*a1157835SDaniel Fojt 	if (!r0kh)
1700*a1157835SDaniel Fojt 		return NULL;
1701*a1157835SDaniel Fojt 
1702*a1157835SDaniel Fojt 	if (src_addr)
1703*a1157835SDaniel Fojt 		os_memcpy(r0kh->addr, src_addr, sizeof(r0kh->addr));
1704*a1157835SDaniel Fojt 
1705*a1157835SDaniel Fojt 	if (id_len > FT_R0KH_ID_MAX_LEN)
1706*a1157835SDaniel Fojt 		id_len = FT_R0KH_ID_MAX_LEN;
1707*a1157835SDaniel Fojt 	os_memcpy(r0kh->id, r0kh_id, id_len);
1708*a1157835SDaniel Fojt 	r0kh->id_len = id_len;
1709*a1157835SDaniel Fojt 
1710*a1157835SDaniel Fojt 	os_memcpy(r0kh->key, r0kh_wildcard->key, sizeof(r0kh->key));
1711*a1157835SDaniel Fojt 
1712*a1157835SDaniel Fojt 	r0kh->next = *wpa_auth->conf.r0kh_list;
1713*a1157835SDaniel Fojt 	*wpa_auth->conf.r0kh_list = r0kh;
1714*a1157835SDaniel Fojt 
1715*a1157835SDaniel Fojt 	if (timeout > 0)
1716*a1157835SDaniel Fojt 		eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r0kh,
1717*a1157835SDaniel Fojt 				       wpa_auth, r0kh);
1718*a1157835SDaniel Fojt 
1719*a1157835SDaniel Fojt 	if (wpa_ft_rrb_init_r0kh_seq(r0kh) < 0)
1720*a1157835SDaniel Fojt 		return NULL;
1721*a1157835SDaniel Fojt 
1722*a1157835SDaniel Fojt 	return r0kh;
1723*a1157835SDaniel Fojt }
1724*a1157835SDaniel Fojt 
1725*a1157835SDaniel Fojt 
wpa_ft_rrb_del_r1kh(void * eloop_ctx,void * timeout_ctx)1726*a1157835SDaniel Fojt static void wpa_ft_rrb_del_r1kh(void *eloop_ctx, void *timeout_ctx)
1727*a1157835SDaniel Fojt {
1728*a1157835SDaniel Fojt 	struct wpa_authenticator *wpa_auth = eloop_ctx;
1729*a1157835SDaniel Fojt 	struct ft_remote_r1kh *r1kh, *prev = NULL;
1730*a1157835SDaniel Fojt 
1731*a1157835SDaniel Fojt 	if (!wpa_auth->conf.r1kh_list)
1732*a1157835SDaniel Fojt 		return;
1733*a1157835SDaniel Fojt 
1734*a1157835SDaniel Fojt 	for (r1kh = *wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) {
1735*a1157835SDaniel Fojt 		if (r1kh == timeout_ctx)
1736*a1157835SDaniel Fojt 			break;
1737*a1157835SDaniel Fojt 		prev = r1kh;
1738*a1157835SDaniel Fojt 	}
1739*a1157835SDaniel Fojt 	if (!r1kh)
1740*a1157835SDaniel Fojt 		return;
1741*a1157835SDaniel Fojt 	if (prev)
1742*a1157835SDaniel Fojt 		prev->next = r1kh->next;
1743*a1157835SDaniel Fojt 	else
1744*a1157835SDaniel Fojt 		*wpa_auth->conf.r1kh_list = r1kh->next;
1745*a1157835SDaniel Fojt 	if (r1kh->seq)
1746*a1157835SDaniel Fojt 		wpa_ft_rrb_seq_flush(wpa_auth, r1kh->seq, 0);
1747*a1157835SDaniel Fojt 	os_free(r1kh->seq);
1748*a1157835SDaniel Fojt 	os_free(r1kh);
1749*a1157835SDaniel Fojt }
1750*a1157835SDaniel Fojt 
1751*a1157835SDaniel Fojt 
wpa_ft_rrb_r1kh_replenish(struct wpa_authenticator * wpa_auth,struct ft_remote_r1kh * r1kh,int timeout)1752*a1157835SDaniel Fojt static void wpa_ft_rrb_r1kh_replenish(struct wpa_authenticator *wpa_auth,
1753*a1157835SDaniel Fojt 				      struct ft_remote_r1kh *r1kh, int timeout)
1754*a1157835SDaniel Fojt {
1755*a1157835SDaniel Fojt 	if (timeout > 0)
1756*a1157835SDaniel Fojt 		eloop_replenish_timeout(timeout, 0, wpa_ft_rrb_del_r1kh,
1757*a1157835SDaniel Fojt 					wpa_auth, r1kh);
1758*a1157835SDaniel Fojt }
1759*a1157835SDaniel Fojt 
1760*a1157835SDaniel Fojt 
1761*a1157835SDaniel Fojt static struct ft_remote_r1kh *
wpa_ft_rrb_add_r1kh(struct wpa_authenticator * wpa_auth,struct ft_remote_r1kh * r1kh_wildcard,const u8 * src_addr,const u8 * r1kh_id,int timeout)1762*a1157835SDaniel Fojt wpa_ft_rrb_add_r1kh(struct wpa_authenticator *wpa_auth,
1763*a1157835SDaniel Fojt 		    struct ft_remote_r1kh *r1kh_wildcard,
1764*a1157835SDaniel Fojt 		    const u8 *src_addr, const u8 *r1kh_id, int timeout)
1765*a1157835SDaniel Fojt {
1766*a1157835SDaniel Fojt 	struct ft_remote_r1kh *r1kh;
1767*a1157835SDaniel Fojt 
1768*a1157835SDaniel Fojt 	if (!wpa_auth->conf.r1kh_list)
1769*a1157835SDaniel Fojt 		return NULL;
1770*a1157835SDaniel Fojt 
1771*a1157835SDaniel Fojt 	r1kh = os_zalloc(sizeof(*r1kh));
1772*a1157835SDaniel Fojt 	if (!r1kh)
1773*a1157835SDaniel Fojt 		return NULL;
1774*a1157835SDaniel Fojt 
1775*a1157835SDaniel Fojt 	os_memcpy(r1kh->addr, src_addr, sizeof(r1kh->addr));
1776*a1157835SDaniel Fojt 	os_memcpy(r1kh->id, r1kh_id, sizeof(r1kh->id));
1777*a1157835SDaniel Fojt 	os_memcpy(r1kh->key, r1kh_wildcard->key, sizeof(r1kh->key));
1778*a1157835SDaniel Fojt 	r1kh->next = *wpa_auth->conf.r1kh_list;
1779*a1157835SDaniel Fojt 	*wpa_auth->conf.r1kh_list = r1kh;
1780*a1157835SDaniel Fojt 
1781*a1157835SDaniel Fojt 	if (timeout > 0)
1782*a1157835SDaniel Fojt 		eloop_register_timeout(timeout, 0, wpa_ft_rrb_del_r1kh,
1783*a1157835SDaniel Fojt 				       wpa_auth, r1kh);
1784*a1157835SDaniel Fojt 
1785*a1157835SDaniel Fojt 	if (wpa_ft_rrb_init_r1kh_seq(r1kh) < 0)
1786*a1157835SDaniel Fojt 		return NULL;
1787*a1157835SDaniel Fojt 
1788*a1157835SDaniel Fojt 	return r1kh;
1789*a1157835SDaniel Fojt }
1790*a1157835SDaniel Fojt 
1791*a1157835SDaniel Fojt 
wpa_ft_sta_deinit(struct wpa_state_machine * sm)1792*a1157835SDaniel Fojt void wpa_ft_sta_deinit(struct wpa_state_machine *sm)
1793*a1157835SDaniel Fojt {
1794*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL);
1795*a1157835SDaniel Fojt }
1796*a1157835SDaniel Fojt 
1797*a1157835SDaniel Fojt 
wpa_ft_deinit_seq(struct wpa_authenticator * wpa_auth)1798*a1157835SDaniel Fojt static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth)
1799*a1157835SDaniel Fojt {
1800*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh;
1801*a1157835SDaniel Fojt 	struct ft_remote_r1kh *r1kh;
1802*a1157835SDaniel Fojt 
1803*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpa_ft_rrb_seq_timeout, wpa_auth, ELOOP_ALL_CTX);
1804*a1157835SDaniel Fojt 
1805*a1157835SDaniel Fojt 	if (wpa_auth->conf.r0kh_list)
1806*a1157835SDaniel Fojt 		r0kh = *wpa_auth->conf.r0kh_list;
1807*a1157835SDaniel Fojt 	else
1808*a1157835SDaniel Fojt 		r0kh = NULL;
1809*a1157835SDaniel Fojt 	for (; r0kh; r0kh = r0kh->next) {
1810*a1157835SDaniel Fojt 		if (!r0kh->seq)
1811*a1157835SDaniel Fojt 			continue;
1812*a1157835SDaniel Fojt 		wpa_ft_rrb_seq_flush(wpa_auth, r0kh->seq, 0);
1813*a1157835SDaniel Fojt 		os_free(r0kh->seq);
1814*a1157835SDaniel Fojt 		r0kh->seq = NULL;
1815*a1157835SDaniel Fojt 	}
1816*a1157835SDaniel Fojt 
1817*a1157835SDaniel Fojt 	if (wpa_auth->conf.r1kh_list)
1818*a1157835SDaniel Fojt 		r1kh = *wpa_auth->conf.r1kh_list;
1819*a1157835SDaniel Fojt 	else
1820*a1157835SDaniel Fojt 		r1kh = NULL;
1821*a1157835SDaniel Fojt 	for (; r1kh; r1kh = r1kh->next) {
1822*a1157835SDaniel Fojt 		if (!r1kh->seq)
1823*a1157835SDaniel Fojt 			continue;
1824*a1157835SDaniel Fojt 		wpa_ft_rrb_seq_flush(wpa_auth, r1kh->seq, 0);
1825*a1157835SDaniel Fojt 		os_free(r1kh->seq);
1826*a1157835SDaniel Fojt 		r1kh->seq = NULL;
1827*a1157835SDaniel Fojt 	}
1828*a1157835SDaniel Fojt }
1829*a1157835SDaniel Fojt 
1830*a1157835SDaniel Fojt 
wpa_ft_deinit_rkh_tmp(struct wpa_authenticator * wpa_auth)1831*a1157835SDaniel Fojt static void wpa_ft_deinit_rkh_tmp(struct wpa_authenticator *wpa_auth)
1832*a1157835SDaniel Fojt {
1833*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh, *r0kh_next, *r0kh_prev = NULL;
1834*a1157835SDaniel Fojt 	struct ft_remote_r1kh *r1kh, *r1kh_next, *r1kh_prev = NULL;
1835*a1157835SDaniel Fojt 
1836*a1157835SDaniel Fojt 	if (wpa_auth->conf.r0kh_list)
1837*a1157835SDaniel Fojt 		r0kh = *wpa_auth->conf.r0kh_list;
1838*a1157835SDaniel Fojt 	else
1839*a1157835SDaniel Fojt 		r0kh = NULL;
1840*a1157835SDaniel Fojt 	while (r0kh) {
1841*a1157835SDaniel Fojt 		r0kh_next = r0kh->next;
1842*a1157835SDaniel Fojt 		if (eloop_cancel_timeout(wpa_ft_rrb_del_r0kh, wpa_auth,
1843*a1157835SDaniel Fojt 					 r0kh) > 0) {
1844*a1157835SDaniel Fojt 			if (r0kh_prev)
1845*a1157835SDaniel Fojt 				r0kh_prev->next = r0kh_next;
1846*a1157835SDaniel Fojt 			else
1847*a1157835SDaniel Fojt 				*wpa_auth->conf.r0kh_list = r0kh_next;
1848*a1157835SDaniel Fojt 			os_free(r0kh);
1849*a1157835SDaniel Fojt 		} else {
1850*a1157835SDaniel Fojt 			r0kh_prev = r0kh;
1851*a1157835SDaniel Fojt 		}
1852*a1157835SDaniel Fojt 		r0kh = r0kh_next;
1853*a1157835SDaniel Fojt 	}
1854*a1157835SDaniel Fojt 
1855*a1157835SDaniel Fojt 	if (wpa_auth->conf.r1kh_list)
1856*a1157835SDaniel Fojt 		r1kh = *wpa_auth->conf.r1kh_list;
1857*a1157835SDaniel Fojt 	else
1858*a1157835SDaniel Fojt 		r1kh = NULL;
1859*a1157835SDaniel Fojt 	while (r1kh) {
1860*a1157835SDaniel Fojt 		r1kh_next = r1kh->next;
1861*a1157835SDaniel Fojt 		if (eloop_cancel_timeout(wpa_ft_rrb_del_r1kh, wpa_auth,
1862*a1157835SDaniel Fojt 					 r1kh) > 0) {
1863*a1157835SDaniel Fojt 			if (r1kh_prev)
1864*a1157835SDaniel Fojt 				r1kh_prev->next = r1kh_next;
1865*a1157835SDaniel Fojt 			else
1866*a1157835SDaniel Fojt 				*wpa_auth->conf.r1kh_list = r1kh_next;
1867*a1157835SDaniel Fojt 			os_free(r1kh);
1868*a1157835SDaniel Fojt 		} else {
1869*a1157835SDaniel Fojt 			r1kh_prev = r1kh;
1870*a1157835SDaniel Fojt 		}
1871*a1157835SDaniel Fojt 		r1kh = r1kh_next;
1872*a1157835SDaniel Fojt 	}
1873*a1157835SDaniel Fojt }
1874*a1157835SDaniel Fojt 
1875*a1157835SDaniel Fojt 
wpa_ft_deinit(struct wpa_authenticator * wpa_auth)1876*a1157835SDaniel Fojt void wpa_ft_deinit(struct wpa_authenticator *wpa_auth)
1877*a1157835SDaniel Fojt {
1878*a1157835SDaniel Fojt 	wpa_ft_deinit_seq(wpa_auth);
1879*a1157835SDaniel Fojt 	wpa_ft_deinit_rkh_tmp(wpa_auth);
1880*a1157835SDaniel Fojt }
1881*a1157835SDaniel Fojt 
1882*a1157835SDaniel Fojt 
wpa_ft_block_r0kh(struct wpa_authenticator * wpa_auth,const u8 * f_r0kh_id,size_t f_r0kh_id_len)1883*a1157835SDaniel Fojt static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth,
1884*a1157835SDaniel Fojt 			      const u8 *f_r0kh_id, size_t f_r0kh_id_len)
1885*a1157835SDaniel Fojt {
1886*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh, *r0kh_wildcard;
1887*a1157835SDaniel Fojt 
1888*a1157835SDaniel Fojt 	if (!wpa_auth->conf.rkh_neg_timeout)
1889*a1157835SDaniel Fojt 		return;
1890*a1157835SDaniel Fojt 
1891*a1157835SDaniel Fojt 	wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len,
1892*a1157835SDaniel Fojt 			       &r0kh, &r0kh_wildcard);
1893*a1157835SDaniel Fojt 
1894*a1157835SDaniel Fojt 	if (!r0kh_wildcard) {
1895*a1157835SDaniel Fojt 		/* r0kh removed after neg_timeout and might need re-adding */
1896*a1157835SDaniel Fojt 		return;
1897*a1157835SDaniel Fojt 	}
1898*a1157835SDaniel Fojt 
1899*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID",
1900*a1157835SDaniel Fojt 		    f_r0kh_id, f_r0kh_id_len);
1901*a1157835SDaniel Fojt 
1902*a1157835SDaniel Fojt 	if (r0kh) {
1903*a1157835SDaniel Fojt 		wpa_ft_rrb_r0kh_timeout(wpa_auth, r0kh,
1904*a1157835SDaniel Fojt 					wpa_auth->conf.rkh_neg_timeout);
1905*a1157835SDaniel Fojt 		os_memset(r0kh->addr, 0, ETH_ALEN);
1906*a1157835SDaniel Fojt 	} else
1907*a1157835SDaniel Fojt 		wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, NULL, f_r0kh_id,
1908*a1157835SDaniel Fojt 				    f_r0kh_id_len,
1909*a1157835SDaniel Fojt 				    wpa_auth->conf.rkh_neg_timeout);
1910*a1157835SDaniel Fojt }
1911*a1157835SDaniel Fojt 
1912*a1157835SDaniel Fojt 
wpa_ft_expire_pull(void * eloop_ctx,void * timeout_ctx)1913*a1157835SDaniel Fojt static void wpa_ft_expire_pull(void *eloop_ctx, void *timeout_ctx)
1914*a1157835SDaniel Fojt {
1915*a1157835SDaniel Fojt 	struct wpa_state_machine *sm = eloop_ctx;
1916*a1157835SDaniel Fojt 
1917*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Timeout pending pull request for " MACSTR,
1918*a1157835SDaniel Fojt 		   MAC2STR(sm->addr));
1919*a1157835SDaniel Fojt 	if (sm->ft_pending_pull_left_retries <= 0)
1920*a1157835SDaniel Fojt 		wpa_ft_block_r0kh(sm->wpa_auth, sm->r0kh_id, sm->r0kh_id_len);
1921*a1157835SDaniel Fojt 
1922*a1157835SDaniel Fojt 	/* cancel multiple timeouts */
1923*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpa_ft_expire_pull, sm, NULL);
1924*a1157835SDaniel Fojt 	ft_finish_pull(sm);
1925*a1157835SDaniel Fojt }
1926*a1157835SDaniel Fojt 
1927*a1157835SDaniel Fojt 
wpa_ft_pull_pmk_r1(struct wpa_state_machine * sm,const u8 * ies,size_t ies_len,const u8 * pmk_r0_name)1928*a1157835SDaniel Fojt static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
1929*a1157835SDaniel Fojt 			      const u8 *ies, size_t ies_len,
1930*a1157835SDaniel Fojt 			      const u8 *pmk_r0_name)
1931*a1157835SDaniel Fojt {
1932*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh, *r0kh_wildcard;
1933*a1157835SDaniel Fojt 	u8 *packet = NULL;
1934*a1157835SDaniel Fojt 	const u8 *key, *f_r1kh_id = sm->wpa_auth->conf.r1_key_holder;
1935*a1157835SDaniel Fojt 	size_t packet_len, key_len;
1936*a1157835SDaniel Fojt 	struct ft_rrb_seq f_seq;
1937*a1157835SDaniel Fojt 	int tsecs, tusecs, first;
1938*a1157835SDaniel Fojt 	struct wpabuf *ft_pending_req_ies;
1939*a1157835SDaniel Fojt 	int r0kh_timeout;
1940*a1157835SDaniel Fojt 	struct tlv_list req_enc[] = {
1941*a1157835SDaniel Fojt 		{ .type = FT_RRB_PMK_R0_NAME, .len = WPA_PMK_NAME_LEN,
1942*a1157835SDaniel Fojt 		  .data = pmk_r0_name },
1943*a1157835SDaniel Fojt 		{ .type = FT_RRB_S1KH_ID, .len = ETH_ALEN,
1944*a1157835SDaniel Fojt 		  .data = sm->addr },
1945*a1157835SDaniel Fojt 		{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
1946*a1157835SDaniel Fojt 	};
1947*a1157835SDaniel Fojt 	struct tlv_list req_auth[] = {
1948*a1157835SDaniel Fojt 		{ .type = FT_RRB_NONCE, .len = FT_RRB_NONCE_LEN,
1949*a1157835SDaniel Fojt 		  .data = sm->ft_pending_pull_nonce },
1950*a1157835SDaniel Fojt 		{ .type = FT_RRB_SEQ, .len = sizeof(f_seq),
1951*a1157835SDaniel Fojt 		  .data = (u8 *) &f_seq },
1952*a1157835SDaniel Fojt 		{ .type = FT_RRB_R0KH_ID, .len = sm->r0kh_id_len,
1953*a1157835SDaniel Fojt 		  .data = sm->r0kh_id },
1954*a1157835SDaniel Fojt 		{ .type = FT_RRB_R1KH_ID, .len = FT_R1KH_ID_LEN,
1955*a1157835SDaniel Fojt 		  .data = f_r1kh_id },
1956*a1157835SDaniel Fojt 		{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
1957*a1157835SDaniel Fojt 	};
1958*a1157835SDaniel Fojt 
1959*a1157835SDaniel Fojt 	if (sm->ft_pending_pull_left_retries <= 0)
1960*a1157835SDaniel Fojt 		return -1;
1961*a1157835SDaniel Fojt 	first = sm->ft_pending_pull_left_retries ==
1962*a1157835SDaniel Fojt 		sm->wpa_auth->conf.rkh_pull_retries;
1963*a1157835SDaniel Fojt 	sm->ft_pending_pull_left_retries--;
1964*a1157835SDaniel Fojt 
1965*a1157835SDaniel Fojt 	wpa_ft_rrb_lookup_r0kh(sm->wpa_auth, sm->r0kh_id, sm->r0kh_id_len,
1966*a1157835SDaniel Fojt 			       &r0kh, &r0kh_wildcard);
1967*a1157835SDaniel Fojt 
1968*a1157835SDaniel Fojt 	/* Keep r0kh sufficiently long in the list for seq num check */
1969*a1157835SDaniel Fojt 	r0kh_timeout = sm->wpa_auth->conf.rkh_pull_timeout / 1000 +
1970*a1157835SDaniel Fojt 		1 + ftRRBseqTimeout;
1971*a1157835SDaniel Fojt 	if (r0kh) {
1972*a1157835SDaniel Fojt 		wpa_ft_rrb_r0kh_replenish(sm->wpa_auth, r0kh, r0kh_timeout);
1973*a1157835SDaniel Fojt 	} else if (r0kh_wildcard) {
1974*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Using wildcard R0KH-ID");
1975*a1157835SDaniel Fojt 		/* r0kh->addr: updated by SEQ_RESP and wpa_ft_expire_pull */
1976*a1157835SDaniel Fojt 		r0kh = wpa_ft_rrb_add_r0kh(sm->wpa_auth, r0kh_wildcard,
1977*a1157835SDaniel Fojt 					   r0kh_wildcard->addr,
1978*a1157835SDaniel Fojt 					   sm->r0kh_id, sm->r0kh_id_len,
1979*a1157835SDaniel Fojt 					   r0kh_timeout);
1980*a1157835SDaniel Fojt 	}
1981*a1157835SDaniel Fojt 	if (r0kh == NULL) {
1982*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
1983*a1157835SDaniel Fojt 			    sm->r0kh_id, sm->r0kh_id_len);
1984*a1157835SDaniel Fojt 		return -1;
1985*a1157835SDaniel Fojt 	}
1986*a1157835SDaniel Fojt 	if (is_zero_ether_addr(r0kh->addr)) {
1987*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is blacklisted",
1988*a1157835SDaniel Fojt 			    sm->r0kh_id, sm->r0kh_id_len);
1989*a1157835SDaniel Fojt 		return -1;
1990*a1157835SDaniel Fojt 	}
1991*a1157835SDaniel Fojt 	if (os_memcmp(r0kh->addr, sm->wpa_auth->addr, ETH_ALEN) == 0) {
1992*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1993*a1157835SDaniel Fojt 			   "FT: R0KH-ID points to self - no matching key available");
1994*a1157835SDaniel Fojt 		return -1;
1995*a1157835SDaniel Fojt 	}
1996*a1157835SDaniel Fojt 
1997*a1157835SDaniel Fojt 	key = r0kh->key;
1998*a1157835SDaniel Fojt 	key_len = sizeof(r0kh->key);
19993ff40c12SJohn Marino 
20003ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
20013ff40c12SJohn Marino 		   "address " MACSTR, MAC2STR(r0kh->addr));
20023ff40c12SJohn Marino 
2003*a1157835SDaniel Fojt 	if (r0kh->seq->rx.num_last == 0) {
2004*a1157835SDaniel Fojt 		/* A sequence request will be sent out anyway when pull
2005*a1157835SDaniel Fojt 		 * response is received. Send it out now to avoid one RTT. */
2006*a1157835SDaniel Fojt 		wpa_ft_rrb_seq_req(sm->wpa_auth, r0kh->seq, r0kh->addr,
2007*a1157835SDaniel Fojt 				   r0kh->id, r0kh->id_len, f_r1kh_id, key,
2008*a1157835SDaniel Fojt 				   key_len, NULL, 0, NULL, 0, NULL);
2009*a1157835SDaniel Fojt 	}
20103ff40c12SJohn Marino 
2011*a1157835SDaniel Fojt 	if (first &&
2012*a1157835SDaniel Fojt 	    random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) {
20133ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
20143ff40c12SJohn Marino 			   "nonce");
20153ff40c12SJohn Marino 		return -1;
20163ff40c12SJohn Marino 	}
20173ff40c12SJohn Marino 
2018*a1157835SDaniel Fojt 	if (wpa_ft_new_seq(r0kh->seq, &f_seq) < 0) {
2019*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Failed to get seq num");
2020*a1157835SDaniel Fojt 		return -1;
2021*a1157835SDaniel Fojt 	}
2022*a1157835SDaniel Fojt 
2023*a1157835SDaniel Fojt 	if (wpa_ft_rrb_build(key, key_len, req_enc, NULL, req_auth, NULL,
2024*a1157835SDaniel Fojt 			     sm->wpa_auth->addr, FT_PACKET_R0KH_R1KH_PULL,
2025*a1157835SDaniel Fojt 			     &packet, &packet_len) < 0)
20263ff40c12SJohn Marino 		return -1;
20273ff40c12SJohn Marino 
2028*a1157835SDaniel Fojt 	ft_pending_req_ies = wpabuf_alloc_copy(ies, ies_len);
2029*a1157835SDaniel Fojt 	wpabuf_free(sm->ft_pending_req_ies);
2030*a1157835SDaniel Fojt 	sm->ft_pending_req_ies = ft_pending_req_ies;
2031*a1157835SDaniel Fojt 	if (!sm->ft_pending_req_ies) {
2032*a1157835SDaniel Fojt 		os_free(packet);
2033*a1157835SDaniel Fojt 		return -1;
2034*a1157835SDaniel Fojt 	}
2035*a1157835SDaniel Fojt 
2036*a1157835SDaniel Fojt 	tsecs = sm->wpa_auth->conf.rkh_pull_timeout / 1000;
2037*a1157835SDaniel Fojt 	tusecs = (sm->wpa_auth->conf.rkh_pull_timeout % 1000) * 1000;
2038*a1157835SDaniel Fojt 	eloop_register_timeout(tsecs, tusecs, wpa_ft_expire_pull, sm, NULL);
2039*a1157835SDaniel Fojt 
2040*a1157835SDaniel Fojt 	wpa_ft_rrb_oui_send(sm->wpa_auth, r0kh->addr, FT_PACKET_R0KH_R1KH_PULL,
2041*a1157835SDaniel Fojt 			    packet, packet_len);
2042*a1157835SDaniel Fojt 
2043*a1157835SDaniel Fojt 	os_free(packet);
20443ff40c12SJohn Marino 
20453ff40c12SJohn Marino 	return 0;
20463ff40c12SJohn Marino }
20473ff40c12SJohn Marino 
20483ff40c12SJohn Marino 
wpa_ft_store_pmk_fils(struct wpa_state_machine * sm,const u8 * pmk_r0,const u8 * pmk_r0_name)2049*a1157835SDaniel Fojt int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm,
2050*a1157835SDaniel Fojt 			  const u8 *pmk_r0, const u8 *pmk_r0_name)
20513ff40c12SJohn Marino {
2052*a1157835SDaniel Fojt 	int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
2053*a1157835SDaniel Fojt 	struct vlan_description vlan;
2054*a1157835SDaniel Fojt 	const u8 *identity, *radius_cui;
2055*a1157835SDaniel Fojt 	size_t identity_len, radius_cui_len;
2056*a1157835SDaniel Fojt 	int session_timeout;
2057*a1157835SDaniel Fojt 	size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
2058*a1157835SDaniel Fojt 		SHA384_MAC_LEN : PMK_LEN;
2059*a1157835SDaniel Fojt 
2060*a1157835SDaniel Fojt 	if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
2061*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
2062*a1157835SDaniel Fojt 			   MAC2STR(sm->addr));
2063*a1157835SDaniel Fojt 		return -1;
2064*a1157835SDaniel Fojt 	}
2065*a1157835SDaniel Fojt 
2066*a1157835SDaniel Fojt 	identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
2067*a1157835SDaniel Fojt 	radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr,
2068*a1157835SDaniel Fojt 					       &radius_cui);
2069*a1157835SDaniel Fojt 	session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
2070*a1157835SDaniel Fojt 
2071*a1157835SDaniel Fojt 	return wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
2072*a1157835SDaniel Fojt 				   pmk_r0_name, sm->pairwise, &vlan, expires_in,
2073*a1157835SDaniel Fojt 				   session_timeout, identity, identity_len,
2074*a1157835SDaniel Fojt 				   radius_cui, radius_cui_len);
2075*a1157835SDaniel Fojt }
2076*a1157835SDaniel Fojt 
2077*a1157835SDaniel Fojt 
wpa_auth_derive_ptk_ft(struct wpa_state_machine * sm,struct wpa_ptk * ptk)2078*a1157835SDaniel Fojt int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
2079*a1157835SDaniel Fojt {
2080*a1157835SDaniel Fojt 	u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
2081*a1157835SDaniel Fojt 	size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
2082*a1157835SDaniel Fojt 		SHA384_MAC_LEN : PMK_LEN;
2083*a1157835SDaniel Fojt 	size_t pmk_r1_len = pmk_r0_len;
2084*a1157835SDaniel Fojt 	u8 pmk_r1[PMK_LEN_MAX];
20853ff40c12SJohn Marino 	u8 ptk_name[WPA_PMK_NAME_LEN];
20863ff40c12SJohn Marino 	const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
20873ff40c12SJohn Marino 	const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
20883ff40c12SJohn Marino 	size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
20893ff40c12SJohn Marino 	const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
20903ff40c12SJohn Marino 	const u8 *ssid = sm->wpa_auth->conf.ssid;
20913ff40c12SJohn Marino 	size_t ssid_len = sm->wpa_auth->conf.ssid_len;
2092*a1157835SDaniel Fojt 	int psk_local = sm->wpa_auth->conf.ft_psk_generate_local;
2093*a1157835SDaniel Fojt 	int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
2094*a1157835SDaniel Fojt 	struct vlan_description vlan;
2095*a1157835SDaniel Fojt 	const u8 *identity, *radius_cui;
2096*a1157835SDaniel Fojt 	size_t identity_len, radius_cui_len;
2097*a1157835SDaniel Fojt 	int session_timeout;
2098*a1157835SDaniel Fojt 	const u8 *mpmk;
2099*a1157835SDaniel Fojt 	size_t mpmk_len;
21003ff40c12SJohn Marino 
2101*a1157835SDaniel Fojt 	if (sm->xxkey_len > 0) {
2102*a1157835SDaniel Fojt 		mpmk = sm->xxkey;
2103*a1157835SDaniel Fojt 		mpmk_len = sm->xxkey_len;
2104*a1157835SDaniel Fojt 	} else if (sm->pmksa) {
2105*a1157835SDaniel Fojt 		mpmk = sm->pmksa->pmk;
2106*a1157835SDaniel Fojt 		mpmk_len = sm->pmksa->pmk_len;
2107*a1157835SDaniel Fojt 	} else {
21083ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
21093ff40c12SJohn Marino 			   "derivation");
21103ff40c12SJohn Marino 		return -1;
21113ff40c12SJohn Marino 	}
21123ff40c12SJohn Marino 
2113*a1157835SDaniel Fojt 	if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
2114*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
2115*a1157835SDaniel Fojt 			   MAC2STR(sm->addr));
2116*a1157835SDaniel Fojt 		return -1;
2117*a1157835SDaniel Fojt 	}
21183ff40c12SJohn Marino 
2119*a1157835SDaniel Fojt 	identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
2120*a1157835SDaniel Fojt 	radius_cui_len = wpa_ft_get_radius_cui(sm->wpa_auth, sm->addr,
2121*a1157835SDaniel Fojt 					       &radius_cui);
2122*a1157835SDaniel Fojt 	session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
2123*a1157835SDaniel Fojt 
2124*a1157835SDaniel Fojt 	if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
2125*a1157835SDaniel Fojt 			      r0kh, r0kh_len, sm->addr,
2126*a1157835SDaniel Fojt 			      pmk_r0, pmk_r0_name,
2127*a1157835SDaniel Fojt 			      wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
2128*a1157835SDaniel Fojt 		return -1;
2129*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
2130*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
2131*a1157835SDaniel Fojt 	if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
2132*a1157835SDaniel Fojt 		wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
2133*a1157835SDaniel Fojt 				    pmk_r0_name,
2134*a1157835SDaniel Fojt 				    sm->pairwise, &vlan, expires_in,
2135*a1157835SDaniel Fojt 				    session_timeout, identity, identity_len,
2136*a1157835SDaniel Fojt 				    radius_cui, radius_cui_len);
2137*a1157835SDaniel Fojt 
2138*a1157835SDaniel Fojt 	if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
2139*a1157835SDaniel Fojt 			      pmk_r1, sm->pmk_r1_name) < 0)
2140*a1157835SDaniel Fojt 		return -1;
2141*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
21423ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
21433ff40c12SJohn Marino 		    WPA_PMK_NAME_LEN);
2144*a1157835SDaniel Fojt 	if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
2145*a1157835SDaniel Fojt 		wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
2146*a1157835SDaniel Fojt 				    sm->pmk_r1_name, sm->pairwise, &vlan,
2147*a1157835SDaniel Fojt 				    expires_in, session_timeout, identity,
2148*a1157835SDaniel Fojt 				    identity_len, radius_cui, radius_cui_len);
21493ff40c12SJohn Marino 
2150*a1157835SDaniel Fojt 	return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
2151*a1157835SDaniel Fojt 				 sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
2152*a1157835SDaniel Fojt 				 ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
21533ff40c12SJohn Marino }
21543ff40c12SJohn Marino 
21553ff40c12SJohn Marino 
wpa_auth_get_seqnum(struct wpa_authenticator * wpa_auth,const u8 * addr,int idx,u8 * seq)21563ff40c12SJohn Marino static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
21573ff40c12SJohn Marino 				      const u8 *addr, int idx, u8 *seq)
21583ff40c12SJohn Marino {
2159*a1157835SDaniel Fojt 	if (wpa_auth->cb->get_seqnum == NULL)
21603ff40c12SJohn Marino 		return -1;
2161*a1157835SDaniel Fojt 	return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
21623ff40c12SJohn Marino }
21633ff40c12SJohn Marino 
21643ff40c12SJohn Marino 
wpa_ft_gtk_subelem(struct wpa_state_machine * sm,size_t * len)21653ff40c12SJohn Marino static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
21663ff40c12SJohn Marino {
21673ff40c12SJohn Marino 	u8 *subelem;
21683ff40c12SJohn Marino 	struct wpa_group *gsm = sm->group;
21693ff40c12SJohn Marino 	size_t subelem_len, pad_len;
21703ff40c12SJohn Marino 	const u8 *key;
21713ff40c12SJohn Marino 	size_t key_len;
21723ff40c12SJohn Marino 	u8 keybuf[32];
2173*a1157835SDaniel Fojt 	const u8 *kek;
2174*a1157835SDaniel Fojt 	size_t kek_len;
2175*a1157835SDaniel Fojt 
2176*a1157835SDaniel Fojt 	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
2177*a1157835SDaniel Fojt 		kek = sm->PTK.kek2;
2178*a1157835SDaniel Fojt 		kek_len = sm->PTK.kek2_len;
2179*a1157835SDaniel Fojt 	} else {
2180*a1157835SDaniel Fojt 		kek = sm->PTK.kek;
2181*a1157835SDaniel Fojt 		kek_len = sm->PTK.kek_len;
2182*a1157835SDaniel Fojt 	}
21833ff40c12SJohn Marino 
21843ff40c12SJohn Marino 	key_len = gsm->GTK_len;
21853ff40c12SJohn Marino 	if (key_len > sizeof(keybuf))
21863ff40c12SJohn Marino 		return NULL;
21873ff40c12SJohn Marino 
21883ff40c12SJohn Marino 	/*
21893ff40c12SJohn Marino 	 * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
21903ff40c12SJohn Marino 	 * than 16 bytes.
21913ff40c12SJohn Marino 	 */
21923ff40c12SJohn Marino 	pad_len = key_len % 8;
21933ff40c12SJohn Marino 	if (pad_len)
21943ff40c12SJohn Marino 		pad_len = 8 - pad_len;
21953ff40c12SJohn Marino 	if (key_len + pad_len < 16)
21963ff40c12SJohn Marino 		pad_len += 8;
21973ff40c12SJohn Marino 	if (pad_len && key_len < sizeof(keybuf)) {
21983ff40c12SJohn Marino 		os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
21993ff40c12SJohn Marino 		os_memset(keybuf + key_len, 0, pad_len);
22003ff40c12SJohn Marino 		keybuf[key_len] = 0xdd;
22013ff40c12SJohn Marino 		key_len += pad_len;
22023ff40c12SJohn Marino 		key = keybuf;
22033ff40c12SJohn Marino 	} else
22043ff40c12SJohn Marino 		key = gsm->GTK[gsm->GN - 1];
22053ff40c12SJohn Marino 
22063ff40c12SJohn Marino 	/*
22073ff40c12SJohn Marino 	 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
22083ff40c12SJohn Marino 	 * Key[5..32].
22093ff40c12SJohn Marino 	 */
22103ff40c12SJohn Marino 	subelem_len = 13 + key_len + 8;
22113ff40c12SJohn Marino 	subelem = os_zalloc(subelem_len);
22123ff40c12SJohn Marino 	if (subelem == NULL)
22133ff40c12SJohn Marino 		return NULL;
22143ff40c12SJohn Marino 
22153ff40c12SJohn Marino 	subelem[0] = FTIE_SUBELEM_GTK;
22163ff40c12SJohn Marino 	subelem[1] = 11 + key_len + 8;
22173ff40c12SJohn Marino 	/* Key ID in B0-B1 of Key Info */
22183ff40c12SJohn Marino 	WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
22193ff40c12SJohn Marino 	subelem[4] = gsm->GTK_len;
22203ff40c12SJohn Marino 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
2221*a1157835SDaniel Fojt 	if (aes_wrap(kek, kek_len, key_len / 8, key, subelem + 13)) {
2222*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2223*a1157835SDaniel Fojt 			   "FT: GTK subelem encryption failed: kek_len=%d",
2224*a1157835SDaniel Fojt 			   (int) kek_len);
22253ff40c12SJohn Marino 		os_free(subelem);
22263ff40c12SJohn Marino 		return NULL;
22273ff40c12SJohn Marino 	}
22283ff40c12SJohn Marino 
2229*a1157835SDaniel Fojt 	forced_memzero(keybuf, sizeof(keybuf));
22303ff40c12SJohn Marino 	*len = subelem_len;
22313ff40c12SJohn Marino 	return subelem;
22323ff40c12SJohn Marino }
22333ff40c12SJohn Marino 
22343ff40c12SJohn Marino 
22353ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
wpa_ft_igtk_subelem(struct wpa_state_machine * sm,size_t * len)22363ff40c12SJohn Marino static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
22373ff40c12SJohn Marino {
22383ff40c12SJohn Marino 	u8 *subelem, *pos;
22393ff40c12SJohn Marino 	struct wpa_group *gsm = sm->group;
22403ff40c12SJohn Marino 	size_t subelem_len;
2241*a1157835SDaniel Fojt 	const u8 *kek;
2242*a1157835SDaniel Fojt 	size_t kek_len;
2243*a1157835SDaniel Fojt 	size_t igtk_len;
2244*a1157835SDaniel Fojt 
2245*a1157835SDaniel Fojt 	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
2246*a1157835SDaniel Fojt 		kek = sm->PTK.kek2;
2247*a1157835SDaniel Fojt 		kek_len = sm->PTK.kek2_len;
2248*a1157835SDaniel Fojt 	} else {
2249*a1157835SDaniel Fojt 		kek = sm->PTK.kek;
2250*a1157835SDaniel Fojt 		kek_len = sm->PTK.kek_len;
2251*a1157835SDaniel Fojt 	}
2252*a1157835SDaniel Fojt 
2253*a1157835SDaniel Fojt 	igtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
22543ff40c12SJohn Marino 
22553ff40c12SJohn Marino 	/* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
22563ff40c12SJohn Marino 	 * Key[16+8] */
2257*a1157835SDaniel Fojt 	subelem_len = 1 + 1 + 2 + 6 + 1 + igtk_len + 8;
22583ff40c12SJohn Marino 	subelem = os_zalloc(subelem_len);
22593ff40c12SJohn Marino 	if (subelem == NULL)
22603ff40c12SJohn Marino 		return NULL;
22613ff40c12SJohn Marino 
22623ff40c12SJohn Marino 	pos = subelem;
22633ff40c12SJohn Marino 	*pos++ = FTIE_SUBELEM_IGTK;
22643ff40c12SJohn Marino 	*pos++ = subelem_len - 2;
22653ff40c12SJohn Marino 	WPA_PUT_LE16(pos, gsm->GN_igtk);
22663ff40c12SJohn Marino 	pos += 2;
22673ff40c12SJohn Marino 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
22683ff40c12SJohn Marino 	pos += 6;
2269*a1157835SDaniel Fojt 	*pos++ = igtk_len;
2270*a1157835SDaniel Fojt 	if (aes_wrap(kek, kek_len, igtk_len / 8,
22713ff40c12SJohn Marino 		     gsm->IGTK[gsm->GN_igtk - 4], pos)) {
2272*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2273*a1157835SDaniel Fojt 			   "FT: IGTK subelem encryption failed: kek_len=%d",
2274*a1157835SDaniel Fojt 			   (int) kek_len);
22753ff40c12SJohn Marino 		os_free(subelem);
22763ff40c12SJohn Marino 		return NULL;
22773ff40c12SJohn Marino 	}
22783ff40c12SJohn Marino 
22793ff40c12SJohn Marino 	*len = subelem_len;
22803ff40c12SJohn Marino 	return subelem;
22813ff40c12SJohn Marino }
22823ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
22833ff40c12SJohn Marino 
22843ff40c12SJohn Marino 
wpa_ft_process_rdie(struct wpa_state_machine * sm,u8 * pos,u8 * end,u8 id,u8 descr_count,const u8 * ies,size_t ies_len)22853ff40c12SJohn Marino static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
22863ff40c12SJohn Marino 				u8 *pos, u8 *end, u8 id, u8 descr_count,
22873ff40c12SJohn Marino 				const u8 *ies, size_t ies_len)
22883ff40c12SJohn Marino {
22893ff40c12SJohn Marino 	struct ieee802_11_elems parse;
22903ff40c12SJohn Marino 	struct rsn_rdie *rdie;
22913ff40c12SJohn Marino 
22923ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d",
22933ff40c12SJohn Marino 		   id, descr_count);
22943ff40c12SJohn Marino 	wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)",
22953ff40c12SJohn Marino 		    ies, ies_len);
22963ff40c12SJohn Marino 
22973ff40c12SJohn Marino 	if (end - pos < (int) sizeof(*rdie)) {
22983ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE");
22993ff40c12SJohn Marino 		return pos;
23003ff40c12SJohn Marino 	}
23013ff40c12SJohn Marino 
23023ff40c12SJohn Marino 	*pos++ = WLAN_EID_RIC_DATA;
23033ff40c12SJohn Marino 	*pos++ = sizeof(*rdie);
23043ff40c12SJohn Marino 	rdie = (struct rsn_rdie *) pos;
23053ff40c12SJohn Marino 	rdie->id = id;
23063ff40c12SJohn Marino 	rdie->descr_count = 0;
23073ff40c12SJohn Marino 	rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS);
23083ff40c12SJohn Marino 	pos += sizeof(*rdie);
23093ff40c12SJohn Marino 
23103ff40c12SJohn Marino 	if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) ==
23113ff40c12SJohn Marino 	    ParseFailed) {
23123ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs");
23133ff40c12SJohn Marino 		rdie->status_code =
23143ff40c12SJohn Marino 			host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
23153ff40c12SJohn Marino 		return pos;
23163ff40c12SJohn Marino 	}
23173ff40c12SJohn Marino 
2318*a1157835SDaniel Fojt 	if (parse.wmm_tspec) {
23193ff40c12SJohn Marino 		struct wmm_tspec_element *tspec;
23203ff40c12SJohn Marino 
23213ff40c12SJohn Marino 		if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
23223ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
23233ff40c12SJohn Marino 				   "(%d)", (int) parse.wmm_tspec_len);
23243ff40c12SJohn Marino 			rdie->status_code =
23253ff40c12SJohn Marino 				host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
23263ff40c12SJohn Marino 			return pos;
23273ff40c12SJohn Marino 		}
23283ff40c12SJohn Marino 		if (end - pos < (int) sizeof(*tspec)) {
23293ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "FT: Not enough room for "
23303ff40c12SJohn Marino 				   "response TSPEC");
23313ff40c12SJohn Marino 			rdie->status_code =
23323ff40c12SJohn Marino 				host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
23333ff40c12SJohn Marino 			return pos;
23343ff40c12SJohn Marino 		}
23353ff40c12SJohn Marino 		tspec = (struct wmm_tspec_element *) pos;
23363ff40c12SJohn Marino 		os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
2337*a1157835SDaniel Fojt 	}
2338*a1157835SDaniel Fojt 
2339*a1157835SDaniel Fojt #ifdef NEED_AP_MLME
2340*a1157835SDaniel Fojt 	if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
2341*a1157835SDaniel Fojt 		int res;
2342*a1157835SDaniel Fojt 
2343*a1157835SDaniel Fojt 		res = wmm_process_tspec((struct wmm_tspec_element *) pos);
23443ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
23453ff40c12SJohn Marino 		if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
23463ff40c12SJohn Marino 			rdie->status_code =
23473ff40c12SJohn Marino 				host_to_le16(WLAN_STATUS_INVALID_PARAMETERS);
23483ff40c12SJohn Marino 		else if (res == WMM_ADDTS_STATUS_REFUSED)
23493ff40c12SJohn Marino 			rdie->status_code =
23503ff40c12SJohn Marino 				host_to_le16(WLAN_STATUS_REQUEST_DECLINED);
23513ff40c12SJohn Marino 		else {
23523ff40c12SJohn Marino 			/* TSPEC accepted; include updated TSPEC in response */
23533ff40c12SJohn Marino 			rdie->descr_count = 1;
2354*a1157835SDaniel Fojt 			pos += sizeof(struct wmm_tspec_element);
23553ff40c12SJohn Marino 		}
23563ff40c12SJohn Marino 		return pos;
23573ff40c12SJohn Marino 	}
23583ff40c12SJohn Marino #endif /* NEED_AP_MLME */
23593ff40c12SJohn Marino 
23603ff40c12SJohn Marino 	if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
23613ff40c12SJohn Marino 		int res;
23623ff40c12SJohn Marino 
23633ff40c12SJohn Marino 		res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
2364*a1157835SDaniel Fojt 				       sizeof(struct wmm_tspec_element));
23653ff40c12SJohn Marino 		if (res >= 0) {
23663ff40c12SJohn Marino 			if (res)
23673ff40c12SJohn Marino 				rdie->status_code = host_to_le16(res);
23683ff40c12SJohn Marino 			else {
23693ff40c12SJohn Marino 				/* TSPEC accepted; include updated TSPEC in
23703ff40c12SJohn Marino 				 * response */
23713ff40c12SJohn Marino 				rdie->descr_count = 1;
2372*a1157835SDaniel Fojt 				pos += sizeof(struct wmm_tspec_element);
23733ff40c12SJohn Marino 			}
23743ff40c12SJohn Marino 			return pos;
23753ff40c12SJohn Marino 		}
23763ff40c12SJohn Marino 	}
23773ff40c12SJohn Marino 
23783ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
23793ff40c12SJohn Marino 	rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
23803ff40c12SJohn Marino 	return pos;
23813ff40c12SJohn Marino }
23823ff40c12SJohn Marino 
23833ff40c12SJohn Marino 
wpa_ft_process_ric(struct wpa_state_machine * sm,u8 * pos,u8 * end,const u8 * ric,size_t ric_len)23843ff40c12SJohn Marino static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
23853ff40c12SJohn Marino 			       const u8 *ric, size_t ric_len)
23863ff40c12SJohn Marino {
23873ff40c12SJohn Marino 	const u8 *rpos, *start;
23883ff40c12SJohn Marino 	const struct rsn_rdie *rdie;
23893ff40c12SJohn Marino 
23903ff40c12SJohn Marino 	wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len);
23913ff40c12SJohn Marino 
23923ff40c12SJohn Marino 	rpos = ric;
23933ff40c12SJohn Marino 	while (rpos + sizeof(*rdie) < ric + ric_len) {
23943ff40c12SJohn Marino 		if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) ||
23953ff40c12SJohn Marino 		    rpos + 2 + rpos[1] > ric + ric_len)
23963ff40c12SJohn Marino 			break;
23973ff40c12SJohn Marino 		rdie = (const struct rsn_rdie *) (rpos + 2);
23983ff40c12SJohn Marino 		rpos += 2 + rpos[1];
23993ff40c12SJohn Marino 		start = rpos;
24003ff40c12SJohn Marino 
24013ff40c12SJohn Marino 		while (rpos + 2 <= ric + ric_len &&
24023ff40c12SJohn Marino 		       rpos + 2 + rpos[1] <= ric + ric_len) {
24033ff40c12SJohn Marino 			if (rpos[0] == WLAN_EID_RIC_DATA)
24043ff40c12SJohn Marino 				break;
24053ff40c12SJohn Marino 			rpos += 2 + rpos[1];
24063ff40c12SJohn Marino 		}
24073ff40c12SJohn Marino 		pos = wpa_ft_process_rdie(sm, pos, end, rdie->id,
24083ff40c12SJohn Marino 					  rdie->descr_count,
24093ff40c12SJohn Marino 					  start, rpos - start);
24103ff40c12SJohn Marino 	}
24113ff40c12SJohn Marino 
24123ff40c12SJohn Marino 	return pos;
24133ff40c12SJohn Marino }
24143ff40c12SJohn Marino 
24153ff40c12SJohn Marino 
wpa_sm_write_assoc_resp_ies(struct wpa_state_machine * sm,u8 * pos,size_t max_len,int auth_alg,const u8 * req_ies,size_t req_ies_len)24163ff40c12SJohn Marino u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
24173ff40c12SJohn Marino 				 size_t max_len, int auth_alg,
24183ff40c12SJohn Marino 				 const u8 *req_ies, size_t req_ies_len)
24193ff40c12SJohn Marino {
24203ff40c12SJohn Marino 	u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
2421*a1157835SDaniel Fojt 	u8 *fte_mic, *elem_count;
24223ff40c12SJohn Marino 	size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
24233ff40c12SJohn Marino 	int res;
24243ff40c12SJohn Marino 	struct wpa_auth_config *conf;
24253ff40c12SJohn Marino 	struct wpa_ft_ies parse;
24263ff40c12SJohn Marino 	u8 *ric_start;
24273ff40c12SJohn Marino 	u8 *anonce, *snonce;
2428*a1157835SDaniel Fojt 	const u8 *kck;
2429*a1157835SDaniel Fojt 	size_t kck_len;
2430*a1157835SDaniel Fojt 	int use_sha384;
24313ff40c12SJohn Marino 
24323ff40c12SJohn Marino 	if (sm == NULL)
24333ff40c12SJohn Marino 		return pos;
24343ff40c12SJohn Marino 
2435*a1157835SDaniel Fojt 	use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
24363ff40c12SJohn Marino 	conf = &sm->wpa_auth->conf;
24373ff40c12SJohn Marino 
24383ff40c12SJohn Marino 	if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt))
24393ff40c12SJohn Marino 		return pos;
24403ff40c12SJohn Marino 
24413ff40c12SJohn Marino 	end = pos + max_len;
24423ff40c12SJohn Marino 
2443*a1157835SDaniel Fojt 	if (auth_alg == WLAN_AUTH_FT ||
2444*a1157835SDaniel Fojt 	    ((auth_alg == WLAN_AUTH_FILS_SK ||
2445*a1157835SDaniel Fojt 	      auth_alg == WLAN_AUTH_FILS_SK_PFS ||
2446*a1157835SDaniel Fojt 	      auth_alg == WLAN_AUTH_FILS_PK) &&
2447*a1157835SDaniel Fojt 	     (sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
2448*a1157835SDaniel Fojt 				  WPA_KEY_MGMT_FT_FILS_SHA384)))) {
2449*a1157835SDaniel Fojt 		if (!sm->pmk_r1_name_valid) {
2450*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
2451*a1157835SDaniel Fojt 				   "FT: PMKR1Name is not valid for Assoc Resp RSNE");
2452*a1157835SDaniel Fojt 			return NULL;
2453*a1157835SDaniel Fojt 		}
2454*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name for Assoc Resp RSNE",
2455*a1157835SDaniel Fojt 			    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
24563ff40c12SJohn Marino 		/*
24573ff40c12SJohn Marino 		 * RSN (only present if this is a Reassociation Response and
2458*a1157835SDaniel Fojt 		 * part of a fast BSS transition; or if this is a
2459*a1157835SDaniel Fojt 		 * (Re)Association Response frame during an FT initial mobility
2460*a1157835SDaniel Fojt 		 * domain association using FILS)
24613ff40c12SJohn Marino 		 */
24623ff40c12SJohn Marino 		res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
24633ff40c12SJohn Marino 		if (res < 0)
2464*a1157835SDaniel Fojt 			return NULL;
24653ff40c12SJohn Marino 		rsnie = pos;
24663ff40c12SJohn Marino 		rsnie_len = res;
24673ff40c12SJohn Marino 		pos += res;
24683ff40c12SJohn Marino 	}
24693ff40c12SJohn Marino 
24703ff40c12SJohn Marino 	/* Mobility Domain Information */
24713ff40c12SJohn Marino 	res = wpa_write_mdie(conf, pos, end - pos);
24723ff40c12SJohn Marino 	if (res < 0)
2473*a1157835SDaniel Fojt 		return NULL;
24743ff40c12SJohn Marino 	mdie = pos;
24753ff40c12SJohn Marino 	mdie_len = res;
24763ff40c12SJohn Marino 	pos += res;
24773ff40c12SJohn Marino 
24783ff40c12SJohn Marino 	/* Fast BSS Transition Information */
24793ff40c12SJohn Marino 	if (auth_alg == WLAN_AUTH_FT) {
24803ff40c12SJohn Marino 		subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
2481*a1157835SDaniel Fojt 		if (!subelem) {
2482*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
2483*a1157835SDaniel Fojt 				   "FT: Failed to add GTK subelement");
2484*a1157835SDaniel Fojt 			return NULL;
2485*a1157835SDaniel Fojt 		}
24863ff40c12SJohn Marino 		r0kh_id = sm->r0kh_id;
24873ff40c12SJohn Marino 		r0kh_id_len = sm->r0kh_id_len;
24883ff40c12SJohn Marino 		anonce = sm->ANonce;
24893ff40c12SJohn Marino 		snonce = sm->SNonce;
24903ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
24913ff40c12SJohn Marino 		if (sm->mgmt_frame_prot) {
24923ff40c12SJohn Marino 			u8 *igtk;
24933ff40c12SJohn Marino 			size_t igtk_len;
24943ff40c12SJohn Marino 			u8 *nbuf;
24953ff40c12SJohn Marino 			igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
24963ff40c12SJohn Marino 			if (igtk == NULL) {
2497*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
2498*a1157835SDaniel Fojt 					   "FT: Failed to add IGTK subelement");
24993ff40c12SJohn Marino 				os_free(subelem);
2500*a1157835SDaniel Fojt 				return NULL;
25013ff40c12SJohn Marino 			}
25023ff40c12SJohn Marino 			nbuf = os_realloc(subelem, subelem_len + igtk_len);
25033ff40c12SJohn Marino 			if (nbuf == NULL) {
25043ff40c12SJohn Marino 				os_free(subelem);
25053ff40c12SJohn Marino 				os_free(igtk);
2506*a1157835SDaniel Fojt 				return NULL;
25073ff40c12SJohn Marino 			}
25083ff40c12SJohn Marino 			subelem = nbuf;
25093ff40c12SJohn Marino 			os_memcpy(subelem + subelem_len, igtk, igtk_len);
25103ff40c12SJohn Marino 			subelem_len += igtk_len;
25113ff40c12SJohn Marino 			os_free(igtk);
25123ff40c12SJohn Marino 		}
25133ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
2514*a1157835SDaniel Fojt #ifdef CONFIG_OCV
2515*a1157835SDaniel Fojt 		if (wpa_auth_uses_ocv(sm)) {
2516*a1157835SDaniel Fojt 			struct wpa_channel_info ci;
2517*a1157835SDaniel Fojt 			u8 *nbuf, *ocipos;
2518*a1157835SDaniel Fojt 
2519*a1157835SDaniel Fojt 			if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
2520*a1157835SDaniel Fojt 				wpa_printf(MSG_WARNING,
2521*a1157835SDaniel Fojt 					   "Failed to get channel info for OCI element");
2522*a1157835SDaniel Fojt 				os_free(subelem);
2523*a1157835SDaniel Fojt 				return NULL;
2524*a1157835SDaniel Fojt 			}
2525*a1157835SDaniel Fojt 
2526*a1157835SDaniel Fojt 			subelem_len += 2 + OCV_OCI_LEN;
2527*a1157835SDaniel Fojt 			nbuf = os_realloc(subelem, subelem_len);
2528*a1157835SDaniel Fojt 			if (!nbuf) {
2529*a1157835SDaniel Fojt 				os_free(subelem);
2530*a1157835SDaniel Fojt 				return NULL;
2531*a1157835SDaniel Fojt 			}
2532*a1157835SDaniel Fojt 			subelem = nbuf;
2533*a1157835SDaniel Fojt 
2534*a1157835SDaniel Fojt 			ocipos = subelem + subelem_len - 2 - OCV_OCI_LEN;
2535*a1157835SDaniel Fojt 			*ocipos++ = FTIE_SUBELEM_OCI;
2536*a1157835SDaniel Fojt 			*ocipos++ = OCV_OCI_LEN;
2537*a1157835SDaniel Fojt 			if (ocv_insert_oci(&ci, &ocipos) < 0) {
2538*a1157835SDaniel Fojt 				os_free(subelem);
2539*a1157835SDaniel Fojt 				return NULL;
2540*a1157835SDaniel Fojt 			}
2541*a1157835SDaniel Fojt 		}
2542*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
25433ff40c12SJohn Marino 	} else {
25443ff40c12SJohn Marino 		r0kh_id = conf->r0_key_holder;
25453ff40c12SJohn Marino 		r0kh_id_len = conf->r0_key_holder_len;
25463ff40c12SJohn Marino 		anonce = NULL;
25473ff40c12SJohn Marino 		snonce = NULL;
25483ff40c12SJohn Marino 	}
2549*a1157835SDaniel Fojt 	res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
2550*a1157835SDaniel Fojt 			     anonce, snonce, pos, end - pos,
2551*a1157835SDaniel Fojt 			     subelem, subelem_len);
25523ff40c12SJohn Marino 	os_free(subelem);
25533ff40c12SJohn Marino 	if (res < 0)
2554*a1157835SDaniel Fojt 		return NULL;
25553ff40c12SJohn Marino 	ftie = pos;
25563ff40c12SJohn Marino 	ftie_len = res;
25573ff40c12SJohn Marino 	pos += res;
25583ff40c12SJohn Marino 
2559*a1157835SDaniel Fojt 	if (use_sha384) {
2560*a1157835SDaniel Fojt 		struct rsn_ftie_sha384 *_ftie =
2561*a1157835SDaniel Fojt 			(struct rsn_ftie_sha384 *) (ftie + 2);
25623ff40c12SJohn Marino 
2563*a1157835SDaniel Fojt 		fte_mic = _ftie->mic;
2564*a1157835SDaniel Fojt 		elem_count = &_ftie->mic_control[1];
2565*a1157835SDaniel Fojt 	} else {
2566*a1157835SDaniel Fojt 		struct rsn_ftie *_ftie = (struct rsn_ftie *) (ftie + 2);
2567*a1157835SDaniel Fojt 
2568*a1157835SDaniel Fojt 		fte_mic = _ftie->mic;
2569*a1157835SDaniel Fojt 		elem_count = &_ftie->mic_control[1];
2570*a1157835SDaniel Fojt 	}
25713ff40c12SJohn Marino 	if (auth_alg == WLAN_AUTH_FT)
2572*a1157835SDaniel Fojt 		*elem_count = 3; /* Information element count */
25733ff40c12SJohn Marino 
25743ff40c12SJohn Marino 	ric_start = pos;
2575*a1157835SDaniel Fojt 	if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, use_sha384) == 0
2576*a1157835SDaniel Fojt 	    && parse.ric) {
25773ff40c12SJohn Marino 		pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
25783ff40c12SJohn Marino 					 parse.ric_len);
25793ff40c12SJohn Marino 		if (auth_alg == WLAN_AUTH_FT)
2580*a1157835SDaniel Fojt 			*elem_count +=
25813ff40c12SJohn Marino 				ieee802_11_ie_count(ric_start,
25823ff40c12SJohn Marino 						    pos - ric_start);
25833ff40c12SJohn Marino 	}
25843ff40c12SJohn Marino 	if (ric_start == pos)
25853ff40c12SJohn Marino 		ric_start = NULL;
25863ff40c12SJohn Marino 
2587*a1157835SDaniel Fojt 	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
2588*a1157835SDaniel Fojt 		kck = sm->PTK.kck2;
2589*a1157835SDaniel Fojt 		kck_len = sm->PTK.kck2_len;
2590*a1157835SDaniel Fojt 	} else {
2591*a1157835SDaniel Fojt 		kck = sm->PTK.kck;
2592*a1157835SDaniel Fojt 		kck_len = sm->PTK.kck_len;
2593*a1157835SDaniel Fojt 	}
25943ff40c12SJohn Marino 	if (auth_alg == WLAN_AUTH_FT &&
2595*a1157835SDaniel Fojt 	    wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 6,
25963ff40c12SJohn Marino 		       mdie, mdie_len, ftie, ftie_len,
25973ff40c12SJohn Marino 		       rsnie, rsnie_len,
25983ff40c12SJohn Marino 		       ric_start, ric_start ? pos - ric_start : 0,
2599*a1157835SDaniel Fojt 		       fte_mic) < 0) {
26003ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
2601*a1157835SDaniel Fojt 		return NULL;
2602*a1157835SDaniel Fojt 	}
2603*a1157835SDaniel Fojt 
2604*a1157835SDaniel Fojt 	os_free(sm->assoc_resp_ftie);
2605*a1157835SDaniel Fojt 	sm->assoc_resp_ftie = os_malloc(ftie_len);
2606*a1157835SDaniel Fojt 	if (!sm->assoc_resp_ftie)
2607*a1157835SDaniel Fojt 		return NULL;
2608*a1157835SDaniel Fojt 	os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
26093ff40c12SJohn Marino 
26103ff40c12SJohn Marino 	return pos;
26113ff40c12SJohn Marino }
26123ff40c12SJohn Marino 
26133ff40c12SJohn Marino 
wpa_auth_set_key(struct wpa_authenticator * wpa_auth,int vlan_id,enum wpa_alg alg,const u8 * addr,int idx,u8 * key,size_t key_len)26143ff40c12SJohn Marino static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
26153ff40c12SJohn Marino 				   int vlan_id,
26163ff40c12SJohn Marino 				   enum wpa_alg alg, const u8 *addr, int idx,
26173ff40c12SJohn Marino 				   u8 *key, size_t key_len)
26183ff40c12SJohn Marino {
2619*a1157835SDaniel Fojt 	if (wpa_auth->cb->set_key == NULL)
26203ff40c12SJohn Marino 		return -1;
2621*a1157835SDaniel Fojt 	return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
26223ff40c12SJohn Marino 				     key, key_len);
26233ff40c12SJohn Marino }
26243ff40c12SJohn Marino 
26253ff40c12SJohn Marino 
wpa_ft_install_ptk(struct wpa_state_machine * sm)26263ff40c12SJohn Marino void wpa_ft_install_ptk(struct wpa_state_machine *sm)
26273ff40c12SJohn Marino {
26283ff40c12SJohn Marino 	enum wpa_alg alg;
26293ff40c12SJohn Marino 	int klen;
26303ff40c12SJohn Marino 
26313ff40c12SJohn Marino 	/* MLME-SETKEYS.request(PTK) */
26323ff40c12SJohn Marino 	alg = wpa_cipher_to_alg(sm->pairwise);
26333ff40c12SJohn Marino 	klen = wpa_cipher_key_len(sm->pairwise);
26343ff40c12SJohn Marino 	if (!wpa_cipher_valid_pairwise(sm->pairwise)) {
26353ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip "
26363ff40c12SJohn Marino 			   "PTK configuration", sm->pairwise);
26373ff40c12SJohn Marino 		return;
26383ff40c12SJohn Marino 	}
26393ff40c12SJohn Marino 
2640*a1157835SDaniel Fojt 	if (sm->tk_already_set) {
2641*a1157835SDaniel Fojt 		/* Must avoid TK reconfiguration to prevent clearing of TX/RX
2642*a1157835SDaniel Fojt 		 * PN in the driver */
2643*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2644*a1157835SDaniel Fojt 			   "FT: Do not re-install same PTK to the driver");
2645*a1157835SDaniel Fojt 		return;
2646*a1157835SDaniel Fojt 	}
2647*a1157835SDaniel Fojt 
26483ff40c12SJohn Marino 	/* FIX: add STA entry to kernel/driver here? The set_key will fail
26493ff40c12SJohn Marino 	 * most likely without this.. At the moment, STA entry is added only
26503ff40c12SJohn Marino 	 * after association has been completed. This function will be called
26513ff40c12SJohn Marino 	 * again after association to get the PTK configured, but that could be
26523ff40c12SJohn Marino 	 * optimized by adding the STA entry earlier.
26533ff40c12SJohn Marino 	 */
26543ff40c12SJohn Marino 	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
2655*a1157835SDaniel Fojt 			     sm->PTK.tk, klen))
26563ff40c12SJohn Marino 		return;
26573ff40c12SJohn Marino 
26583ff40c12SJohn Marino 	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
26593ff40c12SJohn Marino 	sm->pairwise_set = TRUE;
2660*a1157835SDaniel Fojt 	sm->tk_already_set = TRUE;
26613ff40c12SJohn Marino }
26623ff40c12SJohn Marino 
26633ff40c12SJohn Marino 
2664*a1157835SDaniel Fojt /* Derive PMK-R1 from PSK, check all available PSK */
wpa_ft_psk_pmk_r1(struct wpa_state_machine * sm,const u8 * req_pmk_r1_name,u8 * out_pmk_r1,int * out_pairwise,struct vlan_description * out_vlan,const u8 ** out_identity,size_t * out_identity_len,const u8 ** out_radius_cui,size_t * out_radius_cui_len,int * out_session_timeout)2665*a1157835SDaniel Fojt static int wpa_ft_psk_pmk_r1(struct wpa_state_machine *sm,
2666*a1157835SDaniel Fojt 			     const u8 *req_pmk_r1_name,
2667*a1157835SDaniel Fojt 			     u8 *out_pmk_r1, int *out_pairwise,
2668*a1157835SDaniel Fojt 			     struct vlan_description *out_vlan,
2669*a1157835SDaniel Fojt 			     const u8 **out_identity, size_t *out_identity_len,
2670*a1157835SDaniel Fojt 			     const u8 **out_radius_cui,
2671*a1157835SDaniel Fojt 			     size_t *out_radius_cui_len,
2672*a1157835SDaniel Fojt 			     int *out_session_timeout)
2673*a1157835SDaniel Fojt {
2674*a1157835SDaniel Fojt 	const u8 *pmk = NULL;
2675*a1157835SDaniel Fojt 	u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
2676*a1157835SDaniel Fojt 	u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
2677*a1157835SDaniel Fojt 	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
2678*a1157835SDaniel Fojt 	const u8 *mdid = wpa_auth->conf.mobility_domain;
2679*a1157835SDaniel Fojt 	const u8 *r0kh = sm->r0kh_id;
2680*a1157835SDaniel Fojt 	size_t r0kh_len = sm->r0kh_id_len;
2681*a1157835SDaniel Fojt 	const u8 *r1kh = wpa_auth->conf.r1_key_holder;
2682*a1157835SDaniel Fojt 	const u8 *ssid = wpa_auth->conf.ssid;
2683*a1157835SDaniel Fojt 	size_t ssid_len = wpa_auth->conf.ssid_len;
2684*a1157835SDaniel Fojt 	int pairwise;
2685*a1157835SDaniel Fojt 
2686*a1157835SDaniel Fojt 	pairwise = sm->pairwise;
2687*a1157835SDaniel Fojt 
2688*a1157835SDaniel Fojt 	for (;;) {
2689*a1157835SDaniel Fojt 		pmk = wpa_ft_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr,
2690*a1157835SDaniel Fojt 				     pmk);
2691*a1157835SDaniel Fojt 		if (pmk == NULL)
2692*a1157835SDaniel Fojt 			break;
2693*a1157835SDaniel Fojt 
2694*a1157835SDaniel Fojt 		if (wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh,
2695*a1157835SDaniel Fojt 				      r0kh_len, sm->addr,
2696*a1157835SDaniel Fojt 				      pmk_r0, pmk_r0_name, 0) < 0 ||
2697*a1157835SDaniel Fojt 		    wpa_derive_pmk_r1(pmk_r0, PMK_LEN, pmk_r0_name, r1kh,
2698*a1157835SDaniel Fojt 				      sm->addr, pmk_r1, pmk_r1_name) < 0 ||
2699*a1157835SDaniel Fojt 		    os_memcmp_const(pmk_r1_name, req_pmk_r1_name,
2700*a1157835SDaniel Fojt 				    WPA_PMK_NAME_LEN) != 0)
2701*a1157835SDaniel Fojt 			continue;
2702*a1157835SDaniel Fojt 
2703*a1157835SDaniel Fojt 		/* We found a PSK that matches the requested pmk_r1_name */
2704*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2705*a1157835SDaniel Fojt 			   "FT: Found PSK to generate PMK-R1 locally");
2706*a1157835SDaniel Fojt 		os_memcpy(out_pmk_r1, pmk_r1, PMK_LEN);
2707*a1157835SDaniel Fojt 		if (out_pairwise)
2708*a1157835SDaniel Fojt 			*out_pairwise = pairwise;
2709*a1157835SDaniel Fojt 		os_memcpy(sm->PMK, pmk, PMK_LEN);
2710*a1157835SDaniel Fojt 		sm->pmk_len = PMK_LEN;
2711*a1157835SDaniel Fojt 		if (out_vlan &&
2712*a1157835SDaniel Fojt 		    wpa_ft_get_vlan(sm->wpa_auth, sm->addr, out_vlan) < 0) {
2713*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "FT: vlan not available for STA "
2714*a1157835SDaniel Fojt 				   MACSTR, MAC2STR(sm->addr));
2715*a1157835SDaniel Fojt 			return -1;
2716*a1157835SDaniel Fojt 		}
2717*a1157835SDaniel Fojt 
2718*a1157835SDaniel Fojt 		if (out_identity && out_identity_len) {
2719*a1157835SDaniel Fojt 			*out_identity_len = wpa_ft_get_identity(
2720*a1157835SDaniel Fojt 				sm->wpa_auth, sm->addr, out_identity);
2721*a1157835SDaniel Fojt 		}
2722*a1157835SDaniel Fojt 
2723*a1157835SDaniel Fojt 		if (out_radius_cui && out_radius_cui_len) {
2724*a1157835SDaniel Fojt 			*out_radius_cui_len = wpa_ft_get_radius_cui(
2725*a1157835SDaniel Fojt 				sm->wpa_auth, sm->addr, out_radius_cui);
2726*a1157835SDaniel Fojt 		}
2727*a1157835SDaniel Fojt 
2728*a1157835SDaniel Fojt 		if (out_session_timeout) {
2729*a1157835SDaniel Fojt 			*out_session_timeout = wpa_ft_get_session_timeout(
2730*a1157835SDaniel Fojt 				sm->wpa_auth, sm->addr);
2731*a1157835SDaniel Fojt 		}
2732*a1157835SDaniel Fojt 
2733*a1157835SDaniel Fojt 		return 0;
2734*a1157835SDaniel Fojt 	}
2735*a1157835SDaniel Fojt 
2736*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
2737*a1157835SDaniel Fojt 		   "FT: Did not find PSK to generate PMK-R1 locally");
2738*a1157835SDaniel Fojt 	return -1;
2739*a1157835SDaniel Fojt }
2740*a1157835SDaniel Fojt 
2741*a1157835SDaniel Fojt 
2742*a1157835SDaniel Fojt /* Detect the configuration the station asked for.
2743*a1157835SDaniel Fojt  * Required to detect FT-PSK and pairwise cipher.
2744*a1157835SDaniel Fojt  */
wpa_ft_set_key_mgmt(struct wpa_state_machine * sm,struct wpa_ft_ies * parse)2745*a1157835SDaniel Fojt static int wpa_ft_set_key_mgmt(struct wpa_state_machine *sm,
2746*a1157835SDaniel Fojt 			       struct wpa_ft_ies *parse)
2747*a1157835SDaniel Fojt {
2748*a1157835SDaniel Fojt 	int key_mgmt, ciphers;
2749*a1157835SDaniel Fojt 
2750*a1157835SDaniel Fojt 	if (sm->wpa_key_mgmt)
2751*a1157835SDaniel Fojt 		return 0;
2752*a1157835SDaniel Fojt 
2753*a1157835SDaniel Fojt 	key_mgmt = parse->key_mgmt & sm->wpa_auth->conf.wpa_key_mgmt;
2754*a1157835SDaniel Fojt 	if (!key_mgmt) {
2755*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Invalid key mgmt (0x%x) from "
2756*a1157835SDaniel Fojt 			   MACSTR, parse->key_mgmt, MAC2STR(sm->addr));
2757*a1157835SDaniel Fojt 		return -1;
2758*a1157835SDaniel Fojt 	}
2759*a1157835SDaniel Fojt 	if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
2760*a1157835SDaniel Fojt 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
2761*a1157835SDaniel Fojt #ifdef CONFIG_SHA384
2762*a1157835SDaniel Fojt 	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
2763*a1157835SDaniel Fojt 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
2764*a1157835SDaniel Fojt #endif /* CONFIG_SHA384 */
2765*a1157835SDaniel Fojt 	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
2766*a1157835SDaniel Fojt 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
2767*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2768*a1157835SDaniel Fojt 	else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
2769*a1157835SDaniel Fojt 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
2770*a1157835SDaniel Fojt 	else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
2771*a1157835SDaniel Fojt 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
2772*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2773*a1157835SDaniel Fojt 	ciphers = parse->pairwise_cipher & sm->wpa_auth->conf.rsn_pairwise;
2774*a1157835SDaniel Fojt 	if (!ciphers) {
2775*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Invalid pairwise cipher (0x%x) from "
2776*a1157835SDaniel Fojt 			   MACSTR,
2777*a1157835SDaniel Fojt 			   parse->pairwise_cipher, MAC2STR(sm->addr));
2778*a1157835SDaniel Fojt 		return -1;
2779*a1157835SDaniel Fojt 	}
2780*a1157835SDaniel Fojt 	sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
2781*a1157835SDaniel Fojt 
2782*a1157835SDaniel Fojt 	return 0;
2783*a1157835SDaniel Fojt }
2784*a1157835SDaniel Fojt 
2785*a1157835SDaniel Fojt 
wpa_ft_local_derive_pmk_r1(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm,const u8 * r0kh_id,size_t r0kh_id_len,const u8 * req_pmk_r0_name,const u8 * req_pmk_r1_name,u8 * out_pmk_r1,int * out_pairwise,struct vlan_description * vlan,const u8 ** identity,size_t * identity_len,const u8 ** radius_cui,size_t * radius_cui_len,int * out_session_timeout)2786*a1157835SDaniel Fojt static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth,
2787*a1157835SDaniel Fojt 				      struct wpa_state_machine *sm,
2788*a1157835SDaniel Fojt 				      const u8 *r0kh_id, size_t r0kh_id_len,
2789*a1157835SDaniel Fojt 				      const u8 *req_pmk_r0_name,
2790*a1157835SDaniel Fojt 				      const u8 *req_pmk_r1_name,
2791*a1157835SDaniel Fojt 				      u8 *out_pmk_r1, int *out_pairwise,
2792*a1157835SDaniel Fojt 				      struct vlan_description *vlan,
2793*a1157835SDaniel Fojt 				      const u8 **identity, size_t *identity_len,
2794*a1157835SDaniel Fojt 				      const u8 **radius_cui,
2795*a1157835SDaniel Fojt 				      size_t *radius_cui_len,
2796*a1157835SDaniel Fojt 				      int *out_session_timeout)
2797*a1157835SDaniel Fojt {
2798*a1157835SDaniel Fojt 	struct wpa_auth_config *conf = &wpa_auth->conf;
2799*a1157835SDaniel Fojt 	const struct wpa_ft_pmk_r0_sa *r0;
2800*a1157835SDaniel Fojt 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
2801*a1157835SDaniel Fojt 	int expires_in = 0;
2802*a1157835SDaniel Fojt 	int session_timeout = 0;
2803*a1157835SDaniel Fojt 	struct os_reltime now;
2804*a1157835SDaniel Fojt 
2805*a1157835SDaniel Fojt 	if (conf->r0_key_holder_len != r0kh_id_len ||
2806*a1157835SDaniel Fojt 	    os_memcmp(conf->r0_key_holder, r0kh_id, conf->r0_key_holder_len) !=
2807*a1157835SDaniel Fojt 	    0)
2808*a1157835SDaniel Fojt 		return -1; /* not our R0KH-ID */
2809*a1157835SDaniel Fojt 
2810*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: STA R0KH-ID matching local configuration");
2811*a1157835SDaniel Fojt 	if (wpa_ft_fetch_pmk_r0(sm->wpa_auth, sm->addr, req_pmk_r0_name, &r0) <
2812*a1157835SDaniel Fojt 	    0)
2813*a1157835SDaniel Fojt 		return -1; /* no matching PMKR0Name in local cache */
2814*a1157835SDaniel Fojt 
2815*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Requested PMKR0Name found in local cache");
2816*a1157835SDaniel Fojt 
2817*a1157835SDaniel Fojt 	if (wpa_derive_pmk_r1(r0->pmk_r0, r0->pmk_r0_len, r0->pmk_r0_name,
2818*a1157835SDaniel Fojt 			      conf->r1_key_holder,
2819*a1157835SDaniel Fojt 			      sm->addr, out_pmk_r1, pmk_r1_name) < 0)
2820*a1157835SDaniel Fojt 		return -1;
2821*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, r0->pmk_r0_len);
2822*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
2823*a1157835SDaniel Fojt 
2824*a1157835SDaniel Fojt 	os_get_reltime(&now);
2825*a1157835SDaniel Fojt 	if (r0->expiration)
2826*a1157835SDaniel Fojt 		expires_in = r0->expiration - now.sec;
2827*a1157835SDaniel Fojt 
2828*a1157835SDaniel Fojt 	if (r0->session_timeout)
2829*a1157835SDaniel Fojt 		session_timeout = r0->session_timeout - now.sec;
2830*a1157835SDaniel Fojt 
2831*a1157835SDaniel Fojt 	wpa_ft_store_pmk_r1(wpa_auth, sm->addr, out_pmk_r1, r0->pmk_r0_len,
2832*a1157835SDaniel Fojt 			    pmk_r1_name,
2833*a1157835SDaniel Fojt 			    sm->pairwise, r0->vlan, expires_in, session_timeout,
2834*a1157835SDaniel Fojt 			    r0->identity, r0->identity_len,
2835*a1157835SDaniel Fojt 			    r0->radius_cui, r0->radius_cui_len);
2836*a1157835SDaniel Fojt 
2837*a1157835SDaniel Fojt 	*out_pairwise = sm->pairwise;
2838*a1157835SDaniel Fojt 	if (vlan) {
2839*a1157835SDaniel Fojt 		if (r0->vlan)
2840*a1157835SDaniel Fojt 			*vlan = *r0->vlan;
2841*a1157835SDaniel Fojt 		else
2842*a1157835SDaniel Fojt 			os_memset(vlan, 0, sizeof(*vlan));
2843*a1157835SDaniel Fojt 	}
2844*a1157835SDaniel Fojt 
2845*a1157835SDaniel Fojt 	if (identity && identity_len) {
2846*a1157835SDaniel Fojt 		*identity = r0->identity;
2847*a1157835SDaniel Fojt 		*identity_len = r0->identity_len;
2848*a1157835SDaniel Fojt 	}
2849*a1157835SDaniel Fojt 
2850*a1157835SDaniel Fojt 	if (radius_cui && radius_cui_len) {
2851*a1157835SDaniel Fojt 		*radius_cui = r0->radius_cui;
2852*a1157835SDaniel Fojt 		*radius_cui_len = r0->radius_cui_len;
2853*a1157835SDaniel Fojt 	}
2854*a1157835SDaniel Fojt 
2855*a1157835SDaniel Fojt 	*out_session_timeout = session_timeout;
2856*a1157835SDaniel Fojt 
2857*a1157835SDaniel Fojt 	return 0;
2858*a1157835SDaniel Fojt }
2859*a1157835SDaniel Fojt 
2860*a1157835SDaniel Fojt 
wpa_ft_process_auth_req(struct wpa_state_machine * sm,const u8 * ies,size_t ies_len,u8 ** resp_ies,size_t * resp_ies_len)2861*a1157835SDaniel Fojt static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
28623ff40c12SJohn Marino 				   const u8 *ies, size_t ies_len,
28633ff40c12SJohn Marino 				   u8 **resp_ies, size_t *resp_ies_len)
28643ff40c12SJohn Marino {
28653ff40c12SJohn Marino 	struct rsn_mdie *mdie;
2866*a1157835SDaniel Fojt 	u8 pmk_r1[PMK_LEN_MAX], pmk_r1_name[WPA_PMK_NAME_LEN];
28673ff40c12SJohn Marino 	u8 ptk_name[WPA_PMK_NAME_LEN];
28683ff40c12SJohn Marino 	struct wpa_auth_config *conf;
28693ff40c12SJohn Marino 	struct wpa_ft_ies parse;
2870*a1157835SDaniel Fojt 	size_t buflen;
28713ff40c12SJohn Marino 	int ret;
28723ff40c12SJohn Marino 	u8 *pos, *end;
2873*a1157835SDaniel Fojt 	int pairwise, session_timeout = 0;
2874*a1157835SDaniel Fojt 	struct vlan_description vlan;
2875*a1157835SDaniel Fojt 	const u8 *identity, *radius_cui;
2876*a1157835SDaniel Fojt 	size_t identity_len = 0, radius_cui_len = 0;
2877*a1157835SDaniel Fojt 	int use_sha384;
2878*a1157835SDaniel Fojt 	size_t pmk_r1_len;
28793ff40c12SJohn Marino 
28803ff40c12SJohn Marino 	*resp_ies = NULL;
28813ff40c12SJohn Marino 	*resp_ies_len = 0;
28823ff40c12SJohn Marino 
28833ff40c12SJohn Marino 	sm->pmk_r1_name_valid = 0;
28843ff40c12SJohn Marino 	conf = &sm->wpa_auth->conf;
28853ff40c12SJohn Marino 
28863ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
28873ff40c12SJohn Marino 		    ies, ies_len);
28883ff40c12SJohn Marino 
2889*a1157835SDaniel Fojt 	if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) {
28903ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
28913ff40c12SJohn Marino 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
28923ff40c12SJohn Marino 	}
2893*a1157835SDaniel Fojt 	use_sha384 = wpa_key_mgmt_sha384(parse.key_mgmt);
2894*a1157835SDaniel Fojt 	pmk_r1_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
28953ff40c12SJohn Marino 
28963ff40c12SJohn Marino 	mdie = (struct rsn_mdie *) parse.mdie;
28973ff40c12SJohn Marino 	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
28983ff40c12SJohn Marino 	    os_memcmp(mdie->mobility_domain,
28993ff40c12SJohn Marino 		      sm->wpa_auth->conf.mobility_domain,
29003ff40c12SJohn Marino 		      MOBILITY_DOMAIN_ID_LEN) != 0) {
29013ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
29023ff40c12SJohn Marino 		return WLAN_STATUS_INVALID_MDIE;
29033ff40c12SJohn Marino 	}
29043ff40c12SJohn Marino 
2905*a1157835SDaniel Fojt 	if (use_sha384) {
2906*a1157835SDaniel Fojt 		struct rsn_ftie_sha384 *ftie;
2907*a1157835SDaniel Fojt 
2908*a1157835SDaniel Fojt 		ftie = (struct rsn_ftie_sha384 *) parse.ftie;
2909*a1157835SDaniel Fojt 		if (!ftie || parse.ftie_len < sizeof(*ftie)) {
29103ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
29113ff40c12SJohn Marino 			return WLAN_STATUS_INVALID_FTIE;
29123ff40c12SJohn Marino 		}
29133ff40c12SJohn Marino 
29143ff40c12SJohn Marino 		os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
2915*a1157835SDaniel Fojt 	} else {
2916*a1157835SDaniel Fojt 		struct rsn_ftie *ftie;
2917*a1157835SDaniel Fojt 
2918*a1157835SDaniel Fojt 		ftie = (struct rsn_ftie *) parse.ftie;
2919*a1157835SDaniel Fojt 		if (!ftie || parse.ftie_len < sizeof(*ftie)) {
2920*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
2921*a1157835SDaniel Fojt 			return WLAN_STATUS_INVALID_FTIE;
2922*a1157835SDaniel Fojt 		}
2923*a1157835SDaniel Fojt 
2924*a1157835SDaniel Fojt 		os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
2925*a1157835SDaniel Fojt 	}
29263ff40c12SJohn Marino 
29273ff40c12SJohn Marino 	if (parse.r0kh_id == NULL) {
29283ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
29293ff40c12SJohn Marino 		return WLAN_STATUS_INVALID_FTIE;
29303ff40c12SJohn Marino 	}
29313ff40c12SJohn Marino 
29323ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID",
29333ff40c12SJohn Marino 		    parse.r0kh_id, parse.r0kh_id_len);
29343ff40c12SJohn Marino 	os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
29353ff40c12SJohn Marino 	sm->r0kh_id_len = parse.r0kh_id_len;
29363ff40c12SJohn Marino 
29373ff40c12SJohn Marino 	if (parse.rsn_pmkid == NULL) {
29383ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
29393ff40c12SJohn Marino 		return WLAN_STATUS_INVALID_PMKID;
29403ff40c12SJohn Marino 	}
29413ff40c12SJohn Marino 
2942*a1157835SDaniel Fojt 	if (wpa_ft_set_key_mgmt(sm, &parse) < 0)
2943*a1157835SDaniel Fojt 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
2944*a1157835SDaniel Fojt 
29453ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
29463ff40c12SJohn Marino 		    parse.rsn_pmkid, WPA_PMK_NAME_LEN);
2947*a1157835SDaniel Fojt 	if (wpa_derive_pmk_r1_name(parse.rsn_pmkid,
29483ff40c12SJohn Marino 				   sm->wpa_auth->conf.r1_key_holder, sm->addr,
2949*a1157835SDaniel Fojt 				   pmk_r1_name, use_sha384) < 0)
2950*a1157835SDaniel Fojt 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
29513ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
29523ff40c12SJohn Marino 		    pmk_r1_name, WPA_PMK_NAME_LEN);
29533ff40c12SJohn Marino 
2954*a1157835SDaniel Fojt 	if (conf->ft_psk_generate_local &&
2955*a1157835SDaniel Fojt 	    wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
2956*a1157835SDaniel Fojt 		if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise,
2957*a1157835SDaniel Fojt 				      &vlan, &identity, &identity_len,
2958*a1157835SDaniel Fojt 				      &radius_cui, &radius_cui_len,
2959*a1157835SDaniel Fojt 				      &session_timeout) < 0)
2960*a1157835SDaniel Fojt 			return WLAN_STATUS_INVALID_PMKID;
2961*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2962*a1157835SDaniel Fojt 			   "FT: Generated PMK-R1 for FT-PSK locally");
2963*a1157835SDaniel Fojt 	} else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name,
2964*a1157835SDaniel Fojt 				       pmk_r1, &pmk_r1_len, &pairwise, &vlan,
2965*a1157835SDaniel Fojt 				       &identity, &identity_len, &radius_cui,
2966*a1157835SDaniel Fojt 				       &radius_cui_len, &session_timeout) < 0) {
2967*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2968*a1157835SDaniel Fojt 			   "FT: No PMK-R1 available in local cache for the requested PMKR1Name");
2969*a1157835SDaniel Fojt 		if (wpa_ft_local_derive_pmk_r1(sm->wpa_auth, sm,
2970*a1157835SDaniel Fojt 					       parse.r0kh_id, parse.r0kh_id_len,
2971*a1157835SDaniel Fojt 					       parse.rsn_pmkid,
2972*a1157835SDaniel Fojt 					       pmk_r1_name, pmk_r1, &pairwise,
2973*a1157835SDaniel Fojt 					       &vlan, &identity, &identity_len,
2974*a1157835SDaniel Fojt 					       &radius_cui, &radius_cui_len,
2975*a1157835SDaniel Fojt 					       &session_timeout) == 0) {
2976*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
2977*a1157835SDaniel Fojt 				   "FT: Generated PMK-R1 based on local PMK-R0");
2978*a1157835SDaniel Fojt 			goto pmk_r1_derived;
2979*a1157835SDaniel Fojt 		}
2980*a1157835SDaniel Fojt 
2981*a1157835SDaniel Fojt 		if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) {
2982*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
2983*a1157835SDaniel Fojt 				   "FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH");
29843ff40c12SJohn Marino 			return WLAN_STATUS_INVALID_PMKID;
29853ff40c12SJohn Marino 		}
29863ff40c12SJohn Marino 
2987*a1157835SDaniel Fojt 		return -1; /* Status pending */
2988*a1157835SDaniel Fojt 	} else {
2989*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Found PMKR1Name from local cache");
29903ff40c12SJohn Marino 	}
29913ff40c12SJohn Marino 
2992*a1157835SDaniel Fojt pmk_r1_derived:
2993*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, pmk_r1_len);
29943ff40c12SJohn Marino 	sm->pmk_r1_name_valid = 1;
29953ff40c12SJohn Marino 	os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
2996*a1157835SDaniel Fojt 	os_memcpy(sm->pmk_r1, pmk_r1, pmk_r1_len);
2997*a1157835SDaniel Fojt 	sm->pmk_r1_len = pmk_r1_len;
29983ff40c12SJohn Marino 
29993ff40c12SJohn Marino 	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
30003ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
30013ff40c12SJohn Marino 			   "ANonce");
30023ff40c12SJohn Marino 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
30033ff40c12SJohn Marino 	}
30043ff40c12SJohn Marino 
30053ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
30063ff40c12SJohn Marino 		    sm->SNonce, WPA_NONCE_LEN);
30073ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
30083ff40c12SJohn Marino 		    sm->ANonce, WPA_NONCE_LEN);
30093ff40c12SJohn Marino 
3010*a1157835SDaniel Fojt 	if (wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
3011*a1157835SDaniel Fojt 			      sm->addr, sm->wpa_auth->addr, pmk_r1_name,
3012*a1157835SDaniel Fojt 			      &sm->PTK, ptk_name, sm->wpa_key_mgmt,
3013*a1157835SDaniel Fojt 			      pairwise) < 0)
3014*a1157835SDaniel Fojt 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
30153ff40c12SJohn Marino 
30163ff40c12SJohn Marino 	sm->pairwise = pairwise;
3017*a1157835SDaniel Fojt 	sm->PTK_valid = TRUE;
3018*a1157835SDaniel Fojt 	sm->tk_already_set = FALSE;
30193ff40c12SJohn Marino 	wpa_ft_install_ptk(sm);
30203ff40c12SJohn Marino 
3021*a1157835SDaniel Fojt 	if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
3022*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
3023*a1157835SDaniel Fojt 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
3024*a1157835SDaniel Fojt 	}
3025*a1157835SDaniel Fojt 	if (wpa_ft_set_identity(sm->wpa_auth, sm->addr,
3026*a1157835SDaniel Fojt 				identity, identity_len) < 0 ||
3027*a1157835SDaniel Fojt 	    wpa_ft_set_radius_cui(sm->wpa_auth, sm->addr,
3028*a1157835SDaniel Fojt 				  radius_cui, radius_cui_len) < 0) {
3029*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Failed to configure identity/CUI");
3030*a1157835SDaniel Fojt 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
3031*a1157835SDaniel Fojt 	}
3032*a1157835SDaniel Fojt 	wpa_ft_set_session_timeout(sm->wpa_auth, sm->addr, session_timeout);
3033*a1157835SDaniel Fojt 
30343ff40c12SJohn Marino 	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
30353ff40c12SJohn Marino 		2 + FT_R1KH_ID_LEN + 200;
30363ff40c12SJohn Marino 	*resp_ies = os_zalloc(buflen);
3037*a1157835SDaniel Fojt 	if (*resp_ies == NULL)
3038*a1157835SDaniel Fojt 		goto fail;
30393ff40c12SJohn Marino 
30403ff40c12SJohn Marino 	pos = *resp_ies;
30413ff40c12SJohn Marino 	end = *resp_ies + buflen;
30423ff40c12SJohn Marino 
30433ff40c12SJohn Marino 	ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
3044*a1157835SDaniel Fojt 	if (ret < 0)
3045*a1157835SDaniel Fojt 		goto fail;
30463ff40c12SJohn Marino 	pos += ret;
30473ff40c12SJohn Marino 
30483ff40c12SJohn Marino 	ret = wpa_write_mdie(conf, pos, end - pos);
3049*a1157835SDaniel Fojt 	if (ret < 0)
3050*a1157835SDaniel Fojt 		goto fail;
30513ff40c12SJohn Marino 	pos += ret;
30523ff40c12SJohn Marino 
3053*a1157835SDaniel Fojt 	ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
30543ff40c12SJohn Marino 			     sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
3055*a1157835SDaniel Fojt 	if (ret < 0)
3056*a1157835SDaniel Fojt 		goto fail;
30573ff40c12SJohn Marino 	pos += ret;
30583ff40c12SJohn Marino 
30593ff40c12SJohn Marino 	*resp_ies_len = pos - *resp_ies;
30603ff40c12SJohn Marino 
30613ff40c12SJohn Marino 	return WLAN_STATUS_SUCCESS;
3062*a1157835SDaniel Fojt fail:
3063*a1157835SDaniel Fojt 	os_free(*resp_ies);
3064*a1157835SDaniel Fojt 	*resp_ies = NULL;
3065*a1157835SDaniel Fojt 	return WLAN_STATUS_UNSPECIFIED_FAILURE;
30663ff40c12SJohn Marino }
30673ff40c12SJohn Marino 
30683ff40c12SJohn Marino 
wpa_ft_process_auth(struct wpa_state_machine * sm,const u8 * bssid,u16 auth_transaction,const u8 * ies,size_t ies_len,void (* cb)(void * ctx,const u8 * dst,const u8 * bssid,u16 auth_transaction,u16 status,const u8 * ies,size_t ies_len),void * ctx)30693ff40c12SJohn Marino void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
30703ff40c12SJohn Marino 			 u16 auth_transaction, const u8 *ies, size_t ies_len,
30713ff40c12SJohn Marino 			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
30723ff40c12SJohn Marino 				    u16 auth_transaction, u16 status,
30733ff40c12SJohn Marino 				    const u8 *ies, size_t ies_len),
30743ff40c12SJohn Marino 			 void *ctx)
30753ff40c12SJohn Marino {
30763ff40c12SJohn Marino 	u16 status;
30773ff40c12SJohn Marino 	u8 *resp_ies;
30783ff40c12SJohn Marino 	size_t resp_ies_len;
3079*a1157835SDaniel Fojt 	int res;
30803ff40c12SJohn Marino 
30813ff40c12SJohn Marino 	if (sm == NULL) {
30823ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
30833ff40c12SJohn Marino 			   "WPA SM not available");
30843ff40c12SJohn Marino 		return;
30853ff40c12SJohn Marino 	}
30863ff40c12SJohn Marino 
30873ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
30883ff40c12SJohn Marino 		   " BSSID=" MACSTR " transaction=%d",
30893ff40c12SJohn Marino 		   MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
3090*a1157835SDaniel Fojt 	sm->ft_pending_cb = cb;
3091*a1157835SDaniel Fojt 	sm->ft_pending_cb_ctx = ctx;
3092*a1157835SDaniel Fojt 	sm->ft_pending_auth_transaction = auth_transaction;
3093*a1157835SDaniel Fojt 	sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries;
3094*a1157835SDaniel Fojt 	res = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
30953ff40c12SJohn Marino 				      &resp_ies_len);
3096*a1157835SDaniel Fojt 	if (res < 0) {
3097*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Callback postponed until response is available");
3098*a1157835SDaniel Fojt 		return;
3099*a1157835SDaniel Fojt 	}
3100*a1157835SDaniel Fojt 	status = res;
31013ff40c12SJohn Marino 
31023ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
3103*a1157835SDaniel Fojt 		   " auth_transaction=%d status=%u (%s)",
3104*a1157835SDaniel Fojt 		   MAC2STR(sm->addr), auth_transaction + 1, status,
3105*a1157835SDaniel Fojt 		   status2str(status));
31063ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
31073ff40c12SJohn Marino 	cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
31083ff40c12SJohn Marino 	   resp_ies, resp_ies_len);
31093ff40c12SJohn Marino 	os_free(resp_ies);
31103ff40c12SJohn Marino }
31113ff40c12SJohn Marino 
31123ff40c12SJohn Marino 
wpa_ft_validate_reassoc(struct wpa_state_machine * sm,const u8 * ies,size_t ies_len)31133ff40c12SJohn Marino u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
31143ff40c12SJohn Marino 			    size_t ies_len)
31153ff40c12SJohn Marino {
31163ff40c12SJohn Marino 	struct wpa_ft_ies parse;
31173ff40c12SJohn Marino 	struct rsn_mdie *mdie;
3118*a1157835SDaniel Fojt 	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
3119*a1157835SDaniel Fojt 	size_t mic_len = 16;
31203ff40c12SJohn Marino 	unsigned int count;
3121*a1157835SDaniel Fojt 	const u8 *kck;
3122*a1157835SDaniel Fojt 	size_t kck_len;
3123*a1157835SDaniel Fojt 	int use_sha384;
3124*a1157835SDaniel Fojt 	const u8 *anonce, *snonce, *fte_mic;
3125*a1157835SDaniel Fojt 	u8 fte_elem_count;
31263ff40c12SJohn Marino 
31273ff40c12SJohn Marino 	if (sm == NULL)
31283ff40c12SJohn Marino 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
31293ff40c12SJohn Marino 
3130*a1157835SDaniel Fojt 	use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
3131*a1157835SDaniel Fojt 
31323ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
31333ff40c12SJohn Marino 
3134*a1157835SDaniel Fojt 	if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) {
31353ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
31363ff40c12SJohn Marino 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
31373ff40c12SJohn Marino 	}
31383ff40c12SJohn Marino 
31393ff40c12SJohn Marino 	if (parse.rsn == NULL) {
31403ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req");
31413ff40c12SJohn Marino 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
31423ff40c12SJohn Marino 	}
31433ff40c12SJohn Marino 
31443ff40c12SJohn Marino 	if (parse.rsn_pmkid == NULL) {
31453ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
31463ff40c12SJohn Marino 		return WLAN_STATUS_INVALID_PMKID;
31473ff40c12SJohn Marino 	}
31483ff40c12SJohn Marino 
3149*a1157835SDaniel Fojt 	if (os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)
3150*a1157835SDaniel Fojt 	    != 0) {
31513ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
31523ff40c12SJohn Marino 			   "with the PMKR1Name derived from auth request");
31533ff40c12SJohn Marino 		return WLAN_STATUS_INVALID_PMKID;
31543ff40c12SJohn Marino 	}
31553ff40c12SJohn Marino 
31563ff40c12SJohn Marino 	mdie = (struct rsn_mdie *) parse.mdie;
31573ff40c12SJohn Marino 	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
31583ff40c12SJohn Marino 	    os_memcmp(mdie->mobility_domain,
31593ff40c12SJohn Marino 		      sm->wpa_auth->conf.mobility_domain,
31603ff40c12SJohn Marino 		      MOBILITY_DOMAIN_ID_LEN) != 0) {
31613ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
31623ff40c12SJohn Marino 		return WLAN_STATUS_INVALID_MDIE;
31633ff40c12SJohn Marino 	}
31643ff40c12SJohn Marino 
3165*a1157835SDaniel Fojt 	if (use_sha384) {
3166*a1157835SDaniel Fojt 		struct rsn_ftie_sha384 *ftie;
3167*a1157835SDaniel Fojt 
3168*a1157835SDaniel Fojt 		ftie = (struct rsn_ftie_sha384 *) parse.ftie;
3169*a1157835SDaniel Fojt 		if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
3170*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
3171*a1157835SDaniel Fojt 			return WLAN_STATUS_INVALID_FTIE;
3172*a1157835SDaniel Fojt 		}
3173*a1157835SDaniel Fojt 
3174*a1157835SDaniel Fojt 		anonce = ftie->anonce;
3175*a1157835SDaniel Fojt 		snonce = ftie->snonce;
3176*a1157835SDaniel Fojt 		fte_elem_count = ftie->mic_control[1];
3177*a1157835SDaniel Fojt 		fte_mic = ftie->mic;
3178*a1157835SDaniel Fojt 	} else {
3179*a1157835SDaniel Fojt 		struct rsn_ftie *ftie;
3180*a1157835SDaniel Fojt 
31813ff40c12SJohn Marino 		ftie = (struct rsn_ftie *) parse.ftie;
31823ff40c12SJohn Marino 		if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
31833ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
31843ff40c12SJohn Marino 			return WLAN_STATUS_INVALID_FTIE;
31853ff40c12SJohn Marino 		}
31863ff40c12SJohn Marino 
3187*a1157835SDaniel Fojt 		anonce = ftie->anonce;
3188*a1157835SDaniel Fojt 		snonce = ftie->snonce;
3189*a1157835SDaniel Fojt 		fte_elem_count = ftie->mic_control[1];
3190*a1157835SDaniel Fojt 		fte_mic = ftie->mic;
31913ff40c12SJohn Marino 	}
31923ff40c12SJohn Marino 
3193*a1157835SDaniel Fojt 	if (os_memcmp(snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
3194*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
3195*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
3196*a1157835SDaniel Fojt 			    snonce, WPA_NONCE_LEN);
3197*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
3198*a1157835SDaniel Fojt 			    sm->SNonce, WPA_NONCE_LEN);
3199*a1157835SDaniel Fojt 		return WLAN_STATUS_INVALID_FTIE;
3200*a1157835SDaniel Fojt 	}
3201*a1157835SDaniel Fojt 
3202*a1157835SDaniel Fojt 	if (os_memcmp(anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
32033ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
32043ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
3205*a1157835SDaniel Fojt 			    anonce, WPA_NONCE_LEN);
32063ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
32073ff40c12SJohn Marino 			    sm->ANonce, WPA_NONCE_LEN);
3208*a1157835SDaniel Fojt 		return WLAN_STATUS_INVALID_FTIE;
32093ff40c12SJohn Marino 	}
32103ff40c12SJohn Marino 
32113ff40c12SJohn Marino 
32123ff40c12SJohn Marino 	if (parse.r0kh_id == NULL) {
32133ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
3214*a1157835SDaniel Fojt 		return WLAN_STATUS_INVALID_FTIE;
32153ff40c12SJohn Marino 	}
32163ff40c12SJohn Marino 
32173ff40c12SJohn Marino 	if (parse.r0kh_id_len != sm->r0kh_id_len ||
3218*a1157835SDaniel Fojt 	    os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
3219*a1157835SDaniel Fojt 	{
32203ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
32213ff40c12SJohn Marino 			   "the current R0KH-ID");
32223ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
32233ff40c12SJohn Marino 			    parse.r0kh_id, parse.r0kh_id_len);
32243ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
32253ff40c12SJohn Marino 			    sm->r0kh_id, sm->r0kh_id_len);
3226*a1157835SDaniel Fojt 		return WLAN_STATUS_INVALID_FTIE;
32273ff40c12SJohn Marino 	}
32283ff40c12SJohn Marino 
32293ff40c12SJohn Marino 	if (parse.r1kh_id == NULL) {
32303ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
3231*a1157835SDaniel Fojt 		return WLAN_STATUS_INVALID_FTIE;
32323ff40c12SJohn Marino 	}
32333ff40c12SJohn Marino 
3234*a1157835SDaniel Fojt 	if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
32353ff40c12SJohn Marino 			    FT_R1KH_ID_LEN) != 0) {
32363ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
32373ff40c12SJohn Marino 			   "ReassocReq");
32383ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
32393ff40c12SJohn Marino 			    parse.r1kh_id, FT_R1KH_ID_LEN);
32403ff40c12SJohn Marino 		wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
32413ff40c12SJohn Marino 			    sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
3242*a1157835SDaniel Fojt 		return WLAN_STATUS_INVALID_FTIE;
32433ff40c12SJohn Marino 	}
32443ff40c12SJohn Marino 
32453ff40c12SJohn Marino 	if (parse.rsn_pmkid == NULL ||
3246*a1157835SDaniel Fojt 	    os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
3247*a1157835SDaniel Fojt 	{
32483ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
32493ff40c12SJohn Marino 			   "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
3250*a1157835SDaniel Fojt 		return WLAN_STATUS_INVALID_PMKID;
32513ff40c12SJohn Marino 	}
32523ff40c12SJohn Marino 
32533ff40c12SJohn Marino 	count = 3;
32543ff40c12SJohn Marino 	if (parse.ric)
32553ff40c12SJohn Marino 		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
3256*a1157835SDaniel Fojt 	if (fte_elem_count != count) {
32573ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
32583ff40c12SJohn Marino 			   "Control: received %u expected %u",
3259*a1157835SDaniel Fojt 			   fte_elem_count, count);
3260*a1157835SDaniel Fojt 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
32613ff40c12SJohn Marino 	}
32623ff40c12SJohn Marino 
3263*a1157835SDaniel Fojt 	if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
3264*a1157835SDaniel Fojt 		kck = sm->PTK.kck2;
3265*a1157835SDaniel Fojt 		kck_len = sm->PTK.kck2_len;
3266*a1157835SDaniel Fojt 	} else {
3267*a1157835SDaniel Fojt 		kck = sm->PTK.kck;
3268*a1157835SDaniel Fojt 		kck_len = sm->PTK.kck_len;
3269*a1157835SDaniel Fojt 	}
3270*a1157835SDaniel Fojt 	if (wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 5,
32713ff40c12SJohn Marino 		       parse.mdie - 2, parse.mdie_len + 2,
32723ff40c12SJohn Marino 		       parse.ftie - 2, parse.ftie_len + 2,
32733ff40c12SJohn Marino 		       parse.rsn - 2, parse.rsn_len + 2,
32743ff40c12SJohn Marino 		       parse.ric, parse.ric_len,
32753ff40c12SJohn Marino 		       mic) < 0) {
32763ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
32773ff40c12SJohn Marino 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
32783ff40c12SJohn Marino 	}
32793ff40c12SJohn Marino 
3280*a1157835SDaniel Fojt 	if (os_memcmp_const(mic, fte_mic, mic_len) != 0) {
32813ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
32823ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
32833ff40c12SJohn Marino 			   MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
3284*a1157835SDaniel Fojt 		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC",
3285*a1157835SDaniel Fojt 			    fte_mic, mic_len);
3286*a1157835SDaniel Fojt 		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len);
32873ff40c12SJohn Marino 		wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
32883ff40c12SJohn Marino 			    parse.mdie - 2, parse.mdie_len + 2);
32893ff40c12SJohn Marino 		wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
32903ff40c12SJohn Marino 			    parse.ftie - 2, parse.ftie_len + 2);
32913ff40c12SJohn Marino 		wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
32923ff40c12SJohn Marino 			    parse.rsn - 2, parse.rsn_len + 2);
32933ff40c12SJohn Marino 		return WLAN_STATUS_INVALID_FTIE;
32943ff40c12SJohn Marino 	}
32953ff40c12SJohn Marino 
3296*a1157835SDaniel Fojt #ifdef CONFIG_OCV
3297*a1157835SDaniel Fojt 	if (wpa_auth_uses_ocv(sm)) {
3298*a1157835SDaniel Fojt 		struct wpa_channel_info ci;
3299*a1157835SDaniel Fojt 		int tx_chanwidth;
3300*a1157835SDaniel Fojt 		int tx_seg1_idx;
3301*a1157835SDaniel Fojt 
3302*a1157835SDaniel Fojt 		if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
3303*a1157835SDaniel Fojt 			wpa_printf(MSG_WARNING,
3304*a1157835SDaniel Fojt 				   "Failed to get channel info to validate received OCI in (Re)Assoc Request");
3305*a1157835SDaniel Fojt 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
3306*a1157835SDaniel Fojt 		}
3307*a1157835SDaniel Fojt 
3308*a1157835SDaniel Fojt 		if (get_sta_tx_parameters(sm,
3309*a1157835SDaniel Fojt 					  channel_width_to_int(ci.chanwidth),
3310*a1157835SDaniel Fojt 					  ci.seg1_idx, &tx_chanwidth,
3311*a1157835SDaniel Fojt 					  &tx_seg1_idx) < 0)
3312*a1157835SDaniel Fojt 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
3313*a1157835SDaniel Fojt 
3314*a1157835SDaniel Fojt 		if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
3315*a1157835SDaniel Fojt 					 tx_chanwidth, tx_seg1_idx) != 0) {
3316*a1157835SDaniel Fojt 			wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
3317*a1157835SDaniel Fojt 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
3318*a1157835SDaniel Fojt 		}
3319*a1157835SDaniel Fojt 	}
3320*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
3321*a1157835SDaniel Fojt 
33223ff40c12SJohn Marino 	return WLAN_STATUS_SUCCESS;
33233ff40c12SJohn Marino }
33243ff40c12SJohn Marino 
33253ff40c12SJohn Marino 
wpa_ft_action_rx(struct wpa_state_machine * sm,const u8 * data,size_t len)33263ff40c12SJohn Marino int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
33273ff40c12SJohn Marino {
33283ff40c12SJohn Marino 	const u8 *sta_addr, *target_ap;
33293ff40c12SJohn Marino 	const u8 *ies;
33303ff40c12SJohn Marino 	size_t ies_len;
33313ff40c12SJohn Marino 	u8 action;
33323ff40c12SJohn Marino 	struct ft_rrb_frame *frame;
33333ff40c12SJohn Marino 
33343ff40c12SJohn Marino 	if (sm == NULL)
33353ff40c12SJohn Marino 		return -1;
33363ff40c12SJohn Marino 
33373ff40c12SJohn Marino 	/*
33383ff40c12SJohn Marino 	 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
33393ff40c12SJohn Marino 	 * FT Request action frame body[variable]
33403ff40c12SJohn Marino 	 */
33413ff40c12SJohn Marino 
33423ff40c12SJohn Marino 	if (len < 14) {
33433ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame "
33443ff40c12SJohn Marino 			   "(len=%lu)", (unsigned long) len);
33453ff40c12SJohn Marino 		return -1;
33463ff40c12SJohn Marino 	}
33473ff40c12SJohn Marino 
33483ff40c12SJohn Marino 	action = data[1];
33493ff40c12SJohn Marino 	sta_addr = data + 2;
33503ff40c12SJohn Marino 	target_ap = data + 8;
33513ff40c12SJohn Marino 	ies = data + 14;
33523ff40c12SJohn Marino 	ies_len = len - 14;
33533ff40c12SJohn Marino 
33543ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR
33553ff40c12SJohn Marino 		   " Target AP=" MACSTR " Action=%d)",
33563ff40c12SJohn Marino 		   MAC2STR(sta_addr), MAC2STR(target_ap), action);
33573ff40c12SJohn Marino 
33583ff40c12SJohn Marino 	if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) {
33593ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: "
33603ff40c12SJohn Marino 			   "STA=" MACSTR " STA-Address=" MACSTR,
33613ff40c12SJohn Marino 			   MAC2STR(sm->addr), MAC2STR(sta_addr));
33623ff40c12SJohn Marino 		return -1;
33633ff40c12SJohn Marino 	}
33643ff40c12SJohn Marino 
33653ff40c12SJohn Marino 	/*
33663ff40c12SJohn Marino 	 * Do some sanity checking on the target AP address (not own and not
33673ff40c12SJohn Marino 	 * broadcast. This could be extended to filter based on a list of known
33683ff40c12SJohn Marino 	 * APs in the MD (if such a list were configured).
33693ff40c12SJohn Marino 	 */
33703ff40c12SJohn Marino 	if ((target_ap[0] & 0x01) ||
33713ff40c12SJohn Marino 	    os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) {
33723ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action "
33733ff40c12SJohn Marino 			   "frame");
33743ff40c12SJohn Marino 		return -1;
33753ff40c12SJohn Marino 	}
33763ff40c12SJohn Marino 
33773ff40c12SJohn Marino 	wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
33783ff40c12SJohn Marino 
3379*a1157835SDaniel Fojt 	if (!sm->wpa_auth->conf.ft_over_ds) {
3380*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Over-DS option disabled - reject");
3381*a1157835SDaniel Fojt 		return -1;
3382*a1157835SDaniel Fojt 	}
3383*a1157835SDaniel Fojt 
33843ff40c12SJohn Marino 	/* RRB - Forward action frame to the target AP */
33853ff40c12SJohn Marino 	frame = os_malloc(sizeof(*frame) + len);
33863ff40c12SJohn Marino 	if (frame == NULL)
33873ff40c12SJohn Marino 		return -1;
33883ff40c12SJohn Marino 	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
33893ff40c12SJohn Marino 	frame->packet_type = FT_PACKET_REQUEST;
33903ff40c12SJohn Marino 	frame->action_length = host_to_le16(len);
33913ff40c12SJohn Marino 	os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN);
33923ff40c12SJohn Marino 	os_memcpy(frame + 1, data, len);
33933ff40c12SJohn Marino 
33943ff40c12SJohn Marino 	wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame,
33953ff40c12SJohn Marino 			sizeof(*frame) + len);
33963ff40c12SJohn Marino 	os_free(frame);
33973ff40c12SJohn Marino 
33983ff40c12SJohn Marino 	return 0;
33993ff40c12SJohn Marino }
34003ff40c12SJohn Marino 
34013ff40c12SJohn Marino 
wpa_ft_rrb_rx_request_cb(void * ctx,const u8 * dst,const u8 * bssid,u16 auth_transaction,u16 resp,const u8 * ies,size_t ies_len)3402*a1157835SDaniel Fojt static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst, const u8 *bssid,
3403*a1157835SDaniel Fojt 				     u16 auth_transaction, u16 resp,
3404*a1157835SDaniel Fojt 				     const u8 *ies, size_t ies_len)
3405*a1157835SDaniel Fojt {
3406*a1157835SDaniel Fojt 	struct wpa_state_machine *sm = ctx;
3407*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Over-the-DS RX request cb for " MACSTR,
3408*a1157835SDaniel Fojt 		   MAC2STR(sm->addr));
3409*a1157835SDaniel Fojt 	wpa_ft_send_rrb_auth_resp(sm, sm->ft_pending_current_ap, sm->addr,
3410*a1157835SDaniel Fojt 				  WLAN_STATUS_SUCCESS, ies, ies_len);
3411*a1157835SDaniel Fojt }
3412*a1157835SDaniel Fojt 
3413*a1157835SDaniel Fojt 
wpa_ft_rrb_rx_request(struct wpa_authenticator * wpa_auth,const u8 * current_ap,const u8 * sta_addr,const u8 * body,size_t len)34143ff40c12SJohn Marino static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
34153ff40c12SJohn Marino 				 const u8 *current_ap, const u8 *sta_addr,
34163ff40c12SJohn Marino 				 const u8 *body, size_t len)
34173ff40c12SJohn Marino {
34183ff40c12SJohn Marino 	struct wpa_state_machine *sm;
34193ff40c12SJohn Marino 	u16 status;
3420*a1157835SDaniel Fojt 	u8 *resp_ies;
3421*a1157835SDaniel Fojt 	size_t resp_ies_len;
3422*a1157835SDaniel Fojt 	int res;
34233ff40c12SJohn Marino 
34243ff40c12SJohn Marino 	sm = wpa_ft_add_sta(wpa_auth, sta_addr);
34253ff40c12SJohn Marino 	if (sm == NULL) {
34263ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on "
34273ff40c12SJohn Marino 			   "RRB Request");
34283ff40c12SJohn Marino 		return -1;
34293ff40c12SJohn Marino 	}
34303ff40c12SJohn Marino 
34313ff40c12SJohn Marino 	wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
34323ff40c12SJohn Marino 
3433*a1157835SDaniel Fojt 	sm->ft_pending_cb = wpa_ft_rrb_rx_request_cb;
3434*a1157835SDaniel Fojt 	sm->ft_pending_cb_ctx = sm;
3435*a1157835SDaniel Fojt 	os_memcpy(sm->ft_pending_current_ap, current_ap, ETH_ALEN);
3436*a1157835SDaniel Fojt 	sm->ft_pending_pull_left_retries = sm->wpa_auth->conf.rkh_pull_retries;
3437*a1157835SDaniel Fojt 	res = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
34383ff40c12SJohn Marino 				      &resp_ies_len);
3439*a1157835SDaniel Fojt 	if (res < 0) {
3440*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: No immediate response available - wait for pull response");
3441*a1157835SDaniel Fojt 		return 0;
3442*a1157835SDaniel Fojt 	}
3443*a1157835SDaniel Fojt 	status = res;
3444*a1157835SDaniel Fojt 
3445*a1157835SDaniel Fojt 	res = wpa_ft_send_rrb_auth_resp(sm, current_ap, sta_addr, status,
3446*a1157835SDaniel Fojt 					resp_ies, resp_ies_len);
3447*a1157835SDaniel Fojt 	os_free(resp_ies);
3448*a1157835SDaniel Fojt 	return res;
3449*a1157835SDaniel Fojt }
3450*a1157835SDaniel Fojt 
3451*a1157835SDaniel Fojt 
wpa_ft_send_rrb_auth_resp(struct wpa_state_machine * sm,const u8 * current_ap,const u8 * sta_addr,u16 status,const u8 * resp_ies,size_t resp_ies_len)3452*a1157835SDaniel Fojt static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
3453*a1157835SDaniel Fojt 				     const u8 *current_ap, const u8 *sta_addr,
3454*a1157835SDaniel Fojt 				     u16 status, const u8 *resp_ies,
3455*a1157835SDaniel Fojt 				     size_t resp_ies_len)
3456*a1157835SDaniel Fojt {
3457*a1157835SDaniel Fojt 	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
3458*a1157835SDaniel Fojt 	size_t rlen;
3459*a1157835SDaniel Fojt 	struct ft_rrb_frame *frame;
3460*a1157835SDaniel Fojt 	u8 *pos;
34613ff40c12SJohn Marino 
34623ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
3463*a1157835SDaniel Fojt 		   " CurrentAP=" MACSTR " status=%u (%s)",
3464*a1157835SDaniel Fojt 		   MAC2STR(sm->addr), MAC2STR(current_ap), status,
3465*a1157835SDaniel Fojt 		   status2str(status));
34663ff40c12SJohn Marino 	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
34673ff40c12SJohn Marino 
34683ff40c12SJohn Marino 	/* RRB - Forward action frame response to the Current AP */
34693ff40c12SJohn Marino 
34703ff40c12SJohn Marino 	/*
34713ff40c12SJohn Marino 	 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
34723ff40c12SJohn Marino 	 * Status_Code[2] FT Request action frame body[variable]
34733ff40c12SJohn Marino 	 */
34743ff40c12SJohn Marino 	rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
34753ff40c12SJohn Marino 
34763ff40c12SJohn Marino 	frame = os_malloc(sizeof(*frame) + rlen);
3477*a1157835SDaniel Fojt 	if (frame == NULL)
34783ff40c12SJohn Marino 		return -1;
34793ff40c12SJohn Marino 	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
34803ff40c12SJohn Marino 	frame->packet_type = FT_PACKET_RESPONSE;
34813ff40c12SJohn Marino 	frame->action_length = host_to_le16(rlen);
34823ff40c12SJohn Marino 	os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
34833ff40c12SJohn Marino 	pos = (u8 *) (frame + 1);
34843ff40c12SJohn Marino 	*pos++ = WLAN_ACTION_FT;
34853ff40c12SJohn Marino 	*pos++ = 2; /* Action: Response */
34863ff40c12SJohn Marino 	os_memcpy(pos, sta_addr, ETH_ALEN);
34873ff40c12SJohn Marino 	pos += ETH_ALEN;
34883ff40c12SJohn Marino 	os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
34893ff40c12SJohn Marino 	pos += ETH_ALEN;
34903ff40c12SJohn Marino 	WPA_PUT_LE16(pos, status);
34913ff40c12SJohn Marino 	pos += 2;
3492*a1157835SDaniel Fojt 	if (resp_ies)
34933ff40c12SJohn Marino 		os_memcpy(pos, resp_ies, resp_ies_len);
34943ff40c12SJohn Marino 
34953ff40c12SJohn Marino 	wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
34963ff40c12SJohn Marino 			sizeof(*frame) + rlen);
34973ff40c12SJohn Marino 	os_free(frame);
34983ff40c12SJohn Marino 
34993ff40c12SJohn Marino 	return 0;
35003ff40c12SJohn Marino }
35013ff40c12SJohn Marino 
35023ff40c12SJohn Marino 
wpa_ft_rrb_build_r0(const u8 * key,const size_t key_len,const struct tlv_list * tlvs,const struct wpa_ft_pmk_r0_sa * pmk_r0,const u8 * r1kh_id,const u8 * s1kh_id,const struct tlv_list * tlv_auth,const u8 * src_addr,u8 type,u8 ** packet,size_t * packet_len)3503*a1157835SDaniel Fojt static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
3504*a1157835SDaniel Fojt 			       const struct tlv_list *tlvs,
3505*a1157835SDaniel Fojt 			       const struct wpa_ft_pmk_r0_sa *pmk_r0,
3506*a1157835SDaniel Fojt 			       const u8 *r1kh_id, const u8 *s1kh_id,
3507*a1157835SDaniel Fojt 			       const struct tlv_list *tlv_auth,
3508*a1157835SDaniel Fojt 			       const u8 *src_addr, u8 type,
3509*a1157835SDaniel Fojt 			       u8 **packet, size_t *packet_len)
3510*a1157835SDaniel Fojt {
3511*a1157835SDaniel Fojt 	u8 pmk_r1[PMK_LEN_MAX];
3512*a1157835SDaniel Fojt 	size_t pmk_r1_len = pmk_r0->pmk_r0_len;
3513*a1157835SDaniel Fojt 	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
3514*a1157835SDaniel Fojt 	u8 f_pairwise[sizeof(le16)];
3515*a1157835SDaniel Fojt 	u8 f_expires_in[sizeof(le16)];
3516*a1157835SDaniel Fojt 	u8 f_session_timeout[sizeof(le32)];
3517*a1157835SDaniel Fojt 	int expires_in;
3518*a1157835SDaniel Fojt 	int session_timeout;
3519*a1157835SDaniel Fojt 	struct os_reltime now;
3520*a1157835SDaniel Fojt 	int ret;
3521*a1157835SDaniel Fojt 	struct tlv_list sess_tlv[] = {
3522*a1157835SDaniel Fojt 		{ .type = FT_RRB_PMK_R1, .len = pmk_r1_len,
3523*a1157835SDaniel Fojt 		  .data = pmk_r1 },
3524*a1157835SDaniel Fojt 		{ .type = FT_RRB_PMK_R1_NAME, .len = sizeof(pmk_r1_name),
3525*a1157835SDaniel Fojt 		  .data = pmk_r1_name },
3526*a1157835SDaniel Fojt 		{ .type = FT_RRB_PAIRWISE, .len = sizeof(f_pairwise),
3527*a1157835SDaniel Fojt 		  .data = f_pairwise },
3528*a1157835SDaniel Fojt 		{ .type = FT_RRB_EXPIRES_IN, .len = sizeof(f_expires_in),
3529*a1157835SDaniel Fojt 		  .data = f_expires_in },
3530*a1157835SDaniel Fojt 		{ .type = FT_RRB_IDENTITY, .len = pmk_r0->identity_len,
3531*a1157835SDaniel Fojt 		  .data = pmk_r0->identity },
3532*a1157835SDaniel Fojt 		{ .type = FT_RRB_RADIUS_CUI, .len = pmk_r0->radius_cui_len,
3533*a1157835SDaniel Fojt 		  .data = pmk_r0->radius_cui },
3534*a1157835SDaniel Fojt 		{ .type = FT_RRB_SESSION_TIMEOUT,
3535*a1157835SDaniel Fojt 		  .len = sizeof(f_session_timeout),
3536*a1157835SDaniel Fojt 		  .data = f_session_timeout },
3537*a1157835SDaniel Fojt 		{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
3538*a1157835SDaniel Fojt 	};
3539*a1157835SDaniel Fojt 
3540*a1157835SDaniel Fojt 	if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_len,
3541*a1157835SDaniel Fojt 			      pmk_r0->pmk_r0_name, r1kh_id,
3542*a1157835SDaniel Fojt 			      s1kh_id, pmk_r1, pmk_r1_name) < 0)
3543*a1157835SDaniel Fojt 		return -1;
3544*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 (for peer AP)",
3545*a1157835SDaniel Fojt 			pmk_r1, pmk_r1_len);
3546*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name (for peer AP)",
3547*a1157835SDaniel Fojt 		    pmk_r1_name, WPA_PMK_NAME_LEN);
3548*a1157835SDaniel Fojt 	WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
3549*a1157835SDaniel Fojt 
3550*a1157835SDaniel Fojt 	os_get_reltime(&now);
3551*a1157835SDaniel Fojt 	if (pmk_r0->expiration > now.sec)
3552*a1157835SDaniel Fojt 		expires_in = pmk_r0->expiration - now.sec;
3553*a1157835SDaniel Fojt 	else if (pmk_r0->expiration)
3554*a1157835SDaniel Fojt 		expires_in = 1;
3555*a1157835SDaniel Fojt 	else
3556*a1157835SDaniel Fojt 		expires_in = 0;
3557*a1157835SDaniel Fojt 	WPA_PUT_LE16(f_expires_in, expires_in);
3558*a1157835SDaniel Fojt 
3559*a1157835SDaniel Fojt 	if (pmk_r0->session_timeout > now.sec)
3560*a1157835SDaniel Fojt 		session_timeout = pmk_r0->session_timeout - now.sec;
3561*a1157835SDaniel Fojt 	else if (pmk_r0->session_timeout)
3562*a1157835SDaniel Fojt 		session_timeout = 1;
3563*a1157835SDaniel Fojt 	else
3564*a1157835SDaniel Fojt 		session_timeout = 0;
3565*a1157835SDaniel Fojt 	WPA_PUT_LE32(f_session_timeout, session_timeout);
3566*a1157835SDaniel Fojt 
3567*a1157835SDaniel Fojt 	ret = wpa_ft_rrb_build(key, key_len, tlvs, sess_tlv, tlv_auth,
3568*a1157835SDaniel Fojt 			       pmk_r0->vlan, src_addr, type,
3569*a1157835SDaniel Fojt 			       packet, packet_len);
3570*a1157835SDaniel Fojt 
3571*a1157835SDaniel Fojt 	forced_memzero(pmk_r1, sizeof(pmk_r1));
3572*a1157835SDaniel Fojt 
3573*a1157835SDaniel Fojt 	return ret;
3574*a1157835SDaniel Fojt }
3575*a1157835SDaniel Fojt 
3576*a1157835SDaniel Fojt 
wpa_ft_rrb_rx_pull(struct wpa_authenticator * wpa_auth,const u8 * src_addr,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,int no_defer)35773ff40c12SJohn Marino static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
35783ff40c12SJohn Marino 			      const u8 *src_addr,
3579*a1157835SDaniel Fojt 			      const u8 *enc, size_t enc_len,
3580*a1157835SDaniel Fojt 			      const u8 *auth, size_t auth_len,
3581*a1157835SDaniel Fojt 			      int no_defer)
35823ff40c12SJohn Marino {
3583*a1157835SDaniel Fojt 	const char *msgtype = "pull request";
3584*a1157835SDaniel Fojt 	u8 *plain = NULL, *packet = NULL;
3585*a1157835SDaniel Fojt 	size_t plain_len = 0, packet_len = 0;
3586*a1157835SDaniel Fojt 	struct ft_remote_r1kh *r1kh, *r1kh_wildcard;
3587*a1157835SDaniel Fojt 	const u8 *key;
3588*a1157835SDaniel Fojt 	size_t key_len;
3589*a1157835SDaniel Fojt 	int seq_ret;
3590*a1157835SDaniel Fojt 	const u8 *f_nonce, *f_r0kh_id, *f_r1kh_id, *f_s1kh_id, *f_pmk_r0_name;
3591*a1157835SDaniel Fojt 	size_t f_nonce_len, f_r0kh_id_len, f_r1kh_id_len, f_s1kh_id_len;
3592*a1157835SDaniel Fojt 	size_t f_pmk_r0_name_len;
3593*a1157835SDaniel Fojt 	const struct wpa_ft_pmk_r0_sa *r0;
3594*a1157835SDaniel Fojt 	int ret;
3595*a1157835SDaniel Fojt 	struct tlv_list resp[2];
3596*a1157835SDaniel Fojt 	struct tlv_list resp_auth[5];
3597*a1157835SDaniel Fojt 	struct ft_rrb_seq f_seq;
35983ff40c12SJohn Marino 
35993ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
36003ff40c12SJohn Marino 
3601*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, msgtype, -1);
3602*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", f_r0kh_id, f_r0kh_id_len);
36033ff40c12SJohn Marino 
3604*a1157835SDaniel Fojt 	if (wpa_ft_rrb_check_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len)) {
3605*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: R0KH-ID mismatch");
3606*a1157835SDaniel Fojt 		goto out;
36073ff40c12SJohn Marino 	}
36083ff40c12SJohn Marino 
3609*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, msgtype, FT_R1KH_ID_LEN);
3610*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: R1KH-ID=" MACSTR, MAC2STR(f_r1kh_id));
3611*a1157835SDaniel Fojt 
3612*a1157835SDaniel Fojt 	wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh, &r1kh_wildcard);
3613*a1157835SDaniel Fojt 	if (r1kh) {
3614*a1157835SDaniel Fojt 		key = r1kh->key;
3615*a1157835SDaniel Fojt 		key_len = sizeof(r1kh->key);
3616*a1157835SDaniel Fojt 	} else if (r1kh_wildcard) {
3617*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Using wildcard R1KH-ID");
3618*a1157835SDaniel Fojt 		key = r1kh_wildcard->key;
3619*a1157835SDaniel Fojt 		key_len = sizeof(r1kh_wildcard->key);
3620*a1157835SDaniel Fojt 	} else {
3621*a1157835SDaniel Fojt 		goto out;
36223ff40c12SJohn Marino 	}
36233ff40c12SJohn Marino 
3624*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_NONCE, nonce, "pull request", FT_RRB_NONCE_LEN);
3625*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: nonce", f_nonce, f_nonce_len);
36263ff40c12SJohn Marino 
3627*a1157835SDaniel Fojt 	seq_ret = FT_RRB_SEQ_DROP;
3628*a1157835SDaniel Fojt 	if (r1kh)
3629*a1157835SDaniel Fojt 		seq_ret = wpa_ft_rrb_seq_chk(r1kh->seq, src_addr, enc, enc_len,
3630*a1157835SDaniel Fojt 					     auth, auth_len, msgtype, no_defer);
3631*a1157835SDaniel Fojt 	if (!no_defer && r1kh_wildcard &&
3632*a1157835SDaniel Fojt 	    (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) {
3633*a1157835SDaniel Fojt 		/* wildcard: r1kh-id unknown or changed addr -> do a seq req */
3634*a1157835SDaniel Fojt 		seq_ret = FT_RRB_SEQ_DEFER;
36353ff40c12SJohn Marino 	}
36363ff40c12SJohn Marino 
3637*a1157835SDaniel Fojt 	if (seq_ret == FT_RRB_SEQ_DROP)
3638*a1157835SDaniel Fojt 		goto out;
36393ff40c12SJohn Marino 
3640*a1157835SDaniel Fojt 	if (wpa_ft_rrb_decrypt(key, key_len, enc, enc_len, auth, auth_len,
3641*a1157835SDaniel Fojt 			       src_addr, FT_PACKET_R0KH_R1KH_PULL,
3642*a1157835SDaniel Fojt 			       &plain, &plain_len) < 0)
3643*a1157835SDaniel Fojt 		goto out;
3644*a1157835SDaniel Fojt 
3645*a1157835SDaniel Fojt 	if (!r1kh)
3646*a1157835SDaniel Fojt 		r1kh = wpa_ft_rrb_add_r1kh(wpa_auth, r1kh_wildcard, src_addr,
3647*a1157835SDaniel Fojt 					   f_r1kh_id,
3648*a1157835SDaniel Fojt 					   wpa_auth->conf.rkh_pos_timeout);
3649*a1157835SDaniel Fojt 	if (!r1kh)
3650*a1157835SDaniel Fojt 		goto out;
3651*a1157835SDaniel Fojt 
3652*a1157835SDaniel Fojt 	if (seq_ret == FT_RRB_SEQ_DEFER) {
3653*a1157835SDaniel Fojt 		wpa_ft_rrb_seq_req(wpa_auth, r1kh->seq, src_addr, f_r0kh_id,
3654*a1157835SDaniel Fojt 				   f_r0kh_id_len, f_r1kh_id, key, key_len,
3655*a1157835SDaniel Fojt 				   enc, enc_len, auth, auth_len,
3656*a1157835SDaniel Fojt 				   &wpa_ft_rrb_rx_pull);
3657*a1157835SDaniel Fojt 		goto out;
36583ff40c12SJohn Marino 	}
36593ff40c12SJohn Marino 
3660*a1157835SDaniel Fojt 	wpa_ft_rrb_seq_accept(wpa_auth, r1kh->seq, src_addr, auth, auth_len,
3661*a1157835SDaniel Fojt 			      msgtype);
3662*a1157835SDaniel Fojt 	wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh,
3663*a1157835SDaniel Fojt 				  wpa_auth->conf.rkh_pos_timeout);
36643ff40c12SJohn Marino 
3665*a1157835SDaniel Fojt 	RRB_GET(FT_RRB_PMK_R0_NAME, pmk_r0_name, msgtype, WPA_PMK_NAME_LEN);
3666*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", f_pmk_r0_name,
3667*a1157835SDaniel Fojt 		    f_pmk_r0_name_len);
3668*a1157835SDaniel Fojt 
3669*a1157835SDaniel Fojt 	RRB_GET(FT_RRB_S1KH_ID, s1kh_id, msgtype, ETH_ALEN);
3670*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: S1KH-ID=" MACSTR, MAC2STR(f_s1kh_id));
3671*a1157835SDaniel Fojt 
3672*a1157835SDaniel Fojt 	if (wpa_ft_new_seq(r1kh->seq, &f_seq) < 0) {
3673*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Failed to get seq num");
3674*a1157835SDaniel Fojt 		goto out;
3675*a1157835SDaniel Fojt 	}
3676*a1157835SDaniel Fojt 
3677*a1157835SDaniel Fojt 	resp[0].type = FT_RRB_S1KH_ID;
3678*a1157835SDaniel Fojt 	resp[0].len = f_s1kh_id_len;
3679*a1157835SDaniel Fojt 	resp[0].data = f_s1kh_id;
3680*a1157835SDaniel Fojt 	resp[1].type = FT_RRB_LAST_EMPTY;
3681*a1157835SDaniel Fojt 	resp[1].len = 0;
3682*a1157835SDaniel Fojt 	resp[1].data = NULL;
3683*a1157835SDaniel Fojt 
3684*a1157835SDaniel Fojt 	resp_auth[0].type = FT_RRB_NONCE;
3685*a1157835SDaniel Fojt 	resp_auth[0].len = f_nonce_len;
3686*a1157835SDaniel Fojt 	resp_auth[0].data = f_nonce;
3687*a1157835SDaniel Fojt 	resp_auth[1].type = FT_RRB_SEQ;
3688*a1157835SDaniel Fojt 	resp_auth[1].len = sizeof(f_seq);
3689*a1157835SDaniel Fojt 	resp_auth[1].data = (u8 *) &f_seq;
3690*a1157835SDaniel Fojt 	resp_auth[2].type = FT_RRB_R0KH_ID;
3691*a1157835SDaniel Fojt 	resp_auth[2].len = f_r0kh_id_len;
3692*a1157835SDaniel Fojt 	resp_auth[2].data = f_r0kh_id;
3693*a1157835SDaniel Fojt 	resp_auth[3].type = FT_RRB_R1KH_ID;
3694*a1157835SDaniel Fojt 	resp_auth[3].len = f_r1kh_id_len;
3695*a1157835SDaniel Fojt 	resp_auth[3].data = f_r1kh_id;
3696*a1157835SDaniel Fojt 	resp_auth[4].type = FT_RRB_LAST_EMPTY;
3697*a1157835SDaniel Fojt 	resp_auth[4].len = 0;
3698*a1157835SDaniel Fojt 	resp_auth[4].data = NULL;
3699*a1157835SDaniel Fojt 
3700*a1157835SDaniel Fojt 	if (wpa_ft_fetch_pmk_r0(wpa_auth, f_s1kh_id, f_pmk_r0_name, &r0) < 0) {
3701*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: No matching PMK-R0-Name found");
3702*a1157835SDaniel Fojt 		ret = wpa_ft_rrb_build(key, key_len, resp, NULL, resp_auth,
3703*a1157835SDaniel Fojt 				       NULL, wpa_auth->addr,
3704*a1157835SDaniel Fojt 				       FT_PACKET_R0KH_R1KH_RESP,
3705*a1157835SDaniel Fojt 				       &packet, &packet_len);
3706*a1157835SDaniel Fojt 	} else {
3707*a1157835SDaniel Fojt 		ret = wpa_ft_rrb_build_r0(key, key_len, resp, r0, f_r1kh_id,
3708*a1157835SDaniel Fojt 					  f_s1kh_id, resp_auth, wpa_auth->addr,
3709*a1157835SDaniel Fojt 					  FT_PACKET_R0KH_R1KH_RESP,
3710*a1157835SDaniel Fojt 					  &packet, &packet_len);
3711*a1157835SDaniel Fojt 	}
3712*a1157835SDaniel Fojt 
3713*a1157835SDaniel Fojt 	if (!ret)
3714*a1157835SDaniel Fojt 		wpa_ft_rrb_oui_send(wpa_auth, src_addr,
3715*a1157835SDaniel Fojt 				    FT_PACKET_R0KH_R1KH_RESP, packet,
3716*a1157835SDaniel Fojt 				    packet_len);
3717*a1157835SDaniel Fojt 
3718*a1157835SDaniel Fojt out:
3719*a1157835SDaniel Fojt 	os_free(plain);
3720*a1157835SDaniel Fojt 	os_free(packet);
37213ff40c12SJohn Marino 
37223ff40c12SJohn Marino 	return 0;
37233ff40c12SJohn Marino }
37243ff40c12SJohn Marino 
37253ff40c12SJohn Marino 
3726*a1157835SDaniel Fojt /* @returns  0 on success
3727*a1157835SDaniel Fojt  *          -1 on error
3728*a1157835SDaniel Fojt  *          -2 if FR_RRB_PAIRWISE is missing
3729*a1157835SDaniel Fojt  */
wpa_ft_rrb_rx_r1(struct wpa_authenticator * wpa_auth,const u8 * src_addr,u8 type,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,const char * msgtype,u8 * s1kh_id_out,int (* cb)(struct wpa_authenticator * wpa_auth,const u8 * src_addr,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,int no_defer))3730*a1157835SDaniel Fojt static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
3731*a1157835SDaniel Fojt 			    const u8 *src_addr, u8 type,
3732*a1157835SDaniel Fojt 			    const u8 *enc, size_t enc_len,
3733*a1157835SDaniel Fojt 			    const u8 *auth, size_t auth_len,
3734*a1157835SDaniel Fojt 			    const char *msgtype, u8 *s1kh_id_out,
3735*a1157835SDaniel Fojt 			    int (*cb)(struct wpa_authenticator *wpa_auth,
3736*a1157835SDaniel Fojt 				      const u8 *src_addr,
3737*a1157835SDaniel Fojt 				      const u8 *enc, size_t enc_len,
3738*a1157835SDaniel Fojt 				      const u8 *auth, size_t auth_len,
3739*a1157835SDaniel Fojt 				      int no_defer))
3740*a1157835SDaniel Fojt {
3741*a1157835SDaniel Fojt 	u8 *plain = NULL;
3742*a1157835SDaniel Fojt 	size_t plain_len = 0;
3743*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh, *r0kh_wildcard;
3744*a1157835SDaniel Fojt 	const u8 *key;
3745*a1157835SDaniel Fojt 	size_t key_len;
3746*a1157835SDaniel Fojt 	int seq_ret;
3747*a1157835SDaniel Fojt 	const u8 *f_r1kh_id, *f_s1kh_id, *f_r0kh_id;
3748*a1157835SDaniel Fojt 	const u8 *f_pmk_r1_name, *f_pairwise, *f_pmk_r1;
3749*a1157835SDaniel Fojt 	const u8 *f_expires_in;
3750*a1157835SDaniel Fojt 	size_t f_r1kh_id_len, f_s1kh_id_len, f_r0kh_id_len;
3751*a1157835SDaniel Fojt 	const u8 *f_identity, *f_radius_cui;
3752*a1157835SDaniel Fojt 	const u8 *f_session_timeout;
3753*a1157835SDaniel Fojt 	size_t f_pmk_r1_name_len, f_pairwise_len, f_pmk_r1_len;
3754*a1157835SDaniel Fojt 	size_t f_expires_in_len;
3755*a1157835SDaniel Fojt 	size_t f_identity_len, f_radius_cui_len;
3756*a1157835SDaniel Fojt 	size_t f_session_timeout_len;
3757*a1157835SDaniel Fojt 	int pairwise;
3758*a1157835SDaniel Fojt 	int ret = -1;
3759*a1157835SDaniel Fojt 	int expires_in;
3760*a1157835SDaniel Fojt 	int session_timeout;
3761*a1157835SDaniel Fojt 	struct vlan_description vlan;
3762*a1157835SDaniel Fojt 	size_t pmk_r1_len;
3763*a1157835SDaniel Fojt 
3764*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, msgtype, -1);
3765*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", f_r0kh_id, f_r0kh_id_len);
3766*a1157835SDaniel Fojt 
3767*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, msgtype, FT_R1KH_ID_LEN);
3768*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: R1KH-ID=" MACSTR, MAC2STR(f_r1kh_id));
3769*a1157835SDaniel Fojt 
3770*a1157835SDaniel Fojt 	if (wpa_ft_rrb_check_r1kh(wpa_auth, f_r1kh_id)) {
3771*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: R1KH-ID mismatch");
3772*a1157835SDaniel Fojt 		goto out;
3773*a1157835SDaniel Fojt 	}
3774*a1157835SDaniel Fojt 
3775*a1157835SDaniel Fojt 	wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, &r0kh,
3776*a1157835SDaniel Fojt 			       &r0kh_wildcard);
3777*a1157835SDaniel Fojt 	if (r0kh) {
3778*a1157835SDaniel Fojt 		key = r0kh->key;
3779*a1157835SDaniel Fojt 		key_len = sizeof(r0kh->key);
3780*a1157835SDaniel Fojt 	} else if (r0kh_wildcard) {
3781*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Using wildcard R0KH-ID");
3782*a1157835SDaniel Fojt 		key = r0kh_wildcard->key;
3783*a1157835SDaniel Fojt 		key_len = sizeof(r0kh_wildcard->key);
3784*a1157835SDaniel Fojt 	} else {
3785*a1157835SDaniel Fojt 		goto out;
3786*a1157835SDaniel Fojt 	}
3787*a1157835SDaniel Fojt 
3788*a1157835SDaniel Fojt 	seq_ret = FT_RRB_SEQ_DROP;
3789*a1157835SDaniel Fojt 	if (r0kh) {
3790*a1157835SDaniel Fojt 		seq_ret = wpa_ft_rrb_seq_chk(r0kh->seq, src_addr, enc, enc_len,
3791*a1157835SDaniel Fojt 					     auth, auth_len, msgtype,
3792*a1157835SDaniel Fojt 					     cb ? 0 : 1);
3793*a1157835SDaniel Fojt 	}
3794*a1157835SDaniel Fojt 	if (cb && r0kh_wildcard &&
3795*a1157835SDaniel Fojt 	    (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) {
3796*a1157835SDaniel Fojt 		/* wildcard: r0kh-id unknown or changed addr -> do a seq req */
3797*a1157835SDaniel Fojt 		seq_ret = FT_RRB_SEQ_DEFER;
3798*a1157835SDaniel Fojt 	}
3799*a1157835SDaniel Fojt 
3800*a1157835SDaniel Fojt 	if (seq_ret == FT_RRB_SEQ_DROP)
3801*a1157835SDaniel Fojt 		goto out;
3802*a1157835SDaniel Fojt 
3803*a1157835SDaniel Fojt 	if (wpa_ft_rrb_decrypt(key, key_len, enc, enc_len, auth, auth_len,
3804*a1157835SDaniel Fojt 			       src_addr, type, &plain, &plain_len) < 0)
3805*a1157835SDaniel Fojt 		goto out;
3806*a1157835SDaniel Fojt 
3807*a1157835SDaniel Fojt 	if (!r0kh)
3808*a1157835SDaniel Fojt 		r0kh = wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard, src_addr,
3809*a1157835SDaniel Fojt 					   f_r0kh_id, f_r0kh_id_len,
3810*a1157835SDaniel Fojt 					   wpa_auth->conf.rkh_pos_timeout);
3811*a1157835SDaniel Fojt 	if (!r0kh)
3812*a1157835SDaniel Fojt 		goto out;
3813*a1157835SDaniel Fojt 
3814*a1157835SDaniel Fojt 	if (seq_ret == FT_RRB_SEQ_DEFER) {
3815*a1157835SDaniel Fojt 		wpa_ft_rrb_seq_req(wpa_auth, r0kh->seq, src_addr, f_r0kh_id,
3816*a1157835SDaniel Fojt 				   f_r0kh_id_len, f_r1kh_id, key, key_len,
3817*a1157835SDaniel Fojt 				   enc, enc_len, auth, auth_len, cb);
3818*a1157835SDaniel Fojt 		goto out;
3819*a1157835SDaniel Fojt 	}
3820*a1157835SDaniel Fojt 
3821*a1157835SDaniel Fojt 	wpa_ft_rrb_seq_accept(wpa_auth, r0kh->seq, src_addr, auth, auth_len,
3822*a1157835SDaniel Fojt 			      msgtype);
3823*a1157835SDaniel Fojt 	wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh,
3824*a1157835SDaniel Fojt 				  wpa_auth->conf.rkh_pos_timeout);
3825*a1157835SDaniel Fojt 
3826*a1157835SDaniel Fojt 	RRB_GET(FT_RRB_S1KH_ID, s1kh_id, msgtype, ETH_ALEN);
3827*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: S1KH-ID=" MACSTR, MAC2STR(f_s1kh_id));
3828*a1157835SDaniel Fojt 
3829*a1157835SDaniel Fojt 	if (s1kh_id_out)
3830*a1157835SDaniel Fojt 		os_memcpy(s1kh_id_out, f_s1kh_id, ETH_ALEN);
3831*a1157835SDaniel Fojt 
3832*a1157835SDaniel Fojt 	ret = -2;
3833*a1157835SDaniel Fojt 	RRB_GET(FT_RRB_PAIRWISE, pairwise, msgtype, sizeof(le16));
3834*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: pairwise", f_pairwise, f_pairwise_len);
3835*a1157835SDaniel Fojt 
3836*a1157835SDaniel Fojt 	ret = -1;
3837*a1157835SDaniel Fojt 	RRB_GET(FT_RRB_PMK_R1_NAME, pmk_r1_name, msgtype, WPA_PMK_NAME_LEN);
3838*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
3839*a1157835SDaniel Fojt 		    f_pmk_r1_name, WPA_PMK_NAME_LEN);
3840*a1157835SDaniel Fojt 
3841*a1157835SDaniel Fojt 	pmk_r1_len = PMK_LEN;
3842*a1157835SDaniel Fojt 	if (wpa_ft_rrb_get_tlv(plain, plain_len, FT_RRB_PMK_R1, &f_pmk_r1_len,
3843*a1157835SDaniel Fojt 			       &f_pmk_r1) == 0 &&
3844*a1157835SDaniel Fojt 	    (f_pmk_r1_len == PMK_LEN || f_pmk_r1_len == SHA384_MAC_LEN))
3845*a1157835SDaniel Fojt 		pmk_r1_len = f_pmk_r1_len;
3846*a1157835SDaniel Fojt 	RRB_GET(FT_RRB_PMK_R1, pmk_r1, msgtype, pmk_r1_len);
3847*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f_pmk_r1, pmk_r1_len);
3848*a1157835SDaniel Fojt 
3849*a1157835SDaniel Fojt 	pairwise = WPA_GET_LE16(f_pairwise);
3850*a1157835SDaniel Fojt 
3851*a1157835SDaniel Fojt 	RRB_GET_OPTIONAL(FT_RRB_EXPIRES_IN, expires_in, msgtype,
3852*a1157835SDaniel Fojt 			 sizeof(le16));
3853*a1157835SDaniel Fojt 	if (f_expires_in)
3854*a1157835SDaniel Fojt 		expires_in = WPA_GET_LE16(f_expires_in);
3855*a1157835SDaniel Fojt 	else
3856*a1157835SDaniel Fojt 		expires_in = 0;
3857*a1157835SDaniel Fojt 
3858*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: PMK-R1 %s - expires_in=%d", msgtype,
3859*a1157835SDaniel Fojt 		   expires_in);
3860*a1157835SDaniel Fojt 
3861*a1157835SDaniel Fojt 	if (wpa_ft_rrb_get_tlv_vlan(plain, plain_len, &vlan) < 0) {
3862*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Cannot parse vlan");
3863*a1157835SDaniel Fojt 		wpa_ft_rrb_dump(plain, plain_len);
3864*a1157835SDaniel Fojt 		goto out;
3865*a1157835SDaniel Fojt 	}
3866*a1157835SDaniel Fojt 
3867*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: vlan %d%s",
3868*a1157835SDaniel Fojt 		   le_to_host16(vlan.untagged), vlan.tagged[0] ? "+" : "");
3869*a1157835SDaniel Fojt 
3870*a1157835SDaniel Fojt 	RRB_GET_OPTIONAL(FT_RRB_IDENTITY, identity, msgtype, -1);
3871*a1157835SDaniel Fojt 	if (f_identity)
3872*a1157835SDaniel Fojt 		wpa_hexdump_ascii(MSG_DEBUG, "FT: Identity", f_identity,
3873*a1157835SDaniel Fojt 				  f_identity_len);
3874*a1157835SDaniel Fojt 
3875*a1157835SDaniel Fojt 	RRB_GET_OPTIONAL(FT_RRB_RADIUS_CUI, radius_cui, msgtype, -1);
3876*a1157835SDaniel Fojt 	if (f_radius_cui)
3877*a1157835SDaniel Fojt 		wpa_hexdump_ascii(MSG_DEBUG, "FT: CUI", f_radius_cui,
3878*a1157835SDaniel Fojt 				  f_radius_cui_len);
3879*a1157835SDaniel Fojt 
3880*a1157835SDaniel Fojt 	RRB_GET_OPTIONAL(FT_RRB_SESSION_TIMEOUT, session_timeout, msgtype,
3881*a1157835SDaniel Fojt 			 sizeof(le32));
3882*a1157835SDaniel Fojt 	if (f_session_timeout)
3883*a1157835SDaniel Fojt 		session_timeout = WPA_GET_LE32(f_session_timeout);
3884*a1157835SDaniel Fojt 	else
3885*a1157835SDaniel Fojt 		session_timeout = 0;
3886*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: session_timeout %d", session_timeout);
3887*a1157835SDaniel Fojt 
3888*a1157835SDaniel Fojt 	if (wpa_ft_store_pmk_r1(wpa_auth, f_s1kh_id, f_pmk_r1, pmk_r1_len,
3889*a1157835SDaniel Fojt 				f_pmk_r1_name,
3890*a1157835SDaniel Fojt 				pairwise, &vlan, expires_in, session_timeout,
3891*a1157835SDaniel Fojt 				f_identity, f_identity_len, f_radius_cui,
3892*a1157835SDaniel Fojt 				f_radius_cui_len) < 0)
3893*a1157835SDaniel Fojt 		goto out;
3894*a1157835SDaniel Fojt 
3895*a1157835SDaniel Fojt 	ret = 0;
3896*a1157835SDaniel Fojt out:
3897*a1157835SDaniel Fojt 	bin_clear_free(plain, plain_len);
3898*a1157835SDaniel Fojt 
3899*a1157835SDaniel Fojt 	return ret;
3900*a1157835SDaniel Fojt 
3901*a1157835SDaniel Fojt }
3902*a1157835SDaniel Fojt 
3903*a1157835SDaniel Fojt 
ft_finish_pull(struct wpa_state_machine * sm)3904*a1157835SDaniel Fojt static void ft_finish_pull(struct wpa_state_machine *sm)
3905*a1157835SDaniel Fojt {
3906*a1157835SDaniel Fojt 	int res;
3907*a1157835SDaniel Fojt 	u8 *resp_ies;
3908*a1157835SDaniel Fojt 	size_t resp_ies_len;
3909*a1157835SDaniel Fojt 	u16 status;
3910*a1157835SDaniel Fojt 
3911*a1157835SDaniel Fojt 	if (!sm->ft_pending_cb || !sm->ft_pending_req_ies)
3912*a1157835SDaniel Fojt 		return;
3913*a1157835SDaniel Fojt 
3914*a1157835SDaniel Fojt 	res = wpa_ft_process_auth_req(sm, wpabuf_head(sm->ft_pending_req_ies),
3915*a1157835SDaniel Fojt 				      wpabuf_len(sm->ft_pending_req_ies),
3916*a1157835SDaniel Fojt 				      &resp_ies, &resp_ies_len);
3917*a1157835SDaniel Fojt 	if (res < 0) {
3918*a1157835SDaniel Fojt 		/* this loop is broken by ft_pending_pull_left_retries */
3919*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
3920*a1157835SDaniel Fojt 			   "FT: Callback postponed until response is available");
3921*a1157835SDaniel Fojt 		return;
3922*a1157835SDaniel Fojt 	}
3923*a1157835SDaniel Fojt 	wpabuf_free(sm->ft_pending_req_ies);
3924*a1157835SDaniel Fojt 	sm->ft_pending_req_ies = NULL;
3925*a1157835SDaniel Fojt 	status = res;
3926*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR
3927*a1157835SDaniel Fojt 		   " - status %u", MAC2STR(sm->addr), status);
3928*a1157835SDaniel Fojt 
3929*a1157835SDaniel Fojt 	sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr, sm->wpa_auth->addr,
3930*a1157835SDaniel Fojt 			  sm->ft_pending_auth_transaction + 1, status,
3931*a1157835SDaniel Fojt 			  resp_ies, resp_ies_len);
3932*a1157835SDaniel Fojt 	os_free(resp_ies);
3933*a1157835SDaniel Fojt }
3934*a1157835SDaniel Fojt 
3935*a1157835SDaniel Fojt 
3936*a1157835SDaniel Fojt struct ft_get_sta_ctx {
3937*a1157835SDaniel Fojt 	const u8 *nonce;
3938*a1157835SDaniel Fojt 	const u8 *s1kh_id;
3939*a1157835SDaniel Fojt 	struct wpa_state_machine *sm;
3940*a1157835SDaniel Fojt };
3941*a1157835SDaniel Fojt 
3942*a1157835SDaniel Fojt 
ft_get_sta_cb(struct wpa_state_machine * sm,void * ctx)3943*a1157835SDaniel Fojt static int ft_get_sta_cb(struct wpa_state_machine *sm, void *ctx)
3944*a1157835SDaniel Fojt {
3945*a1157835SDaniel Fojt 	struct ft_get_sta_ctx *info = ctx;
3946*a1157835SDaniel Fojt 
3947*a1157835SDaniel Fojt 	if ((info->s1kh_id &&
3948*a1157835SDaniel Fojt 	     os_memcmp(info->s1kh_id, sm->addr, ETH_ALEN) != 0) ||
3949*a1157835SDaniel Fojt 	    os_memcmp(info->nonce, sm->ft_pending_pull_nonce,
3950*a1157835SDaniel Fojt 		      FT_RRB_NONCE_LEN) != 0 ||
3951*a1157835SDaniel Fojt 	    sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
3952*a1157835SDaniel Fojt 		return 0;
3953*a1157835SDaniel Fojt 
3954*a1157835SDaniel Fojt 	info->sm = sm;
3955*a1157835SDaniel Fojt 
3956*a1157835SDaniel Fojt 	return 1;
3957*a1157835SDaniel Fojt }
3958*a1157835SDaniel Fojt 
3959*a1157835SDaniel Fojt 
wpa_ft_rrb_rx_resp(struct wpa_authenticator * wpa_auth,const u8 * src_addr,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,int no_defer)39603ff40c12SJohn Marino static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
39613ff40c12SJohn Marino 			      const u8 *src_addr,
3962*a1157835SDaniel Fojt 			      const u8 *enc, size_t enc_len,
3963*a1157835SDaniel Fojt 			      const u8 *auth, size_t auth_len,
3964*a1157835SDaniel Fojt 			      int no_defer)
39653ff40c12SJohn Marino {
3966*a1157835SDaniel Fojt 	const char *msgtype = "pull response";
3967*a1157835SDaniel Fojt 	int nak, ret = -1;
3968*a1157835SDaniel Fojt 	struct ft_get_sta_ctx ctx;
3969*a1157835SDaniel Fojt 	u8 s1kh_id[ETH_ALEN];
3970*a1157835SDaniel Fojt 	const u8 *f_nonce;
3971*a1157835SDaniel Fojt 	size_t f_nonce_len;
39723ff40c12SJohn Marino 
39733ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
39743ff40c12SJohn Marino 
3975*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_NONCE, nonce, msgtype, FT_RRB_NONCE_LEN);
3976*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: nonce", f_nonce, f_nonce_len);
39773ff40c12SJohn Marino 
3978*a1157835SDaniel Fojt 	os_memset(&ctx, 0, sizeof(ctx));
3979*a1157835SDaniel Fojt 	ctx.nonce = f_nonce;
3980*a1157835SDaniel Fojt 	if (!wpa_auth_for_each_sta(wpa_auth, ft_get_sta_cb, &ctx)) {
3981*a1157835SDaniel Fojt 		/* nonce not found */
3982*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Invalid nonce");
39833ff40c12SJohn Marino 		return -1;
39843ff40c12SJohn Marino 	}
39853ff40c12SJohn Marino 
3986*a1157835SDaniel Fojt 	ret = wpa_ft_rrb_rx_r1(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_RESP,
3987*a1157835SDaniel Fojt 			       enc, enc_len, auth, auth_len, msgtype, s1kh_id,
3988*a1157835SDaniel Fojt 			       no_defer ? NULL : &wpa_ft_rrb_rx_resp);
3989*a1157835SDaniel Fojt 	if (ret == -2) {
3990*a1157835SDaniel Fojt 		ret = 0;
3991*a1157835SDaniel Fojt 		nak = 1;
3992*a1157835SDaniel Fojt 	} else {
3993*a1157835SDaniel Fojt 		nak = 0;
3994*a1157835SDaniel Fojt 	}
3995*a1157835SDaniel Fojt 	if (ret < 0)
39963ff40c12SJohn Marino 		return -1;
3997*a1157835SDaniel Fojt 
3998*a1157835SDaniel Fojt 	ctx.s1kh_id = s1kh_id;
3999*a1157835SDaniel Fojt 	if (wpa_auth_for_each_sta(wpa_auth, ft_get_sta_cb, &ctx)) {
4000*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
4001*a1157835SDaniel Fojt 			   "FT: Response to a pending pull request for " MACSTR,
4002*a1157835SDaniel Fojt 			   MAC2STR(ctx.sm->addr));
4003*a1157835SDaniel Fojt 		eloop_cancel_timeout(wpa_ft_expire_pull, ctx.sm, NULL);
4004*a1157835SDaniel Fojt 		if (nak)
4005*a1157835SDaniel Fojt 			ctx.sm->ft_pending_pull_left_retries = 0;
4006*a1157835SDaniel Fojt 		ft_finish_pull(ctx.sm);
40073ff40c12SJohn Marino 	}
40083ff40c12SJohn Marino 
4009*a1157835SDaniel Fojt out:
4010*a1157835SDaniel Fojt 	return ret;
40113ff40c12SJohn Marino }
40123ff40c12SJohn Marino 
40133ff40c12SJohn Marino 
wpa_ft_rrb_rx_push(struct wpa_authenticator * wpa_auth,const u8 * src_addr,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,int no_defer)40143ff40c12SJohn Marino static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
40153ff40c12SJohn Marino 			      const u8 *src_addr,
4016*a1157835SDaniel Fojt 			      const u8 *enc, size_t enc_len,
4017*a1157835SDaniel Fojt 			      const u8 *auth, size_t auth_len, int no_defer)
40183ff40c12SJohn Marino {
4019*a1157835SDaniel Fojt 	const char *msgtype = "push";
40203ff40c12SJohn Marino 
40213ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
40223ff40c12SJohn Marino 
4023*a1157835SDaniel Fojt 	if (wpa_ft_rrb_rx_r1(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_PUSH,
4024*a1157835SDaniel Fojt 			     enc, enc_len, auth, auth_len, msgtype, NULL,
4025*a1157835SDaniel Fojt 			     no_defer ? NULL : wpa_ft_rrb_rx_push) < 0)
40263ff40c12SJohn Marino 		return -1;
40273ff40c12SJohn Marino 
40283ff40c12SJohn Marino 	return 0;
40293ff40c12SJohn Marino }
40303ff40c12SJohn Marino 
40313ff40c12SJohn Marino 
wpa_ft_rrb_rx_seq(struct wpa_authenticator * wpa_auth,const u8 * src_addr,int type,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,struct ft_remote_seq ** rkh_seq,u8 ** key,size_t * key_len,struct ft_remote_r0kh ** r0kh_out,struct ft_remote_r1kh ** r1kh_out,struct ft_remote_r0kh ** r0kh_wildcard_out,struct ft_remote_r1kh ** r1kh_wildcard_out)4032*a1157835SDaniel Fojt static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth,
4033*a1157835SDaniel Fojt 			     const u8 *src_addr, int type,
4034*a1157835SDaniel Fojt 			     const u8 *enc, size_t enc_len,
4035*a1157835SDaniel Fojt 			     const u8 *auth, size_t auth_len,
4036*a1157835SDaniel Fojt 			     struct ft_remote_seq **rkh_seq,
4037*a1157835SDaniel Fojt 			     u8 **key, size_t *key_len,
4038*a1157835SDaniel Fojt 			     struct ft_remote_r0kh **r0kh_out,
4039*a1157835SDaniel Fojt 			     struct ft_remote_r1kh **r1kh_out,
4040*a1157835SDaniel Fojt 			     struct ft_remote_r0kh **r0kh_wildcard_out,
4041*a1157835SDaniel Fojt 			     struct ft_remote_r1kh **r1kh_wildcard_out)
4042*a1157835SDaniel Fojt {
4043*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh = NULL;
4044*a1157835SDaniel Fojt 	struct ft_remote_r1kh *r1kh = NULL;
4045*a1157835SDaniel Fojt 	const u8 *f_r0kh_id, *f_r1kh_id;
4046*a1157835SDaniel Fojt 	size_t f_r0kh_id_len, f_r1kh_id_len;
4047*a1157835SDaniel Fojt 	int to_r0kh, to_r1kh;
4048*a1157835SDaniel Fojt 	u8 *plain = NULL;
4049*a1157835SDaniel Fojt 	size_t plain_len = 0;
4050*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh_wildcard;
4051*a1157835SDaniel Fojt 	struct ft_remote_r1kh *r1kh_wildcard;
4052*a1157835SDaniel Fojt 
4053*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, "seq", -1);
4054*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, "seq", FT_R1KH_ID_LEN);
4055*a1157835SDaniel Fojt 
4056*a1157835SDaniel Fojt 	to_r0kh = !wpa_ft_rrb_check_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len);
4057*a1157835SDaniel Fojt 	to_r1kh = !wpa_ft_rrb_check_r1kh(wpa_auth, f_r1kh_id);
4058*a1157835SDaniel Fojt 
4059*a1157835SDaniel Fojt 	if (to_r0kh && to_r1kh) {
4060*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: seq - local R0KH-ID and R1KH-ID");
4061*a1157835SDaniel Fojt 		goto out;
4062*a1157835SDaniel Fojt 	}
4063*a1157835SDaniel Fojt 
4064*a1157835SDaniel Fojt 	if (!to_r0kh && !to_r1kh) {
4065*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: seq - remote R0KH-ID and R1KH-ID");
4066*a1157835SDaniel Fojt 		goto out;
4067*a1157835SDaniel Fojt 	}
4068*a1157835SDaniel Fojt 
4069*a1157835SDaniel Fojt 	if (!to_r0kh) {
4070*a1157835SDaniel Fojt 		wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len,
4071*a1157835SDaniel Fojt 				       &r0kh, &r0kh_wildcard);
4072*a1157835SDaniel Fojt 		if (!r0kh_wildcard &&
4073*a1157835SDaniel Fojt 		    (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) {
4074*a1157835SDaniel Fojt 			wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
4075*a1157835SDaniel Fojt 				    f_r0kh_id, f_r0kh_id_len);
4076*a1157835SDaniel Fojt 			goto out;
4077*a1157835SDaniel Fojt 		}
4078*a1157835SDaniel Fojt 		if (r0kh) {
4079*a1157835SDaniel Fojt 			*key = r0kh->key;
4080*a1157835SDaniel Fojt 			*key_len = sizeof(r0kh->key);
4081*a1157835SDaniel Fojt 		} else {
4082*a1157835SDaniel Fojt 			*key = r0kh_wildcard->key;
4083*a1157835SDaniel Fojt 			*key_len = sizeof(r0kh_wildcard->key);
4084*a1157835SDaniel Fojt 		}
4085*a1157835SDaniel Fojt 	}
4086*a1157835SDaniel Fojt 
4087*a1157835SDaniel Fojt 	if (!to_r1kh) {
4088*a1157835SDaniel Fojt 		wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh,
4089*a1157835SDaniel Fojt 				       &r1kh_wildcard);
4090*a1157835SDaniel Fojt 		if (!r1kh_wildcard &&
4091*a1157835SDaniel Fojt 		    (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) {
4092*a1157835SDaniel Fojt 			wpa_hexdump(MSG_DEBUG, "FT: Did not find R1KH-ID",
4093*a1157835SDaniel Fojt 				    f_r1kh_id, FT_R1KH_ID_LEN);
4094*a1157835SDaniel Fojt 			goto out;
4095*a1157835SDaniel Fojt 		}
4096*a1157835SDaniel Fojt 		if (r1kh) {
4097*a1157835SDaniel Fojt 			*key = r1kh->key;
4098*a1157835SDaniel Fojt 			*key_len = sizeof(r1kh->key);
4099*a1157835SDaniel Fojt 		} else {
4100*a1157835SDaniel Fojt 			*key = r1kh_wildcard->key;
4101*a1157835SDaniel Fojt 			*key_len = sizeof(r1kh_wildcard->key);
4102*a1157835SDaniel Fojt 		}
4103*a1157835SDaniel Fojt 	}
4104*a1157835SDaniel Fojt 
4105*a1157835SDaniel Fojt 	if (wpa_ft_rrb_decrypt(*key, *key_len, enc, enc_len, auth, auth_len,
4106*a1157835SDaniel Fojt 			       src_addr, type, &plain, &plain_len) < 0)
4107*a1157835SDaniel Fojt 		goto out;
4108*a1157835SDaniel Fojt 
4109*a1157835SDaniel Fojt 	os_free(plain);
4110*a1157835SDaniel Fojt 
4111*a1157835SDaniel Fojt 	if (!to_r0kh) {
4112*a1157835SDaniel Fojt 		if (!r0kh)
4113*a1157835SDaniel Fojt 			r0kh = wpa_ft_rrb_add_r0kh(wpa_auth, r0kh_wildcard,
4114*a1157835SDaniel Fojt 						   src_addr, f_r0kh_id,
4115*a1157835SDaniel Fojt 						   f_r0kh_id_len,
4116*a1157835SDaniel Fojt 						   ftRRBseqTimeout);
4117*a1157835SDaniel Fojt 		if (!r0kh)
4118*a1157835SDaniel Fojt 			goto out;
4119*a1157835SDaniel Fojt 
4120*a1157835SDaniel Fojt 		wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh, ftRRBseqTimeout);
4121*a1157835SDaniel Fojt 		*rkh_seq = r0kh->seq;
4122*a1157835SDaniel Fojt 		if (r0kh_out)
4123*a1157835SDaniel Fojt 			*r0kh_out = r0kh;
4124*a1157835SDaniel Fojt 		if (r0kh_wildcard_out)
4125*a1157835SDaniel Fojt 			*r0kh_wildcard_out = r0kh_wildcard;
4126*a1157835SDaniel Fojt 	}
4127*a1157835SDaniel Fojt 
4128*a1157835SDaniel Fojt 	if (!to_r1kh) {
4129*a1157835SDaniel Fojt 		if (!r1kh)
4130*a1157835SDaniel Fojt 			r1kh = wpa_ft_rrb_add_r1kh(wpa_auth, r1kh_wildcard,
4131*a1157835SDaniel Fojt 						   src_addr, f_r1kh_id,
4132*a1157835SDaniel Fojt 						   ftRRBseqTimeout);
4133*a1157835SDaniel Fojt 		if (!r1kh)
4134*a1157835SDaniel Fojt 			goto out;
4135*a1157835SDaniel Fojt 
4136*a1157835SDaniel Fojt 		wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh, ftRRBseqTimeout);
4137*a1157835SDaniel Fojt 		*rkh_seq = r1kh->seq;
4138*a1157835SDaniel Fojt 		if (r1kh_out)
4139*a1157835SDaniel Fojt 			*r1kh_out = r1kh;
4140*a1157835SDaniel Fojt 		if (r1kh_wildcard_out)
4141*a1157835SDaniel Fojt 			*r1kh_wildcard_out = r1kh_wildcard;
4142*a1157835SDaniel Fojt 	}
4143*a1157835SDaniel Fojt 
4144*a1157835SDaniel Fojt 	return 0;
4145*a1157835SDaniel Fojt out:
4146*a1157835SDaniel Fojt 	return -1;
4147*a1157835SDaniel Fojt }
4148*a1157835SDaniel Fojt 
4149*a1157835SDaniel Fojt 
wpa_ft_rrb_rx_seq_req(struct wpa_authenticator * wpa_auth,const u8 * src_addr,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,int no_defer)4150*a1157835SDaniel Fojt static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth,
4151*a1157835SDaniel Fojt 				 const u8 *src_addr,
4152*a1157835SDaniel Fojt 				 const u8 *enc, size_t enc_len,
4153*a1157835SDaniel Fojt 				 const u8 *auth, size_t auth_len,
4154*a1157835SDaniel Fojt 				 int no_defer)
4155*a1157835SDaniel Fojt {
4156*a1157835SDaniel Fojt 	int ret = -1;
4157*a1157835SDaniel Fojt 	struct ft_rrb_seq f_seq;
4158*a1157835SDaniel Fojt 	const u8 *f_nonce, *f_r0kh_id, *f_r1kh_id;
4159*a1157835SDaniel Fojt 	size_t f_nonce_len, f_r0kh_id_len, f_r1kh_id_len;
4160*a1157835SDaniel Fojt 	struct ft_remote_seq *rkh_seq = NULL;
4161*a1157835SDaniel Fojt 	u8 *packet = NULL, *key = NULL;
4162*a1157835SDaniel Fojt 	size_t packet_len = 0, key_len = 0;
4163*a1157835SDaniel Fojt 	struct tlv_list seq_resp_auth[5];
4164*a1157835SDaniel Fojt 
4165*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Received sequence number request");
4166*a1157835SDaniel Fojt 
4167*a1157835SDaniel Fojt 	if (wpa_ft_rrb_rx_seq(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_REQ,
4168*a1157835SDaniel Fojt 			      enc, enc_len, auth, auth_len, &rkh_seq, &key,
4169*a1157835SDaniel Fojt 			      &key_len, NULL, NULL, NULL, NULL) < 0)
4170*a1157835SDaniel Fojt 		goto out;
4171*a1157835SDaniel Fojt 
4172*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_NONCE, nonce, "seq request", FT_RRB_NONCE_LEN);
4173*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: seq request - nonce", f_nonce, f_nonce_len);
4174*a1157835SDaniel Fojt 
4175*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_R0KH_ID, r0kh_id, "seq", -1);
4176*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_R1KH_ID, r1kh_id, "seq", FT_R1KH_ID_LEN);
4177*a1157835SDaniel Fojt 
4178*a1157835SDaniel Fojt 	if (wpa_ft_new_seq(rkh_seq, &f_seq) < 0) {
4179*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Failed to get seq num");
4180*a1157835SDaniel Fojt 		goto out;
4181*a1157835SDaniel Fojt 	}
4182*a1157835SDaniel Fojt 
4183*a1157835SDaniel Fojt 	seq_resp_auth[0].type = FT_RRB_NONCE;
4184*a1157835SDaniel Fojt 	seq_resp_auth[0].len = f_nonce_len;
4185*a1157835SDaniel Fojt 	seq_resp_auth[0].data = f_nonce;
4186*a1157835SDaniel Fojt 	seq_resp_auth[1].type = FT_RRB_SEQ;
4187*a1157835SDaniel Fojt 	seq_resp_auth[1].len = sizeof(f_seq);
4188*a1157835SDaniel Fojt 	seq_resp_auth[1].data = (u8 *) &f_seq;
4189*a1157835SDaniel Fojt 	seq_resp_auth[2].type = FT_RRB_R0KH_ID;
4190*a1157835SDaniel Fojt 	seq_resp_auth[2].len = f_r0kh_id_len;
4191*a1157835SDaniel Fojt 	seq_resp_auth[2].data = f_r0kh_id;
4192*a1157835SDaniel Fojt 	seq_resp_auth[3].type = FT_RRB_R1KH_ID;
4193*a1157835SDaniel Fojt 	seq_resp_auth[3].len = FT_R1KH_ID_LEN;
4194*a1157835SDaniel Fojt 	seq_resp_auth[3].data = f_r1kh_id;
4195*a1157835SDaniel Fojt 	seq_resp_auth[4].type = FT_RRB_LAST_EMPTY;
4196*a1157835SDaniel Fojt 	seq_resp_auth[4].len = 0;
4197*a1157835SDaniel Fojt 	seq_resp_auth[4].data = NULL;
4198*a1157835SDaniel Fojt 
4199*a1157835SDaniel Fojt 	if (wpa_ft_rrb_build(key, key_len, NULL, NULL, seq_resp_auth, NULL,
4200*a1157835SDaniel Fojt 			     wpa_auth->addr, FT_PACKET_R0KH_R1KH_SEQ_RESP,
4201*a1157835SDaniel Fojt 			     &packet, &packet_len) < 0)
4202*a1157835SDaniel Fojt 		goto out;
4203*a1157835SDaniel Fojt 
4204*a1157835SDaniel Fojt 	wpa_ft_rrb_oui_send(wpa_auth, src_addr,
4205*a1157835SDaniel Fojt 			    FT_PACKET_R0KH_R1KH_SEQ_RESP, packet,
4206*a1157835SDaniel Fojt 			    packet_len);
4207*a1157835SDaniel Fojt 
4208*a1157835SDaniel Fojt out:
4209*a1157835SDaniel Fojt 	os_free(packet);
4210*a1157835SDaniel Fojt 
4211*a1157835SDaniel Fojt 	return ret;
4212*a1157835SDaniel Fojt }
4213*a1157835SDaniel Fojt 
4214*a1157835SDaniel Fojt 
wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator * wpa_auth,const u8 * src_addr,const u8 * enc,size_t enc_len,const u8 * auth,size_t auth_len,int no_defer)4215*a1157835SDaniel Fojt static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth,
4216*a1157835SDaniel Fojt 				  const u8 *src_addr,
4217*a1157835SDaniel Fojt 				  const u8 *enc, size_t enc_len,
4218*a1157835SDaniel Fojt 				  const u8 *auth, size_t auth_len,
4219*a1157835SDaniel Fojt 				  int no_defer)
4220*a1157835SDaniel Fojt {
4221*a1157835SDaniel Fojt 	u8 *key = NULL;
4222*a1157835SDaniel Fojt 	size_t key_len = 0;
4223*a1157835SDaniel Fojt 	struct ft_remote_r0kh *r0kh = NULL, *r0kh_wildcard = NULL;
4224*a1157835SDaniel Fojt 	struct ft_remote_r1kh *r1kh = NULL, *r1kh_wildcard = NULL;
4225*a1157835SDaniel Fojt 	const u8 *f_nonce, *f_seq;
4226*a1157835SDaniel Fojt 	size_t f_nonce_len, f_seq_len;
4227*a1157835SDaniel Fojt 	struct ft_remote_seq *rkh_seq = NULL;
4228*a1157835SDaniel Fojt 	struct ft_remote_item *item;
4229*a1157835SDaniel Fojt 	struct os_reltime now, now_remote;
4230*a1157835SDaniel Fojt 	int seq_ret, found;
4231*a1157835SDaniel Fojt 	const struct ft_rrb_seq *msg_both;
4232*a1157835SDaniel Fojt 	u32 msg_dom, msg_seq;
4233*a1157835SDaniel Fojt 
4234*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: Received sequence number response");
4235*a1157835SDaniel Fojt 
4236*a1157835SDaniel Fojt 	if (wpa_ft_rrb_rx_seq(wpa_auth, src_addr, FT_PACKET_R0KH_R1KH_SEQ_RESP,
4237*a1157835SDaniel Fojt 			      enc, enc_len, auth, auth_len, &rkh_seq, &key,
4238*a1157835SDaniel Fojt 			      &key_len, &r0kh, &r1kh, &r0kh_wildcard,
4239*a1157835SDaniel Fojt 			      &r1kh_wildcard) < 0)
4240*a1157835SDaniel Fojt 		goto out;
4241*a1157835SDaniel Fojt 
4242*a1157835SDaniel Fojt 	RRB_GET_AUTH(FT_RRB_NONCE, nonce, "seq response", FT_RRB_NONCE_LEN);
4243*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "FT: seq response - nonce", f_nonce,
4244*a1157835SDaniel Fojt 		    f_nonce_len);
4245*a1157835SDaniel Fojt 
4246*a1157835SDaniel Fojt 	found = 0;
4247*a1157835SDaniel Fojt 	dl_list_for_each(item, &rkh_seq->rx.queue, struct ft_remote_item,
4248*a1157835SDaniel Fojt 			 list) {
4249*a1157835SDaniel Fojt 		if (os_memcmp_const(f_nonce, item->nonce,
4250*a1157835SDaniel Fojt 				    FT_RRB_NONCE_LEN) != 0 ||
4251*a1157835SDaniel Fojt 		    os_get_reltime(&now) < 0 ||
4252*a1157835SDaniel Fojt 		    os_reltime_expired(&now, &item->nonce_ts, ftRRBseqTimeout))
4253*a1157835SDaniel Fojt 			continue;
4254*a1157835SDaniel Fojt 
4255*a1157835SDaniel Fojt 		found = 1;
4256*a1157835SDaniel Fojt 		break;
4257*a1157835SDaniel Fojt 	}
4258*a1157835SDaniel Fojt 	if (!found) {
4259*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: seq response - bad nonce");
4260*a1157835SDaniel Fojt 		goto out;
4261*a1157835SDaniel Fojt 	}
4262*a1157835SDaniel Fojt 
4263*a1157835SDaniel Fojt 	if (r0kh) {
4264*a1157835SDaniel Fojt 		wpa_ft_rrb_r0kh_replenish(wpa_auth, r0kh,
4265*a1157835SDaniel Fojt 					  wpa_auth->conf.rkh_pos_timeout);
4266*a1157835SDaniel Fojt 		if (r0kh_wildcard)
4267*a1157835SDaniel Fojt 			os_memcpy(r0kh->addr, src_addr, ETH_ALEN);
4268*a1157835SDaniel Fojt 	}
4269*a1157835SDaniel Fojt 
4270*a1157835SDaniel Fojt 	if (r1kh) {
4271*a1157835SDaniel Fojt 		wpa_ft_rrb_r1kh_replenish(wpa_auth, r1kh,
4272*a1157835SDaniel Fojt 					  wpa_auth->conf.rkh_pos_timeout);
4273*a1157835SDaniel Fojt 		if (r1kh_wildcard)
4274*a1157835SDaniel Fojt 			os_memcpy(r1kh->addr, src_addr, ETH_ALEN);
4275*a1157835SDaniel Fojt 	}
4276*a1157835SDaniel Fojt 
4277*a1157835SDaniel Fojt 	seq_ret = wpa_ft_rrb_seq_chk(rkh_seq, src_addr, enc, enc_len, auth,
4278*a1157835SDaniel Fojt 				     auth_len, "seq response", 1);
4279*a1157835SDaniel Fojt 	if (seq_ret == FT_RRB_SEQ_OK) {
4280*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: seq response - valid seq number");
4281*a1157835SDaniel Fojt 		wpa_ft_rrb_seq_accept(wpa_auth, rkh_seq, src_addr, auth,
4282*a1157835SDaniel Fojt 				      auth_len, "seq response");
4283*a1157835SDaniel Fojt 	} else {
4284*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: seq response - reset seq number");
4285*a1157835SDaniel Fojt 
4286*a1157835SDaniel Fojt 		RRB_GET_AUTH(FT_RRB_SEQ, seq, "seq response",
4287*a1157835SDaniel Fojt 			     sizeof(*msg_both));
4288*a1157835SDaniel Fojt 		msg_both = (const struct ft_rrb_seq *) f_seq;
4289*a1157835SDaniel Fojt 
4290*a1157835SDaniel Fojt 		msg_dom = le_to_host32(msg_both->dom);
4291*a1157835SDaniel Fojt 		msg_seq = le_to_host32(msg_both->seq);
4292*a1157835SDaniel Fojt 		now_remote.sec = le_to_host32(msg_both->ts);
4293*a1157835SDaniel Fojt 		now_remote.usec = 0;
4294*a1157835SDaniel Fojt 
4295*a1157835SDaniel Fojt 		rkh_seq->rx.num_last = 2;
4296*a1157835SDaniel Fojt 		rkh_seq->rx.dom = msg_dom;
4297*a1157835SDaniel Fojt 		rkh_seq->rx.offsetidx = 0;
4298*a1157835SDaniel Fojt 		/* Accept some older, possibly cached packets as well */
4299*a1157835SDaniel Fojt 		rkh_seq->rx.last[0] = msg_seq - FT_REMOTE_SEQ_BACKLOG -
4300*a1157835SDaniel Fojt 			dl_list_len(&rkh_seq->rx.queue);
4301*a1157835SDaniel Fojt 		rkh_seq->rx.last[1] = msg_seq;
4302*a1157835SDaniel Fojt 
4303*a1157835SDaniel Fojt 		/* local time - offset = remote time
4304*a1157835SDaniel Fojt 		 * <=> local time - remote time = offset */
4305*a1157835SDaniel Fojt 		os_reltime_sub(&now, &now_remote, &rkh_seq->rx.time_offset);
4306*a1157835SDaniel Fojt 	}
4307*a1157835SDaniel Fojt 
4308*a1157835SDaniel Fojt 	wpa_ft_rrb_seq_flush(wpa_auth, rkh_seq, 1);
4309*a1157835SDaniel Fojt 
4310*a1157835SDaniel Fojt 	return 0;
4311*a1157835SDaniel Fojt out:
4312*a1157835SDaniel Fojt 	return -1;
4313*a1157835SDaniel Fojt }
4314*a1157835SDaniel Fojt 
4315*a1157835SDaniel Fojt 
wpa_ft_rrb_rx(struct wpa_authenticator * wpa_auth,const u8 * src_addr,const u8 * data,size_t data_len)43163ff40c12SJohn Marino int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
43173ff40c12SJohn Marino 		  const u8 *data, size_t data_len)
43183ff40c12SJohn Marino {
43193ff40c12SJohn Marino 	struct ft_rrb_frame *frame;
43203ff40c12SJohn Marino 	u16 alen;
43213ff40c12SJohn Marino 	const u8 *pos, *end, *start;
43223ff40c12SJohn Marino 	u8 action;
43233ff40c12SJohn Marino 	const u8 *sta_addr, *target_ap_addr;
43243ff40c12SJohn Marino 
43253ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
43263ff40c12SJohn Marino 		   MAC2STR(src_addr));
43273ff40c12SJohn Marino 
43283ff40c12SJohn Marino 	if (data_len < sizeof(*frame)) {
43293ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)",
43303ff40c12SJohn Marino 			   (unsigned long) data_len);
43313ff40c12SJohn Marino 		return -1;
43323ff40c12SJohn Marino 	}
43333ff40c12SJohn Marino 
43343ff40c12SJohn Marino 	pos = data;
43353ff40c12SJohn Marino 	frame = (struct ft_rrb_frame *) pos;
43363ff40c12SJohn Marino 	pos += sizeof(*frame);
43373ff40c12SJohn Marino 
43383ff40c12SJohn Marino 	alen = le_to_host16(frame->action_length);
43393ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d "
43403ff40c12SJohn Marino 		   "action_length=%d ap_address=" MACSTR,
43413ff40c12SJohn Marino 		   frame->frame_type, frame->packet_type, alen,
43423ff40c12SJohn Marino 		   MAC2STR(frame->ap_address));
43433ff40c12SJohn Marino 
43443ff40c12SJohn Marino 	if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) {
43453ff40c12SJohn Marino 		/* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
43463ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with "
43473ff40c12SJohn Marino 			   "unrecognized type %d", frame->frame_type);
43483ff40c12SJohn Marino 		return -1;
43493ff40c12SJohn Marino 	}
43503ff40c12SJohn Marino 
43513ff40c12SJohn Marino 	if (alen > data_len - sizeof(*frame)) {
43523ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action "
43533ff40c12SJohn Marino 			   "frame");
43543ff40c12SJohn Marino 		return -1;
43553ff40c12SJohn Marino 	}
43563ff40c12SJohn Marino 
43573ff40c12SJohn Marino 	wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
43583ff40c12SJohn Marino 
43593ff40c12SJohn Marino 	if (alen < 1 + 1 + 2 * ETH_ALEN) {
43603ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough "
43613ff40c12SJohn Marino 			   "room for Action Frame body); alen=%lu",
43623ff40c12SJohn Marino 			   (unsigned long) alen);
43633ff40c12SJohn Marino 		return -1;
43643ff40c12SJohn Marino 	}
43653ff40c12SJohn Marino 	start = pos;
43663ff40c12SJohn Marino 	end = pos + alen;
43673ff40c12SJohn Marino 
43683ff40c12SJohn Marino 	if (*pos != WLAN_ACTION_FT) {
43693ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category "
43703ff40c12SJohn Marino 			   "%d", *pos);
43713ff40c12SJohn Marino 		return -1;
43723ff40c12SJohn Marino 	}
43733ff40c12SJohn Marino 
43743ff40c12SJohn Marino 	pos++;
43753ff40c12SJohn Marino 	action = *pos++;
43763ff40c12SJohn Marino 	sta_addr = pos;
43773ff40c12SJohn Marino 	pos += ETH_ALEN;
43783ff40c12SJohn Marino 	target_ap_addr = pos;
43793ff40c12SJohn Marino 	pos += ETH_ALEN;
43803ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr="
43813ff40c12SJohn Marino 		   MACSTR " target_ap_addr=" MACSTR,
43823ff40c12SJohn Marino 		   action, MAC2STR(sta_addr), MAC2STR(target_ap_addr));
43833ff40c12SJohn Marino 
43843ff40c12SJohn Marino 	if (frame->packet_type == FT_PACKET_REQUEST) {
43853ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request");
43863ff40c12SJohn Marino 
43873ff40c12SJohn Marino 		if (action != 1) {
43883ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in "
43893ff40c12SJohn Marino 				   "RRB Request", action);
43903ff40c12SJohn Marino 			return -1;
43913ff40c12SJohn Marino 		}
43923ff40c12SJohn Marino 
43933ff40c12SJohn Marino 		if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) {
43943ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "FT: Target AP address in the "
43953ff40c12SJohn Marino 				   "RRB Request does not match with own "
43963ff40c12SJohn Marino 				   "address");
43973ff40c12SJohn Marino 			return -1;
43983ff40c12SJohn Marino 		}
43993ff40c12SJohn Marino 
44003ff40c12SJohn Marino 		if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address,
44013ff40c12SJohn Marino 					  sta_addr, pos, end - pos) < 0)
44023ff40c12SJohn Marino 			return -1;
44033ff40c12SJohn Marino 	} else if (frame->packet_type == FT_PACKET_RESPONSE) {
44043ff40c12SJohn Marino 		u16 status_code;
44053ff40c12SJohn Marino 
44063ff40c12SJohn Marino 		if (end - pos < 2) {
44073ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "FT: Not enough room for status "
44083ff40c12SJohn Marino 				   "code in RRB Response");
44093ff40c12SJohn Marino 			return -1;
44103ff40c12SJohn Marino 		}
44113ff40c12SJohn Marino 		status_code = WPA_GET_LE16(pos);
44123ff40c12SJohn Marino 		pos += 2;
44133ff40c12SJohn Marino 
44143ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
44153ff40c12SJohn Marino 			   "(status_code=%d)", status_code);
44163ff40c12SJohn Marino 
44173ff40c12SJohn Marino 		if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0)
44183ff40c12SJohn Marino 			return -1;
44193ff40c12SJohn Marino 	} else {
44203ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown "
44213ff40c12SJohn Marino 			   "packet_type %d", frame->packet_type);
44223ff40c12SJohn Marino 		return -1;
44233ff40c12SJohn Marino 	}
44243ff40c12SJohn Marino 
4425*a1157835SDaniel Fojt 	if (end > pos) {
4426*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
4427*a1157835SDaniel Fojt 			    pos, end - pos);
4428*a1157835SDaniel Fojt 	}
4429*a1157835SDaniel Fojt 
44303ff40c12SJohn Marino 	return 0;
44313ff40c12SJohn Marino }
44323ff40c12SJohn Marino 
44333ff40c12SJohn Marino 
wpa_ft_rrb_oui_rx(struct wpa_authenticator * wpa_auth,const u8 * src_addr,const u8 * dst_addr,u8 oui_suffix,const u8 * data,size_t data_len)4434*a1157835SDaniel Fojt void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
4435*a1157835SDaniel Fojt 		       const u8 *dst_addr, u8 oui_suffix, const u8 *data,
4436*a1157835SDaniel Fojt 		       size_t data_len)
4437*a1157835SDaniel Fojt {
4438*a1157835SDaniel Fojt 	const u8 *auth, *enc;
4439*a1157835SDaniel Fojt 	size_t alen, elen;
4440*a1157835SDaniel Fojt 	int no_defer = 0;
4441*a1157835SDaniel Fojt 
4442*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
4443*a1157835SDaniel Fojt 		   MACSTR, MAC2STR(src_addr));
4444*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
4445*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
4446*a1157835SDaniel Fojt 
4447*a1157835SDaniel Fojt 	if (is_multicast_ether_addr(src_addr)) {
4448*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
4449*a1157835SDaniel Fojt 			   "FT: RRB-OUI received frame from multicast address "
4450*a1157835SDaniel Fojt 			   MACSTR, MAC2STR(src_addr));
4451*a1157835SDaniel Fojt 		return;
4452*a1157835SDaniel Fojt 	}
4453*a1157835SDaniel Fojt 
4454*a1157835SDaniel Fojt 	if (is_multicast_ether_addr(dst_addr)) {
4455*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
4456*a1157835SDaniel Fojt 			   "FT: RRB-OUI received frame from remote AP " MACSTR
4457*a1157835SDaniel Fojt 			   " to multicast address " MACSTR,
4458*a1157835SDaniel Fojt 			   MAC2STR(src_addr), MAC2STR(dst_addr));
4459*a1157835SDaniel Fojt 		no_defer = 1;
4460*a1157835SDaniel Fojt 	}
4461*a1157835SDaniel Fojt 
4462*a1157835SDaniel Fojt 	if (data_len < sizeof(u16)) {
4463*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
4464*a1157835SDaniel Fojt 		return;
4465*a1157835SDaniel Fojt 	}
4466*a1157835SDaniel Fojt 
4467*a1157835SDaniel Fojt 	alen = WPA_GET_LE16(data);
4468*a1157835SDaniel Fojt 	if (data_len < sizeof(u16) + alen) {
4469*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
4470*a1157835SDaniel Fojt 		return;
4471*a1157835SDaniel Fojt 	}
4472*a1157835SDaniel Fojt 
4473*a1157835SDaniel Fojt 	auth = data + sizeof(u16);
4474*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "FT: Authenticated payload", auth, alen);
4475*a1157835SDaniel Fojt 	enc = data + sizeof(u16) + alen;
4476*a1157835SDaniel Fojt 	elen = data_len - sizeof(u16) - alen;
4477*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "FT: Encrypted payload", enc, elen);
4478*a1157835SDaniel Fojt 
4479*a1157835SDaniel Fojt 	switch (oui_suffix) {
4480*a1157835SDaniel Fojt 	case FT_PACKET_R0KH_R1KH_PULL:
4481*a1157835SDaniel Fojt 		wpa_ft_rrb_rx_pull(wpa_auth, src_addr, enc, elen, auth, alen,
4482*a1157835SDaniel Fojt 				   no_defer);
4483*a1157835SDaniel Fojt 		break;
4484*a1157835SDaniel Fojt 	case FT_PACKET_R0KH_R1KH_RESP:
4485*a1157835SDaniel Fojt 		wpa_ft_rrb_rx_resp(wpa_auth, src_addr, enc, elen, auth, alen,
4486*a1157835SDaniel Fojt 				   no_defer);
4487*a1157835SDaniel Fojt 		break;
4488*a1157835SDaniel Fojt 	case FT_PACKET_R0KH_R1KH_PUSH:
4489*a1157835SDaniel Fojt 		wpa_ft_rrb_rx_push(wpa_auth, src_addr, enc, elen, auth, alen,
4490*a1157835SDaniel Fojt 				   no_defer);
4491*a1157835SDaniel Fojt 		break;
4492*a1157835SDaniel Fojt 	case FT_PACKET_R0KH_R1KH_SEQ_REQ:
4493*a1157835SDaniel Fojt 		wpa_ft_rrb_rx_seq_req(wpa_auth, src_addr, enc, elen, auth, alen,
4494*a1157835SDaniel Fojt 				      no_defer);
4495*a1157835SDaniel Fojt 		break;
4496*a1157835SDaniel Fojt 	case FT_PACKET_R0KH_R1KH_SEQ_RESP:
4497*a1157835SDaniel Fojt 		wpa_ft_rrb_rx_seq_resp(wpa_auth, src_addr, enc, elen, auth,
4498*a1157835SDaniel Fojt 				       alen, no_defer);
4499*a1157835SDaniel Fojt 		break;
4500*a1157835SDaniel Fojt 	}
4501*a1157835SDaniel Fojt }
4502*a1157835SDaniel Fojt 
4503*a1157835SDaniel Fojt 
wpa_ft_generate_pmk_r1(struct wpa_authenticator * wpa_auth,struct wpa_ft_pmk_r0_sa * pmk_r0,struct ft_remote_r1kh * r1kh,const u8 * s1kh_id)4504*a1157835SDaniel Fojt static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
45053ff40c12SJohn Marino 				  struct wpa_ft_pmk_r0_sa *pmk_r0,
45063ff40c12SJohn Marino 				  struct ft_remote_r1kh *r1kh,
4507*a1157835SDaniel Fojt 				  const u8 *s1kh_id)
45083ff40c12SJohn Marino {
4509*a1157835SDaniel Fojt 	u8 *packet;
4510*a1157835SDaniel Fojt 	size_t packet_len;
4511*a1157835SDaniel Fojt 	struct ft_rrb_seq f_seq;
4512*a1157835SDaniel Fojt 	struct tlv_list push[] = {
4513*a1157835SDaniel Fojt 		{ .type = FT_RRB_S1KH_ID, .len = ETH_ALEN,
4514*a1157835SDaniel Fojt 		  .data = s1kh_id },
4515*a1157835SDaniel Fojt 		{ .type = FT_RRB_PMK_R0_NAME, .len = WPA_PMK_NAME_LEN,
4516*a1157835SDaniel Fojt 		  .data = pmk_r0->pmk_r0_name },
4517*a1157835SDaniel Fojt 		{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
4518*a1157835SDaniel Fojt 	};
4519*a1157835SDaniel Fojt 	struct tlv_list push_auth[] = {
4520*a1157835SDaniel Fojt 		{ .type = FT_RRB_SEQ, .len = sizeof(f_seq),
4521*a1157835SDaniel Fojt 		  .data = (u8 *) &f_seq },
4522*a1157835SDaniel Fojt 		{ .type = FT_RRB_R0KH_ID,
4523*a1157835SDaniel Fojt 		  .len = wpa_auth->conf.r0_key_holder_len,
4524*a1157835SDaniel Fojt 		  .data = wpa_auth->conf.r0_key_holder },
4525*a1157835SDaniel Fojt 		{ .type = FT_RRB_R1KH_ID, .len = FT_R1KH_ID_LEN,
4526*a1157835SDaniel Fojt 		  .data = r1kh->id },
4527*a1157835SDaniel Fojt 		{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
4528*a1157835SDaniel Fojt 	};
45293ff40c12SJohn Marino 
4530*a1157835SDaniel Fojt 	if (wpa_ft_new_seq(r1kh->seq, &f_seq) < 0) {
4531*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "FT: Failed to get seq num");
4532*a1157835SDaniel Fojt 		return -1;
4533*a1157835SDaniel Fojt 	}
45343ff40c12SJohn Marino 
4535*a1157835SDaniel Fojt 	if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0,
4536*a1157835SDaniel Fojt 				r1kh->id, s1kh_id, push_auth, wpa_auth->addr,
4537*a1157835SDaniel Fojt 				FT_PACKET_R0KH_R1KH_PUSH,
4538*a1157835SDaniel Fojt 				&packet, &packet_len) < 0)
4539*a1157835SDaniel Fojt 		return -1;
45403ff40c12SJohn Marino 
4541*a1157835SDaniel Fojt 	wpa_ft_rrb_oui_send(wpa_auth, r1kh->addr, FT_PACKET_R0KH_R1KH_PUSH,
4542*a1157835SDaniel Fojt 			    packet, packet_len);
4543*a1157835SDaniel Fojt 
4544*a1157835SDaniel Fojt 	os_free(packet);
4545*a1157835SDaniel Fojt 	return 0;
45463ff40c12SJohn Marino }
45473ff40c12SJohn Marino 
45483ff40c12SJohn Marino 
wpa_ft_push_pmk_r1(struct wpa_authenticator * wpa_auth,const u8 * addr)45493ff40c12SJohn Marino void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
45503ff40c12SJohn Marino {
4551*a1157835SDaniel Fojt 	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
4552*a1157835SDaniel Fojt 	struct wpa_ft_pmk_r0_sa *r0, *r0found = NULL;
45533ff40c12SJohn Marino 	struct ft_remote_r1kh *r1kh;
45543ff40c12SJohn Marino 
45553ff40c12SJohn Marino 	if (!wpa_auth->conf.pmk_r1_push)
45563ff40c12SJohn Marino 		return;
4557*a1157835SDaniel Fojt 	if (!wpa_auth->conf.r1kh_list)
4558*a1157835SDaniel Fojt 		return;
45593ff40c12SJohn Marino 
4560*a1157835SDaniel Fojt 	dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) {
4561*a1157835SDaniel Fojt 		if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0) {
4562*a1157835SDaniel Fojt 			r0found = r0;
45633ff40c12SJohn Marino 			break;
4564*a1157835SDaniel Fojt 		}
45653ff40c12SJohn Marino 	}
45663ff40c12SJohn Marino 
4567*a1157835SDaniel Fojt 	r0 = r0found;
45683ff40c12SJohn Marino 	if (r0 == NULL || r0->pmk_r1_pushed)
45693ff40c12SJohn Marino 		return;
45703ff40c12SJohn Marino 	r0->pmk_r1_pushed = 1;
45713ff40c12SJohn Marino 
45723ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
45733ff40c12SJohn Marino 		   "for STA " MACSTR, MAC2STR(addr));
45743ff40c12SJohn Marino 
4575*a1157835SDaniel Fojt 	for (r1kh = *wpa_auth->conf.r1kh_list; r1kh; r1kh = r1kh->next) {
4576*a1157835SDaniel Fojt 		if (is_zero_ether_addr(r1kh->addr) ||
4577*a1157835SDaniel Fojt 		    is_zero_ether_addr(r1kh->id))
4578*a1157835SDaniel Fojt 			continue;
4579*a1157835SDaniel Fojt 		if (wpa_ft_rrb_init_r1kh_seq(r1kh) < 0)
4580*a1157835SDaniel Fojt 			continue;
4581*a1157835SDaniel Fojt 		wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr);
45823ff40c12SJohn Marino 	}
45833ff40c12SJohn Marino }
45843ff40c12SJohn Marino 
4585*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R_AP */
4586