Home | History | Annotate | Download | only in wpa_supplicant
      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 */
     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 */
     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 */
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 *
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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