2 * Control interface for shared AP commands
3 * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
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"
17 #include "ieee802_1x.h"
19 #include "ieee802_11.h"
21 #include "wps_hostapd.h"
22 #include "p2p_hostapd.h"
23 #include "ctrl_iface_ap.h"
24 #include "ap_drv_ops.h"
29 static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
31 char *buf, size_t buflen)
33 struct hostap_sta_driver_data data;
36 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
39 ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
40 "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n",
41 data.rx_packets, data.tx_packets,
42 data.rx_bytes, data.tx_bytes, data.inactive_msec);
43 if (os_snprintf_error(buflen, ret))
49 static int hostapd_get_sta_conn_time(struct sta_info *sta,
50 char *buf, size_t buflen)
52 struct os_reltime age;
55 if (!sta->connected_time.sec)
58 os_reltime_age(&sta->connected_time, &age);
60 ret = os_snprintf(buf, buflen, "connected_time=%u\n",
61 (unsigned int) age.sec);
62 if (os_snprintf_error(buflen, ret))
68 static const char * timeout_next_str(int val)
72 return "NULLFUNC POLL";
79 case STA_DISASSOC_FROM_CLI:
80 return "DISASSOC_FROM_CLI";
87 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
89 char *buf, size_t buflen)
97 ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
99 if (os_snprintf_error(buflen - len, ret))
103 ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
108 ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
109 "listen_interval=%d\nsupported_rates=",
110 sta->aid, sta->capability, sta->listen_interval);
111 if (os_snprintf_error(buflen - len, ret))
115 for (i = 0; i < sta->supported_rates_len; i++) {
116 ret = os_snprintf(buf + len, buflen - len, "%02x%s",
117 sta->supported_rates[i],
118 i + 1 < sta->supported_rates_len ? " " : "");
119 if (os_snprintf_error(buflen - len, ret))
124 ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
125 timeout_next_str(sta->timeout_next));
126 if (os_snprintf_error(buflen - len, ret))
130 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
133 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
136 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
139 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
143 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
147 len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
148 len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
151 if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
152 res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
154 if (!os_snprintf_error(buflen - len, res))
157 #endif /* CONFIG_SAE */
159 if (sta->vlan_id > 0) {
160 res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
162 if (!os_snprintf_error(buflen - len, res))
166 res = mbo_ap_get_info(sta, buf + len, buflen - len);
170 if (sta->supp_op_classes &&
171 buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
172 len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
173 len += wpa_snprintf_hex(buf + len, buflen - len,
174 sta->supp_op_classes + 1,
175 sta->supp_op_classes[0]);
176 len += os_snprintf(buf + len, buflen - len, "\n");
183 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
184 char *buf, size_t buflen)
186 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
190 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
191 char *buf, size_t buflen)
196 struct sta_info *sta;
198 if (hwaddr_aton(txtaddr, addr)) {
199 ret = os_snprintf(buf, buflen, "FAIL\n");
200 if (os_snprintf_error(buflen, ret))
205 sta = ap_get_sta(hapd, addr);
209 pos = os_strchr(txtaddr, ' ');
213 #ifdef HOSTAPD_DUMP_STATE
214 if (os_strcmp(pos, "eapol") == 0) {
215 if (sta->eapol_sm == NULL)
217 return eapol_auth_dump_state(sta->eapol_sm, buf,
220 #endif /* HOSTAPD_DUMP_STATE */
225 ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
226 ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
232 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
233 char *buf, size_t buflen)
236 struct sta_info *sta;
239 if (hwaddr_aton(txtaddr, addr) ||
240 (sta = ap_get_sta(hapd, addr)) == NULL) {
241 ret = os_snprintf(buf, buflen, "FAIL\n");
242 if (os_snprintf_error(buflen, ret))
250 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
254 #ifdef CONFIG_P2P_MANAGER
255 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
256 u8 minor_reason_code, const u8 *addr)
258 struct ieee80211_mgmt *mgmt;
262 if (!hapd->drv_priv || !hapd->driver->send_frame)
265 mgmt = os_zalloc(sizeof(*mgmt) + 100);
269 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
270 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
271 " with minor reason code %u (stype=%u (%s))",
272 MAC2STR(addr), minor_reason_code, stype,
273 fc2str(le_to_host16(mgmt->frame_control)));
275 os_memcpy(mgmt->da, addr, ETH_ALEN);
276 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
277 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
278 if (stype == WLAN_FC_STYPE_DEAUTH) {
279 mgmt->u.deauth.reason_code =
280 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
281 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
283 mgmt->u.disassoc.reason_code =
284 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
285 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
288 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
290 WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
293 *pos++ = P2P_ATTR_MINOR_REASON_CODE;
294 WPA_PUT_LE16(pos, 1);
296 *pos++ = minor_reason_code;
298 ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
299 pos - (u8 *) mgmt, 1);
302 return ret < 0 ? -1 : 0;
304 #endif /* CONFIG_P2P_MANAGER */
307 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
311 struct sta_info *sta;
313 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
315 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
318 if (hwaddr_aton(txtaddr, addr))
321 pos = os_strstr(txtaddr, " reason=");
323 reason = atoi(pos + 8);
325 pos = os_strstr(txtaddr, " test=");
327 struct ieee80211_mgmt mgmt;
329 if (!hapd->drv_priv || !hapd->driver->send_frame)
333 os_memset(&mgmt, 0, sizeof(mgmt));
334 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
335 WLAN_FC_STYPE_DEAUTH);
336 os_memcpy(mgmt.da, addr, ETH_ALEN);
337 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
338 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
339 mgmt.u.deauth.reason_code = host_to_le16(reason);
340 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
342 sizeof(mgmt.u.deauth),
348 #ifdef CONFIG_P2P_MANAGER
349 pos = os_strstr(txtaddr, " p2p=");
351 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
352 atoi(pos + 5), addr);
354 #endif /* CONFIG_P2P_MANAGER */
356 if (os_strstr(txtaddr, " tx=0"))
357 hostapd_drv_sta_remove(hapd, addr);
359 hostapd_drv_sta_deauth(hapd, addr, reason);
360 sta = ap_get_sta(hapd, addr);
362 ap_sta_deauthenticate(hapd, sta, reason);
363 else if (addr[0] == 0xff)
364 hostapd_free_stas(hapd);
370 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
374 struct sta_info *sta;
376 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
378 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
381 if (hwaddr_aton(txtaddr, addr))
384 pos = os_strstr(txtaddr, " reason=");
386 reason = atoi(pos + 8);
388 pos = os_strstr(txtaddr, " test=");
390 struct ieee80211_mgmt mgmt;
392 if (!hapd->drv_priv || !hapd->driver->send_frame)
396 os_memset(&mgmt, 0, sizeof(mgmt));
397 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
398 WLAN_FC_STYPE_DISASSOC);
399 os_memcpy(mgmt.da, addr, ETH_ALEN);
400 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
401 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
402 mgmt.u.disassoc.reason_code = host_to_le16(reason);
403 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
405 sizeof(mgmt.u.deauth),
411 #ifdef CONFIG_P2P_MANAGER
412 pos = os_strstr(txtaddr, " p2p=");
414 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
415 atoi(pos + 5), addr);
417 #endif /* CONFIG_P2P_MANAGER */
419 if (os_strstr(txtaddr, " tx=0"))
420 hostapd_drv_sta_remove(hapd, addr);
422 hostapd_drv_sta_disassoc(hapd, addr, reason);
423 sta = ap_get_sta(hapd, addr);
425 ap_sta_disassociate(hapd, sta, reason);
426 else if (addr[0] == 0xff)
427 hostapd_free_stas(hapd);
433 #ifdef CONFIG_TAXONOMY
434 int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
436 char *buf, size_t buflen)
439 struct sta_info *sta;
441 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
443 if (hwaddr_aton(txtaddr, addr))
446 sta = ap_get_sta(hapd, addr);
450 return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
452 #endif /* CONFIG_TAXONOMY */
455 int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
459 struct sta_info *sta;
461 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
463 if (hwaddr_aton(txtaddr, addr))
466 sta = ap_get_sta(hapd, addr);
470 hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
471 sta->flags & WLAN_STA_WMM);
476 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
479 struct hostapd_iface *iface = hapd->iface;
483 ret = os_snprintf(buf + len, buflen - len,
487 "num_sta_non_erp=%d\n"
488 "num_sta_no_short_slot_time=%d\n"
489 "num_sta_no_short_preamble=%d\n"
491 "num_sta_ht_no_gf=%d\n"
493 "num_sta_ht_20_mhz=%d\n"
494 "num_sta_ht40_intolerant=%d\n"
497 hostapd_state_text(iface->state),
500 iface->num_sta_non_erp,
501 iface->num_sta_no_short_slot_time,
502 iface->num_sta_no_short_preamble,
504 iface->num_sta_ht_no_gf,
505 iface->num_sta_no_ht,
506 iface->num_sta_ht_20mhz,
507 iface->num_sta_ht40_intolerant,
510 if (os_snprintf_error(buflen - len, ret))
514 if (!iface->cac_started || !iface->dfs_cac_ms) {
515 ret = os_snprintf(buf + len, buflen - len,
516 "cac_time_seconds=%d\n"
517 "cac_time_left_seconds=N/A\n",
518 iface->dfs_cac_ms / 1000);
520 /* CAC started and CAC time set - calculate remaining time */
521 struct os_reltime now;
522 unsigned int left_time;
524 os_reltime_age(&iface->dfs_cac_start, &now);
525 left_time = iface->dfs_cac_ms / 1000 - now.sec;
526 ret = os_snprintf(buf + len, buflen - len,
527 "cac_time_seconds=%u\n"
528 "cac_time_left_seconds=%u\n",
529 iface->dfs_cac_ms / 1000,
532 if (os_snprintf_error(buflen - len, ret))
536 ret = os_snprintf(buf + len, buflen - len,
538 "secondary_channel=%d\n"
541 iface->conf->channel,
542 iface->conf->ieee80211n && !hapd->conf->disable_11n ?
543 iface->conf->secondary_channel : 0,
544 iface->conf->ieee80211n && !hapd->conf->disable_11n,
545 iface->conf->ieee80211ac &&
546 !hapd->conf->disable_11ac);
547 if (os_snprintf_error(buflen - len, ret))
550 if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
551 ret = os_snprintf(buf + len, buflen - len,
552 "vht_oper_chwidth=%d\n"
553 "vht_oper_centr_freq_seg0_idx=%d\n"
554 "vht_oper_centr_freq_seg1_idx=%d\n",
555 iface->conf->vht_oper_chwidth,
556 iface->conf->vht_oper_centr_freq_seg0_idx,
557 iface->conf->vht_oper_centr_freq_seg1_idx);
558 if (os_snprintf_error(buflen - len, ret))
563 for (i = 0; i < iface->num_bss; i++) {
564 struct hostapd_data *bss = iface->bss[i];
565 ret = os_snprintf(buf + len, buflen - len,
567 "bssid[%d]=" MACSTR "\n"
570 (int) i, bss->conf->iface,
571 (int) i, MAC2STR(bss->own_addr),
573 wpa_ssid_txt(bss->conf->ssid.ssid,
574 bss->conf->ssid.ssid_len),
575 (int) i, bss->num_sta);
576 if (os_snprintf_error(buflen - len, ret))
585 int hostapd_parse_csa_settings(const char *pos,
586 struct csa_settings *settings)
590 os_memset(settings, 0, sizeof(*settings));
591 settings->cs_count = strtol(pos, &end, 10);
593 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
597 settings->freq_params.freq = atoi(end);
598 if (settings->freq_params.freq == 0) {
599 wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
603 #define SET_CSA_SETTING(str) \
605 const char *pos2 = os_strstr(pos, " " #str "="); \
607 pos2 += sizeof(" " #str "=") - 1; \
608 settings->freq_params.str = atoi(pos2); \
612 SET_CSA_SETTING(center_freq1);
613 SET_CSA_SETTING(center_freq2);
614 SET_CSA_SETTING(bandwidth);
615 SET_CSA_SETTING(sec_channel_offset);
616 settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
617 settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
618 settings->block_tx = !!os_strstr(pos, " blocktx");
619 #undef SET_CSA_SETTING
625 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
627 return hostapd_drv_stop_ap(hapd);
631 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
634 return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
638 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
640 wpa_auth_pmksa_flush(hapd->wpa_auth);