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/wpa_ctrl.h"
14 #include "rsn_supp/wpa.h"
15 #include "wpa_supplicant_i.h"
18 #include "ctrl_iface.h"
21 #include "hs20_supplicant.h"
23 #define MAX_TFS_IE_LEN 1024
24 #define WNM_MAX_NEIGHBOR_REPORT 10
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
)
31 wpa_printf(MSG_DEBUG
, "%s: TFS get operation %d", __func__
, oper
);
33 return wpa_drv_wnm_oper(wpa_s
, oper
, wpa_s
->bssid
, buf
, buf_len
);
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
,
42 wpa_printf(MSG_DEBUG
, "%s: TFS set operation %d", __func__
, oper
);
44 return wpa_drv_wnm_oper(wpa_s
, oper
, addr
, buf
, buf_len
);
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
)
52 struct ieee80211_mgmt
*mgmt
;
55 struct wnm_sleep_element
*wnmsleep_ie
;
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
;
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
));
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
)
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
);
82 wnmtfs_ie_len
= wpabuf_len(tfs_req
);
83 wnmtfs_ie
= os_malloc(wnmtfs_ie_len
);
84 if (wnmtfs_ie
== NULL
) {
88 os_memcpy(wnmtfs_ie
, wpabuf_head(tfs_req
), wnmtfs_ie_len
);
90 wnmtfs_ie
= os_zalloc(MAX_TFS_IE_LEN
);
91 if (wnmtfs_ie
== NULL
) {
95 if (ieee80211_11_get_tfs_ie(wpa_s
, wnmtfs_ie
, &wnmtfs_ie_len
,
102 wpa_hexdump(MSG_DEBUG
, "WNM: TFS Request element",
103 (u8
*) wnmtfs_ie
, wnmtfs_ie_len
);
105 mgmt
= os_zalloc(sizeof(*mgmt
) + wnmsleep_ie_len
+ wnmtfs_ie_len
);
107 wpa_printf(MSG_DEBUG
, "MLME: Failed to allocate buffer for "
108 "WNM-Sleep Request action frame");
109 os_free(wnmsleep_ie
);
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
,
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
);
130 len
= 1 + sizeof(mgmt
->u
.action
.u
.wnm_sleep_req
) + wnmsleep_ie_len
+
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);
137 wpa_printf(MSG_DEBUG
, "Failed to send WNM-Sleep Request "
138 "(action=%d, intval=%d)", action
, intval
);
140 os_free(wnmsleep_ie
);
148 static void wnm_sleep_mode_enter_success(struct wpa_supplicant
*wpa_s
,
149 u8
*tfsresp_ie_start
,
152 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_CONFIRM
,
153 wpa_s
->bssid
, NULL
, NULL
);
154 /* remove GTK/IGTK ?? */
156 /* set the TFS Resp IE(s) */
157 if (tfsresp_ie_start
&& tfsresp_ie_end
&&
158 tfsresp_ie_end
- tfsresp_ie_start
>= 0) {
160 tfsresp_ie_len
= (tfsresp_ie_end
+ tfsresp_ie_end
[1] + 2) -
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
,
167 WNM_SLEEP_TFS_RESP_IE_SET
))
168 wpa_printf(MSG_DEBUG
, "WNM: Fail to set TFS Resp IE");
173 static void wnm_sleep_mode_exit_success(struct wpa_supplicant
*wpa_s
,
174 const u8
*frm
, u16 key_len_total
)
179 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_CONFIRM
, wpa_s
->bssid
,
182 /* Install GTK/IGTK */
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
);
189 while (ptr
+ 1 < end
) {
190 if (ptr
+ 2 + ptr
[1] > end
) {
191 wpa_printf(MSG_DEBUG
, "WNM: Invalid Key Data element "
194 wpa_hexdump(MSG_DEBUG
, "WNM: Remaining data",
199 if (*ptr
== WNM_SLEEP_SUBELEM_GTK
) {
200 if (ptr
[1] < 11 + 5) {
201 wpa_printf(MSG_DEBUG
, "WNM: Too short GTK "
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 "
212 wpa_wnmsleep_install_key(
214 WNM_SLEEP_SUBELEM_GTK
,
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 "
224 wpa_wnmsleep_install_key(wpa_s
->wpa
,
225 WNM_SLEEP_SUBELEM_IGTK
, ptr
);
226 ptr
+= 10 + WPA_IGTK_LEN
;
227 #endif /* CONFIG_IEEE80211W */
229 break; /* skip the loop */
234 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant
*wpa_s
,
235 const u8
*frm
, int len
)
238 * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
239 * WNM-Sleep Mode IE | TFS Response IE
241 u8
*pos
= (u8
*) frm
; /* point to payload after the action field */
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
;
250 key_len_total
= WPA_GET_LE16(frm
+ 1);
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");
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
);
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
;
273 wpa_printf(MSG_DEBUG
, "EID %d not recognized", *pos
);
278 wpa_printf(MSG_DEBUG
, "No WNM-Sleep IE found");
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
,
290 } else if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_EXIT
) {
291 wnm_sleep_mode_exit_success(wpa_s
, frm
, key_len_total
);
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
);
307 void wnm_deallocate_memory(struct wpa_supplicant
*wpa_s
)
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
);
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
;
328 static void wnm_parse_neighbor_report_elem(struct neighbor_report
*rep
,
329 u8 id
, u8 elen
, const u8
*pos
)
332 case WNM_NEIGHBOR_TSF
:
334 wpa_printf(MSG_DEBUG
, "WNM: Too short TSF");
337 os_free(rep
->tsf_info
);
338 rep
->tsf_info
= os_zalloc(sizeof(struct tsf_info
));
339 if (rep
->tsf_info
== NULL
)
341 os_memcpy(rep
->tsf_info
->tsf_offset
, pos
, 2);
342 os_memcpy(rep
->tsf_info
->beacon_interval
, pos
+ 2, 2);
344 case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING
:
346 wpa_printf(MSG_DEBUG
, "WNM: Too short condensed "
350 os_free(rep
->con_coun_str
);
352 os_zalloc(sizeof(struct condensed_country_string
));
353 if (rep
->con_coun_str
== NULL
)
355 os_memcpy(rep
->con_coun_str
->country_string
, pos
, 2);
357 case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE
:
359 wpa_printf(MSG_DEBUG
, "WNM: Too short BSS transition "
363 os_free(rep
->bss_tran_can
);
365 os_zalloc(sizeof(struct bss_transition_candidate
));
366 if (rep
->bss_tran_can
== NULL
)
368 rep
->bss_tran_can
->preference
= pos
[0];
370 case WNM_NEIGHBOR_BSS_TERMINATION_DURATION
:
372 wpa_printf(MSG_DEBUG
, "WNM: Too short BSS termination "
376 os_free(rep
->bss_term_dur
);
378 os_zalloc(sizeof(struct bss_termination_duration
));
379 if (rep
->bss_term_dur
== NULL
)
381 os_memcpy(rep
->bss_term_dur
->duration
, pos
, 10);
383 case WNM_NEIGHBOR_BEARING
:
385 wpa_printf(MSG_DEBUG
, "WNM: Too short neighbor "
389 os_free(rep
->bearing
);
390 rep
->bearing
= os_zalloc(sizeof(struct bearing
));
391 if (rep
->bearing
== NULL
)
393 os_memcpy(rep
->bearing
->bearing
, pos
, 8);
395 case WNM_NEIGHBOR_MEASUREMENT_PILOT
:
397 wpa_printf(MSG_DEBUG
, "WNM: Too short measurement "
401 os_free(rep
->meas_pilot
);
402 rep
->meas_pilot
= os_zalloc(sizeof(struct measurement_pilot
));
403 if (rep
->meas_pilot
== NULL
)
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);
409 case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES
:
411 wpa_printf(MSG_DEBUG
, "WNM: Too short RRM enabled "
415 os_free(rep
->rrm_cap
);
417 os_zalloc(sizeof(struct rrm_enabled_capabilities
));
418 if (rep
->rrm_cap
== NULL
)
420 os_memcpy(rep
->rrm_cap
->capabilities
, pos
, 5);
422 case WNM_NEIGHBOR_MULTIPLE_BSSID
:
424 wpa_printf(MSG_DEBUG
, "WNM: Too short multiple BSSID");
427 os_free(rep
->mul_bssid
);
428 rep
->mul_bssid
= os_zalloc(sizeof(struct multiple_bssid
));
429 if (rep
->mul_bssid
== NULL
)
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);
439 static void wnm_parse_neighbor_report(struct wpa_supplicant
*wpa_s
,
440 const u8
*pos
, u8 len
,
441 struct neighbor_report
*rep
)
446 wpa_printf(MSG_DEBUG
, "WNM: Too short neighbor report");
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);
464 wpa_printf(MSG_DEBUG
, "WNM: Subelement id=%u len=%u", id
, elen
);
467 wpa_printf(MSG_DEBUG
,
468 "WNM: Truncated neighbor report subelement");
471 wnm_parse_neighbor_report_elem(rep
, id
, elen
, pos
);
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
)
486 if (scan_res
== NULL
|| num_neigh_rep
== 0 || !wpa_s
->current_bss
)
489 wpa_printf(MSG_DEBUG
, "WNM: Current BSS " MACSTR
" RSSI %d",
490 MAC2STR(wpa_s
->bssid
), wpa_s
->current_bss
->level
);
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
,
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
);
508 wpa_printf(MSG_DEBUG
, "scan_res[%d] " MACSTR
510 MAC2STR(scan_res
->res
[j
]->bssid
),
511 scan_res
->res
[j
]->level
);
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
)
525 struct ieee80211_mgmt
*mgmt
;
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
);
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
;
546 os_memcpy(pos
, target_bssid
, ETH_ALEN
);
548 } else if (status
== WNM_BSS_TM_ACCEPT
) {
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.
554 os_memset(pos
, 0, ETH_ALEN
);
558 len
= pos
- (u8
*) &mgmt
->u
.action
.category
;
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);
566 void wnm_scan_response(struct wpa_supplicant
*wpa_s
,
567 struct wpa_scan_results
*scan_res
)
571 if (scan_res
== NULL
) {
572 wpa_printf(MSG_ERROR
, "Scan result is NULL");
573 goto send_bss_resp_fail
;
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
,
581 /* Associate to the network */
583 struct wpa_ssid
*ssid
= wpa_s
->current_ssid
;
585 bss
= wpa_bss_get_bssid(wpa_s
, bssid
);
587 wpa_printf(MSG_DEBUG
, "WNM: Target AP not found from "
589 goto send_bss_resp_fail
;
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
,
600 wpa_s
->reassociate
= 1;
601 wpa_supplicant_connect(wpa_s
, bss
, ssid
);
602 wnm_deallocate_memory(wpa_s
);
606 /* Send reject response for all the failures */
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
,
619 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant
*wpa_s
,
620 const u8
*pos
, const u8
*end
,
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
;
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
);
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");
645 os_memcpy(wpa_s
->wnm_bss_termination_duration
, pos
, 12);
646 pos
+= 12; /* BSS Termination Duration */
649 if (wpa_s
->wnm_mode
& WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT
) {
651 unsigned int beacon_int
;
653 if (pos
+ 1 > end
|| pos
+ 1 + pos
[0] > end
) {
654 wpa_printf(MSG_DEBUG
, "WNM: Invalid BSS Transition "
655 "Management Request (URL)");
658 os_memcpy(url
, pos
+ 1, pos
[0]);
662 if (wpa_s
->current_bss
)
663 beacon_int
= wpa_s
->current_bss
->beacon_int
;
665 beacon_int
= 100; /* best guess */
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
);
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
678 wpa_printf(MSG_DEBUG
, "Trying to find another BSS");
679 wpa_supplicant_req_scan(wpa_s
, 0, 0);
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
)
693 while (pos
+ 2 <= end
&&
694 wpa_s
->wnm_num_neighbor_report
< WNM_MAX_NEIGHBOR_REPORT
)
699 wpa_printf(MSG_DEBUG
, "WNM: Neighbor report tag %u",
701 if (pos
+ len
> end
) {
702 wpa_printf(MSG_DEBUG
, "WNM: Truncated request");
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
);
713 wpa_s
->wnm_num_neighbor_report
++;
716 wpa_s
->scan_res_handler
= wnm_scan_response
;
717 wpa_supplicant_req_scan(wpa_s
, 0, 0);
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
;
723 wpa_msg(wpa_s
, MSG_INFO
, "WNM: BSS Transition Management Request did not include candidates");
724 status
= WNM_BSS_TM_REJECT_UNSPECIFIED
;
726 wnm_send_bss_transition_mgmt_resp(wpa_s
,
727 wpa_s
->wnm_dialog_token
,
733 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant
*wpa_s
,
737 struct ieee80211_mgmt
*mgmt
;
741 wpa_printf(MSG_DEBUG
, "WNM: Send BSS Transition Management Query to "
742 MACSTR
" query_reason=%u",
743 MAC2STR(wpa_s
->bssid
), query_reason
);
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
;
758 len
= pos
- (u8
*) &mgmt
->u
.action
.category
;
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);
768 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant
*wpa_s
,
769 const u8
*sa
, const u8
*data
,
772 const u8
*pos
, *end
, *next
;
778 while (pos
+ 1 < end
) {
781 wpa_printf(MSG_DEBUG
, "WNM: WFA subelement %u len %u",
783 if (ie_len
> end
- pos
) {
784 wpa_printf(MSG_DEBUG
, "WNM: Not enough room for "
793 wpa_printf(MSG_DEBUG
, "WNM: Subelement OUI %06x type %u",
794 WPA_GET_BE24(pos
), pos
[3]);
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 */
806 wpa_printf(MSG_DEBUG
, "WNM: Subscription Remediation "
808 ie_end
= pos
+ ie_len
;
812 wpa_printf(MSG_DEBUG
, "WNM: No Server URL included");
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)",
819 (int) (ie_end
- pos
));
822 url
= os_malloc(url_len
+ 1);
825 os_memcpy(url
, pos
, url_len
);
827 osu_method
= pos
[url_len
];
829 hs20_rx_subscription_remediation(wpa_s
, url
,
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
) {
845 ie_end
= pos
+ ie_len
;
848 reauth_delay
= WPA_GET_LE16(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
)
857 url
= os_malloc(url_len
+ 1);
860 os_memcpy(url
, pos
, url_len
);
862 hs20_rx_deauth_imminent_notice(wpa_s
, code
,
868 #endif /* CONFIG_HS20 */
875 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant
*wpa_s
,
876 const u8
*sa
, const u8
*frm
, int len
)
879 u8 dialog_token
, type
;
881 /* Dialog Token [1] | Type [1] | Subelements */
883 if (len
< 2 || sa
== NULL
)
887 dialog_token
= *pos
++;
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",
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");
905 ieee802_11_rx_wnm_notif_req_wfa(wpa_s
, sa
, pos
, end
- pos
);
908 wpa_dbg(wpa_s
, MSG_DEBUG
, "WNM: Ignore unknown "
909 "WNM-Notification type %u", type
);
915 void ieee802_11_rx_wnm_action(struct wpa_supplicant
*wpa_s
,
916 const struct ieee80211_mgmt
*mgmt
, size_t len
)
921 if (len
< IEEE80211_HDRLEN
+ 2)
924 pos
= ((const u8
*) mgmt
) + IEEE80211_HDRLEN
+ 1;
926 end
= ((const u8
*) mgmt
) + len
;
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 "
938 case WNM_BSS_TRANS_MGMT_REQ
:
939 ieee802_11_rx_bss_trans_mgmt_req(wpa_s
, pos
, end
,
940 !(mgmt
->da
[0] & 0x01));
942 case WNM_SLEEP_MODE_RESP
:
943 ieee802_11_rx_wnmsleep_resp(wpa_s
, pos
, end
- pos
);
945 case WNM_NOTIFICATION_REQ
:
946 ieee802_11_rx_wnm_notif_req(wpa_s
, mgmt
->sa
, pos
, end
- pos
);
949 wpa_printf(MSG_ERROR
, "WNM: Unknown request");