xref: /freebsd/contrib/wpa/src/ap/ctrl_iface_ap.c (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
1 /*
2  * Control interface for shared AP commands
3  * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
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/sae.h"
14 #include "eapol_auth/eapol_auth_sm.h"
15 #include "fst/fst_ctrl_iface.h"
16 #include "hostapd.h"
17 #include "ieee802_1x.h"
18 #include "wpa_auth.h"
19 #include "ieee802_11.h"
20 #include "sta_info.h"
21 #include "wps_hostapd.h"
22 #include "p2p_hostapd.h"
23 #include "ctrl_iface_ap.h"
24 #include "ap_drv_ops.h"
25 #include "mbo_ap.h"
26 #include "taxonomy.h"
27 
28 
29 static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
30 					   size_t curr_len, const u8 *mcs_set)
31 {
32 	int ret;
33 	size_t len = curr_len;
34 
35 	ret = os_snprintf(buf + len, buflen - len,
36 			  "ht_mcs_bitmask=");
37 	if (os_snprintf_error(buflen - len, ret))
38 		return len;
39 	len += ret;
40 
41 	/* 77 first bits (+ 3 reserved bits) */
42 	len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
43 
44 	ret = os_snprintf(buf + len, buflen - len, "\n");
45 	if (os_snprintf_error(buflen - len, ret))
46 		return curr_len;
47 	len += ret;
48 
49 	return len;
50 }
51 
52 
53 static int hostapd_get_sta_conn_time(struct sta_info *sta,
54 				     struct hostap_sta_driver_data *data,
55 				     char *buf, size_t buflen)
56 {
57 	struct os_reltime age;
58 	unsigned long secs;
59 	int ret;
60 
61 	if (sta->connected_time.sec) {
62 		/* Locally maintained time in AP mode */
63 		os_reltime_age(&sta->connected_time, &age);
64 		secs = (unsigned long) age.sec;
65 	} else if (data->flags & STA_DRV_DATA_CONN_TIME) {
66 		/* Time from the driver in mesh mode */
67 		secs = data->connected_sec;
68 	} else {
69 		return 0;
70 	}
71 
72 	ret = os_snprintf(buf, buflen, "connected_time=%lu\n", secs);
73 	if (os_snprintf_error(buflen, ret))
74 		return 0;
75 	return ret;
76 }
77 
78 
79 static int hostapd_get_sta_info(struct hostapd_data *hapd,
80 				struct sta_info *sta,
81 				char *buf, size_t buflen)
82 {
83 	struct hostap_sta_driver_data data;
84 	int ret;
85 	int len = 0;
86 
87 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
88 		return 0;
89 
90 	ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
91 			  "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
92 			  "signal=%d\n",
93 			  data.rx_packets, data.tx_packets,
94 			  data.rx_bytes, data.tx_bytes, data.inactive_msec,
95 			  data.signal);
96 	if (os_snprintf_error(buflen, ret))
97 		return 0;
98 	len += ret;
99 
100 	ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
101 			  data.current_rx_rate);
102 	if (os_snprintf_error(buflen - len, ret))
103 		return len;
104 	len += ret;
105 	if (data.flags & STA_DRV_DATA_RX_MCS) {
106 		ret = os_snprintf(buf + len, buflen - len, " mcs %u",
107 				  data.rx_mcs);
108 		if (!os_snprintf_error(buflen - len, ret))
109 			len += ret;
110 	}
111 	if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
112 		ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
113 				  data.rx_vhtmcs);
114 		if (!os_snprintf_error(buflen - len, ret))
115 			len += ret;
116 	}
117 	if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
118 		ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
119 				  data.rx_vht_nss);
120 		if (!os_snprintf_error(buflen - len, ret))
121 			len += ret;
122 	}
123 	if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
124 		ret = os_snprintf(buf + len, buflen - len, " shortGI");
125 		if (!os_snprintf_error(buflen - len, ret))
126 			len += ret;
127 	}
128 	ret = os_snprintf(buf + len, buflen - len, "\n");
129 	if (!os_snprintf_error(buflen - len, ret))
130 		len += ret;
131 
132 	ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
133 			  data.current_tx_rate);
134 	if (os_snprintf_error(buflen - len, ret))
135 		return len;
136 	len += ret;
137 	if (data.flags & STA_DRV_DATA_TX_MCS) {
138 		ret = os_snprintf(buf + len, buflen - len, " mcs %u",
139 				  data.tx_mcs);
140 		if (!os_snprintf_error(buflen - len, ret))
141 			len += ret;
142 	}
143 	if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
144 		ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
145 				  data.tx_vhtmcs);
146 		if (!os_snprintf_error(buflen - len, ret))
147 			len += ret;
148 	}
149 	if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
150 		ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
151 				  data.tx_vht_nss);
152 		if (!os_snprintf_error(buflen - len, ret))
153 			len += ret;
154 	}
155 	if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
156 		ret = os_snprintf(buf + len, buflen - len, " shortGI");
157 		if (!os_snprintf_error(buflen - len, ret))
158 			len += ret;
159 	}
160 	ret = os_snprintf(buf + len, buflen - len, "\n");
161 	if (!os_snprintf_error(buflen - len, ret))
162 		len += ret;
163 
164 	if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
165 		ret = os_snprintf(buf + len, buflen - len,
166 				  "rx_vht_mcs_map=%04x\n"
167 				  "tx_vht_mcs_map=%04x\n",
168 				  le_to_host16(sta->vht_capabilities->
169 					       vht_supported_mcs_set.rx_map),
170 				  le_to_host16(sta->vht_capabilities->
171 					       vht_supported_mcs_set.tx_map));
172 		if (!os_snprintf_error(buflen - len, ret))
173 			len += ret;
174 	}
175 
176 	if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
177 		len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
178 						   sta->ht_capabilities->
179 						   supported_mcs_set);
180 	}
181 
182 	if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
183 		ret = os_snprintf(buf + len, buflen - len,
184 				  "last_ack_signal=%d\n", data.last_ack_rssi);
185 		if (!os_snprintf_error(buflen - len, ret))
186 			len += ret;
187 	}
188 
189 	len += hostapd_get_sta_conn_time(sta, &data, buf + len, buflen - len);
190 
191 	return len;
192 }
193 
194 
195 static const char * timeout_next_str(int val)
196 {
197 	switch (val) {
198 	case STA_NULLFUNC:
199 		return "NULLFUNC POLL";
200 	case STA_DISASSOC:
201 		return "DISASSOC";
202 	case STA_DEAUTH:
203 		return "DEAUTH";
204 	case STA_REMOVE:
205 		return "REMOVE";
206 	case STA_DISASSOC_FROM_CLI:
207 		return "DISASSOC_FROM_CLI";
208 	}
209 
210 	return "?";
211 }
212 
213 
214 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
215 				      struct sta_info *sta,
216 				      char *buf, size_t buflen)
217 {
218 	int len, res, ret, i;
219 	const char *keyid;
220 
221 	if (!sta)
222 		return 0;
223 
224 	len = 0;
225 	ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
226 			  MAC2STR(sta->addr));
227 	if (os_snprintf_error(buflen - len, ret))
228 		return len;
229 	len += ret;
230 
231 	ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
232 	if (ret < 0)
233 		return len;
234 	len += ret;
235 
236 	ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
237 			  "listen_interval=%d\nsupported_rates=",
238 			  sta->aid, sta->capability, sta->listen_interval);
239 	if (os_snprintf_error(buflen - len, ret))
240 		return len;
241 	len += ret;
242 
243 	for (i = 0; i < sta->supported_rates_len; i++) {
244 		ret = os_snprintf(buf + len, buflen - len, "%02x%s",
245 				  sta->supported_rates[i],
246 				  i + 1 < sta->supported_rates_len ? " " : "");
247 		if (os_snprintf_error(buflen - len, ret))
248 			return len;
249 		len += ret;
250 	}
251 
252 	ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
253 			  timeout_next_str(sta->timeout_next));
254 	if (os_snprintf_error(buflen - len, ret))
255 		return len;
256 	len += ret;
257 
258 	res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
259 	if (res >= 0)
260 		len += res;
261 	res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
262 	if (res >= 0)
263 		len += res;
264 	res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
265 	if (res >= 0)
266 		len += res;
267 	res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
268 				      buflen - len);
269 	if (res >= 0)
270 		len += res;
271 	res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
272 	if (res >= 0)
273 		len += res;
274 
275 	len += hostapd_get_sta_info(hapd, sta, buf + len, buflen - len);
276 
277 #ifdef CONFIG_SAE
278 	if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
279 		res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
280 				  sta->sae->group);
281 		if (!os_snprintf_error(buflen - len, res))
282 			len += res;
283 	}
284 
285 	if (sta->sae && sta->sae->tmp) {
286 		const u8 *pos;
287 		unsigned int j, count;
288 		struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
289 
290 		res = os_snprintf(buf + len, buflen - len,
291 				  "sae_rejected_groups=");
292 		if (!os_snprintf_error(buflen - len, res))
293 			len += res;
294 
295 		if (groups) {
296 			pos = wpabuf_head(groups);
297 			count = wpabuf_len(groups) / 2;
298 		} else {
299 			pos = NULL;
300 			count = 0;
301 		}
302 		for (j = 0; pos && j < count; j++) {
303 			res = os_snprintf(buf + len, buflen - len, "%s%d",
304 					  j == 0 ? "" : " ", WPA_GET_LE16(pos));
305 			if (!os_snprintf_error(buflen - len, res))
306 				len += res;
307 			pos += 2;
308 		}
309 
310 		res = os_snprintf(buf + len, buflen - len, "\n");
311 		if (!os_snprintf_error(buflen - len, res))
312 			len += res;
313 	}
314 #endif /* CONFIG_SAE */
315 
316 	if (sta->vlan_id > 0) {
317 		res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
318 				  sta->vlan_id);
319 		if (!os_snprintf_error(buflen - len, res))
320 			len += res;
321 	}
322 
323 	res = mbo_ap_get_info(sta, buf + len, buflen - len);
324 	if (res >= 0)
325 		len += res;
326 
327 	if (sta->supp_op_classes &&
328 	    buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
329 		len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
330 		len += wpa_snprintf_hex(buf + len, buflen - len,
331 					sta->supp_op_classes + 1,
332 					sta->supp_op_classes[0]);
333 		len += os_snprintf(buf + len, buflen - len, "\n");
334 	}
335 
336 	if (sta->power_capab) {
337 		ret = os_snprintf(buf + len, buflen - len,
338 				  "min_txpower=%d\n"
339 				  "max_txpower=%d\n",
340 				  sta->min_tx_power, sta->max_tx_power);
341 		if (!os_snprintf_error(buflen - len, ret))
342 			len += ret;
343 	}
344 
345 #ifdef CONFIG_IEEE80211AC
346 	if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
347 		res = os_snprintf(buf + len, buflen - len,
348 				  "vht_caps_info=0x%08x\n",
349 				  le_to_host32(sta->vht_capabilities->
350 					       vht_capabilities_info));
351 		if (!os_snprintf_error(buflen - len, res))
352 			len += res;
353 	}
354 #endif /* CONFIG_IEEE80211AC */
355 
356 	if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
357 		res = os_snprintf(buf + len, buflen - len,
358 				  "ht_caps_info=0x%04x\n",
359 				  le_to_host16(sta->ht_capabilities->
360 					       ht_capabilities_info));
361 		if (!os_snprintf_error(buflen - len, res))
362 			len += res;
363 	}
364 
365 	if (sta->ext_capability &&
366 	    buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
367 		len += os_snprintf(buf + len, buflen - len, "ext_capab=");
368 		len += wpa_snprintf_hex(buf + len, buflen - len,
369 					sta->ext_capability + 1,
370 					sta->ext_capability[0]);
371 		len += os_snprintf(buf + len, buflen - len, "\n");
372 	}
373 
374 	if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
375 		ret = os_snprintf(buf + len, buflen - len,
376 				  "wds_sta_ifname=%s\n", sta->ifname_wds);
377 		if (!os_snprintf_error(buflen - len, ret))
378 			len += ret;
379 	}
380 
381 	keyid = ap_sta_wpa_get_keyid(hapd, sta);
382 	if (keyid) {
383 		ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
384 		if (!os_snprintf_error(buflen - len, ret))
385 			len += ret;
386 	}
387 
388 	return len;
389 }
390 
391 
392 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
393 				 char *buf, size_t buflen)
394 {
395 	return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
396 }
397 
398 
399 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
400 			   char *buf, size_t buflen)
401 {
402 	u8 addr[ETH_ALEN];
403 	int ret;
404 	const char *pos;
405 	struct sta_info *sta;
406 
407 	if (hwaddr_aton(txtaddr, addr)) {
408 		ret = os_snprintf(buf, buflen, "FAIL\n");
409 		if (os_snprintf_error(buflen, ret))
410 			return 0;
411 		return ret;
412 	}
413 
414 	sta = ap_get_sta(hapd, addr);
415 	if (sta == NULL)
416 		return -1;
417 
418 	pos = os_strchr(txtaddr, ' ');
419 	if (pos) {
420 		pos++;
421 
422 #ifdef HOSTAPD_DUMP_STATE
423 		if (os_strcmp(pos, "eapol") == 0) {
424 			if (sta->eapol_sm == NULL)
425 				return -1;
426 			return eapol_auth_dump_state(sta->eapol_sm, buf,
427 						     buflen);
428 		}
429 #endif /* HOSTAPD_DUMP_STATE */
430 
431 		return -1;
432 	}
433 
434 	ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
435 	ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
436 
437 	return ret;
438 }
439 
440 
441 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
442 				char *buf, size_t buflen)
443 {
444 	u8 addr[ETH_ALEN];
445 	struct sta_info *sta;
446 	int ret;
447 
448 	if (hwaddr_aton(txtaddr, addr) ||
449 	    (sta = ap_get_sta(hapd, addr)) == NULL) {
450 		ret = os_snprintf(buf, buflen, "FAIL\n");
451 		if (os_snprintf_error(buflen, ret))
452 			return 0;
453 		return ret;
454 	}
455 
456 	if (!sta->next)
457 		return 0;
458 
459 	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
460 }
461 
462 
463 #ifdef CONFIG_P2P_MANAGER
464 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
465 				  u8 minor_reason_code, const u8 *addr)
466 {
467 	struct ieee80211_mgmt *mgmt;
468 	int ret;
469 	u8 *pos;
470 
471 	mgmt = os_zalloc(sizeof(*mgmt) + 100);
472 	if (mgmt == NULL)
473 		return -1;
474 
475 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
476 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
477 		" with minor reason code %u (stype=%u (%s))",
478 		MAC2STR(addr), minor_reason_code, stype,
479 		fc2str(le_to_host16(mgmt->frame_control)));
480 
481 	os_memcpy(mgmt->da, addr, ETH_ALEN);
482 	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
483 	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
484 	if (stype == WLAN_FC_STYPE_DEAUTH) {
485 		mgmt->u.deauth.reason_code =
486 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
487 		pos = mgmt->u.deauth.variable;
488 	} else {
489 		mgmt->u.disassoc.reason_code =
490 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
491 		pos = mgmt->u.disassoc.variable;
492 	}
493 
494 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
495 	*pos++ = 4 + 3 + 1;
496 	WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
497 	pos += 4;
498 
499 	*pos++ = P2P_ATTR_MINOR_REASON_CODE;
500 	WPA_PUT_LE16(pos, 1);
501 	pos += 2;
502 	*pos++ = minor_reason_code;
503 
504 	ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
505 				    0);
506 	os_free(mgmt);
507 
508 	return ret < 0 ? -1 : 0;
509 }
510 #endif /* CONFIG_P2P_MANAGER */
511 
512 
513 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
514 				      const char *txtaddr)
515 {
516 	u8 addr[ETH_ALEN];
517 	struct sta_info *sta;
518 	const char *pos;
519 	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
520 
521 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
522 		txtaddr);
523 
524 	if (hwaddr_aton(txtaddr, addr))
525 		return -1;
526 
527 	pos = os_strstr(txtaddr, " reason=");
528 	if (pos)
529 		reason = atoi(pos + 8);
530 
531 	pos = os_strstr(txtaddr, " test=");
532 	if (pos) {
533 		struct ieee80211_mgmt mgmt;
534 		int encrypt;
535 
536 		pos += 6;
537 		encrypt = atoi(pos);
538 		os_memset(&mgmt, 0, sizeof(mgmt));
539 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
540 						  WLAN_FC_STYPE_DEAUTH);
541 		os_memcpy(mgmt.da, addr, ETH_ALEN);
542 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
543 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
544 		mgmt.u.deauth.reason_code = host_to_le16(reason);
545 		if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
546 					  IEEE80211_HDRLEN +
547 					  sizeof(mgmt.u.deauth),
548 					  0, NULL, 0, !encrypt) < 0)
549 			return -1;
550 		return 0;
551 	}
552 
553 #ifdef CONFIG_P2P_MANAGER
554 	pos = os_strstr(txtaddr, " p2p=");
555 	if (pos) {
556 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
557 					      atoi(pos + 5), addr);
558 	}
559 #endif /* CONFIG_P2P_MANAGER */
560 
561 	if (os_strstr(txtaddr, " tx=0"))
562 		hostapd_drv_sta_remove(hapd, addr);
563 	else
564 		hostapd_drv_sta_deauth(hapd, addr, reason);
565 	sta = ap_get_sta(hapd, addr);
566 	if (sta)
567 		ap_sta_deauthenticate(hapd, sta, reason);
568 	else if (addr[0] == 0xff)
569 		hostapd_free_stas(hapd);
570 
571 	return 0;
572 }
573 
574 
575 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
576 				    const char *txtaddr)
577 {
578 	u8 addr[ETH_ALEN];
579 	struct sta_info *sta;
580 	const char *pos;
581 	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
582 
583 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
584 		txtaddr);
585 
586 	if (hwaddr_aton(txtaddr, addr))
587 		return -1;
588 
589 	pos = os_strstr(txtaddr, " reason=");
590 	if (pos)
591 		reason = atoi(pos + 8);
592 
593 	pos = os_strstr(txtaddr, " test=");
594 	if (pos) {
595 		struct ieee80211_mgmt mgmt;
596 		int encrypt;
597 
598 		pos += 6;
599 		encrypt = atoi(pos);
600 		os_memset(&mgmt, 0, sizeof(mgmt));
601 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
602 						  WLAN_FC_STYPE_DISASSOC);
603 		os_memcpy(mgmt.da, addr, ETH_ALEN);
604 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
605 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
606 		mgmt.u.disassoc.reason_code = host_to_le16(reason);
607 		if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
608 					  IEEE80211_HDRLEN +
609 					  sizeof(mgmt.u.deauth),
610 					  0, NULL, 0, !encrypt) < 0)
611 			return -1;
612 		return 0;
613 	}
614 
615 #ifdef CONFIG_P2P_MANAGER
616 	pos = os_strstr(txtaddr, " p2p=");
617 	if (pos) {
618 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
619 					      atoi(pos + 5), addr);
620 	}
621 #endif /* CONFIG_P2P_MANAGER */
622 
623 	if (os_strstr(txtaddr, " tx=0"))
624 		hostapd_drv_sta_remove(hapd, addr);
625 	else
626 		hostapd_drv_sta_disassoc(hapd, addr, reason);
627 	sta = ap_get_sta(hapd, addr);
628 	if (sta)
629 		ap_sta_disassociate(hapd, sta, reason);
630 	else if (addr[0] == 0xff)
631 		hostapd_free_stas(hapd);
632 
633 	return 0;
634 }
635 
636 
637 #ifdef CONFIG_TAXONOMY
638 int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
639 				 const char *txtaddr,
640 				 char *buf, size_t buflen)
641 {
642 	u8 addr[ETH_ALEN];
643 	struct sta_info *sta;
644 
645 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
646 
647 	if (hwaddr_aton(txtaddr, addr))
648 		return -1;
649 
650 	sta = ap_get_sta(hapd, addr);
651 	if (!sta)
652 		return -1;
653 
654 	return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
655 }
656 #endif /* CONFIG_TAXONOMY */
657 
658 
659 int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
660 				const char *txtaddr)
661 {
662 	u8 addr[ETH_ALEN];
663 	struct sta_info *sta;
664 
665 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
666 
667 	if (hwaddr_aton(txtaddr, addr))
668 		return -1;
669 
670 	sta = ap_get_sta(hapd, addr);
671 	if (!sta)
672 		return -1;
673 
674 	hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
675 				sta->flags & WLAN_STA_WMM);
676 	return 0;
677 }
678 
679 
680 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
681 			      size_t buflen)
682 {
683 	struct hostapd_iface *iface = hapd->iface;
684 	struct hostapd_hw_modes *mode = iface->current_mode;
685 	int len = 0, ret, j;
686 	size_t i;
687 
688 	ret = os_snprintf(buf + len, buflen - len,
689 			  "state=%s\n"
690 			  "phy=%s\n"
691 			  "freq=%d\n"
692 			  "num_sta_non_erp=%d\n"
693 			  "num_sta_no_short_slot_time=%d\n"
694 			  "num_sta_no_short_preamble=%d\n"
695 			  "olbc=%d\n"
696 			  "num_sta_ht_no_gf=%d\n"
697 			  "num_sta_no_ht=%d\n"
698 			  "num_sta_ht_20_mhz=%d\n"
699 			  "num_sta_ht40_intolerant=%d\n"
700 			  "olbc_ht=%d\n"
701 			  "ht_op_mode=0x%x\n",
702 			  hostapd_state_text(iface->state),
703 			  iface->phy,
704 			  iface->freq,
705 			  iface->num_sta_non_erp,
706 			  iface->num_sta_no_short_slot_time,
707 			  iface->num_sta_no_short_preamble,
708 			  iface->olbc,
709 			  iface->num_sta_ht_no_gf,
710 			  iface->num_sta_no_ht,
711 			  iface->num_sta_ht_20mhz,
712 			  iface->num_sta_ht40_intolerant,
713 			  iface->olbc_ht,
714 			  iface->ht_op_mode);
715 	if (os_snprintf_error(buflen - len, ret))
716 		return len;
717 	len += ret;
718 
719 	if (!iface->cac_started || !iface->dfs_cac_ms) {
720 		ret = os_snprintf(buf + len, buflen - len,
721 				  "cac_time_seconds=%d\n"
722 				  "cac_time_left_seconds=N/A\n",
723 				  iface->dfs_cac_ms / 1000);
724 	} else {
725 		/* CAC started and CAC time set - calculate remaining time */
726 		struct os_reltime now;
727 		unsigned int left_time;
728 
729 		os_reltime_age(&iface->dfs_cac_start, &now);
730 		left_time = iface->dfs_cac_ms / 1000 - now.sec;
731 		ret = os_snprintf(buf + len, buflen - len,
732 				  "cac_time_seconds=%u\n"
733 				  "cac_time_left_seconds=%u\n",
734 				  iface->dfs_cac_ms / 1000,
735 				  left_time);
736 	}
737 	if (os_snprintf_error(buflen - len, ret))
738 		return len;
739 	len += ret;
740 
741 	ret = os_snprintf(buf + len, buflen - len,
742 			  "channel=%u\n"
743 			  "edmg_enable=%d\n"
744 			  "edmg_channel=%d\n"
745 			  "secondary_channel=%d\n"
746 			  "ieee80211n=%d\n"
747 			  "ieee80211ac=%d\n"
748 			  "ieee80211ax=%d\n"
749 			  "beacon_int=%u\n"
750 			  "dtim_period=%d\n",
751 			  iface->conf->channel,
752 			  iface->conf->enable_edmg,
753 			  iface->conf->edmg_channel,
754 			  iface->conf->ieee80211n && !hapd->conf->disable_11n ?
755 			  iface->conf->secondary_channel : 0,
756 			  iface->conf->ieee80211n && !hapd->conf->disable_11n,
757 			  iface->conf->ieee80211ac &&
758 			  !hapd->conf->disable_11ac,
759 			  iface->conf->ieee80211ax &&
760 			  !hapd->conf->disable_11ax,
761 			  iface->conf->beacon_int,
762 			  hapd->conf->dtim_period);
763 	if (os_snprintf_error(buflen - len, ret))
764 		return len;
765 	len += ret;
766 
767 #ifdef CONFIG_IEEE80211AX
768 	if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
769 		ret = os_snprintf(buf + len, buflen - len,
770 				  "he_oper_chwidth=%d\n"
771 				  "he_oper_centr_freq_seg0_idx=%d\n"
772 				  "he_oper_centr_freq_seg1_idx=%d\n",
773 				  iface->conf->he_oper_chwidth,
774 				  iface->conf->he_oper_centr_freq_seg0_idx,
775 				  iface->conf->he_oper_centr_freq_seg1_idx);
776 		if (os_snprintf_error(buflen - len, ret))
777 			return len;
778 		len += ret;
779 	}
780 #endif /* CONFIG_IEEE80211AX */
781 
782 	if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
783 		ret = os_snprintf(buf + len, buflen - len,
784 				  "vht_oper_chwidth=%d\n"
785 				  "vht_oper_centr_freq_seg0_idx=%d\n"
786 				  "vht_oper_centr_freq_seg1_idx=%d\n"
787 				  "vht_caps_info=%08x\n",
788 				  iface->conf->vht_oper_chwidth,
789 				  iface->conf->vht_oper_centr_freq_seg0_idx,
790 				  iface->conf->vht_oper_centr_freq_seg1_idx,
791 				  iface->conf->vht_capab);
792 		if (os_snprintf_error(buflen - len, ret))
793 			return len;
794 		len += ret;
795 	}
796 
797 	if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
798 		u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
799 		u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
800 
801 		ret = os_snprintf(buf + len, buflen - len,
802 				  "rx_vht_mcs_map=%04x\n"
803 				  "tx_vht_mcs_map=%04x\n",
804 				  rxmap, txmap);
805 		if (os_snprintf_error(buflen - len, ret))
806 			return len;
807 		len += ret;
808 	}
809 
810 	if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
811 		ret = os_snprintf(buf + len, buflen - len,
812 				  "ht_caps_info=%04x\n",
813 				  hapd->iconf->ht_capab);
814 		if (os_snprintf_error(buflen - len, ret))
815 			return len;
816 		len += ret;
817 	}
818 
819 	if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
820 		len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
821 						   mode->mcs_set);
822 	}
823 
824 	if (iface->current_rates && iface->num_rates) {
825 		ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
826 		if (os_snprintf_error(buflen - len, ret))
827 			return len;
828 		len += ret;
829 
830 		for (j = 0; j < iface->num_rates; j++) {
831 			ret = os_snprintf(buf + len, buflen - len, "%s%02x",
832 					  j > 0 ? " " : "",
833 					  iface->current_rates[j].rate / 5);
834 			if (os_snprintf_error(buflen - len, ret))
835 				return len;
836 			len += ret;
837 		}
838 		ret = os_snprintf(buf + len, buflen - len, "\n");
839 		if (os_snprintf_error(buflen - len, ret))
840 			return len;
841 		len += ret;
842 	}
843 
844 	for (j = 0; mode && j < mode->num_channels; j++) {
845 		if (mode->channels[j].freq == iface->freq) {
846 			ret = os_snprintf(buf + len, buflen - len,
847 					  "max_txpower=%u\n",
848 					  mode->channels[j].max_tx_power);
849 			if (os_snprintf_error(buflen - len, ret))
850 				return len;
851 			len += ret;
852 			break;
853 		}
854 	}
855 
856 	for (i = 0; i < iface->num_bss; i++) {
857 		struct hostapd_data *bss = iface->bss[i];
858 		ret = os_snprintf(buf + len, buflen - len,
859 				  "bss[%d]=%s\n"
860 				  "bssid[%d]=" MACSTR "\n"
861 				  "ssid[%d]=%s\n"
862 				  "num_sta[%d]=%d\n",
863 				  (int) i, bss->conf->iface,
864 				  (int) i, MAC2STR(bss->own_addr),
865 				  (int) i,
866 				  wpa_ssid_txt(bss->conf->ssid.ssid,
867 					       bss->conf->ssid.ssid_len),
868 				  (int) i, bss->num_sta);
869 		if (os_snprintf_error(buflen - len, ret))
870 			return len;
871 		len += ret;
872 	}
873 
874 	if (hapd->conf->chan_util_avg_period) {
875 		ret = os_snprintf(buf + len, buflen - len,
876 				  "chan_util_avg=%u\n",
877 				  iface->chan_util_average);
878 		if (os_snprintf_error(buflen - len, ret))
879 			return len;
880 		len += ret;
881 	}
882 
883 	return len;
884 }
885 
886 
887 int hostapd_parse_csa_settings(const char *pos,
888 			       struct csa_settings *settings)
889 {
890 	char *end;
891 
892 	os_memset(settings, 0, sizeof(*settings));
893 	settings->cs_count = strtol(pos, &end, 10);
894 	if (pos == end) {
895 		wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
896 		return -1;
897 	}
898 
899 	settings->freq_params.freq = atoi(end);
900 	if (settings->freq_params.freq == 0) {
901 		wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
902 		return -1;
903 	}
904 
905 #define SET_CSA_SETTING(str) \
906 	do { \
907 		const char *pos2 = os_strstr(pos, " " #str "="); \
908 		if (pos2) { \
909 			pos2 += sizeof(" " #str "=") - 1; \
910 			settings->freq_params.str = atoi(pos2); \
911 		} \
912 	} while (0)
913 
914 	SET_CSA_SETTING(center_freq1);
915 	SET_CSA_SETTING(center_freq2);
916 	SET_CSA_SETTING(bandwidth);
917 	SET_CSA_SETTING(sec_channel_offset);
918 	settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
919 	settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
920 	settings->freq_params.he_enabled = !!os_strstr(pos, " he");
921 	settings->block_tx = !!os_strstr(pos, " blocktx");
922 #undef SET_CSA_SETTING
923 
924 	return 0;
925 }
926 
927 
928 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
929 {
930 	return hostapd_drv_stop_ap(hapd);
931 }
932 
933 
934 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
935 				  size_t len)
936 {
937 	return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
938 }
939 
940 
941 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
942 {
943 	wpa_auth_pmksa_flush(hapd->wpa_auth);
944 }
945 
946 
947 int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
948 {
949 	u8 spa[ETH_ALEN];
950 	u8 pmkid[PMKID_LEN];
951 	u8 pmk[PMK_LEN_MAX];
952 	size_t pmk_len;
953 	char *pos, *pos2;
954 	int akmp = 0, expiration = 0;
955 
956 	/*
957 	 * Entry format:
958 	 * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
959 	 */
960 
961 	if (hwaddr_aton(cmd, spa))
962 		return -1;
963 
964 	pos = os_strchr(cmd, ' ');
965 	if (!pos)
966 		return -1;
967 	pos++;
968 
969 	if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
970 		return -1;
971 
972 	pos = os_strchr(pos, ' ');
973 	if (!pos)
974 		return -1;
975 	pos++;
976 
977 	pos2 = os_strchr(pos, ' ');
978 	if (!pos2)
979 		return -1;
980 	pmk_len = (pos2 - pos) / 2;
981 	if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
982 	    hexstr2bin(pos, pmk, pmk_len) < 0)
983 		return -1;
984 
985 	pos = pos2 + 1;
986 
987 	if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
988 		return -1;
989 
990 	return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
991 				   pmkid, expiration, akmp);
992 }
993 
994 
995 #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
996 #ifdef CONFIG_MESH
997 
998 int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
999 				       const u8 *addr, char *buf, size_t len)
1000 {
1001 	return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
1002 }
1003 
1004 
1005 void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
1006 {
1007 	u8 spa[ETH_ALEN];
1008 	u8 pmkid[PMKID_LEN];
1009 	u8 pmk[PMK_LEN_MAX];
1010 	char *pos;
1011 	int expiration;
1012 
1013 	/*
1014 	 * Entry format:
1015 	 * <BSSID> <PMKID> <PMK> <expiration in seconds>
1016 	 */
1017 
1018 	if (hwaddr_aton(cmd, spa))
1019 		return NULL;
1020 
1021 	pos = os_strchr(cmd, ' ');
1022 	if (!pos)
1023 		return NULL;
1024 	pos++;
1025 
1026 	if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
1027 		return NULL;
1028 
1029 	pos = os_strchr(pos, ' ');
1030 	if (!pos)
1031 		return NULL;
1032 	pos++;
1033 
1034 	if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
1035 		return NULL;
1036 
1037 	pos = os_strchr(pos, ' ');
1038 	if (!pos)
1039 		return NULL;
1040 	pos++;
1041 
1042 	if (sscanf(pos, "%d", &expiration) != 1)
1043 		return NULL;
1044 
1045 	return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
1046 }
1047 
1048 #endif /* CONFIG_MESH */
1049 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
1050