]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/src/ap/wnm_ap.c
Update hostapd/wpa_supplicant to 2.8 to fix multiple vulnerabilities.
[FreeBSD/FreeBSD.git] / contrib / wpa / src / ap / wnm_ap.c
1 /*
2  * hostapd - WNM
3  * Copyright (c) 2011-2014, 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 "utils/eloop.h"
13 #include "common/ieee802_11_defs.h"
14 #include "common/wpa_ctrl.h"
15 #include "common/ocv.h"
16 #include "ap/hostapd.h"
17 #include "ap/sta_info.h"
18 #include "ap/ap_config.h"
19 #include "ap/ap_drv_ops.h"
20 #include "ap/wpa_auth.h"
21 #include "mbo_ap.h"
22 #include "wnm_ap.h"
23
24 #define MAX_TFS_IE_LEN  1024
25
26
27 /* get the TFS IE from driver */
28 static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
29                                    u8 *buf, u16 *buf_len, enum wnm_oper oper)
30 {
31         wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
32
33         return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
34 }
35
36
37 /* set the TFS IE to driver */
38 static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
39                                    u8 *buf, u16 *buf_len, enum wnm_oper oper)
40 {
41         wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
42
43         return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
44 }
45
46
47 /* MLME-SLEEPMODE.response */
48 static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
49                                          const u8 *addr, u8 dialog_token,
50                                          u8 action_type, u16 intval)
51 {
52         struct ieee80211_mgmt *mgmt;
53         int res;
54         size_t len;
55         size_t gtk_elem_len = 0;
56         size_t igtk_elem_len = 0;
57         struct wnm_sleep_element wnmsleep_ie;
58         u8 *wnmtfs_ie, *oci_ie;
59         u8 wnmsleep_ie_len, oci_ie_len;
60         u16 wnmtfs_ie_len;
61         u8 *pos;
62         struct sta_info *sta;
63         enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ?
64                 WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE;
65
66         sta = ap_get_sta(hapd, addr);
67         if (sta == NULL) {
68                 wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
69                 return -EINVAL;
70         }
71
72         /* WNM-Sleep Mode IE */
73         os_memset(&wnmsleep_ie, 0, sizeof(struct wnm_sleep_element));
74         wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
75         wnmsleep_ie.eid = WLAN_EID_WNMSLEEP;
76         wnmsleep_ie.len = wnmsleep_ie_len - 2;
77         wnmsleep_ie.action_type = action_type;
78         wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT;
79         wnmsleep_ie.intval = host_to_le16(intval);
80
81         /* TFS IE(s) */
82         wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
83         if (wnmtfs_ie == NULL)
84                 return -1;
85         if (ieee80211_11_get_tfs_ie(hapd, addr, wnmtfs_ie, &wnmtfs_ie_len,
86                                     tfs_oper)) {
87                 wnmtfs_ie_len = 0;
88                 os_free(wnmtfs_ie);
89                 wnmtfs_ie = NULL;
90         }
91
92         oci_ie = NULL;
93         oci_ie_len = 0;
94 #ifdef CONFIG_OCV
95         if (action_type == WNM_SLEEP_MODE_EXIT &&
96             wpa_auth_uses_ocv(sta->wpa_sm)) {
97                 struct wpa_channel_info ci;
98
99                 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
100                         wpa_printf(MSG_WARNING,
101                                    "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
102                         os_free(wnmtfs_ie);
103                         return -1;
104                 }
105
106                 oci_ie_len = OCV_OCI_EXTENDED_LEN;
107                 oci_ie = os_zalloc(oci_ie_len);
108                 if (!oci_ie) {
109                         wpa_printf(MSG_WARNING,
110                                    "Failed to allocate buffer for OCI element in WNM-Sleep Mode frame");
111                         os_free(wnmtfs_ie);
112                         return -1;
113                 }
114
115                 if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
116                         os_free(wnmtfs_ie);
117                         os_free(oci_ie);
118                         return -1;
119                 }
120         }
121 #endif /* CONFIG_OCV */
122
123 #define MAX_GTK_SUBELEM_LEN 45
124 #define MAX_IGTK_SUBELEM_LEN 26
125         mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
126                          MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
127                          oci_ie_len);
128         if (mgmt == NULL) {
129                 wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
130                            "WNM-Sleep Response action frame");
131                 res = -1;
132                 goto fail;
133         }
134         os_memcpy(mgmt->da, addr, ETH_ALEN);
135         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
136         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
137         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
138                                            WLAN_FC_STYPE_ACTION);
139         mgmt->u.action.category = WLAN_ACTION_WNM;
140         mgmt->u.action.u.wnm_sleep_resp.action = WNM_SLEEP_MODE_RESP;
141         mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token;
142         pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
143         /* add key data if MFP is enabled */
144         if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
145             hapd->conf->wnm_sleep_mode_no_keys ||
146             action_type != WNM_SLEEP_MODE_EXIT) {
147                 mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
148         } else {
149                 gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos);
150                 pos += gtk_elem_len;
151                 wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
152                            (int) gtk_elem_len);
153 #ifdef CONFIG_IEEE80211W
154                 res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
155                 if (res < 0)
156                         goto fail;
157                 igtk_elem_len = res;
158                 pos += igtk_elem_len;
159                 wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
160                            (int) igtk_elem_len);
161 #endif /* CONFIG_IEEE80211W */
162
163                 WPA_PUT_LE16((u8 *)
164                              &mgmt->u.action.u.wnm_sleep_resp.keydata_len,
165                              gtk_elem_len + igtk_elem_len);
166         }
167         os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
168         /* copy TFS IE here */
169         pos += wnmsleep_ie_len;
170         if (wnmtfs_ie) {
171                 os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
172                 pos += wnmtfs_ie_len;
173         }
174 #ifdef CONFIG_OCV
175         /* copy OCV OCI here */
176         if (oci_ie_len > 0)
177                 os_memcpy(pos, oci_ie, oci_ie_len);
178 #endif /* CONFIG_OCV */
179
180         len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
181                 igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
182
183         /* In driver, response frame should be forced to sent when STA is in
184          * PS mode */
185         res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
186                                       mgmt->da, &mgmt->u.action.category, len);
187
188         if (!res) {
189                 wpa_printf(MSG_DEBUG, "Successfully send WNM-Sleep Response "
190                            "frame");
191
192                 /* when entering wnmsleep
193                  * 1. pause the node in driver
194                  * 2. mark the node so that AP won't update GTK/IGTK during
195                  * WNM Sleep
196                  */
197                 if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
198                     wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
199                         sta->flags |= WLAN_STA_WNM_SLEEP_MODE;
200                         hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
201                                              addr, NULL, NULL);
202                         wpa_set_wnmsleep(sta->wpa_sm, 1);
203                 }
204                 /* when exiting wnmsleep
205                  * 1. unmark the node
206                  * 2. start GTK/IGTK update if MFP is not used
207                  * 3. unpause the node in driver
208                  */
209                 if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
210                      wnmsleep_ie.status ==
211                      WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) &&
212                     wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) {
213                         sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
214                         wpa_set_wnmsleep(sta->wpa_sm, 0);
215                         hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
216                                              addr, NULL, NULL);
217                         if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
218                             hapd->conf->wnm_sleep_mode_no_keys)
219                                 wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
220                 }
221         } else
222                 wpa_printf(MSG_DEBUG, "Fail to send WNM-Sleep Response frame");
223
224 #undef MAX_GTK_SUBELEM_LEN
225 #undef MAX_IGTK_SUBELEM_LEN
226 fail:
227         os_free(wnmtfs_ie);
228         os_free(oci_ie);
229         os_free(mgmt);
230         return res;
231 }
232
233
234 static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
235                                        const u8 *addr, const u8 *frm, int len)
236 {
237         /* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
238         const u8 *pos = frm;
239         u8 dialog_token;
240         struct wnm_sleep_element *wnmsleep_ie = NULL;
241         /* multiple TFS Req IE (assuming consecutive) */
242         u8 *tfsreq_ie_start = NULL;
243         u8 *tfsreq_ie_end = NULL;
244         u16 tfsreq_ie_len = 0;
245 #ifdef CONFIG_OCV
246         struct sta_info *sta;
247         const u8 *oci_ie = NULL;
248         u8 oci_ie_len = 0;
249 #endif /* CONFIG_OCV */
250
251         if (!hapd->conf->wnm_sleep_mode) {
252                 wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from "
253                            MACSTR " since WNM-Sleep Mode is disabled",
254                            MAC2STR(addr));
255                 return;
256         }
257
258         if (len < 1) {
259                 wpa_printf(MSG_DEBUG,
260                            "WNM: Ignore too short WNM-Sleep Mode Request from "
261                            MACSTR, MAC2STR(addr));
262                 return;
263         }
264
265         dialog_token = *pos++;
266         while (pos + 1 < frm + len) {
267                 u8 ie_len = pos[1];
268                 if (pos + 2 + ie_len > frm + len)
269                         break;
270                 if (*pos == WLAN_EID_WNMSLEEP &&
271                     ie_len >= (int) sizeof(*wnmsleep_ie) - 2)
272                         wnmsleep_ie = (struct wnm_sleep_element *) pos;
273                 else if (*pos == WLAN_EID_TFS_REQ) {
274                         if (!tfsreq_ie_start)
275                                 tfsreq_ie_start = (u8 *) pos;
276                         tfsreq_ie_end = (u8 *) pos;
277 #ifdef CONFIG_OCV
278                 } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
279                            pos[2] == WLAN_EID_EXT_OCV_OCI) {
280                         oci_ie = pos + 3;
281                         oci_ie_len = ie_len - 1;
282 #endif /* CONFIG_OCV */
283                 } else
284                         wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
285                                    *pos);
286                 pos += ie_len + 2;
287         }
288
289         if (!wnmsleep_ie) {
290                 wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
291                 return;
292         }
293
294 #ifdef CONFIG_OCV
295         sta = ap_get_sta(hapd, addr);
296         if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
297             sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
298                 struct wpa_channel_info ci;
299
300                 if (hostapd_drv_channel_info(hapd, &ci) != 0) {
301                         wpa_printf(MSG_WARNING,
302                                    "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
303                         return;
304                 }
305
306                 if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
307                                          channel_width_to_int(ci.chanwidth),
308                                          ci.seg1_idx) != 0) {
309                         wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
310                         return;
311                 }
312         }
313 #endif /* CONFIG_OCV */
314
315         if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
316             tfsreq_ie_start && tfsreq_ie_end &&
317             tfsreq_ie_end - tfsreq_ie_start >= 0) {
318                 tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) -
319                         tfsreq_ie_start;
320                 wpa_printf(MSG_DEBUG, "TFS Req IE(s) found");
321                 /* pass the TFS Req IE(s) to driver for processing */
322                 if (ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
323                                             &tfsreq_ie_len,
324                                             WNM_SLEEP_TFS_REQ_IE_SET))
325                         wpa_printf(MSG_DEBUG, "Fail to set TFS Req IE");
326         }
327
328         ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token,
329                                       wnmsleep_ie->action_type,
330                                       le_to_host16(wnmsleep_ie->intval));
331
332         if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
333                 /* clear the tfs after sending the resp frame */
334                 ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
335                                         &tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL);
336         }
337 }
338
339
340 static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
341                                                   const u8 *addr,
342                                                   u8 dialog_token)
343 {
344         struct ieee80211_mgmt *mgmt;
345         size_t len;
346         u8 *pos;
347         int res;
348
349         mgmt = os_zalloc(sizeof(*mgmt));
350         if (mgmt == NULL)
351                 return -1;
352         os_memcpy(mgmt->da, addr, ETH_ALEN);
353         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
354         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
355         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
356                                            WLAN_FC_STYPE_ACTION);
357         mgmt->u.action.category = WLAN_ACTION_WNM;
358         mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
359         mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
360         mgmt->u.action.u.bss_tm_req.req_mode = 0;
361         mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
362         mgmt->u.action.u.bss_tm_req.validity_interval = 1;
363         pos = mgmt->u.action.u.bss_tm_req.variable;
364
365         wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
366                    MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
367                    "validity_interval=%u",
368                    MAC2STR(addr), dialog_token,
369                    mgmt->u.action.u.bss_tm_req.req_mode,
370                    le_to_host16(mgmt->u.action.u.bss_tm_req.disassoc_timer),
371                    mgmt->u.action.u.bss_tm_req.validity_interval);
372
373         len = pos - &mgmt->u.action.category;
374         res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
375                                       mgmt->da, &mgmt->u.action.category, len);
376         os_free(mgmt);
377         return res;
378 }
379
380
381 static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd,
382                                                const u8 *addr, const u8 *frm,
383                                                size_t len)
384 {
385         u8 dialog_token, reason;
386         const u8 *pos, *end;
387         int enabled = hapd->conf->bss_transition;
388
389 #ifdef CONFIG_MBO
390         if (hapd->conf->mbo_enabled)
391                 enabled = 1;
392 #endif /* CONFIG_MBO */
393         if (!enabled) {
394                 wpa_printf(MSG_DEBUG,
395                            "Ignore BSS Transition Management Query from "
396                            MACSTR
397                            " since BSS Transition Management is disabled",
398                            MAC2STR(addr));
399                 return;
400         }
401
402         if (len < 2) {
403                 wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Query from "
404                            MACSTR, MAC2STR(addr));
405                 return;
406         }
407
408         pos = frm;
409         end = pos + len;
410         dialog_token = *pos++;
411         reason = *pos++;
412
413         wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query from "
414                    MACSTR " dialog_token=%u reason=%u",
415                    MAC2STR(addr), dialog_token, reason);
416
417         wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
418                     pos, end - pos);
419
420         ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
421 }
422
423
424 void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx)
425 {
426         struct hostapd_data *hapd = eloop_ctx;
427         struct sta_info *sta = timeout_ctx;
428
429         if (sta->agreed_to_steer) {
430                 wpa_printf(MSG_DEBUG, "%s: Reset steering flag for STA " MACSTR,
431                            hapd->conf->iface, MAC2STR(sta->addr));
432                 sta->agreed_to_steer = 0;
433         }
434 }
435
436
437 static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
438                                               const u8 *addr, const u8 *frm,
439                                               size_t len)
440 {
441         u8 dialog_token, status_code, bss_termination_delay;
442         const u8 *pos, *end;
443         int enabled = hapd->conf->bss_transition;
444         struct sta_info *sta;
445
446 #ifdef CONFIG_MBO
447         if (hapd->conf->mbo_enabled)
448                 enabled = 1;
449 #endif /* CONFIG_MBO */
450         if (!enabled) {
451                 wpa_printf(MSG_DEBUG,
452                            "Ignore BSS Transition Management Response from "
453                            MACSTR
454                            " since BSS Transition Management is disabled",
455                            MAC2STR(addr));
456                 return;
457         }
458
459         if (len < 3) {
460                 wpa_printf(MSG_DEBUG, "WNM: Ignore too short BSS Transition Management Response from "
461                            MACSTR, MAC2STR(addr));
462                 return;
463         }
464
465         pos = frm;
466         end = pos + len;
467         dialog_token = *pos++;
468         status_code = *pos++;
469         bss_termination_delay = *pos++;
470
471         wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Response from "
472                    MACSTR " dialog_token=%u status_code=%u "
473                    "bss_termination_delay=%u", MAC2STR(addr), dialog_token,
474                    status_code, bss_termination_delay);
475
476         sta = ap_get_sta(hapd, addr);
477         if (!sta) {
478                 wpa_printf(MSG_DEBUG, "Station " MACSTR
479                            " not found for received BSS TM Response",
480                            MAC2STR(addr));
481                 return;
482         }
483
484         if (status_code == WNM_BSS_TM_ACCEPT) {
485                 if (end - pos < ETH_ALEN) {
486                         wpa_printf(MSG_DEBUG, "WNM: not enough room for Target BSSID field");
487                         return;
488                 }
489                 sta->agreed_to_steer = 1;
490                 eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
491                 eloop_register_timeout(2, 0, ap_sta_reset_steer_flag_timer,
492                                        hapd, sta);
493                 wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
494                            MAC2STR(pos));
495                 wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
496                         " status_code=%u bss_termination_delay=%u target_bssid="
497                         MACSTR,
498                         MAC2STR(addr), status_code, bss_termination_delay,
499                         MAC2STR(pos));
500                 pos += ETH_ALEN;
501         } else {
502                 sta->agreed_to_steer = 0;
503                 wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
504                         " status_code=%u bss_termination_delay=%u",
505                         MAC2STR(addr), status_code, bss_termination_delay);
506         }
507
508         wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
509                     pos, end - pos);
510 }
511
512
513 static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
514                                                const u8 *addr, const u8 *buf,
515                                                size_t len)
516 {
517         u8 dialog_token, type;
518
519         if (len < 2)
520                 return;
521         dialog_token = *buf++;
522         type = *buf++;
523         len -= 2;
524
525         wpa_printf(MSG_DEBUG,
526                    "WNM: Received WNM Notification Request frame from "
527                    MACSTR " (dialog_token=%u type=%u)",
528                    MAC2STR(addr), dialog_token, type);
529         wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
530                     buf, len);
531         if (type == WLAN_EID_VENDOR_SPECIFIC)
532                 mbo_ap_wnm_notification_req(hapd, addr, buf, len);
533 }
534
535
536 static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd,
537                                                 const u8 *addr, const u8 *buf,
538                                                 size_t len)
539 {
540         u8 dialog_token;
541         char *hex;
542         size_t hex_len;
543
544         if (!hapd->conf->coloc_intf_reporting) {
545                 wpa_printf(MSG_DEBUG,
546                            "WNM: Ignore unexpected Collocated Interference Report from "
547                            MACSTR, MAC2STR(addr));
548                 return;
549         }
550
551         if (len < 1) {
552                 wpa_printf(MSG_DEBUG,
553                            "WNM: Ignore too short Collocated Interference Report from "
554                            MACSTR, MAC2STR(addr));
555                 return;
556         }
557         dialog_token = *buf++;
558         len--;
559
560         wpa_printf(MSG_DEBUG,
561                    "WNM: Received Collocated Interference Report frame from "
562                    MACSTR " (dialog_token=%u)",
563                    MAC2STR(addr), dialog_token);
564         wpa_hexdump(MSG_MSGDUMP, "WNM: Collocated Interference Report Elements",
565                     buf, len);
566
567         hex_len = 2 * len + 1;
568         hex = os_malloc(hex_len);
569         if (!hex)
570                 return;
571         wpa_snprintf_hex(hex, hex_len, buf, len);
572         wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, COLOC_INTF_REPORT MACSTR " %d %s",
573                      MAC2STR(addr), dialog_token, hex);
574         os_free(hex);
575 }
576
577
578 int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
579                                 const struct ieee80211_mgmt *mgmt, size_t len)
580 {
581         u8 action;
582         const u8 *payload;
583         size_t plen;
584
585         if (len < IEEE80211_HDRLEN + 2)
586                 return -1;
587
588         payload = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1;
589         action = *payload++;
590         plen = len - IEEE80211_HDRLEN - 2;
591
592         switch (action) {
593         case WNM_BSS_TRANS_MGMT_QUERY:
594                 ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload,
595                                                    plen);
596                 return 0;
597         case WNM_BSS_TRANS_MGMT_RESP:
598                 ieee802_11_rx_bss_trans_mgmt_resp(hapd, mgmt->sa, payload,
599                                                   plen);
600                 return 0;
601         case WNM_SLEEP_MODE_REQ:
602                 ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen);
603                 return 0;
604         case WNM_NOTIFICATION_REQ:
605                 ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload,
606                                                    plen);
607                 return 0;
608         case WNM_COLLOCATED_INTERFERENCE_REPORT:
609                 ieee802_11_rx_wnm_coloc_intf_report(hapd, mgmt->sa, payload,
610                                                     plen);
611                 return 0;
612         }
613
614         wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
615                    action, MAC2STR(mgmt->sa));
616         return -1;
617 }
618
619
620 int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
621                                struct sta_info *sta, int disassoc_timer)
622 {
623         u8 buf[1000], *pos;
624         struct ieee80211_mgmt *mgmt;
625
626         os_memset(buf, 0, sizeof(buf));
627         mgmt = (struct ieee80211_mgmt *) buf;
628         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
629                                            WLAN_FC_STYPE_ACTION);
630         os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
631         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
632         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
633         mgmt->u.action.category = WLAN_ACTION_WNM;
634         mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
635         mgmt->u.action.u.bss_tm_req.dialog_token = 1;
636         mgmt->u.action.u.bss_tm_req.req_mode =
637                 WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
638         mgmt->u.action.u.bss_tm_req.disassoc_timer =
639                 host_to_le16(disassoc_timer);
640         mgmt->u.action.u.bss_tm_req.validity_interval = 0;
641
642         pos = mgmt->u.action.u.bss_tm_req.variable;
643
644         wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
645                    MACSTR, disassoc_timer, MAC2STR(sta->addr));
646         if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
647                 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
648                            "Management Request frame");
649                 return -1;
650         }
651
652         return 0;
653 }
654
655
656 static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
657                                int disassoc_timer)
658 {
659         int timeout, beacon_int;
660
661         /*
662          * Prevent STA from reconnecting using cached PMKSA to force
663          * full authentication with the authentication server (which may
664          * decide to reject the connection),
665          */
666         wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
667
668         beacon_int = hapd->iconf->beacon_int;
669         if (beacon_int < 1)
670                 beacon_int = 100; /* best guess */
671         /* Calculate timeout in ms based on beacon_int in TU */
672         timeout = disassoc_timer * beacon_int * 128 / 125;
673         wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
674                    " set to %d ms", MAC2STR(sta->addr), timeout);
675
676         sta->timeout_next = STA_DISASSOC_FROM_CLI;
677         eloop_cancel_timeout(ap_handle_timer, hapd, sta);
678         eloop_register_timeout(timeout / 1000,
679                                timeout % 1000 * 1000,
680                                ap_handle_timer, hapd, sta);
681 }
682
683
684 int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
685                                    struct sta_info *sta, const char *url,
686                                    int disassoc_timer)
687 {
688         u8 buf[1000], *pos;
689         struct ieee80211_mgmt *mgmt;
690         size_t url_len;
691
692         os_memset(buf, 0, sizeof(buf));
693         mgmt = (struct ieee80211_mgmt *) buf;
694         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
695                                            WLAN_FC_STYPE_ACTION);
696         os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
697         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
698         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
699         mgmt->u.action.category = WLAN_ACTION_WNM;
700         mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
701         mgmt->u.action.u.bss_tm_req.dialog_token = 1;
702         mgmt->u.action.u.bss_tm_req.req_mode =
703                 WNM_BSS_TM_REQ_DISASSOC_IMMINENT |
704                 WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
705         mgmt->u.action.u.bss_tm_req.disassoc_timer =
706                 host_to_le16(disassoc_timer);
707         mgmt->u.action.u.bss_tm_req.validity_interval = 0x01;
708
709         pos = mgmt->u.action.u.bss_tm_req.variable;
710
711         /* Session Information URL */
712         url_len = os_strlen(url);
713         if (url_len > 255)
714                 return -1;
715         *pos++ = url_len;
716         os_memcpy(pos, url, url_len);
717         pos += url_len;
718
719         if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
720                 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
721                            "Management Request frame");
722                 return -1;
723         }
724
725         if (disassoc_timer) {
726                 /* send disassociation frame after time-out */
727                 set_disassoc_timer(hapd, sta, disassoc_timer);
728         }
729
730         return 0;
731 }
732
733
734 int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
735                         u8 req_mode, int disassoc_timer, u8 valid_int,
736                         const u8 *bss_term_dur, const char *url,
737                         const u8 *nei_rep, size_t nei_rep_len,
738                         const u8 *mbo_attrs, size_t mbo_len)
739 {
740         u8 *buf, *pos;
741         struct ieee80211_mgmt *mgmt;
742         size_t url_len;
743
744         wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
745                    MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x",
746                    MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int);
747         buf = os_zalloc(1000 + nei_rep_len + mbo_len);
748         if (buf == NULL)
749                 return -1;
750         mgmt = (struct ieee80211_mgmt *) buf;
751         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
752                                            WLAN_FC_STYPE_ACTION);
753         os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
754         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
755         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
756         mgmt->u.action.category = WLAN_ACTION_WNM;
757         mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
758         mgmt->u.action.u.bss_tm_req.dialog_token = 1;
759         mgmt->u.action.u.bss_tm_req.req_mode = req_mode;
760         mgmt->u.action.u.bss_tm_req.disassoc_timer =
761                 host_to_le16(disassoc_timer);
762         mgmt->u.action.u.bss_tm_req.validity_interval = valid_int;
763
764         pos = mgmt->u.action.u.bss_tm_req.variable;
765
766         if ((req_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) &&
767             bss_term_dur) {
768                 os_memcpy(pos, bss_term_dur, 12);
769                 pos += 12;
770         }
771
772         if (url) {
773                 /* Session Information URL */
774                 url_len = os_strlen(url);
775                 if (url_len > 255) {
776                         os_free(buf);
777                         return -1;
778                 }
779
780                 *pos++ = url_len;
781                 os_memcpy(pos, url, url_len);
782                 pos += url_len;
783         }
784
785         if (nei_rep) {
786                 os_memcpy(pos, nei_rep, nei_rep_len);
787                 pos += nei_rep_len;
788         }
789
790         if (mbo_len > 0) {
791                 pos += mbo_add_ie(pos, buf + sizeof(buf) - pos, mbo_attrs,
792                                   mbo_len);
793         }
794
795         if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
796                 wpa_printf(MSG_DEBUG,
797                            "Failed to send BSS Transition Management Request frame");
798                 os_free(buf);
799                 return -1;
800         }
801         os_free(buf);
802
803         if (disassoc_timer) {
804                 /* send disassociation frame after time-out */
805                 set_disassoc_timer(hapd, sta, disassoc_timer);
806         }
807
808         return 0;
809 }
810
811
812 int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
813                             unsigned int auto_report, unsigned int timeout)
814 {
815         u8 buf[100], *pos;
816         struct ieee80211_mgmt *mgmt;
817         u8 dialog_token = 1;
818
819         if (auto_report > 3 || timeout > 63)
820                 return -1;
821         os_memset(buf, 0, sizeof(buf));
822         mgmt = (struct ieee80211_mgmt *) buf;
823         mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
824                                            WLAN_FC_STYPE_ACTION);
825         os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
826         os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
827         os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
828         mgmt->u.action.category = WLAN_ACTION_WNM;
829         mgmt->u.action.u.coloc_intf_req.action =
830                 WNM_COLLOCATED_INTERFERENCE_REQ;
831         mgmt->u.action.u.coloc_intf_req.dialog_token = dialog_token;
832         mgmt->u.action.u.coloc_intf_req.req_info = auto_report | (timeout << 2);
833         pos = &mgmt->u.action.u.coloc_intf_req.req_info;
834         pos++;
835
836         wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
837                    MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
838                    MAC2STR(sta->addr), dialog_token, auto_report, timeout);
839         if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
840                 wpa_printf(MSG_DEBUG,
841                            "WNM: Failed to send Collocated Interference Request frame");
842                 return -1;
843         }
844
845         return 0;
846 }