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 wpa_s
->wnmsleep_used
= 1;
145 os_free(wnmsleep_ie
);
153 static void wnm_sleep_mode_enter_success(struct wpa_supplicant
*wpa_s
,
154 const u8
*tfsresp_ie_start
,
155 const u8
*tfsresp_ie_end
)
157 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_CONFIRM
,
158 wpa_s
->bssid
, NULL
, NULL
);
159 /* remove GTK/IGTK ?? */
161 /* set the TFS Resp IE(s) */
162 if (tfsresp_ie_start
&& tfsresp_ie_end
&&
163 tfsresp_ie_end
- tfsresp_ie_start
>= 0) {
165 tfsresp_ie_len
= (tfsresp_ie_end
+ tfsresp_ie_end
[1] + 2) -
167 wpa_printf(MSG_DEBUG
, "TFS Resp IE(s) found");
168 /* pass the TFS Resp IE(s) to driver for processing */
169 if (ieee80211_11_set_tfs_ie(wpa_s
, wpa_s
->bssid
,
172 WNM_SLEEP_TFS_RESP_IE_SET
))
173 wpa_printf(MSG_DEBUG
, "WNM: Fail to set TFS Resp IE");
178 static void wnm_sleep_mode_exit_success(struct wpa_supplicant
*wpa_s
,
179 const u8
*frm
, u16 key_len_total
)
184 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_CONFIRM
, wpa_s
->bssid
,
187 /* Install GTK/IGTK */
189 /* point to key data field */
190 ptr
= (u8
*) frm
+ 1 + 2;
191 end
= ptr
+ key_len_total
;
192 wpa_hexdump_key(MSG_DEBUG
, "WNM: Key Data", ptr
, key_len_total
);
194 if (key_len_total
&& !wpa_sm_pmf_enabled(wpa_s
->wpa
)) {
195 wpa_msg(wpa_s
, MSG_INFO
,
196 "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled");
200 while (end
- ptr
> 1) {
201 if (2 + ptr
[1] > end
- ptr
) {
202 wpa_printf(MSG_DEBUG
, "WNM: Invalid Key Data element "
205 wpa_hexdump(MSG_DEBUG
, "WNM: Remaining data",
210 if (*ptr
== WNM_SLEEP_SUBELEM_GTK
) {
211 if (ptr
[1] < 11 + 5) {
212 wpa_printf(MSG_DEBUG
, "WNM: Too short GTK "
216 gtk_len
= *(ptr
+ 4);
217 if (ptr
[1] < 11 + gtk_len
||
218 gtk_len
< 5 || gtk_len
> 32) {
219 wpa_printf(MSG_DEBUG
, "WNM: Invalid GTK "
223 wpa_wnmsleep_install_key(
225 WNM_SLEEP_SUBELEM_GTK
,
228 #ifdef CONFIG_IEEE80211W
229 } else if (*ptr
== WNM_SLEEP_SUBELEM_IGTK
) {
230 if (ptr
[1] < 2 + 6 + WPA_IGTK_LEN
) {
231 wpa_printf(MSG_DEBUG
, "WNM: Too short IGTK "
235 wpa_wnmsleep_install_key(wpa_s
->wpa
,
236 WNM_SLEEP_SUBELEM_IGTK
, ptr
);
237 ptr
+= 10 + WPA_IGTK_LEN
;
238 #endif /* CONFIG_IEEE80211W */
240 break; /* skip the loop */
245 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant
*wpa_s
,
246 const u8
*frm
, int len
)
249 * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
250 * WNM-Sleep Mode IE | TFS Response IE
252 const u8
*pos
= frm
; /* point to payload after the action field */
254 struct wnm_sleep_element
*wnmsleep_ie
= NULL
;
255 /* multiple TFS Resp IE (assuming consecutive) */
256 const u8
*tfsresp_ie_start
= NULL
;
257 const u8
*tfsresp_ie_end
= NULL
;
260 if (!wpa_s
->wnmsleep_used
) {
261 wpa_printf(MSG_DEBUG
,
262 "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association");
268 key_len_total
= WPA_GET_LE16(frm
+ 1);
270 wpa_printf(MSG_DEBUG
, "WNM-Sleep Mode Response token=%u key_len_total=%d",
271 frm
[0], key_len_total
);
273 if (key_len_total
> left
) {
274 wpa_printf(MSG_INFO
, "WNM: Too short frame for Key Data field");
277 pos
+= 3 + key_len_total
;
278 while (pos
- frm
+ 1 < len
) {
279 u8 ie_len
= *(pos
+ 1);
280 if (2 + ie_len
> frm
+ len
- pos
) {
281 wpa_printf(MSG_INFO
, "WNM: Invalid IE len %u", ie_len
);
284 wpa_hexdump(MSG_DEBUG
, "WNM: Element", pos
, 2 + ie_len
);
285 if (*pos
== WLAN_EID_WNMSLEEP
&& ie_len
>= 4)
286 wnmsleep_ie
= (struct wnm_sleep_element
*) pos
;
287 else if (*pos
== WLAN_EID_TFS_RESP
) {
288 if (!tfsresp_ie_start
)
289 tfsresp_ie_start
= pos
;
290 tfsresp_ie_end
= pos
;
292 wpa_printf(MSG_DEBUG
, "EID %d not recognized", *pos
);
297 wpa_printf(MSG_DEBUG
, "No WNM-Sleep IE found");
301 if (wnmsleep_ie
->status
== WNM_STATUS_SLEEP_ACCEPT
||
302 wnmsleep_ie
->status
== WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE
) {
303 wpa_printf(MSG_DEBUG
, "Successfully recv WNM-Sleep Response "
304 "frame (action=%d, intval=%d)",
305 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
306 if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_ENTER
) {
307 wnm_sleep_mode_enter_success(wpa_s
, tfsresp_ie_start
,
309 } else if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_EXIT
) {
310 wnm_sleep_mode_exit_success(wpa_s
, frm
, key_len_total
);
313 wpa_printf(MSG_DEBUG
, "Reject recv WNM-Sleep Response frame "
314 "(action=%d, intval=%d)",
315 wnmsleep_ie
->action_type
, wnmsleep_ie
->intval
);
316 if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_ENTER
)
317 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_ENTER_FAIL
,
318 wpa_s
->bssid
, NULL
, NULL
);
319 else if (wnmsleep_ie
->action_type
== WNM_SLEEP_MODE_EXIT
)
320 wpa_drv_wnm_oper(wpa_s
, WNM_SLEEP_EXIT_FAIL
,
321 wpa_s
->bssid
, NULL
, NULL
);
326 void wnm_deallocate_memory(struct wpa_supplicant
*wpa_s
)
330 for (i
= 0; i
< wpa_s
->wnm_num_neighbor_report
; i
++) {
331 os_free(wpa_s
->wnm_neighbor_report_elements
[i
].meas_pilot
);
332 os_free(wpa_s
->wnm_neighbor_report_elements
[i
].mul_bssid
);
335 wpa_s
->wnm_num_neighbor_report
= 0;
336 os_free(wpa_s
->wnm_neighbor_report_elements
);
337 wpa_s
->wnm_neighbor_report_elements
= NULL
;
341 static void wnm_parse_neighbor_report_elem(struct neighbor_report
*rep
,
342 u8 id
, u8 elen
, const u8
*pos
)
345 case WNM_NEIGHBOR_TSF
:
347 wpa_printf(MSG_DEBUG
, "WNM: Too short TSF");
350 rep
->tsf_offset
= WPA_GET_LE16(pos
);
351 rep
->beacon_int
= WPA_GET_LE16(pos
+ 2);
352 rep
->tsf_present
= 1;
354 case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING
:
356 wpa_printf(MSG_DEBUG
, "WNM: Too short condensed "
360 os_memcpy(rep
->country
, pos
, 2);
361 rep
->country_present
= 1;
363 case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE
:
365 wpa_printf(MSG_DEBUG
, "WNM: Too short BSS transition "
369 rep
->preference
= pos
[0];
370 rep
->preference_present
= 1;
372 case WNM_NEIGHBOR_BSS_TERMINATION_DURATION
:
373 rep
->bss_term_tsf
= WPA_GET_LE64(pos
);
374 rep
->bss_term_dur
= WPA_GET_LE16(pos
+ 8);
375 rep
->bss_term_present
= 1;
377 case WNM_NEIGHBOR_BEARING
:
379 wpa_printf(MSG_DEBUG
, "WNM: Too short neighbor "
383 rep
->bearing
= WPA_GET_LE16(pos
);
384 rep
->distance
= WPA_GET_LE32(pos
+ 2);
385 rep
->rel_height
= WPA_GET_LE16(pos
+ 2 + 4);
386 rep
->bearing_present
= 1;
388 case WNM_NEIGHBOR_MEASUREMENT_PILOT
:
390 wpa_printf(MSG_DEBUG
, "WNM: Too short measurement "
394 os_free(rep
->meas_pilot
);
395 rep
->meas_pilot
= os_zalloc(sizeof(struct measurement_pilot
));
396 if (rep
->meas_pilot
== NULL
)
398 rep
->meas_pilot
->measurement_pilot
= pos
[0];
399 rep
->meas_pilot
->subelem_len
= elen
- 1;
400 os_memcpy(rep
->meas_pilot
->subelems
, pos
+ 1, elen
- 1);
402 case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES
:
404 wpa_printf(MSG_DEBUG
, "WNM: Too short RRM enabled "
408 os_memcpy(rep
->rm_capab
, pos
, 5);
409 rep
->rm_capab_present
= 1;
411 case WNM_NEIGHBOR_MULTIPLE_BSSID
:
413 wpa_printf(MSG_DEBUG
, "WNM: Too short multiple BSSID");
416 os_free(rep
->mul_bssid
);
417 rep
->mul_bssid
= os_zalloc(sizeof(struct multiple_bssid
));
418 if (rep
->mul_bssid
== NULL
)
420 rep
->mul_bssid
->max_bssid_indicator
= pos
[0];
421 rep
->mul_bssid
->subelem_len
= elen
- 1;
422 os_memcpy(rep
->mul_bssid
->subelems
, pos
+ 1, elen
- 1);
428 static int wnm_nei_get_chan(struct wpa_supplicant
*wpa_s
, u8 op_class
, u8 chan
)
430 struct wpa_bss
*bss
= wpa_s
->current_bss
;
431 const char *country
= NULL
;
435 const u8
*elem
= wpa_bss_get_ie(bss
, WLAN_EID_COUNTRY
);
437 if (elem
&& elem
[1] >= 2)
438 country
= (const char *) (elem
+ 2);
441 freq
= ieee80211_chan_to_freq(country
, op_class
, chan
);
442 if (freq
<= 0 && op_class
== 0) {
444 * Some APs do not advertise correct operating class
445 * information. Try to determine the most likely operating
446 * frequency based on the channel number.
448 if (chan
>= 1 && chan
<= 13)
449 freq
= 2407 + chan
* 5;
452 else if (chan
>= 36 && chan
<= 169)
453 freq
= 5000 + chan
* 5;
459 static void wnm_parse_neighbor_report(struct wpa_supplicant
*wpa_s
,
460 const u8
*pos
, u8 len
,
461 struct neighbor_report
*rep
)
466 wpa_printf(MSG_DEBUG
, "WNM: Too short neighbor report");
470 os_memcpy(rep
->bssid
, pos
, ETH_ALEN
);
471 rep
->bssid_info
= WPA_GET_LE32(pos
+ ETH_ALEN
);
472 rep
->regulatory_class
= *(pos
+ 10);
473 rep
->channel_number
= *(pos
+ 11);
474 rep
->phy_type
= *(pos
+ 12);
484 wpa_printf(MSG_DEBUG
, "WNM: Subelement id=%u len=%u", id
, elen
);
487 wpa_printf(MSG_DEBUG
,
488 "WNM: Truncated neighbor report subelement");
491 wnm_parse_neighbor_report_elem(rep
, id
, elen
, pos
);
496 rep
->freq
= wnm_nei_get_chan(wpa_s
, rep
->regulatory_class
,
497 rep
->channel_number
);
501 static struct wpa_bss
*
502 compare_scan_neighbor_results(struct wpa_supplicant
*wpa_s
)
506 struct wpa_bss
*bss
= wpa_s
->current_bss
;
507 struct wpa_bss
*target
;
512 wpa_printf(MSG_DEBUG
, "WNM: Current BSS " MACSTR
" RSSI %d",
513 MAC2STR(wpa_s
->bssid
), bss
->level
);
515 for (i
= 0; i
< wpa_s
->wnm_num_neighbor_report
; i
++) {
516 struct neighbor_report
*nei
;
518 nei
= &wpa_s
->wnm_neighbor_report_elements
[i
];
519 if (nei
->preference_present
&& nei
->preference
== 0) {
520 wpa_printf(MSG_DEBUG
, "Skip excluded BSS " MACSTR
,
521 MAC2STR(nei
->bssid
));
525 target
= wpa_bss_get_bssid(wpa_s
, nei
->bssid
);
527 wpa_printf(MSG_DEBUG
, "Candidate BSS " MACSTR
528 " (pref %d) not found in scan results",
530 nei
->preference_present
? nei
->preference
:
535 if (bss
->ssid_len
!= target
->ssid_len
||
536 os_memcmp(bss
->ssid
, target
->ssid
, bss
->ssid_len
) != 0) {
538 * TODO: Could consider allowing transition to another
539 * ESS if PMF was enabled for the association.
541 wpa_printf(MSG_DEBUG
, "Candidate BSS " MACSTR
542 " (pref %d) in different ESS",
544 nei
->preference_present
? nei
->preference
:
549 if (wpa_is_bss_tmp_disallowed(wpa_s
, target
->bssid
)) {
550 wpa_printf(MSG_DEBUG
,
551 "MBO: Candidate BSS " MACSTR
552 " retry delay is not over yet",
553 MAC2STR(nei
->bssid
));
557 if (target
->level
< bss
->level
&& target
->level
< -80) {
558 wpa_printf(MSG_DEBUG
, "Candidate BSS " MACSTR
559 " (pref %d) does not have sufficient signal level (%d)",
561 nei
->preference_present
? nei
->preference
:
567 wpa_printf(MSG_DEBUG
,
568 "WNM: Found an acceptable preferred transition candidate BSS "
570 MAC2STR(nei
->bssid
), target
->level
);
578 static int wpa_bss_ies_eq(struct wpa_bss
*a
, struct wpa_bss
*b
, u8 eid
)
580 const u8
*ie_a
, *ie_b
;
585 ie_a
= wpa_bss_get_ie(a
, eid
);
586 ie_b
= wpa_bss_get_ie(b
, eid
);
588 if (!ie_a
|| !ie_b
|| ie_a
[1] != ie_b
[1])
591 return os_memcmp(ie_a
, ie_b
, ie_a
[1]) == 0;
595 static u32
wnm_get_bss_info(struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
599 info
|= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH
;
602 * Leave the security and key scope bits unset to indicate that the
603 * security information is not available.
606 if (bss
->caps
& WLAN_CAPABILITY_SPECTRUM_MGMT
)
607 info
|= NEI_REP_BSSID_INFO_SPECTRUM_MGMT
;
608 if (bss
->caps
& WLAN_CAPABILITY_QOS
)
609 info
|= NEI_REP_BSSID_INFO_QOS
;
610 if (bss
->caps
& WLAN_CAPABILITY_APSD
)
611 info
|= NEI_REP_BSSID_INFO_APSD
;
612 if (bss
->caps
& WLAN_CAPABILITY_RADIO_MEASUREMENT
)
613 info
|= NEI_REP_BSSID_INFO_RM
;
614 if (bss
->caps
& WLAN_CAPABILITY_DELAYED_BLOCK_ACK
)
615 info
|= NEI_REP_BSSID_INFO_DELAYED_BA
;
616 if (bss
->caps
& WLAN_CAPABILITY_IMM_BLOCK_ACK
)
617 info
|= NEI_REP_BSSID_INFO_IMM_BA
;
618 if (wpa_bss_ies_eq(bss
, wpa_s
->current_bss
, WLAN_EID_MOBILITY_DOMAIN
))
619 info
|= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN
;
620 if (wpa_bss_ies_eq(bss
, wpa_s
->current_bss
, WLAN_EID_HT_CAP
))
621 info
|= NEI_REP_BSSID_INFO_HT
;
627 static int wnm_add_nei_rep(u8
*buf
, size_t len
, const u8
*bssid
, u32 bss_info
,
628 u8 op_class
, u8 chan
, u8 phy_type
, u8 pref
)
633 wpa_printf(MSG_DEBUG
,
634 "WNM: Not enough room for Neighbor Report element");
638 *pos
++ = WLAN_EID_NEIGHBOR_REPORT
;
639 /* length: 13 for basic neighbor report + 3 for preference subelement */
641 os_memcpy(pos
, bssid
, ETH_ALEN
);
643 WPA_PUT_LE32(pos
, bss_info
);
648 *pos
++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE
;
655 static int wnm_nei_rep_add_bss(struct wpa_supplicant
*wpa_s
,
656 struct wpa_bss
*bss
, u8
*buf
, size_t len
,
661 int sec_chan
= 0, vht
= 0;
662 enum phy_type phy_type
;
664 struct ieee80211_ht_operation
*ht_oper
= NULL
;
665 struct ieee80211_vht_operation
*vht_oper
= NULL
;
667 ie
= wpa_bss_get_ie(bss
, WLAN_EID_HT_OPERATION
);
668 if (ie
&& ie
[1] >= 2) {
669 ht_oper
= (struct ieee80211_ht_operation
*) (ie
+ 2);
671 if (ht_oper
->ht_param
& HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE
)
673 else if (ht_oper
->ht_param
&
674 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW
)
678 ie
= wpa_bss_get_ie(bss
, WLAN_EID_VHT_OPERATION
);
679 if (ie
&& ie
[1] >= 1) {
680 vht_oper
= (struct ieee80211_vht_operation
*) (ie
+ 2);
682 if (vht_oper
->vht_op_info_chwidth
== VHT_CHANWIDTH_80MHZ
||
683 vht_oper
->vht_op_info_chwidth
== VHT_CHANWIDTH_160MHZ
||
684 vht_oper
->vht_op_info_chwidth
== VHT_CHANWIDTH_80P80MHZ
)
685 vht
= vht_oper
->vht_op_info_chwidth
;
688 if (ieee80211_freq_to_channel_ext(bss
->freq
, sec_chan
, vht
, &op_class
,
689 &chan
) == NUM_HOSTAPD_MODES
) {
690 wpa_printf(MSG_DEBUG
,
691 "WNM: Cannot determine operating class and channel");
695 phy_type
= ieee80211_get_phy_type(bss
->freq
, (ht_oper
!= NULL
),
697 if (phy_type
== PHY_TYPE_UNSPECIFIED
) {
698 wpa_printf(MSG_DEBUG
,
699 "WNM: Cannot determine BSS phy type for Neighbor Report");
703 info
= wnm_get_bss_info(wpa_s
, bss
);
705 return wnm_add_nei_rep(buf
, len
, bss
->bssid
, info
, op_class
, chan
,
710 static int wnm_add_cand_list(struct wpa_supplicant
*wpa_s
, u8
*buf
, size_t len
)
713 unsigned int i
, pref
= 255;
714 struct os_reltime now
;
715 struct wpa_ssid
*ssid
= wpa_s
->current_ssid
;
721 * TODO: Define when scan results are no longer valid for the candidate
724 os_get_reltime(&now
);
725 if (os_reltime_expired(&now
, &wpa_s
->last_scan
, 10))
728 wpa_printf(MSG_DEBUG
,
729 "WNM: Add candidate list to BSS Transition Management Response frame");
730 for (i
= 0; i
< wpa_s
->last_scan_res_used
&& pref
; i
++) {
731 struct wpa_bss
*bss
= wpa_s
->last_scan_res
[i
];
734 if (wpa_scan_res_match(wpa_s
, i
, bss
, ssid
, 1)) {
735 res
= wnm_nei_rep_add_bss(wpa_s
, bss
, pos
, len
, pref
--);
737 continue; /* could not build entry for BSS */
739 break; /* no more room for candidates */
748 wpa_hexdump(MSG_DEBUG
,
749 "WNM: BSS Transition Management Response candidate list",
756 static void wnm_send_bss_transition_mgmt_resp(
757 struct wpa_supplicant
*wpa_s
, u8 dialog_token
,
758 enum bss_trans_mgmt_status_code status
, u8 delay
,
759 const u8
*target_bssid
)
762 struct ieee80211_mgmt
*mgmt
;
766 wpa_printf(MSG_DEBUG
, "WNM: Send BSS Transition Management Response "
767 "to " MACSTR
" dialog_token=%u status=%u delay=%d",
768 MAC2STR(wpa_s
->bssid
), dialog_token
, status
, delay
);
769 if (!wpa_s
->current_bss
) {
770 wpa_printf(MSG_DEBUG
,
771 "WNM: Current BSS not known - drop response");
775 mgmt
= (struct ieee80211_mgmt
*) buf
;
776 os_memset(&buf
, 0, sizeof(buf
));
777 os_memcpy(mgmt
->da
, wpa_s
->bssid
, ETH_ALEN
);
778 os_memcpy(mgmt
->sa
, wpa_s
->own_addr
, ETH_ALEN
);
779 os_memcpy(mgmt
->bssid
, wpa_s
->bssid
, ETH_ALEN
);
780 mgmt
->frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
781 WLAN_FC_STYPE_ACTION
);
782 mgmt
->u
.action
.category
= WLAN_ACTION_WNM
;
783 mgmt
->u
.action
.u
.bss_tm_resp
.action
= WNM_BSS_TRANS_MGMT_RESP
;
784 mgmt
->u
.action
.u
.bss_tm_resp
.dialog_token
= dialog_token
;
785 mgmt
->u
.action
.u
.bss_tm_resp
.status_code
= status
;
786 mgmt
->u
.action
.u
.bss_tm_resp
.bss_termination_delay
= delay
;
787 pos
= mgmt
->u
.action
.u
.bss_tm_resp
.variable
;
789 os_memcpy(pos
, target_bssid
, ETH_ALEN
);
791 } else if (status
== WNM_BSS_TM_ACCEPT
) {
793 * P802.11-REVmc clarifies that the Target BSSID field is always
794 * present when status code is zero, so use a fake value here if
795 * no BSSID is yet known.
797 os_memset(pos
, 0, ETH_ALEN
);
801 if (status
== WNM_BSS_TM_ACCEPT
)
802 pos
+= wnm_add_cand_list(wpa_s
, pos
, buf
+ sizeof(buf
) - pos
);
805 if (status
!= WNM_BSS_TM_ACCEPT
) {
806 pos
+= wpas_mbo_ie_bss_trans_reject(
807 wpa_s
, pos
, buf
+ sizeof(buf
) - pos
,
808 MBO_TRANSITION_REJECT_REASON_UNSPECIFIED
);
810 #endif /* CONFIG_MBO */
812 len
= pos
- (u8
*) &mgmt
->u
.action
.category
;
814 res
= wpa_drv_send_action(wpa_s
, wpa_s
->assoc_freq
, 0, wpa_s
->bssid
,
815 wpa_s
->own_addr
, wpa_s
->bssid
,
816 &mgmt
->u
.action
.category
, len
, 0);
818 wpa_printf(MSG_DEBUG
,
819 "WNM: Failed to send BSS Transition Management Response");
824 int wnm_scan_process(struct wpa_supplicant
*wpa_s
, int reply_on_fail
)
827 struct wpa_ssid
*ssid
= wpa_s
->current_ssid
;
828 enum bss_trans_mgmt_status_code status
= WNM_BSS_TM_REJECT_UNSPECIFIED
;
830 if (!wpa_s
->wnm_neighbor_report_elements
)
833 if (os_reltime_before(&wpa_s
->wnm_cand_valid_until
,
834 &wpa_s
->scan_trigger_time
)) {
835 wpa_printf(MSG_DEBUG
, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
836 wnm_deallocate_memory(wpa_s
);
840 if (!wpa_s
->current_bss
||
841 os_memcmp(wpa_s
->wnm_cand_from_bss
, wpa_s
->current_bss
->bssid
,
843 wpa_printf(MSG_DEBUG
, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it");
847 /* Compare the Neighbor Report and scan results */
848 bss
= compare_scan_neighbor_results(wpa_s
);
850 wpa_printf(MSG_DEBUG
, "WNM: No BSS transition candidate match found");
851 status
= WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES
;
852 goto send_bss_resp_fail
;
855 /* Associate to the network */
856 /* Send the BSS Management Response - Accept */
857 if (wpa_s
->wnm_reply
) {
858 wpa_s
->wnm_reply
= 0;
859 wnm_send_bss_transition_mgmt_resp(wpa_s
,
860 wpa_s
->wnm_dialog_token
,
865 if (bss
== wpa_s
->current_bss
) {
866 wpa_printf(MSG_DEBUG
,
867 "WNM: Already associated with the preferred candidate");
868 wnm_deallocate_memory(wpa_s
);
872 wpa_s
->reassociate
= 1;
873 wpa_supplicant_connect(wpa_s
, bss
, ssid
);
874 wnm_deallocate_memory(wpa_s
);
881 /* Send reject response for all the failures */
883 if (wpa_s
->wnm_reply
) {
884 wpa_s
->wnm_reply
= 0;
885 wnm_send_bss_transition_mgmt_resp(wpa_s
,
886 wpa_s
->wnm_dialog_token
,
889 wnm_deallocate_memory(wpa_s
);
895 static int cand_pref_compar(const void *a
, const void *b
)
897 const struct neighbor_report
*aa
= a
;
898 const struct neighbor_report
*bb
= b
;
900 if (!aa
->preference_present
&& !bb
->preference_present
)
902 if (!aa
->preference_present
)
904 if (!bb
->preference_present
)
906 if (bb
->preference
> aa
->preference
)
908 if (bb
->preference
< aa
->preference
)
914 static void wnm_sort_cand_list(struct wpa_supplicant
*wpa_s
)
916 if (!wpa_s
->wnm_neighbor_report_elements
)
918 qsort(wpa_s
->wnm_neighbor_report_elements
,
919 wpa_s
->wnm_num_neighbor_report
, sizeof(struct neighbor_report
),
924 static void wnm_dump_cand_list(struct wpa_supplicant
*wpa_s
)
928 wpa_printf(MSG_DEBUG
, "WNM: BSS Transition Candidate List");
929 if (!wpa_s
->wnm_neighbor_report_elements
)
931 for (i
= 0; i
< wpa_s
->wnm_num_neighbor_report
; i
++) {
932 struct neighbor_report
*nei
;
934 nei
= &wpa_s
->wnm_neighbor_report_elements
[i
];
935 wpa_printf(MSG_DEBUG
, "%u: " MACSTR
936 " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d",
937 i
, MAC2STR(nei
->bssid
), nei
->bssid_info
,
938 nei
->regulatory_class
,
939 nei
->channel_number
, nei
->phy_type
,
940 nei
->preference_present
? nei
->preference
: -1,
946 static int chan_supported(struct wpa_supplicant
*wpa_s
, int freq
)
950 for (i
= 0; i
< wpa_s
->hw
.num_modes
; i
++) {
951 struct hostapd_hw_modes
*mode
= &wpa_s
->hw
.modes
[i
];
954 for (j
= 0; j
< mode
->num_channels
; j
++) {
955 struct hostapd_channel_data
*chan
;
957 chan
= &mode
->channels
[j
];
958 if (chan
->freq
== freq
&&
959 !(chan
->flag
& HOSTAPD_CHAN_DISABLED
))
968 static void wnm_set_scan_freqs(struct wpa_supplicant
*wpa_s
)
974 if (!wpa_s
->wnm_neighbor_report_elements
)
977 if (wpa_s
->hw
.modes
== NULL
)
980 os_free(wpa_s
->next_scan_freqs
);
981 wpa_s
->next_scan_freqs
= NULL
;
983 freqs
= os_calloc(wpa_s
->wnm_num_neighbor_report
+ 1, sizeof(int));
987 for (i
= 0; i
< wpa_s
->wnm_num_neighbor_report
; i
++) {
988 struct neighbor_report
*nei
;
990 nei
= &wpa_s
->wnm_neighbor_report_elements
[i
];
991 if (nei
->freq
<= 0) {
992 wpa_printf(MSG_DEBUG
,
993 "WNM: Unknown neighbor operating frequency for "
994 MACSTR
" - scan all channels",
995 MAC2STR(nei
->bssid
));
999 if (chan_supported(wpa_s
, nei
->freq
))
1000 add_freq(freqs
, &num_freqs
, nei
->freq
);
1003 if (num_freqs
== 0) {
1008 wpa_printf(MSG_DEBUG
,
1009 "WNM: Scan %d frequencies based on transition candidate list",
1011 wpa_s
->next_scan_freqs
= freqs
;
1015 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant
*wpa_s
,
1016 const u8
*pos
, const u8
*end
,
1019 unsigned int beacon_int
;
1023 #endif /* CONFIG_MBO */
1028 if (wpa_s
->current_bss
)
1029 beacon_int
= wpa_s
->current_bss
->beacon_int
;
1031 beacon_int
= 100; /* best guess */
1033 wpa_s
->wnm_dialog_token
= pos
[0];
1034 wpa_s
->wnm_mode
= pos
[1];
1035 wpa_s
->wnm_dissoc_timer
= WPA_GET_LE16(pos
+ 2);
1037 wpa_s
->wnm_reply
= reply
;
1039 wpa_printf(MSG_DEBUG
, "WNM: BSS Transition Management Request: "
1040 "dialog_token=%u request_mode=0x%x "
1041 "disassoc_timer=%u validity_interval=%u",
1042 wpa_s
->wnm_dialog_token
, wpa_s
->wnm_mode
,
1043 wpa_s
->wnm_dissoc_timer
, valid_int
);
1047 if (wpa_s
->wnm_mode
& WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED
) {
1048 if (end
- pos
< 12) {
1049 wpa_printf(MSG_DEBUG
, "WNM: Too short BSS TM Request");
1052 os_memcpy(wpa_s
->wnm_bss_termination_duration
, pos
, 12);
1053 pos
+= 12; /* BSS Termination Duration */
1056 if (wpa_s
->wnm_mode
& WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT
) {
1059 if (end
- pos
< 1 || 1 + pos
[0] > end
- pos
) {
1060 wpa_printf(MSG_DEBUG
, "WNM: Invalid BSS Transition "
1061 "Management Request (URL)");
1064 os_memcpy(url
, pos
+ 1, pos
[0]);
1068 wpa_msg(wpa_s
, MSG_INFO
, ESS_DISASSOC_IMMINENT
"%d %u %s",
1069 wpa_sm_pmf_enabled(wpa_s
->wpa
),
1070 wpa_s
->wnm_dissoc_timer
* beacon_int
* 128 / 125, url
);
1073 if (wpa_s
->wnm_mode
& WNM_BSS_TM_REQ_DISASSOC_IMMINENT
) {
1074 wpa_msg(wpa_s
, MSG_INFO
, "WNM: Disassociation Imminent - "
1075 "Disassociation Timer %u", wpa_s
->wnm_dissoc_timer
);
1076 if (wpa_s
->wnm_dissoc_timer
&& !wpa_s
->scanning
) {
1077 /* TODO: mark current BSS less preferred for
1079 wpa_printf(MSG_DEBUG
, "Trying to find another BSS");
1080 wpa_supplicant_req_scan(wpa_s
, 0, 0);
1085 vendor
= get_ie(pos
, end
- pos
, WLAN_EID_VENDOR_SPECIFIC
);
1087 wpas_mbo_ie_trans_req(wpa_s
, vendor
+ 2, vendor
[1]);
1088 #endif /* CONFIG_MBO */
1090 if (wpa_s
->wnm_mode
& WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED
) {
1091 unsigned int valid_ms
;
1093 wpa_msg(wpa_s
, MSG_INFO
, "WNM: Preferred List Available");
1094 wnm_deallocate_memory(wpa_s
);
1095 wpa_s
->wnm_neighbor_report_elements
= os_calloc(
1096 WNM_MAX_NEIGHBOR_REPORT
,
1097 sizeof(struct neighbor_report
));
1098 if (wpa_s
->wnm_neighbor_report_elements
== NULL
)
1101 while (end
- pos
>= 2 &&
1102 wpa_s
->wnm_num_neighbor_report
< WNM_MAX_NEIGHBOR_REPORT
)
1107 wpa_printf(MSG_DEBUG
, "WNM: Neighbor report tag %u",
1109 if (len
> end
- pos
) {
1110 wpa_printf(MSG_DEBUG
, "WNM: Truncated request");
1113 if (tag
== WLAN_EID_NEIGHBOR_REPORT
) {
1114 struct neighbor_report
*rep
;
1115 rep
= &wpa_s
->wnm_neighbor_report_elements
[
1116 wpa_s
->wnm_num_neighbor_report
];
1117 wnm_parse_neighbor_report(wpa_s
, pos
, len
, rep
);
1121 wpa_s
->wnm_num_neighbor_report
++;
1123 wnm_sort_cand_list(wpa_s
);
1124 wnm_dump_cand_list(wpa_s
);
1125 valid_ms
= valid_int
* beacon_int
* 128 / 125;
1126 wpa_printf(MSG_DEBUG
, "WNM: Candidate list valid for %u ms",
1128 os_get_reltime(&wpa_s
->wnm_cand_valid_until
);
1129 wpa_s
->wnm_cand_valid_until
.sec
+= valid_ms
/ 1000;
1130 wpa_s
->wnm_cand_valid_until
.usec
+= (valid_ms
% 1000) * 1000;
1131 wpa_s
->wnm_cand_valid_until
.sec
+=
1132 wpa_s
->wnm_cand_valid_until
.usec
/ 1000000;
1133 wpa_s
->wnm_cand_valid_until
.usec
%= 1000000;
1134 os_memcpy(wpa_s
->wnm_cand_from_bss
, wpa_s
->bssid
, ETH_ALEN
);
1136 if (wpa_s
->last_scan_res_used
> 0) {
1137 struct os_reltime now
;
1139 os_get_reltime(&now
);
1140 if (!os_reltime_expired(&now
, &wpa_s
->last_scan
, 10)) {
1141 wpa_printf(MSG_DEBUG
,
1142 "WNM: Try to use recent scan results");
1143 if (wnm_scan_process(wpa_s
, 0) > 0)
1145 wpa_printf(MSG_DEBUG
,
1146 "WNM: No match in previous scan results - try a new scan");
1150 wnm_set_scan_freqs(wpa_s
);
1151 if (wpa_s
->wnm_num_neighbor_report
== 1) {
1152 os_memcpy(wpa_s
->next_scan_bssid
,
1153 wpa_s
->wnm_neighbor_report_elements
[0].bssid
,
1155 wpa_printf(MSG_DEBUG
,
1156 "WNM: Scan only for a specific BSSID since there is only a single candidate "
1157 MACSTR
, MAC2STR(wpa_s
->next_scan_bssid
));
1159 wpa_supplicant_req_scan(wpa_s
, 0, 0);
1161 enum bss_trans_mgmt_status_code status
;
1162 if (wpa_s
->wnm_mode
& WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT
)
1163 status
= WNM_BSS_TM_ACCEPT
;
1165 wpa_msg(wpa_s
, MSG_INFO
, "WNM: BSS Transition Management Request did not include candidates");
1166 status
= WNM_BSS_TM_REJECT_UNSPECIFIED
;
1168 wnm_send_bss_transition_mgmt_resp(wpa_s
,
1169 wpa_s
->wnm_dialog_token
,
1175 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant
*wpa_s
,
1176 u8 query_reason
, int cand_list
)
1179 struct ieee80211_mgmt
*mgmt
;
1183 wpa_printf(MSG_DEBUG
, "WNM: Send BSS Transition Management Query to "
1184 MACSTR
" query_reason=%u%s",
1185 MAC2STR(wpa_s
->bssid
), query_reason
,
1186 cand_list
? " candidate list" : "");
1188 mgmt
= (struct ieee80211_mgmt
*) buf
;
1189 os_memset(&buf
, 0, sizeof(buf
));
1190 os_memcpy(mgmt
->da
, wpa_s
->bssid
, ETH_ALEN
);
1191 os_memcpy(mgmt
->sa
, wpa_s
->own_addr
, ETH_ALEN
);
1192 os_memcpy(mgmt
->bssid
, wpa_s
->bssid
, ETH_ALEN
);
1193 mgmt
->frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
1194 WLAN_FC_STYPE_ACTION
);
1195 mgmt
->u
.action
.category
= WLAN_ACTION_WNM
;
1196 mgmt
->u
.action
.u
.bss_tm_query
.action
= WNM_BSS_TRANS_MGMT_QUERY
;
1197 mgmt
->u
.action
.u
.bss_tm_query
.dialog_token
= 1;
1198 mgmt
->u
.action
.u
.bss_tm_query
.query_reason
= query_reason
;
1199 pos
= mgmt
->u
.action
.u
.bss_tm_query
.variable
;
1202 pos
+= wnm_add_cand_list(wpa_s
, pos
, buf
+ sizeof(buf
) - pos
);
1204 len
= pos
- (u8
*) &mgmt
->u
.action
.category
;
1206 ret
= wpa_drv_send_action(wpa_s
, wpa_s
->assoc_freq
, 0, wpa_s
->bssid
,
1207 wpa_s
->own_addr
, wpa_s
->bssid
,
1208 &mgmt
->u
.action
.category
, len
, 0);
1214 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant
*wpa_s
,
1215 const u8
*sa
, const u8
*data
,
1218 const u8
*pos
, *end
, *next
;
1224 while (end
- pos
> 1) {
1227 wpa_printf(MSG_DEBUG
, "WNM: WFA subelement %u len %u",
1229 if (ie_len
> end
- pos
) {
1230 wpa_printf(MSG_DEBUG
, "WNM: Not enough room for "
1234 next
= pos
+ ie_len
;
1239 wpa_printf(MSG_DEBUG
, "WNM: Subelement OUI %06x type %u",
1240 WPA_GET_BE24(pos
), pos
[3]);
1243 if (ie
== WLAN_EID_VENDOR_SPECIFIC
&& ie_len
>= 5 &&
1244 WPA_GET_BE24(pos
) == OUI_WFA
&&
1245 pos
[3] == HS20_WNM_SUB_REM_NEEDED
) {
1246 /* Subscription Remediation subelement */
1252 wpa_printf(MSG_DEBUG
, "WNM: Subscription Remediation "
1254 ie_end
= pos
+ ie_len
;
1258 wpa_printf(MSG_DEBUG
, "WNM: No Server URL included");
1262 if (url_len
+ 1 > ie_end
- pos
) {
1263 wpa_printf(MSG_DEBUG
, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
1265 (int) (ie_end
- pos
));
1268 url
= os_malloc(url_len
+ 1);
1271 os_memcpy(url
, pos
, url_len
);
1272 url
[url_len
] = '\0';
1273 osu_method
= pos
[url_len
];
1275 hs20_rx_subscription_remediation(wpa_s
, url
,
1282 if (ie
== WLAN_EID_VENDOR_SPECIFIC
&& ie_len
>= 8 &&
1283 WPA_GET_BE24(pos
) == OUI_WFA
&&
1284 pos
[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE
) {
1291 ie_end
= pos
+ ie_len
;
1294 reauth_delay
= WPA_GET_LE16(pos
);
1297 wpa_printf(MSG_DEBUG
, "WNM: HS 2.0 Deauthentication "
1298 "Imminent - Reason Code %u "
1299 "Re-Auth Delay %u URL Length %u",
1300 code
, reauth_delay
, url_len
);
1301 if (url_len
> ie_end
- pos
)
1303 url
= os_malloc(url_len
+ 1);
1306 os_memcpy(url
, pos
, url_len
);
1307 url
[url_len
] = '\0';
1308 hs20_rx_deauth_imminent_notice(wpa_s
, code
,
1314 #endif /* CONFIG_HS20 */
1321 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant
*wpa_s
,
1322 const u8
*sa
, const u8
*frm
, int len
)
1324 const u8
*pos
, *end
;
1325 u8 dialog_token
, type
;
1327 /* Dialog Token [1] | Type [1] | Subelements */
1329 if (len
< 2 || sa
== NULL
)
1333 dialog_token
= *pos
++;
1336 wpa_dbg(wpa_s
, MSG_DEBUG
, "WNM: Received WNM-Notification Request "
1337 "(dialog_token %u type %u sa " MACSTR
")",
1338 dialog_token
, type
, MAC2STR(sa
));
1339 wpa_hexdump(MSG_DEBUG
, "WNM-Notification Request subelements",
1342 if (wpa_s
->wpa_state
!= WPA_COMPLETED
||
1343 os_memcmp(sa
, wpa_s
->bssid
, ETH_ALEN
) != 0) {
1344 wpa_dbg(wpa_s
, MSG_DEBUG
, "WNM: WNM-Notification frame not "
1345 "from our AP - ignore it");
1351 ieee802_11_rx_wnm_notif_req_wfa(wpa_s
, sa
, pos
, end
- pos
);
1354 wpa_dbg(wpa_s
, MSG_DEBUG
, "WNM: Ignore unknown "
1355 "WNM-Notification type %u", type
);
1361 void ieee802_11_rx_wnm_action(struct wpa_supplicant
*wpa_s
,
1362 const struct ieee80211_mgmt
*mgmt
, size_t len
)
1364 const u8
*pos
, *end
;
1367 if (len
< IEEE80211_HDRLEN
+ 2)
1370 pos
= ((const u8
*) mgmt
) + IEEE80211_HDRLEN
+ 1;
1372 end
= ((const u8
*) mgmt
) + len
;
1374 wpa_printf(MSG_DEBUG
, "WNM: RX action %u from " MACSTR
,
1375 act
, MAC2STR(mgmt
->sa
));
1376 if (wpa_s
->wpa_state
< WPA_ASSOCIATED
||
1377 os_memcmp(mgmt
->sa
, wpa_s
->bssid
, ETH_ALEN
) != 0) {
1378 wpa_printf(MSG_DEBUG
, "WNM: Ignore unexpected WNM Action "
1384 case WNM_BSS_TRANS_MGMT_REQ
:
1385 ieee802_11_rx_bss_trans_mgmt_req(wpa_s
, pos
, end
,
1386 !(mgmt
->da
[0] & 0x01));
1388 case WNM_SLEEP_MODE_RESP
:
1389 ieee802_11_rx_wnmsleep_resp(wpa_s
, pos
, end
- pos
);
1391 case WNM_NOTIFICATION_REQ
:
1392 ieee802_11_rx_wnm_notif_req(wpa_s
, mgmt
->sa
, pos
, end
- pos
);
1395 wpa_printf(MSG_ERROR
, "WNM: Unknown request");