1 /*
2  * wpa_supplicant - WNM
3  * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "utils/includes.h"
10 
11 #include "utils/common.h"
12 #include "common/ieee802_11_defs.h"
13 #include "common/ieee802_11_common.h"
14 #include "common/wpa_ctrl.h"
15 #include "rsn_supp/wpa.h"
16 #include "wpa_supplicant_i.h"
17 #include "driver_i.h"
18 #include "scan.h"
19 #include "ctrl_iface.h"
20 #include "bss.h"
21 #include "wnm_sta.h"
22 #include "hs20_supplicant.h"
23 
24 #define MAX_TFS_IE_LEN  1024
25 #define WNM_MAX_NEIGHBOR_REPORT 10
26 
27 
28 /* get the TFS IE from driver */
ieee80211_11_get_tfs_ie(struct wpa_supplicant * wpa_s,u8 * buf,u16 * buf_len,enum wnm_oper oper)29 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
30 				   u16 *buf_len, enum wnm_oper oper)
31 {
32 	wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
33 
34 	return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len);
35 }
36 
37 
38 /* set the TFS IE to driver */
ieee80211_11_set_tfs_ie(struct wpa_supplicant * wpa_s,const u8 * addr,const u8 * buf,u16 buf_len,enum wnm_oper oper)39 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
40 				   const u8 *addr, const u8 *buf, u16 buf_len,
41 				   enum wnm_oper oper)
42 {
43 	u16 len = buf_len;
44 
45 	wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
46 
47 	return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len);
48 }
49 
50 
51 /* MLME-SLEEPMODE.request */
ieee802_11_send_wnmsleep_req(struct wpa_supplicant * wpa_s,u8 action,u16 intval,struct wpabuf * tfs_req)52 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
53 				 u8 action, u16 intval, struct wpabuf *tfs_req)
54 {
55 	struct ieee80211_mgmt *mgmt;
56 	int res;
57 	size_t len;
58 	struct wnm_sleep_element *wnmsleep_ie;
59 	u8 *wnmtfs_ie;
60 	u8 wnmsleep_ie_len;
61 	u16 wnmtfs_ie_len;  /* possibly multiple IE(s) */
62 	enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
63 		WNM_SLEEP_TFS_REQ_IE_NONE;
64 
65 	wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request "
66 		   "action=%s to " MACSTR,
67 		   action == 0 ? "enter" : "exit",
68 		   MAC2STR(wpa_s->bssid));
69 
70 	/* WNM-Sleep Mode IE */
71 	wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
72 	wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element));
73 	if (wnmsleep_ie == NULL)
74 		return -1;
75 	wnmsleep_ie->eid = WLAN_EID_WNMSLEEP;
76 	wnmsleep_ie->len = wnmsleep_ie_len - 2;
77 	wnmsleep_ie->action_type = action;
78 	wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT;
79 	wnmsleep_ie->intval = host_to_le16(intval);
80 	wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element",
81 		    (u8 *) wnmsleep_ie, wnmsleep_ie_len);
82 
83 	/* TFS IE(s) */
84 	if (tfs_req) {
85 		wnmtfs_ie_len = wpabuf_len(tfs_req);
86 		wnmtfs_ie = os_malloc(wnmtfs_ie_len);
87 		if (wnmtfs_ie == NULL) {
88 			os_free(wnmsleep_ie);
89 			return -1;
90 		}
91 		os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len);
92 	} else {
93 		wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
94 		if (wnmtfs_ie == NULL) {
95 			os_free(wnmsleep_ie);
96 			return -1;
97 		}
98 		if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
99 					    tfs_oper)) {
100 			wnmtfs_ie_len = 0;
101 			os_free(wnmtfs_ie);
102 			wnmtfs_ie = NULL;
103 		}
104 	}
105 	wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
106 		    (u8 *) wnmtfs_ie, wnmtfs_ie_len);
107 
108 	mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
109 	if (mgmt == NULL) {
110 		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
111 			   "WNM-Sleep Request action frame");
112 		os_free(wnmsleep_ie);
113 		os_free(wnmtfs_ie);
114 		return -1;
115 	}
116 
117 	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
118 	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
119 	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
120 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
121 					   WLAN_FC_STYPE_ACTION);
122 	mgmt->u.action.category = WLAN_ACTION_WNM;
123 	mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ;
124 	mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1;
125 	os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie,
126 		  wnmsleep_ie_len);
127 	/* copy TFS IE here */
128 	if (wnmtfs_ie_len > 0) {
129 		os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
130 			  wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
131 	}
132 
133 	len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
134 		wnmtfs_ie_len;
135 
136 	res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
137 				  wpa_s->own_addr, wpa_s->bssid,
138 				  &mgmt->u.action.category, len, 0);
139 	if (res < 0)
140 		wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
141 			   "(action=%d, intval=%d)", action, intval);
142 	else
143 		wpa_s->wnmsleep_used = 1;
144 
145 	os_free(wnmsleep_ie);
146 	os_free(wnmtfs_ie);
147 	os_free(mgmt);
148 
149 	return res;
150 }
151 
152 
wnm_sleep_mode_enter_success(struct wpa_supplicant * wpa_s,const u8 * tfsresp_ie_start,const u8 * tfsresp_ie_end)153 static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
154 					 const u8 *tfsresp_ie_start,
155 					 const u8 *tfsresp_ie_end)
156 {
157 	wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
158 			 wpa_s->bssid, NULL, NULL);
159 	/* remove GTK/IGTK ?? */
160 
161 	/* set the TFS Resp IE(s) */
162 	if (tfsresp_ie_start && tfsresp_ie_end &&
163 	    tfsresp_ie_end - tfsresp_ie_start >= 0) {
164 		u16 tfsresp_ie_len;
165 		tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) -
166 			tfsresp_ie_start;
167 		wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
168 		/* pass the TFS Resp IE(s) to driver for processing */
169 		if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
170 					    tfsresp_ie_start,
171 					    tfsresp_ie_len,
172 					    WNM_SLEEP_TFS_RESP_IE_SET))
173 			wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
174 	}
175 }
176 
177 
wnm_sleep_mode_exit_success(struct wpa_supplicant * wpa_s,const u8 * frm,u16 key_len_total)178 static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
179 					const u8 *frm, u16 key_len_total)
180 {
181 	u8 *ptr, *end;
182 	u8 gtk_len;
183 
184 	wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM,  wpa_s->bssid,
185 			 NULL, NULL);
186 
187 	/* Install GTK/IGTK */
188 
189 	/* point to key data field */
190 	ptr = (u8 *) frm + 1 + 2;
191 	end = ptr + key_len_total;
192 	wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
193 
194 	if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) {
195 		wpa_msg(wpa_s, MSG_INFO,
196 			"WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled");
197 		return;
198 	}
199 
200 	while (end - ptr > 1) {
201 		if (2 + ptr[1] > end - ptr) {
202 			wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
203 				   "length");
204 			if (end > ptr) {
205 				wpa_hexdump(MSG_DEBUG, "WNM: Remaining data",
206 					    ptr, end - ptr);
207 			}
208 			break;
209 		}
210 		if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
211 			if (ptr[1] < 11 + 5) {
212 				wpa_printf(MSG_DEBUG, "WNM: Too short GTK "
213 					   "subelem");
214 				break;
215 			}
216 			gtk_len = *(ptr + 4);
217 			if (ptr[1] < 11 + gtk_len ||
218 			    gtk_len < 5 || gtk_len > 32) {
219 				wpa_printf(MSG_DEBUG, "WNM: Invalid GTK "
220 					   "subelem");
221 				break;
222 			}
223 			wpa_wnmsleep_install_key(
224 				wpa_s->wpa,
225 				WNM_SLEEP_SUBELEM_GTK,
226 				ptr);
227 			ptr += 13 + gtk_len;
228 #ifdef CONFIG_IEEE80211W
229 		} else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
230 			if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
231 				wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
232 					   "subelem");
233 				break;
234 			}
235 			wpa_wnmsleep_install_key(wpa_s->wpa,
236 						 WNM_SLEEP_SUBELEM_IGTK, ptr);
237 			ptr += 10 + WPA_IGTK_LEN;
238 #endif /* CONFIG_IEEE80211W */
239 		} else
240 			break; /* skip the loop */
241 	}
242 }
243 
244 
ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant * wpa_s,const u8 * frm,int len)245 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
246 					const u8 *frm, int len)
247 {
248 	/*
249 	 * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
250 	 * WNM-Sleep Mode IE | TFS Response IE
251 	 */
252 	const u8 *pos = frm; /* point to payload after the action field */
253 	u16 key_len_total;
254 	struct wnm_sleep_element *wnmsleep_ie = NULL;
255 	/* multiple TFS Resp IE (assuming consecutive) */
256 	const u8 *tfsresp_ie_start = NULL;
257 	const u8 *tfsresp_ie_end = NULL;
258 	size_t left;
259 
260 	if (!wpa_s->wnmsleep_used) {
261 		wpa_printf(MSG_DEBUG,
262 			   "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association");
263 		return;
264 	}
265 
266 	if (len < 3)
267 		return;
268 	key_len_total = WPA_GET_LE16(frm + 1);
269 
270 	wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d",
271 		   frm[0], key_len_total);
272 	left = len - 3;
273 	if (key_len_total > left) {
274 		wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
275 		return;
276 	}
277 	pos += 3 + key_len_total;
278 	while (pos - frm + 1 < len) {
279 		u8 ie_len = *(pos + 1);
280 		if (2 + ie_len > frm + len - pos) {
281 			wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len);
282 			break;
283 		}
284 		wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len);
285 		if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4)
286 			wnmsleep_ie = (struct wnm_sleep_element *) pos;
287 		else if (*pos == WLAN_EID_TFS_RESP) {
288 			if (!tfsresp_ie_start)
289 				tfsresp_ie_start = pos;
290 			tfsresp_ie_end = pos;
291 		} else
292 			wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
293 		pos += ie_len + 2;
294 	}
295 
296 	if (!wnmsleep_ie) {
297 		wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
298 		return;
299 	}
300 
301 	if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
302 	    wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
303 		wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
304 			   "frame (action=%d, intval=%d)",
305 			   wnmsleep_ie->action_type, wnmsleep_ie->intval);
306 		if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) {
307 			wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start,
308 						     tfsresp_ie_end);
309 		} else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
310 			wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total);
311 		}
312 	} else {
313 		wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
314 			   "(action=%d, intval=%d)",
315 			   wnmsleep_ie->action_type, wnmsleep_ie->intval);
316 		if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER)
317 			wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
318 					 wpa_s->bssid, NULL, NULL);
319 		else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT)
320 			wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
321 					 wpa_s->bssid, NULL, NULL);
322 	}
323 }
324 
325 
wnm_deallocate_memory(struct wpa_supplicant * wpa_s)326 void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
327 {
328 	int i;
329 
330 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
331 		os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
332 		os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
333 	}
334 
335 	wpa_s->wnm_num_neighbor_report = 0;
336 	os_free(wpa_s->wnm_neighbor_report_elements);
337 	wpa_s->wnm_neighbor_report_elements = NULL;
338 }
339 
340 
wnm_parse_neighbor_report_elem(struct neighbor_report * rep,u8 id,u8 elen,const u8 * pos)341 static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
342 					   u8 id, u8 elen, const u8 *pos)
343 {
344 	switch (id) {
345 	case WNM_NEIGHBOR_TSF:
346 		if (elen < 2 + 2) {
347 			wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
348 			break;
349 		}
350 		rep->tsf_offset = WPA_GET_LE16(pos);
351 		rep->beacon_int = WPA_GET_LE16(pos + 2);
352 		rep->tsf_present = 1;
353 		break;
354 	case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
355 		if (elen < 2) {
356 			wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
357 				   "country string");
358 			break;
359 		}
360 		os_memcpy(rep->country, pos, 2);
361 		rep->country_present = 1;
362 		break;
363 	case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
364 		if (elen < 1) {
365 			wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
366 				   "candidate");
367 			break;
368 		}
369 		rep->preference = pos[0];
370 		rep->preference_present = 1;
371 		break;
372 	case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
373 		rep->bss_term_tsf = WPA_GET_LE64(pos);
374 		rep->bss_term_dur = WPA_GET_LE16(pos + 8);
375 		rep->bss_term_present = 1;
376 		break;
377 	case WNM_NEIGHBOR_BEARING:
378 		if (elen < 8) {
379 			wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
380 				   "bearing");
381 			break;
382 		}
383 		rep->bearing = WPA_GET_LE16(pos);
384 		rep->distance = WPA_GET_LE32(pos + 2);
385 		rep->rel_height = WPA_GET_LE16(pos + 2 + 4);
386 		rep->bearing_present = 1;
387 		break;
388 	case WNM_NEIGHBOR_MEASUREMENT_PILOT:
389 		if (elen < 1) {
390 			wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
391 				   "pilot");
392 			break;
393 		}
394 		os_free(rep->meas_pilot);
395 		rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
396 		if (rep->meas_pilot == NULL)
397 			break;
398 		rep->meas_pilot->measurement_pilot = pos[0];
399 		rep->meas_pilot->subelem_len = elen - 1;
400 		os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1);
401 		break;
402 	case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
403 		if (elen < 5) {
404 			wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
405 				   "capabilities");
406 			break;
407 		}
408 		os_memcpy(rep->rm_capab, pos, 5);
409 		rep->rm_capab_present = 1;
410 		break;
411 	case WNM_NEIGHBOR_MULTIPLE_BSSID:
412 		if (elen < 1) {
413 			wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
414 			break;
415 		}
416 		os_free(rep->mul_bssid);
417 		rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
418 		if (rep->mul_bssid == NULL)
419 			break;
420 		rep->mul_bssid->max_bssid_indicator = pos[0];
421 		rep->mul_bssid->subelem_len = elen - 1;
422 		os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1);
423 		break;
424 	}
425 }
426 
427 
wnm_nei_get_chan(struct wpa_supplicant * wpa_s,u8 op_class,u8 chan)428 static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
429 {
430 	struct wpa_bss *bss = wpa_s->current_bss;
431 	const char *country = NULL;
432 	int freq;
433 
434 	if (bss) {
435 		const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
436 
437 		if (elem && elem[1] >= 2)
438 			country = (const char *) (elem + 2);
439 	}
440 
441 	freq = ieee80211_chan_to_freq(country, op_class, chan);
442 	if (freq <= 0 && op_class == 0) {
443 		/*
444 		 * Some APs do not advertise correct operating class
445 		 * information. Try to determine the most likely operating
446 		 * frequency based on the channel number.
447 		 */
448 		if (chan >= 1 && chan <= 13)
449 			freq = 2407 + chan * 5;
450 		else if (chan == 14)
451 			freq = 2484;
452 		else if (chan >= 36 && chan <= 169)
453 			freq = 5000 + chan * 5;
454 	}
455 	return freq;
456 }
457 
458 
wnm_parse_neighbor_report(struct wpa_supplicant * wpa_s,const u8 * pos,u8 len,struct neighbor_report * rep)459 static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
460 				      const u8 *pos, u8 len,
461 				      struct neighbor_report *rep)
462 {
463 	u8 left = len;
464 
465 	if (left < 13) {
466 		wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
467 		return;
468 	}
469 
470 	os_memcpy(rep->bssid, pos, ETH_ALEN);
471 	rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN);
472 	rep->regulatory_class = *(pos + 10);
473 	rep->channel_number = *(pos + 11);
474 	rep->phy_type = *(pos + 12);
475 
476 	pos += 13;
477 	left -= 13;
478 
479 	while (left >= 2) {
480 		u8 id, elen;
481 
482 		id = *pos++;
483 		elen = *pos++;
484 		wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen);
485 		left -= 2;
486 		if (elen > left) {
487 			wpa_printf(MSG_DEBUG,
488 				   "WNM: Truncated neighbor report subelement");
489 			break;
490 		}
491 		wnm_parse_neighbor_report_elem(rep, id, elen, pos);
492 		left -= elen;
493 		pos += elen;
494 	}
495 
496 	rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class,
497 				     rep->channel_number);
498 }
499 
500 
501 static struct wpa_bss *
compare_scan_neighbor_results(struct wpa_supplicant * wpa_s)502 compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
503 {
504 
505 	u8 i;
506 	struct wpa_bss *bss = wpa_s->current_bss;
507 	struct wpa_bss *target;
508 
509 	if (!bss)
510 		return 0;
511 
512 	wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
513 		   MAC2STR(wpa_s->bssid), bss->level);
514 
515 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
516 		struct neighbor_report *nei;
517 
518 		nei = &wpa_s->wnm_neighbor_report_elements[i];
519 		if (nei->preference_present && nei->preference == 0) {
520 			wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
521 				   MAC2STR(nei->bssid));
522 			continue;
523 		}
524 
525 		target = wpa_bss_get_bssid(wpa_s, nei->bssid);
526 		if (!target) {
527 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
528 				   " (pref %d) not found in scan results",
529 				   MAC2STR(nei->bssid),
530 				   nei->preference_present ? nei->preference :
531 				   -1);
532 			continue;
533 		}
534 
535 		if (bss->ssid_len != target->ssid_len ||
536 		    os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
537 			/*
538 			 * TODO: Could consider allowing transition to another
539 			 * ESS if PMF was enabled for the association.
540 			 */
541 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
542 				   " (pref %d) in different ESS",
543 				   MAC2STR(nei->bssid),
544 				   nei->preference_present ? nei->preference :
545 				   -1);
546 			continue;
547 		}
548 
549 		if (wpa_s->current_ssid &&
550 		    !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
551 					1)) {
552 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
553 				   " (pref %d) does not match the current network profile",
554 				   MAC2STR(nei->bssid),
555 				   nei->preference_present ? nei->preference :
556 				   -1);
557 			continue;
558 		}
559 
560 		if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
561 			wpa_printf(MSG_DEBUG,
562 				   "MBO: Candidate BSS " MACSTR
563 				   " retry delay is not over yet",
564 				   MAC2STR(nei->bssid));
565 			continue;
566 		}
567 
568 		if (target->level < bss->level && target->level < -80) {
569 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
570 				   " (pref %d) does not have sufficient signal level (%d)",
571 				   MAC2STR(nei->bssid),
572 				   nei->preference_present ? nei->preference :
573 				   -1,
574 				   target->level);
575 			continue;
576 		}
577 
578 		wpa_printf(MSG_DEBUG,
579 			   "WNM: Found an acceptable preferred transition candidate BSS "
580 			   MACSTR " (RSSI %d)",
581 			   MAC2STR(nei->bssid), target->level);
582 		return target;
583 	}
584 
585 	return NULL;
586 }
587 
588 
wpa_bss_ies_eq(struct wpa_bss * a,struct wpa_bss * b,u8 eid)589 static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
590 {
591 	const u8 *ie_a, *ie_b;
592 
593 	if (!a || !b)
594 		return 0;
595 
596 	ie_a = wpa_bss_get_ie(a, eid);
597 	ie_b = wpa_bss_get_ie(b, eid);
598 
599 	if (!ie_a || !ie_b || ie_a[1] != ie_b[1])
600 		return 0;
601 
602 	return os_memcmp(ie_a, ie_b, ie_a[1]) == 0;
603 }
604 
605 
wnm_get_bss_info(struct wpa_supplicant * wpa_s,struct wpa_bss * bss)606 static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
607 {
608 	u32 info = 0;
609 
610 	info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH;
611 
612 	/*
613 	 * Leave the security and key scope bits unset to indicate that the
614 	 * security information is not available.
615 	 */
616 
617 	if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT)
618 		info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
619 	if (bss->caps & WLAN_CAPABILITY_QOS)
620 		info |= NEI_REP_BSSID_INFO_QOS;
621 	if (bss->caps & WLAN_CAPABILITY_APSD)
622 		info |= NEI_REP_BSSID_INFO_APSD;
623 	if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT)
624 		info |= NEI_REP_BSSID_INFO_RM;
625 	if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK)
626 		info |= NEI_REP_BSSID_INFO_DELAYED_BA;
627 	if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK)
628 		info |= NEI_REP_BSSID_INFO_IMM_BA;
629 	if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN))
630 		info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN;
631 	if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP))
632 		info |= NEI_REP_BSSID_INFO_HT;
633 
634 	return info;
635 }
636 
637 
wnm_add_nei_rep(u8 * buf,size_t len,const u8 * bssid,u32 bss_info,u8 op_class,u8 chan,u8 phy_type,u8 pref)638 static int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info,
639 			   u8 op_class, u8 chan, u8 phy_type, u8 pref)
640 {
641 	u8 *pos = buf;
642 
643 	if (len < 18) {
644 		wpa_printf(MSG_DEBUG,
645 			   "WNM: Not enough room for Neighbor Report element");
646 		return -1;
647 	}
648 
649 	*pos++ = WLAN_EID_NEIGHBOR_REPORT;
650 	/* length: 13 for basic neighbor report + 3 for preference subelement */
651 	*pos++ = 16;
652 	os_memcpy(pos, bssid, ETH_ALEN);
653 	pos += ETH_ALEN;
654 	WPA_PUT_LE32(pos, bss_info);
655 	pos += 4;
656 	*pos++ = op_class;
657 	*pos++ = chan;
658 	*pos++ = phy_type;
659 	*pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE;
660 	*pos++ = 1;
661 	*pos++ = pref;
662 	return pos - buf;
663 }
664 
665 
wnm_nei_rep_add_bss(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,u8 * buf,size_t len,u8 pref)666 static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s,
667 			       struct wpa_bss *bss, u8 *buf, size_t len,
668 			       u8 pref)
669 {
670 	const u8 *ie;
671 	u8 op_class, chan;
672 	int sec_chan = 0, vht = 0;
673 	enum phy_type phy_type;
674 	u32 info;
675 	struct ieee80211_ht_operation *ht_oper = NULL;
676 	struct ieee80211_vht_operation *vht_oper = NULL;
677 
678 	ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
679 	if (ie && ie[1] >= 2) {
680 		ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
681 
682 		if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
683 			sec_chan = 1;
684 		else if (ht_oper->ht_param &
685 			 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
686 			sec_chan = -1;
687 	}
688 
689 	ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION);
690 	if (ie && ie[1] >= 1) {
691 		vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
692 
693 		if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ ||
694 		    vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ ||
695 		    vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ)
696 			vht = vht_oper->vht_op_info_chwidth;
697 	}
698 
699 	if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class,
700 					  &chan) == NUM_HOSTAPD_MODES) {
701 		wpa_printf(MSG_DEBUG,
702 			   "WNM: Cannot determine operating class and channel");
703 		return -2;
704 	}
705 
706 	phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL),
707 					  (vht_oper != NULL));
708 	if (phy_type == PHY_TYPE_UNSPECIFIED) {
709 		wpa_printf(MSG_DEBUG,
710 			   "WNM: Cannot determine BSS phy type for Neighbor Report");
711 		return -2;
712 	}
713 
714 	info = wnm_get_bss_info(wpa_s, bss);
715 
716 	return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan,
717 			       phy_type, pref);
718 }
719 
720 
wnm_add_cand_list(struct wpa_supplicant * wpa_s,u8 * buf,size_t len)721 static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
722 {
723 	u8 *pos = buf;
724 	unsigned int i, pref = 255;
725 	struct os_reltime now;
726 	struct wpa_ssid *ssid = wpa_s->current_ssid;
727 
728 	if (!ssid)
729 		return 0;
730 
731 	/*
732 	 * TODO: Define when scan results are no longer valid for the candidate
733 	 * list.
734 	 */
735 	os_get_reltime(&now);
736 	if (os_reltime_expired(&now, &wpa_s->last_scan, 10))
737 		return 0;
738 
739 	wpa_printf(MSG_DEBUG,
740 		   "WNM: Add candidate list to BSS Transition Management Response frame");
741 	for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) {
742 		struct wpa_bss *bss = wpa_s->last_scan_res[i];
743 		int res;
744 
745 		if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) {
746 			res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--);
747 			if (res == -2)
748 				continue; /* could not build entry for BSS */
749 			if (res < 0)
750 				break; /* no more room for candidates */
751 			if (pref == 1)
752 				break;
753 
754 			pos += res;
755 			len -= res;
756 		}
757 	}
758 
759 	wpa_hexdump(MSG_DEBUG,
760 		    "WNM: BSS Transition Management Response candidate list",
761 		    buf, pos - buf);
762 
763 	return pos - buf;
764 }
765 
766 
wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant * wpa_s,u8 dialog_token,enum bss_trans_mgmt_status_code status,u8 delay,const u8 * target_bssid)767 static void wnm_send_bss_transition_mgmt_resp(
768 	struct wpa_supplicant *wpa_s, u8 dialog_token,
769 	enum bss_trans_mgmt_status_code status, u8 delay,
770 	const u8 *target_bssid)
771 {
772 	u8 buf[2000], *pos;
773 	struct ieee80211_mgmt *mgmt;
774 	size_t len;
775 	int res;
776 
777 	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
778 		   "to " MACSTR " dialog_token=%u status=%u delay=%d",
779 		   MAC2STR(wpa_s->bssid), dialog_token, status, delay);
780 	if (!wpa_s->current_bss) {
781 		wpa_printf(MSG_DEBUG,
782 			   "WNM: Current BSS not known - drop response");
783 		return;
784 	}
785 
786 	mgmt = (struct ieee80211_mgmt *) buf;
787 	os_memset(&buf, 0, sizeof(buf));
788 	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
789 	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
790 	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
791 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
792 					   WLAN_FC_STYPE_ACTION);
793 	mgmt->u.action.category = WLAN_ACTION_WNM;
794 	mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
795 	mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
796 	mgmt->u.action.u.bss_tm_resp.status_code = status;
797 	mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
798 	pos = mgmt->u.action.u.bss_tm_resp.variable;
799 	if (target_bssid) {
800 		os_memcpy(pos, target_bssid, ETH_ALEN);
801 		pos += ETH_ALEN;
802 	} else if (status == WNM_BSS_TM_ACCEPT) {
803 		/*
804 		 * P802.11-REVmc clarifies that the Target BSSID field is always
805 		 * present when status code is zero, so use a fake value here if
806 		 * no BSSID is yet known.
807 		 */
808 		os_memset(pos, 0, ETH_ALEN);
809 		pos += ETH_ALEN;
810 	}
811 
812 	if (status == WNM_BSS_TM_ACCEPT)
813 		pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
814 
815 #ifdef CONFIG_MBO
816 	if (status != WNM_BSS_TM_ACCEPT) {
817 		pos += wpas_mbo_ie_bss_trans_reject(
818 			wpa_s, pos, buf + sizeof(buf) - pos,
819 			MBO_TRANSITION_REJECT_REASON_UNSPECIFIED);
820 	}
821 #endif /* CONFIG_MBO */
822 
823 	len = pos - (u8 *) &mgmt->u.action.category;
824 
825 	res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
826 				  wpa_s->own_addr, wpa_s->bssid,
827 				  &mgmt->u.action.category, len, 0);
828 	if (res < 0) {
829 		wpa_printf(MSG_DEBUG,
830 			   "WNM: Failed to send BSS Transition Management Response");
831 	}
832 }
833 
834 
wnm_scan_process(struct wpa_supplicant * wpa_s,int reply_on_fail)835 int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
836 {
837 	struct wpa_bss *bss;
838 	struct wpa_ssid *ssid = wpa_s->current_ssid;
839 	enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
840 
841 	if (!wpa_s->wnm_neighbor_report_elements)
842 		return 0;
843 
844 	if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
845 			      &wpa_s->scan_trigger_time)) {
846 		wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
847 		wnm_deallocate_memory(wpa_s);
848 		return 0;
849 	}
850 
851 	if (!wpa_s->current_bss ||
852 	    os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid,
853 		      ETH_ALEN) != 0) {
854 		wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it");
855 		return 0;
856 	}
857 
858 	/* Compare the Neighbor Report and scan results */
859 	bss = compare_scan_neighbor_results(wpa_s);
860 	if (!bss) {
861 		wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
862 		status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
863 		goto send_bss_resp_fail;
864 	}
865 
866 	/* Associate to the network */
867 	/* Send the BSS Management Response - Accept */
868 	if (wpa_s->wnm_reply) {
869 		wpa_s->wnm_reply = 0;
870 		wnm_send_bss_transition_mgmt_resp(wpa_s,
871 						  wpa_s->wnm_dialog_token,
872 						  WNM_BSS_TM_ACCEPT,
873 						  0, bss->bssid);
874 	}
875 
876 	if (bss == wpa_s->current_bss) {
877 		wpa_printf(MSG_DEBUG,
878 			   "WNM: Already associated with the preferred candidate");
879 		wnm_deallocate_memory(wpa_s);
880 		return 1;
881 	}
882 
883 	wpa_s->reassociate = 1;
884 	wpa_supplicant_connect(wpa_s, bss, ssid);
885 	wnm_deallocate_memory(wpa_s);
886 	return 1;
887 
888 send_bss_resp_fail:
889 	if (!reply_on_fail)
890 		return 0;
891 
892 	/* Send reject response for all the failures */
893 
894 	if (wpa_s->wnm_reply) {
895 		wpa_s->wnm_reply = 0;
896 		wnm_send_bss_transition_mgmt_resp(wpa_s,
897 						  wpa_s->wnm_dialog_token,
898 						  status, 0, NULL);
899 	}
900 	wnm_deallocate_memory(wpa_s);
901 
902 	return 0;
903 }
904 
905 
cand_pref_compar(const void * a,const void * b)906 static int cand_pref_compar(const void *a, const void *b)
907 {
908 	const struct neighbor_report *aa = a;
909 	const struct neighbor_report *bb = b;
910 
911 	if (!aa->preference_present && !bb->preference_present)
912 		return 0;
913 	if (!aa->preference_present)
914 		return 1;
915 	if (!bb->preference_present)
916 		return -1;
917 	if (bb->preference > aa->preference)
918 		return 1;
919 	if (bb->preference < aa->preference)
920 		return -1;
921 	return 0;
922 }
923 
924 
wnm_sort_cand_list(struct wpa_supplicant * wpa_s)925 static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s)
926 {
927 	if (!wpa_s->wnm_neighbor_report_elements)
928 		return;
929 	qsort(wpa_s->wnm_neighbor_report_elements,
930 	      wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report),
931 	      cand_pref_compar);
932 }
933 
934 
wnm_dump_cand_list(struct wpa_supplicant * wpa_s)935 static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
936 {
937 	unsigned int i;
938 
939 	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List");
940 	if (!wpa_s->wnm_neighbor_report_elements)
941 		return;
942 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
943 		struct neighbor_report *nei;
944 
945 		nei = &wpa_s->wnm_neighbor_report_elements[i];
946 		wpa_printf(MSG_DEBUG, "%u: " MACSTR
947 			   " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d",
948 			   i, MAC2STR(nei->bssid), nei->bssid_info,
949 			   nei->regulatory_class,
950 			   nei->channel_number, nei->phy_type,
951 			   nei->preference_present ? nei->preference : -1,
952 			   nei->freq);
953 	}
954 }
955 
956 
chan_supported(struct wpa_supplicant * wpa_s,int freq)957 static int chan_supported(struct wpa_supplicant *wpa_s, int freq)
958 {
959 	unsigned int i;
960 
961 	for (i = 0; i < wpa_s->hw.num_modes; i++) {
962 		struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
963 		int j;
964 
965 		for (j = 0; j < mode->num_channels; j++) {
966 			struct hostapd_channel_data *chan;
967 
968 			chan = &mode->channels[j];
969 			if (chan->freq == freq &&
970 			    !(chan->flag & HOSTAPD_CHAN_DISABLED))
971 				return 1;
972 		}
973 	}
974 
975 	return 0;
976 }
977 
978 
wnm_set_scan_freqs(struct wpa_supplicant * wpa_s)979 static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
980 {
981 	int *freqs;
982 	int num_freqs = 0;
983 	unsigned int i;
984 
985 	if (!wpa_s->wnm_neighbor_report_elements)
986 		return;
987 
988 	if (wpa_s->hw.modes == NULL)
989 		return;
990 
991 	os_free(wpa_s->next_scan_freqs);
992 	wpa_s->next_scan_freqs = NULL;
993 
994 	freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int));
995 	if (freqs == NULL)
996 		return;
997 
998 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
999 		struct neighbor_report *nei;
1000 
1001 		nei = &wpa_s->wnm_neighbor_report_elements[i];
1002 		if (nei->freq <= 0) {
1003 			wpa_printf(MSG_DEBUG,
1004 				   "WNM: Unknown neighbor operating frequency for "
1005 				   MACSTR " - scan all channels",
1006 				   MAC2STR(nei->bssid));
1007 			os_free(freqs);
1008 			return;
1009 		}
1010 		if (chan_supported(wpa_s, nei->freq))
1011 			add_freq(freqs, &num_freqs, nei->freq);
1012 	}
1013 
1014 	if (num_freqs == 0) {
1015 		os_free(freqs);
1016 		return;
1017 	}
1018 
1019 	wpa_printf(MSG_DEBUG,
1020 		   "WNM: Scan %d frequencies based on transition candidate list",
1021 		   num_freqs);
1022 	wpa_s->next_scan_freqs = freqs;
1023 }
1024 
1025 
ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant * wpa_s,const u8 * pos,const u8 * end,int reply)1026 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
1027 					     const u8 *pos, const u8 *end,
1028 					     int reply)
1029 {
1030 	unsigned int beacon_int;
1031 	u8 valid_int;
1032 #ifdef CONFIG_MBO
1033 	const u8 *vendor;
1034 #endif /* CONFIG_MBO */
1035 
1036 	if (end - pos < 5)
1037 		return;
1038 
1039 	if (wpa_s->current_bss)
1040 		beacon_int = wpa_s->current_bss->beacon_int;
1041 	else
1042 		beacon_int = 100; /* best guess */
1043 
1044 	wpa_s->wnm_dialog_token = pos[0];
1045 	wpa_s->wnm_mode = pos[1];
1046 	wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
1047 	valid_int = pos[4];
1048 	wpa_s->wnm_reply = reply;
1049 
1050 	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
1051 		   "dialog_token=%u request_mode=0x%x "
1052 		   "disassoc_timer=%u validity_interval=%u",
1053 		   wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
1054 		   wpa_s->wnm_dissoc_timer, valid_int);
1055 
1056 	pos += 5;
1057 
1058 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
1059 		if (end - pos < 12) {
1060 			wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
1061 			return;
1062 		}
1063 		os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
1064 		pos += 12; /* BSS Termination Duration */
1065 	}
1066 
1067 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
1068 		char url[256];
1069 
1070 		if (end - pos < 1 || 1 + pos[0] > end - pos) {
1071 			wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
1072 				   "Management Request (URL)");
1073 			return;
1074 		}
1075 		os_memcpy(url, pos + 1, pos[0]);
1076 		url[pos[0]] = '\0';
1077 		pos += 1 + pos[0];
1078 
1079 		wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
1080 			wpa_sm_pmf_enabled(wpa_s->wpa),
1081 			wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
1082 	}
1083 
1084 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
1085 		wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
1086 			"Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
1087 		if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) {
1088 			/* TODO: mark current BSS less preferred for
1089 			 * selection */
1090 			wpa_printf(MSG_DEBUG, "Trying to find another BSS");
1091 			wpa_supplicant_req_scan(wpa_s, 0, 0);
1092 		}
1093 	}
1094 
1095 #ifdef CONFIG_MBO
1096 	vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
1097 	if (vendor)
1098 		wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
1099 #endif /* CONFIG_MBO */
1100 
1101 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
1102 		unsigned int valid_ms;
1103 
1104 		wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
1105 		wnm_deallocate_memory(wpa_s);
1106 		wpa_s->wnm_neighbor_report_elements = os_calloc(
1107 			WNM_MAX_NEIGHBOR_REPORT,
1108 			sizeof(struct neighbor_report));
1109 		if (wpa_s->wnm_neighbor_report_elements == NULL)
1110 			return;
1111 
1112 		while (end - pos >= 2 &&
1113 		       wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
1114 		{
1115 			u8 tag = *pos++;
1116 			u8 len = *pos++;
1117 
1118 			wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
1119 				   tag);
1120 			if (len > end - pos) {
1121 				wpa_printf(MSG_DEBUG, "WNM: Truncated request");
1122 				return;
1123 			}
1124 			if (tag == WLAN_EID_NEIGHBOR_REPORT) {
1125 				struct neighbor_report *rep;
1126 				rep = &wpa_s->wnm_neighbor_report_elements[
1127 					wpa_s->wnm_num_neighbor_report];
1128 				wnm_parse_neighbor_report(wpa_s, pos, len, rep);
1129 				wpa_s->wnm_num_neighbor_report++;
1130 			}
1131 
1132 			pos += len;
1133 		}
1134 
1135 		if (!wpa_s->wnm_num_neighbor_report) {
1136 			wpa_printf(MSG_DEBUG,
1137 				   "WNM: Candidate list included bit is set, but no candidates found");
1138 			wnm_send_bss_transition_mgmt_resp(
1139 				wpa_s, wpa_s->wnm_dialog_token,
1140 				WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
1141 				0, NULL);
1142 			return;
1143 		}
1144 
1145 		wnm_sort_cand_list(wpa_s);
1146 		wnm_dump_cand_list(wpa_s);
1147 		valid_ms = valid_int * beacon_int * 128 / 125;
1148 		wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
1149 			   valid_ms);
1150 		os_get_reltime(&wpa_s->wnm_cand_valid_until);
1151 		wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
1152 		wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
1153 		wpa_s->wnm_cand_valid_until.sec +=
1154 			wpa_s->wnm_cand_valid_until.usec / 1000000;
1155 		wpa_s->wnm_cand_valid_until.usec %= 1000000;
1156 		os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
1157 
1158 		if (wpa_s->last_scan_res_used > 0) {
1159 			struct os_reltime now;
1160 
1161 			os_get_reltime(&now);
1162 			if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) {
1163 				wpa_printf(MSG_DEBUG,
1164 					   "WNM: Try to use recent scan results");
1165 				if (wnm_scan_process(wpa_s, 0) > 0)
1166 					return;
1167 				wpa_printf(MSG_DEBUG,
1168 					   "WNM: No match in previous scan results - try a new scan");
1169 			}
1170 		}
1171 
1172 		wnm_set_scan_freqs(wpa_s);
1173 		if (wpa_s->wnm_num_neighbor_report == 1) {
1174 			os_memcpy(wpa_s->next_scan_bssid,
1175 				  wpa_s->wnm_neighbor_report_elements[0].bssid,
1176 				  ETH_ALEN);
1177 			wpa_printf(MSG_DEBUG,
1178 				   "WNM: Scan only for a specific BSSID since there is only a single candidate "
1179 				   MACSTR, MAC2STR(wpa_s->next_scan_bssid));
1180 		}
1181 		wpa_supplicant_req_scan(wpa_s, 0, 0);
1182 	} else if (reply) {
1183 		enum bss_trans_mgmt_status_code status;
1184 		if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
1185 			status = WNM_BSS_TM_ACCEPT;
1186 		else {
1187 			wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
1188 			status = WNM_BSS_TM_REJECT_UNSPECIFIED;
1189 		}
1190 		wnm_send_bss_transition_mgmt_resp(wpa_s,
1191 						  wpa_s->wnm_dialog_token,
1192 						  status, 0, NULL);
1193 	}
1194 }
1195 
1196 
wnm_send_bss_transition_mgmt_query(struct wpa_supplicant * wpa_s,u8 query_reason,int cand_list)1197 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
1198 				       u8 query_reason, int cand_list)
1199 {
1200 	u8 buf[2000], *pos;
1201 	struct ieee80211_mgmt *mgmt;
1202 	size_t len;
1203 	int ret;
1204 
1205 	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
1206 		   MACSTR " query_reason=%u%s",
1207 		   MAC2STR(wpa_s->bssid), query_reason,
1208 		   cand_list ? " candidate list" : "");
1209 
1210 	mgmt = (struct ieee80211_mgmt *) buf;
1211 	os_memset(&buf, 0, sizeof(buf));
1212 	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
1213 	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
1214 	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
1215 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
1216 					   WLAN_FC_STYPE_ACTION);
1217 	mgmt->u.action.category = WLAN_ACTION_WNM;
1218 	mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY;
1219 	mgmt->u.action.u.bss_tm_query.dialog_token = 1;
1220 	mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
1221 	pos = mgmt->u.action.u.bss_tm_query.variable;
1222 
1223 	if (cand_list)
1224 		pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
1225 
1226 	len = pos - (u8 *) &mgmt->u.action.category;
1227 
1228 	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
1229 				  wpa_s->own_addr, wpa_s->bssid,
1230 				  &mgmt->u.action.category, len, 0);
1231 
1232 	return ret;
1233 }
1234 
1235 
ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant * wpa_s,const u8 * sa,const u8 * data,int len)1236 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
1237 					    const u8 *sa, const u8 *data,
1238 					    int len)
1239 {
1240 	const u8 *pos, *end, *next;
1241 	u8 ie, ie_len;
1242 
1243 	pos = data;
1244 	end = data + len;
1245 
1246 	while (end - pos > 1) {
1247 		ie = *pos++;
1248 		ie_len = *pos++;
1249 		wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u",
1250 			   ie, ie_len);
1251 		if (ie_len > end - pos) {
1252 			wpa_printf(MSG_DEBUG, "WNM: Not enough room for "
1253 				   "subelement");
1254 			break;
1255 		}
1256 		next = pos + ie_len;
1257 		if (ie_len < 4) {
1258 			pos = next;
1259 			continue;
1260 		}
1261 		wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u",
1262 			   WPA_GET_BE24(pos), pos[3]);
1263 
1264 #ifdef CONFIG_HS20
1265 		if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
1266 		    WPA_GET_BE24(pos) == OUI_WFA &&
1267 		    pos[3] == HS20_WNM_SUB_REM_NEEDED) {
1268 			/* Subscription Remediation subelement */
1269 			const u8 *ie_end;
1270 			u8 url_len;
1271 			char *url;
1272 			u8 osu_method;
1273 
1274 			wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation "
1275 				   "subelement");
1276 			ie_end = pos + ie_len;
1277 			pos += 4;
1278 			url_len = *pos++;
1279 			if (url_len == 0) {
1280 				wpa_printf(MSG_DEBUG, "WNM: No Server URL included");
1281 				url = NULL;
1282 				osu_method = 1;
1283 			} else {
1284 				if (url_len + 1 > ie_end - pos) {
1285 					wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
1286 						   url_len,
1287 						   (int) (ie_end - pos));
1288 					break;
1289 				}
1290 				url = os_malloc(url_len + 1);
1291 				if (url == NULL)
1292 					break;
1293 				os_memcpy(url, pos, url_len);
1294 				url[url_len] = '\0';
1295 				osu_method = pos[url_len];
1296 			}
1297 			hs20_rx_subscription_remediation(wpa_s, url,
1298 							 osu_method);
1299 			os_free(url);
1300 			pos = next;
1301 			continue;
1302 		}
1303 
1304 		if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 &&
1305 		    WPA_GET_BE24(pos) == OUI_WFA &&
1306 		    pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) {
1307 			const u8 *ie_end;
1308 			u8 url_len;
1309 			char *url;
1310 			u8 code;
1311 			u16 reauth_delay;
1312 
1313 			ie_end = pos + ie_len;
1314 			pos += 4;
1315 			code = *pos++;
1316 			reauth_delay = WPA_GET_LE16(pos);
1317 			pos += 2;
1318 			url_len = *pos++;
1319 			wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication "
1320 				   "Imminent - Reason Code %u   "
1321 				   "Re-Auth Delay %u  URL Length %u",
1322 				   code, reauth_delay, url_len);
1323 			if (url_len > ie_end - pos)
1324 				break;
1325 			url = os_malloc(url_len + 1);
1326 			if (url == NULL)
1327 				break;
1328 			os_memcpy(url, pos, url_len);
1329 			url[url_len] = '\0';
1330 			hs20_rx_deauth_imminent_notice(wpa_s, code,
1331 						       reauth_delay, url);
1332 			os_free(url);
1333 			pos = next;
1334 			continue;
1335 		}
1336 #endif /* CONFIG_HS20 */
1337 
1338 		pos = next;
1339 	}
1340 }
1341 
1342 
ieee802_11_rx_wnm_notif_req(struct wpa_supplicant * wpa_s,const u8 * sa,const u8 * frm,int len)1343 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s,
1344 					const u8 *sa, const u8 *frm, int len)
1345 {
1346 	const u8 *pos, *end;
1347 	u8 dialog_token, type;
1348 
1349 	/* Dialog Token [1] | Type [1] | Subelements */
1350 
1351 	if (len < 2 || sa == NULL)
1352 		return;
1353 	end = frm + len;
1354 	pos = frm;
1355 	dialog_token = *pos++;
1356 	type = *pos++;
1357 
1358 	wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request "
1359 		"(dialog_token %u type %u sa " MACSTR ")",
1360 		dialog_token, type, MAC2STR(sa));
1361 	wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements",
1362 		    pos, end - pos);
1363 
1364 	if (wpa_s->wpa_state != WPA_COMPLETED ||
1365 	    os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
1366 		wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not "
1367 			"from our AP - ignore it");
1368 		return;
1369 	}
1370 
1371 	switch (type) {
1372 	case 1:
1373 		ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos);
1374 		break;
1375 	default:
1376 		wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown "
1377 			"WNM-Notification type %u", type);
1378 		break;
1379 	}
1380 }
1381 
1382 
ieee802_11_rx_wnm_action(struct wpa_supplicant * wpa_s,const struct ieee80211_mgmt * mgmt,size_t len)1383 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
1384 			      const struct ieee80211_mgmt *mgmt, size_t len)
1385 {
1386 	const u8 *pos, *end;
1387 	u8 act;
1388 
1389 	if (len < IEEE80211_HDRLEN + 2)
1390 		return;
1391 
1392 	pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1;
1393 	act = *pos++;
1394 	end = ((const u8 *) mgmt) + len;
1395 
1396 	wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
1397 		   act, MAC2STR(mgmt->sa));
1398 	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
1399 	    os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
1400 		wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
1401 			   "frame");
1402 		return;
1403 	}
1404 
1405 	switch (act) {
1406 	case WNM_BSS_TRANS_MGMT_REQ:
1407 		ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
1408 						 !(mgmt->da[0] & 0x01));
1409 		break;
1410 	case WNM_SLEEP_MODE_RESP:
1411 		ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos);
1412 		break;
1413 	case WNM_NOTIFICATION_REQ:
1414 		ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
1415 		break;
1416 	default:
1417 		wpa_printf(MSG_ERROR, "WNM: Unknown request");
1418 		break;
1419 	}
1420 }
1421