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"
27 static int hostapd_get_sta_tx_rx(struct hostapd_data
*hapd
,
29 char *buf
, size_t buflen
)
31 struct hostap_sta_driver_data data
;
34 if (hostapd_drv_read_sta_data(hapd
, &data
, sta
->addr
) < 0)
37 ret
= os_snprintf(buf
, buflen
, "rx_packets=%lu\ntx_packets=%lu\n"
38 "rx_bytes=%llu\ntx_bytes=%llu\n",
39 data
.rx_packets
, data
.tx_packets
,
40 data
.rx_bytes
, data
.tx_bytes
);
41 if (os_snprintf_error(buflen
, ret
))
47 static int hostapd_get_sta_conn_time(struct sta_info
*sta
,
48 char *buf
, size_t buflen
)
50 struct os_reltime age
;
53 if (!sta
->connected_time
.sec
)
56 os_reltime_age(&sta
->connected_time
, &age
);
58 ret
= os_snprintf(buf
, buflen
, "connected_time=%u\n",
59 (unsigned int) age
.sec
);
60 if (os_snprintf_error(buflen
, ret
))
66 static const char * timeout_next_str(int val
)
70 return "NULLFUNC POLL";
77 case STA_DISASSOC_FROM_CLI
:
78 return "DISASSOC_FROM_CLI";
85 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data
*hapd
,
87 char *buf
, size_t buflen
)
95 ret
= os_snprintf(buf
+ len
, buflen
- len
, MACSTR
"\nflags=",
97 if (os_snprintf_error(buflen
- len
, ret
))
101 ret
= ap_sta_flags_txt(sta
->flags
, buf
+ len
, buflen
- len
);
106 ret
= os_snprintf(buf
+ len
, buflen
- len
, "\naid=%d\ncapability=0x%x\n"
107 "listen_interval=%d\nsupported_rates=",
108 sta
->aid
, sta
->capability
, sta
->listen_interval
);
109 if (os_snprintf_error(buflen
- len
, ret
))
113 for (i
= 0; i
< sta
->supported_rates_len
; i
++) {
114 ret
= os_snprintf(buf
+ len
, buflen
- len
, "%02x%s",
115 sta
->supported_rates
[i
],
116 i
+ 1 < sta
->supported_rates_len
? " " : "");
117 if (os_snprintf_error(buflen
- len
, ret
))
122 ret
= os_snprintf(buf
+ len
, buflen
- len
, "\ntimeout_next=%s\n",
123 timeout_next_str(sta
->timeout_next
));
124 if (os_snprintf_error(buflen
- len
, ret
))
128 res
= ieee802_11_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
131 res
= wpa_get_mib_sta(sta
->wpa_sm
, buf
+ len
, buflen
- len
);
134 res
= ieee802_1x_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
137 res
= hostapd_wps_get_mib_sta(hapd
, sta
->addr
, buf
+ len
,
141 res
= hostapd_p2p_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
145 len
+= hostapd_get_sta_tx_rx(hapd
, sta
, buf
+ len
, buflen
- len
);
146 len
+= hostapd_get_sta_conn_time(sta
, buf
+ len
, buflen
- len
);
149 if (sta
->sae
&& sta
->sae
->state
== SAE_ACCEPTED
) {
150 res
= os_snprintf(buf
+ len
, buflen
- len
, "sae_group=%d\n",
152 if (!os_snprintf_error(buflen
- len
, res
))
155 #endif /* CONFIG_SAE */
157 if (sta
->vlan_id
> 0) {
158 res
= os_snprintf(buf
+ len
, buflen
- len
, "vlan_id=%d\n",
160 if (!os_snprintf_error(buflen
- len
, res
))
168 int hostapd_ctrl_iface_sta_first(struct hostapd_data
*hapd
,
169 char *buf
, size_t buflen
)
171 return hostapd_ctrl_iface_sta_mib(hapd
, hapd
->sta_list
, buf
, buflen
);
175 int hostapd_ctrl_iface_sta(struct hostapd_data
*hapd
, const char *txtaddr
,
176 char *buf
, size_t buflen
)
181 struct sta_info
*sta
;
183 if (hwaddr_aton(txtaddr
, addr
)) {
184 ret
= os_snprintf(buf
, buflen
, "FAIL\n");
185 if (os_snprintf_error(buflen
, ret
))
190 sta
= ap_get_sta(hapd
, addr
);
194 pos
= os_strchr(txtaddr
, ' ');
198 #ifdef HOSTAPD_DUMP_STATE
199 if (os_strcmp(pos
, "eapol") == 0) {
200 if (sta
->eapol_sm
== NULL
)
202 return eapol_auth_dump_state(sta
->eapol_sm
, buf
,
205 #endif /* HOSTAPD_DUMP_STATE */
210 ret
= hostapd_ctrl_iface_sta_mib(hapd
, sta
, buf
, buflen
);
211 ret
+= fst_ctrl_iface_mb_info(addr
, buf
+ ret
, buflen
- ret
);
217 int hostapd_ctrl_iface_sta_next(struct hostapd_data
*hapd
, const char *txtaddr
,
218 char *buf
, size_t buflen
)
221 struct sta_info
*sta
;
224 if (hwaddr_aton(txtaddr
, addr
) ||
225 (sta
= ap_get_sta(hapd
, addr
)) == NULL
) {
226 ret
= os_snprintf(buf
, buflen
, "FAIL\n");
227 if (os_snprintf_error(buflen
, ret
))
235 return hostapd_ctrl_iface_sta_mib(hapd
, sta
->next
, buf
, buflen
);
239 #ifdef CONFIG_P2P_MANAGER
240 static int p2p_manager_disconnect(struct hostapd_data
*hapd
, u16 stype
,
241 u8 minor_reason_code
, const u8
*addr
)
243 struct ieee80211_mgmt
*mgmt
;
247 if (hapd
->driver
->send_frame
== NULL
)
250 mgmt
= os_zalloc(sizeof(*mgmt
) + 100);
254 mgmt
->frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
, stype
);
255 wpa_dbg(hapd
->msg_ctx
, MSG_DEBUG
, "P2P: Disconnect STA " MACSTR
256 " with minor reason code %u (stype=%u (%s))",
257 MAC2STR(addr
), minor_reason_code
, stype
,
258 fc2str(mgmt
->frame_control
));
260 os_memcpy(mgmt
->da
, addr
, ETH_ALEN
);
261 os_memcpy(mgmt
->sa
, hapd
->own_addr
, ETH_ALEN
);
262 os_memcpy(mgmt
->bssid
, hapd
->own_addr
, ETH_ALEN
);
263 if (stype
== WLAN_FC_STYPE_DEAUTH
) {
264 mgmt
->u
.deauth
.reason_code
=
265 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID
);
266 pos
= (u8
*) (&mgmt
->u
.deauth
.reason_code
+ 1);
268 mgmt
->u
.disassoc
.reason_code
=
269 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID
);
270 pos
= (u8
*) (&mgmt
->u
.disassoc
.reason_code
+ 1);
273 *pos
++ = WLAN_EID_VENDOR_SPECIFIC
;
275 WPA_PUT_BE32(pos
, P2P_IE_VENDOR_TYPE
);
278 *pos
++ = P2P_ATTR_MINOR_REASON_CODE
;
279 WPA_PUT_LE16(pos
, 1);
281 *pos
++ = minor_reason_code
;
283 ret
= hapd
->driver
->send_frame(hapd
->drv_priv
, (u8
*) mgmt
,
284 pos
- (u8
*) mgmt
, 1);
287 return ret
< 0 ? -1 : 0;
289 #endif /* CONFIG_P2P_MANAGER */
292 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data
*hapd
,
296 struct sta_info
*sta
;
298 u16 reason
= WLAN_REASON_PREV_AUTH_NOT_VALID
;
300 wpa_dbg(hapd
->msg_ctx
, MSG_DEBUG
, "CTRL_IFACE DEAUTHENTICATE %s",
303 if (hwaddr_aton(txtaddr
, addr
))
306 pos
= os_strstr(txtaddr
, " reason=");
308 reason
= atoi(pos
+ 8);
310 pos
= os_strstr(txtaddr
, " test=");
312 struct ieee80211_mgmt mgmt
;
314 if (hapd
->driver
->send_frame
== NULL
)
318 os_memset(&mgmt
, 0, sizeof(mgmt
));
319 mgmt
.frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
320 WLAN_FC_STYPE_DEAUTH
);
321 os_memcpy(mgmt
.da
, addr
, ETH_ALEN
);
322 os_memcpy(mgmt
.sa
, hapd
->own_addr
, ETH_ALEN
);
323 os_memcpy(mgmt
.bssid
, hapd
->own_addr
, ETH_ALEN
);
324 mgmt
.u
.deauth
.reason_code
= host_to_le16(reason
);
325 if (hapd
->driver
->send_frame(hapd
->drv_priv
, (u8
*) &mgmt
,
327 sizeof(mgmt
.u
.deauth
),
333 #ifdef CONFIG_P2P_MANAGER
334 pos
= os_strstr(txtaddr
, " p2p=");
336 return p2p_manager_disconnect(hapd
, WLAN_FC_STYPE_DEAUTH
,
337 atoi(pos
+ 5), addr
);
339 #endif /* CONFIG_P2P_MANAGER */
341 hostapd_drv_sta_deauth(hapd
, addr
, reason
);
342 sta
= ap_get_sta(hapd
, addr
);
344 ap_sta_deauthenticate(hapd
, sta
, reason
);
345 else if (addr
[0] == 0xff)
346 hostapd_free_stas(hapd
);
352 int hostapd_ctrl_iface_disassociate(struct hostapd_data
*hapd
,
356 struct sta_info
*sta
;
358 u16 reason
= WLAN_REASON_PREV_AUTH_NOT_VALID
;
360 wpa_dbg(hapd
->msg_ctx
, MSG_DEBUG
, "CTRL_IFACE DISASSOCIATE %s",
363 if (hwaddr_aton(txtaddr
, addr
))
366 pos
= os_strstr(txtaddr
, " reason=");
368 reason
= atoi(pos
+ 8);
370 pos
= os_strstr(txtaddr
, " test=");
372 struct ieee80211_mgmt mgmt
;
374 if (hapd
->driver
->send_frame
== NULL
)
378 os_memset(&mgmt
, 0, sizeof(mgmt
));
379 mgmt
.frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
380 WLAN_FC_STYPE_DISASSOC
);
381 os_memcpy(mgmt
.da
, addr
, ETH_ALEN
);
382 os_memcpy(mgmt
.sa
, hapd
->own_addr
, ETH_ALEN
);
383 os_memcpy(mgmt
.bssid
, hapd
->own_addr
, ETH_ALEN
);
384 mgmt
.u
.disassoc
.reason_code
= host_to_le16(reason
);
385 if (hapd
->driver
->send_frame(hapd
->drv_priv
, (u8
*) &mgmt
,
387 sizeof(mgmt
.u
.deauth
),
393 #ifdef CONFIG_P2P_MANAGER
394 pos
= os_strstr(txtaddr
, " p2p=");
396 return p2p_manager_disconnect(hapd
, WLAN_FC_STYPE_DISASSOC
,
397 atoi(pos
+ 5), addr
);
399 #endif /* CONFIG_P2P_MANAGER */
401 hostapd_drv_sta_disassoc(hapd
, addr
, reason
);
402 sta
= ap_get_sta(hapd
, addr
);
404 ap_sta_disassociate(hapd
, sta
, reason
);
405 else if (addr
[0] == 0xff)
406 hostapd_free_stas(hapd
);
412 int hostapd_ctrl_iface_status(struct hostapd_data
*hapd
, char *buf
,
415 struct hostapd_iface
*iface
= hapd
->iface
;
419 ret
= os_snprintf(buf
+ len
, buflen
- len
,
423 "num_sta_non_erp=%d\n"
424 "num_sta_no_short_slot_time=%d\n"
425 "num_sta_no_short_preamble=%d\n"
427 "num_sta_ht_no_gf=%d\n"
429 "num_sta_ht_20_mhz=%d\n"
430 "num_sta_ht40_intolerant=%d\n"
433 hostapd_state_text(iface
->state
),
436 iface
->num_sta_non_erp
,
437 iface
->num_sta_no_short_slot_time
,
438 iface
->num_sta_no_short_preamble
,
440 iface
->num_sta_ht_no_gf
,
441 iface
->num_sta_no_ht
,
442 iface
->num_sta_ht_20mhz
,
443 iface
->num_sta_ht40_intolerant
,
446 if (os_snprintf_error(buflen
- len
, ret
))
450 if (!iface
->cac_started
|| !iface
->dfs_cac_ms
) {
451 ret
= os_snprintf(buf
+ len
, buflen
- len
,
452 "cac_time_seconds=%d\n"
453 "cac_time_left_seconds=N/A\n",
454 iface
->dfs_cac_ms
/ 1000);
456 /* CAC started and CAC time set - calculate remaining time */
457 struct os_reltime now
;
458 unsigned int left_time
;
460 os_reltime_age(&iface
->dfs_cac_start
, &now
);
461 left_time
= iface
->dfs_cac_ms
/ 1000 - now
.sec
;
462 ret
= os_snprintf(buf
+ len
, buflen
- len
,
463 "cac_time_seconds=%u\n"
464 "cac_time_left_seconds=%u\n",
465 iface
->dfs_cac_ms
/ 1000,
468 if (os_snprintf_error(buflen
- len
, ret
))
472 ret
= os_snprintf(buf
+ len
, buflen
- len
,
474 "secondary_channel=%d\n"
477 "vht_oper_chwidth=%d\n"
478 "vht_oper_centr_freq_seg0_idx=%d\n"
479 "vht_oper_centr_freq_seg1_idx=%d\n",
480 iface
->conf
->channel
,
481 iface
->conf
->secondary_channel
,
482 iface
->conf
->ieee80211n
,
483 iface
->conf
->ieee80211ac
,
484 iface
->conf
->vht_oper_chwidth
,
485 iface
->conf
->vht_oper_centr_freq_seg0_idx
,
486 iface
->conf
->vht_oper_centr_freq_seg1_idx
);
487 if (os_snprintf_error(buflen
- len
, ret
))
491 for (i
= 0; i
< iface
->num_bss
; i
++) {
492 struct hostapd_data
*bss
= iface
->bss
[i
];
493 ret
= os_snprintf(buf
+ len
, buflen
- len
,
495 "bssid[%d]=" MACSTR
"\n"
498 (int) i
, bss
->conf
->iface
,
499 (int) i
, MAC2STR(bss
->own_addr
),
501 wpa_ssid_txt(bss
->conf
->ssid
.ssid
,
502 bss
->conf
->ssid
.ssid_len
),
503 (int) i
, bss
->num_sta
);
504 if (os_snprintf_error(buflen
- len
, ret
))
513 int hostapd_parse_csa_settings(const char *pos
,
514 struct csa_settings
*settings
)
518 os_memset(settings
, 0, sizeof(*settings
));
519 settings
->cs_count
= strtol(pos
, &end
, 10);
521 wpa_printf(MSG_ERROR
, "chanswitch: invalid cs_count provided");
525 settings
->freq_params
.freq
= atoi(end
);
526 if (settings
->freq_params
.freq
== 0) {
527 wpa_printf(MSG_ERROR
, "chanswitch: invalid freq provided");
531 #define SET_CSA_SETTING(str) \
533 const char *pos2 = os_strstr(pos, " " #str "="); \
535 pos2 += sizeof(" " #str "=") - 1; \
536 settings->freq_params.str = atoi(pos2); \
540 SET_CSA_SETTING(center_freq1
);
541 SET_CSA_SETTING(center_freq2
);
542 SET_CSA_SETTING(bandwidth
);
543 SET_CSA_SETTING(sec_channel_offset
);
544 settings
->freq_params
.ht_enabled
= !!os_strstr(pos
, " ht");
545 settings
->freq_params
.vht_enabled
= !!os_strstr(pos
, " vht");
546 settings
->block_tx
= !!os_strstr(pos
, " blocktx");
547 #undef SET_CSA_SETTING
553 int hostapd_ctrl_iface_stop_ap(struct hostapd_data
*hapd
)
555 return hostapd_drv_stop_ap(hapd
);