2 * Control interface for shared AP commands
3 * Copyright (c) 2004-2013, 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"
14 #include "ieee802_1x.h"
16 #include "ieee802_11.h"
18 #include "wps_hostapd.h"
19 #include "p2p_hostapd.h"
20 #include "ctrl_iface_ap.h"
21 #include "ap_drv_ops.h"
24 static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
26 char *buf, size_t buflen)
28 struct hostap_sta_driver_data data;
31 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
34 ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
35 "rx_bytes=%lu\ntx_bytes=%lu\n",
36 data.rx_packets, data.tx_packets,
37 data.rx_bytes, data.tx_bytes);
38 if (ret < 0 || (size_t) ret >= buflen)
44 static int hostapd_get_sta_conn_time(struct sta_info *sta,
45 char *buf, size_t buflen)
47 struct os_reltime age;
50 if (!sta->connected_time.sec)
53 os_reltime_age(&sta->connected_time, &age);
55 ret = os_snprintf(buf, buflen, "connected_time=%u\n",
56 (unsigned int) age.sec);
57 if (ret < 0 || (size_t) ret >= buflen)
63 static const char * timeout_next_str(int val)
67 return "NULLFUNC POLL";
74 case STA_DISASSOC_FROM_CLI:
75 return "DISASSOC_FROM_CLI";
82 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
84 char *buf, size_t buflen)
89 ret = os_snprintf(buf, buflen, "FAIL\n");
90 if (ret < 0 || (size_t) ret >= buflen)
96 ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
98 if (ret < 0 || (size_t) ret >= buflen - len)
102 ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
107 ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
108 "listen_interval=%d\nsupported_rates=",
109 sta->aid, sta->capability, sta->listen_interval);
110 if (ret < 0 || (size_t) ret >= buflen - len)
114 for (i = 0; i < sta->supported_rates_len; i++) {
115 ret = os_snprintf(buf + len, buflen - len, "%02x%s",
116 sta->supported_rates[i],
117 i + 1 < sta->supported_rates_len ? " " : "");
118 if (ret < 0 || (size_t) ret >= buflen - len)
123 ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
124 timeout_next_str(sta->timeout_next));
125 if (ret < 0 || (size_t) ret >= buflen - len)
129 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
132 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
135 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
138 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
142 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
146 len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
147 len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
153 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
154 char *buf, size_t buflen)
156 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
160 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
161 char *buf, size_t buflen)
166 if (hwaddr_aton(txtaddr, addr)) {
167 ret = os_snprintf(buf, buflen, "FAIL\n");
168 if (ret < 0 || (size_t) ret >= buflen)
172 return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
177 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
178 char *buf, size_t buflen)
181 struct sta_info *sta;
184 if (hwaddr_aton(txtaddr, addr) ||
185 (sta = ap_get_sta(hapd, addr)) == NULL) {
186 ret = os_snprintf(buf, buflen, "FAIL\n");
187 if (ret < 0 || (size_t) ret >= buflen)
191 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
195 #ifdef CONFIG_P2P_MANAGER
196 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
197 u8 minor_reason_code, const u8 *addr)
199 struct ieee80211_mgmt *mgmt;
203 if (hapd->driver->send_frame == NULL)
206 mgmt = os_zalloc(sizeof(*mgmt) + 100);
210 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
211 " with minor reason code %u (stype=%u)",
212 MAC2STR(addr), minor_reason_code, stype);
214 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
215 os_memcpy(mgmt->da, addr, ETH_ALEN);
216 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
217 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
218 if (stype == WLAN_FC_STYPE_DEAUTH) {
219 mgmt->u.deauth.reason_code =
220 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
221 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
223 mgmt->u.disassoc.reason_code =
224 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
225 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
228 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
230 WPA_PUT_BE24(pos, OUI_WFA);
232 *pos++ = P2P_OUI_TYPE;
234 *pos++ = P2P_ATTR_MINOR_REASON_CODE;
235 WPA_PUT_LE16(pos, 1);
237 *pos++ = minor_reason_code;
239 ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
240 pos - (u8 *) mgmt, 1);
243 return ret < 0 ? -1 : 0;
245 #endif /* CONFIG_P2P_MANAGER */
248 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
252 struct sta_info *sta;
254 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
256 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
259 if (hwaddr_aton(txtaddr, addr))
262 pos = os_strstr(txtaddr, " test=");
264 struct ieee80211_mgmt mgmt;
266 if (hapd->driver->send_frame == NULL)
270 os_memset(&mgmt, 0, sizeof(mgmt));
271 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
272 WLAN_FC_STYPE_DEAUTH);
273 os_memcpy(mgmt.da, addr, ETH_ALEN);
274 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
275 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
276 mgmt.u.deauth.reason_code =
277 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
278 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
280 sizeof(mgmt.u.deauth),
286 #ifdef CONFIG_P2P_MANAGER
287 pos = os_strstr(txtaddr, " p2p=");
289 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
290 atoi(pos + 5), addr);
292 #endif /* CONFIG_P2P_MANAGER */
294 pos = os_strstr(txtaddr, " reason=");
296 reason = atoi(pos + 8);
298 hostapd_drv_sta_deauth(hapd, addr, reason);
299 sta = ap_get_sta(hapd, addr);
301 ap_sta_deauthenticate(hapd, sta, reason);
302 else if (addr[0] == 0xff)
303 hostapd_free_stas(hapd);
309 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
313 struct sta_info *sta;
315 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
317 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
320 if (hwaddr_aton(txtaddr, addr))
323 pos = os_strstr(txtaddr, " test=");
325 struct ieee80211_mgmt mgmt;
327 if (hapd->driver->send_frame == NULL)
331 os_memset(&mgmt, 0, sizeof(mgmt));
332 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
333 WLAN_FC_STYPE_DISASSOC);
334 os_memcpy(mgmt.da, addr, ETH_ALEN);
335 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
336 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
337 mgmt.u.disassoc.reason_code =
338 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
339 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
341 sizeof(mgmt.u.deauth),
347 #ifdef CONFIG_P2P_MANAGER
348 pos = os_strstr(txtaddr, " p2p=");
350 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
351 atoi(pos + 5), addr);
353 #endif /* CONFIG_P2P_MANAGER */
355 pos = os_strstr(txtaddr, " reason=");
357 reason = atoi(pos + 8);
359 hostapd_drv_sta_disassoc(hapd, addr, reason);
360 sta = ap_get_sta(hapd, addr);
362 ap_sta_disassociate(hapd, sta, reason);
363 else if (addr[0] == 0xff)
364 hostapd_free_stas(hapd);
370 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
373 struct hostapd_iface *iface = hapd->iface;
377 ret = os_snprintf(buf + len, buflen - len,
381 "num_sta_non_erp=%d\n"
382 "num_sta_no_short_slot_time=%d\n"
383 "num_sta_no_short_preamble=%d\n"
385 "num_sta_ht_no_gf=%d\n"
387 "num_sta_ht_20_mhz=%d\n"
390 hostapd_state_text(iface->state),
393 iface->num_sta_non_erp,
394 iface->num_sta_no_short_slot_time,
395 iface->num_sta_no_short_preamble,
397 iface->num_sta_ht_no_gf,
398 iface->num_sta_no_ht,
399 iface->num_sta_ht_20mhz,
402 if (ret < 0 || (size_t) ret >= buflen - len)
406 ret = os_snprintf(buf + len, buflen - len,
408 "secondary_channel=%d\n"
411 "vht_oper_chwidth=%d\n"
412 "vht_oper_centr_freq_seg0_idx=%d\n"
413 "vht_oper_centr_freq_seg1_idx=%d\n",
414 iface->conf->channel,
415 iface->conf->secondary_channel,
416 iface->conf->ieee80211n,
417 iface->conf->ieee80211ac,
418 iface->conf->vht_oper_chwidth,
419 iface->conf->vht_oper_centr_freq_seg0_idx,
420 iface->conf->vht_oper_centr_freq_seg1_idx);
421 if (ret < 0 || (size_t) ret >= buflen - len)
425 for (i = 0; i < iface->num_bss; i++) {
426 struct hostapd_data *bss = iface->bss[i];
427 ret = os_snprintf(buf + len, buflen - len,
429 "bssid[%d]=" MACSTR "\n"
432 (int) i, bss->conf->iface,
433 (int) i, MAC2STR(bss->own_addr),
435 wpa_ssid_txt(bss->conf->ssid.ssid,
436 bss->conf->ssid.ssid_len),
437 (int) i, bss->num_sta);
438 if (ret < 0 || (size_t) ret >= buflen - len)
447 int hostapd_parse_csa_settings(const char *pos,
448 struct csa_settings *settings)
455 os_memset(settings, 0, sizeof(*settings));
456 settings->cs_count = strtol(pos, &end, 10);
458 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
462 settings->freq_params.freq = atoi(end);
463 if (settings->freq_params.freq == 0) {
464 wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
468 #define SET_CSA_SETTING(str) \
470 const char *pos2 = os_strstr(pos, " " #str "="); \
472 pos2 += sizeof(" " #str "=") - 1; \
473 settings->freq_params.str = atoi(pos2); \
477 SET_CSA_SETTING(center_freq1);
478 SET_CSA_SETTING(center_freq2);
479 SET_CSA_SETTING(bandwidth);
480 SET_CSA_SETTING(sec_channel_offset);
481 settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
482 settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
483 settings->block_tx = !!os_strstr(pos, " blocktx");
484 #undef SET_CSA_SETTING