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/wpa_ctrl.h" 14 #include "rsn_supp/wpa.h" 15 #include "wpa_supplicant_i.h" 16 #include "driver_i.h" 17 #include "scan.h" 18 #include "ctrl_iface.h" 19 #include "bss.h" 20 #include "wnm_sta.h" 21 #include "hs20_supplicant.h" 22 23 #define MAX_TFS_IE_LEN 1024 24 #define WNM_MAX_NEIGHBOR_REPORT 10 25 26 27 /* get the TFS IE from driver */ 28 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, 29 u16 *buf_len, enum wnm_oper oper) 30 { 31 wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); 32 33 return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); 34 } 35 36 37 /* set the TFS IE to driver */ 38 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, 39 const u8 *addr, u8 *buf, u16 *buf_len, 40 enum wnm_oper oper) 41 { 42 wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); 43 44 return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len); 45 } 46 47 48 /* MLME-SLEEPMODE.request */ 49 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 50 u8 action, u16 intval, struct wpabuf *tfs_req) 51 { 52 struct ieee80211_mgmt *mgmt; 53 int res; 54 size_t len; 55 struct wnm_sleep_element *wnmsleep_ie; 56 u8 *wnmtfs_ie; 57 u8 wnmsleep_ie_len; 58 u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ 59 enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : 60 WNM_SLEEP_TFS_REQ_IE_NONE; 61 62 wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " 63 "action=%s to " MACSTR, 64 action == 0 ? "enter" : "exit", 65 MAC2STR(wpa_s->bssid)); 66 67 /* WNM-Sleep Mode IE */ 68 wnmsleep_ie_len = sizeof(struct wnm_sleep_element); 69 wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); 70 if (wnmsleep_ie == NULL) 71 return -1; 72 wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; 73 wnmsleep_ie->len = wnmsleep_ie_len - 2; 74 wnmsleep_ie->action_type = action; 75 wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; 76 wnmsleep_ie->intval = host_to_le16(intval); 77 wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", 78 (u8 *) wnmsleep_ie, wnmsleep_ie_len); 79 80 /* TFS IE(s) */ 81 if (tfs_req) { 82 wnmtfs_ie_len = wpabuf_len(tfs_req); 83 wnmtfs_ie = os_malloc(wnmtfs_ie_len); 84 if (wnmtfs_ie == NULL) { 85 os_free(wnmsleep_ie); 86 return -1; 87 } 88 os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); 89 } else { 90 wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); 91 if (wnmtfs_ie == NULL) { 92 os_free(wnmsleep_ie); 93 return -1; 94 } 95 if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, 96 tfs_oper)) { 97 wnmtfs_ie_len = 0; 98 os_free(wnmtfs_ie); 99 wnmtfs_ie = NULL; 100 } 101 } 102 wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", 103 (u8 *) wnmtfs_ie, wnmtfs_ie_len); 104 105 mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); 106 if (mgmt == NULL) { 107 wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 108 "WNM-Sleep Request action frame"); 109 os_free(wnmsleep_ie); 110 os_free(wnmtfs_ie); 111 return -1; 112 } 113 114 os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 115 os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 116 os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 117 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 118 WLAN_FC_STYPE_ACTION); 119 mgmt->u.action.category = WLAN_ACTION_WNM; 120 mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; 121 mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; 122 os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, 123 wnmsleep_ie_len); 124 /* copy TFS IE here */ 125 if (wnmtfs_ie_len > 0) { 126 os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + 127 wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); 128 } 129 130 len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + 131 wnmtfs_ie_len; 132 133 res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 134 wpa_s->own_addr, wpa_s->bssid, 135 &mgmt->u.action.category, len, 0); 136 if (res < 0) 137 wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " 138 "(action=%d, intval=%d)", action, intval); 139 140 os_free(wnmsleep_ie); 141 os_free(wnmtfs_ie); 142 os_free(mgmt); 143 144 return res; 145 } 146 147 148 static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, 149 u8 *tfsresp_ie_start, 150 u8 *tfsresp_ie_end) 151 { 152 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, 153 wpa_s->bssid, NULL, NULL); 154 /* remove GTK/IGTK ?? */ 155 156 /* set the TFS Resp IE(s) */ 157 if (tfsresp_ie_start && tfsresp_ie_end && 158 tfsresp_ie_end - tfsresp_ie_start >= 0) { 159 u16 tfsresp_ie_len; 160 tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - 161 tfsresp_ie_start; 162 wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); 163 /* pass the TFS Resp IE(s) to driver for processing */ 164 if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, 165 tfsresp_ie_start, 166 &tfsresp_ie_len, 167 WNM_SLEEP_TFS_RESP_IE_SET)) 168 wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); 169 } 170 } 171 172 173 static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, 174 const u8 *frm, u16 key_len_total) 175 { 176 u8 *ptr, *end; 177 u8 gtk_len; 178 179 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, 180 NULL, NULL); 181 182 /* Install GTK/IGTK */ 183 184 /* point to key data field */ 185 ptr = (u8 *) frm + 1 + 2; 186 end = ptr + key_len_total; 187 wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); 188 189 while (ptr + 1 < end) { 190 if (ptr + 2 + ptr[1] > end) { 191 wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " 192 "length"); 193 if (end > ptr) { 194 wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", 195 ptr, end - ptr); 196 } 197 break; 198 } 199 if (*ptr == WNM_SLEEP_SUBELEM_GTK) { 200 if (ptr[1] < 11 + 5) { 201 wpa_printf(MSG_DEBUG, "WNM: Too short GTK " 202 "subelem"); 203 break; 204 } 205 gtk_len = *(ptr + 4); 206 if (ptr[1] < 11 + gtk_len || 207 gtk_len < 5 || gtk_len > 32) { 208 wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " 209 "subelem"); 210 break; 211 } 212 wpa_wnmsleep_install_key( 213 wpa_s->wpa, 214 WNM_SLEEP_SUBELEM_GTK, 215 ptr); 216 ptr += 13 + gtk_len; 217 #ifdef CONFIG_IEEE80211W 218 } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { 219 if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { 220 wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " 221 "subelem"); 222 break; 223 } 224 wpa_wnmsleep_install_key(wpa_s->wpa, 225 WNM_SLEEP_SUBELEM_IGTK, ptr); 226 ptr += 10 + WPA_IGTK_LEN; 227 #endif /* CONFIG_IEEE80211W */ 228 } else 229 break; /* skip the loop */ 230 } 231 } 232 233 234 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 235 const u8 *frm, int len) 236 { 237 /* 238 * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | 239 * WNM-Sleep Mode IE | TFS Response IE 240 */ 241 u8 *pos = (u8 *) frm; /* point to payload after the action field */ 242 u16 key_len_total; 243 struct wnm_sleep_element *wnmsleep_ie = NULL; 244 /* multiple TFS Resp IE (assuming consecutive) */ 245 u8 *tfsresp_ie_start = NULL; 246 u8 *tfsresp_ie_end = NULL; 247 248 if (len < 3) 249 return; 250 key_len_total = WPA_GET_LE16(frm + 1); 251 252 wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", 253 frm[0], key_len_total); 254 pos += 3 + key_len_total; 255 if (pos > frm + len) { 256 wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); 257 return; 258 } 259 while (pos - frm < len) { 260 u8 ie_len = *(pos + 1); 261 if (pos + 2 + ie_len > frm + len) { 262 wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); 263 break; 264 } 265 wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); 266 if (*pos == WLAN_EID_WNMSLEEP) 267 wnmsleep_ie = (struct wnm_sleep_element *) pos; 268 else if (*pos == WLAN_EID_TFS_RESP) { 269 if (!tfsresp_ie_start) 270 tfsresp_ie_start = pos; 271 tfsresp_ie_end = pos; 272 } else 273 wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); 274 pos += ie_len + 2; 275 } 276 277 if (!wnmsleep_ie) { 278 wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); 279 return; 280 } 281 282 if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || 283 wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { 284 wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " 285 "frame (action=%d, intval=%d)", 286 wnmsleep_ie->action_type, wnmsleep_ie->intval); 287 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { 288 wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, 289 tfsresp_ie_end); 290 } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { 291 wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); 292 } 293 } else { 294 wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " 295 "(action=%d, intval=%d)", 296 wnmsleep_ie->action_type, wnmsleep_ie->intval); 297 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) 298 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, 299 wpa_s->bssid, NULL, NULL); 300 else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) 301 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, 302 wpa_s->bssid, NULL, NULL); 303 } 304 } 305 306 307 void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) 308 { 309 int i; 310 311 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { 312 os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info); 313 os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str); 314 os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can); 315 os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur); 316 os_free(wpa_s->wnm_neighbor_report_elements[i].bearing); 317 os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); 318 os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap); 319 os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); 320 } 321 322 wpa_s->wnm_num_neighbor_report = 0; 323 os_free(wpa_s->wnm_neighbor_report_elements); 324 wpa_s->wnm_neighbor_report_elements = NULL; 325 } 326 327 328 static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, 329 u8 id, u8 elen, const u8 *pos) 330 { 331 switch (id) { 332 case WNM_NEIGHBOR_TSF: 333 if (elen < 2 + 2) { 334 wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); 335 break; 336 } 337 os_free(rep->tsf_info); 338 rep->tsf_info = os_zalloc(sizeof(struct tsf_info)); 339 if (rep->tsf_info == NULL) 340 break; 341 os_memcpy(rep->tsf_info->tsf_offset, pos, 2); 342 os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2); 343 break; 344 case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: 345 if (elen < 2) { 346 wpa_printf(MSG_DEBUG, "WNM: Too short condensed " 347 "country string"); 348 break; 349 } 350 os_free(rep->con_coun_str); 351 rep->con_coun_str = 352 os_zalloc(sizeof(struct condensed_country_string)); 353 if (rep->con_coun_str == NULL) 354 break; 355 os_memcpy(rep->con_coun_str->country_string, pos, 2); 356 break; 357 case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: 358 if (elen < 1) { 359 wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " 360 "candidate"); 361 break; 362 } 363 os_free(rep->bss_tran_can); 364 rep->bss_tran_can = 365 os_zalloc(sizeof(struct bss_transition_candidate)); 366 if (rep->bss_tran_can == NULL) 367 break; 368 rep->bss_tran_can->preference = pos[0]; 369 break; 370 case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: 371 if (elen < 10) { 372 wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination " 373 "duration"); 374 break; 375 } 376 os_free(rep->bss_term_dur); 377 rep->bss_term_dur = 378 os_zalloc(sizeof(struct bss_termination_duration)); 379 if (rep->bss_term_dur == NULL) 380 break; 381 os_memcpy(rep->bss_term_dur->duration, pos, 10); 382 break; 383 case WNM_NEIGHBOR_BEARING: 384 if (elen < 8) { 385 wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " 386 "bearing"); 387 break; 388 } 389 os_free(rep->bearing); 390 rep->bearing = os_zalloc(sizeof(struct bearing)); 391 if (rep->bearing == NULL) 392 break; 393 os_memcpy(rep->bearing->bearing, pos, 8); 394 break; 395 case WNM_NEIGHBOR_MEASUREMENT_PILOT: 396 if (elen < 1) { 397 wpa_printf(MSG_DEBUG, "WNM: Too short measurement " 398 "pilot"); 399 break; 400 } 401 os_free(rep->meas_pilot); 402 rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); 403 if (rep->meas_pilot == NULL) 404 break; 405 rep->meas_pilot->measurement_pilot = pos[0]; 406 rep->meas_pilot->subelem_len = elen - 1; 407 os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); 408 break; 409 case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: 410 if (elen < 5) { 411 wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " 412 "capabilities"); 413 break; 414 } 415 os_free(rep->rrm_cap); 416 rep->rrm_cap = 417 os_zalloc(sizeof(struct rrm_enabled_capabilities)); 418 if (rep->rrm_cap == NULL) 419 break; 420 os_memcpy(rep->rrm_cap->capabilities, pos, 5); 421 break; 422 case WNM_NEIGHBOR_MULTIPLE_BSSID: 423 if (elen < 1) { 424 wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); 425 break; 426 } 427 os_free(rep->mul_bssid); 428 rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); 429 if (rep->mul_bssid == NULL) 430 break; 431 rep->mul_bssid->max_bssid_indicator = pos[0]; 432 rep->mul_bssid->subelem_len = elen - 1; 433 os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); 434 break; 435 } 436 } 437 438 439 static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, 440 const u8 *pos, u8 len, 441 struct neighbor_report *rep) 442 { 443 u8 left = len; 444 445 if (left < 13) { 446 wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); 447 return; 448 } 449 450 os_memcpy(rep->bssid, pos, ETH_ALEN); 451 os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4); 452 rep->regulatory_class = *(pos + 10); 453 rep->channel_number = *(pos + 11); 454 rep->phy_type = *(pos + 12); 455 456 pos += 13; 457 left -= 13; 458 459 while (left >= 2) { 460 u8 id, elen; 461 462 id = *pos++; 463 elen = *pos++; 464 wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); 465 left -= 2; 466 if (elen > left) { 467 wpa_printf(MSG_DEBUG, 468 "WNM: Truncated neighbor report subelement"); 469 break; 470 } 471 wnm_parse_neighbor_report_elem(rep, id, elen, pos); 472 left -= elen; 473 pos += elen; 474 } 475 } 476 477 478 static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, 479 struct wpa_scan_results *scan_res, 480 struct neighbor_report *neigh_rep, 481 u8 num_neigh_rep, u8 *bssid_to_connect) 482 { 483 484 u8 i, j; 485 486 if (scan_res == NULL || num_neigh_rep == 0 || !wpa_s->current_bss) 487 return 0; 488 489 wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", 490 MAC2STR(wpa_s->bssid), wpa_s->current_bss->level); 491 492 for (i = 0; i < num_neigh_rep; i++) { 493 for (j = 0; j < scan_res->num; j++) { 494 /* Check for a better RSSI AP */ 495 if (os_memcmp(scan_res->res[j]->bssid, 496 neigh_rep[i].bssid, ETH_ALEN) == 0 && 497 scan_res->res[j]->level > 498 wpa_s->current_bss->level) { 499 /* Got a BSSID with better RSSI value */ 500 os_memcpy(bssid_to_connect, neigh_rep[i].bssid, 501 ETH_ALEN); 502 wpa_printf(MSG_DEBUG, "Found a BSS " MACSTR 503 " with better scan RSSI %d", 504 MAC2STR(scan_res->res[j]->bssid), 505 scan_res->res[j]->level); 506 return 1; 507 } 508 wpa_printf(MSG_DEBUG, "scan_res[%d] " MACSTR 509 " RSSI %d", j, 510 MAC2STR(scan_res->res[j]->bssid), 511 scan_res->res[j]->level); 512 } 513 } 514 515 return 0; 516 } 517 518 519 static void wnm_send_bss_transition_mgmt_resp( 520 struct wpa_supplicant *wpa_s, u8 dialog_token, 521 enum bss_trans_mgmt_status_code status, u8 delay, 522 const u8 *target_bssid) 523 { 524 u8 buf[1000], *pos; 525 struct ieee80211_mgmt *mgmt; 526 size_t len; 527 528 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " 529 "to " MACSTR " dialog_token=%u status=%u delay=%d", 530 MAC2STR(wpa_s->bssid), dialog_token, status, delay); 531 532 mgmt = (struct ieee80211_mgmt *) buf; 533 os_memset(&buf, 0, sizeof(buf)); 534 os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 535 os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 536 os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 537 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 538 WLAN_FC_STYPE_ACTION); 539 mgmt->u.action.category = WLAN_ACTION_WNM; 540 mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; 541 mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; 542 mgmt->u.action.u.bss_tm_resp.status_code = status; 543 mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; 544 pos = mgmt->u.action.u.bss_tm_resp.variable; 545 if (target_bssid) { 546 os_memcpy(pos, target_bssid, ETH_ALEN); 547 pos += ETH_ALEN; 548 } else if (status == WNM_BSS_TM_ACCEPT) { 549 /* 550 * P802.11-REVmc clarifies that the Target BSSID field is always 551 * present when status code is zero, so use a fake value here if 552 * no BSSID is yet known. 553 */ 554 os_memset(pos, 0, ETH_ALEN); 555 pos += ETH_ALEN; 556 } 557 558 len = pos - (u8 *) &mgmt->u.action.category; 559 560 wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 561 wpa_s->own_addr, wpa_s->bssid, 562 &mgmt->u.action.category, len, 0); 563 } 564 565 566 void wnm_scan_response(struct wpa_supplicant *wpa_s, 567 struct wpa_scan_results *scan_res) 568 { 569 u8 bssid[ETH_ALEN]; 570 571 if (scan_res == NULL) { 572 wpa_printf(MSG_ERROR, "Scan result is NULL"); 573 goto send_bss_resp_fail; 574 } 575 576 /* Compare the Neighbor Report and scan results */ 577 if (compare_scan_neighbor_results(wpa_s, scan_res, 578 wpa_s->wnm_neighbor_report_elements, 579 wpa_s->wnm_num_neighbor_report, 580 bssid) == 1) { 581 /* Associate to the network */ 582 struct wpa_bss *bss; 583 struct wpa_ssid *ssid = wpa_s->current_ssid; 584 585 bss = wpa_bss_get_bssid(wpa_s, bssid); 586 if (!bss) { 587 wpa_printf(MSG_DEBUG, "WNM: Target AP not found from " 588 "BSS table"); 589 goto send_bss_resp_fail; 590 } 591 592 /* Send the BSS Management Response - Accept */ 593 if (wpa_s->wnm_reply) { 594 wnm_send_bss_transition_mgmt_resp(wpa_s, 595 wpa_s->wnm_dialog_token, 596 WNM_BSS_TM_ACCEPT, 597 0, bssid); 598 } 599 600 wpa_s->reassociate = 1; 601 wpa_supplicant_connect(wpa_s, bss, ssid); 602 wnm_deallocate_memory(wpa_s); 603 return; 604 } 605 606 /* Send reject response for all the failures */ 607 send_bss_resp_fail: 608 wnm_deallocate_memory(wpa_s); 609 if (wpa_s->wnm_reply) { 610 wnm_send_bss_transition_mgmt_resp(wpa_s, 611 wpa_s->wnm_dialog_token, 612 WNM_BSS_TM_REJECT_UNSPECIFIED, 613 0, NULL); 614 } 615 return; 616 } 617 618 619 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, 620 const u8 *pos, const u8 *end, 621 int reply) 622 { 623 if (pos + 5 > end) 624 return; 625 626 wpa_s->wnm_dialog_token = pos[0]; 627 wpa_s->wnm_mode = pos[1]; 628 wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); 629 wpa_s->wnm_validity_interval = pos[4]; 630 wpa_s->wnm_reply = reply; 631 632 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " 633 "dialog_token=%u request_mode=0x%x " 634 "disassoc_timer=%u validity_interval=%u", 635 wpa_s->wnm_dialog_token, wpa_s->wnm_mode, 636 wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval); 637 638 pos += 5; 639 640 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { 641 if (pos + 12 > end) { 642 wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); 643 return; 644 } 645 os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); 646 pos += 12; /* BSS Termination Duration */ 647 } 648 649 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { 650 char url[256]; 651 unsigned int beacon_int; 652 653 if (pos + 1 > end || pos + 1 + pos[0] > end) { 654 wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " 655 "Management Request (URL)"); 656 return; 657 } 658 os_memcpy(url, pos + 1, pos[0]); 659 url[pos[0]] = '\0'; 660 pos += 1 + pos[0]; 661 662 if (wpa_s->current_bss) 663 beacon_int = wpa_s->current_bss->beacon_int; 664 else 665 beacon_int = 100; /* best guess */ 666 667 wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", 668 wpa_sm_pmf_enabled(wpa_s->wpa), 669 wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); 670 } 671 672 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { 673 wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " 674 "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); 675 if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { 676 /* TODO: mark current BSS less preferred for 677 * selection */ 678 wpa_printf(MSG_DEBUG, "Trying to find another BSS"); 679 wpa_supplicant_req_scan(wpa_s, 0, 0); 680 } 681 } 682 683 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { 684 wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); 685 wpa_s->wnm_num_neighbor_report = 0; 686 os_free(wpa_s->wnm_neighbor_report_elements); 687 wpa_s->wnm_neighbor_report_elements = os_zalloc( 688 WNM_MAX_NEIGHBOR_REPORT * 689 sizeof(struct neighbor_report)); 690 if (wpa_s->wnm_neighbor_report_elements == NULL) 691 return; 692 693 while (pos + 2 <= end && 694 wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) 695 { 696 u8 tag = *pos++; 697 u8 len = *pos++; 698 699 wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", 700 tag); 701 if (pos + len > end) { 702 wpa_printf(MSG_DEBUG, "WNM: Truncated request"); 703 return; 704 } 705 if (tag == WLAN_EID_NEIGHBOR_REPORT) { 706 struct neighbor_report *rep; 707 rep = &wpa_s->wnm_neighbor_report_elements[ 708 wpa_s->wnm_num_neighbor_report]; 709 wnm_parse_neighbor_report(wpa_s, pos, len, rep); 710 } 711 712 pos += len; 713 wpa_s->wnm_num_neighbor_report++; 714 } 715 716 wpa_s->scan_res_handler = wnm_scan_response; 717 wpa_supplicant_req_scan(wpa_s, 0, 0); 718 } else if (reply) { 719 enum bss_trans_mgmt_status_code status; 720 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) 721 status = WNM_BSS_TM_ACCEPT; 722 else { 723 wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); 724 status = WNM_BSS_TM_REJECT_UNSPECIFIED; 725 } 726 wnm_send_bss_transition_mgmt_resp(wpa_s, 727 wpa_s->wnm_dialog_token, 728 status, 0, NULL); 729 } 730 } 731 732 733 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, 734 u8 query_reason) 735 { 736 u8 buf[1000], *pos; 737 struct ieee80211_mgmt *mgmt; 738 size_t len; 739 int ret; 740 741 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " 742 MACSTR " query_reason=%u", 743 MAC2STR(wpa_s->bssid), query_reason); 744 745 mgmt = (struct ieee80211_mgmt *) buf; 746 os_memset(&buf, 0, sizeof(buf)); 747 os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 748 os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 749 os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 750 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 751 WLAN_FC_STYPE_ACTION); 752 mgmt->u.action.category = WLAN_ACTION_WNM; 753 mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; 754 mgmt->u.action.u.bss_tm_query.dialog_token = 1; 755 mgmt->u.action.u.bss_tm_query.query_reason = query_reason; 756 pos = mgmt->u.action.u.bss_tm_query.variable; 757 758 len = pos - (u8 *) &mgmt->u.action.category; 759 760 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, 761 wpa_s->own_addr, wpa_s->bssid, 762 &mgmt->u.action.category, len, 0); 763 764 return ret; 765 } 766 767 768 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, 769 const u8 *sa, const u8 *data, 770 int len) 771 { 772 const u8 *pos, *end, *next; 773 u8 ie, ie_len; 774 775 pos = data; 776 end = data + len; 777 778 while (pos + 1 < end) { 779 ie = *pos++; 780 ie_len = *pos++; 781 wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", 782 ie, ie_len); 783 if (ie_len > end - pos) { 784 wpa_printf(MSG_DEBUG, "WNM: Not enough room for " 785 "subelement"); 786 break; 787 } 788 next = pos + ie_len; 789 if (ie_len < 4) { 790 pos = next; 791 continue; 792 } 793 wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", 794 WPA_GET_BE24(pos), pos[3]); 795 796 #ifdef CONFIG_HS20 797 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && 798 WPA_GET_BE24(pos) == OUI_WFA && 799 pos[3] == HS20_WNM_SUB_REM_NEEDED) { 800 /* Subscription Remediation subelement */ 801 const u8 *ie_end; 802 u8 url_len; 803 char *url; 804 u8 osu_method; 805 806 wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " 807 "subelement"); 808 ie_end = pos + ie_len; 809 pos += 4; 810 url_len = *pos++; 811 if (url_len == 0) { 812 wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); 813 url = NULL; 814 osu_method = 1; 815 } else { 816 if (pos + url_len + 1 > ie_end) { 817 wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", 818 url_len, 819 (int) (ie_end - pos)); 820 break; 821 } 822 url = os_malloc(url_len + 1); 823 if (url == NULL) 824 break; 825 os_memcpy(url, pos, url_len); 826 url[url_len] = '\0'; 827 osu_method = pos[url_len]; 828 } 829 hs20_rx_subscription_remediation(wpa_s, url, 830 osu_method); 831 os_free(url); 832 pos = next; 833 continue; 834 } 835 836 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && 837 WPA_GET_BE24(pos) == OUI_WFA && 838 pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { 839 const u8 *ie_end; 840 u8 url_len; 841 char *url; 842 u8 code; 843 u16 reauth_delay; 844 845 ie_end = pos + ie_len; 846 pos += 4; 847 code = *pos++; 848 reauth_delay = WPA_GET_LE16(pos); 849 pos += 2; 850 url_len = *pos++; 851 wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " 852 "Imminent - Reason Code %u " 853 "Re-Auth Delay %u URL Length %u", 854 code, reauth_delay, url_len); 855 if (pos + url_len > ie_end) 856 break; 857 url = os_malloc(url_len + 1); 858 if (url == NULL) 859 break; 860 os_memcpy(url, pos, url_len); 861 url[url_len] = '\0'; 862 hs20_rx_deauth_imminent_notice(wpa_s, code, 863 reauth_delay, url); 864 os_free(url); 865 pos = next; 866 continue; 867 } 868 #endif /* CONFIG_HS20 */ 869 870 pos = next; 871 } 872 } 873 874 875 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, 876 const u8 *sa, const u8 *frm, int len) 877 { 878 const u8 *pos, *end; 879 u8 dialog_token, type; 880 881 /* Dialog Token [1] | Type [1] | Subelements */ 882 883 if (len < 2 || sa == NULL) 884 return; 885 end = frm + len; 886 pos = frm; 887 dialog_token = *pos++; 888 type = *pos++; 889 890 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " 891 "(dialog_token %u type %u sa " MACSTR ")", 892 dialog_token, type, MAC2STR(sa)); 893 wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", 894 pos, end - pos); 895 896 if (wpa_s->wpa_state != WPA_COMPLETED || 897 os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { 898 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " 899 "from our AP - ignore it"); 900 return; 901 } 902 903 switch (type) { 904 case 1: 905 ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); 906 break; 907 default: 908 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " 909 "WNM-Notification type %u", type); 910 break; 911 } 912 } 913 914 915 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, 916 const struct ieee80211_mgmt *mgmt, size_t len) 917 { 918 const u8 *pos, *end; 919 u8 act; 920 921 if (len < IEEE80211_HDRLEN + 2) 922 return; 923 924 pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; 925 act = *pos++; 926 end = ((const u8 *) mgmt) + len; 927 928 wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, 929 act, MAC2STR(mgmt->sa)); 930 if (wpa_s->wpa_state < WPA_ASSOCIATED || 931 os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 932 wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " 933 "frame"); 934 return; 935 } 936 937 switch (act) { 938 case WNM_BSS_TRANS_MGMT_REQ: 939 ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, 940 !(mgmt->da[0] & 0x01)); 941 break; 942 case WNM_SLEEP_MODE_RESP: 943 ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); 944 break; 945 case WNM_NOTIFICATION_REQ: 946 ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); 947 break; 948 default: 949 wpa_printf(MSG_ERROR, "WNM: Unknown request"); 950 break; 951 } 952 } 953