Home | History | Annotate | Line # | Download | only in ap
      1 /*
      2  * Control interface for shared AP commands
      3  * Copyright (c) 2004-2019, 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 #include "taxonomy.h"
     27 #include "wnm_ap.h"
     28 
     29 
     30 static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
     31 					   size_t curr_len, const u8 *mcs_set)
     32 {
     33 	int ret;
     34 	size_t len = curr_len;
     35 
     36 	ret = os_snprintf(buf + len, buflen - len,
     37 			  "ht_mcs_bitmask=");
     38 	if (os_snprintf_error(buflen - len, ret))
     39 		return len;
     40 	len += ret;
     41 
     42 	/* 77 first bits (+ 3 reserved bits) */
     43 	len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
     44 
     45 	ret = os_snprintf(buf + len, buflen - len, "\n");
     46 	if (os_snprintf_error(buflen - len, ret))
     47 		return curr_len;
     48 	len += ret;
     49 
     50 	return len;
     51 }
     52 
     53 
     54 static int hostapd_get_sta_conn_time(struct sta_info *sta,
     55 				     struct hostap_sta_driver_data *data,
     56 				     char *buf, size_t buflen)
     57 {
     58 	struct os_reltime age;
     59 	unsigned long secs;
     60 	int ret;
     61 
     62 	if (sta->connected_time.sec) {
     63 		/* Locally maintained time in AP mode */
     64 		os_reltime_age(&sta->connected_time, &age);
     65 		secs = (unsigned long) age.sec;
     66 	} else if (data->flags & STA_DRV_DATA_CONN_TIME) {
     67 		/* Time from the driver in mesh mode */
     68 		secs = data->connected_sec;
     69 	} else {
     70 		return 0;
     71 	}
     72 
     73 	ret = os_snprintf(buf, buflen, "connected_time=%lu\n", secs);
     74 	if (os_snprintf_error(buflen, ret))
     75 		return 0;
     76 	return ret;
     77 }
     78 
     79 
     80 static int hostapd_get_sta_info(struct hostapd_data *hapd,
     81 				struct sta_info *sta,
     82 				char *buf, size_t buflen)
     83 {
     84 	struct hostap_sta_driver_data data;
     85 	int ret;
     86 	int len = 0;
     87 
     88 	if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
     89 		return 0;
     90 
     91 	ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
     92 			  "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
     93 			  "signal=%d\n",
     94 			  data.rx_packets, data.tx_packets,
     95 			  data.rx_bytes, data.tx_bytes, data.inactive_msec,
     96 			  data.signal);
     97 	if (os_snprintf_error(buflen, ret))
     98 		return 0;
     99 	len += ret;
    100 
    101 	ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
    102 			  data.current_rx_rate / 100);
    103 	if (os_snprintf_error(buflen - len, ret))
    104 		return len;
    105 	len += ret;
    106 	if (data.flags & STA_DRV_DATA_RX_MCS) {
    107 		ret = os_snprintf(buf + len, buflen - len, " mcs %u",
    108 				  data.rx_mcs);
    109 		if (!os_snprintf_error(buflen - len, ret))
    110 			len += ret;
    111 	}
    112 	if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
    113 		ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
    114 				  data.rx_vhtmcs);
    115 		if (!os_snprintf_error(buflen - len, ret))
    116 			len += ret;
    117 	}
    118 	if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
    119 		ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
    120 				  data.rx_vht_nss);
    121 		if (!os_snprintf_error(buflen - len, ret))
    122 			len += ret;
    123 	}
    124 	if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
    125 		ret = os_snprintf(buf + len, buflen - len, " shortGI");
    126 		if (!os_snprintf_error(buflen - len, ret))
    127 			len += ret;
    128 	}
    129 	ret = os_snprintf(buf + len, buflen - len, "\n");
    130 	if (!os_snprintf_error(buflen - len, ret))
    131 		len += ret;
    132 
    133 	ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
    134 			  data.current_tx_rate / 100);
    135 	if (os_snprintf_error(buflen - len, ret))
    136 		return len;
    137 	len += ret;
    138 	if (data.flags & STA_DRV_DATA_TX_MCS) {
    139 		ret = os_snprintf(buf + len, buflen - len, " mcs %u",
    140 				  data.tx_mcs);
    141 		if (!os_snprintf_error(buflen - len, ret))
    142 			len += ret;
    143 	}
    144 	if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
    145 		ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
    146 				  data.tx_vhtmcs);
    147 		if (!os_snprintf_error(buflen - len, ret))
    148 			len += ret;
    149 	}
    150 	if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
    151 		ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
    152 				  data.tx_vht_nss);
    153 		if (!os_snprintf_error(buflen - len, ret))
    154 			len += ret;
    155 	}
    156 	if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
    157 		ret = os_snprintf(buf + len, buflen - len, " shortGI");
    158 		if (!os_snprintf_error(buflen - len, ret))
    159 			len += ret;
    160 	}
    161 	ret = os_snprintf(buf + len, buflen - len, "\n");
    162 	if (!os_snprintf_error(buflen - len, ret))
    163 		len += ret;
    164 
    165 	if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
    166 		ret = os_snprintf(buf + len, buflen - len,
    167 				  "rx_vht_mcs_map=%04x\n"
    168 				  "tx_vht_mcs_map=%04x\n",
    169 				  le_to_host16(sta->vht_capabilities->
    170 					       vht_supported_mcs_set.rx_map),
    171 				  le_to_host16(sta->vht_capabilities->
    172 					       vht_supported_mcs_set.tx_map));
    173 		if (!os_snprintf_error(buflen - len, ret))
    174 			len += ret;
    175 	}
    176 
    177 	if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
    178 		len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
    179 						   sta->ht_capabilities->
    180 						   supported_mcs_set);
    181 	}
    182 
    183 	if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
    184 		ret = os_snprintf(buf + len, buflen - len,
    185 				  "last_ack_signal=%d\n", data.last_ack_rssi);
    186 		if (!os_snprintf_error(buflen - len, ret))
    187 			len += ret;
    188 	}
    189 
    190 	len += hostapd_get_sta_conn_time(sta, &data, buf + len, buflen - len);
    191 
    192 	return len;
    193 }
    194 
    195 
    196 static const char * timeout_next_str(int val)
    197 {
    198 	switch (val) {
    199 	case STA_NULLFUNC:
    200 		return "NULLFUNC POLL";
    201 	case STA_DISASSOC:
    202 		return "DISASSOC";
    203 	case STA_DEAUTH:
    204 		return "DEAUTH";
    205 	case STA_REMOVE:
    206 		return "REMOVE";
    207 	case STA_DISASSOC_FROM_CLI:
    208 		return "DISASSOC_FROM_CLI";
    209 	default:
    210 		return "?";
    211 	}
    212 }
    213 
    214 
    215 static const char * hw_mode_str(enum hostapd_hw_mode mode)
    216 {
    217 	switch (mode) {
    218 	case HOSTAPD_MODE_IEEE80211B:
    219 		return "b";
    220 	case HOSTAPD_MODE_IEEE80211G:
    221 		return "g";
    222 	case HOSTAPD_MODE_IEEE80211A:
    223 		return "a";
    224 	case HOSTAPD_MODE_IEEE80211AD:
    225 		return "ad";
    226 	case HOSTAPD_MODE_IEEE80211ANY:
    227 		return "any";
    228 	case NUM_HOSTAPD_MODES:
    229 		return "invalid";
    230 	}
    231 	return "unknown";
    232 }
    233 
    234 
    235 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
    236 				      struct sta_info *sta,
    237 				      char *buf, size_t buflen)
    238 {
    239 	int len, res, ret, i;
    240 	const char *keyid;
    241 	const u8 *dpp_pkhash;
    242 
    243 	if (!sta)
    244 		return 0;
    245 
    246 	len = 0;
    247 	ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
    248 			  MAC2STR(sta->addr));
    249 	if (os_snprintf_error(buflen - len, ret))
    250 		return len;
    251 	len += ret;
    252 
    253 	ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
    254 	if (ret < 0)
    255 		return len;
    256 	len += ret;
    257 
    258 	ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
    259 			  "listen_interval=%d\nsupported_rates=",
    260 			  sta->aid, sta->capability, sta->listen_interval);
    261 	if (os_snprintf_error(buflen - len, ret))
    262 		return len;
    263 	len += ret;
    264 
    265 	for (i = 0; i < sta->supported_rates_len; i++) {
    266 		ret = os_snprintf(buf + len, buflen - len, "%02x%s",
    267 				  sta->supported_rates[i],
    268 				  i + 1 < sta->supported_rates_len ? " " : "");
    269 		if (os_snprintf_error(buflen - len, ret))
    270 			return len;
    271 		len += ret;
    272 	}
    273 
    274 	ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
    275 			  timeout_next_str(sta->timeout_next));
    276 	if (os_snprintf_error(buflen - len, ret))
    277 		return len;
    278 	len += ret;
    279 
    280 	if (sta->max_idle_period) {
    281 		ret = os_snprintf(buf + len, buflen - len,
    282 				  "max_idle_period=%d\n", sta->max_idle_period);
    283 		if (os_snprintf_error(buflen - len, ret))
    284 			return len;
    285 		len += ret;
    286 	}
    287 
    288 	res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
    289 	if (res >= 0)
    290 		len += res;
    291 	res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
    292 	if (res >= 0)
    293 		len += res;
    294 	res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
    295 	if (res >= 0)
    296 		len += res;
    297 	res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
    298 				      buflen - len);
    299 	if (res >= 0)
    300 		len += res;
    301 	res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
    302 	if (res >= 0)
    303 		len += res;
    304 
    305 	len += hostapd_get_sta_info(hapd, sta, buf + len, buflen - len);
    306 
    307 #ifdef CONFIG_SAE
    308 	if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
    309 		res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
    310 				  sta->sae->group);
    311 		if (!os_snprintf_error(buflen - len, res))
    312 			len += res;
    313 	}
    314 
    315 	if (sta->sae && sta->sae->tmp) {
    316 		const u8 *pos;
    317 		unsigned int j, count;
    318 		struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
    319 
    320 		res = os_snprintf(buf + len, buflen - len,
    321 				  "sae_rejected_groups=");
    322 		if (!os_snprintf_error(buflen - len, res))
    323 			len += res;
    324 
    325 		if (groups) {
    326 			pos = wpabuf_head(groups);
    327 			count = wpabuf_len(groups) / 2;
    328 		} else {
    329 			pos = NULL;
    330 			count = 0;
    331 		}
    332 		for (j = 0; pos && j < count; j++) {
    333 			res = os_snprintf(buf + len, buflen - len, "%s%d",
    334 					  j == 0 ? "" : " ", WPA_GET_LE16(pos));
    335 			if (!os_snprintf_error(buflen - len, res))
    336 				len += res;
    337 			pos += 2;
    338 		}
    339 
    340 		res = os_snprintf(buf + len, buflen - len, "\n");
    341 		if (!os_snprintf_error(buflen - len, res))
    342 			len += res;
    343 	}
    344 #endif /* CONFIG_SAE */
    345 
    346 	if (sta->vlan_id > 0) {
    347 		res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
    348 				  sta->vlan_id);
    349 		if (!os_snprintf_error(buflen - len, res))
    350 			len += res;
    351 	}
    352 
    353 	res = mbo_ap_get_info(sta, buf + len, buflen - len);
    354 	if (res >= 0)
    355 		len += res;
    356 
    357 	if (sta->supp_op_classes &&
    358 	    buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
    359 		res = os_snprintf(buf + len, buflen - len, "supp_op_classes=");
    360 		if (!os_snprintf_error(buflen - len, res))
    361 			len += res;
    362 		len += wpa_snprintf_hex(buf + len, buflen - len,
    363 					sta->supp_op_classes + 1,
    364 					sta->supp_op_classes[0]);
    365 		res = os_snprintf(buf + len, buflen - len, "\n");
    366 		if (!os_snprintf_error(buflen - len, res))
    367 			len += res;
    368 	}
    369 
    370 	if (sta->power_capab) {
    371 		ret = os_snprintf(buf + len, buflen - len,
    372 				  "min_txpower=%d\n"
    373 				  "max_txpower=%d\n",
    374 				  sta->min_tx_power, sta->max_tx_power);
    375 		if (!os_snprintf_error(buflen - len, ret))
    376 			len += ret;
    377 	}
    378 
    379 #ifdef CONFIG_IEEE80211AX
    380 	if ((sta->flags & WLAN_STA_HE) && sta->he_capab) {
    381 		res = os_snprintf(buf + len, buflen - len, "he_capab=");
    382 		if (!os_snprintf_error(buflen - len, res))
    383 			len += res;
    384 		len += wpa_snprintf_hex(buf + len, buflen - len,
    385 					(const u8 *) sta->he_capab,
    386 					sta->he_capab_len);
    387 		res = os_snprintf(buf + len, buflen - len, "\n");
    388 		if (!os_snprintf_error(buflen - len, res))
    389 			len += res;
    390 	}
    391 #endif /* CONFIG_IEEE80211AX */
    392 
    393 #ifdef CONFIG_IEEE80211BE
    394 	if ((sta->flags & WLAN_STA_EHT) && sta->eht_capab) {
    395 		res = os_snprintf(buf + len, buflen - len, "eht_capab=");
    396 		if (!os_snprintf_error(buflen - len, res))
    397 			len += res;
    398 		len += wpa_snprintf_hex(buf + len, buflen - len,
    399 					(const u8 *) sta->eht_capab,
    400 					sta->eht_capab_len);
    401 		res = os_snprintf(buf + len, buflen - len, "\n");
    402 		if (!os_snprintf_error(buflen - len, res))
    403 			len += res;
    404 	}
    405 #endif /* CONFIG_IEEE80211BE */
    406 
    407 #ifdef CONFIG_IEEE80211AC
    408 	if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
    409 		res = os_snprintf(buf + len, buflen - len,
    410 				  "vht_caps_info=0x%08x\n",
    411 				  le_to_host32(sta->vht_capabilities->
    412 					       vht_capabilities_info));
    413 		if (!os_snprintf_error(buflen - len, res))
    414 			len += res;
    415 
    416 		res = os_snprintf(buf + len, buflen - len, "vht_capab=");
    417 		if (!os_snprintf_error(buflen - len, res))
    418 			len += res;
    419 		len += wpa_snprintf_hex(buf + len, buflen - len,
    420 					(const u8 *) sta->vht_capabilities,
    421 					sizeof(*sta->vht_capabilities));
    422 		res = os_snprintf(buf + len, buflen - len, "\n");
    423 		if (!os_snprintf_error(buflen - len, res))
    424 			len += res;
    425 	}
    426 #endif /* CONFIG_IEEE80211AC */
    427 
    428 	if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
    429 		res = os_snprintf(buf + len, buflen - len,
    430 				  "ht_caps_info=0x%04x\n",
    431 				  le_to_host16(sta->ht_capabilities->
    432 					       ht_capabilities_info));
    433 		if (!os_snprintf_error(buflen - len, res))
    434 			len += res;
    435 	}
    436 
    437 	if (sta->ext_capability &&
    438 	    buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
    439 		res = os_snprintf(buf + len, buflen - len, "ext_capab=");
    440 		if (!os_snprintf_error(buflen - len, res))
    441 			len += res;
    442 		len += wpa_snprintf_hex(buf + len, buflen - len,
    443 					sta->ext_capability + 1,
    444 					sta->ext_capability[0]);
    445 		res = os_snprintf(buf + len, buflen - len, "\n");
    446 		if (!os_snprintf_error(buflen - len, res))
    447 			len += res;
    448 	}
    449 
    450 	if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
    451 		ret = os_snprintf(buf + len, buflen - len,
    452 				  "wds_sta_ifname=%s\n", sta->ifname_wds);
    453 		if (!os_snprintf_error(buflen - len, ret))
    454 			len += ret;
    455 	}
    456 
    457 	keyid = ap_sta_wpa_get_keyid(hapd, sta);
    458 	if (keyid) {
    459 		ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
    460 		if (!os_snprintf_error(buflen - len, ret))
    461 			len += ret;
    462 	}
    463 
    464 	dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
    465 	if (dpp_pkhash) {
    466 		ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash=");
    467 		if (!os_snprintf_error(buflen - len, ret))
    468 			len += ret;
    469 		len += wpa_snprintf_hex(buf + len, buflen - len, dpp_pkhash,
    470 					SHA256_MAC_LEN);
    471 		ret = os_snprintf(buf + len, buflen - len, "\n");
    472 		if (!os_snprintf_error(buflen - len, ret))
    473 			len += ret;
    474 	}
    475 
    476 #ifdef CONFIG_IEEE80211BE
    477 	if (sta->mld_info.mld_sta) {
    478 		for (i = 0; i < MAX_NUM_MLD_LINKS; ++i) {
    479 			if (!sta->mld_info.links[i].valid)
    480 				continue;
    481 			ret = os_snprintf(
    482 				buf + len, buflen - len,
    483 				"peer_addr[%d]=" MACSTR "\n",
    484 				i, MAC2STR(sta->mld_info.links[i].peer_addr));
    485 			if (!os_snprintf_error(buflen - len, ret))
    486 				len += ret;
    487 		}
    488 	}
    489 #endif /* CONFIG_IEEE80211BE */
    490 
    491 	return len;
    492 }
    493 
    494 
    495 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
    496 				 char *buf, size_t buflen)
    497 {
    498 	return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
    499 }
    500 
    501 
    502 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
    503 			   char *buf, size_t buflen)
    504 {
    505 	u8 addr[ETH_ALEN];
    506 	int ret;
    507 	const char *pos;
    508 	struct sta_info *sta;
    509 
    510 	if (hwaddr_aton(txtaddr, addr)) {
    511 		ret = os_snprintf(buf, buflen, "FAIL\n");
    512 		if (os_snprintf_error(buflen, ret))
    513 			return 0;
    514 		return ret;
    515 	}
    516 
    517 	sta = ap_get_sta(hapd, addr);
    518 	if (sta == NULL)
    519 		return -1;
    520 
    521 	pos = os_strchr(txtaddr, ' ');
    522 	if (pos) {
    523 		pos++;
    524 
    525 #ifdef HOSTAPD_DUMP_STATE
    526 		if (os_strcmp(pos, "eapol") == 0) {
    527 			if (sta->eapol_sm == NULL)
    528 				return -1;
    529 			return eapol_auth_dump_state(sta->eapol_sm, buf,
    530 						     buflen);
    531 		}
    532 #endif /* HOSTAPD_DUMP_STATE */
    533 
    534 		return -1;
    535 	}
    536 
    537 	ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
    538 	ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
    539 
    540 	return ret;
    541 }
    542 
    543 
    544 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
    545 				char *buf, size_t buflen)
    546 {
    547 	u8 addr[ETH_ALEN];
    548 	struct sta_info *sta;
    549 	int ret;
    550 
    551 	if (hwaddr_aton(txtaddr, addr) ||
    552 	    (sta = ap_get_sta(hapd, addr)) == NULL) {
    553 		ret = os_snprintf(buf, buflen, "FAIL\n");
    554 		if (os_snprintf_error(buflen, ret))
    555 			return 0;
    556 		return ret;
    557 	}
    558 
    559 	if (!sta->next)
    560 		return 0;
    561 
    562 	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
    563 }
    564 
    565 
    566 #ifdef CONFIG_P2P_MANAGER
    567 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
    568 				  u8 minor_reason_code, const u8 *addr)
    569 {
    570 	struct ieee80211_mgmt *mgmt;
    571 	int ret;
    572 	u8 *pos;
    573 
    574 	mgmt = os_zalloc(sizeof(*mgmt) + 100);
    575 	if (mgmt == NULL)
    576 		return -1;
    577 
    578 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
    579 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
    580 		" with minor reason code %u (stype=%u (%s))",
    581 		MAC2STR(addr), minor_reason_code, stype,
    582 		fc2str(le_to_host16(mgmt->frame_control)));
    583 
    584 	os_memcpy(mgmt->da, addr, ETH_ALEN);
    585 	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
    586 	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
    587 	if (stype == WLAN_FC_STYPE_DEAUTH) {
    588 		mgmt->u.deauth.reason_code =
    589 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    590 		pos = mgmt->u.deauth.variable;
    591 	} else {
    592 		mgmt->u.disassoc.reason_code =
    593 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    594 		pos = mgmt->u.disassoc.variable;
    595 	}
    596 
    597 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
    598 	*pos++ = 4 + 3 + 1;
    599 	WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
    600 	pos += 4;
    601 
    602 	*pos++ = P2P_ATTR_MINOR_REASON_CODE;
    603 	WPA_PUT_LE16(pos, 1);
    604 	pos += 2;
    605 	*pos++ = minor_reason_code;
    606 
    607 	ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
    608 				    0);
    609 	os_free(mgmt);
    610 
    611 	return ret < 0 ? -1 : 0;
    612 }
    613 #endif /* CONFIG_P2P_MANAGER */
    614 
    615 
    616 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
    617 				      const char *txtaddr)
    618 {
    619 	u8 addr[ETH_ALEN];
    620 	struct sta_info *sta;
    621 	const char *pos;
    622 	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
    623 
    624 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
    625 		txtaddr);
    626 
    627 	if (hwaddr_aton(txtaddr, addr))
    628 		return -1;
    629 
    630 	pos = os_strstr(txtaddr, " reason=");
    631 	if (pos)
    632 		reason = atoi(pos + 8);
    633 
    634 	pos = os_strstr(txtaddr, " test=");
    635 	if (pos) {
    636 		struct ieee80211_mgmt mgmt;
    637 		int encrypt;
    638 
    639 		pos += 6;
    640 		encrypt = atoi(pos);
    641 		os_memset(&mgmt, 0, sizeof(mgmt));
    642 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    643 						  WLAN_FC_STYPE_DEAUTH);
    644 		os_memcpy(mgmt.da, addr, ETH_ALEN);
    645 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
    646 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
    647 		mgmt.u.deauth.reason_code = host_to_le16(reason);
    648 		if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
    649 					  IEEE80211_HDRLEN +
    650 					  sizeof(mgmt.u.deauth),
    651 					  0, NULL, 0, !encrypt) < 0)
    652 			return -1;
    653 		return 0;
    654 	}
    655 
    656 #ifdef CONFIG_P2P_MANAGER
    657 	pos = os_strstr(txtaddr, " p2p=");
    658 	if (pos) {
    659 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
    660 					      atoi(pos + 5), addr);
    661 	}
    662 #endif /* CONFIG_P2P_MANAGER */
    663 
    664 	if (os_strstr(txtaddr, " tx=0"))
    665 		hostapd_drv_sta_remove(hapd, addr);
    666 	else
    667 		hostapd_drv_sta_deauth(hapd, addr, reason);
    668 	sta = ap_get_sta(hapd, addr);
    669 	if (sta)
    670 		ap_sta_deauthenticate(hapd, sta, reason);
    671 	else if (addr[0] == 0xff)
    672 		hostapd_free_stas(hapd);
    673 
    674 	return 0;
    675 }
    676 
    677 
    678 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
    679 				    const char *txtaddr)
    680 {
    681 	u8 addr[ETH_ALEN];
    682 	struct sta_info *sta;
    683 	const char *pos;
    684 	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
    685 
    686 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
    687 		txtaddr);
    688 
    689 	if (hwaddr_aton(txtaddr, addr))
    690 		return -1;
    691 
    692 	pos = os_strstr(txtaddr, " reason=");
    693 	if (pos)
    694 		reason = atoi(pos + 8);
    695 
    696 	pos = os_strstr(txtaddr, " test=");
    697 	if (pos) {
    698 		struct ieee80211_mgmt mgmt;
    699 		int encrypt;
    700 
    701 		pos += 6;
    702 		encrypt = atoi(pos);
    703 		os_memset(&mgmt, 0, sizeof(mgmt));
    704 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    705 						  WLAN_FC_STYPE_DISASSOC);
    706 		os_memcpy(mgmt.da, addr, ETH_ALEN);
    707 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
    708 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
    709 		mgmt.u.disassoc.reason_code = host_to_le16(reason);
    710 		if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
    711 					  IEEE80211_HDRLEN +
    712 					  sizeof(mgmt.u.deauth),
    713 					  0, NULL, 0, !encrypt) < 0)
    714 			return -1;
    715 		return 0;
    716 	}
    717 
    718 #ifdef CONFIG_P2P_MANAGER
    719 	pos = os_strstr(txtaddr, " p2p=");
    720 	if (pos) {
    721 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
    722 					      atoi(pos + 5), addr);
    723 	}
    724 #endif /* CONFIG_P2P_MANAGER */
    725 
    726 	if (os_strstr(txtaddr, " tx=0"))
    727 		hostapd_drv_sta_remove(hapd, addr);
    728 	else
    729 		hostapd_drv_sta_disassoc(hapd, addr, reason);
    730 	sta = ap_get_sta(hapd, addr);
    731 	if (sta)
    732 		ap_sta_disassociate(hapd, sta, reason);
    733 	else if (addr[0] == 0xff)
    734 		hostapd_free_stas(hapd);
    735 
    736 	return 0;
    737 }
    738 
    739 
    740 #ifdef CONFIG_TAXONOMY
    741 int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
    742 				 const char *txtaddr,
    743 				 char *buf, size_t buflen)
    744 {
    745 	u8 addr[ETH_ALEN];
    746 	struct sta_info *sta;
    747 
    748 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
    749 
    750 	if (hwaddr_aton(txtaddr, addr))
    751 		return -1;
    752 
    753 	sta = ap_get_sta(hapd, addr);
    754 	if (!sta)
    755 		return -1;
    756 
    757 	return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
    758 }
    759 #endif /* CONFIG_TAXONOMY */
    760 
    761 
    762 int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
    763 				const char *txtaddr)
    764 {
    765 	u8 addr[ETH_ALEN];
    766 	struct sta_info *sta;
    767 
    768 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
    769 
    770 	if (hwaddr_aton(txtaddr, addr))
    771 		return -1;
    772 
    773 	sta = ap_get_sta(hapd, addr);
    774 	if (!sta)
    775 		return -1;
    776 
    777 	hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
    778 				sta->flags & WLAN_STA_WMM);
    779 	return 0;
    780 }
    781 
    782 
    783 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
    784 			      size_t buflen)
    785 {
    786 	struct hostapd_iface *iface = hapd->iface;
    787 	struct hostapd_hw_modes *mode = iface->current_mode;
    788 	struct hostapd_config *iconf = hapd->iconf;
    789 	int len = 0, ret, j;
    790 	size_t i;
    791 
    792 	ret = os_snprintf(buf + len, buflen - len,
    793 			  "state=%s\n"
    794 			  "phy=%s\n"
    795 			  "freq=%d\n"
    796 			  "num_sta_non_erp=%d\n"
    797 			  "num_sta_no_short_slot_time=%d\n"
    798 			  "num_sta_no_short_preamble=%d\n"
    799 			  "olbc=%d\n"
    800 			  "num_sta_ht_no_gf=%d\n"
    801 			  "num_sta_no_ht=%d\n"
    802 			  "num_sta_ht_20_mhz=%d\n"
    803 			  "num_sta_ht40_intolerant=%d\n"
    804 			  "olbc_ht=%d\n"
    805 			  "ht_op_mode=0x%x\n",
    806 			  hostapd_state_text(iface->state),
    807 			  iface->phy,
    808 			  iface->freq,
    809 			  iface->num_sta_non_erp,
    810 			  iface->num_sta_no_short_slot_time,
    811 			  iface->num_sta_no_short_preamble,
    812 			  iface->olbc,
    813 			  iface->num_sta_ht_no_gf,
    814 			  iface->num_sta_no_ht,
    815 			  iface->num_sta_ht_20mhz,
    816 			  iface->num_sta_ht40_intolerant,
    817 			  iface->olbc_ht,
    818 			  iface->ht_op_mode);
    819 	if (os_snprintf_error(buflen - len, ret))
    820 		return len;
    821 	len += ret;
    822 
    823 	if (mode) {
    824 		ret = os_snprintf(buf + len, buflen - len, "hw_mode=%s\n",
    825 				  hw_mode_str(mode->mode));
    826 		if (os_snprintf_error(buflen - len, ret))
    827 			return len;
    828 		len += ret;
    829 	}
    830 
    831 	if (iconf->country[0] && iconf->country[1]) {
    832 		ret = os_snprintf(buf + len, buflen - len,
    833 				  "country_code=%c%c\ncountry3=0x%X\n",
    834 				  iconf->country[0], iconf->country[1],
    835 				  iconf->country[2]);
    836 		if (os_snprintf_error(buflen - len, ret))
    837 			return len;
    838 		len += ret;
    839 	}
    840 
    841 	if (!iface->cac_started || !iface->dfs_cac_ms) {
    842 		ret = os_snprintf(buf + len, buflen - len,
    843 				  "cac_time_seconds=%d\n"
    844 				  "cac_time_left_seconds=N/A\n",
    845 				  iface->dfs_cac_ms / 1000);
    846 	} else {
    847 		/* CAC started and CAC time set - calculate remaining time */
    848 		struct os_reltime now;
    849 		long left_time;
    850 
    851 		os_reltime_age(&iface->dfs_cac_start, &now);
    852 		left_time = (long) iface->dfs_cac_ms / 1000 - now.sec;
    853 		ret = os_snprintf(buf + len, buflen - len,
    854 				  "cac_time_seconds=%u\n"
    855 				  "cac_time_left_seconds=%lu\n",
    856 				  iface->dfs_cac_ms / 1000,
    857 				  left_time > 0 ? left_time : 0);
    858 	}
    859 	if (os_snprintf_error(buflen - len, ret))
    860 		return len;
    861 	len += ret;
    862 
    863 	ret = os_snprintf(buf + len, buflen - len,
    864 			  "channel=%u\n"
    865 			  "edmg_enable=%d\n"
    866 			  "edmg_channel=%d\n"
    867 			  "secondary_channel=%d\n"
    868 			  "ieee80211n=%d\n"
    869 			  "ieee80211ac=%d\n"
    870 			  "ieee80211ax=%d\n"
    871 			  "ieee80211be=%d\n"
    872 			  "beacon_int=%u\n"
    873 			  "dtim_period=%d\n",
    874 			  iface->conf->channel,
    875 			  iface->conf->enable_edmg,
    876 			  iface->conf->edmg_channel,
    877 			  iface->conf->ieee80211n && !hapd->conf->disable_11n ?
    878 			  iface->conf->secondary_channel : 0,
    879 			  iface->conf->ieee80211n && !hapd->conf->disable_11n,
    880 			  iface->conf->ieee80211ac &&
    881 			  !hapd->conf->disable_11ac,
    882 			  iface->conf->ieee80211ax &&
    883 			  !hapd->conf->disable_11ax,
    884 			  iface->conf->ieee80211be &&
    885 			  !hapd->conf->disable_11be,
    886 			  iface->conf->beacon_int,
    887 			  hapd->conf->dtim_period);
    888 	if (os_snprintf_error(buflen - len, ret))
    889 		return len;
    890 	len += ret;
    891 
    892 #ifdef CONFIG_IEEE80211BE
    893 	if (iface->conf->ieee80211be && !hapd->conf->disable_11be) {
    894 		ret = os_snprintf(buf + len, buflen - len,
    895 				  "eht_oper_chwidth=%d\n"
    896 				  "eht_oper_centr_freq_seg0_idx=%d\n",
    897 				  iface->conf->eht_oper_chwidth,
    898 				  iface->conf->eht_oper_centr_freq_seg0_idx);
    899 		if (os_snprintf_error(buflen - len, ret))
    900 			return len;
    901 		len += ret;
    902 
    903 		if (is_6ghz_op_class(iface->conf->op_class) &&
    904 		    hostapd_get_oper_chwidth(iface->conf) ==
    905 		    CONF_OPER_CHWIDTH_320MHZ) {
    906 			ret = os_snprintf(buf + len, buflen - len,
    907 					  "eht_bw320_offset=%d\n",
    908 					  iface->conf->eht_bw320_offset);
    909 			if (os_snprintf_error(buflen - len, ret))
    910 				return len;
    911 			len += ret;
    912 		}
    913 
    914 		if (hapd->conf->mld_ap) {
    915 			struct hostapd_data *link_bss;
    916 
    917 			ret = os_snprintf(buf + len, buflen - len,
    918 					  "num_links=%d\n",
    919 					  hapd->mld->num_links);
    920 			if (os_snprintf_error(buflen - len, ret))
    921 				return len;
    922 			len += ret;
    923 
    924 			/* Self BSS */
    925 			ret = os_snprintf(buf + len, buflen - len,
    926 					  "link_id=%d\n"
    927 					  "link_addr=" MACSTR "\n",
    928 					  hapd->mld_link_id,
    929 					  MAC2STR(hapd->own_addr));
    930 			if (os_snprintf_error(buflen - len, ret))
    931 				return len;
    932 			len += ret;
    933 
    934 			/* Partner BSSs */
    935 			for_each_mld_link(link_bss, hapd) {
    936 				if (link_bss == hapd)
    937 					continue;
    938 
    939 				ret = os_snprintf(buf + len, buflen - len,
    940 						  "partner_link[%d]=" MACSTR
    941 						  "\n",
    942 						  link_bss->mld_link_id,
    943 						  MAC2STR(link_bss->own_addr));
    944 				if (os_snprintf_error(buflen - len, ret))
    945 					return len;
    946 				len += ret;
    947 			}
    948 		}
    949 	}
    950 #endif /* CONFIG_IEEE80211BE */
    951 
    952 #ifdef CONFIG_IEEE80211AX
    953 	if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
    954 		ret = os_snprintf(buf + len, buflen - len,
    955 				  "he_oper_chwidth=%d\n"
    956 				  "he_oper_centr_freq_seg0_idx=%d\n"
    957 				  "he_oper_centr_freq_seg1_idx=%d\n",
    958 				  iface->conf->he_oper_chwidth,
    959 				  iface->conf->he_oper_centr_freq_seg0_idx,
    960 				  iface->conf->he_oper_centr_freq_seg1_idx);
    961 		if (os_snprintf_error(buflen - len, ret))
    962 			return len;
    963 		len += ret;
    964 
    965 		if (!iconf->he_op.he_bss_color_disabled &&
    966 		    iconf->he_op.he_bss_color) {
    967 			ret = os_snprintf(buf + len, buflen - len,
    968 					  "he_bss_color=%d\n",
    969 					  iconf->he_op.he_bss_color);
    970 			if (os_snprintf_error(buflen - len, ret))
    971 				return len;
    972 			len += ret;
    973 		}
    974 	}
    975 #endif /* CONFIG_IEEE80211AX */
    976 
    977 	if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
    978 		ret = os_snprintf(buf + len, buflen - len,
    979 				  "vht_oper_chwidth=%d\n"
    980 				  "vht_oper_centr_freq_seg0_idx=%d\n"
    981 				  "vht_oper_centr_freq_seg1_idx=%d\n"
    982 				  "vht_caps_info=%08x\n",
    983 				  iface->conf->vht_oper_chwidth,
    984 				  iface->conf->vht_oper_centr_freq_seg0_idx,
    985 				  iface->conf->vht_oper_centr_freq_seg1_idx,
    986 				  iface->conf->vht_capab);
    987 		if (os_snprintf_error(buflen - len, ret))
    988 			return len;
    989 		len += ret;
    990 	}
    991 
    992 	if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
    993 		u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
    994 		u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
    995 
    996 		ret = os_snprintf(buf + len, buflen - len,
    997 				  "rx_vht_mcs_map=%04x\n"
    998 				  "tx_vht_mcs_map=%04x\n",
    999 				  rxmap, txmap);
   1000 		if (os_snprintf_error(buflen - len, ret))
   1001 			return len;
   1002 		len += ret;
   1003 	}
   1004 
   1005 	if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
   1006 		ret = os_snprintf(buf + len, buflen - len,
   1007 				  "ht_caps_info=%04x\n",
   1008 				  hapd->iconf->ht_capab);
   1009 		if (os_snprintf_error(buflen - len, ret))
   1010 			return len;
   1011 		len += ret;
   1012 	}
   1013 
   1014 	if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
   1015 		len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
   1016 						   mode->mcs_set);
   1017 	}
   1018 
   1019 	if (iface->current_rates && iface->num_rates) {
   1020 		ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
   1021 		if (os_snprintf_error(buflen - len, ret))
   1022 			return len;
   1023 		len += ret;
   1024 
   1025 		for (j = 0; j < iface->num_rates; j++) {
   1026 			ret = os_snprintf(buf + len, buflen - len, "%s%02x",
   1027 					  j > 0 ? " " : "",
   1028 					  iface->current_rates[j].rate / 5);
   1029 			if (os_snprintf_error(buflen - len, ret))
   1030 				return len;
   1031 			len += ret;
   1032 		}
   1033 		ret = os_snprintf(buf + len, buflen - len, "\n");
   1034 		if (os_snprintf_error(buflen - len, ret))
   1035 			return len;
   1036 		len += ret;
   1037 	}
   1038 
   1039 	for (j = 0; mode && j < mode->num_channels; j++) {
   1040 		if (mode->channels[j].freq == iface->freq) {
   1041 			ret = os_snprintf(buf + len, buflen - len,
   1042 					  "max_txpower=%u\n",
   1043 					  mode->channels[j].max_tx_power);
   1044 			if (os_snprintf_error(buflen - len, ret))
   1045 				return len;
   1046 			len += ret;
   1047 			break;
   1048 		}
   1049 	}
   1050 
   1051 	for (i = 0; i < iface->num_bss; i++) {
   1052 		struct hostapd_data *bss = iface->bss[i];
   1053 		ret = os_snprintf(buf + len, buflen - len,
   1054 				  "bss[%d]=%s\n"
   1055 				  "bssid[%d]=" MACSTR "\n"
   1056 				  "ssid[%d]=%s\n"
   1057 				  "num_sta[%d]=%d\n",
   1058 				  (int) i, bss->conf->iface,
   1059 				  (int) i, MAC2STR(bss->own_addr),
   1060 				  (int) i,
   1061 				  wpa_ssid_txt(bss->conf->ssid.ssid,
   1062 					       bss->conf->ssid.ssid_len),
   1063 				  (int) i, bss->num_sta);
   1064 		if (os_snprintf_error(buflen - len, ret))
   1065 			return len;
   1066 		len += ret;
   1067 
   1068 #ifdef CONFIG_IEEE80211BE
   1069 		if (bss->conf->mld_ap) {
   1070 			ret = os_snprintf(buf + len, buflen - len,
   1071 					  "mld_addr[%d]=" MACSTR "\n"
   1072 					  "mld_id[%d]=%d\n"
   1073 					  "mld_link_id[%d]=%d\n",
   1074 					  (int) i, MAC2STR(bss->mld->mld_addr),
   1075 					  (int) i, hostapd_get_mld_id(bss),
   1076 					  (int) i, bss->mld_link_id);
   1077 			if (os_snprintf_error(buflen - len, ret))
   1078 				return len;
   1079 			len += ret;
   1080 		}
   1081 #endif /* CONFIG_IEEE80211BE */
   1082 	}
   1083 
   1084 	if (hapd->conf->chan_util_avg_period) {
   1085 		ret = os_snprintf(buf + len, buflen - len,
   1086 				  "chan_util_avg=%u\n",
   1087 				  iface->chan_util_average);
   1088 		if (os_snprintf_error(buflen - len, ret))
   1089 			return len;
   1090 		len += ret;
   1091 	}
   1092 
   1093 	return len;
   1094 }
   1095 
   1096 
   1097 int hostapd_parse_csa_settings(const char *pos,
   1098 			       struct csa_settings *settings)
   1099 {
   1100 	char *end;
   1101 
   1102 	os_memset(settings, 0, sizeof(*settings));
   1103 	settings->cs_count = strtol(pos, &end, 10);
   1104 	if (pos == end) {
   1105 		wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
   1106 		return -1;
   1107 	}
   1108 
   1109 	settings->freq_params.freq = atoi(end);
   1110 	if (settings->freq_params.freq == 0) {
   1111 		wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
   1112 		return -1;
   1113 	}
   1114 
   1115 #define SET_CSA_SETTING(str) \
   1116 	do { \
   1117 		const char *pos2 = os_strstr(pos, " " #str "="); \
   1118 		if (pos2) { \
   1119 			pos2 += sizeof(" " #str "=") - 1; \
   1120 			settings->freq_params.str = atoi(pos2); \
   1121 		} \
   1122 	} while (0)
   1123 
   1124 #define SET_CSA_SETTING_EXT(str) \
   1125 	do { \
   1126 		const char *pos2 = os_strstr(pos, " " #str "="); \
   1127 		if (pos2) { \
   1128 			pos2 += sizeof(" " #str "=") - 1; \
   1129 			settings->str = atoi(pos2); \
   1130 		} \
   1131 	} while (0)
   1132 
   1133 	SET_CSA_SETTING(center_freq1);
   1134 	SET_CSA_SETTING(center_freq2);
   1135 	SET_CSA_SETTING(bandwidth);
   1136 	SET_CSA_SETTING(sec_channel_offset);
   1137 	SET_CSA_SETTING_EXT(punct_bitmap);
   1138 	settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
   1139 	settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
   1140 	settings->freq_params.he_enabled = !!os_strstr(pos, " he");
   1141 	settings->freq_params.eht_enabled = !!os_strstr(pos, " eht");
   1142 	settings->block_tx = !!os_strstr(pos, " blocktx");
   1143 #undef SET_CSA_SETTING
   1144 #undef SET_CSA_SETTING_EXT
   1145 
   1146 	return 0;
   1147 }
   1148 
   1149 
   1150 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
   1151 {
   1152 	return hostapd_drv_stop_ap(hapd);
   1153 }
   1154 
   1155 
   1156 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
   1157 				  size_t len)
   1158 {
   1159 	return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
   1160 }
   1161 
   1162 
   1163 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
   1164 {
   1165 	wpa_auth_pmksa_flush(hapd->wpa_auth);
   1166 }
   1167 
   1168 
   1169 int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
   1170 {
   1171 	u8 spa[ETH_ALEN];
   1172 	u8 pmkid[PMKID_LEN];
   1173 	u8 pmk[PMK_LEN_MAX];
   1174 	size_t pmk_len;
   1175 	char *pos, *pos2;
   1176 	int akmp = 0, expiration = 0;
   1177 
   1178 	/*
   1179 	 * Entry format:
   1180 	 * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
   1181 	 */
   1182 
   1183 	if (hwaddr_aton(cmd, spa))
   1184 		return -1;
   1185 
   1186 	pos = os_strchr(cmd, ' ');
   1187 	if (!pos)
   1188 		return -1;
   1189 	pos++;
   1190 
   1191 	if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
   1192 		return -1;
   1193 
   1194 	pos = os_strchr(pos, ' ');
   1195 	if (!pos)
   1196 		return -1;
   1197 	pos++;
   1198 
   1199 	pos2 = os_strchr(pos, ' ');
   1200 	if (!pos2)
   1201 		return -1;
   1202 	pmk_len = (pos2 - pos) / 2;
   1203 	if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
   1204 	    hexstr2bin(pos, pmk, pmk_len) < 0)
   1205 		return -1;
   1206 
   1207 	pos = pos2 + 1;
   1208 
   1209 	if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
   1210 		return -1;
   1211 
   1212 	return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
   1213 				   pmkid, expiration, akmp, NULL);
   1214 }
   1215 
   1216 
   1217 #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
   1218 #ifdef CONFIG_MESH
   1219 
   1220 int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
   1221 				       const u8 *addr, char *buf, size_t len)
   1222 {
   1223 	return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
   1224 }
   1225 
   1226 
   1227 void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
   1228 {
   1229 	u8 spa[ETH_ALEN];
   1230 	u8 pmkid[PMKID_LEN];
   1231 	u8 pmk[PMK_LEN_MAX];
   1232 	char *pos;
   1233 	int expiration;
   1234 
   1235 	/*
   1236 	 * Entry format:
   1237 	 * <BSSID> <PMKID> <PMK> <expiration in seconds>
   1238 	 */
   1239 
   1240 	if (hwaddr_aton(cmd, spa))
   1241 		return NULL;
   1242 
   1243 	pos = os_strchr(cmd, ' ');
   1244 	if (!pos)
   1245 		return NULL;
   1246 	pos++;
   1247 
   1248 	if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
   1249 		return NULL;
   1250 
   1251 	pos = os_strchr(pos, ' ');
   1252 	if (!pos)
   1253 		return NULL;
   1254 	pos++;
   1255 
   1256 	if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
   1257 		return NULL;
   1258 
   1259 	pos = os_strchr(pos, ' ');
   1260 	if (!pos)
   1261 		return NULL;
   1262 	pos++;
   1263 
   1264 	if (sscanf(pos, "%d", &expiration) != 1)
   1265 		return NULL;
   1266 
   1267 	return wpa_auth_pmksa_create_entry(aa, spa, pmk, PMK_LEN,
   1268 					   WPA_KEY_MGMT_SAE, pmkid, expiration);
   1269 }
   1270 
   1271 #endif /* CONFIG_MESH */
   1272 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
   1273 
   1274 
   1275 #ifdef CONFIG_WNM_AP
   1276 
   1277 int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
   1278 					 const char *cmd)
   1279 {
   1280 	u8 addr[ETH_ALEN];
   1281 	int disassoc_timer;
   1282 	struct sta_info *sta;
   1283 
   1284 	if (hwaddr_aton(cmd, addr))
   1285 		return -1;
   1286 	if (cmd[17] != ' ')
   1287 		return -1;
   1288 	disassoc_timer = atoi(cmd + 17);
   1289 
   1290 	sta = ap_get_sta(hapd, addr);
   1291 	if (sta == NULL) {
   1292 		wpa_printf(MSG_DEBUG, "Station " MACSTR
   1293 			   " not found for disassociation imminent message",
   1294 			   MAC2STR(addr));
   1295 		return -1;
   1296 	}
   1297 
   1298 	return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
   1299 }
   1300 
   1301 
   1302 int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
   1303 				    const char *cmd)
   1304 {
   1305 	u8 addr[ETH_ALEN];
   1306 	const char *url, *timerstr;
   1307 	int disassoc_timer;
   1308 	struct sta_info *sta;
   1309 
   1310 	if (hwaddr_aton(cmd, addr))
   1311 		return -1;
   1312 
   1313 	sta = ap_get_sta(hapd, addr);
   1314 	if (sta == NULL) {
   1315 		wpa_printf(MSG_DEBUG, "Station " MACSTR
   1316 			   " not found for ESS disassociation imminent message",
   1317 			   MAC2STR(addr));
   1318 		return -1;
   1319 	}
   1320 
   1321 	timerstr = cmd + 17;
   1322 	if (*timerstr != ' ')
   1323 		return -1;
   1324 	timerstr++;
   1325 	disassoc_timer = atoi(timerstr);
   1326 	if (disassoc_timer < 0 || disassoc_timer > 65535)
   1327 		return -1;
   1328 
   1329 	url = os_strchr(timerstr, ' ');
   1330 	if (url == NULL)
   1331 		return -1;
   1332 	url++;
   1333 
   1334 	return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
   1335 }
   1336 
   1337 
   1338 int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
   1339 				  const char *cmd)
   1340 {
   1341 	u8 addr[ETH_ALEN];
   1342 	const char *pos, *end;
   1343 	int disassoc_timer = 0;
   1344 	struct sta_info *sta;
   1345 	u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
   1346 	u8 bss_term_dur[12];
   1347 	char *url = NULL;
   1348 	int ret;
   1349 	u8 nei_rep[1000];
   1350 	int nei_len;
   1351 	u8 mbo[10];
   1352 	size_t mbo_len = 0;
   1353 
   1354 	if (hwaddr_aton(cmd, addr)) {
   1355 		wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
   1356 		return -1;
   1357 	}
   1358 
   1359 	sta = ap_get_sta(hapd, addr);
   1360 	if (sta == NULL) {
   1361 		wpa_printf(MSG_DEBUG, "Station " MACSTR
   1362 			   " not found for BSS TM Request message",
   1363 			   MAC2STR(addr));
   1364 		return -1;
   1365 	}
   1366 
   1367 	pos = os_strstr(cmd, " disassoc_timer=");
   1368 	if (pos) {
   1369 		pos += 16;
   1370 		disassoc_timer = atoi(pos);
   1371 		if (disassoc_timer < 0 || disassoc_timer > 65535) {
   1372 			wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
   1373 			return -1;
   1374 		}
   1375 	}
   1376 
   1377 	pos = os_strstr(cmd, " valid_int=");
   1378 	if (pos) {
   1379 		pos += 11;
   1380 		valid_int = atoi(pos);
   1381 	}
   1382 
   1383 	pos = os_strstr(cmd, " dialog_token=");
   1384 	if (pos) {
   1385 		pos += 14;
   1386 		dialog_token = atoi(pos);
   1387 	}
   1388 
   1389 	pos = os_strstr(cmd, " bss_term=");
   1390 	if (pos) {
   1391 		pos += 10;
   1392 		req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
   1393 		/* TODO: TSF configurable/learnable */
   1394 		bss_term_dur[0] = 4; /* Subelement ID */
   1395 		bss_term_dur[1] = 10; /* Length */
   1396 		os_memset(&bss_term_dur[2], 0, 8);
   1397 		end = os_strchr(pos, ',');
   1398 		if (end == NULL) {
   1399 			wpa_printf(MSG_DEBUG, "Invalid bss_term data");
   1400 			return -1;
   1401 		}
   1402 		end++;
   1403 		WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
   1404 	}
   1405 
   1406 	nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
   1407 						  sizeof(nei_rep));
   1408 	if (nei_len < 0)
   1409 		return -1;
   1410 
   1411 	pos = os_strstr(cmd, " url=");
   1412 	if (pos) {
   1413 		size_t len;
   1414 		pos += 5;
   1415 		end = os_strchr(pos, ' ');
   1416 		if (end)
   1417 			len = end - pos;
   1418 		else
   1419 			len = os_strlen(pos);
   1420 		url = os_malloc(len + 1);
   1421 		if (url == NULL)
   1422 			return -1;
   1423 		os_memcpy(url, pos, len);
   1424 		url[len] = '\0';
   1425 		req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
   1426 	}
   1427 
   1428 	if (os_strstr(cmd, " pref=1"))
   1429 		req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
   1430 	if (os_strstr(cmd, " abridged=1"))
   1431 		req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
   1432 	if (os_strstr(cmd, " disassoc_imminent=1"))
   1433 		req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
   1434 	if (os_strstr(cmd, " link_removal_imminent=1"))
   1435 		req_mode |= WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT;
   1436 
   1437 #ifdef CONFIG_MBO
   1438 	pos = os_strstr(cmd, "mbo=");
   1439 	if (pos) {
   1440 		unsigned int mbo_reason, cell_pref, reassoc_delay;
   1441 		u8 *mbo_pos = mbo;
   1442 
   1443 		ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
   1444 			     &reassoc_delay, &cell_pref);
   1445 		if (ret != 3) {
   1446 			wpa_printf(MSG_DEBUG,
   1447 				   "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
   1448 			ret = -1;
   1449 			goto fail;
   1450 		}
   1451 
   1452 		if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
   1453 			wpa_printf(MSG_DEBUG,
   1454 				   "Invalid MBO transition reason code %u",
   1455 				   mbo_reason);
   1456 			ret = -1;
   1457 			goto fail;
   1458 		}
   1459 
   1460 		/* Valid values for Cellular preference are: 0, 1, 255 */
   1461 		if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
   1462 			wpa_printf(MSG_DEBUG,
   1463 				   "Invalid MBO cellular capability %u",
   1464 				   cell_pref);
   1465 			ret = -1;
   1466 			goto fail;
   1467 		}
   1468 
   1469 		if (reassoc_delay > 65535 ||
   1470 		    (reassoc_delay &&
   1471 		     !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
   1472 			wpa_printf(MSG_DEBUG,
   1473 				   "MBO: Assoc retry delay is only valid in disassoc imminent mode");
   1474 			ret = -1;
   1475 			goto fail;
   1476 		}
   1477 
   1478 		*mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
   1479 		*mbo_pos++ = 1;
   1480 		*mbo_pos++ = mbo_reason;
   1481 		*mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
   1482 		*mbo_pos++ = 1;
   1483 		*mbo_pos++ = cell_pref;
   1484 
   1485 		if (reassoc_delay) {
   1486 			*mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
   1487 			*mbo_pos++ = 2;
   1488 			WPA_PUT_LE16(mbo_pos, reassoc_delay);
   1489 			mbo_pos += 2;
   1490 		}
   1491 
   1492 		mbo_len = mbo_pos - mbo;
   1493 	}
   1494 #endif /* CONFIG_MBO */
   1495 
   1496 	ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
   1497 				  valid_int, bss_term_dur, dialog_token, url,
   1498 				  nei_len ? nei_rep : NULL, nei_len,
   1499 				  mbo_len ? mbo : NULL, mbo_len);
   1500 #ifdef CONFIG_MBO
   1501 fail:
   1502 #endif /* CONFIG_MBO */
   1503 	os_free(url);
   1504 	return ret;
   1505 }
   1506 
   1507 #endif /* CONFIG_WNM_AP */
   1508 
   1509 
   1510 int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
   1511 				   const char *txtaddr)
   1512 {
   1513 	u8 addr[ETH_ALEN];
   1514 	struct vlan_description vlan_id;
   1515 
   1516 	if (!(*num))
   1517 		return 0;
   1518 
   1519 	if (hwaddr_aton(txtaddr, addr))
   1520 		return -1;
   1521 
   1522 	if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
   1523 		hostapd_remove_acl_mac(acl, num, addr);
   1524 
   1525 	return 0;
   1526 }
   1527 
   1528 
   1529 void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
   1530 				       int *num)
   1531 {
   1532 	while (*num)
   1533 		hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
   1534 }
   1535 
   1536 
   1537 int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
   1538 				    char *buf, size_t buflen)
   1539 {
   1540 	int i = 0, len = 0, ret = 0;
   1541 
   1542 	if (!acl)
   1543 		return 0;
   1544 
   1545 	while (i < num) {
   1546 		ret = os_snprintf(buf + len, buflen - len,
   1547 				  MACSTR " VLAN_ID=%d\n",
   1548 				  MAC2STR(acl[i].addr),
   1549 				  acl[i].vlan_id.untagged);
   1550 		if (ret < 0 || (size_t) ret >= buflen - len)
   1551 			return len;
   1552 		i++;
   1553 		len += ret;
   1554 	}
   1555 	return len;
   1556 }
   1557 
   1558 
   1559 int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
   1560 				   const char *cmd)
   1561 {
   1562 	u8 addr[ETH_ALEN];
   1563 	struct vlan_description vlan_id;
   1564 	int ret = 0, vlanid = 0;
   1565 	const char *pos;
   1566 
   1567 	if (hwaddr_aton(cmd, addr))
   1568 		return -1;
   1569 
   1570 	pos = os_strstr(cmd, "VLAN_ID=");
   1571 	if (pos)
   1572 		vlanid = atoi(pos + 8);
   1573 
   1574 	if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
   1575 		ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
   1576 		if (ret != -1 && *acl)
   1577 			qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
   1578 	}
   1579 
   1580 	return ret < 0 ? -1 : 0;
   1581 }
   1582 
   1583 
   1584 int hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
   1585 {
   1586 	struct sta_info *sta;
   1587 	struct vlan_description vlan_id;
   1588 
   1589 	if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
   1590 		return 0;
   1591 
   1592 	for (sta = hapd->sta_list; sta; sta = sta->next) {
   1593 		if (!hostapd_maclist_found(hapd->conf->accept_mac,
   1594 					   hapd->conf->num_accept_mac,
   1595 					   sta->addr, &vlan_id) ||
   1596 		    (vlan_id.notempty &&
   1597 		     vlan_compare(&vlan_id, sta->vlan_desc)))
   1598 			ap_sta_disconnect(hapd, sta, sta->addr,
   1599 					  WLAN_REASON_UNSPECIFIED);
   1600 	}
   1601 
   1602 	return 0;
   1603 }
   1604 
   1605 
   1606 int hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
   1607 {
   1608 	struct sta_info *sta;
   1609 	struct vlan_description vlan_id;
   1610 
   1611 	for (sta = hapd->sta_list; sta; sta = sta->next) {
   1612 		if (hostapd_maclist_found(hapd->conf->deny_mac,
   1613 					  hapd->conf->num_deny_mac, sta->addr,
   1614 					  &vlan_id) &&
   1615 		    (!vlan_id.notempty ||
   1616 		     !vlan_compare(&vlan_id, sta->vlan_desc)))
   1617 			ap_sta_disconnect(hapd, sta, sta->addr,
   1618 					  WLAN_REASON_UNSPECIFIED);
   1619 	}
   1620 
   1621 	return 0;
   1622 }
   1623