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