3 * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
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"
19 #include "ctrl_iface.h"
22 #include "hs20_supplicant.h"
24 #define MAX_TFS_IE_LEN 1024
25 #define WNM_MAX_NEIGHBOR_REPORT 10
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)
32 wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
34 return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len);
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,
45 wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
47 return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len);
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)
55 struct ieee80211_mgmt *mgmt;
58 struct wnm_sleep_element *wnmsleep_ie;
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;
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));
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)
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);
85 wnmtfs_ie_len = wpabuf_len(tfs_req);
86 wnmtfs_ie = os_malloc(wnmtfs_ie_len);
87 if (wnmtfs_ie == NULL) {
91 os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len);
93 wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
94 if (wnmtfs_ie == NULL) {
98 if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
105 wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
106 (u8 *) wnmtfs_ie, wnmtfs_ie_len);
108 mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
110 wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
111 "WNM-Sleep Request action frame");
112 os_free(wnmsleep_ie);
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,
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);
133 len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
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);
140 wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
141 "(action=%d, intval=%d)", action, intval);
143 os_free(wnmsleep_ie);
151 static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
152 const u8 *tfsresp_ie_start,
153 const u8 *tfsresp_ie_end)
155 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
156 wpa_s->bssid, NULL, NULL);
157 /* remove GTK/IGTK ?? */
159 /* set the TFS Resp IE(s) */
160 if (tfsresp_ie_start && tfsresp_ie_end &&
161 tfsresp_ie_end - tfsresp_ie_start >= 0) {
163 tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) -
165 wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
166 /* pass the TFS Resp IE(s) to driver for processing */
167 if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
170 WNM_SLEEP_TFS_RESP_IE_SET))
171 wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
176 static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
177 const u8 *frm, u16 key_len_total)
182 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid,
185 /* Install GTK/IGTK */
187 /* point to key data field */
188 ptr = (u8 *) frm + 1 + 2;
189 end = ptr + key_len_total;
190 wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
192 while (end - ptr > 1) {
193 if (2 + ptr[1] > end - ptr) {
194 wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
197 wpa_hexdump(MSG_DEBUG, "WNM: Remaining data",
202 if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
203 if (ptr[1] < 11 + 5) {
204 wpa_printf(MSG_DEBUG, "WNM: Too short GTK "
208 gtk_len = *(ptr + 4);
209 if (ptr[1] < 11 + gtk_len ||
210 gtk_len < 5 || gtk_len > 32) {
211 wpa_printf(MSG_DEBUG, "WNM: Invalid GTK "
215 wpa_wnmsleep_install_key(
217 WNM_SLEEP_SUBELEM_GTK,
220 #ifdef CONFIG_IEEE80211W
221 } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
222 if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
223 wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
227 wpa_wnmsleep_install_key(wpa_s->wpa,
228 WNM_SLEEP_SUBELEM_IGTK, ptr);
229 ptr += 10 + WPA_IGTK_LEN;
230 #endif /* CONFIG_IEEE80211W */
232 break; /* skip the loop */
237 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
238 const u8 *frm, int len)
241 * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
242 * WNM-Sleep Mode IE | TFS Response IE
244 const u8 *pos = frm; /* point to payload after the action field */
246 struct wnm_sleep_element *wnmsleep_ie = NULL;
247 /* multiple TFS Resp IE (assuming consecutive) */
248 const u8 *tfsresp_ie_start = NULL;
249 const u8 *tfsresp_ie_end = NULL;
254 key_len_total = WPA_GET_LE16(frm + 1);
256 wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d",
257 frm[0], key_len_total);
259 if (key_len_total > left) {
260 wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
263 pos += 3 + key_len_total;
264 while (pos - frm + 1 < len) {
265 u8 ie_len = *(pos + 1);
266 if (2 + ie_len > frm + len - pos) {
267 wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len);
270 wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len);
271 if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4)
272 wnmsleep_ie = (struct wnm_sleep_element *) pos;
273 else if (*pos == WLAN_EID_TFS_RESP) {
274 if (!tfsresp_ie_start)
275 tfsresp_ie_start = pos;
276 tfsresp_ie_end = pos;
278 wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
283 wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
287 if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
288 wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
289 wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
290 "frame (action=%d, intval=%d)",
291 wnmsleep_ie->action_type, wnmsleep_ie->intval);
292 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) {
293 wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start,
295 } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
296 wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total);
299 wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
300 "(action=%d, intval=%d)",
301 wnmsleep_ie->action_type, wnmsleep_ie->intval);
302 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER)
303 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
304 wpa_s->bssid, NULL, NULL);
305 else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT)
306 wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
307 wpa_s->bssid, NULL, NULL);
312 void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
316 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
317 os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
318 os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
321 wpa_s->wnm_num_neighbor_report = 0;
322 os_free(wpa_s->wnm_neighbor_report_elements);
323 wpa_s->wnm_neighbor_report_elements = NULL;
327 static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
328 u8 id, u8 elen, const u8 *pos)
331 case WNM_NEIGHBOR_TSF:
333 wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
336 rep->tsf_offset = WPA_GET_LE16(pos);
337 rep->beacon_int = WPA_GET_LE16(pos + 2);
338 rep->tsf_present = 1;
340 case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
342 wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
346 os_memcpy(rep->country, pos, 2);
347 rep->country_present = 1;
349 case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
351 wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
355 rep->preference = pos[0];
356 rep->preference_present = 1;
358 case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
359 rep->bss_term_tsf = WPA_GET_LE64(pos);
360 rep->bss_term_dur = WPA_GET_LE16(pos + 8);
361 rep->bss_term_present = 1;
363 case WNM_NEIGHBOR_BEARING:
365 wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
369 rep->bearing = WPA_GET_LE16(pos);
370 rep->distance = WPA_GET_LE32(pos + 2);
371 rep->rel_height = WPA_GET_LE16(pos + 2 + 4);
372 rep->bearing_present = 1;
374 case WNM_NEIGHBOR_MEASUREMENT_PILOT:
376 wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
380 os_free(rep->meas_pilot);
381 rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
382 if (rep->meas_pilot == NULL)
384 rep->meas_pilot->measurement_pilot = pos[0];
385 rep->meas_pilot->subelem_len = elen - 1;
386 os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1);
388 case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
390 wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
394 os_memcpy(rep->rm_capab, pos, 5);
395 rep->rm_capab_present = 1;
397 case WNM_NEIGHBOR_MULTIPLE_BSSID:
399 wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
402 os_free(rep->mul_bssid);
403 rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
404 if (rep->mul_bssid == NULL)
406 rep->mul_bssid->max_bssid_indicator = pos[0];
407 rep->mul_bssid->subelem_len = elen - 1;
408 os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1);
414 static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
416 struct wpa_bss *bss = wpa_s->current_bss;
417 const char *country = NULL;
420 const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
422 if (elem && elem[1] >= 2)
423 country = (const char *) (elem + 2);
426 return ieee80211_chan_to_freq(country, op_class, chan);
430 static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
431 const u8 *pos, u8 len,
432 struct neighbor_report *rep)
437 wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
441 os_memcpy(rep->bssid, pos, ETH_ALEN);
442 rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN);
443 rep->regulatory_class = *(pos + 10);
444 rep->channel_number = *(pos + 11);
445 rep->phy_type = *(pos + 12);
455 wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen);
458 wpa_printf(MSG_DEBUG,
459 "WNM: Truncated neighbor report subelement");
462 wnm_parse_neighbor_report_elem(rep, id, elen, pos);
467 rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class,
468 rep->channel_number);
472 static struct wpa_bss *
473 compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
477 struct wpa_bss *bss = wpa_s->current_bss;
478 struct wpa_bss *target;
483 wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
484 MAC2STR(wpa_s->bssid), bss->level);
486 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
487 struct neighbor_report *nei;
489 nei = &wpa_s->wnm_neighbor_report_elements[i];
490 if (nei->preference_present && nei->preference == 0) {
491 wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
492 MAC2STR(nei->bssid));
496 target = wpa_bss_get_bssid(wpa_s, nei->bssid);
498 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
499 " (pref %d) not found in scan results",
501 nei->preference_present ? nei->preference :
506 if (bss->ssid_len != target->ssid_len ||
507 os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
509 * TODO: Could consider allowing transition to another
510 * ESS if PMF was enabled for the association.
512 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
513 " (pref %d) in different ESS",
515 nei->preference_present ? nei->preference :
520 if (target->level < bss->level && target->level < -80) {
521 wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
522 " (pref %d) does not have sufficient signal level (%d)",
524 nei->preference_present ? nei->preference :
530 wpa_printf(MSG_DEBUG,
531 "WNM: Found an acceptable preferred transition candidate BSS "
533 MAC2STR(nei->bssid), target->level);
541 static void wnm_send_bss_transition_mgmt_resp(
542 struct wpa_supplicant *wpa_s, u8 dialog_token,
543 enum bss_trans_mgmt_status_code status, u8 delay,
544 const u8 *target_bssid)
547 struct ieee80211_mgmt *mgmt;
551 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
552 "to " MACSTR " dialog_token=%u status=%u delay=%d",
553 MAC2STR(wpa_s->bssid), dialog_token, status, delay);
554 if (!wpa_s->current_bss) {
555 wpa_printf(MSG_DEBUG,
556 "WNM: Current BSS not known - drop response");
560 mgmt = (struct ieee80211_mgmt *) buf;
561 os_memset(&buf, 0, sizeof(buf));
562 os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
563 os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
564 os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
565 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
566 WLAN_FC_STYPE_ACTION);
567 mgmt->u.action.category = WLAN_ACTION_WNM;
568 mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
569 mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
570 mgmt->u.action.u.bss_tm_resp.status_code = status;
571 mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
572 pos = mgmt->u.action.u.bss_tm_resp.variable;
574 os_memcpy(pos, target_bssid, ETH_ALEN);
576 } else if (status == WNM_BSS_TM_ACCEPT) {
578 * P802.11-REVmc clarifies that the Target BSSID field is always
579 * present when status code is zero, so use a fake value here if
580 * no BSSID is yet known.
582 os_memset(pos, 0, ETH_ALEN);
586 len = pos - (u8 *) &mgmt->u.action.category;
588 res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
589 wpa_s->own_addr, wpa_s->bssid,
590 &mgmt->u.action.category, len, 0);
592 wpa_printf(MSG_DEBUG,
593 "WNM: Failed to send BSS Transition Management Response");
598 int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
601 struct wpa_ssid *ssid = wpa_s->current_ssid;
602 enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
604 if (!wpa_s->wnm_neighbor_report_elements)
607 if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
608 &wpa_s->scan_trigger_time)) {
609 wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
610 wnm_deallocate_memory(wpa_s);
614 if (!wpa_s->current_bss ||
615 os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid,
617 wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it");
621 /* Compare the Neighbor Report and scan results */
622 bss = compare_scan_neighbor_results(wpa_s);
624 wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
625 status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
626 goto send_bss_resp_fail;
629 /* Associate to the network */
630 /* Send the BSS Management Response - Accept */
631 if (wpa_s->wnm_reply) {
632 wpa_s->wnm_reply = 0;
633 wnm_send_bss_transition_mgmt_resp(wpa_s,
634 wpa_s->wnm_dialog_token,
639 if (bss == wpa_s->current_bss) {
640 wpa_printf(MSG_DEBUG,
641 "WNM: Already associated with the preferred candidate");
642 wnm_deallocate_memory(wpa_s);
646 wpa_s->reassociate = 1;
647 wpa_supplicant_connect(wpa_s, bss, ssid);
648 wnm_deallocate_memory(wpa_s);
655 /* Send reject response for all the failures */
657 if (wpa_s->wnm_reply) {
658 wpa_s->wnm_reply = 0;
659 wnm_send_bss_transition_mgmt_resp(wpa_s,
660 wpa_s->wnm_dialog_token,
663 wnm_deallocate_memory(wpa_s);
669 static int cand_pref_compar(const void *a, const void *b)
671 const struct neighbor_report *aa = a;
672 const struct neighbor_report *bb = b;
674 if (!aa->preference_present && !bb->preference_present)
676 if (!aa->preference_present)
678 if (!bb->preference_present)
680 if (bb->preference > aa->preference)
682 if (bb->preference < aa->preference)
688 static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s)
690 if (!wpa_s->wnm_neighbor_report_elements)
692 qsort(wpa_s->wnm_neighbor_report_elements,
693 wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report),
698 static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
702 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List");
703 if (!wpa_s->wnm_neighbor_report_elements)
705 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
706 struct neighbor_report *nei;
708 nei = &wpa_s->wnm_neighbor_report_elements[i];
709 wpa_printf(MSG_DEBUG, "%u: " MACSTR
710 " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d",
711 i, MAC2STR(nei->bssid), nei->bssid_info,
712 nei->regulatory_class,
713 nei->channel_number, nei->phy_type,
714 nei->preference_present ? nei->preference : -1,
720 static int chan_supported(struct wpa_supplicant *wpa_s, int freq)
724 for (i = 0; i < wpa_s->hw.num_modes; i++) {
725 struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
728 for (j = 0; j < mode->num_channels; j++) {
729 struct hostapd_channel_data *chan;
731 chan = &mode->channels[j];
732 if (chan->freq == freq &&
733 !(chan->flag & HOSTAPD_CHAN_DISABLED))
742 static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
748 if (!wpa_s->wnm_neighbor_report_elements)
751 if (wpa_s->hw.modes == NULL)
754 os_free(wpa_s->next_scan_freqs);
755 wpa_s->next_scan_freqs = NULL;
757 freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int));
761 for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
762 struct neighbor_report *nei;
764 nei = &wpa_s->wnm_neighbor_report_elements[i];
765 if (nei->freq <= 0) {
766 wpa_printf(MSG_DEBUG,
767 "WNM: Unknown neighbor operating frequency for "
768 MACSTR " - scan all channels",
769 MAC2STR(nei->bssid));
773 if (chan_supported(wpa_s, nei->freq))
774 add_freq(freqs, &num_freqs, nei->freq);
777 if (num_freqs == 0) {
782 wpa_printf(MSG_DEBUG,
783 "WNM: Scan %d frequencies based on transition candidate list",
785 wpa_s->next_scan_freqs = freqs;
789 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
790 const u8 *pos, const u8 *end,
793 unsigned int beacon_int;
799 if (wpa_s->current_bss)
800 beacon_int = wpa_s->current_bss->beacon_int;
802 beacon_int = 100; /* best guess */
804 wpa_s->wnm_dialog_token = pos[0];
805 wpa_s->wnm_mode = pos[1];
806 wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
808 wpa_s->wnm_reply = reply;
810 wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
811 "dialog_token=%u request_mode=0x%x "
812 "disassoc_timer=%u validity_interval=%u",
813 wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
814 wpa_s->wnm_dissoc_timer, valid_int);
818 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
819 if (end - pos < 12) {
820 wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
823 os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
824 pos += 12; /* BSS Termination Duration */
827 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
830 if (end - pos < 1 || 1 + pos[0] > end - pos) {
831 wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
832 "Management Request (URL)");
835 os_memcpy(url, pos + 1, pos[0]);
839 wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
840 wpa_sm_pmf_enabled(wpa_s->wpa),
841 wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
844 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
845 wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
846 "Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
847 if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) {
848 /* TODO: mark current BSS less preferred for
850 wpa_printf(MSG_DEBUG, "Trying to find another BSS");
851 wpa_supplicant_req_scan(wpa_s, 0, 0);
855 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
856 unsigned int valid_ms;
858 wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
859 wnm_deallocate_memory(wpa_s);
860 wpa_s->wnm_neighbor_report_elements = os_calloc(
861 WNM_MAX_NEIGHBOR_REPORT,
862 sizeof(struct neighbor_report));
863 if (wpa_s->wnm_neighbor_report_elements == NULL)
866 while (end - pos >= 2 &&
867 wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
872 wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
874 if (len > end - pos) {
875 wpa_printf(MSG_DEBUG, "WNM: Truncated request");
878 if (tag == WLAN_EID_NEIGHBOR_REPORT) {
879 struct neighbor_report *rep;
880 rep = &wpa_s->wnm_neighbor_report_elements[
881 wpa_s->wnm_num_neighbor_report];
882 wnm_parse_neighbor_report(wpa_s, pos, len, rep);
886 wpa_s->wnm_num_neighbor_report++;
888 wnm_sort_cand_list(wpa_s);
889 wnm_dump_cand_list(wpa_s);
890 valid_ms = valid_int * beacon_int * 128 / 125;
891 wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
893 os_get_reltime(&wpa_s->wnm_cand_valid_until);
894 wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
895 wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
896 wpa_s->wnm_cand_valid_until.sec +=
897 wpa_s->wnm_cand_valid_until.usec / 1000000;
898 wpa_s->wnm_cand_valid_until.usec %= 1000000;
899 os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
901 if (wpa_s->last_scan_res_used > 0) {
902 struct os_reltime now;
904 os_get_reltime(&now);
905 if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) {
906 wpa_printf(MSG_DEBUG,
907 "WNM: Try to use recent scan results");
908 if (wnm_scan_process(wpa_s, 0) > 0)
910 wpa_printf(MSG_DEBUG,
911 "WNM: No match in previous scan results - try a new scan");
915 wnm_set_scan_freqs(wpa_s);
916 wpa_supplicant_req_scan(wpa_s, 0, 0);
918 enum bss_trans_mgmt_status_code status;
919 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
920 status = WNM_BSS_TM_ACCEPT;
922 wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
923 status = WNM_BSS_TM_REJECT_UNSPECIFIED;
925 wnm_send_bss_transition_mgmt_resp(wpa_s,
926 wpa_s->wnm_dialog_token,
932 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
936 struct ieee80211_mgmt *mgmt;
940 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
941 MACSTR " query_reason=%u",
942 MAC2STR(wpa_s->bssid), query_reason);
944 mgmt = (struct ieee80211_mgmt *) buf;
945 os_memset(&buf, 0, sizeof(buf));
946 os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
947 os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
948 os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
949 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
950 WLAN_FC_STYPE_ACTION);
951 mgmt->u.action.category = WLAN_ACTION_WNM;
952 mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY;
953 mgmt->u.action.u.bss_tm_query.dialog_token = 1;
954 mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
955 pos = mgmt->u.action.u.bss_tm_query.variable;
957 len = pos - (u8 *) &mgmt->u.action.category;
959 ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
960 wpa_s->own_addr, wpa_s->bssid,
961 &mgmt->u.action.category, len, 0);
967 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
968 const u8 *sa, const u8 *data,
971 const u8 *pos, *end, *next;
977 while (end - pos > 1) {
980 wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u",
982 if (ie_len > end - pos) {
983 wpa_printf(MSG_DEBUG, "WNM: Not enough room for "
992 wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u",
993 WPA_GET_BE24(pos), pos[3]);
996 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
997 WPA_GET_BE24(pos) == OUI_WFA &&
998 pos[3] == HS20_WNM_SUB_REM_NEEDED) {
999 /* Subscription Remediation subelement */
1005 wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation "
1007 ie_end = pos + ie_len;
1011 wpa_printf(MSG_DEBUG, "WNM: No Server URL included");
1015 if (url_len + 1 > ie_end - pos) {
1016 wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
1018 (int) (ie_end - pos));
1021 url = os_malloc(url_len + 1);
1024 os_memcpy(url, pos, url_len);
1025 url[url_len] = '\0';
1026 osu_method = pos[url_len];
1028 hs20_rx_subscription_remediation(wpa_s, url,
1035 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 &&
1036 WPA_GET_BE24(pos) == OUI_WFA &&
1037 pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) {
1044 ie_end = pos + ie_len;
1047 reauth_delay = WPA_GET_LE16(pos);
1050 wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication "
1051 "Imminent - Reason Code %u "
1052 "Re-Auth Delay %u URL Length %u",
1053 code, reauth_delay, url_len);
1054 if (url_len > ie_end - pos)
1056 url = os_malloc(url_len + 1);
1059 os_memcpy(url, pos, url_len);
1060 url[url_len] = '\0';
1061 hs20_rx_deauth_imminent_notice(wpa_s, code,
1067 #endif /* CONFIG_HS20 */
1074 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s,
1075 const u8 *sa, const u8 *frm, int len)
1077 const u8 *pos, *end;
1078 u8 dialog_token, type;
1080 /* Dialog Token [1] | Type [1] | Subelements */
1082 if (len < 2 || sa == NULL)
1086 dialog_token = *pos++;
1089 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request "
1090 "(dialog_token %u type %u sa " MACSTR ")",
1091 dialog_token, type, MAC2STR(sa));
1092 wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements",
1095 if (wpa_s->wpa_state != WPA_COMPLETED ||
1096 os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
1097 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not "
1098 "from our AP - ignore it");
1104 ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos);
1107 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown "
1108 "WNM-Notification type %u", type);
1114 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
1115 const struct ieee80211_mgmt *mgmt, size_t len)
1117 const u8 *pos, *end;
1120 if (len < IEEE80211_HDRLEN + 2)
1123 pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1;
1125 end = ((const u8 *) mgmt) + len;
1127 wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
1128 act, MAC2STR(mgmt->sa));
1129 if (wpa_s->wpa_state < WPA_ASSOCIATED ||
1130 os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
1131 wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
1137 case WNM_BSS_TRANS_MGMT_REQ:
1138 ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
1139 !(mgmt->da[0] & 0x01));
1141 case WNM_SLEEP_MODE_RESP:
1142 ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos);
1144 case WNM_NOTIFICATION_REQ:
1145 ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
1148 wpa_printf(MSG_ERROR, "WNM: Unknown request");