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