TDLS: Declare tdls_testing as extern in a header file
[mech_eap.git] / wpa_supplicant / wnm_sta.c
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/ieee802_11_common.h"
14 #include "common/wpa_ctrl.h"
15 #include "rsn_supp/wpa.h"
16 #include "wpa_supplicant_i.h"
17 #include "driver_i.h"
18 #include "scan.h"
19 #include "ctrl_iface.h"
20 #include "bss.h"
21 #include "wnm_sta.h"
22 #include "hs20_supplicant.h"
23
24 #define MAX_TFS_IE_LEN  1024
25 #define WNM_MAX_NEIGHBOR_REPORT 10
26
27 #define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */
28
29 /* get the TFS IE from driver */
30 static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
31                                    u16 *buf_len, enum wnm_oper oper)
32 {
33         wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
34
35         return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len);
36 }
37
38
39 /* set the TFS IE to driver */
40 static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
41                                    const u8 *addr, const u8 *buf, u16 buf_len,
42                                    enum wnm_oper oper)
43 {
44         u16 len = buf_len;
45
46         wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
47
48         return wpa_drv_wnm_oper(wpa_s, oper, addr, (u8 *) buf, &len);
49 }
50
51
52 /* MLME-SLEEPMODE.request */
53 int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
54                                  u8 action, u16 intval, struct wpabuf *tfs_req)
55 {
56         struct ieee80211_mgmt *mgmt;
57         int res;
58         size_t len;
59         struct wnm_sleep_element *wnmsleep_ie;
60         u8 *wnmtfs_ie;
61         u8 wnmsleep_ie_len;
62         u16 wnmtfs_ie_len;  /* possibly multiple IE(s) */
63         enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
64                 WNM_SLEEP_TFS_REQ_IE_NONE;
65
66         wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request "
67                    "action=%s to " MACSTR,
68                    action == 0 ? "enter" : "exit",
69                    MAC2STR(wpa_s->bssid));
70
71         /* WNM-Sleep Mode IE */
72         wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
73         wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element));
74         if (wnmsleep_ie == NULL)
75                 return -1;
76         wnmsleep_ie->eid = WLAN_EID_WNMSLEEP;
77         wnmsleep_ie->len = wnmsleep_ie_len - 2;
78         wnmsleep_ie->action_type = action;
79         wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT;
80         wnmsleep_ie->intval = host_to_le16(intval);
81         wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element",
82                     (u8 *) wnmsleep_ie, wnmsleep_ie_len);
83
84         /* TFS IE(s) */
85         if (tfs_req) {
86                 wnmtfs_ie_len = wpabuf_len(tfs_req);
87                 wnmtfs_ie = os_malloc(wnmtfs_ie_len);
88                 if (wnmtfs_ie == NULL) {
89                         os_free(wnmsleep_ie);
90                         return -1;
91                 }
92                 os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len);
93         } else {
94                 wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
95                 if (wnmtfs_ie == NULL) {
96                         os_free(wnmsleep_ie);
97                         return -1;
98                 }
99                 if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
100                                             tfs_oper)) {
101                         wnmtfs_ie_len = 0;
102                         os_free(wnmtfs_ie);
103                         wnmtfs_ie = NULL;
104                 }
105         }
106         wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
107                     (u8 *) wnmtfs_ie, wnmtfs_ie_len);
108
109         mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
110         if (mgmt == NULL) {
111                 wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
112                            "WNM-Sleep Request action frame");
113                 os_free(wnmsleep_ie);
114                 os_free(wnmtfs_ie);
115                 return -1;
116         }
117
118         os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
119         os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
120         os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
121         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
122                                            WLAN_FC_STYPE_ACTION);
123         mgmt->u.action.category = WLAN_ACTION_WNM;
124         mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ;
125         mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1;
126         os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie,
127                   wnmsleep_ie_len);
128         /* copy TFS IE here */
129         if (wnmtfs_ie_len > 0) {
130                 os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
131                           wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
132         }
133
134         len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
135                 wnmtfs_ie_len;
136
137         res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
138                                   wpa_s->own_addr, wpa_s->bssid,
139                                   &mgmt->u.action.category, len, 0);
140         if (res < 0)
141                 wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
142                            "(action=%d, intval=%d)", action, intval);
143         else
144                 wpa_s->wnmsleep_used = 1;
145
146         os_free(wnmsleep_ie);
147         os_free(wnmtfs_ie);
148         os_free(mgmt);
149
150         return res;
151 }
152
153
154 static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
155                                          const u8 *tfsresp_ie_start,
156                                          const u8 *tfsresp_ie_end)
157 {
158         wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
159                          wpa_s->bssid, NULL, NULL);
160         /* remove GTK/IGTK ?? */
161
162         /* set the TFS Resp IE(s) */
163         if (tfsresp_ie_start && tfsresp_ie_end &&
164             tfsresp_ie_end - tfsresp_ie_start >= 0) {
165                 u16 tfsresp_ie_len;
166                 tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) -
167                         tfsresp_ie_start;
168                 wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
169                 /* pass the TFS Resp IE(s) to driver for processing */
170                 if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
171                                             tfsresp_ie_start,
172                                             tfsresp_ie_len,
173                                             WNM_SLEEP_TFS_RESP_IE_SET))
174                         wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
175         }
176 }
177
178
179 static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
180                                         const u8 *frm, u16 key_len_total)
181 {
182         u8 *ptr, *end;
183         u8 gtk_len;
184
185         wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM,  wpa_s->bssid,
186                          NULL, NULL);
187
188         /* Install GTK/IGTK */
189
190         /* point to key data field */
191         ptr = (u8 *) frm + 1 + 2;
192         end = ptr + key_len_total;
193         wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
194
195         if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) {
196                 wpa_msg(wpa_s, MSG_INFO,
197                         "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled");
198                 return;
199         }
200
201         while (end - ptr > 1) {
202                 if (2 + ptr[1] > end - ptr) {
203                         wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
204                                    "length");
205                         if (end > ptr) {
206                                 wpa_hexdump(MSG_DEBUG, "WNM: Remaining data",
207                                             ptr, end - ptr);
208                         }
209                         break;
210                 }
211                 if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
212                         if (ptr[1] < 11 + 5) {
213                                 wpa_printf(MSG_DEBUG, "WNM: Too short GTK "
214                                            "subelem");
215                                 break;
216                         }
217                         gtk_len = *(ptr + 4);
218                         if (ptr[1] < 11 + gtk_len ||
219                             gtk_len < 5 || gtk_len > 32) {
220                                 wpa_printf(MSG_DEBUG, "WNM: Invalid GTK "
221                                            "subelem");
222                                 break;
223                         }
224                         wpa_wnmsleep_install_key(
225                                 wpa_s->wpa,
226                                 WNM_SLEEP_SUBELEM_GTK,
227                                 ptr);
228                         ptr += 13 + gtk_len;
229 #ifdef CONFIG_IEEE80211W
230                 } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
231                         if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
232                                 wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
233                                            "subelem");
234                                 break;
235                         }
236                         wpa_wnmsleep_install_key(wpa_s->wpa,
237                                                  WNM_SLEEP_SUBELEM_IGTK, ptr);
238                         ptr += 10 + WPA_IGTK_LEN;
239 #endif /* CONFIG_IEEE80211W */
240                 } else
241                         break; /* skip the loop */
242         }
243 }
244
245
246 static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
247                                         const u8 *frm, int len)
248 {
249         /*
250          * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data |
251          * WNM-Sleep Mode IE | TFS Response IE
252          */
253         const u8 *pos = frm; /* point to payload after the action field */
254         u16 key_len_total;
255         struct wnm_sleep_element *wnmsleep_ie = NULL;
256         /* multiple TFS Resp IE (assuming consecutive) */
257         const u8 *tfsresp_ie_start = NULL;
258         const u8 *tfsresp_ie_end = NULL;
259         size_t left;
260
261         if (!wpa_s->wnmsleep_used) {
262                 wpa_printf(MSG_DEBUG,
263                            "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode has not been used in this association");
264                 return;
265         }
266
267         if (len < 3)
268                 return;
269         key_len_total = WPA_GET_LE16(frm + 1);
270
271         wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d",
272                    frm[0], key_len_total);
273         left = len - 3;
274         if (key_len_total > left) {
275                 wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
276                 return;
277         }
278         pos += 3 + key_len_total;
279         while (pos - frm + 1 < len) {
280                 u8 ie_len = *(pos + 1);
281                 if (2 + ie_len > frm + len - pos) {
282                         wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len);
283                         break;
284                 }
285                 wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len);
286                 if (*pos == WLAN_EID_WNMSLEEP && ie_len >= 4)
287                         wnmsleep_ie = (struct wnm_sleep_element *) pos;
288                 else if (*pos == WLAN_EID_TFS_RESP) {
289                         if (!tfsresp_ie_start)
290                                 tfsresp_ie_start = pos;
291                         tfsresp_ie_end = pos;
292                 } else
293                         wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
294                 pos += ie_len + 2;
295         }
296
297         if (!wnmsleep_ie) {
298                 wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
299                 return;
300         }
301
302         if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
303             wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
304                 wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
305                            "frame (action=%d, intval=%d)",
306                            wnmsleep_ie->action_type, wnmsleep_ie->intval);
307                 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) {
308                         wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start,
309                                                      tfsresp_ie_end);
310                 } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
311                         wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total);
312                 }
313         } else {
314                 wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
315                            "(action=%d, intval=%d)",
316                            wnmsleep_ie->action_type, wnmsleep_ie->intval);
317                 if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER)
318                         wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
319                                          wpa_s->bssid, NULL, NULL);
320                 else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT)
321                         wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
322                                          wpa_s->bssid, NULL, NULL);
323         }
324 }
325
326
327 void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
328 {
329         int i;
330
331         for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
332                 os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
333                 os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
334         }
335
336         wpa_s->wnm_num_neighbor_report = 0;
337         os_free(wpa_s->wnm_neighbor_report_elements);
338         wpa_s->wnm_neighbor_report_elements = NULL;
339 }
340
341
342 static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
343                                            u8 id, u8 elen, const u8 *pos)
344 {
345         switch (id) {
346         case WNM_NEIGHBOR_TSF:
347                 if (elen < 2 + 2) {
348                         wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
349                         break;
350                 }
351                 rep->tsf_offset = WPA_GET_LE16(pos);
352                 rep->beacon_int = WPA_GET_LE16(pos + 2);
353                 rep->tsf_present = 1;
354                 break;
355         case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
356                 if (elen < 2) {
357                         wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
358                                    "country string");
359                         break;
360                 }
361                 os_memcpy(rep->country, pos, 2);
362                 rep->country_present = 1;
363                 break;
364         case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
365                 if (elen < 1) {
366                         wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
367                                    "candidate");
368                         break;
369                 }
370                 rep->preference = pos[0];
371                 rep->preference_present = 1;
372                 break;
373         case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
374                 rep->bss_term_tsf = WPA_GET_LE64(pos);
375                 rep->bss_term_dur = WPA_GET_LE16(pos + 8);
376                 rep->bss_term_present = 1;
377                 break;
378         case WNM_NEIGHBOR_BEARING:
379                 if (elen < 8) {
380                         wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
381                                    "bearing");
382                         break;
383                 }
384                 rep->bearing = WPA_GET_LE16(pos);
385                 rep->distance = WPA_GET_LE32(pos + 2);
386                 rep->rel_height = WPA_GET_LE16(pos + 2 + 4);
387                 rep->bearing_present = 1;
388                 break;
389         case WNM_NEIGHBOR_MEASUREMENT_PILOT:
390                 if (elen < 1) {
391                         wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
392                                    "pilot");
393                         break;
394                 }
395                 os_free(rep->meas_pilot);
396                 rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
397                 if (rep->meas_pilot == NULL)
398                         break;
399                 rep->meas_pilot->measurement_pilot = pos[0];
400                 rep->meas_pilot->subelem_len = elen - 1;
401                 os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1);
402                 break;
403         case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
404                 if (elen < 5) {
405                         wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
406                                    "capabilities");
407                         break;
408                 }
409                 os_memcpy(rep->rm_capab, pos, 5);
410                 rep->rm_capab_present = 1;
411                 break;
412         case WNM_NEIGHBOR_MULTIPLE_BSSID:
413                 if (elen < 1) {
414                         wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
415                         break;
416                 }
417                 os_free(rep->mul_bssid);
418                 rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
419                 if (rep->mul_bssid == NULL)
420                         break;
421                 rep->mul_bssid->max_bssid_indicator = pos[0];
422                 rep->mul_bssid->subelem_len = elen - 1;
423                 os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1);
424                 break;
425         }
426 }
427
428
429 static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
430 {
431         struct wpa_bss *bss = wpa_s->current_bss;
432         const char *country = NULL;
433         int freq;
434
435         if (bss) {
436                 const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
437
438                 if (elem && elem[1] >= 2)
439                         country = (const char *) (elem + 2);
440         }
441
442         freq = ieee80211_chan_to_freq(country, op_class, chan);
443         if (freq <= 0 && op_class == 0) {
444                 /*
445                  * Some APs do not advertise correct operating class
446                  * information. Try to determine the most likely operating
447                  * frequency based on the channel number.
448                  */
449                 if (chan >= 1 && chan <= 13)
450                         freq = 2407 + chan * 5;
451                 else if (chan == 14)
452                         freq = 2484;
453                 else if (chan >= 36 && chan <= 169)
454                         freq = 5000 + chan * 5;
455         }
456         return freq;
457 }
458
459
460 static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
461                                       const u8 *pos, u8 len,
462                                       struct neighbor_report *rep)
463 {
464         u8 left = len;
465
466         if (left < 13) {
467                 wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
468                 return;
469         }
470
471         os_memcpy(rep->bssid, pos, ETH_ALEN);
472         rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN);
473         rep->regulatory_class = *(pos + 10);
474         rep->channel_number = *(pos + 11);
475         rep->phy_type = *(pos + 12);
476
477         pos += 13;
478         left -= 13;
479
480         while (left >= 2) {
481                 u8 id, elen;
482
483                 id = *pos++;
484                 elen = *pos++;
485                 wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen);
486                 left -= 2;
487                 if (elen > left) {
488                         wpa_printf(MSG_DEBUG,
489                                    "WNM: Truncated neighbor report subelement");
490                         break;
491                 }
492                 wnm_parse_neighbor_report_elem(rep, id, elen, pos);
493                 left -= elen;
494                 pos += elen;
495         }
496
497         rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class,
498                                      rep->channel_number);
499 }
500
501
502 static struct wpa_bss *
503 compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs)
504 {
505
506         u8 i;
507         struct wpa_bss *bss = wpa_s->current_bss;
508         struct wpa_bss *target;
509
510         if (!bss)
511                 return NULL;
512
513         wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
514                    MAC2STR(wpa_s->bssid), bss->level);
515
516         for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
517                 struct neighbor_report *nei;
518
519                 nei = &wpa_s->wnm_neighbor_report_elements[i];
520                 if (nei->preference_present && nei->preference == 0) {
521                         wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
522                                    MAC2STR(nei->bssid));
523                         continue;
524                 }
525
526                 target = wpa_bss_get_bssid(wpa_s, nei->bssid);
527                 if (!target) {
528                         wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
529                                    " (pref %d) not found in scan results",
530                                    MAC2STR(nei->bssid),
531                                    nei->preference_present ? nei->preference :
532                                    -1);
533                         continue;
534                 }
535
536                 if (age_secs) {
537                         struct os_reltime now;
538
539                         if (os_get_reltime(&now) == 0 &&
540                             os_reltime_expired(&now, &target->last_update,
541                                                age_secs)) {
542                                 wpa_printf(MSG_DEBUG,
543                                            "Candidate BSS is more than %ld seconds old",
544                                            age_secs);
545                                 continue;
546                         }
547                 }
548
549                 if (bss->ssid_len != target->ssid_len ||
550                     os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
551                         /*
552                          * TODO: Could consider allowing transition to another
553                          * ESS if PMF was enabled for the association.
554                          */
555                         wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
556                                    " (pref %d) in different ESS",
557                                    MAC2STR(nei->bssid),
558                                    nei->preference_present ? nei->preference :
559                                    -1);
560                         continue;
561                 }
562
563                 if (wpa_s->current_ssid &&
564                     !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
565                                         1)) {
566                         wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
567                                    " (pref %d) does not match the current network profile",
568                                    MAC2STR(nei->bssid),
569                                    nei->preference_present ? nei->preference :
570                                    -1);
571                         continue;
572                 }
573
574                 if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
575                         wpa_printf(MSG_DEBUG,
576                                    "MBO: Candidate BSS " MACSTR
577                                    " retry delay is not over yet",
578                                    MAC2STR(nei->bssid));
579                         continue;
580                 }
581
582                 if (target->level < bss->level && target->level < -80) {
583                         wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
584                                    " (pref %d) does not have sufficient signal level (%d)",
585                                    MAC2STR(nei->bssid),
586                                    nei->preference_present ? nei->preference :
587                                    -1,
588                                    target->level);
589                         continue;
590                 }
591
592                 wpa_printf(MSG_DEBUG,
593                            "WNM: Found an acceptable preferred transition candidate BSS "
594                            MACSTR " (RSSI %d)",
595                            MAC2STR(nei->bssid), target->level);
596                 return target;
597         }
598
599         return NULL;
600 }
601
602
603 static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
604 {
605         const u8 *ie_a, *ie_b;
606
607         if (!a || !b)
608                 return 0;
609
610         ie_a = wpa_bss_get_ie(a, eid);
611         ie_b = wpa_bss_get_ie(b, eid);
612
613         if (!ie_a || !ie_b || ie_a[1] != ie_b[1])
614                 return 0;
615
616         return os_memcmp(ie_a, ie_b, ie_a[1]) == 0;
617 }
618
619
620 static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
621 {
622         u32 info = 0;
623
624         info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH;
625
626         /*
627          * Leave the security and key scope bits unset to indicate that the
628          * security information is not available.
629          */
630
631         if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT)
632                 info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
633         if (bss->caps & WLAN_CAPABILITY_QOS)
634                 info |= NEI_REP_BSSID_INFO_QOS;
635         if (bss->caps & WLAN_CAPABILITY_APSD)
636                 info |= NEI_REP_BSSID_INFO_APSD;
637         if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT)
638                 info |= NEI_REP_BSSID_INFO_RM;
639         if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK)
640                 info |= NEI_REP_BSSID_INFO_DELAYED_BA;
641         if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK)
642                 info |= NEI_REP_BSSID_INFO_IMM_BA;
643         if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN))
644                 info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN;
645         if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP))
646                 info |= NEI_REP_BSSID_INFO_HT;
647
648         return info;
649 }
650
651
652 static int wnm_add_nei_rep(u8 *buf, size_t len, const u8 *bssid, u32 bss_info,
653                            u8 op_class, u8 chan, u8 phy_type, u8 pref)
654 {
655         u8 *pos = buf;
656
657         if (len < 18) {
658                 wpa_printf(MSG_DEBUG,
659                            "WNM: Not enough room for Neighbor Report element");
660                 return -1;
661         }
662
663         *pos++ = WLAN_EID_NEIGHBOR_REPORT;
664         /* length: 13 for basic neighbor report + 3 for preference subelement */
665         *pos++ = 16;
666         os_memcpy(pos, bssid, ETH_ALEN);
667         pos += ETH_ALEN;
668         WPA_PUT_LE32(pos, bss_info);
669         pos += 4;
670         *pos++ = op_class;
671         *pos++ = chan;
672         *pos++ = phy_type;
673         *pos++ = WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE;
674         *pos++ = 1;
675         *pos++ = pref;
676         return pos - buf;
677 }
678
679
680 static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s,
681                                struct wpa_bss *bss, u8 *buf, size_t len,
682                                u8 pref)
683 {
684         const u8 *ie;
685         u8 op_class, chan;
686         int sec_chan = 0, vht = 0;
687         enum phy_type phy_type;
688         u32 info;
689         struct ieee80211_ht_operation *ht_oper = NULL;
690         struct ieee80211_vht_operation *vht_oper = NULL;
691
692         ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
693         if (ie && ie[1] >= 2) {
694                 ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
695
696                 if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
697                         sec_chan = 1;
698                 else if (ht_oper->ht_param &
699                          HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
700                         sec_chan = -1;
701         }
702
703         ie = wpa_bss_get_ie(bss, WLAN_EID_VHT_OPERATION);
704         if (ie && ie[1] >= 1) {
705                 vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
706
707                 if (vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80MHZ ||
708                     vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_160MHZ ||
709                     vht_oper->vht_op_info_chwidth == VHT_CHANWIDTH_80P80MHZ)
710                         vht = vht_oper->vht_op_info_chwidth;
711         }
712
713         if (ieee80211_freq_to_channel_ext(bss->freq, sec_chan, vht, &op_class,
714                                           &chan) == NUM_HOSTAPD_MODES) {
715                 wpa_printf(MSG_DEBUG,
716                            "WNM: Cannot determine operating class and channel");
717                 return -2;
718         }
719
720         phy_type = ieee80211_get_phy_type(bss->freq, (ht_oper != NULL),
721                                           (vht_oper != NULL));
722         if (phy_type == PHY_TYPE_UNSPECIFIED) {
723                 wpa_printf(MSG_DEBUG,
724                            "WNM: Cannot determine BSS phy type for Neighbor Report");
725                 return -2;
726         }
727
728         info = wnm_get_bss_info(wpa_s, bss);
729
730         return wnm_add_nei_rep(buf, len, bss->bssid, info, op_class, chan,
731                                phy_type, pref);
732 }
733
734
735 static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len)
736 {
737         u8 *pos = buf;
738         unsigned int i, pref = 255;
739         struct os_reltime now;
740         struct wpa_ssid *ssid = wpa_s->current_ssid;
741
742         if (!ssid)
743                 return 0;
744
745         /*
746          * TODO: Define when scan results are no longer valid for the candidate
747          * list.
748          */
749         os_get_reltime(&now);
750         if (os_reltime_expired(&now, &wpa_s->last_scan, 10))
751                 return 0;
752
753         wpa_printf(MSG_DEBUG,
754                    "WNM: Add candidate list to BSS Transition Management Response frame");
755         for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) {
756                 struct wpa_bss *bss = wpa_s->last_scan_res[i];
757                 int res;
758
759                 if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) {
760                         res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--);
761                         if (res == -2)
762                                 continue; /* could not build entry for BSS */
763                         if (res < 0)
764                                 break; /* no more room for candidates */
765                         if (pref == 1)
766                                 break;
767
768                         pos += res;
769                         len -= res;
770                 }
771         }
772
773         wpa_hexdump(MSG_DEBUG,
774                     "WNM: BSS Transition Management Response candidate list",
775                     buf, pos - buf);
776
777         return pos - buf;
778 }
779
780
781 static void wnm_send_bss_transition_mgmt_resp(
782         struct wpa_supplicant *wpa_s, u8 dialog_token,
783         enum bss_trans_mgmt_status_code status, u8 delay,
784         const u8 *target_bssid)
785 {
786         u8 buf[2000], *pos;
787         struct ieee80211_mgmt *mgmt;
788         size_t len;
789         int res;
790
791         wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
792                    "to " MACSTR " dialog_token=%u status=%u delay=%d",
793                    MAC2STR(wpa_s->bssid), dialog_token, status, delay);
794         if (!wpa_s->current_bss) {
795                 wpa_printf(MSG_DEBUG,
796                            "WNM: Current BSS not known - drop response");
797                 return;
798         }
799
800         mgmt = (struct ieee80211_mgmt *) buf;
801         os_memset(&buf, 0, sizeof(buf));
802         os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
803         os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
804         os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
805         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
806                                            WLAN_FC_STYPE_ACTION);
807         mgmt->u.action.category = WLAN_ACTION_WNM;
808         mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
809         mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
810         mgmt->u.action.u.bss_tm_resp.status_code = status;
811         mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
812         pos = mgmt->u.action.u.bss_tm_resp.variable;
813         if (target_bssid) {
814                 os_memcpy(pos, target_bssid, ETH_ALEN);
815                 pos += ETH_ALEN;
816         } else if (status == WNM_BSS_TM_ACCEPT) {
817                 /*
818                  * P802.11-REVmc clarifies that the Target BSSID field is always
819                  * present when status code is zero, so use a fake value here if
820                  * no BSSID is yet known.
821                  */
822                 os_memset(pos, 0, ETH_ALEN);
823                 pos += ETH_ALEN;
824         }
825
826         if (status == WNM_BSS_TM_ACCEPT)
827                 pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
828
829 #ifdef CONFIG_MBO
830         if (status != WNM_BSS_TM_ACCEPT) {
831                 pos += wpas_mbo_ie_bss_trans_reject(
832                         wpa_s, pos, buf + sizeof(buf) - pos,
833                         MBO_TRANSITION_REJECT_REASON_UNSPECIFIED);
834         }
835 #endif /* CONFIG_MBO */
836
837         len = pos - (u8 *) &mgmt->u.action.category;
838
839         res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
840                                   wpa_s->own_addr, wpa_s->bssid,
841                                   &mgmt->u.action.category, len, 0);
842         if (res < 0) {
843                 wpa_printf(MSG_DEBUG,
844                            "WNM: Failed to send BSS Transition Management Response");
845         }
846 }
847
848
849 static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
850                                struct wpa_bss *bss, struct wpa_ssid *ssid,
851                                int after_new_scan)
852 {
853         wpa_dbg(wpa_s, MSG_DEBUG,
854                 "WNM: Transition to BSS " MACSTR
855                 " based on BSS Transition Management Request (old BSSID "
856                 MACSTR " after_new_scan=%d)",
857                 MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan);
858
859         /* Send the BSS Management Response - Accept */
860         if (wpa_s->wnm_reply) {
861                 wpa_s->wnm_reply = 0;
862                 wpa_printf(MSG_DEBUG,
863                            "WNM: Sending successful BSS Transition Management Response");
864                 wnm_send_bss_transition_mgmt_resp(wpa_s,
865                                                   wpa_s->wnm_dialog_token,
866                                                   WNM_BSS_TM_ACCEPT,
867                                                   0, bss->bssid);
868         }
869
870         if (bss == wpa_s->current_bss) {
871                 wpa_printf(MSG_DEBUG,
872                            "WNM: Already associated with the preferred candidate");
873                 wnm_deallocate_memory(wpa_s);
874                 return;
875         }
876
877         wpa_s->reassociate = 1;
878         wpa_printf(MSG_DEBUG, "WNM: Issuing connect");
879         wpa_supplicant_connect(wpa_s, bss, ssid);
880         wnm_deallocate_memory(wpa_s);
881 }
882
883
884 int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
885 {
886         struct wpa_bss *bss;
887         struct wpa_ssid *ssid = wpa_s->current_ssid;
888         enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
889
890         if (!wpa_s->wnm_neighbor_report_elements)
891                 return 0;
892
893         wpa_dbg(wpa_s, MSG_DEBUG,
894                 "WNM: Process scan results for BSS Transition Management");
895         if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
896                               &wpa_s->scan_trigger_time)) {
897                 wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
898                 wnm_deallocate_memory(wpa_s);
899                 return 0;
900         }
901
902         if (!wpa_s->current_bss ||
903             os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid,
904                       ETH_ALEN) != 0) {
905                 wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it");
906                 return 0;
907         }
908
909         /* Compare the Neighbor Report and scan results */
910         bss = compare_scan_neighbor_results(wpa_s, 0);
911         if (!bss) {
912                 wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
913                 status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
914                 goto send_bss_resp_fail;
915         }
916
917         /* Associate to the network */
918         wnm_bss_tm_connect(wpa_s, bss, ssid, 1);
919         return 1;
920
921 send_bss_resp_fail:
922         if (!reply_on_fail)
923                 return 0;
924
925         /* Send reject response for all the failures */
926
927         if (wpa_s->wnm_reply) {
928                 wpa_s->wnm_reply = 0;
929                 wnm_send_bss_transition_mgmt_resp(wpa_s,
930                                                   wpa_s->wnm_dialog_token,
931                                                   status, 0, NULL);
932         }
933         wnm_deallocate_memory(wpa_s);
934
935         return 0;
936 }
937
938
939 static int cand_pref_compar(const void *a, const void *b)
940 {
941         const struct neighbor_report *aa = a;
942         const struct neighbor_report *bb = b;
943
944         if (!aa->preference_present && !bb->preference_present)
945                 return 0;
946         if (!aa->preference_present)
947                 return 1;
948         if (!bb->preference_present)
949                 return -1;
950         if (bb->preference > aa->preference)
951                 return 1;
952         if (bb->preference < aa->preference)
953                 return -1;
954         return 0;
955 }
956
957
958 static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s)
959 {
960         if (!wpa_s->wnm_neighbor_report_elements)
961                 return;
962         qsort(wpa_s->wnm_neighbor_report_elements,
963               wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report),
964               cand_pref_compar);
965 }
966
967
968 static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
969 {
970         unsigned int i;
971
972         wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List");
973         if (!wpa_s->wnm_neighbor_report_elements)
974                 return;
975         for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
976                 struct neighbor_report *nei;
977
978                 nei = &wpa_s->wnm_neighbor_report_elements[i];
979                 wpa_printf(MSG_DEBUG, "%u: " MACSTR
980                            " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d",
981                            i, MAC2STR(nei->bssid), nei->bssid_info,
982                            nei->regulatory_class,
983                            nei->channel_number, nei->phy_type,
984                            nei->preference_present ? nei->preference : -1,
985                            nei->freq);
986         }
987 }
988
989
990 static int chan_supported(struct wpa_supplicant *wpa_s, int freq)
991 {
992         unsigned int i;
993
994         for (i = 0; i < wpa_s->hw.num_modes; i++) {
995                 struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
996                 int j;
997
998                 for (j = 0; j < mode->num_channels; j++) {
999                         struct hostapd_channel_data *chan;
1000
1001                         chan = &mode->channels[j];
1002                         if (chan->freq == freq &&
1003                             !(chan->flag & HOSTAPD_CHAN_DISABLED))
1004                                 return 1;
1005                 }
1006         }
1007
1008         return 0;
1009 }
1010
1011
1012 static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
1013 {
1014         int *freqs;
1015         int num_freqs = 0;
1016         unsigned int i;
1017
1018         if (!wpa_s->wnm_neighbor_report_elements)
1019                 return;
1020
1021         if (wpa_s->hw.modes == NULL)
1022                 return;
1023
1024         os_free(wpa_s->next_scan_freqs);
1025         wpa_s->next_scan_freqs = NULL;
1026
1027         freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int));
1028         if (freqs == NULL)
1029                 return;
1030
1031         for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
1032                 struct neighbor_report *nei;
1033
1034                 nei = &wpa_s->wnm_neighbor_report_elements[i];
1035                 if (nei->freq <= 0) {
1036                         wpa_printf(MSG_DEBUG,
1037                                    "WNM: Unknown neighbor operating frequency for "
1038                                    MACSTR " - scan all channels",
1039                                    MAC2STR(nei->bssid));
1040                         os_free(freqs);
1041                         return;
1042                 }
1043                 if (chan_supported(wpa_s, nei->freq))
1044                         add_freq(freqs, &num_freqs, nei->freq);
1045         }
1046
1047         if (num_freqs == 0) {
1048                 os_free(freqs);
1049                 return;
1050         }
1051
1052         wpa_printf(MSG_DEBUG,
1053                    "WNM: Scan %d frequencies based on transition candidate list",
1054                    num_freqs);
1055         wpa_s->next_scan_freqs = freqs;
1056 }
1057
1058
1059 static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
1060 {
1061         struct wpa_scan_results *scan_res;
1062         struct wpa_bss *bss;
1063         struct wpa_ssid *ssid = wpa_s->current_ssid;
1064         u8 i, found = 0;
1065         size_t j;
1066
1067         wpa_dbg(wpa_s, MSG_DEBUG,
1068                 "WNM: Fetch current scan results from the driver for checking transition candidates");
1069         scan_res = wpa_drv_get_scan_results2(wpa_s);
1070         if (!scan_res) {
1071                 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results");
1072                 return 0;
1073         }
1074
1075         if (scan_res->fetch_time.sec == 0)
1076                 os_get_reltime(&scan_res->fetch_time);
1077
1078         filter_scan_res(wpa_s, scan_res);
1079
1080         for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
1081                 struct neighbor_report *nei;
1082
1083                 nei = &wpa_s->wnm_neighbor_report_elements[i];
1084                 if (nei->preference_present && nei->preference == 0)
1085                         continue;
1086
1087                 for (j = 0; j < scan_res->num; j++) {
1088                         struct wpa_scan_res *res;
1089                         const u8 *ssid_ie;
1090
1091                         res = scan_res->res[j];
1092                         if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 ||
1093                             res->age > WNM_SCAN_RESULT_AGE * 1000)
1094                                 continue;
1095                         bss = wpa_s->current_bss;
1096                         ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
1097                         if (bss && ssid_ie &&
1098                             (bss->ssid_len != ssid_ie[1] ||
1099                              os_memcmp(bss->ssid, ssid_ie + 2,
1100                                        bss->ssid_len) != 0))
1101                                 continue;
1102
1103                         /* Potential candidate found */
1104                         found = 1;
1105                         scan_snr(res);
1106                         scan_est_throughput(wpa_s, res);
1107                         wpa_bss_update_scan_res(wpa_s, res,
1108                                                 &scan_res->fetch_time);
1109                 }
1110         }
1111
1112         wpa_scan_results_free(scan_res);
1113         if (!found) {
1114                 wpa_dbg(wpa_s, MSG_DEBUG,
1115                         "WNM: No transition candidate matches existing scan results");
1116                 return 0;
1117         }
1118
1119         bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE);
1120         if (!bss) {
1121                 wpa_dbg(wpa_s, MSG_DEBUG,
1122                         "WNM: Comparison of scan results against transition candidates did not find matches");
1123                 return 0;
1124         }
1125
1126         /* Associate to the network */
1127         wnm_bss_tm_connect(wpa_s, bss, ssid, 0);
1128         return 1;
1129 }
1130
1131
1132 static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
1133                                              const u8 *pos, const u8 *end,
1134                                              int reply)
1135 {
1136         unsigned int beacon_int;
1137         u8 valid_int;
1138 #ifdef CONFIG_MBO
1139         const u8 *vendor;
1140 #endif /* CONFIG_MBO */
1141
1142         if (end - pos < 5)
1143                 return;
1144
1145         if (wpa_s->current_bss)
1146                 beacon_int = wpa_s->current_bss->beacon_int;
1147         else
1148                 beacon_int = 100; /* best guess */
1149
1150         wpa_s->wnm_dialog_token = pos[0];
1151         wpa_s->wnm_mode = pos[1];
1152         wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
1153         valid_int = pos[4];
1154         wpa_s->wnm_reply = reply;
1155
1156         wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
1157                    "dialog_token=%u request_mode=0x%x "
1158                    "disassoc_timer=%u validity_interval=%u",
1159                    wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
1160                    wpa_s->wnm_dissoc_timer, valid_int);
1161
1162         pos += 5;
1163
1164         if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
1165                 if (end - pos < 12) {
1166                         wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
1167                         return;
1168                 }
1169                 os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
1170                 pos += 12; /* BSS Termination Duration */
1171         }
1172
1173         if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
1174                 char url[256];
1175
1176                 if (end - pos < 1 || 1 + pos[0] > end - pos) {
1177                         wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
1178                                    "Management Request (URL)");
1179                         return;
1180                 }
1181                 os_memcpy(url, pos + 1, pos[0]);
1182                 url[pos[0]] = '\0';
1183                 pos += 1 + pos[0];
1184
1185                 wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
1186                         wpa_sm_pmf_enabled(wpa_s->wpa),
1187                         wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
1188         }
1189
1190         if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
1191                 wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
1192                         "Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
1193                 if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) {
1194                         /* TODO: mark current BSS less preferred for
1195                          * selection */
1196                         wpa_printf(MSG_DEBUG, "Trying to find another BSS");
1197                         wpa_supplicant_req_scan(wpa_s, 0, 0);
1198                 }
1199         }
1200
1201 #ifdef CONFIG_MBO
1202         vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
1203         if (vendor)
1204                 wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
1205 #endif /* CONFIG_MBO */
1206
1207         if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
1208                 unsigned int valid_ms;
1209
1210                 wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
1211                 wnm_deallocate_memory(wpa_s);
1212                 wpa_s->wnm_neighbor_report_elements = os_calloc(
1213                         WNM_MAX_NEIGHBOR_REPORT,
1214                         sizeof(struct neighbor_report));
1215                 if (wpa_s->wnm_neighbor_report_elements == NULL)
1216                         return;
1217
1218                 while (end - pos >= 2 &&
1219                        wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
1220                 {
1221                         u8 tag = *pos++;
1222                         u8 len = *pos++;
1223
1224                         wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
1225                                    tag);
1226                         if (len > end - pos) {
1227                                 wpa_printf(MSG_DEBUG, "WNM: Truncated request");
1228                                 return;
1229                         }
1230                         if (tag == WLAN_EID_NEIGHBOR_REPORT) {
1231                                 struct neighbor_report *rep;
1232                                 rep = &wpa_s->wnm_neighbor_report_elements[
1233                                         wpa_s->wnm_num_neighbor_report];
1234                                 wnm_parse_neighbor_report(wpa_s, pos, len, rep);
1235                                 wpa_s->wnm_num_neighbor_report++;
1236                         }
1237
1238                         pos += len;
1239                 }
1240
1241                 if (!wpa_s->wnm_num_neighbor_report) {
1242                         wpa_printf(MSG_DEBUG,
1243                                    "WNM: Candidate list included bit is set, but no candidates found");
1244                         wnm_send_bss_transition_mgmt_resp(
1245                                 wpa_s, wpa_s->wnm_dialog_token,
1246                                 WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
1247                                 0, NULL);
1248                         return;
1249                 }
1250
1251                 wnm_sort_cand_list(wpa_s);
1252                 wnm_dump_cand_list(wpa_s);
1253                 valid_ms = valid_int * beacon_int * 128 / 125;
1254                 wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
1255                            valid_ms);
1256                 os_get_reltime(&wpa_s->wnm_cand_valid_until);
1257                 wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
1258                 wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
1259                 wpa_s->wnm_cand_valid_until.sec +=
1260                         wpa_s->wnm_cand_valid_until.usec / 1000000;
1261                 wpa_s->wnm_cand_valid_until.usec %= 1000000;
1262                 os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
1263
1264                 /*
1265                  * Fetch the latest scan results from the kernel and check for
1266                  * candidates based on those results first. This can help in
1267                  * finding more up-to-date information should the driver has
1268                  * done some internal scanning operations after the last scan
1269                  * result update in wpa_supplicant.
1270                  */
1271                 if (wnm_fetch_scan_results(wpa_s) > 0)
1272                         return;
1273
1274                 /*
1275                  * Try to use previously received scan results, if they are
1276                  * recent enough to use for a connection.
1277                  */
1278                 if (wpa_s->last_scan_res_used > 0) {
1279                         struct os_reltime now;
1280
1281                         os_get_reltime(&now);
1282                         if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) {
1283                                 wpa_printf(MSG_DEBUG,
1284                                            "WNM: Try to use recent scan results");
1285                                 if (wnm_scan_process(wpa_s, 0) > 0)
1286                                         return;
1287                                 wpa_printf(MSG_DEBUG,
1288                                            "WNM: No match in previous scan results - try a new scan");
1289                         }
1290                 }
1291
1292                 wnm_set_scan_freqs(wpa_s);
1293                 if (wpa_s->wnm_num_neighbor_report == 1) {
1294                         os_memcpy(wpa_s->next_scan_bssid,
1295                                   wpa_s->wnm_neighbor_report_elements[0].bssid,
1296                                   ETH_ALEN);
1297                         wpa_printf(MSG_DEBUG,
1298                                    "WNM: Scan only for a specific BSSID since there is only a single candidate "
1299                                    MACSTR, MAC2STR(wpa_s->next_scan_bssid));
1300                 }
1301                 wpa_supplicant_req_scan(wpa_s, 0, 0);
1302         } else if (reply) {
1303                 enum bss_trans_mgmt_status_code status;
1304                 if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
1305                         status = WNM_BSS_TM_ACCEPT;
1306                 else {
1307                         wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
1308                         status = WNM_BSS_TM_REJECT_UNSPECIFIED;
1309                 }
1310                 wnm_send_bss_transition_mgmt_resp(wpa_s,
1311                                                   wpa_s->wnm_dialog_token,
1312                                                   status, 0, NULL);
1313         }
1314 }
1315
1316
1317 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
1318                                        u8 query_reason, int cand_list)
1319 {
1320         u8 buf[2000], *pos;
1321         struct ieee80211_mgmt *mgmt;
1322         size_t len;
1323         int ret;
1324
1325         wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
1326                    MACSTR " query_reason=%u%s",
1327                    MAC2STR(wpa_s->bssid), query_reason,
1328                    cand_list ? " candidate list" : "");
1329
1330         mgmt = (struct ieee80211_mgmt *) buf;
1331         os_memset(&buf, 0, sizeof(buf));
1332         os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
1333         os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
1334         os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
1335         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
1336                                            WLAN_FC_STYPE_ACTION);
1337         mgmt->u.action.category = WLAN_ACTION_WNM;
1338         mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY;
1339         mgmt->u.action.u.bss_tm_query.dialog_token = 1;
1340         mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
1341         pos = mgmt->u.action.u.bss_tm_query.variable;
1342
1343         if (cand_list)
1344                 pos += wnm_add_cand_list(wpa_s, pos, buf + sizeof(buf) - pos);
1345
1346         len = pos - (u8 *) &mgmt->u.action.category;
1347
1348         ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
1349                                   wpa_s->own_addr, wpa_s->bssid,
1350                                   &mgmt->u.action.category, len, 0);
1351
1352         return ret;
1353 }
1354
1355
1356 static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s,
1357                                             const u8 *sa, const u8 *data,
1358                                             int len)
1359 {
1360         const u8 *pos, *end, *next;
1361         u8 ie, ie_len;
1362
1363         pos = data;
1364         end = data + len;
1365
1366         while (end - pos > 1) {
1367                 ie = *pos++;
1368                 ie_len = *pos++;
1369                 wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u",
1370                            ie, ie_len);
1371                 if (ie_len > end - pos) {
1372                         wpa_printf(MSG_DEBUG, "WNM: Not enough room for "
1373                                    "subelement");
1374                         break;
1375                 }
1376                 next = pos + ie_len;
1377                 if (ie_len < 4) {
1378                         pos = next;
1379                         continue;
1380                 }
1381                 wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u",
1382                            WPA_GET_BE24(pos), pos[3]);
1383
1384 #ifdef CONFIG_HS20
1385                 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
1386                     WPA_GET_BE24(pos) == OUI_WFA &&
1387                     pos[3] == HS20_WNM_SUB_REM_NEEDED) {
1388                         /* Subscription Remediation subelement */
1389                         const u8 *ie_end;
1390                         u8 url_len;
1391                         char *url;
1392                         u8 osu_method;
1393
1394                         wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation "
1395                                    "subelement");
1396                         ie_end = pos + ie_len;
1397                         pos += 4;
1398                         url_len = *pos++;
1399                         if (url_len == 0) {
1400                                 wpa_printf(MSG_DEBUG, "WNM: No Server URL included");
1401                                 url = NULL;
1402                                 osu_method = 1;
1403                         } else {
1404                                 if (url_len + 1 > ie_end - pos) {
1405                                         wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
1406                                                    url_len,
1407                                                    (int) (ie_end - pos));
1408                                         break;
1409                                 }
1410                                 url = os_malloc(url_len + 1);
1411                                 if (url == NULL)
1412                                         break;
1413                                 os_memcpy(url, pos, url_len);
1414                                 url[url_len] = '\0';
1415                                 osu_method = pos[url_len];
1416                         }
1417                         hs20_rx_subscription_remediation(wpa_s, url,
1418                                                          osu_method);
1419                         os_free(url);
1420                         pos = next;
1421                         continue;
1422                 }
1423
1424                 if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 &&
1425                     WPA_GET_BE24(pos) == OUI_WFA &&
1426                     pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) {
1427                         const u8 *ie_end;
1428                         u8 url_len;
1429                         char *url;
1430                         u8 code;
1431                         u16 reauth_delay;
1432
1433                         ie_end = pos + ie_len;
1434                         pos += 4;
1435                         code = *pos++;
1436                         reauth_delay = WPA_GET_LE16(pos);
1437                         pos += 2;
1438                         url_len = *pos++;
1439                         wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication "
1440                                    "Imminent - Reason Code %u   "
1441                                    "Re-Auth Delay %u  URL Length %u",
1442                                    code, reauth_delay, url_len);
1443                         if (url_len > ie_end - pos)
1444                                 break;
1445                         url = os_malloc(url_len + 1);
1446                         if (url == NULL)
1447                                 break;
1448                         os_memcpy(url, pos, url_len);
1449                         url[url_len] = '\0';
1450                         hs20_rx_deauth_imminent_notice(wpa_s, code,
1451                                                        reauth_delay, url);
1452                         os_free(url);
1453                         pos = next;
1454                         continue;
1455                 }
1456 #endif /* CONFIG_HS20 */
1457
1458                 pos = next;
1459         }
1460 }
1461
1462
1463 static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s,
1464                                         const u8 *sa, const u8 *frm, int len)
1465 {
1466         const u8 *pos, *end;
1467         u8 dialog_token, type;
1468
1469         /* Dialog Token [1] | Type [1] | Subelements */
1470
1471         if (len < 2 || sa == NULL)
1472                 return;
1473         end = frm + len;
1474         pos = frm;
1475         dialog_token = *pos++;
1476         type = *pos++;
1477
1478         wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request "
1479                 "(dialog_token %u type %u sa " MACSTR ")",
1480                 dialog_token, type, MAC2STR(sa));
1481         wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements",
1482                     pos, end - pos);
1483
1484         if (wpa_s->wpa_state != WPA_COMPLETED ||
1485             os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
1486                 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not "
1487                         "from our AP - ignore it");
1488                 return;
1489         }
1490
1491         switch (type) {
1492         case 1:
1493                 ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos);
1494                 break;
1495         default:
1496                 wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown "
1497                         "WNM-Notification type %u", type);
1498                 break;
1499         }
1500 }
1501
1502
1503 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
1504                               const struct ieee80211_mgmt *mgmt, size_t len)
1505 {
1506         const u8 *pos, *end;
1507         u8 act;
1508
1509         if (len < IEEE80211_HDRLEN + 2)
1510                 return;
1511
1512         pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1;
1513         act = *pos++;
1514         end = ((const u8 *) mgmt) + len;
1515
1516         wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
1517                    act, MAC2STR(mgmt->sa));
1518         if (wpa_s->wpa_state < WPA_ASSOCIATED ||
1519             os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
1520                 wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
1521                            "frame");
1522                 return;
1523         }
1524
1525         switch (act) {
1526         case WNM_BSS_TRANS_MGMT_REQ:
1527                 ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
1528                                                  !(mgmt->da[0] & 0x01));
1529                 break;
1530         case WNM_SLEEP_MODE_RESP:
1531                 ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos);
1532                 break;
1533         case WNM_NOTIFICATION_REQ:
1534                 ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos);
1535                 break;
1536         default:
1537                 wpa_printf(MSG_ERROR, "WNM: Unknown request");
1538                 break;
1539         }
1540 }