Home | History | Annotate | Line # | Download | only in wpa_supplicant
wnm_sta.c revision 1.6.8.1
      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 "common/ocv.h"
     16 #include "rsn_supp/wpa.h"
     17 #include "config.h"
     18 #include "wpa_supplicant_i.h"
     19 #include "driver_i.h"
     20 #include "scan.h"
     21 #include "ctrl_iface.h"
     22 #include "bss.h"
     23 #include "wnm_sta.h"
     24 #include "notify.h"
     25 #include "hs20_supplicant.h"
     26 
     27 #define MAX_TFS_IE_LEN  1024
     28 #define WNM_MAX_NEIGHBOR_REPORT 10
     29 
     30 #define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */
     31 
     32 /* get the TFS IE from driver */
     33 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
     34 				   u16 *buf_len, enum wnm_oper oper)
     35 {
     36 	wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
     37 
     38 	return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len);
     39 }
     40 
     41 
     42 /* set the TFS IE to driver */
     43 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
     44 				   const u8 *addr, const u8 *buf, u16 buf_len,
     45 				   enum wnm_oper oper)
     46 {
     47 	u16 len = buf_len;
     48 
     49 	wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
     50 
     51 	return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len);
     52 }
     53 
     54 
     55 /* MLME-SLEEPMODE.request */
     56 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
     57 				 u8 action, u16 intval, struct wpabuf *tfs_req)
     58 {
     59 	struct ieee80211_mgmt *mgmt;
     60 	int res;
     61 	size_t len;
     62 	struct wnm_sleep_element *wnmsleep_ie;
     63 	u8 *wnmtfs_ie, *oci_ie;
     64 	u8 wnmsleep_ie_len, oci_ie_len;
     65 	u16 wnmtfs_ie_len;  /* possibly multiple IE(s) */
     66 	enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
     67 		WNM_SLEEP_TFS_REQ_IE_NONE;
     68 
     69 	wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request "
     70 		   "action=%s to " MACSTR,
     71 		   action == 0 ? "enter" : "exit",
     72 		   MAC2STR(wpa_s->bssid));
     73 
     74 	/* WNM-Sleep Mode IE */
     75 	wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
     76 	wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element));
     77 	if (wnmsleep_ie == NULL)
     78 		return -1;
     79 	wnmsleep_ie->eid = WLAN_EID_WNMSLEEP;
     80 	wnmsleep_ie->len = wnmsleep_ie_len - 2;
     81 	wnmsleep_ie->action_type = action;
     82 	wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT;
     83 	wnmsleep_ie->intval = host_to_le16(intval);
     84 	wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element",
     85 		    (u8 *) wnmsleep_ie, wnmsleep_ie_len);
     86 
     87 	/* TFS IE(s) */
     88 	if (tfs_req) {
     89 		wnmtfs_ie_len = wpabuf_len(tfs_req);
     90 		wnmtfs_ie = os_memdup(wpabuf_head(tfs_req), wnmtfs_ie_len);
     91 		if (wnmtfs_ie == NULL) {
     92 			os_free(wnmsleep_ie);
     93 			return -1;
     94 		}
     95 	} else {
     96 		wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
     97 		if (wnmtfs_ie == NULL) {
     98 			os_free(wnmsleep_ie);
     99 			return -1;
    100 		}
    101 		if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
    102 					    tfs_oper)) {
    103 			wnmtfs_ie_len = 0;
    104 			os_free(wnmtfs_ie);
    105 			wnmtfs_ie = NULL;
    106 		}
    107 	}
    108 	wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
    109 		    (u8 *) wnmtfs_ie, wnmtfs_ie_len);
    110 
    111 	oci_ie = NULL;
    112 	oci_ie_len = 0;
    113 #ifdef CONFIG_OCV
    114 	if (action == WNM_SLEEP_MODE_EXIT && wpa_sm_ocv_enabled(wpa_s->wpa)) {
    115 		struct wpa_channel_info ci;
    116 
    117 		if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
    118 			wpa_printf(MSG_WARNING,
    119 				   "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
    120 			os_free(wnmsleep_ie);
    121 			os_free(wnmtfs_ie);
    122 			return -1;
    123 		}
    124 #ifdef CONFIG_TESTING_OPTIONS
    125 		if (wpa_s->oci_freq_override_wnm_sleep) {
    126 			wpa_printf(MSG_INFO,
    127 				   "TEST: Override OCI KDE frequency %d -> %d MHz",
    128 				   ci.frequency,
    129 				   wpa_s->oci_freq_override_wnm_sleep);
    130 			ci.frequency = wpa_s->oci_freq_override_wnm_sleep;
    131 		}
    132 #endif /* CONFIG_TESTING_OPTIONS */
    133 
    134 		oci_ie_len = OCV_OCI_EXTENDED_LEN;
    135 		oci_ie = os_zalloc(oci_ie_len);
    136 		if (!oci_ie) {
    137 			wpa_printf(MSG_WARNING,
    138 				   "Failed to allocate buffer for for OCI element in WNM-Sleep Mode frame");
    139 			os_free(wnmsleep_ie);
    140 			os_free(wnmtfs_ie);
    141 			return -1;
    142 		}
    143 
    144 		if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
    145 			os_free(wnmsleep_ie);
    146 			os_free(wnmtfs_ie);
    147 			os_free(oci_ie);
    148 			return -1;
    149 		}
    150 	}
    151 #endif /* CONFIG_OCV */
    152 
    153 	mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len +
    154 			 oci_ie_len);
    155 	if (mgmt == NULL) {
    156 		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
    157 			   "WNM-Sleep Request action frame");
    158 		os_free(wnmsleep_ie);
    159 		os_free(wnmtfs_ie);
    160 		return -1;
    161 	}
    162 
    163 	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
    164 	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
    165 	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
    166 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    167 					   WLAN_FC_STYPE_ACTION);
    168 	mgmt->u.action.category = WLAN_ACTION_WNM;
    169 	mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ;
    170 	mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1;
    171 	os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie,
    172 		  wnmsleep_ie_len);
    173 	/* copy TFS IE here */
    174 	if (wnmtfs_ie_len > 0) {
    175 		os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
    176 			  wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
    177 	}
    178 
    179 #ifdef CONFIG_OCV
    180 	/* copy OCV OCI here */
    181 	if (oci_ie_len > 0) {
    182 		os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
    183 			  wnmsleep_ie_len + wnmtfs_ie_len, oci_ie, oci_ie_len);
    184 	}
    185 #endif /* CONFIG_OCV */
    186 
    187 	len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
    188 		wnmtfs_ie_len + oci_ie_len;
    189 
    190 	res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
    191 				  wpa_s->own_addr, wpa_s->bssid,
    192 				  &mgmt->u.action.category, len, 0);
    193 	if (res < 0)
    194 		wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
    195 			   "(action=%d, intval=%d)", action, intval);
    196 	else
    197 		wpa_s->wnmsleep_used = 1;
    198 
    199 	os_free(wnmsleep_ie);
    200 	os_free(wnmtfs_ie);
    201 	os_free(oci_ie);
    202 	os_free(mgmt);
    203 
    204 	return res;
    205 }
    206 
    207 
    208 static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
    209 					 const u8 *tfsresp_ie_start,
    210 					 const u8 *tfsresp_ie_end)
    211 {
    212 	wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
    213 			 wpa_s->bssid, NULL, NULL);
    214 	/* remove GTK/IGTK ?? */
    215 
    216 	/* set the TFS Resp IE(s) */
    217 	if (tfsresp_ie_start && tfsresp_ie_end &&
    218 	    tfsresp_ie_end - tfsresp_ie_start >= 0) {
    219 		u16 tfsresp_ie_len;
    220 		tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) -
    221 			tfsresp_ie_start;
    222 		wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
    223 		/* pass the TFS Resp IE(s) to driver for processing */
    224 		if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
    225 					    tfsresp_ie_start,
    226 					    tfsresp_ie_len,
    227 					    WNM_SLEEP_TFS_RESP_IE_SET))
    228 			wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
    229 	}
    230 }
    231 
    232 
    233 static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
    234 					const u8 *frm, u16 key_len_total)
    235 {
    236 	u8 *ptr, *end;
    237 	u8 gtk_len;
    238 
    239 	wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM,  wpa_s->bssid,
    240 			 NULL, NULL);
    241 
    242 	/* Install GTK/IGTK */
    243 
    244 	/* point to key data field */
    245 	ptr = (u8 *) frm + 1 + 2;
    246 	end = ptr + key_len_total;
    247 	wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
    248 
    249 	if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) {
    250 		wpa_msg(wpa_s, MSG_INFO,
    251 			"WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled");
    252 		return;
    253 	}
    254 
    255 	while (end - ptr > 1) {
    256 		if (2 + ptr[1] > end - ptr) {
    257 			wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
    258 				   "length");
    259 			if (end > ptr) {
    260 				wpa_hexdump(MSG_DEBUG, "WNM: Remaining data",
    261 					    ptr, end - ptr);
    262 			}
    263 			break;
    264 		}
    265 		if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
    266 			if (ptr[1] < 11 + 5) {
    267 				wpa_printf(MSG_DEBUG, "WNM: Too short GTK "
    268 					   "subelem");
    269 				break;
    270 			}
    271 			gtk_len = *(ptr + 4);
    272 			if (ptr[1] < 11 + gtk_len ||
    273 			    gtk_len < 5 || gtk_len > 32) {
    274 				wpa_printf(MSG_DEBUG, "WNM: Invalid GTK "
    275 					   "subelem");
    276 				break;
    277 			}
    278 			wpa_wnmsleep_install_key(
    279 				wpa_s->wpa,
    280 				WNM_SLEEP_SUBELEM_GTK,
    281 				ptr);
    282 			ptr += 13 + gtk_len;
    283 		} else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
    284 			if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
    285 				wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
    286 					   "subelem");
    287 				break;
    288 			}
    289 			wpa_wnmsleep_install_key(wpa_s->wpa,
    290 						 WNM_SLEEP_SUBELEM_IGTK, ptr);
    291 			ptr += 10 + WPA_IGTK_LEN;
    292 		} else if (*ptr == WNM_SLEEP_SUBELEM_BIGTK) {
    293 			if (ptr[1] < 2 + 6 + WPA_BIGTK_LEN) {
    294 				wpa_printf(MSG_DEBUG,
    295 					   "WNM: Too short BIGTK subelem");
    296 				break;
    297 			}
    298 			wpa_wnmsleep_install_key(wpa_s->wpa,
    299 						 WNM_SLEEP_SUBELEM_BIGTK, ptr);
    300 			ptr += 10 + WPA_BIGTK_LEN;
    301 		} else
    302 			break; /* skip the loop */
    303 	}
    304 }
    305 
    306 
    307 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
    308 					const u8 *frm, int len)
    309 {
    310 	/*
    311 	 * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
    312 	 * WNM-Sleep Mode IE | TFS Response IE
    313 	 */
    314 	const u8 *pos = frm; /* point to payload after the action field */
    315 	u16 key_len_total;
    316 	struct wnm_sleep_element *wnmsleep_ie = NULL;
    317 	/* multiple TFS Resp IE (assuming consecutive) */
    318 	const u8 *tfsresp_ie_start = NULL;
    319 	const u8 *tfsresp_ie_end = NULL;
    320 #ifdef CONFIG_OCV
    321 	const u8 *oci_ie = NULL;
    322 	u8 oci_ie_len = 0;
    323 #endif /* CONFIG_OCV */
    324 	size_t left;
    325 
    326 	if (!wpa_s->wnmsleep_used) {
    327 		wpa_printf(MSG_DEBUG,
    328 			   "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode operation has not been requested");
    329 		return;
    330 	}
    331 
    332 	if (len < 3)
    333 		return;
    334 	key_len_total = WPA_GET_LE16(frm + 1);
    335 
    336 	wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d",
    337 		   frm[0], key_len_total);
    338 	left = len - 3;
    339 	if (key_len_total > left) {
    340 		wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
    341 		return;
    342 	}
    343 	pos += 3 + key_len_total;
    344 	while (pos - frm + 1 < len) {
    345 		u8 ie_len = *(pos + 1);
    346 		if (2 + ie_len > frm + len - pos) {
    347 			wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len);
    348 			break;
    349 		}
    350 		wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len);
    351 		if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4)
    352 			wnmsleep_ie = (struct wnm_sleep_element *) pos;
    353 		else if (*pos == WLAN_EID_TFS_RESP) {
    354 			if (!tfsresp_ie_start)
    355 				tfsresp_ie_start = pos;
    356 			tfsresp_ie_end = pos;
    357 #ifdef CONFIG_OCV
    358 		} else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
    359 			   pos[2] == WLAN_EID_EXT_OCV_OCI) {
    360 			oci_ie = pos + 3;
    361 			oci_ie_len = ie_len - 1;
    362 #endif /* CONFIG_OCV */
    363 		} else
    364 			wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
    365 		pos += ie_len + 2;
    366 	}
    367 
    368 	if (!wnmsleep_ie) {
    369 		wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
    370 		return;
    371 	}
    372 
    373 #ifdef CONFIG_OCV
    374 	if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
    375 	    wpa_sm_ocv_enabled(wpa_s->wpa)) {
    376 		struct wpa_channel_info ci;
    377 
    378 		if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
    379 			wpa_msg(wpa_s, MSG_WARNING,
    380 				"Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
    381 			return;
    382 		}
    383 
    384 		if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
    385 					 channel_width_to_int(ci.chanwidth),
    386 					 ci.seg1_idx) != OCI_SUCCESS) {
    387 			wpa_msg(wpa_s, MSG_WARNING, "WNM: OCV failed: %s",
    388 				ocv_errorstr);
    389 			return;
    390 		}
    391 	}
    392 #endif /* CONFIG_OCV */
    393 
    394 	wpa_s->wnmsleep_used = 0;
    395 
    396 	if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
    397 	    wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
    398 		wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
    399 			   "frame (action=%d, intval=%d)",
    400 			   wnmsleep_ie->action_type, wnmsleep_ie->intval);
    401 		if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) {
    402 			wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start,
    403 						     tfsresp_ie_end);
    404 		} else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
    405 			wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total);
    406 		}
    407 	} else {
    408 		wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
    409 			   "(action=%d, intval=%d)",
    410 			   wnmsleep_ie->action_type, wnmsleep_ie->intval);
    411 		if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER)
    412 			wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
    413 					 wpa_s->bssid, NULL, NULL);
    414 		else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT)
    415 			wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
    416 					 wpa_s->bssid, NULL, NULL);
    417 	}
    418 }
    419 
    420 
    421 void wnm_btm_reset(struct wpa_supplicant *wpa_s)
    422 {
    423 	int i;
    424 
    425 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
    426 		os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
    427 		os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
    428 	}
    429 
    430 	wpa_s->wnm_num_neighbor_report = 0;
    431 	os_free(wpa_s->wnm_neighbor_report_elements);
    432 	wpa_s->wnm_neighbor_report_elements = NULL;
    433 
    434 	wpa_s->wnm_cand_valid_until.sec = 0;
    435 	wpa_s->wnm_cand_valid_until.usec = 0;
    436 
    437 	wpa_s->wnm_mode = 0;
    438 	wpa_s->wnm_dialog_token = 0;
    439 	wpa_s->wnm_reply = 0;
    440 
    441 #ifdef CONFIG_MBO
    442 	wpa_s->wnm_mbo_trans_reason_present = 0;
    443 	wpa_s->wnm_mbo_transition_reason = 0;
    444 #endif /* CONFIG_MBO */
    445 }
    446 
    447 
    448 static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
    449 					   u8 id, u8 elen, const u8 *pos)
    450 {
    451 	switch (id) {
    452 	case WNM_NEIGHBOR_TSF:
    453 		if (elen < 2 + 2) {
    454 			wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
    455 			break;
    456 		}
    457 		rep->tsf_offset = WPA_GET_LE16(pos);
    458 		rep->beacon_int = WPA_GET_LE16(pos + 2);
    459 		rep->tsf_present = 1;
    460 		break;
    461 	case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
    462 		if (elen < 2) {
    463 			wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
    464 				   "country string");
    465 			break;
    466 		}
    467 		os_memcpy(rep->country, pos, 2);
    468 		rep->country_present = 1;
    469 		break;
    470 	case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
    471 		if (elen < 1) {
    472 			wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
    473 				   "candidate");
    474 			break;
    475 		}
    476 		rep->preference = pos[0];
    477 		rep->preference_present = 1;
    478 		break;
    479 	case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
    480 		if (elen < 10) {
    481 			wpa_printf(MSG_DEBUG,
    482 				   "WNM: Too short BSS termination duration");
    483 			break;
    484 		}
    485 		rep->bss_term_tsf = WPA_GET_LE64(pos);
    486 		rep->bss_term_dur = WPA_GET_LE16(pos + 8);
    487 		rep->bss_term_present = 1;
    488 		break;
    489 	case WNM_NEIGHBOR_BEARING:
    490 		if (elen < 8) {
    491 			wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
    492 				   "bearing");
    493 			break;
    494 		}
    495 		rep->bearing = WPA_GET_LE16(pos);
    496 		rep->distance = WPA_GET_LE32(pos + 2);
    497 		rep->rel_height = WPA_GET_LE16(pos + 2 + 4);
    498 		rep->bearing_present = 1;
    499 		break;
    500 	case WNM_NEIGHBOR_MEASUREMENT_PILOT:
    501 		if (elen < 1) {
    502 			wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
    503 				   "pilot");
    504 			break;
    505 		}
    506 		os_free(rep->meas_pilot);
    507 		rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
    508 		if (rep->meas_pilot == NULL)
    509 			break;
    510 		rep->meas_pilot->measurement_pilot = pos[0];
    511 		rep->meas_pilot->subelem_len = elen - 1;
    512 		os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1);
    513 		break;
    514 	case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
    515 		if (elen < 5) {
    516 			wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
    517 				   "capabilities");
    518 			break;
    519 		}
    520 		os_memcpy(rep->rm_capab, pos, 5);
    521 		rep->rm_capab_present = 1;
    522 		break;
    523 	case WNM_NEIGHBOR_MULTIPLE_BSSID:
    524 		if (elen < 1) {
    525 			wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
    526 			break;
    527 		}
    528 		os_free(rep->mul_bssid);
    529 		rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
    530 		if (rep->mul_bssid == NULL)
    531 			break;
    532 		rep->mul_bssid->max_bssid_indicator = pos[0];
    533 		rep->mul_bssid->subelem_len = elen - 1;
    534 		os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1);
    535 		break;
    536 	default:
    537 		wpa_printf(MSG_DEBUG,
    538 			   "WNM: Unsupported neighbor report subelement id %u",
    539 			   id);
    540 		break;
    541 	}
    542 }
    543 
    544 
    545 static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
    546 {
    547 	struct wpa_bss *bss = wpa_s->current_bss;
    548 	const char *country = NULL;
    549 	int freq;
    550 
    551 	if (bss) {
    552 		const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
    553 
    554 		if (elem && elem[1] >= 2)
    555 			country = (const char *) (elem + 2);
    556 	}
    557 
    558 	freq = ieee80211_chan_to_freq(country, op_class, chan);
    559 	if (freq <= 0 && op_class == 0) {
    560 		/*
    561 		 * Some APs do not advertise correct operating class
    562 		 * information. Try to determine the most likely operating
    563 		 * frequency based on the channel number.
    564 		 */
    565 		if (chan >= 1 && chan <= 13)
    566 			freq = 2407 + chan * 5;
    567 		else if (chan == 14)
    568 			freq = 2484;
    569 		else if (chan >= 36 && chan <= 177)
    570 			freq = 5000 + chan * 5;
    571 	}
    572 	return freq;
    573 }
    574 
    575 
    576 static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
    577 				      const u8 *pos, u8 len,
    578 				      struct neighbor_report *rep)
    579 {
    580 	u8 left = len;
    581 
    582 	if (left < 13) {
    583 		wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
    584 		return;
    585 	}
    586 
    587 	os_memcpy(rep->bssid, pos, ETH_ALEN);
    588 	rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN);
    589 	rep->regulatory_class = *(pos + 10);
    590 	rep->channel_number = *(pos + 11);
    591 	rep->phy_type = *(pos + 12);
    592 
    593 	pos += 13;
    594 	left -= 13;
    595 
    596 	while (left >= 2) {
    597 		u8 id, elen;
    598 
    599 		id = *pos++;
    600 		elen = *pos++;
    601 		wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen);
    602 		left -= 2;
    603 		if (elen > left) {
    604 			wpa_printf(MSG_DEBUG,
    605 				   "WNM: Truncated neighbor report subelement");
    606 			break;
    607 		}
    608 		wnm_parse_neighbor_report_elem(rep, id, elen, pos);
    609 		left -= elen;
    610 		pos += elen;
    611 	}
    612 
    613 	rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class,
    614 				     rep->channel_number);
    615 }
    616 
    617 
    618 static void wnm_clear_acceptable(struct wpa_supplicant *wpa_s)
    619 {
    620 	unsigned int i;
    621 
    622 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++)
    623 		wpa_s->wnm_neighbor_report_elements[i].acceptable = 0;
    624 }
    625 
    626 #ifdef CONFIG_MBO
    627 static struct wpa_bss *
    628 get_mbo_transition_candidate(struct wpa_supplicant *wpa_s,
    629 			     enum mbo_transition_reject_reason *reason)
    630 {
    631 	struct wpa_bss *target = NULL;
    632 	struct wpa_bss_trans_info params;
    633 	struct wpa_bss_candidate_info *info = NULL;
    634 	struct neighbor_report *nei = wpa_s->wnm_neighbor_report_elements;
    635 	u8 *first_candidate_bssid = NULL, *pos;
    636 	unsigned int i;
    637 
    638 	params.mbo_transition_reason = wpa_s->wnm_mbo_transition_reason;
    639 	params.n_candidates = 0;
    640 	params.bssid = os_calloc(wpa_s->wnm_num_neighbor_report, ETH_ALEN);
    641 	if (!params.bssid)
    642 		return NULL;
    643 
    644 	pos = params.bssid;
    645 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; nei++, i++) {
    646 		if (nei->is_first)
    647 			first_candidate_bssid = nei->bssid;
    648 		if (!nei->acceptable)
    649 			continue;
    650 		os_memcpy(pos, nei->bssid, ETH_ALEN);
    651 		pos += ETH_ALEN;
    652 		params.n_candidates++;
    653 	}
    654 
    655 	if (!params.n_candidates)
    656 		goto end;
    657 
    658 	info = wpa_drv_get_bss_trans_status(wpa_s, &params);
    659 	if (!info) {
    660 		/* If failed to get candidate BSS transition status from driver,
    661 		 * get the first acceptable candidate from wpa_supplicant.
    662 		 */
    663 		target = wpa_bss_get_bssid(wpa_s, params.bssid);
    664 		goto end;
    665 	}
    666 
    667 	/* Get the first acceptable candidate from driver */
    668 	for (i = 0; i < info->num; i++) {
    669 		if (info->candidates[i].is_accept) {
    670 			target = wpa_bss_get_bssid(wpa_s,
    671 						   info->candidates[i].bssid);
    672 			goto end;
    673 		}
    674 	}
    675 
    676 	/* If Disassociation Imminent is set and driver rejects all the
    677 	 * candidate select first acceptable candidate which has
    678 	 * rssi > disassoc_imminent_rssi_threshold
    679 	 */
    680 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
    681 		for (i = 0; i < info->num; i++) {
    682 			target = wpa_bss_get_bssid(wpa_s,
    683 						   info->candidates[i].bssid);
    684 			if (target &&
    685 			    (target->level <
    686 			     wpa_s->conf->disassoc_imminent_rssi_threshold))
    687 				continue;
    688 			goto end;
    689 		}
    690 	}
    691 
    692 	/* While sending BTM reject use reason code of the first candidate
    693 	 * received in BTM request frame
    694 	 */
    695 	if (reason) {
    696 		for (i = 0; i < info->num; i++) {
    697 			if (first_candidate_bssid &&
    698 			    ether_addr_equal(first_candidate_bssid,
    699 					     info->candidates[i].bssid)) {
    700 				*reason = info->candidates[i].reject_reason;
    701 				break;
    702 			}
    703 		}
    704 	}
    705 
    706 	target = NULL;
    707 
    708 end:
    709 	os_free(params.bssid);
    710 	if (info) {
    711 		os_free(info->candidates);
    712 		os_free(info);
    713 	}
    714 	return target;
    715 }
    716 #endif /* CONFIG_MBO */
    717 
    718 
    719 static struct wpa_bss * find_better_target(struct wpa_bss *a,
    720 					   struct wpa_bss *b)
    721 {
    722 	if (!a)
    723 		return b;
    724 	if (!b)
    725 		return a;
    726 
    727 	if (a->est_throughput > b->est_throughput) {
    728 		wpa_printf(MSG_DEBUG, "WNM: A is better: " MACSTR
    729 			   " est-tput: %d  B: " MACSTR " est-tput: %d",
    730 			   MAC2STR(a->bssid), a->est_throughput,
    731 			   MAC2STR(b->bssid), b->est_throughput);
    732 		return a;
    733 	}
    734 
    735 	wpa_printf(MSG_DEBUG, "WNM: B is better, A: " MACSTR
    736 		   " est-tput: %d  B: " MACSTR " est-tput: %d",
    737 		   MAC2STR(a->bssid), a->est_throughput,
    738 		   MAC2STR(b->bssid), b->est_throughput);
    739 	return b;
    740 }
    741 
    742 static struct wpa_bss *
    743 compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs,
    744 			      enum mbo_transition_reject_reason *reason)
    745 {
    746 	u8 i;
    747 	struct wpa_bss *bss = wpa_s->current_bss;
    748 	struct wpa_bss *target;
    749 	struct wpa_bss *best_target = NULL;
    750 	struct wpa_bss *bss_in_list = NULL;
    751 
    752 	if (!bss)
    753 		return NULL;
    754 
    755 	wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
    756 		   MAC2STR(wpa_s->bssid), bss->level);
    757 
    758 	wnm_clear_acceptable(wpa_s);
    759 
    760 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
    761 		struct neighbor_report *nei;
    762 
    763 		nei = &wpa_s->wnm_neighbor_report_elements[i];
    764 		if (nei->preference_present && nei->preference == 0) {
    765 			wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
    766 				   MAC2STR(nei->bssid));
    767 			continue;
    768 		}
    769 
    770 		target = wpa_bss_get_bssid(wpa_s, nei->bssid);
    771 		if (!target) {
    772 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
    773 				   " (pref %d) not found in scan results",
    774 				   MAC2STR(nei->bssid),
    775 				   nei->preference_present ? nei->preference :
    776 				   -1);
    777 			continue;
    778 		}
    779 
    780 		if (age_secs) {
    781 			struct os_reltime now;
    782 
    783 			if (os_get_reltime(&now) == 0 &&
    784 			    os_reltime_expired(&now, &target->last_update,
    785 					       age_secs)) {
    786 				wpa_printf(MSG_DEBUG,
    787 					   "Candidate BSS is more than %ld seconds old",
    788 					   age_secs);
    789 				continue;
    790 			}
    791 		}
    792 
    793 		/*
    794 		 * TODO: Could consider allowing transition to another ESS if
    795 		 * PMF was enabled for the association.
    796 		 */
    797 		if (!wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
    798 					1, 0)) {
    799 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
    800 				   " (pref %d) does not match the current network profile",
    801 				   MAC2STR(nei->bssid),
    802 				   nei->preference_present ? nei->preference :
    803 				   -1);
    804 			continue;
    805 		}
    806 
    807 		if (target->level < bss->level && target->level < -80) {
    808 			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
    809 				   " (pref %d) does not have sufficient signal level (%d)",
    810 				   MAC2STR(nei->bssid),
    811 				   nei->preference_present ? nei->preference :
    812 				   -1,
    813 				   target->level);
    814 			continue;
    815 		}
    816 
    817 		nei->acceptable = 1;
    818 
    819 		best_target = find_better_target(target, best_target);
    820 		if (target == bss)
    821 			bss_in_list = bss;
    822 	}
    823 
    824 #ifdef CONFIG_MBO
    825 	if (wpa_s->wnm_mbo_trans_reason_present)
    826 		target = get_mbo_transition_candidate(wpa_s, reason);
    827 	else
    828 		target = best_target;
    829 #else /* CONFIG_MBO */
    830 	target = best_target;
    831 #endif /* CONFIG_MBO */
    832 
    833 	if (!target)
    834 		return NULL;
    835 
    836 	wpa_printf(MSG_DEBUG,
    837 		   "WNM: Found an acceptable preferred transition candidate BSS "
    838 		   MACSTR " (RSSI %d, tput: %d  bss-tput: %d)",
    839 		   MAC2STR(target->bssid), target->level,
    840 		   target->est_throughput, bss->est_throughput);
    841 
    842 	if (!bss_in_list)
    843 		return target;
    844 
    845 	if ((!target->est_throughput && !bss_in_list->est_throughput) ||
    846 	    (target->est_throughput > bss_in_list->est_throughput &&
    847 	     target->est_throughput - bss_in_list->est_throughput >
    848 	     bss_in_list->est_throughput >> 4)) {
    849 		/* It is more than 100/16 percent better, so switch. */
    850 		return target;
    851 	}
    852 
    853 	wpa_printf(MSG_DEBUG,
    854 		   "WNM: Stay with our current BSS, not enough change in estimated throughput to switch");
    855 	return bss_in_list;
    856 }
    857 
    858 
    859 static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
    860 {
    861 	const u8 *ie_a, *ie_b;
    862 
    863 	if (!a || !b)
    864 		return 0;
    865 
    866 	ie_a = wpa_bss_get_ie(a, eid);
    867 	ie_b = wpa_bss_get_ie(b, eid);
    868 
    869 	if (!ie_a || !ie_b || ie_a[1] != ie_b[1])
    870 		return 0;
    871 
    872 	return os_memcmp(ie_a, ie_b, ie_a[1]) == 0;
    873 }
    874 
    875 
    876 static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
    877 {
    878 	u32 info = 0;
    879 
    880 	info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH;
    881 
    882 	/*
    883 	 * Leave the security and key scope bits unset to indicate that the
    884 	 * security information is not available.
    885 	 */
    886 
    887 	if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT)
    888 		info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
    889 	if (bss->caps & WLAN_CAPABILITY_QOS)
    890 		info |= NEI_REP_BSSID_INFO_QOS;
    891 	if (bss->caps & WLAN_CAPABILITY_APSD)
    892 		info |= NEI_REP_BSSID_INFO_APSD;
    893 	if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT)
    894 		info |= NEI_REP_BSSID_INFO_RM;
    895 	if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK)
    896 		info |= NEI_REP_BSSID_INFO_DELAYED_BA;
    897 	if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK)
    898 		info |= NEI_REP_BSSID_INFO_IMM_BA;
    899 	if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN))
    900 		info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN;
    901 	if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP))
    902 		info |= NEI_REP_BSSID_INFO_HT;
    903 
    904 	return info;
    905 }
    906 
    907 
    908 static int wnm_add_nei_rep(struct wpabuf **buf, const u8 *bssid,
    909 			   u32 bss_info, u8 op_class, u8 chan, u8 phy_type,
    910 			   u8 pref)
    911 {
    912 	if (wpabuf_len(*buf) + 18 >
    913 	    IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN) {
    914 		wpa_printf(MSG_DEBUG,
    915 			   "WNM: No room in frame for Neighbor Report element");
    916 		return -1;
    917 	}
    918 
    919 	if (wpabuf_resize(buf, 18) < 0) {
    920 		wpa_printf(MSG_DEBUG,
    921 			   "WNM: Failed to allocate memory for Neighbor Report element");
    922 		return -1;
    923 	}
    924 
    925 	wpabuf_put_u8(*buf, WLAN_EID_NEIGHBOR_REPORT);
    926 	/* length: 13 for basic neighbor report + 3 for preference subelement */
    927 	wpabuf_put_u8(*buf, 16);
    928 	wpabuf_put_data(*buf, bssid, ETH_ALEN);
    929 	wpabuf_put_le32(*buf, bss_info);
    930 	wpabuf_put_u8(*buf, op_class);
    931 	wpabuf_put_u8(*buf, chan);
    932 	wpabuf_put_u8(*buf, phy_type);
    933 	wpabuf_put_u8(*buf, WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE);
    934 	wpabuf_put_u8(*buf, 1);
    935 	wpabuf_put_u8(*buf, pref);
    936 	return 0;
    937 }
    938 
    939 
    940 static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s,
    941 			       struct wpa_bss *bss, struct wpabuf **buf,
    942 			       u8 pref)
    943 {
    944 	const u8 *ie;
    945 	u8 op_class, chan;
    946 	int sec_chan = 0;
    947 	enum oper_chan_width vht = CONF_OPER_CHWIDTH_USE_HT;
    948 	enum phy_type phy_type;
    949 	u32 info;
    950 	struct ieee80211_ht_operation *ht_oper = NULL;
    951 	struct ieee80211_vht_operation *vht_oper = NULL;
    952 
    953 	ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
    954 	if (ie && ie[1] >= 2) {
    955 		ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
    956 
    957 		if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
    958 			sec_chan = 1;
    959 		else if (ht_oper->ht_param &
    960 			 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
    961 			sec_chan = -1;
    962 	}
    963 
    964 	ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION);
    965 	if (ie && ie[1] >= 1) {
    966 		vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
    967 
    968 		if (vht_oper->vht_op_info_chwidth == CHANWIDTH_80MHZ ||
    969 		    vht_oper->vht_op_info_chwidth == CHANWIDTH_160MHZ ||
    970 		    vht_oper->vht_op_info_chwidth == CHANWIDTH_80P80MHZ)
    971 			vht = vht_oper->vht_op_info_chwidth;
    972 	}
    973 
    974 	if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class,
    975 					  &chan) == NUM_HOSTAPD_MODES) {
    976 		wpa_printf(MSG_DEBUG,
    977 			   "WNM: Cannot determine operating class and channel");
    978 		return -2;
    979 	}
    980 
    981 	phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL),
    982 					  (vht_oper != NULL));
    983 	if (phy_type == PHY_TYPE_UNSPECIFIED) {
    984 		wpa_printf(MSG_DEBUG,
    985 			   "WNM: Cannot determine BSS phy type for Neighbor Report");
    986 		return -2;
    987 	}
    988 
    989 	info = wnm_get_bss_info(wpa_s, bss);
    990 
    991 	return wnm_add_nei_rep(buf, bss->bssid, info, op_class, chan, phy_type,
    992 			       pref);
    993 }
    994 
    995 
    996 static void wnm_add_cand_list(struct wpa_supplicant *wpa_s, struct wpabuf **buf)
    997 {
    998 	unsigned int i, pref = 255;
    999 	struct os_reltime now;
   1000 	struct wpa_ssid *ssid = wpa_s->current_ssid;
   1001 
   1002 	if (!ssid)
   1003 		return;
   1004 
   1005 	/*
   1006 	 * TODO: Define when scan results are no longer valid for the candidate
   1007 	 * list.
   1008 	 */
   1009 	os_get_reltime(&now);
   1010 	if (os_reltime_expired(&now, &wpa_s->last_scan, 10))
   1011 		return;
   1012 
   1013 	wpa_printf(MSG_DEBUG,
   1014 		   "WNM: Add candidate list to BSS Transition Management Response frame");
   1015 	for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) {
   1016 		struct wpa_bss *bss = wpa_s->last_scan_res[i];
   1017 		int res;
   1018 
   1019 		if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) {
   1020 			res = wnm_nei_rep_add_bss(wpa_s, bss, buf, pref--);
   1021 			if (res == -2)
   1022 				continue; /* could not build entry for BSS */
   1023 			if (res < 0)
   1024 				break; /* no more room for candidates */
   1025 			if (pref == 1)
   1026 				break;
   1027 		}
   1028 	}
   1029 
   1030 	wpa_hexdump_buf(MSG_DEBUG,
   1031 			"WNM: BSS Transition Management Response candidate list",
   1032 			*buf);
   1033 }
   1034 
   1035 
   1036 #define BTM_RESP_MIN_SIZE	5 + ETH_ALEN
   1037 
   1038 static int wnm_send_bss_transition_mgmt_resp(
   1039 	struct wpa_supplicant *wpa_s,
   1040 	enum bss_trans_mgmt_status_code status,
   1041 	enum mbo_transition_reject_reason reason,
   1042 	u8 delay, const u8 *target_bssid)
   1043 {
   1044 	struct wpabuf *buf;
   1045 	int res;
   1046 
   1047 	wpa_s->wnm_reply = 0;
   1048 
   1049 	wpa_printf(MSG_DEBUG,
   1050 		   "WNM: Send BSS Transition Management Response to " MACSTR
   1051 		   " dialog_token=%u status=%u reason=%u delay=%d",
   1052 		   MAC2STR(wpa_s->bssid), wpa_s->wnm_dialog_token, status,
   1053 		   reason, delay);
   1054 	if (!wpa_s->current_bss) {
   1055 		wpa_printf(MSG_DEBUG,
   1056 			   "WNM: Current BSS not known - drop response");
   1057 		return -1;
   1058 	}
   1059 
   1060 	buf = wpabuf_alloc(BTM_RESP_MIN_SIZE);
   1061 	if (!buf) {
   1062 		wpa_printf(MSG_DEBUG,
   1063 			   "WNM: Failed to allocate memory for BTM response");
   1064 		return -1;
   1065 	}
   1066 
   1067 	wpa_s->bss_tm_status = status;
   1068 	wpas_notify_bss_tm_status(wpa_s);
   1069 
   1070 	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
   1071 	wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP);
   1072 	wpabuf_put_u8(buf, wpa_s->wnm_dialog_token);
   1073 	wpabuf_put_u8(buf, status);
   1074 	wpabuf_put_u8(buf, delay);
   1075 	if (target_bssid) {
   1076 		wpabuf_put_data(buf, target_bssid, ETH_ALEN);
   1077 	} else if (status == WNM_BSS_TM_ACCEPT) {
   1078 		/*
   1079 		 * P802.11-REVmc clarifies that the Target BSSID field is always
   1080 		 * present when status code is zero, so use a fake value here if
   1081 		 * no BSSID is yet known.
   1082 		 */
   1083 		wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN);
   1084 	}
   1085 
   1086 	if (status == WNM_BSS_TM_ACCEPT && target_bssid)
   1087 		wnm_add_cand_list(wpa_s, &buf);
   1088 
   1089 #ifdef CONFIG_MBO
   1090 	if (status != WNM_BSS_TM_ACCEPT &&
   1091 	    wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE)) {
   1092 		u8 mbo[10];
   1093 		size_t ret;
   1094 
   1095 		ret = wpas_mbo_ie_bss_trans_reject(wpa_s, mbo, sizeof(mbo),
   1096 						   reason);
   1097 		if (ret) {
   1098 			if (wpabuf_resize(&buf, ret) < 0) {
   1099 				wpabuf_free(buf);
   1100 				wpa_printf(MSG_DEBUG,
   1101 					   "WNM: Failed to allocate memory for MBO IE");
   1102 				return -1;
   1103 			}
   1104 
   1105 			wpabuf_put_data(buf, mbo, ret);
   1106 		}
   1107 	}
   1108 #endif /* CONFIG_MBO */
   1109 
   1110 	res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
   1111 				  wpa_s->own_addr, wpa_s->bssid,
   1112 				  wpabuf_head_u8(buf), wpabuf_len(buf), 0);
   1113 	if (res < 0) {
   1114 		wpa_printf(MSG_DEBUG,
   1115 			   "WNM: Failed to send BSS Transition Management Response");
   1116 	}
   1117 
   1118 	wpabuf_free(buf);
   1119 
   1120 	return res;
   1121 }
   1122 
   1123 
   1124 static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
   1125 			       struct wpa_bss *bss, struct wpa_ssid *ssid,
   1126 			       int after_new_scan)
   1127 {
   1128 	struct wpa_radio_work *already_connecting;
   1129 
   1130 	wpa_dbg(wpa_s, MSG_DEBUG,
   1131 		"WNM: Transition to BSS " MACSTR
   1132 		" based on BSS Transition Management Request (old BSSID "
   1133 		MACSTR " after_new_scan=%d)",
   1134 		MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan);
   1135 
   1136 	/* Send the BSS Management Response - Accept */
   1137 	if (wpa_s->wnm_reply) {
   1138 		wpa_s->wnm_target_bss = bss;
   1139 		wpa_printf(MSG_DEBUG,
   1140 			   "WNM: Sending successful BSS Transition Management Response");
   1141 
   1142 		/* This function will be called again from the TX handler to
   1143 		 * start the actual reassociation after this response has been
   1144 		 * delivered to the current AP. */
   1145 		if (wnm_send_bss_transition_mgmt_resp(
   1146 			    wpa_s, WNM_BSS_TM_ACCEPT,
   1147 			    MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
   1148 			    bss->bssid) >= 0)
   1149 			return;
   1150 	}
   1151 
   1152 	if (bss == wpa_s->current_bss) {
   1153 		wpa_printf(MSG_DEBUG,
   1154 			   "WNM: Already associated with the preferred candidate");
   1155 		wnm_btm_reset(wpa_s);
   1156 		return;
   1157 	}
   1158 
   1159 	already_connecting = radio_work_pending(wpa_s, "sme-connect");
   1160 	wpa_s->reassociate = 1;
   1161 	wpa_printf(MSG_DEBUG, "WNM: Issuing connect");
   1162 	wpa_supplicant_connect(wpa_s, bss, ssid);
   1163 
   1164 	/*
   1165 	 * Indicate that a BSS transition is in progress so scan results that
   1166 	 * come in before the 'sme-connect' radio work gets executed do not
   1167 	 * override the original connection attempt.
   1168 	 */
   1169 	if (!already_connecting && radio_work_pending(wpa_s, "sme-connect"))
   1170 		wpa_s->bss_trans_mgmt_in_progress = true;
   1171 }
   1172 
   1173 
   1174 int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
   1175 {
   1176 	struct wpa_bss *bss;
   1177 	struct wpa_ssid *ssid = wpa_s->current_ssid;
   1178 	enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
   1179 	enum mbo_transition_reject_reason reason =
   1180 		MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
   1181 
   1182 	if (!wpa_s->wnm_dialog_token)
   1183 		return 0;
   1184 
   1185 	wpa_dbg(wpa_s, MSG_DEBUG,
   1186 		"WNM: Process scan results for BSS Transition Management");
   1187 	if (!pre_scan_check &&
   1188 	    os_reltime_initialized(&wpa_s->wnm_cand_valid_until) &&
   1189 	    os_reltime_before(&wpa_s->wnm_cand_valid_until,
   1190 			      &wpa_s->scan_trigger_time)) {
   1191 		wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
   1192 		goto send_bss_resp_fail;
   1193 	}
   1194 
   1195 	/* Compare the Neighbor Report and scan results */
   1196 	bss = compare_scan_neighbor_results(wpa_s, 0, &reason);
   1197 
   1198 	/*
   1199 	 * If this is a pre-scan check, returning 0 will trigger a scan and
   1200 	 * another call. In that case, reject "bad" candidates in the hope of
   1201 	 * finding a better candidate after scanning.
   1202 	 *
   1203 	 * Use a simple heuristic to check whether the selection is reasonable
   1204 	 * or a scan is a good idea. For that, we need to have found a
   1205 	 * candidate BSS (which might be the current one), it is up-to-date,
   1206 	 * and we don't want to immediately roam back again.
   1207 	 */
   1208 	if (pre_scan_check) {
   1209 		struct os_reltime age;
   1210 
   1211 		if (!bss)
   1212 			return 0;
   1213 
   1214 		os_reltime_age(&bss->last_update, &age);
   1215 		if (age.sec >= 10)
   1216 			return 0;
   1217 
   1218 #ifndef CONFIG_NO_ROAMING
   1219 		if (wpa_s->current_bss && bss != wpa_s->current_bss &&
   1220 		    wpa_supplicant_need_to_roam_within_ess(wpa_s,
   1221 							   wpa_s->current_bss,
   1222 							   bss))
   1223 			return 0;
   1224 #endif /* CONFIG_NO_ROAMING */
   1225 	}
   1226 
   1227 	if (!bss) {
   1228 		wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
   1229 		status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
   1230 		goto send_bss_resp_fail;
   1231 	}
   1232 
   1233 	/* Associate to the network */
   1234 	wnm_bss_tm_connect(wpa_s, bss, ssid, 1);
   1235 	return 1;
   1236 
   1237 send_bss_resp_fail:
   1238 	/* Send reject response for all the failures */
   1239 
   1240 	if (wpa_s->wnm_reply)
   1241 		wnm_send_bss_transition_mgmt_resp(wpa_s, status, reason,
   1242 						  0, NULL);
   1243 
   1244 	wnm_btm_reset(wpa_s);
   1245 
   1246 	return 0;
   1247 }
   1248 
   1249 
   1250 static int cand_pref_compar(const void *a, const void *b)
   1251 {
   1252 	const struct neighbor_report *aa = a;
   1253 	const struct neighbor_report *bb = b;
   1254 
   1255 	if (aa->disassoc_imminent && !bb->disassoc_imminent)
   1256 		return 1;
   1257 	if (bb->disassoc_imminent && !aa->disassoc_imminent)
   1258 		return -1;
   1259 
   1260 	if (!aa->preference_present && !bb->preference_present)
   1261 		return 0;
   1262 	if (!aa->preference_present)
   1263 		return 1;
   1264 	if (!bb->preference_present)
   1265 		return -1;
   1266 	if (bb->preference > aa->preference)
   1267 		return 1;
   1268 	if (bb->preference < aa->preference)
   1269 		return -1;
   1270 	return 0;
   1271 }
   1272 
   1273 
   1274 static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s)
   1275 {
   1276 	if (!wpa_s->wnm_neighbor_report_elements)
   1277 		return;
   1278 	qsort(wpa_s->wnm_neighbor_report_elements,
   1279 	      wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report),
   1280 	      cand_pref_compar);
   1281 }
   1282 
   1283 
   1284 static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
   1285 {
   1286 	unsigned int i;
   1287 
   1288 	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List");
   1289 	if (!wpa_s->wnm_neighbor_report_elements)
   1290 		return;
   1291 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
   1292 		struct neighbor_report *nei;
   1293 
   1294 		nei = &wpa_s->wnm_neighbor_report_elements[i];
   1295 		wpa_printf(MSG_DEBUG, "%u: " MACSTR
   1296 			   " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d",
   1297 			   i, MAC2STR(nei->bssid), nei->bssid_info,
   1298 			   nei->regulatory_class,
   1299 			   nei->channel_number, nei->phy_type,
   1300 			   nei->preference_present ? nei->preference : -1,
   1301 			   nei->freq);
   1302 	}
   1303 }
   1304 
   1305 
   1306 static int chan_supported(struct wpa_supplicant *wpa_s, int freq)
   1307 {
   1308 	unsigned int i;
   1309 
   1310 	for (i = 0; i < wpa_s->hw.num_modes; i++) {
   1311 		struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
   1312 		int j;
   1313 
   1314 		for (j = 0; j < mode->num_channels; j++) {
   1315 			struct hostapd_channel_data *chan;
   1316 
   1317 			chan = &mode->channels[j];
   1318 			if (chan->freq == freq &&
   1319 			    !(chan->flag & HOSTAPD_CHAN_DISABLED))
   1320 				return 1;
   1321 		}
   1322 	}
   1323 
   1324 	return 0;
   1325 }
   1326 
   1327 
   1328 static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
   1329 {
   1330 	int *freqs;
   1331 	int num_freqs = 0;
   1332 	unsigned int i;
   1333 
   1334 	if (!wpa_s->wnm_neighbor_report_elements)
   1335 		return;
   1336 
   1337 	if (wpa_s->hw.modes == NULL)
   1338 		return;
   1339 
   1340 	os_free(wpa_s->next_scan_freqs);
   1341 	wpa_s->next_scan_freqs = NULL;
   1342 
   1343 	freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int));
   1344 	if (freqs == NULL)
   1345 		return;
   1346 
   1347 	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
   1348 		struct neighbor_report *nei;
   1349 
   1350 		nei = &wpa_s->wnm_neighbor_report_elements[i];
   1351 
   1352 		if (nei->preference_present && nei->preference == 0)
   1353 			continue;
   1354 
   1355 		if (nei->freq <= 0) {
   1356 			wpa_printf(MSG_DEBUG,
   1357 				   "WNM: Unknown neighbor operating frequency for "
   1358 				   MACSTR " - scan all channels",
   1359 				   MAC2STR(nei->bssid));
   1360 			os_free(freqs);
   1361 			return;
   1362 		}
   1363 		if (chan_supported(wpa_s, nei->freq))
   1364 			add_freq(freqs, &num_freqs, nei->freq);
   1365 	}
   1366 
   1367 	if (num_freqs == 0) {
   1368 		os_free(freqs);
   1369 		return;
   1370 	}
   1371 
   1372 	wpa_printf(MSG_DEBUG,
   1373 		   "WNM: Scan %d frequencies based on transition candidate list",
   1374 		   num_freqs);
   1375 	wpa_s->next_scan_freqs = freqs;
   1376 }
   1377 
   1378 
   1379 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
   1380 					     const u8 *pos, const u8 *end,
   1381 					     int reply)
   1382 {
   1383 	unsigned int beacon_int;
   1384 	u8 valid_int;
   1385 #ifdef CONFIG_MBO
   1386 	const u8 *vendor;
   1387 #endif /* CONFIG_MBO */
   1388 	bool disassoc_imminent;
   1389 
   1390 	if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm)
   1391 		return;
   1392 
   1393 	if (end - pos < 5)
   1394 		return;
   1395 
   1396 	if (wpa_s->current_bss)
   1397 		beacon_int = wpa_s->current_bss->beacon_int;
   1398 	else
   1399 		beacon_int = 100; /* best guess */
   1400 
   1401 	wnm_btm_reset(wpa_s);
   1402 
   1403 	wpa_s->wnm_dialog_token = pos[0];
   1404 	wpa_s->wnm_mode = pos[1];
   1405 	wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
   1406 	wpa_s->wnm_link_removal = false;
   1407 	valid_int = pos[4];
   1408 	wpa_s->wnm_reply = reply;
   1409 
   1410 	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
   1411 		   "dialog_token=%u request_mode=0x%x "
   1412 		   "disassoc_timer=%u validity_interval=%u",
   1413 		   wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
   1414 		   wpa_s->wnm_dissoc_timer, valid_int);
   1415 
   1416 #if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS)
   1417 	if (wpa_s->reject_btm_req_reason) {
   1418 		wpa_printf(MSG_INFO,
   1419 			   "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d",
   1420 			   wpa_s->reject_btm_req_reason);
   1421 		wnm_send_bss_transition_mgmt_resp(
   1422 			wpa_s, wpa_s->reject_btm_req_reason,
   1423 			MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
   1424 		return;
   1425 	}
   1426 #endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */
   1427 
   1428 	pos += 5;
   1429 
   1430 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
   1431 		if (end - pos < 12) {
   1432 			wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
   1433 			return;
   1434 		}
   1435 		os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
   1436 		pos += 12; /* BSS Termination Duration */
   1437 	}
   1438 
   1439 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
   1440 		char url[256];
   1441 		u8 url_len;
   1442 
   1443 		if (end - pos < 1) {
   1444 			wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
   1445 				   "Management Request (URL)");
   1446 			return;
   1447 		}
   1448 		url_len = *pos++;
   1449 		if (url_len > end - pos) {
   1450 			wpa_printf(MSG_DEBUG,
   1451 				   "WNM: Invalid BSS Transition Management Request (URL truncated)");
   1452 			return;
   1453 		}
   1454 		os_memcpy(url, pos, url_len);
   1455 		url[url_len] = '\0';
   1456 		pos += url_len;
   1457 
   1458 		wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
   1459 			wpa_sm_pmf_enabled(wpa_s->wpa),
   1460 			wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
   1461 	}
   1462 
   1463 	disassoc_imminent = wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
   1464 
   1465 	/*
   1466 	 * Based on IEEE P802.11be/D5.0, when a station is a non-AP MLD with
   1467 	 * more than one affiliated link, the Link Removal Imminent field is
   1468 	 * set to 1, and the BSS Termination Included field is set to 1, only
   1469 	 * one of the links is removed and the other links remain associated.
   1470 	 * Ignore the Disassociation Imminent field in such a case.
   1471 	 *
   1472 	 * TODO: We should check if the AP has more than one link.
   1473 	 * TODO: We should pass the RX link and use that
   1474 	 */
   1475 	if (disassoc_imminent && wpa_s->valid_links &&
   1476 	    (wpa_s->wnm_mode & WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT) &&
   1477 	    (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED)) {
   1478 		/* If we still have a link, then just accept the request */
   1479 		if (wpa_s->valid_links & (wpa_s->valid_links - 1)) {
   1480 			wpa_printf(MSG_INFO,
   1481 				   "WNM: BTM request for a single MLO link - ignore disassociation imminent since other links remain associated");
   1482 			disassoc_imminent = false;
   1483 
   1484 			wnm_send_bss_transition_mgmt_resp(
   1485 				wpa_s, WNM_BSS_TM_ACCEPT, 0, 0, NULL);
   1486 
   1487 			return;
   1488 		}
   1489 
   1490 		/* The last link is being removed (which must be the assoc link)
   1491 		 */
   1492 		wpa_s->wnm_link_removal = true;
   1493 		os_memcpy(wpa_s->wnm_dissoc_addr,
   1494 			  wpa_s->links[wpa_s->mlo_assoc_link_id].bssid,
   1495 			  ETH_ALEN);
   1496 	} else {
   1497 		os_memcpy(wpa_s->wnm_dissoc_addr, wpa_s->valid_links ?
   1498 			  wpa_s->ap_mld_addr : wpa_s->bssid, ETH_ALEN);
   1499 	}
   1500 
   1501 	if (disassoc_imminent) {
   1502 		wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
   1503 			"Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
   1504 		if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning &&
   1505 		    (!wpa_s->current_ssid || !wpa_s->current_ssid->bssid_set)) {
   1506 			wpa_printf(MSG_DEBUG, "Trying to find another BSS");
   1507 			wpa_supplicant_req_scan(wpa_s, 0, 0);
   1508 		}
   1509 	}
   1510 
   1511 #ifdef CONFIG_MBO
   1512 	vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
   1513 	if (vendor)
   1514 		wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
   1515 #endif /* CONFIG_MBO */
   1516 
   1517 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
   1518 		unsigned int valid_ms;
   1519 
   1520 		wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
   1521 		wpa_s->wnm_neighbor_report_elements = os_calloc(
   1522 			WNM_MAX_NEIGHBOR_REPORT,
   1523 			sizeof(struct neighbor_report));
   1524 		if (wpa_s->wnm_neighbor_report_elements == NULL)
   1525 			return;
   1526 
   1527 		while (end - pos >= 2 &&
   1528 		       wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
   1529 		{
   1530 			u8 tag = *pos++;
   1531 			u8 len = *pos++;
   1532 
   1533 			wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
   1534 				   tag);
   1535 			if (len > end - pos) {
   1536 				wpa_printf(MSG_DEBUG, "WNM: Truncated request");
   1537 				return;
   1538 			}
   1539 			if (tag == WLAN_EID_NEIGHBOR_REPORT) {
   1540 				struct neighbor_report *rep;
   1541 				rep = &wpa_s->wnm_neighbor_report_elements[
   1542 					wpa_s->wnm_num_neighbor_report];
   1543 				wnm_parse_neighbor_report(wpa_s, pos, len, rep);
   1544 				if ((wpa_s->wnm_mode &
   1545 				     WNM_BSS_TM_REQ_DISASSOC_IMMINENT) &&
   1546 				    ether_addr_equal(rep->bssid, wpa_s->bssid))
   1547 					rep->disassoc_imminent = 1;
   1548 
   1549 				wpa_s->wnm_num_neighbor_report++;
   1550 #ifdef CONFIG_MBO
   1551 				if (wpa_s->wnm_mbo_trans_reason_present &&
   1552 				    wpa_s->wnm_num_neighbor_report == 1) {
   1553 					rep->is_first = 1;
   1554 					wpa_printf(MSG_DEBUG,
   1555 						   "WNM: First transition candidate is "
   1556 						   MACSTR, MAC2STR(rep->bssid));
   1557 				}
   1558 #endif /* CONFIG_MBO */
   1559 			}
   1560 
   1561 			pos += len;
   1562 		}
   1563 
   1564 		if (!wpa_s->wnm_num_neighbor_report) {
   1565 			wpa_printf(MSG_DEBUG,
   1566 				   "WNM: Candidate list included bit is set, but no candidates found");
   1567 			wnm_send_bss_transition_mgmt_resp(
   1568 				wpa_s, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
   1569 				MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
   1570 				NULL);
   1571 			return;
   1572 		}
   1573 
   1574 		if (wpa_s->current_ssid && wpa_s->current_ssid->bssid_set) {
   1575 			wpa_printf(MSG_DEBUG,
   1576 				   "WNM: Configuration prevents roaming (BSSID set)");
   1577 			wnm_send_bss_transition_mgmt_resp(
   1578 				wpa_s, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
   1579 				MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
   1580 				NULL);
   1581 			return;
   1582 		}
   1583 
   1584 		wnm_sort_cand_list(wpa_s);
   1585 		wnm_dump_cand_list(wpa_s);
   1586 		valid_ms = valid_int * beacon_int * 128 / 125;
   1587 		wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
   1588 			   valid_ms);
   1589 		os_get_reltime(&wpa_s->wnm_cand_valid_until);
   1590 		wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
   1591 		wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
   1592 		wpa_s->wnm_cand_valid_until.sec +=
   1593 			wpa_s->wnm_cand_valid_until.usec / 1000000;
   1594 		wpa_s->wnm_cand_valid_until.usec %= 1000000;
   1595 
   1596 		/*
   1597 		* Try fetching the latest scan results from the kernel.
   1598 		* This can help in finding more up-to-date information should
   1599 		* the driver have done some internal scanning operations after
   1600 		* the last scan result update in wpa_supplicant.
   1601 		*
   1602 		* It is not a new scan, this does not update the last_scan
   1603 		* timestamp nor will it expire old BSSs.
   1604 		*/
   1605 		wpa_supplicant_update_scan_results(wpa_s, NULL);
   1606 		if (wnm_scan_process(wpa_s, true) > 0)
   1607 			return;
   1608 		wpa_printf(MSG_DEBUG,
   1609 			   "WNM: No valid match in previous scan results - try a new scan");
   1610 
   1611 		wnm_set_scan_freqs(wpa_s);
   1612 		if (wpa_s->wnm_num_neighbor_report == 1) {
   1613 			os_memcpy(wpa_s->next_scan_bssid,
   1614 				  wpa_s->wnm_neighbor_report_elements[0].bssid,
   1615 				  ETH_ALEN);
   1616 			wpa_printf(MSG_DEBUG,
   1617 				   "WNM: Scan only for a specific BSSID since there is only a single candidate "
   1618 				   MACSTR, MAC2STR(wpa_s->next_scan_bssid));
   1619 		}
   1620 		wpa_supplicant_req_scan(wpa_s, 0, 0);
   1621 	} else if (reply) {
   1622 		enum bss_trans_mgmt_status_code status;
   1623 
   1624 		if ((wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) ||
   1625 		    wpa_s->wnm_link_removal)
   1626 			status = WNM_BSS_TM_ACCEPT;
   1627 		else {
   1628 			wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
   1629 			status = WNM_BSS_TM_REJECT_UNSPECIFIED;
   1630 		}
   1631 		wnm_send_bss_transition_mgmt_resp(
   1632 			wpa_s, status,
   1633 			MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
   1634 	}
   1635 }
   1636 
   1637 
   1638 int wnm_btm_resp_tx_status(struct wpa_supplicant *wpa_s, const u8 *data,
   1639 			   size_t data_len)
   1640 {
   1641 	const struct ieee80211_mgmt *frame =
   1642 		(const struct ieee80211_mgmt *) data;
   1643 
   1644 	if (data_len <
   1645 	    IEEE80211_HDRLEN + sizeof(frame->u.action.u.bss_tm_resp) ||
   1646 	    frame->u.action.category != WLAN_ACTION_WNM ||
   1647 	    frame->u.action.u.bss_tm_resp.action != WNM_BSS_TRANS_MGMT_RESP ||
   1648 	    frame->u.action.u.bss_tm_resp.status_code != WNM_BSS_TM_ACCEPT)
   1649 		return -1;
   1650 
   1651 	/*
   1652 	 * If disassoc imminent bit was set in the request, the response may
   1653 	 * indicate accept even if no candidate was found, so bail out here.
   1654 	 */
   1655 	if (!wpa_s->wnm_target_bss) {
   1656 		wpa_printf(MSG_DEBUG, "WNM: Target BSS is not set");
   1657 		return 0;
   1658 	}
   1659 
   1660 	if (!wpa_s->current_ssid)
   1661 		return 0;
   1662 
   1663 	wnm_bss_tm_connect(wpa_s, wpa_s->wnm_target_bss, wpa_s->current_ssid,
   1664 			   0);
   1665 
   1666 	wpa_s->wnm_target_bss = NULL;
   1667 	return 0;
   1668 }
   1669 
   1670 
   1671 #define BTM_QUERY_MIN_SIZE	4
   1672 
   1673 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
   1674 				       u8 query_reason,
   1675 				       const char *btm_candidates,
   1676 				       int cand_list)
   1677 {
   1678 	struct wpabuf *buf;
   1679 	int ret;
   1680 
   1681 	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
   1682 		   MACSTR " query_reason=%u%s",
   1683 		   MAC2STR(wpa_s->bssid), query_reason,
   1684 		   cand_list ? " candidate list" : "");
   1685 
   1686 	buf = wpabuf_alloc(BTM_QUERY_MIN_SIZE);
   1687 	if (!buf)
   1688 		return -1;
   1689 
   1690 	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
   1691 	wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_QUERY);
   1692 	wpabuf_put_u8(buf, 1);
   1693 	wpabuf_put_u8(buf, query_reason);
   1694 
   1695 	if (cand_list)
   1696 		wnm_add_cand_list(wpa_s, &buf);
   1697 
   1698 	if (btm_candidates) {
   1699 		const size_t max_len = 1000;
   1700 
   1701 		ret = wpabuf_resize(&buf, max_len);
   1702 		if (ret < 0) {
   1703 			wpabuf_free(buf);
   1704 			return ret;
   1705 		}
   1706 
   1707 		ret = ieee802_11_parse_candidate_list(btm_candidates,
   1708 						      wpabuf_put(buf, 0),
   1709 						      max_len);
   1710 		if (ret < 0) {
   1711 			wpabuf_free(buf);
   1712 			return ret;
   1713 		}
   1714 
   1715 		wpabuf_put(buf, ret);
   1716 	}
   1717 
   1718 	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
   1719 				  wpa_s->own_addr, wpa_s->bssid,
   1720 				  wpabuf_head_u8(buf), wpabuf_len(buf), 0);
   1721 
   1722 	wpabuf_free(buf);
   1723 	return ret;
   1724 }
   1725 
   1726 
   1727 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
   1728 					    const u8 *sa, const u8 *data,
   1729 					    int len)
   1730 {
   1731 	const u8 *pos, *end, *next;
   1732 	u8 ie, ie_len;
   1733 
   1734 	pos = data;
   1735 	end = data + len;
   1736 
   1737 	while (end - pos > 1) {
   1738 		ie = *pos++;
   1739 		ie_len = *pos++;
   1740 		wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u",
   1741 			   ie, ie_len);
   1742 		if (ie_len > end - pos) {
   1743 			wpa_printf(MSG_DEBUG, "WNM: Not enough room for "
   1744 				   "subelement");
   1745 			break;
   1746 		}
   1747 		next = pos + ie_len;
   1748 		if (ie_len < 4) {
   1749 			pos = next;
   1750 			continue;
   1751 		}
   1752 		wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u",
   1753 			   WPA_GET_BE24(pos), pos[3]);
   1754 
   1755 #ifdef CONFIG_HS20
   1756 		if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
   1757 		    WPA_GET_BE24(pos) == OUI_WFA &&
   1758 		    pos[3] == HS20_WNM_SUB_REM_NEEDED) {
   1759 			/* Subscription Remediation subelement */
   1760 			const u8 *ie_end;
   1761 			u8 url_len;
   1762 			char *url;
   1763 			u8 osu_method;
   1764 
   1765 			wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation "
   1766 				   "subelement");
   1767 			ie_end = pos + ie_len;
   1768 			pos += 4;
   1769 			url_len = *pos++;
   1770 			if (url_len == 0) {
   1771 				wpa_printf(MSG_DEBUG, "WNM: No Server URL included");
   1772 				url = NULL;
   1773 				osu_method = 1;
   1774 			} else {
   1775 				if (url_len + 1 > ie_end - pos) {
   1776 					wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
   1777 						   url_len,
   1778 						   (int) (ie_end - pos));
   1779 					break;
   1780 				}
   1781 				url = os_malloc(url_len + 1);
   1782 				if (url == NULL)
   1783 					break;
   1784 				os_memcpy(url, pos, url_len);
   1785 				url[url_len] = '\0';
   1786 				osu_method = pos[url_len];
   1787 			}
   1788 			hs20_rx_subscription_remediation(wpa_s, url,
   1789 							 osu_method);
   1790 			os_free(url);
   1791 			pos = next;
   1792 			continue;
   1793 		}
   1794 
   1795 		if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 &&
   1796 		    WPA_GET_BE24(pos) == OUI_WFA &&
   1797 		    pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) {
   1798 			const u8 *ie_end;
   1799 			u8 url_len;
   1800 			char *url;
   1801 			u8 code;
   1802 			u16 reauth_delay;
   1803 
   1804 			ie_end = pos + ie_len;
   1805 			pos += 4;
   1806 			code = *pos++;
   1807 			reauth_delay = WPA_GET_LE16(pos);
   1808 			pos += 2;
   1809 			url_len = *pos++;
   1810 			wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication "
   1811 				   "Imminent - Reason Code %u   "
   1812 				   "Re-Auth Delay %u  URL Length %u",
   1813 				   code, reauth_delay, url_len);
   1814 			if (url_len > ie_end - pos)
   1815 				break;
   1816 			url = os_malloc(url_len + 1);
   1817 			if (url == NULL)
   1818 				break;
   1819 			os_memcpy(url, pos, url_len);
   1820 			url[url_len] = '\0';
   1821 			hs20_rx_deauth_imminent_notice(wpa_s, code,
   1822 						       reauth_delay, url);
   1823 			os_free(url);
   1824 			pos = next;
   1825 			continue;
   1826 		}
   1827 
   1828 		if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
   1829 		    WPA_GET_BE24(pos) == OUI_WFA &&
   1830 		    pos[3] == HS20_WNM_T_C_ACCEPTANCE) {
   1831 			const u8 *ie_end;
   1832 			u8 url_len;
   1833 			char *url;
   1834 
   1835 			ie_end = pos + ie_len;
   1836 			pos += 4;
   1837 			url_len = *pos++;
   1838 			wpa_printf(MSG_DEBUG,
   1839 				   "WNM: HS 2.0 Terms and Conditions Acceptance (URL Length %u)",
   1840 				   url_len);
   1841 			if (url_len > ie_end - pos)
   1842 				break;
   1843 			url = os_malloc(url_len + 1);
   1844 			if (!url)
   1845 				break;
   1846 			os_memcpy(url, pos, url_len);
   1847 			url[url_len] = '\0';
   1848 			hs20_rx_t_c_acceptance(wpa_s, url);
   1849 			os_free(url);
   1850 			pos = next;
   1851 			continue;
   1852 		}
   1853 #endif /* CONFIG_HS20 */
   1854 
   1855 		pos = next;
   1856 	}
   1857 }
   1858 
   1859 
   1860 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s,
   1861 					const u8 *sa, const u8 *frm, int len)
   1862 {
   1863 	const u8 *pos, *end;
   1864 	u8 dialog_token, type;
   1865 
   1866 	/* Dialog Token [1] | Type [1] | Subelements */
   1867 
   1868 	if (len < 2 || sa == NULL)
   1869 		return;
   1870 	end = frm + len;
   1871 	pos = frm;
   1872 	dialog_token = *pos++;
   1873 	type = *pos++;
   1874 
   1875 	wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request "
   1876 		"(dialog_token %u type %u sa " MACSTR ")",
   1877 		dialog_token, type, MAC2STR(sa));
   1878 	wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements",
   1879 		    pos, end - pos);
   1880 
   1881 	if (wpa_s->wpa_state != WPA_COMPLETED ||
   1882 	    (!ether_addr_equal(sa, wpa_s->bssid) &&
   1883 	     (!wpa_s->valid_links ||
   1884 	      !ether_addr_equal(sa, wpa_s->ap_mld_addr)))) {
   1885 		wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not "
   1886 			"from our AP - ignore it");
   1887 		return;
   1888 	}
   1889 
   1890 	switch (type) {
   1891 	case 1:
   1892 		ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos);
   1893 		break;
   1894 	default:
   1895 		wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown "
   1896 			"WNM-Notification type %u", type);
   1897 		break;
   1898 	}
   1899 }
   1900 
   1901 
   1902 static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s,
   1903 					     const u8 *sa, const u8 *frm,
   1904 					     int len)
   1905 {
   1906 	u8 dialog_token, req_info, auto_report, timeout;
   1907 
   1908 	if (!wpa_s->conf->coloc_intf_reporting)
   1909 		return;
   1910 
   1911 	/* Dialog Token [1] | Request Info [1] */
   1912 
   1913 	if (len < 2)
   1914 		return;
   1915 	dialog_token = frm[0];
   1916 	req_info = frm[1];
   1917 	auto_report = req_info & 0x03;
   1918 	timeout = req_info >> 2;
   1919 
   1920 	wpa_dbg(wpa_s, MSG_DEBUG,
   1921 		"WNM: Received Collocated Interference Request (dialog_token %u auto_report %u timeout %u sa " MACSTR ")",
   1922 		dialog_token, auto_report, timeout, MAC2STR(sa));
   1923 
   1924 	if (dialog_token == 0)
   1925 		return; /* only nonzero values are used for request */
   1926 
   1927 	if (wpa_s->wpa_state != WPA_COMPLETED ||
   1928 	    (!ether_addr_equal(sa, wpa_s->bssid) &&
   1929 	     (!wpa_s->valid_links ||
   1930 	      !ether_addr_equal(sa, wpa_s->ap_mld_addr)))) {
   1931 		wpa_dbg(wpa_s, MSG_DEBUG,
   1932 			"WNM: Collocated Interference Request frame not from current AP - ignore it");
   1933 		return;
   1934 	}
   1935 
   1936 	wpa_msg(wpa_s, MSG_INFO, COLOC_INTF_REQ "%u %u %u",
   1937 		dialog_token, auto_report, timeout);
   1938 	wpa_s->coloc_intf_dialog_token = dialog_token;
   1939 	wpa_s->coloc_intf_auto_report = auto_report;
   1940 	wpa_s->coloc_intf_timeout = timeout;
   1941 }
   1942 
   1943 
   1944 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
   1945 			      const struct ieee80211_mgmt *mgmt, size_t len)
   1946 {
   1947 	const u8 *pos, *end;
   1948 	u8 act;
   1949 
   1950 	if (len < IEEE80211_HDRLEN + 2)
   1951 		return;
   1952 
   1953 	pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1;
   1954 	act = *pos++;
   1955 	end = ((const u8 *) mgmt) + len;
   1956 
   1957 	wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
   1958 		   act, MAC2STR(mgmt->sa));
   1959 	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
   1960 	    (!ether_addr_equal(mgmt->sa, wpa_s->bssid) &&
   1961 	     (!wpa_s->valid_links ||
   1962 	      !ether_addr_equal(mgmt->sa, wpa_s->ap_mld_addr)))) {
   1963 		wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
   1964 			   "frame");
   1965 		return;
   1966 	}
   1967 
   1968 	switch (act) {
   1969 	case WNM_BSS_TRANS_MGMT_REQ:
   1970 		ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
   1971 						 !(mgmt->da[0] & 0x01));
   1972 		break;
   1973 	case WNM_SLEEP_MODE_RESP:
   1974 		ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos);
   1975 		break;
   1976 	case WNM_NOTIFICATION_REQ:
   1977 		ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
   1978 		break;
   1979 	case WNM_COLLOCATED_INTERFERENCE_REQ:
   1980 		ieee802_11_rx_wnm_coloc_intf_req(wpa_s, mgmt->sa, pos,
   1981 						 end - pos);
   1982 		break;
   1983 	default:
   1984 		wpa_printf(MSG_ERROR, "WNM: Unknown request");
   1985 		break;
   1986 	}
   1987 }
   1988 
   1989 
   1990 int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
   1991 			       const struct wpabuf *elems)
   1992 {
   1993 	struct wpabuf *buf;
   1994 	int ret;
   1995 
   1996 	if (wpa_s->wpa_state < WPA_ASSOCIATED || !elems)
   1997 		return -1;
   1998 
   1999 	wpa_printf(MSG_DEBUG, "WNM: Send Collocated Interference Report to "
   2000 		   MACSTR " (dialog token %u)",
   2001 		   MAC2STR(wpa_s->bssid), dialog_token);
   2002 
   2003 	buf = wpabuf_alloc(3 + wpabuf_len(elems));
   2004 	if (!buf)
   2005 		return -1;
   2006 
   2007 	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
   2008 	wpabuf_put_u8(buf, WNM_COLLOCATED_INTERFERENCE_REPORT);
   2009 	wpabuf_put_u8(buf, dialog_token);
   2010 	wpabuf_put_buf(buf, elems);
   2011 
   2012 	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
   2013 				  wpa_s->own_addr, wpa_s->bssid,
   2014 				  wpabuf_head_u8(buf), wpabuf_len(buf), 0);
   2015 	wpabuf_free(buf);
   2016 	return ret;
   2017 }
   2018 
   2019 
   2020 void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
   2021 			      struct wpabuf *elems)
   2022 {
   2023 	if (elems && wpabuf_len(elems) == 0) {
   2024 		wpabuf_free(elems);
   2025 		elems = NULL;
   2026 	}
   2027 
   2028 	/* NOTE: The elements are not stored as they are only send out once */
   2029 
   2030 	if (wpa_s->conf->coloc_intf_reporting && elems &&
   2031 	    wpa_s->coloc_intf_dialog_token &&
   2032 	    (wpa_s->coloc_intf_auto_report == 1 ||
   2033 	     wpa_s->coloc_intf_auto_report == 3)) {
   2034 		/* TODO: Check that there has not been less than
   2035 		 * wpa_s->coloc_intf_timeout * 200 TU from the last report.
   2036 		 */
   2037 		wnm_send_coloc_intf_report(wpa_s,
   2038 					   wpa_s->coloc_intf_dialog_token,
   2039 					   elems);
   2040 	}
   2041 
   2042 	wpabuf_free(elems);
   2043 }
   2044 
   2045 
   2046 void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s)
   2047 {
   2048 	wpa_s->coloc_intf_dialog_token = 0;
   2049 	wpa_s->coloc_intf_auto_report = 0;
   2050 }
   2051 
   2052 
   2053 bool wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
   2054 {
   2055 	if (!(wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))
   2056 		return false;
   2057 
   2058 	/*
   2059 	 * In case disassociation imminent is set, do no try to use a BSS to
   2060 	 * which we are connected.
   2061 	 */
   2062 	if (wpa_s->wnm_link_removal ||
   2063 	    !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) ||
   2064 	    is_zero_ether_addr(bss->mld_addr)) {
   2065 		if (ether_addr_equal(bss->bssid, wpa_s->wnm_dissoc_addr))
   2066 			return true;
   2067 	} else {
   2068 		if (ether_addr_equal(bss->mld_addr, wpa_s->wnm_dissoc_addr))
   2069 			return true;
   2070 	}
   2071 
   2072 	return false;
   2073 }
   2074