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