Home | History | Annotate | Download | only in ap
      1 /*
      2  * Control interface for shared AP commands
      3  * Copyright (c) 2004-2014, Jouni Malinen <j (at) 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 
     27 
     28 static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
     29 				 struct sta_info *sta,
     30 				 char *buf, size_t buflen)
     31 {
     32 	struct hostap_sta_driver_data data;
     33 	int ret;
     34 
     35 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
     36 		return 0;
     37 
     38 	ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
     39 			  "rx_bytes=%llu\ntx_bytes=%llu\n",
     40 			  data.rx_packets, data.tx_packets,
     41 			  data.rx_bytes, data.tx_bytes);
     42 	if (os_snprintf_error(buflen, ret))
     43 		return 0;
     44 	return ret;
     45 }
     46 
     47 
     48 static int hostapd_get_sta_conn_time(struct sta_info *sta,
     49 				     char *buf, size_t buflen)
     50 {
     51 	struct os_reltime age;
     52 	int ret;
     53 
     54 	if (!sta->connected_time.sec)
     55 		return 0;
     56 
     57 	os_reltime_age(&sta->connected_time, &age);
     58 
     59 	ret = os_snprintf(buf, buflen, "connected_time=%u\n",
     60 			  (unsigned int) age.sec);
     61 	if (os_snprintf_error(buflen, ret))
     62 		return 0;
     63 	return ret;
     64 }
     65 
     66 
     67 static const char * timeout_next_str(int val)
     68 {
     69 	switch (val) {
     70 	case STA_NULLFUNC:
     71 		return "NULLFUNC POLL";
     72 	case STA_DISASSOC:
     73 		return "DISASSOC";
     74 	case STA_DEAUTH:
     75 		return "DEAUTH";
     76 	case STA_REMOVE:
     77 		return "REMOVE";
     78 	case STA_DISASSOC_FROM_CLI:
     79 		return "DISASSOC_FROM_CLI";
     80 	}
     81 
     82 	return "?";
     83 }
     84 
     85 
     86 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
     87 				      struct sta_info *sta,
     88 				      char *buf, size_t buflen)
     89 {
     90 	int len, res, ret, i;
     91 
     92 	if (!sta)
     93 		return 0;
     94 
     95 	len = 0;
     96 	ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
     97 			  MAC2STR(sta->addr));
     98 	if (os_snprintf_error(buflen - len, ret))
     99 		return len;
    100 	len += ret;
    101 
    102 	ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
    103 	if (ret < 0)
    104 		return len;
    105 	len += ret;
    106 
    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 (os_snprintf_error(buflen - len, ret))
    111 		return len;
    112 	len += ret;
    113 
    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 (os_snprintf_error(buflen - len, ret))
    119 			return len;
    120 		len += ret;
    121 	}
    122 
    123 	ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
    124 			  timeout_next_str(sta->timeout_next));
    125 	if (os_snprintf_error(buflen - len, ret))
    126 		return len;
    127 	len += ret;
    128 
    129 	res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
    130 	if (res >= 0)
    131 		len += res;
    132 	res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
    133 	if (res >= 0)
    134 		len += res;
    135 	res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
    136 	if (res >= 0)
    137 		len += res;
    138 	res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
    139 				      buflen - len);
    140 	if (res >= 0)
    141 		len += res;
    142 	res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
    143 	if (res >= 0)
    144 		len += res;
    145 
    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);
    148 
    149 #ifdef CONFIG_SAE
    150 	if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
    151 		res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
    152 				  sta->sae->group);
    153 		if (!os_snprintf_error(buflen - len, res))
    154 			len += res;
    155 	}
    156 #endif /* CONFIG_SAE */
    157 
    158 	if (sta->vlan_id > 0) {
    159 		res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
    160 				  sta->vlan_id);
    161 		if (!os_snprintf_error(buflen - len, res))
    162 			len += res;
    163 	}
    164 
    165 	res = mbo_ap_get_info(sta, buf + len, buflen - len);
    166 	if (res >= 0)
    167 		len += res;
    168 
    169 	if (sta->supp_op_classes &&
    170 	    buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
    171 		len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
    172 		len += wpa_snprintf_hex(buf + len, buflen - len,
    173 					sta->supp_op_classes + 1,
    174 					sta->supp_op_classes[0]);
    175 		len += os_snprintf(buf + len, buflen - len, "\n");
    176 	}
    177 
    178 	return len;
    179 }
    180 
    181 
    182 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
    183 				 char *buf, size_t buflen)
    184 {
    185 	return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
    186 }
    187 
    188 
    189 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
    190 			   char *buf, size_t buflen)
    191 {
    192 	u8 addr[ETH_ALEN];
    193 	int ret;
    194 	const char *pos;
    195 	struct sta_info *sta;
    196 
    197 	if (hwaddr_aton(txtaddr, addr)) {
    198 		ret = os_snprintf(buf, buflen, "FAIL\n");
    199 		if (os_snprintf_error(buflen, ret))
    200 			return 0;
    201 		return ret;
    202 	}
    203 
    204 	sta = ap_get_sta(hapd, addr);
    205 	if (sta == NULL)
    206 		return -1;
    207 
    208 	pos = os_strchr(txtaddr, ' ');
    209 	if (pos) {
    210 		pos++;
    211 
    212 #ifdef HOSTAPD_DUMP_STATE
    213 		if (os_strcmp(pos, "eapol") == 0) {
    214 			if (sta->eapol_sm == NULL)
    215 				return -1;
    216 			return eapol_auth_dump_state(sta->eapol_sm, buf,
    217 						     buflen);
    218 		}
    219 #endif /* HOSTAPD_DUMP_STATE */
    220 
    221 		return -1;
    222 	}
    223 
    224 	ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
    225 	ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
    226 
    227 	return ret;
    228 }
    229 
    230 
    231 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
    232 				char *buf, size_t buflen)
    233 {
    234 	u8 addr[ETH_ALEN];
    235 	struct sta_info *sta;
    236 	int ret;
    237 
    238 	if (hwaddr_aton(txtaddr, addr) ||
    239 	    (sta = ap_get_sta(hapd, addr)) == NULL) {
    240 		ret = os_snprintf(buf, buflen, "FAIL\n");
    241 		if (os_snprintf_error(buflen, ret))
    242 			return 0;
    243 		return ret;
    244 	}
    245 
    246 	if (!sta->next)
    247 		return 0;
    248 
    249 	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
    250 }
    251 
    252 
    253 #ifdef CONFIG_P2P_MANAGER
    254 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
    255 				  u8 minor_reason_code, const u8 *addr)
    256 {
    257 	struct ieee80211_mgmt *mgmt;
    258 	int ret;
    259 	u8 *pos;
    260 
    261 	if (hapd->driver->send_frame == NULL)
    262 		return -1;
    263 
    264 	mgmt = os_zalloc(sizeof(*mgmt) + 100);
    265 	if (mgmt == NULL)
    266 		return -1;
    267 
    268 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
    269 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
    270 		" with minor reason code %u (stype=%u (%s))",
    271 		MAC2STR(addr), minor_reason_code, stype,
    272 		fc2str(mgmt->frame_control));
    273 
    274 	os_memcpy(mgmt->da, addr, ETH_ALEN);
    275 	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
    276 	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
    277 	if (stype == WLAN_FC_STYPE_DEAUTH) {
    278 		mgmt->u.deauth.reason_code =
    279 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    280 		pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
    281 	} else {
    282 		mgmt->u.disassoc.reason_code =
    283 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    284 		pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
    285 	}
    286 
    287 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
    288 	*pos++ = 4 + 3 + 1;
    289 	WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
    290 	pos += 4;
    291 
    292 	*pos++ = P2P_ATTR_MINOR_REASON_CODE;
    293 	WPA_PUT_LE16(pos, 1);
    294 	pos += 2;
    295 	*pos++ = minor_reason_code;
    296 
    297 	ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
    298 				       pos - (u8 *) mgmt, 1);
    299 	os_free(mgmt);
    300 
    301 	return ret < 0 ? -1 : 0;
    302 }
    303 #endif /* CONFIG_P2P_MANAGER */
    304 
    305 
    306 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
    307 				      const char *txtaddr)
    308 {
    309 	u8 addr[ETH_ALEN];
    310 	struct sta_info *sta;
    311 	const char *pos;
    312 	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
    313 
    314 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
    315 		txtaddr);
    316 
    317 	if (hwaddr_aton(txtaddr, addr))
    318 		return -1;
    319 
    320 	pos = os_strstr(txtaddr, " reason=");
    321 	if (pos)
    322 		reason = atoi(pos + 8);
    323 
    324 	pos = os_strstr(txtaddr, " test=");
    325 	if (pos) {
    326 		struct ieee80211_mgmt mgmt;
    327 		int encrypt;
    328 		if (hapd->driver->send_frame == NULL)
    329 			return -1;
    330 		pos += 6;
    331 		encrypt = atoi(pos);
    332 		os_memset(&mgmt, 0, sizeof(mgmt));
    333 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    334 						  WLAN_FC_STYPE_DEAUTH);
    335 		os_memcpy(mgmt.da, addr, ETH_ALEN);
    336 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
    337 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
    338 		mgmt.u.deauth.reason_code = host_to_le16(reason);
    339 		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
    340 					     IEEE80211_HDRLEN +
    341 					     sizeof(mgmt.u.deauth),
    342 					     encrypt) < 0)
    343 			return -1;
    344 		return 0;
    345 	}
    346 
    347 #ifdef CONFIG_P2P_MANAGER
    348 	pos = os_strstr(txtaddr, " p2p=");
    349 	if (pos) {
    350 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
    351 					      atoi(pos + 5), addr);
    352 	}
    353 #endif /* CONFIG_P2P_MANAGER */
    354 
    355 	hostapd_drv_sta_deauth(hapd, addr, reason);
    356 	sta = ap_get_sta(hapd, addr);
    357 	if (sta)
    358 		ap_sta_deauthenticate(hapd, sta, reason);
    359 	else if (addr[0] == 0xff)
    360 		hostapd_free_stas(hapd);
    361 
    362 	return 0;
    363 }
    364 
    365 
    366 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
    367 				    const char *txtaddr)
    368 {
    369 	u8 addr[ETH_ALEN];
    370 	struct sta_info *sta;
    371 	const char *pos;
    372 	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
    373 
    374 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
    375 		txtaddr);
    376 
    377 	if (hwaddr_aton(txtaddr, addr))
    378 		return -1;
    379 
    380 	pos = os_strstr(txtaddr, " reason=");
    381 	if (pos)
    382 		reason = atoi(pos + 8);
    383 
    384 	pos = os_strstr(txtaddr, " test=");
    385 	if (pos) {
    386 		struct ieee80211_mgmt mgmt;
    387 		int encrypt;
    388 		if (hapd->driver->send_frame == NULL)
    389 			return -1;
    390 		pos += 6;
    391 		encrypt = atoi(pos);
    392 		os_memset(&mgmt, 0, sizeof(mgmt));
    393 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    394 						  WLAN_FC_STYPE_DISASSOC);
    395 		os_memcpy(mgmt.da, addr, ETH_ALEN);
    396 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
    397 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
    398 		mgmt.u.disassoc.reason_code = host_to_le16(reason);
    399 		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
    400 					     IEEE80211_HDRLEN +
    401 					     sizeof(mgmt.u.deauth),
    402 					     encrypt) < 0)
    403 			return -1;
    404 		return 0;
    405 	}
    406 
    407 #ifdef CONFIG_P2P_MANAGER
    408 	pos = os_strstr(txtaddr, " p2p=");
    409 	if (pos) {
    410 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
    411 					      atoi(pos + 5), addr);
    412 	}
    413 #endif /* CONFIG_P2P_MANAGER */
    414 
    415 	hostapd_drv_sta_disassoc(hapd, addr, reason);
    416 	sta = ap_get_sta(hapd, addr);
    417 	if (sta)
    418 		ap_sta_disassociate(hapd, sta, reason);
    419 	else if (addr[0] == 0xff)
    420 		hostapd_free_stas(hapd);
    421 
    422 	return 0;
    423 }
    424 
    425 
    426 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
    427 			      size_t buflen)
    428 {
    429 	struct hostapd_iface *iface = hapd->iface;
    430 	int len = 0, ret;
    431 	size_t i;
    432 
    433 	ret = os_snprintf(buf + len, buflen - len,
    434 			  "state=%s\n"
    435 			  "phy=%s\n"
    436 			  "freq=%d\n"
    437 			  "num_sta_non_erp=%d\n"
    438 			  "num_sta_no_short_slot_time=%d\n"
    439 			  "num_sta_no_short_preamble=%d\n"
    440 			  "olbc=%d\n"
    441 			  "num_sta_ht_no_gf=%d\n"
    442 			  "num_sta_no_ht=%d\n"
    443 			  "num_sta_ht_20_mhz=%d\n"
    444 			  "num_sta_ht40_intolerant=%d\n"
    445 			  "olbc_ht=%d\n"
    446 			  "ht_op_mode=0x%x\n",
    447 			  hostapd_state_text(iface->state),
    448 			  iface->phy,
    449 			  iface->freq,
    450 			  iface->num_sta_non_erp,
    451 			  iface->num_sta_no_short_slot_time,
    452 			  iface->num_sta_no_short_preamble,
    453 			  iface->olbc,
    454 			  iface->num_sta_ht_no_gf,
    455 			  iface->num_sta_no_ht,
    456 			  iface->num_sta_ht_20mhz,
    457 			  iface->num_sta_ht40_intolerant,
    458 			  iface->olbc_ht,
    459 			  iface->ht_op_mode);
    460 	if (os_snprintf_error(buflen - len, ret))
    461 		return len;
    462 	len += ret;
    463 
    464 	if (!iface->cac_started || !iface->dfs_cac_ms) {
    465 		ret = os_snprintf(buf + len, buflen - len,
    466 				  "cac_time_seconds=%d\n"
    467 				  "cac_time_left_seconds=N/A\n",
    468 				  iface->dfs_cac_ms / 1000);
    469 	} else {
    470 		/* CAC started and CAC time set - calculate remaining time */
    471 		struct os_reltime now;
    472 		unsigned int left_time;
    473 
    474 		os_reltime_age(&iface->dfs_cac_start, &now);
    475 		left_time = iface->dfs_cac_ms / 1000 - now.sec;
    476 		ret = os_snprintf(buf + len, buflen - len,
    477 				  "cac_time_seconds=%u\n"
    478 				  "cac_time_left_seconds=%u\n",
    479 				  iface->dfs_cac_ms / 1000,
    480 				  left_time);
    481 	}
    482 	if (os_snprintf_error(buflen - len, ret))
    483 		return len;
    484 	len += ret;
    485 
    486 	ret = os_snprintf(buf + len, buflen - len,
    487 			  "channel=%u\n"
    488 			  "secondary_channel=%d\n"
    489 			  "ieee80211n=%d\n"
    490 			  "ieee80211ac=%d\n"
    491 			  "vht_oper_chwidth=%d\n"
    492 			  "vht_oper_centr_freq_seg0_idx=%d\n"
    493 			  "vht_oper_centr_freq_seg1_idx=%d\n",
    494 			  iface->conf->channel,
    495 			  iface->conf->secondary_channel,
    496 			  iface->conf->ieee80211n,
    497 			  iface->conf->ieee80211ac,
    498 			  iface->conf->vht_oper_chwidth,
    499 			  iface->conf->vht_oper_centr_freq_seg0_idx,
    500 			  iface->conf->vht_oper_centr_freq_seg1_idx);
    501 	if (os_snprintf_error(buflen - len, ret))
    502 		return len;
    503 	len += ret;
    504 
    505 	for (i = 0; i < iface->num_bss; i++) {
    506 		struct hostapd_data *bss = iface->bss[i];
    507 		ret = os_snprintf(buf + len, buflen - len,
    508 				  "bss[%d]=%s\n"
    509 				  "bssid[%d]=" MACSTR "\n"
    510 				  "ssid[%d]=%s\n"
    511 				  "num_sta[%d]=%d\n",
    512 				  (int) i, bss->conf->iface,
    513 				  (int) i, MAC2STR(bss->own_addr),
    514 				  (int) i,
    515 				  wpa_ssid_txt(bss->conf->ssid.ssid,
    516 					       bss->conf->ssid.ssid_len),
    517 				  (int) i, bss->num_sta);
    518 		if (os_snprintf_error(buflen - len, ret))
    519 			return len;
    520 		len += ret;
    521 	}
    522 
    523 	return len;
    524 }
    525 
    526 
    527 int hostapd_parse_csa_settings(const char *pos,
    528 			       struct csa_settings *settings)
    529 {
    530 	char *end;
    531 
    532 	os_memset(settings, 0, sizeof(*settings));
    533 	settings->cs_count = strtol(pos, &end, 10);
    534 	if (pos == end) {
    535 		wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
    536 		return -1;
    537 	}
    538 
    539 	settings->freq_params.freq = atoi(end);
    540 	if (settings->freq_params.freq == 0) {
    541 		wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
    542 		return -1;
    543 	}
    544 
    545 #define SET_CSA_SETTING(str) \
    546 	do { \
    547 		const char *pos2 = os_strstr(pos, " " #str "="); \
    548 		if (pos2) { \
    549 			pos2 += sizeof(" " #str "=") - 1; \
    550 			settings->freq_params.str = atoi(pos2); \
    551 		} \
    552 	} while (0)
    553 
    554 	SET_CSA_SETTING(center_freq1);
    555 	SET_CSA_SETTING(center_freq2);
    556 	SET_CSA_SETTING(bandwidth);
    557 	SET_CSA_SETTING(sec_channel_offset);
    558 	settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
    559 	settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
    560 	settings->block_tx = !!os_strstr(pos, " blocktx");
    561 #undef SET_CSA_SETTING
    562 
    563 	return 0;
    564 }
    565 
    566 
    567 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
    568 {
    569 	return hostapd_drv_stop_ap(hapd);
    570 }
    571 
    572 
    573 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
    574 				  size_t len)
    575 {
    576 	return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
    577 }
    578 
    579 
    580 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
    581 {
    582 	wpa_auth_pmksa_flush(hapd->wpa_auth);
    583 }
    584