139beb93cSSam Leffler /*
239beb93cSSam Leffler * hostapd / UNIX domain socket -based control interface
385732ac8SCy Schubert * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
9e28a4053SRui Paulo #include "utils/includes.h"
1039beb93cSSam Leffler
1139beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
1239beb93cSSam Leffler
135b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
14c1d255d3SCy Schubert #ifdef __NetBSD__
15c1d255d3SCy Schubert #include <net/if_ether.h>
16c1d255d3SCy Schubert #else
175b9c547cSRui Paulo #include <net/ethernet.h>
18c1d255d3SCy Schubert #endif
195b9c547cSRui Paulo #include <netinet/ip.h>
205b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
215b9c547cSRui Paulo
2239beb93cSSam Leffler #include <sys/un.h>
2339beb93cSSam Leffler #include <sys/stat.h>
243157ba21SRui Paulo #include <stddef.h>
2539beb93cSSam Leffler
26780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
27780fb4a2SCy Schubert #include <netdb.h>
28780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
29780fb4a2SCy Schubert
30e28a4053SRui Paulo #include "utils/common.h"
31e28a4053SRui Paulo #include "utils/eloop.h"
32780fb4a2SCy Schubert #include "utils/module_tests.h"
33f05cddf9SRui Paulo #include "common/version.h"
34e28a4053SRui Paulo #include "common/ieee802_11_defs.h"
35780fb4a2SCy Schubert #include "common/ctrl_iface_common.h"
3685732ac8SCy Schubert #ifdef CONFIG_DPP
3785732ac8SCy Schubert #include "common/dpp.h"
3885732ac8SCy Schubert #endif /* CONFIG_DPP */
3985732ac8SCy Schubert #include "common/wpa_ctrl.h"
40c1d255d3SCy Schubert #include "common/ptksa_cache.h"
41*a90b9d01SCy Schubert #include "common/hw_features_common.h"
42*a90b9d01SCy Schubert #include "common/nan_de.h"
435b9c547cSRui Paulo #include "crypto/tls.h"
44e28a4053SRui Paulo #include "drivers/driver.h"
45325151a3SRui Paulo #include "eapol_auth/eapol_auth_sm.h"
4639beb93cSSam Leffler #include "radius/radius_client.h"
475b9c547cSRui Paulo #include "radius/radius_server.h"
485b9c547cSRui Paulo #include "l2_packet/l2_packet.h"
49e28a4053SRui Paulo #include "ap/hostapd.h"
50e28a4053SRui Paulo #include "ap/ap_config.h"
51e28a4053SRui Paulo #include "ap/ieee802_1x.h"
52e28a4053SRui Paulo #include "ap/wpa_auth.h"
53c1d255d3SCy Schubert #include "ap/pmksa_cache_auth.h"
54e28a4053SRui Paulo #include "ap/ieee802_11.h"
55e28a4053SRui Paulo #include "ap/sta_info.h"
56e28a4053SRui Paulo #include "ap/wps_hostapd.h"
57e28a4053SRui Paulo #include "ap/ctrl_iface_ap.h"
58f05cddf9SRui Paulo #include "ap/ap_drv_ops.h"
595b9c547cSRui Paulo #include "ap/hs20.h"
605b9c547cSRui Paulo #include "ap/wnm_ap.h"
615b9c547cSRui Paulo #include "ap/wpa_auth.h"
625b9c547cSRui Paulo #include "ap/beacon.h"
63780fb4a2SCy Schubert #include "ap/neighbor_db.h"
64780fb4a2SCy Schubert #include "ap/rrm.h"
6585732ac8SCy Schubert #include "ap/dpp_hostapd.h"
66c1d255d3SCy Schubert #include "ap/dfs.h"
67*a90b9d01SCy Schubert #include "ap/nan_usd_ap.h"
68f05cddf9SRui Paulo #include "wps/wps_defs.h"
69f05cddf9SRui Paulo #include "wps/wps.h"
70325151a3SRui Paulo #include "fst/fst_ctrl_iface.h"
71f05cddf9SRui Paulo #include "config_file.h"
7239beb93cSSam Leffler #include "ctrl_iface.h"
7339beb93cSSam Leffler
7439beb93cSSam Leffler
75325151a3SRui Paulo #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
76325151a3SRui Paulo
77780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
78780fb4a2SCy Schubert #define HOSTAPD_CTRL_IFACE_PORT 8877
79780fb4a2SCy Schubert #define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
80780fb4a2SCy Schubert #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
81780fb4a2SCy Schubert #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT 50
82780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
8339beb93cSSam Leffler
8439beb93cSSam Leffler static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
85325151a3SRui Paulo enum wpa_msg_type type,
8639beb93cSSam Leffler const char *buf, size_t len);
8739beb93cSSam Leffler
8839beb93cSSam Leffler
hostapd_ctrl_iface_attach(struct hostapd_data * hapd,struct sockaddr_storage * from,socklen_t fromlen,const char * input)8939beb93cSSam Leffler static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
90780fb4a2SCy Schubert struct sockaddr_storage *from,
9185732ac8SCy Schubert socklen_t fromlen, const char *input)
9239beb93cSSam Leffler {
9385732ac8SCy Schubert return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen, input);
9439beb93cSSam Leffler }
9539beb93cSSam Leffler
9639beb93cSSam Leffler
hostapd_ctrl_iface_detach(struct hostapd_data * hapd,struct sockaddr_storage * from,socklen_t fromlen)9739beb93cSSam Leffler static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
98780fb4a2SCy Schubert struct sockaddr_storage *from,
9939beb93cSSam Leffler socklen_t fromlen)
10039beb93cSSam Leffler {
101780fb4a2SCy Schubert return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen);
10239beb93cSSam Leffler }
10339beb93cSSam Leffler
10439beb93cSSam Leffler
hostapd_ctrl_iface_level(struct hostapd_data * hapd,struct sockaddr_storage * from,socklen_t fromlen,char * level)10539beb93cSSam Leffler static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
106780fb4a2SCy Schubert struct sockaddr_storage *from,
10739beb93cSSam Leffler socklen_t fromlen,
10839beb93cSSam Leffler char *level)
10939beb93cSSam Leffler {
110780fb4a2SCy Schubert return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level);
11139beb93cSSam Leffler }
11239beb93cSSam Leffler
11339beb93cSSam Leffler
hostapd_ctrl_iface_new_sta(struct hostapd_data * hapd,const char * txtaddr)11439beb93cSSam Leffler static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
11539beb93cSSam Leffler const char *txtaddr)
11639beb93cSSam Leffler {
11739beb93cSSam Leffler u8 addr[ETH_ALEN];
11839beb93cSSam Leffler struct sta_info *sta;
11939beb93cSSam Leffler
12039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
12139beb93cSSam Leffler
12239beb93cSSam Leffler if (hwaddr_aton(txtaddr, addr))
12339beb93cSSam Leffler return -1;
12439beb93cSSam Leffler
12539beb93cSSam Leffler sta = ap_get_sta(hapd, addr);
12639beb93cSSam Leffler if (sta)
12739beb93cSSam Leffler return 0;
12839beb93cSSam Leffler
12939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
13039beb93cSSam Leffler "notification", MAC2STR(addr));
13139beb93cSSam Leffler sta = ap_sta_add(hapd, addr);
13239beb93cSSam Leffler if (sta == NULL)
13339beb93cSSam Leffler return -1;
13439beb93cSSam Leffler
13539beb93cSSam Leffler hostapd_new_assoc_sta(hapd, sta, 0);
13639beb93cSSam Leffler return 0;
13739beb93cSSam Leffler }
13839beb93cSSam Leffler
13939beb93cSSam Leffler
140e28a4053SRui Paulo #ifdef NEED_AP_MLME
hostapd_ctrl_iface_sa_query(struct hostapd_data * hapd,const char * txtaddr)14139beb93cSSam Leffler static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
14239beb93cSSam Leffler const char *txtaddr)
14339beb93cSSam Leffler {
14439beb93cSSam Leffler u8 addr[ETH_ALEN];
14539beb93cSSam Leffler u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
14639beb93cSSam Leffler
14739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
14839beb93cSSam Leffler
149e28a4053SRui Paulo if (hwaddr_aton(txtaddr, addr) ||
150e28a4053SRui Paulo os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
15139beb93cSSam Leffler return -1;
15239beb93cSSam Leffler
15339beb93cSSam Leffler ieee802_11_send_sa_query_req(hapd, addr, trans_id);
15439beb93cSSam Leffler
15539beb93cSSam Leffler return 0;
15639beb93cSSam Leffler }
157e28a4053SRui Paulo #endif /* NEED_AP_MLME */
15839beb93cSSam Leffler
15939beb93cSSam Leffler
16039beb93cSSam Leffler #ifdef CONFIG_WPS
hostapd_ctrl_iface_wps_pin(struct hostapd_data * hapd,char * txt)16139beb93cSSam Leffler static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
16239beb93cSSam Leffler {
16339beb93cSSam Leffler char *pin = os_strchr(txt, ' ');
1643157ba21SRui Paulo char *timeout_txt;
1653157ba21SRui Paulo int timeout;
166f05cddf9SRui Paulo u8 addr_buf[ETH_ALEN], *addr = NULL;
167f05cddf9SRui Paulo char *pos;
1683157ba21SRui Paulo
16939beb93cSSam Leffler if (pin == NULL)
17039beb93cSSam Leffler return -1;
17139beb93cSSam Leffler *pin++ = '\0';
1723157ba21SRui Paulo
1733157ba21SRui Paulo timeout_txt = os_strchr(pin, ' ');
1743157ba21SRui Paulo if (timeout_txt) {
1753157ba21SRui Paulo *timeout_txt++ = '\0';
1763157ba21SRui Paulo timeout = atoi(timeout_txt);
177f05cddf9SRui Paulo pos = os_strchr(timeout_txt, ' ');
178f05cddf9SRui Paulo if (pos) {
179f05cddf9SRui Paulo *pos++ = '\0';
180f05cddf9SRui Paulo if (hwaddr_aton(pos, addr_buf) == 0)
181f05cddf9SRui Paulo addr = addr_buf;
182f05cddf9SRui Paulo }
1833157ba21SRui Paulo } else
1843157ba21SRui Paulo timeout = 0;
1853157ba21SRui Paulo
186f05cddf9SRui Paulo return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
18739beb93cSSam Leffler }
188e28a4053SRui Paulo
189e28a4053SRui Paulo
hostapd_ctrl_iface_wps_check_pin(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)190f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_check_pin(
191f05cddf9SRui Paulo struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
192e28a4053SRui Paulo {
193f05cddf9SRui Paulo char pin[9];
194f05cddf9SRui Paulo size_t len;
195f05cddf9SRui Paulo char *pos;
196f05cddf9SRui Paulo int ret;
197e28a4053SRui Paulo
198f05cddf9SRui Paulo wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
199f05cddf9SRui Paulo (u8 *) cmd, os_strlen(cmd));
200f05cddf9SRui Paulo for (pos = cmd, len = 0; *pos != '\0'; pos++) {
201f05cddf9SRui Paulo if (*pos < '0' || *pos > '9')
202f05cddf9SRui Paulo continue;
203f05cddf9SRui Paulo pin[len++] = *pos;
204f05cddf9SRui Paulo if (len == 9) {
205f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
206e28a4053SRui Paulo return -1;
207e28a4053SRui Paulo }
208f05cddf9SRui Paulo }
209f05cddf9SRui Paulo if (len != 4 && len != 8) {
210f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
211f05cddf9SRui Paulo return -1;
212f05cddf9SRui Paulo }
213f05cddf9SRui Paulo pin[len] = '\0';
214f05cddf9SRui Paulo
215f05cddf9SRui Paulo if (len == 8) {
216f05cddf9SRui Paulo unsigned int pin_val;
217f05cddf9SRui Paulo pin_val = atoi(pin);
218f05cddf9SRui Paulo if (!wps_pin_valid(pin_val)) {
219f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
220f05cddf9SRui Paulo ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
2215b9c547cSRui Paulo if (os_snprintf_error(buflen, ret))
222f05cddf9SRui Paulo return -1;
223f05cddf9SRui Paulo return ret;
224f05cddf9SRui Paulo }
225f05cddf9SRui Paulo }
226f05cddf9SRui Paulo
227f05cddf9SRui Paulo ret = os_snprintf(buf, buflen, "%s", pin);
2285b9c547cSRui Paulo if (os_snprintf_error(buflen, ret))
229f05cddf9SRui Paulo return -1;
230f05cddf9SRui Paulo
231f05cddf9SRui Paulo return ret;
232f05cddf9SRui Paulo }
233f05cddf9SRui Paulo
234f05cddf9SRui Paulo
235f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data * hapd,char * pos)236f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
237f05cddf9SRui Paulo char *pos)
238f05cddf9SRui Paulo {
239f05cddf9SRui Paulo size_t len;
240f05cddf9SRui Paulo struct wpabuf *buf;
241f05cddf9SRui Paulo int ret;
242f05cddf9SRui Paulo
243f05cddf9SRui Paulo len = os_strlen(pos);
244f05cddf9SRui Paulo if (len & 0x01)
245f05cddf9SRui Paulo return -1;
246f05cddf9SRui Paulo len /= 2;
247f05cddf9SRui Paulo
248f05cddf9SRui Paulo buf = wpabuf_alloc(len);
249f05cddf9SRui Paulo if (buf == NULL)
250f05cddf9SRui Paulo return -1;
251f05cddf9SRui Paulo if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
252f05cddf9SRui Paulo wpabuf_free(buf);
253f05cddf9SRui Paulo return -1;
254f05cddf9SRui Paulo }
255f05cddf9SRui Paulo
256f05cddf9SRui Paulo ret = hostapd_wps_nfc_tag_read(hapd, buf);
257f05cddf9SRui Paulo wpabuf_free(buf);
258f05cddf9SRui Paulo
259f05cddf9SRui Paulo return ret;
260f05cddf9SRui Paulo }
261f05cddf9SRui Paulo
262f05cddf9SRui Paulo
hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data * hapd,char * cmd,char * reply,size_t max_len)263f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
264f05cddf9SRui Paulo char *cmd, char *reply,
265f05cddf9SRui Paulo size_t max_len)
266f05cddf9SRui Paulo {
267f05cddf9SRui Paulo int ndef;
268f05cddf9SRui Paulo struct wpabuf *buf;
269f05cddf9SRui Paulo int res;
270f05cddf9SRui Paulo
271f05cddf9SRui Paulo if (os_strcmp(cmd, "WPS") == 0)
272f05cddf9SRui Paulo ndef = 0;
273f05cddf9SRui Paulo else if (os_strcmp(cmd, "NDEF") == 0)
274f05cddf9SRui Paulo ndef = 1;
275f05cddf9SRui Paulo else
276f05cddf9SRui Paulo return -1;
277f05cddf9SRui Paulo
278f05cddf9SRui Paulo buf = hostapd_wps_nfc_config_token(hapd, ndef);
279f05cddf9SRui Paulo if (buf == NULL)
280f05cddf9SRui Paulo return -1;
281f05cddf9SRui Paulo
282f05cddf9SRui Paulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
283f05cddf9SRui Paulo wpabuf_len(buf));
284f05cddf9SRui Paulo reply[res++] = '\n';
285f05cddf9SRui Paulo reply[res] = '\0';
286f05cddf9SRui Paulo
287f05cddf9SRui Paulo wpabuf_free(buf);
288f05cddf9SRui Paulo
289f05cddf9SRui Paulo return res;
290f05cddf9SRui Paulo }
291f05cddf9SRui Paulo
292f05cddf9SRui Paulo
hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data * hapd,char * reply,size_t max_len,int ndef)293f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
294f05cddf9SRui Paulo char *reply, size_t max_len,
295f05cddf9SRui Paulo int ndef)
296f05cddf9SRui Paulo {
297f05cddf9SRui Paulo struct wpabuf *buf;
298f05cddf9SRui Paulo int res;
299f05cddf9SRui Paulo
300f05cddf9SRui Paulo buf = hostapd_wps_nfc_token_gen(hapd, ndef);
301f05cddf9SRui Paulo if (buf == NULL)
302f05cddf9SRui Paulo return -1;
303f05cddf9SRui Paulo
304f05cddf9SRui Paulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
305f05cddf9SRui Paulo wpabuf_len(buf));
306f05cddf9SRui Paulo reply[res++] = '\n';
307f05cddf9SRui Paulo reply[res] = '\0';
308f05cddf9SRui Paulo
309f05cddf9SRui Paulo wpabuf_free(buf);
310f05cddf9SRui Paulo
311f05cddf9SRui Paulo return res;
312f05cddf9SRui Paulo }
313f05cddf9SRui Paulo
314f05cddf9SRui Paulo
hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data * hapd,char * cmd,char * reply,size_t max_len)315f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
316f05cddf9SRui Paulo char *cmd, char *reply,
317f05cddf9SRui Paulo size_t max_len)
318f05cddf9SRui Paulo {
319f05cddf9SRui Paulo if (os_strcmp(cmd, "WPS") == 0)
320f05cddf9SRui Paulo return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
321f05cddf9SRui Paulo max_len, 0);
322f05cddf9SRui Paulo
323f05cddf9SRui Paulo if (os_strcmp(cmd, "NDEF") == 0)
324f05cddf9SRui Paulo return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
325f05cddf9SRui Paulo max_len, 1);
326f05cddf9SRui Paulo
327f05cddf9SRui Paulo if (os_strcmp(cmd, "enable") == 0)
328f05cddf9SRui Paulo return hostapd_wps_nfc_token_enable(hapd);
329f05cddf9SRui Paulo
330f05cddf9SRui Paulo if (os_strcmp(cmd, "disable") == 0) {
331f05cddf9SRui Paulo hostapd_wps_nfc_token_disable(hapd);
332f05cddf9SRui Paulo return 0;
333f05cddf9SRui Paulo }
334f05cddf9SRui Paulo
335f05cddf9SRui Paulo return -1;
336f05cddf9SRui Paulo }
3375b9c547cSRui Paulo
3385b9c547cSRui Paulo
hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data * hapd,char * cmd,char * reply,size_t max_len)3395b9c547cSRui Paulo static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
3405b9c547cSRui Paulo char *cmd, char *reply,
3415b9c547cSRui Paulo size_t max_len)
3425b9c547cSRui Paulo {
3435b9c547cSRui Paulo struct wpabuf *buf;
3445b9c547cSRui Paulo int res;
3455b9c547cSRui Paulo char *pos;
3465b9c547cSRui Paulo int ndef;
3475b9c547cSRui Paulo
3485b9c547cSRui Paulo pos = os_strchr(cmd, ' ');
3495b9c547cSRui Paulo if (pos == NULL)
3505b9c547cSRui Paulo return -1;
3515b9c547cSRui Paulo *pos++ = '\0';
3525b9c547cSRui Paulo
3535b9c547cSRui Paulo if (os_strcmp(cmd, "WPS") == 0)
3545b9c547cSRui Paulo ndef = 0;
3555b9c547cSRui Paulo else if (os_strcmp(cmd, "NDEF") == 0)
3565b9c547cSRui Paulo ndef = 1;
3575b9c547cSRui Paulo else
3585b9c547cSRui Paulo return -1;
3595b9c547cSRui Paulo
3605b9c547cSRui Paulo if (os_strcmp(pos, "WPS-CR") == 0)
3615b9c547cSRui Paulo buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
3625b9c547cSRui Paulo else
3635b9c547cSRui Paulo buf = NULL;
3645b9c547cSRui Paulo if (buf == NULL)
3655b9c547cSRui Paulo return -1;
3665b9c547cSRui Paulo
3675b9c547cSRui Paulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
3685b9c547cSRui Paulo wpabuf_len(buf));
3695b9c547cSRui Paulo reply[res++] = '\n';
3705b9c547cSRui Paulo reply[res] = '\0';
3715b9c547cSRui Paulo
3725b9c547cSRui Paulo wpabuf_free(buf);
3735b9c547cSRui Paulo
3745b9c547cSRui Paulo return res;
3755b9c547cSRui Paulo }
3765b9c547cSRui Paulo
3775b9c547cSRui Paulo
hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data * hapd,char * cmd)3785b9c547cSRui Paulo static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
3795b9c547cSRui Paulo char *cmd)
3805b9c547cSRui Paulo {
3815b9c547cSRui Paulo size_t len;
3825b9c547cSRui Paulo struct wpabuf *req, *sel;
3835b9c547cSRui Paulo int ret;
3845b9c547cSRui Paulo char *pos, *role, *type, *pos2;
3855b9c547cSRui Paulo
3865b9c547cSRui Paulo role = cmd;
3875b9c547cSRui Paulo pos = os_strchr(role, ' ');
3885b9c547cSRui Paulo if (pos == NULL)
3895b9c547cSRui Paulo return -1;
3905b9c547cSRui Paulo *pos++ = '\0';
3915b9c547cSRui Paulo
3925b9c547cSRui Paulo type = pos;
3935b9c547cSRui Paulo pos = os_strchr(type, ' ');
3945b9c547cSRui Paulo if (pos == NULL)
3955b9c547cSRui Paulo return -1;
3965b9c547cSRui Paulo *pos++ = '\0';
3975b9c547cSRui Paulo
3985b9c547cSRui Paulo pos2 = os_strchr(pos, ' ');
3995b9c547cSRui Paulo if (pos2 == NULL)
4005b9c547cSRui Paulo return -1;
4015b9c547cSRui Paulo *pos2++ = '\0';
4025b9c547cSRui Paulo
4035b9c547cSRui Paulo len = os_strlen(pos);
4045b9c547cSRui Paulo if (len & 0x01)
4055b9c547cSRui Paulo return -1;
4065b9c547cSRui Paulo len /= 2;
4075b9c547cSRui Paulo
4085b9c547cSRui Paulo req = wpabuf_alloc(len);
4095b9c547cSRui Paulo if (req == NULL)
4105b9c547cSRui Paulo return -1;
4115b9c547cSRui Paulo if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
4125b9c547cSRui Paulo wpabuf_free(req);
4135b9c547cSRui Paulo return -1;
4145b9c547cSRui Paulo }
4155b9c547cSRui Paulo
4165b9c547cSRui Paulo len = os_strlen(pos2);
4175b9c547cSRui Paulo if (len & 0x01) {
4185b9c547cSRui Paulo wpabuf_free(req);
4195b9c547cSRui Paulo return -1;
4205b9c547cSRui Paulo }
4215b9c547cSRui Paulo len /= 2;
4225b9c547cSRui Paulo
4235b9c547cSRui Paulo sel = wpabuf_alloc(len);
4245b9c547cSRui Paulo if (sel == NULL) {
4255b9c547cSRui Paulo wpabuf_free(req);
4265b9c547cSRui Paulo return -1;
4275b9c547cSRui Paulo }
4285b9c547cSRui Paulo if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
4295b9c547cSRui Paulo wpabuf_free(req);
4305b9c547cSRui Paulo wpabuf_free(sel);
4315b9c547cSRui Paulo return -1;
4325b9c547cSRui Paulo }
4335b9c547cSRui Paulo
4345b9c547cSRui Paulo if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
4355b9c547cSRui Paulo ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
4365b9c547cSRui Paulo } else {
4375b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
4385b9c547cSRui Paulo "reported: role=%s type=%s", role, type);
4395b9c547cSRui Paulo ret = -1;
4405b9c547cSRui Paulo }
4415b9c547cSRui Paulo wpabuf_free(req);
4425b9c547cSRui Paulo wpabuf_free(sel);
4435b9c547cSRui Paulo
4445b9c547cSRui Paulo return ret;
4455b9c547cSRui Paulo }
4465b9c547cSRui Paulo
447f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
448e28a4053SRui Paulo
449e28a4053SRui Paulo
hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data * hapd,char * txt,char * buf,size_t buflen)450e28a4053SRui Paulo static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
451e28a4053SRui Paulo char *buf, size_t buflen)
452e28a4053SRui Paulo {
453e28a4053SRui Paulo int timeout = 300;
454e28a4053SRui Paulo char *pos;
455e28a4053SRui Paulo const char *pin_txt;
456e28a4053SRui Paulo
457e28a4053SRui Paulo pos = os_strchr(txt, ' ');
458e28a4053SRui Paulo if (pos)
459e28a4053SRui Paulo *pos++ = '\0';
460e28a4053SRui Paulo
461e28a4053SRui Paulo if (os_strcmp(txt, "disable") == 0) {
462e28a4053SRui Paulo hostapd_wps_ap_pin_disable(hapd);
463e28a4053SRui Paulo return os_snprintf(buf, buflen, "OK\n");
464e28a4053SRui Paulo }
465e28a4053SRui Paulo
466e28a4053SRui Paulo if (os_strcmp(txt, "random") == 0) {
467e28a4053SRui Paulo if (pos)
468e28a4053SRui Paulo timeout = atoi(pos);
469e28a4053SRui Paulo pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
470e28a4053SRui Paulo if (pin_txt == NULL)
471e28a4053SRui Paulo return -1;
472e28a4053SRui Paulo return os_snprintf(buf, buflen, "%s", pin_txt);
473e28a4053SRui Paulo }
474e28a4053SRui Paulo
475e28a4053SRui Paulo if (os_strcmp(txt, "get") == 0) {
476e28a4053SRui Paulo pin_txt = hostapd_wps_ap_pin_get(hapd);
477e28a4053SRui Paulo if (pin_txt == NULL)
478e28a4053SRui Paulo return -1;
479e28a4053SRui Paulo return os_snprintf(buf, buflen, "%s", pin_txt);
480e28a4053SRui Paulo }
481e28a4053SRui Paulo
482e28a4053SRui Paulo if (os_strcmp(txt, "set") == 0) {
483e28a4053SRui Paulo char *pin;
484e28a4053SRui Paulo if (pos == NULL)
485e28a4053SRui Paulo return -1;
486e28a4053SRui Paulo pin = pos;
487e28a4053SRui Paulo pos = os_strchr(pos, ' ');
488e28a4053SRui Paulo if (pos) {
489e28a4053SRui Paulo *pos++ = '\0';
490e28a4053SRui Paulo timeout = atoi(pos);
491e28a4053SRui Paulo }
492e28a4053SRui Paulo if (os_strlen(pin) > buflen)
493e28a4053SRui Paulo return -1;
494e28a4053SRui Paulo if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
495e28a4053SRui Paulo return -1;
496e28a4053SRui Paulo return os_snprintf(buf, buflen, "%s", pin);
497e28a4053SRui Paulo }
498e28a4053SRui Paulo
499e28a4053SRui Paulo return -1;
500e28a4053SRui Paulo }
501f05cddf9SRui Paulo
502f05cddf9SRui Paulo
hostapd_ctrl_iface_wps_config(struct hostapd_data * hapd,char * txt)503f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
504f05cddf9SRui Paulo {
505f05cddf9SRui Paulo char *pos;
506f05cddf9SRui Paulo char *ssid, *auth, *encr = NULL, *key = NULL;
507f05cddf9SRui Paulo
508f05cddf9SRui Paulo ssid = txt;
509f05cddf9SRui Paulo pos = os_strchr(txt, ' ');
510f05cddf9SRui Paulo if (!pos)
511f05cddf9SRui Paulo return -1;
512f05cddf9SRui Paulo *pos++ = '\0';
513f05cddf9SRui Paulo
514f05cddf9SRui Paulo auth = pos;
515f05cddf9SRui Paulo pos = os_strchr(pos, ' ');
516f05cddf9SRui Paulo if (pos) {
517f05cddf9SRui Paulo *pos++ = '\0';
518f05cddf9SRui Paulo encr = pos;
519f05cddf9SRui Paulo pos = os_strchr(pos, ' ');
520f05cddf9SRui Paulo if (pos) {
521f05cddf9SRui Paulo *pos++ = '\0';
522f05cddf9SRui Paulo key = pos;
523f05cddf9SRui Paulo }
524f05cddf9SRui Paulo }
525f05cddf9SRui Paulo
526f05cddf9SRui Paulo return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
527f05cddf9SRui Paulo }
5285b9c547cSRui Paulo
5295b9c547cSRui Paulo
pbc_status_str(enum pbc_status status)5305b9c547cSRui Paulo static const char * pbc_status_str(enum pbc_status status)
5315b9c547cSRui Paulo {
5325b9c547cSRui Paulo switch (status) {
5335b9c547cSRui Paulo case WPS_PBC_STATUS_DISABLE:
5345b9c547cSRui Paulo return "Disabled";
5355b9c547cSRui Paulo case WPS_PBC_STATUS_ACTIVE:
5365b9c547cSRui Paulo return "Active";
5375b9c547cSRui Paulo case WPS_PBC_STATUS_TIMEOUT:
5385b9c547cSRui Paulo return "Timed-out";
5395b9c547cSRui Paulo case WPS_PBC_STATUS_OVERLAP:
5405b9c547cSRui Paulo return "Overlap";
5415b9c547cSRui Paulo default:
5425b9c547cSRui Paulo return "Unknown";
5435b9c547cSRui Paulo }
5445b9c547cSRui Paulo }
5455b9c547cSRui Paulo
5465b9c547cSRui Paulo
hostapd_ctrl_iface_wps_get_status(struct hostapd_data * hapd,char * buf,size_t buflen)5475b9c547cSRui Paulo static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
5485b9c547cSRui Paulo char *buf, size_t buflen)
5495b9c547cSRui Paulo {
5505b9c547cSRui Paulo int ret;
5515b9c547cSRui Paulo char *pos, *end;
5525b9c547cSRui Paulo
5535b9c547cSRui Paulo pos = buf;
5545b9c547cSRui Paulo end = buf + buflen;
5555b9c547cSRui Paulo
5565b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
5575b9c547cSRui Paulo pbc_status_str(hapd->wps_stats.pbc_status));
5585b9c547cSRui Paulo
5595b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
5605b9c547cSRui Paulo return pos - buf;
5615b9c547cSRui Paulo pos += ret;
5625b9c547cSRui Paulo
5635b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
5645b9c547cSRui Paulo (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
5655b9c547cSRui Paulo "Success":
5665b9c547cSRui Paulo (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
5675b9c547cSRui Paulo "Failed" : "None")));
5685b9c547cSRui Paulo
5695b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
5705b9c547cSRui Paulo return pos - buf;
5715b9c547cSRui Paulo pos += ret;
5725b9c547cSRui Paulo
5735b9c547cSRui Paulo /* If status == Failure - Add possible Reasons */
5745b9c547cSRui Paulo if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
5755b9c547cSRui Paulo hapd->wps_stats.failure_reason > 0) {
5765b9c547cSRui Paulo ret = os_snprintf(pos, end - pos,
5775b9c547cSRui Paulo "Failure Reason: %s\n",
5785b9c547cSRui Paulo wps_ei_str(hapd->wps_stats.failure_reason));
5795b9c547cSRui Paulo
5805b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
5815b9c547cSRui Paulo return pos - buf;
5825b9c547cSRui Paulo pos += ret;
5835b9c547cSRui Paulo }
5845b9c547cSRui Paulo
5855b9c547cSRui Paulo if (hapd->wps_stats.status) {
5865b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
5875b9c547cSRui Paulo MAC2STR(hapd->wps_stats.peer_addr));
5885b9c547cSRui Paulo
5895b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
5905b9c547cSRui Paulo return pos - buf;
5915b9c547cSRui Paulo pos += ret;
5925b9c547cSRui Paulo }
5935b9c547cSRui Paulo
5945b9c547cSRui Paulo return pos - buf;
5955b9c547cSRui Paulo }
5965b9c547cSRui Paulo
59739beb93cSSam Leffler #endif /* CONFIG_WPS */
59839beb93cSSam Leffler
5995b9c547cSRui Paulo #ifdef CONFIG_HS20
6005b9c547cSRui Paulo
hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data * hapd,const char * cmd)6015b9c547cSRui Paulo static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
6025b9c547cSRui Paulo const char *cmd)
6035b9c547cSRui Paulo {
6045b9c547cSRui Paulo u8 addr[ETH_ALEN];
6055b9c547cSRui Paulo const char *url;
6065b9c547cSRui Paulo
6075b9c547cSRui Paulo if (hwaddr_aton(cmd, addr))
6085b9c547cSRui Paulo return -1;
6095b9c547cSRui Paulo url = cmd + 17;
6105b9c547cSRui Paulo if (*url == '\0') {
6115b9c547cSRui Paulo url = NULL;
6125b9c547cSRui Paulo } else {
6135b9c547cSRui Paulo if (*url != ' ')
6145b9c547cSRui Paulo return -1;
6155b9c547cSRui Paulo url++;
6165b9c547cSRui Paulo if (*url == '\0')
6175b9c547cSRui Paulo url = NULL;
6185b9c547cSRui Paulo }
6195b9c547cSRui Paulo
6205b9c547cSRui Paulo return hs20_send_wnm_notification(hapd, addr, 1, url);
6215b9c547cSRui Paulo }
6225b9c547cSRui Paulo
6235b9c547cSRui Paulo
hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data * hapd,const char * cmd)6245b9c547cSRui Paulo static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
6255b9c547cSRui Paulo const char *cmd)
6265b9c547cSRui Paulo {
6275b9c547cSRui Paulo u8 addr[ETH_ALEN];
6285b9c547cSRui Paulo int code, reauth_delay, ret;
6295b9c547cSRui Paulo const char *pos;
6305b9c547cSRui Paulo size_t url_len;
6315b9c547cSRui Paulo struct wpabuf *req;
6325b9c547cSRui Paulo
6335b9c547cSRui Paulo /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
6345b9c547cSRui Paulo if (hwaddr_aton(cmd, addr))
6355b9c547cSRui Paulo return -1;
6365b9c547cSRui Paulo
6375b9c547cSRui Paulo pos = os_strchr(cmd, ' ');
6385b9c547cSRui Paulo if (pos == NULL)
6395b9c547cSRui Paulo return -1;
6405b9c547cSRui Paulo pos++;
6415b9c547cSRui Paulo code = atoi(pos);
6425b9c547cSRui Paulo
6435b9c547cSRui Paulo pos = os_strchr(pos, ' ');
6445b9c547cSRui Paulo if (pos == NULL)
6455b9c547cSRui Paulo return -1;
6465b9c547cSRui Paulo pos++;
6475b9c547cSRui Paulo reauth_delay = atoi(pos);
6485b9c547cSRui Paulo
6495b9c547cSRui Paulo url_len = 0;
6505b9c547cSRui Paulo pos = os_strchr(pos, ' ');
6515b9c547cSRui Paulo if (pos) {
6525b9c547cSRui Paulo pos++;
6535b9c547cSRui Paulo url_len = os_strlen(pos);
6545b9c547cSRui Paulo }
6555b9c547cSRui Paulo
6565b9c547cSRui Paulo req = wpabuf_alloc(4 + url_len);
6575b9c547cSRui Paulo if (req == NULL)
6585b9c547cSRui Paulo return -1;
6595b9c547cSRui Paulo wpabuf_put_u8(req, code);
6605b9c547cSRui Paulo wpabuf_put_le16(req, reauth_delay);
6615b9c547cSRui Paulo wpabuf_put_u8(req, url_len);
6625b9c547cSRui Paulo if (pos)
6635b9c547cSRui Paulo wpabuf_put_data(req, pos, url_len);
6645b9c547cSRui Paulo
6655b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
6665b9c547cSRui Paulo " to indicate imminent deauthentication (code=%d "
6675b9c547cSRui Paulo "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
6685b9c547cSRui Paulo ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
6695b9c547cSRui Paulo wpabuf_free(req);
6705b9c547cSRui Paulo return ret;
6715b9c547cSRui Paulo }
6725b9c547cSRui Paulo
6735b9c547cSRui Paulo #endif /* CONFIG_HS20 */
6745b9c547cSRui Paulo
6755b9c547cSRui Paulo
6765b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING
6775b9c547cSRui Paulo
hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data * hapd,const char * cmd)6785b9c547cSRui Paulo static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
6795b9c547cSRui Paulo const char *cmd)
6805b9c547cSRui Paulo {
6815b9c547cSRui Paulo u8 qos_map_set[16 + 2 * 21], count = 0;
6825b9c547cSRui Paulo const char *pos = cmd;
6835b9c547cSRui Paulo int val, ret;
6845b9c547cSRui Paulo
6855b9c547cSRui Paulo for (;;) {
6865b9c547cSRui Paulo if (count == sizeof(qos_map_set)) {
6875b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
6885b9c547cSRui Paulo return -1;
6895b9c547cSRui Paulo }
6905b9c547cSRui Paulo
6915b9c547cSRui Paulo val = atoi(pos);
6925b9c547cSRui Paulo if (val < 0 || val > 255) {
6935b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid QoS Map Set");
6945b9c547cSRui Paulo return -1;
6955b9c547cSRui Paulo }
6965b9c547cSRui Paulo
6975b9c547cSRui Paulo qos_map_set[count++] = val;
6985b9c547cSRui Paulo pos = os_strchr(pos, ',');
6995b9c547cSRui Paulo if (!pos)
7005b9c547cSRui Paulo break;
7015b9c547cSRui Paulo pos++;
7025b9c547cSRui Paulo }
7035b9c547cSRui Paulo
7045b9c547cSRui Paulo if (count < 16 || count & 1) {
7055b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid QoS Map Set");
7065b9c547cSRui Paulo return -1;
7075b9c547cSRui Paulo }
7085b9c547cSRui Paulo
7095b9c547cSRui Paulo ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
7105b9c547cSRui Paulo if (ret) {
7115b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
7125b9c547cSRui Paulo return -1;
7135b9c547cSRui Paulo }
7145b9c547cSRui Paulo
7155b9c547cSRui Paulo os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
7165b9c547cSRui Paulo hapd->conf->qos_map_set_len = count;
7175b9c547cSRui Paulo
7185b9c547cSRui Paulo return 0;
7195b9c547cSRui Paulo }
7205b9c547cSRui Paulo
7215b9c547cSRui Paulo
hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data * hapd,const char * cmd)7225b9c547cSRui Paulo static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
7235b9c547cSRui Paulo const char *cmd)
7245b9c547cSRui Paulo {
7255b9c547cSRui Paulo u8 addr[ETH_ALEN];
7265b9c547cSRui Paulo struct sta_info *sta;
7275b9c547cSRui Paulo struct wpabuf *buf;
7285b9c547cSRui Paulo u8 *qos_map_set = hapd->conf->qos_map_set;
7295b9c547cSRui Paulo u8 qos_map_set_len = hapd->conf->qos_map_set_len;
7305b9c547cSRui Paulo int ret;
7315b9c547cSRui Paulo
7325b9c547cSRui Paulo if (!qos_map_set_len) {
7335b9c547cSRui Paulo wpa_printf(MSG_INFO, "QoS Map Set is not set");
7345b9c547cSRui Paulo return -1;
7355b9c547cSRui Paulo }
7365b9c547cSRui Paulo
7375b9c547cSRui Paulo if (hwaddr_aton(cmd, addr))
7385b9c547cSRui Paulo return -1;
7395b9c547cSRui Paulo
7405b9c547cSRui Paulo sta = ap_get_sta(hapd, addr);
7415b9c547cSRui Paulo if (sta == NULL) {
7425b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
7435b9c547cSRui Paulo "for QoS Map Configuration message",
7445b9c547cSRui Paulo MAC2STR(addr));
7455b9c547cSRui Paulo return -1;
7465b9c547cSRui Paulo }
7475b9c547cSRui Paulo
7485b9c547cSRui Paulo if (!sta->qos_map_enabled) {
7495b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
7505b9c547cSRui Paulo "support for QoS Map", MAC2STR(addr));
7515b9c547cSRui Paulo return -1;
7525b9c547cSRui Paulo }
7535b9c547cSRui Paulo
7545b9c547cSRui Paulo buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
7555b9c547cSRui Paulo if (buf == NULL)
7565b9c547cSRui Paulo return -1;
7575b9c547cSRui Paulo
7585b9c547cSRui Paulo wpabuf_put_u8(buf, WLAN_ACTION_QOS);
7595b9c547cSRui Paulo wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
7605b9c547cSRui Paulo
7615b9c547cSRui Paulo /* QoS Map Set Element */
7625b9c547cSRui Paulo wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
7635b9c547cSRui Paulo wpabuf_put_u8(buf, qos_map_set_len);
7645b9c547cSRui Paulo wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
7655b9c547cSRui Paulo
7665b9c547cSRui Paulo ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
7675b9c547cSRui Paulo wpabuf_head(buf), wpabuf_len(buf));
7685b9c547cSRui Paulo wpabuf_free(buf);
7695b9c547cSRui Paulo
7705b9c547cSRui Paulo return ret;
7715b9c547cSRui Paulo }
7725b9c547cSRui Paulo
7735b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */
7745b9c547cSRui Paulo
77539beb93cSSam Leffler
77685732ac8SCy Schubert #ifdef CONFIG_WNM_AP
777f05cddf9SRui Paulo
hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data * hapd,const char * cmd)77885732ac8SCy Schubert static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
77985732ac8SCy Schubert const char *cmd)
78085732ac8SCy Schubert {
78185732ac8SCy Schubert u8 addr[ETH_ALEN];
78285732ac8SCy Schubert struct sta_info *sta;
78385732ac8SCy Schubert const char *pos;
78485732ac8SCy Schubert unsigned int auto_report, timeout;
78585732ac8SCy Schubert
78685732ac8SCy Schubert if (hwaddr_aton(cmd, addr)) {
78785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
78885732ac8SCy Schubert return -1;
78985732ac8SCy Schubert }
79085732ac8SCy Schubert
79185732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
79285732ac8SCy Schubert if (!sta) {
79385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Station " MACSTR
79485732ac8SCy Schubert " not found for Collocated Interference Request",
79585732ac8SCy Schubert MAC2STR(addr));
79685732ac8SCy Schubert return -1;
79785732ac8SCy Schubert }
79885732ac8SCy Schubert
79985732ac8SCy Schubert pos = cmd + 17;
80085732ac8SCy Schubert if (*pos != ' ')
80185732ac8SCy Schubert return -1;
80285732ac8SCy Schubert pos++;
80385732ac8SCy Schubert auto_report = atoi(pos);
80485732ac8SCy Schubert pos = os_strchr(pos, ' ');
80585732ac8SCy Schubert if (!pos)
80685732ac8SCy Schubert return -1;
80785732ac8SCy Schubert pos++;
80885732ac8SCy Schubert timeout = atoi(pos);
80985732ac8SCy Schubert
81085732ac8SCy Schubert return wnm_send_coloc_intf_req(hapd, sta, auto_report, timeout);
81185732ac8SCy Schubert }
81285732ac8SCy Schubert
81385732ac8SCy Schubert #endif /* CONFIG_WNM_AP */
814f05cddf9SRui Paulo
815f05cddf9SRui Paulo
hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data * hapd,char * buf,size_t buflen)816325151a3SRui Paulo static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
817f05cddf9SRui Paulo char *buf, size_t buflen)
818f05cddf9SRui Paulo {
819325151a3SRui Paulo int ret = 0;
820f05cddf9SRui Paulo char *pos, *end;
821f05cddf9SRui Paulo
822f05cddf9SRui Paulo pos = buf;
823f05cddf9SRui Paulo end = buf + buflen;
824f05cddf9SRui Paulo
825325151a3SRui Paulo WPA_ASSERT(hapd->conf->wpa_key_mgmt);
826f05cddf9SRui Paulo
827f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
828f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "WPA-PSK ");
8295b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
830f05cddf9SRui Paulo return pos - buf;
831f05cddf9SRui Paulo pos += ret;
832f05cddf9SRui Paulo }
833f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
834f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "WPA-EAP ");
8355b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
836f05cddf9SRui Paulo return pos - buf;
837f05cddf9SRui Paulo pos += ret;
838f05cddf9SRui Paulo }
83985732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
840f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
841f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "FT-PSK ");
8425b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
843f05cddf9SRui Paulo return pos - buf;
844f05cddf9SRui Paulo pos += ret;
845f05cddf9SRui Paulo }
846f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
847f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "FT-EAP ");
8485b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
849f05cddf9SRui Paulo return pos - buf;
850f05cddf9SRui Paulo pos += ret;
851f05cddf9SRui Paulo }
85285732ac8SCy Schubert #ifdef CONFIG_SHA384
85385732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
85485732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FT-EAP-SHA384 ");
85585732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
85685732ac8SCy Schubert return pos - buf;
85785732ac8SCy Schubert pos += ret;
85885732ac8SCy Schubert }
85985732ac8SCy Schubert #endif /* CONFIG_SHA384 */
8605b9c547cSRui Paulo #ifdef CONFIG_SAE
8615b9c547cSRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
8625b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "FT-SAE ");
8635b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
8645b9c547cSRui Paulo return pos - buf;
8655b9c547cSRui Paulo pos += ret;
8665b9c547cSRui Paulo }
867*a90b9d01SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
868*a90b9d01SCy Schubert ret = os_snprintf(pos, end - pos, "FT-SAE-EXT-KEY ");
869*a90b9d01SCy Schubert if (os_snprintf_error(end - pos, ret))
870*a90b9d01SCy Schubert return pos - buf;
871*a90b9d01SCy Schubert pos += ret;
872*a90b9d01SCy Schubert }
8735b9c547cSRui Paulo #endif /* CONFIG_SAE */
87485732ac8SCy Schubert #ifdef CONFIG_FILS
87585732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
87685732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FT-FILS-SHA256 ");
87785732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
87885732ac8SCy Schubert return pos - buf;
87985732ac8SCy Schubert pos += ret;
88085732ac8SCy Schubert }
88185732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
88285732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FT-FILS-SHA384 ");
88385732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
88485732ac8SCy Schubert return pos - buf;
88585732ac8SCy Schubert pos += ret;
88685732ac8SCy Schubert }
88785732ac8SCy Schubert #endif /* CONFIG_FILS */
88885732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
889f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
890f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
8915b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
892f05cddf9SRui Paulo return pos - buf;
893f05cddf9SRui Paulo pos += ret;
894f05cddf9SRui Paulo }
895f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
896f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
8975b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
898f05cddf9SRui Paulo return pos - buf;
899f05cddf9SRui Paulo pos += ret;
900f05cddf9SRui Paulo }
9015b9c547cSRui Paulo #ifdef CONFIG_SAE
9025b9c547cSRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
9035b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "SAE ");
9045b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
9055b9c547cSRui Paulo return pos - buf;
9065b9c547cSRui Paulo pos += ret;
9075b9c547cSRui Paulo }
908*a90b9d01SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
909*a90b9d01SCy Schubert ret = os_snprintf(pos, end - pos, "SAE-EXT-KEY ");
910*a90b9d01SCy Schubert if (os_snprintf_error(end - pos, ret))
911*a90b9d01SCy Schubert return pos - buf;
912*a90b9d01SCy Schubert pos += ret;
913*a90b9d01SCy Schubert }
9145b9c547cSRui Paulo #endif /* CONFIG_SAE */
9155b9c547cSRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
9165b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
9175b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
9185b9c547cSRui Paulo return pos - buf;
9195b9c547cSRui Paulo pos += ret;
9205b9c547cSRui Paulo }
9215b9c547cSRui Paulo if (hapd->conf->wpa_key_mgmt &
9225b9c547cSRui Paulo WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
9235b9c547cSRui Paulo ret = os_snprintf(pos, end - pos,
9245b9c547cSRui Paulo "WPA-EAP-SUITE-B-192 ");
9255b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
926f05cddf9SRui Paulo return pos - buf;
927f05cddf9SRui Paulo pos += ret;
928f05cddf9SRui Paulo }
92985732ac8SCy Schubert #ifdef CONFIG_FILS
93085732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
93185732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FILS-SHA256 ");
93285732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
93385732ac8SCy Schubert return pos - buf;
93485732ac8SCy Schubert pos += ret;
93585732ac8SCy Schubert }
93685732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
93785732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FILS-SHA384 ");
93885732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
93985732ac8SCy Schubert return pos - buf;
94085732ac8SCy Schubert pos += ret;
94185732ac8SCy Schubert }
94285732ac8SCy Schubert #endif /* CONFIG_FILS */
94385732ac8SCy Schubert
94485732ac8SCy Schubert #ifdef CONFIG_OWE
94585732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
94685732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "OWE ");
94785732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
94885732ac8SCy Schubert return pos - buf;
94985732ac8SCy Schubert pos += ret;
95085732ac8SCy Schubert }
95185732ac8SCy Schubert #endif /* CONFIG_OWE */
95285732ac8SCy Schubert
95385732ac8SCy Schubert #ifdef CONFIG_DPP
95485732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
95585732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "DPP ");
95685732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
95785732ac8SCy Schubert return pos - buf;
95885732ac8SCy Schubert pos += ret;
95985732ac8SCy Schubert }
96085732ac8SCy Schubert #endif /* CONFIG_DPP */
961*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
962*a90b9d01SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) {
963*a90b9d01SCy Schubert ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA384 ");
964*a90b9d01SCy Schubert if (os_snprintf_error(end - pos, ret))
965*a90b9d01SCy Schubert return pos - buf;
966*a90b9d01SCy Schubert pos += ret;
967*a90b9d01SCy Schubert }
968*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
969f05cddf9SRui Paulo
970325151a3SRui Paulo if (pos > buf && *(pos - 1) == ' ') {
971325151a3SRui Paulo *(pos - 1) = '\0';
972325151a3SRui Paulo pos--;
973325151a3SRui Paulo }
974325151a3SRui Paulo
975325151a3SRui Paulo return pos - buf;
976325151a3SRui Paulo }
977325151a3SRui Paulo
978325151a3SRui Paulo
hostapd_ctrl_iface_get_config(struct hostapd_data * hapd,char * buf,size_t buflen)979325151a3SRui Paulo static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
980325151a3SRui Paulo char *buf, size_t buflen)
981325151a3SRui Paulo {
982325151a3SRui Paulo int ret;
983325151a3SRui Paulo char *pos, *end;
984325151a3SRui Paulo
985325151a3SRui Paulo pos = buf;
986325151a3SRui Paulo end = buf + buflen;
987325151a3SRui Paulo
988325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
989325151a3SRui Paulo "ssid=%s\n",
990325151a3SRui Paulo MAC2STR(hapd->own_addr),
991325151a3SRui Paulo wpa_ssid_txt(hapd->conf->ssid.ssid,
992325151a3SRui Paulo hapd->conf->ssid.ssid_len));
993325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
994325151a3SRui Paulo return pos - buf;
995325151a3SRui Paulo pos += ret;
996325151a3SRui Paulo
997*a90b9d01SCy Schubert if ((hapd->conf->config_id)) {
998*a90b9d01SCy Schubert ret = os_snprintf(pos, end - pos, "config_id=%s\n",
999*a90b9d01SCy Schubert hapd->conf->config_id);
1000*a90b9d01SCy Schubert if (os_snprintf_error(end - pos, ret))
1001*a90b9d01SCy Schubert return pos - buf;
1002*a90b9d01SCy Schubert pos += ret;
1003*a90b9d01SCy Schubert }
1004*a90b9d01SCy Schubert
1005325151a3SRui Paulo #ifdef CONFIG_WPS
1006325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
1007325151a3SRui Paulo hapd->conf->wps_state == 0 ? "disabled" :
1008325151a3SRui Paulo (hapd->conf->wps_state == 1 ? "not configured" :
1009325151a3SRui Paulo "configured"));
1010325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1011325151a3SRui Paulo return pos - buf;
1012325151a3SRui Paulo pos += ret;
1013325151a3SRui Paulo
1014325151a3SRui Paulo if (hapd->conf->wps_state && hapd->conf->wpa &&
1015325151a3SRui Paulo hapd->conf->ssid.wpa_passphrase) {
1016325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
1017325151a3SRui Paulo hapd->conf->ssid.wpa_passphrase);
1018325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1019325151a3SRui Paulo return pos - buf;
1020325151a3SRui Paulo pos += ret;
1021325151a3SRui Paulo }
1022325151a3SRui Paulo
1023325151a3SRui Paulo if (hapd->conf->wps_state && hapd->conf->wpa &&
1024325151a3SRui Paulo hapd->conf->ssid.wpa_psk &&
1025325151a3SRui Paulo hapd->conf->ssid.wpa_psk->group) {
1026325151a3SRui Paulo char hex[PMK_LEN * 2 + 1];
1027325151a3SRui Paulo wpa_snprintf_hex(hex, sizeof(hex),
1028325151a3SRui Paulo hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
1029325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
1030325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1031325151a3SRui Paulo return pos - buf;
1032325151a3SRui Paulo pos += ret;
1033325151a3SRui Paulo }
1034c1d255d3SCy Schubert
1035c1d255d3SCy Schubert if (hapd->conf->multi_ap) {
1036c1d255d3SCy Schubert struct hostapd_ssid *ssid = &hapd->conf->multi_ap_backhaul_ssid;
1037c1d255d3SCy Schubert
1038c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos, "multi_ap=%d\n",
1039c1d255d3SCy Schubert hapd->conf->multi_ap);
1040c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1041c1d255d3SCy Schubert return pos - buf;
1042c1d255d3SCy Schubert pos += ret;
1043c1d255d3SCy Schubert
1044c1d255d3SCy Schubert if (ssid->ssid_len) {
1045c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos,
1046c1d255d3SCy Schubert "multi_ap_backhaul_ssid=%s\n",
1047c1d255d3SCy Schubert wpa_ssid_txt(ssid->ssid,
1048c1d255d3SCy Schubert ssid->ssid_len));
1049c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1050c1d255d3SCy Schubert return pos - buf;
1051c1d255d3SCy Schubert pos += ret;
1052c1d255d3SCy Schubert }
1053c1d255d3SCy Schubert
1054c1d255d3SCy Schubert if (hapd->conf->wps_state && hapd->conf->wpa &&
1055c1d255d3SCy Schubert ssid->wpa_passphrase) {
1056c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos,
1057c1d255d3SCy Schubert "multi_ap_backhaul_wpa_passphrase=%s\n",
1058c1d255d3SCy Schubert ssid->wpa_passphrase);
1059c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1060c1d255d3SCy Schubert return pos - buf;
1061c1d255d3SCy Schubert pos += ret;
1062c1d255d3SCy Schubert }
1063c1d255d3SCy Schubert
1064c1d255d3SCy Schubert if (hapd->conf->wps_state && hapd->conf->wpa &&
1065c1d255d3SCy Schubert ssid->wpa_psk &&
1066c1d255d3SCy Schubert ssid->wpa_psk->group) {
1067c1d255d3SCy Schubert char hex[PMK_LEN * 2 + 1];
1068c1d255d3SCy Schubert
1069c1d255d3SCy Schubert wpa_snprintf_hex(hex, sizeof(hex), ssid->wpa_psk->psk,
1070c1d255d3SCy Schubert PMK_LEN);
1071c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos,
1072c1d255d3SCy Schubert "multi_ap_backhaul_wpa_psk=%s\n",
1073c1d255d3SCy Schubert hex);
1074c1d255d3SCy Schubert forced_memzero(hex, sizeof(hex));
1075c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1076c1d255d3SCy Schubert return pos - buf;
1077c1d255d3SCy Schubert pos += ret;
1078c1d255d3SCy Schubert }
1079c1d255d3SCy Schubert }
1080325151a3SRui Paulo #endif /* CONFIG_WPS */
1081325151a3SRui Paulo
1082325151a3SRui Paulo if (hapd->conf->wpa) {
1083325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "wpa=%d\n", hapd->conf->wpa);
1084325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1085325151a3SRui Paulo return pos - buf;
1086325151a3SRui Paulo pos += ret;
1087325151a3SRui Paulo }
1088325151a3SRui Paulo
1089325151a3SRui Paulo if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
1090325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "key_mgmt=");
1091325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1092325151a3SRui Paulo return pos - buf;
1093325151a3SRui Paulo pos += ret;
1094325151a3SRui Paulo
1095325151a3SRui Paulo pos += hostapd_ctrl_iface_get_key_mgmt(hapd, pos, end - pos);
1096325151a3SRui Paulo
10975b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "\n");
10985b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1099f05cddf9SRui Paulo return pos - buf;
1100f05cddf9SRui Paulo pos += ret;
11015b9c547cSRui Paulo }
11025b9c547cSRui Paulo
11035b9c547cSRui Paulo if (hapd->conf->wpa) {
11045b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
11055b9c547cSRui Paulo wpa_cipher_txt(hapd->conf->wpa_group));
11065b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1107f05cddf9SRui Paulo return pos - buf;
1108f05cddf9SRui Paulo pos += ret;
1109f05cddf9SRui Paulo }
1110f05cddf9SRui Paulo
1111f05cddf9SRui Paulo if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
1112f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
11135b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1114f05cddf9SRui Paulo return pos - buf;
1115f05cddf9SRui Paulo pos += ret;
1116f05cddf9SRui Paulo
11175b9c547cSRui Paulo ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
11185b9c547cSRui Paulo " ");
11195b9c547cSRui Paulo if (ret < 0)
1120f05cddf9SRui Paulo return pos - buf;
1121f05cddf9SRui Paulo pos += ret;
1122f05cddf9SRui Paulo
1123f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "\n");
11245b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1125f05cddf9SRui Paulo return pos - buf;
1126f05cddf9SRui Paulo pos += ret;
1127f05cddf9SRui Paulo }
1128f05cddf9SRui Paulo
1129f05cddf9SRui Paulo if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
1130f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
11315b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1132f05cddf9SRui Paulo return pos - buf;
1133f05cddf9SRui Paulo pos += ret;
1134f05cddf9SRui Paulo
11355b9c547cSRui Paulo ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise,
11365b9c547cSRui Paulo " ");
11375b9c547cSRui Paulo if (ret < 0)
1138f05cddf9SRui Paulo return pos - buf;
1139f05cddf9SRui Paulo pos += ret;
1140f05cddf9SRui Paulo
1141f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "\n");
11425b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1143f05cddf9SRui Paulo return pos - buf;
1144f05cddf9SRui Paulo pos += ret;
1145f05cddf9SRui Paulo }
1146f05cddf9SRui Paulo
1147c1d255d3SCy Schubert if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
1148c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
1149c1d255d3SCy Schubert hapd->conf->wpa_deny_ptk0_rekey);
1150c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1151c1d255d3SCy Schubert return pos - buf;
1152c1d255d3SCy Schubert pos += ret;
1153c1d255d3SCy Schubert }
1154c1d255d3SCy Schubert
1155c1d255d3SCy Schubert if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
1156c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
1157c1d255d3SCy Schubert hapd->conf->extended_key_id);
1158c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1159c1d255d3SCy Schubert return pos - buf;
1160c1d255d3SCy Schubert pos += ret;
1161c1d255d3SCy Schubert }
1162c1d255d3SCy Schubert
1163f05cddf9SRui Paulo return pos - buf;
1164f05cddf9SRui Paulo }
1165f05cddf9SRui Paulo
1166f05cddf9SRui Paulo
hostapd_ctrl_iface_set_band(struct hostapd_data * hapd,const char * bands)1167c1d255d3SCy Schubert static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
1168c1d255d3SCy Schubert const char *bands)
1169c1d255d3SCy Schubert {
1170c1d255d3SCy Schubert union wpa_event_data event;
1171c1d255d3SCy Schubert u32 setband_mask = WPA_SETBAND_AUTO;
1172c1d255d3SCy Schubert
1173c1d255d3SCy Schubert /*
1174c1d255d3SCy Schubert * For example:
1175c1d255d3SCy Schubert * SET setband 2G,6G
1176c1d255d3SCy Schubert * SET setband 5G
1177c1d255d3SCy Schubert * SET setband AUTO
1178c1d255d3SCy Schubert */
1179c1d255d3SCy Schubert if (!os_strstr(bands, "AUTO")) {
1180c1d255d3SCy Schubert if (os_strstr(bands, "5G"))
1181c1d255d3SCy Schubert setband_mask |= WPA_SETBAND_5G;
1182c1d255d3SCy Schubert if (os_strstr(bands, "6G"))
1183c1d255d3SCy Schubert setband_mask |= WPA_SETBAND_6G;
1184c1d255d3SCy Schubert if (os_strstr(bands, "2G"))
1185c1d255d3SCy Schubert setband_mask |= WPA_SETBAND_2G;
1186c1d255d3SCy Schubert if (setband_mask == WPA_SETBAND_AUTO)
1187c1d255d3SCy Schubert return -1;
1188c1d255d3SCy Schubert }
1189c1d255d3SCy Schubert
1190c1d255d3SCy Schubert if (hostapd_drv_set_band(hapd, setband_mask) == 0) {
1191c1d255d3SCy Schubert os_memset(&event, 0, sizeof(event));
1192c1d255d3SCy Schubert event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
1193c1d255d3SCy Schubert event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
1194c1d255d3SCy Schubert wpa_supplicant_event(hapd, EVENT_CHANNEL_LIST_CHANGED, &event);
1195c1d255d3SCy Schubert }
1196c1d255d3SCy Schubert
1197c1d255d3SCy Schubert return 0;
1198c1d255d3SCy Schubert }
1199c1d255d3SCy Schubert
1200c1d255d3SCy Schubert
hostapd_ctrl_iface_set(struct hostapd_data * hapd,char * cmd)1201f05cddf9SRui Paulo static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
1202f05cddf9SRui Paulo {
1203f05cddf9SRui Paulo char *value;
1204f05cddf9SRui Paulo int ret = 0;
1205f05cddf9SRui Paulo
1206f05cddf9SRui Paulo value = os_strchr(cmd, ' ');
1207f05cddf9SRui Paulo if (value == NULL)
1208f05cddf9SRui Paulo return -1;
1209f05cddf9SRui Paulo *value++ = '\0';
1210f05cddf9SRui Paulo
1211f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
1212f05cddf9SRui Paulo if (0) {
1213f05cddf9SRui Paulo #ifdef CONFIG_WPS_TESTING
1214f05cddf9SRui Paulo } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
1215f05cddf9SRui Paulo long int val;
1216f05cddf9SRui Paulo val = strtol(value, NULL, 0);
1217f05cddf9SRui Paulo if (val < 0 || val > 0xff) {
1218f05cddf9SRui Paulo ret = -1;
1219f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid "
1220f05cddf9SRui Paulo "wps_version_number %ld", val);
1221f05cddf9SRui Paulo } else {
1222f05cddf9SRui Paulo wps_version_number = val;
1223f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
1224f05cddf9SRui Paulo "version %u.%u",
1225f05cddf9SRui Paulo (wps_version_number & 0xf0) >> 4,
1226f05cddf9SRui Paulo wps_version_number & 0x0f);
1227f05cddf9SRui Paulo hostapd_wps_update_ie(hapd);
1228f05cddf9SRui Paulo }
12294b72b91aSCy Schubert } else if (os_strcasecmp(cmd, "wps_testing_stub_cred") == 0) {
12304b72b91aSCy Schubert wps_testing_stub_cred = atoi(value);
12314b72b91aSCy Schubert wpa_printf(MSG_DEBUG, "WPS: Testing - stub_cred=%d",
12324b72b91aSCy Schubert wps_testing_stub_cred);
12335b9c547cSRui Paulo } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
12345b9c547cSRui Paulo wps_corrupt_pkhash = atoi(value);
12355b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
12365b9c547cSRui Paulo wps_corrupt_pkhash);
1237f05cddf9SRui Paulo #endif /* CONFIG_WPS_TESTING */
12385b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
12395b9c547cSRui Paulo } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
12405b9c547cSRui Paulo hapd->ext_mgmt_frame_handling = atoi(value);
12415b9c547cSRui Paulo } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
12425b9c547cSRui Paulo hapd->ext_eapol_frame_io = atoi(value);
1243c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "force_backlog_bytes") == 0) {
1244c1d255d3SCy Schubert hapd->force_backlog_bytes = atoi(value);
124585732ac8SCy Schubert #ifdef CONFIG_DPP
124685732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
124785732ac8SCy Schubert os_free(hapd->dpp_config_obj_override);
124885732ac8SCy Schubert hapd->dpp_config_obj_override = os_strdup(value);
124985732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
125085732ac8SCy Schubert os_free(hapd->dpp_discovery_override);
125185732ac8SCy Schubert hapd->dpp_discovery_override = os_strdup(value);
125285732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
125385732ac8SCy Schubert os_free(hapd->dpp_groups_override);
125485732ac8SCy Schubert hapd->dpp_groups_override = os_strdup(value);
125585732ac8SCy Schubert } else if (os_strcasecmp(cmd,
125685732ac8SCy Schubert "dpp_ignore_netaccesskey_mismatch") == 0) {
125785732ac8SCy Schubert hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
125885732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
125985732ac8SCy Schubert dpp_test = atoi(value);
1260c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
1261c1d255d3SCy Schubert dpp_version_override = atoi(value);
126285732ac8SCy Schubert #endif /* CONFIG_DPP */
12635b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
1264780fb4a2SCy Schubert #ifdef CONFIG_MBO
1265780fb4a2SCy Schubert } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) {
1266780fb4a2SCy Schubert int val;
1267780fb4a2SCy Schubert
1268780fb4a2SCy Schubert if (!hapd->conf->mbo_enabled)
1269780fb4a2SCy Schubert return -1;
1270780fb4a2SCy Schubert
1271780fb4a2SCy Schubert val = atoi(value);
127232a95656SCy Schubert if (val < 0 || val > MBO_ASSOC_DISALLOW_REASON_LOW_RSSI)
1273780fb4a2SCy Schubert return -1;
1274780fb4a2SCy Schubert
1275780fb4a2SCy Schubert hapd->mbo_assoc_disallow = val;
1276780fb4a2SCy Schubert ieee802_11_update_beacons(hapd->iface);
1277780fb4a2SCy Schubert
1278780fb4a2SCy Schubert /*
1279780fb4a2SCy Schubert * TODO: Need to configure drivers that do AP MLME offload with
1280780fb4a2SCy Schubert * disallowing station logic.
1281780fb4a2SCy Schubert */
1282780fb4a2SCy Schubert #endif /* CONFIG_MBO */
128385732ac8SCy Schubert #ifdef CONFIG_DPP
128485732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
128585732ac8SCy Schubert os_free(hapd->dpp_configurator_params);
128685732ac8SCy Schubert hapd->dpp_configurator_params = os_strdup(value);
1287*a90b9d01SCy Schubert #ifdef CONFIG_DPP2
1288*a90b9d01SCy Schubert dpp_controller_set_params(hapd->iface->interfaces->dpp, value);
1289*a90b9d01SCy Schubert #endif /* CONFIG_DPP2 */
1290c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
1291c1d255d3SCy Schubert hapd->dpp_init_max_tries = atoi(value);
1292c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
1293c1d255d3SCy Schubert hapd->dpp_init_retry_time = atoi(value);
1294c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
1295c1d255d3SCy Schubert hapd->dpp_resp_wait_time = atoi(value);
1296c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
1297c1d255d3SCy Schubert hapd->dpp_resp_max_tries = atoi(value);
1298c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
1299c1d255d3SCy Schubert hapd->dpp_resp_retry_time = atoi(value);
130085732ac8SCy Schubert #endif /* CONFIG_DPP */
1301c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "setband") == 0) {
1302c1d255d3SCy Schubert ret = hostapd_ctrl_iface_set_band(hapd, value);
1303f05cddf9SRui Paulo } else {
1304f05cddf9SRui Paulo ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
13055b9c547cSRui Paulo if (ret)
13065b9c547cSRui Paulo return ret;
13075b9c547cSRui Paulo
13085b9c547cSRui Paulo if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
130985732ac8SCy Schubert hostapd_disassoc_deny_mac(hapd);
131085732ac8SCy Schubert } else if (os_strcasecmp(cmd, "accept_mac_file") == 0) {
131185732ac8SCy Schubert hostapd_disassoc_accept_mac(hapd);
1312*a90b9d01SCy Schubert } else if (os_strcasecmp(cmd, "ssid") == 0) {
1313*a90b9d01SCy Schubert hostapd_neighbor_sync_own_report(hapd);
131485732ac8SCy Schubert } else if (os_strncmp(cmd, "wme_ac_", 7) == 0 ||
131585732ac8SCy Schubert os_strncmp(cmd, "wmm_ac_", 7) == 0) {
131685732ac8SCy Schubert hapd->parameter_set_count++;
131785732ac8SCy Schubert if (ieee802_11_update_beacons(hapd->iface))
131885732ac8SCy Schubert wpa_printf(MSG_DEBUG,
131985732ac8SCy Schubert "Failed to update beacons with WMM parameters");
1320c1d255d3SCy Schubert } else if (os_strcmp(cmd, "wpa_passphrase") == 0 ||
1321c1d255d3SCy Schubert os_strcmp(cmd, "sae_password") == 0 ||
1322c1d255d3SCy Schubert os_strcmp(cmd, "sae_pwe") == 0) {
1323c1d255d3SCy Schubert if (hapd->started)
1324c1d255d3SCy Schubert hostapd_setup_sae_pt(hapd->conf);
1325c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "transition_disable") == 0) {
1326c1d255d3SCy Schubert wpa_auth_set_transition_disable(hapd->wpa_auth,
1327c1d255d3SCy Schubert hapd->conf->transition_disable);
13285b9c547cSRui Paulo }
1329c1d255d3SCy Schubert
1330c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1331c1d255d3SCy Schubert if (os_strcmp(cmd, "ft_rsnxe_used") == 0)
1332c1d255d3SCy Schubert wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth,
1333c1d255d3SCy Schubert hapd->conf->ft_rsnxe_used);
1334c1d255d3SCy Schubert else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0)
1335c1d255d3SCy Schubert wpa_auth_set_ocv_override_freq(
1336c1d255d3SCy Schubert hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
1337c1d255d3SCy Schubert atoi(value));
1338c1d255d3SCy Schubert else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0)
1339c1d255d3SCy Schubert wpa_auth_set_ocv_override_freq(
1340c1d255d3SCy Schubert hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
1341c1d255d3SCy Schubert atoi(value));
1342c1d255d3SCy Schubert else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0)
1343c1d255d3SCy Schubert wpa_auth_set_ocv_override_freq(
1344c1d255d3SCy Schubert hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
1345c1d255d3SCy Schubert atoi(value));
1346c1d255d3SCy Schubert else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0)
1347c1d255d3SCy Schubert wpa_auth_set_ocv_override_freq(
1348c1d255d3SCy Schubert hapd->wpa_auth,
1349c1d255d3SCy Schubert WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value));
1350c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1351f05cddf9SRui Paulo }
1352f05cddf9SRui Paulo
1353f05cddf9SRui Paulo return ret;
1354f05cddf9SRui Paulo }
1355f05cddf9SRui Paulo
1356f05cddf9SRui Paulo
hostapd_ctrl_iface_get(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)1357f05cddf9SRui Paulo static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
1358f05cddf9SRui Paulo char *buf, size_t buflen)
1359f05cddf9SRui Paulo {
1360f05cddf9SRui Paulo int res;
1361f05cddf9SRui Paulo
1362f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
1363f05cddf9SRui Paulo
1364f05cddf9SRui Paulo if (os_strcmp(cmd, "version") == 0) {
1365f05cddf9SRui Paulo res = os_snprintf(buf, buflen, "%s", VERSION_STR);
13665b9c547cSRui Paulo if (os_snprintf_error(buflen, res))
13675b9c547cSRui Paulo return -1;
13685b9c547cSRui Paulo return res;
13695b9c547cSRui Paulo } else if (os_strcmp(cmd, "tls_library") == 0) {
13705b9c547cSRui Paulo res = tls_get_library_version(buf, buflen);
13715b9c547cSRui Paulo if (os_snprintf_error(buflen, res))
1372f05cddf9SRui Paulo return -1;
1373f05cddf9SRui Paulo return res;
1374f05cddf9SRui Paulo }
1375f05cddf9SRui Paulo
1376f05cddf9SRui Paulo return -1;
1377f05cddf9SRui Paulo }
1378f05cddf9SRui Paulo
1379f05cddf9SRui Paulo
hostapd_ctrl_iface_enable(struct hostapd_iface * iface)1380f05cddf9SRui Paulo static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
1381f05cddf9SRui Paulo {
1382f05cddf9SRui Paulo if (hostapd_enable_iface(iface) < 0) {
1383f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Enabling of interface failed");
1384f05cddf9SRui Paulo return -1;
1385f05cddf9SRui Paulo }
1386f05cddf9SRui Paulo return 0;
1387f05cddf9SRui Paulo }
1388f05cddf9SRui Paulo
1389f05cddf9SRui Paulo
hostapd_ctrl_iface_reload(struct hostapd_iface * iface)1390f05cddf9SRui Paulo static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
1391f05cddf9SRui Paulo {
1392f05cddf9SRui Paulo if (hostapd_reload_iface(iface) < 0) {
1393f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Reloading of interface failed");
1394f05cddf9SRui Paulo return -1;
1395f05cddf9SRui Paulo }
1396f05cddf9SRui Paulo return 0;
1397f05cddf9SRui Paulo }
1398f05cddf9SRui Paulo
1399f05cddf9SRui Paulo
hostapd_ctrl_iface_reload_bss(struct hostapd_data * bss)1400*a90b9d01SCy Schubert static int hostapd_ctrl_iface_reload_bss(struct hostapd_data *bss)
1401*a90b9d01SCy Schubert {
1402*a90b9d01SCy Schubert if (hostapd_reload_bss_only(bss) < 0) {
1403*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "Reloading of BSS failed");
1404*a90b9d01SCy Schubert return -1;
1405*a90b9d01SCy Schubert }
1406*a90b9d01SCy Schubert return 0;
1407*a90b9d01SCy Schubert }
1408*a90b9d01SCy Schubert
1409*a90b9d01SCy Schubert
hostapd_ctrl_iface_disable(struct hostapd_iface * iface)1410f05cddf9SRui Paulo static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
1411f05cddf9SRui Paulo {
1412f05cddf9SRui Paulo if (hostapd_disable_iface(iface) < 0) {
1413f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Disabling of interface failed");
1414f05cddf9SRui Paulo return -1;
1415f05cddf9SRui Paulo }
1416f05cddf9SRui Paulo return 0;
1417f05cddf9SRui Paulo }
1418f05cddf9SRui Paulo
1419f05cddf9SRui Paulo
14204bc52338SCy Schubert static int
hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data * hapd,struct sta_info * sta,void * ctx)14214bc52338SCy Schubert hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd,
14224bc52338SCy Schubert struct sta_info *sta, void *ctx)
14234bc52338SCy Schubert {
14244bc52338SCy Schubert struct hostapd_wpa_psk *psk;
14254bc52338SCy Schubert const u8 *pmk;
14264bc52338SCy Schubert int pmk_len;
14274bc52338SCy Schubert int pmk_match;
14284bc52338SCy Schubert int sta_match;
14294bc52338SCy Schubert int bss_match;
14304bc52338SCy Schubert int reason;
14314bc52338SCy Schubert
14324bc52338SCy Schubert pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
14334bc52338SCy Schubert
14344bc52338SCy Schubert for (psk = hapd->conf->ssid.wpa_psk; pmk && psk; psk = psk->next) {
14354bc52338SCy Schubert pmk_match = PMK_LEN == pmk_len &&
14364bc52338SCy Schubert os_memcmp(psk->psk, pmk, pmk_len) == 0;
14374bc52338SCy Schubert sta_match = psk->group == 0 &&
1438*a90b9d01SCy Schubert ether_addr_equal(sta->addr, psk->addr);
14394bc52338SCy Schubert bss_match = psk->group == 1;
14404bc52338SCy Schubert
14414bc52338SCy Schubert if (pmk_match && (sta_match || bss_match))
14424bc52338SCy Schubert return 0;
14434bc52338SCy Schubert }
14444bc52338SCy Schubert
14454bc52338SCy Schubert wpa_printf(MSG_INFO, "STA " MACSTR
14464bc52338SCy Schubert " PSK/passphrase no longer valid - disconnect",
14474bc52338SCy Schubert MAC2STR(sta->addr));
14484bc52338SCy Schubert reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
14494bc52338SCy Schubert hostapd_drv_sta_deauth(hapd, sta->addr, reason);
14504bc52338SCy Schubert ap_sta_deauthenticate(hapd, sta, reason);
14514bc52338SCy Schubert
14524bc52338SCy Schubert return 0;
14534bc52338SCy Schubert }
14544bc52338SCy Schubert
14554bc52338SCy Schubert
hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data * hapd)14564bc52338SCy Schubert static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd)
14574bc52338SCy Schubert {
14584bc52338SCy Schubert struct hostapd_bss_config *conf = hapd->conf;
14594bc52338SCy Schubert int err;
14604bc52338SCy Schubert
14614bc52338SCy Schubert hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
14624bc52338SCy Schubert
14634bc52338SCy Schubert err = hostapd_setup_wpa_psk(conf);
14644bc52338SCy Schubert if (err < 0) {
14654bc52338SCy Schubert wpa_printf(MSG_ERROR, "Reloading WPA-PSK passwords failed: %d",
14664bc52338SCy Schubert err);
14674bc52338SCy Schubert return -1;
14684bc52338SCy Schubert }
14694bc52338SCy Schubert
14704bc52338SCy Schubert ap_for_each_sta(hapd, hostapd_ctrl_iface_kick_mismatch_psk_sta_iter,
14714bc52338SCy Schubert NULL);
14724bc52338SCy Schubert
14734bc52338SCy Schubert return 0;
14744bc52338SCy Schubert }
14754bc52338SCy Schubert
14764bc52338SCy Schubert
1477*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R_AP
1478*a90b9d01SCy Schubert
hostapd_ctrl_iface_get_rxkhs(struct hostapd_data * hapd,char * buf,size_t buflen)1479*a90b9d01SCy Schubert static int hostapd_ctrl_iface_get_rxkhs(struct hostapd_data *hapd,
1480*a90b9d01SCy Schubert char *buf, size_t buflen)
1481*a90b9d01SCy Schubert {
1482*a90b9d01SCy Schubert int ret, start_pos;
1483*a90b9d01SCy Schubert char *pos, *end;
1484*a90b9d01SCy Schubert struct ft_remote_r0kh *r0kh;
1485*a90b9d01SCy Schubert struct ft_remote_r1kh *r1kh;
1486*a90b9d01SCy Schubert struct hostapd_bss_config *conf = hapd->conf;
1487*a90b9d01SCy Schubert
1488*a90b9d01SCy Schubert pos = buf;
1489*a90b9d01SCy Schubert end = buf + buflen;
1490*a90b9d01SCy Schubert
1491*a90b9d01SCy Schubert for (r0kh = conf->r0kh_list; r0kh; r0kh=r0kh->next) {
1492*a90b9d01SCy Schubert start_pos = pos - buf;
1493*a90b9d01SCy Schubert ret = os_snprintf(pos, end - pos, "r0kh=" MACSTR " ",
1494*a90b9d01SCy Schubert MAC2STR(r0kh->addr));
1495*a90b9d01SCy Schubert if (os_snprintf_error(end - pos, ret))
1496*a90b9d01SCy Schubert return start_pos;
1497*a90b9d01SCy Schubert pos += ret;
1498*a90b9d01SCy Schubert if (r0kh->id_len + 1 >= (size_t) (end - pos))
1499*a90b9d01SCy Schubert return start_pos;
1500*a90b9d01SCy Schubert os_memcpy(pos, r0kh->id, r0kh->id_len);
1501*a90b9d01SCy Schubert pos += r0kh->id_len;
1502*a90b9d01SCy Schubert *pos++ = ' ';
1503*a90b9d01SCy Schubert pos += wpa_snprintf_hex(pos, end - pos, r0kh->key,
1504*a90b9d01SCy Schubert sizeof(r0kh->key));
1505*a90b9d01SCy Schubert ret = os_snprintf(pos, end - pos, "\n");
1506*a90b9d01SCy Schubert if (os_snprintf_error(end - pos, ret))
1507*a90b9d01SCy Schubert return start_pos;
1508*a90b9d01SCy Schubert pos += ret;
1509*a90b9d01SCy Schubert }
1510*a90b9d01SCy Schubert
1511*a90b9d01SCy Schubert for (r1kh = conf->r1kh_list; r1kh; r1kh=r1kh->next) {
1512*a90b9d01SCy Schubert start_pos = pos - buf;
1513*a90b9d01SCy Schubert ret = os_snprintf(pos, end - pos, "r1kh=" MACSTR " " MACSTR " ",
1514*a90b9d01SCy Schubert MAC2STR(r1kh->addr), MAC2STR(r1kh->id));
1515*a90b9d01SCy Schubert if (os_snprintf_error(end - pos, ret))
1516*a90b9d01SCy Schubert return start_pos;
1517*a90b9d01SCy Schubert pos += ret;
1518*a90b9d01SCy Schubert pos += wpa_snprintf_hex(pos, end - pos, r1kh->key,
1519*a90b9d01SCy Schubert sizeof(r1kh->key));
1520*a90b9d01SCy Schubert ret = os_snprintf(pos, end - pos, "\n");
1521*a90b9d01SCy Schubert if (os_snprintf_error(end - pos, ret))
1522*a90b9d01SCy Schubert return start_pos;
1523*a90b9d01SCy Schubert pos += ret;
1524*a90b9d01SCy Schubert }
1525*a90b9d01SCy Schubert
1526*a90b9d01SCy Schubert return pos - buf;
1527*a90b9d01SCy Schubert }
1528*a90b9d01SCy Schubert
1529*a90b9d01SCy Schubert
hostapd_ctrl_iface_reload_rxkhs(struct hostapd_data * hapd)1530*a90b9d01SCy Schubert static int hostapd_ctrl_iface_reload_rxkhs(struct hostapd_data *hapd)
1531*a90b9d01SCy Schubert {
1532*a90b9d01SCy Schubert struct hostapd_bss_config *conf = hapd->conf;
1533*a90b9d01SCy Schubert int err;
1534*a90b9d01SCy Schubert
1535*a90b9d01SCy Schubert hostapd_config_clear_rxkhs(conf);
1536*a90b9d01SCy Schubert
1537*a90b9d01SCy Schubert err = hostapd_config_read_rxkh_file(conf, conf->rxkh_file);
1538*a90b9d01SCy Schubert if (err < 0) {
1539*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "Reloading RxKHs failed: %d",
1540*a90b9d01SCy Schubert err);
1541*a90b9d01SCy Schubert return -1;
1542*a90b9d01SCy Schubert }
1543*a90b9d01SCy Schubert
1544*a90b9d01SCy Schubert return 0;
1545*a90b9d01SCy Schubert }
1546*a90b9d01SCy Schubert
1547*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
1548*a90b9d01SCy Schubert
1549*a90b9d01SCy Schubert
15505b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
15515b9c547cSRui Paulo
hostapd_ctrl_iface_radar(struct hostapd_data * hapd,char * cmd)15525b9c547cSRui Paulo static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
15535b9c547cSRui Paulo {
15545b9c547cSRui Paulo union wpa_event_data data;
15555b9c547cSRui Paulo char *pos, *param;
15565b9c547cSRui Paulo enum wpa_event_type event;
15575b9c547cSRui Paulo
15585b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
15595b9c547cSRui Paulo
15605b9c547cSRui Paulo os_memset(&data, 0, sizeof(data));
15615b9c547cSRui Paulo
15625b9c547cSRui Paulo param = os_strchr(cmd, ' ');
15635b9c547cSRui Paulo if (param == NULL)
15645b9c547cSRui Paulo return -1;
15655b9c547cSRui Paulo *param++ = '\0';
15665b9c547cSRui Paulo
15675b9c547cSRui Paulo if (os_strcmp(cmd, "DETECTED") == 0)
15685b9c547cSRui Paulo event = EVENT_DFS_RADAR_DETECTED;
15695b9c547cSRui Paulo else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
15705b9c547cSRui Paulo event = EVENT_DFS_CAC_FINISHED;
15715b9c547cSRui Paulo else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
15725b9c547cSRui Paulo event = EVENT_DFS_CAC_ABORTED;
15735b9c547cSRui Paulo else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
15745b9c547cSRui Paulo event = EVENT_DFS_NOP_FINISHED;
15755b9c547cSRui Paulo else {
15765b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
15775b9c547cSRui Paulo cmd);
15785b9c547cSRui Paulo return -1;
15795b9c547cSRui Paulo }
15805b9c547cSRui Paulo
15815b9c547cSRui Paulo pos = os_strstr(param, "freq=");
15825b9c547cSRui Paulo if (pos)
15835b9c547cSRui Paulo data.dfs_event.freq = atoi(pos + 5);
15845b9c547cSRui Paulo
15855b9c547cSRui Paulo pos = os_strstr(param, "ht_enabled=1");
15865b9c547cSRui Paulo if (pos)
15875b9c547cSRui Paulo data.dfs_event.ht_enabled = 1;
15885b9c547cSRui Paulo
15895b9c547cSRui Paulo pos = os_strstr(param, "chan_offset=");
15905b9c547cSRui Paulo if (pos)
15915b9c547cSRui Paulo data.dfs_event.chan_offset = atoi(pos + 12);
15925b9c547cSRui Paulo
15935b9c547cSRui Paulo pos = os_strstr(param, "chan_width=");
15945b9c547cSRui Paulo if (pos)
15955b9c547cSRui Paulo data.dfs_event.chan_width = atoi(pos + 11);
15965b9c547cSRui Paulo
15975b9c547cSRui Paulo pos = os_strstr(param, "cf1=");
15985b9c547cSRui Paulo if (pos)
15995b9c547cSRui Paulo data.dfs_event.cf1 = atoi(pos + 4);
16005b9c547cSRui Paulo
16015b9c547cSRui Paulo pos = os_strstr(param, "cf2=");
16025b9c547cSRui Paulo if (pos)
16035b9c547cSRui Paulo data.dfs_event.cf2 = atoi(pos + 4);
16045b9c547cSRui Paulo
16055b9c547cSRui Paulo wpa_supplicant_event(hapd, event, &data);
16065b9c547cSRui Paulo
16075b9c547cSRui Paulo return 0;
16085b9c547cSRui Paulo }
16095b9c547cSRui Paulo
16105b9c547cSRui Paulo
hostapd_ctrl_iface_mgmt_tx(struct hostapd_data * hapd,char * cmd)16115b9c547cSRui Paulo static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
16125b9c547cSRui Paulo {
16135b9c547cSRui Paulo size_t len;
16145b9c547cSRui Paulo u8 *buf;
16155b9c547cSRui Paulo int res;
16165b9c547cSRui Paulo
16175b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
16185b9c547cSRui Paulo
16195b9c547cSRui Paulo len = os_strlen(cmd);
16205b9c547cSRui Paulo if (len & 1)
16215b9c547cSRui Paulo return -1;
16225b9c547cSRui Paulo len /= 2;
16235b9c547cSRui Paulo
16245b9c547cSRui Paulo buf = os_malloc(len);
16255b9c547cSRui Paulo if (buf == NULL)
16265b9c547cSRui Paulo return -1;
16275b9c547cSRui Paulo
16285b9c547cSRui Paulo if (hexstr2bin(cmd, buf, len) < 0) {
16295b9c547cSRui Paulo os_free(buf);
16305b9c547cSRui Paulo return -1;
16315b9c547cSRui Paulo }
16325b9c547cSRui Paulo
1633c1d255d3SCy Schubert res = hostapd_drv_send_mlme(hapd, buf, len, 0, NULL, 0, 0);
16345b9c547cSRui Paulo os_free(buf);
16355b9c547cSRui Paulo return res;
16365b9c547cSRui Paulo }
16375b9c547cSRui Paulo
16385b9c547cSRui Paulo
hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data * hapd,char * cmd)163985732ac8SCy Schubert static int hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data *hapd,
164085732ac8SCy Schubert char *cmd)
164185732ac8SCy Schubert {
164285732ac8SCy Schubert char *pos, *param;
164385732ac8SCy Schubert size_t len;
164485732ac8SCy Schubert u8 *buf;
164585732ac8SCy Schubert int stype = 0, ok = 0;
164685732ac8SCy Schubert union wpa_event_data event;
164785732ac8SCy Schubert
164885732ac8SCy Schubert if (!hapd->ext_mgmt_frame_handling)
164985732ac8SCy Schubert return -1;
165085732ac8SCy Schubert
165185732ac8SCy Schubert /* stype=<val> ok=<0/1> buf=<frame hexdump> */
165285732ac8SCy Schubert
165385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "External MGMT TX status process: %s", cmd);
165485732ac8SCy Schubert
165585732ac8SCy Schubert pos = cmd;
165685732ac8SCy Schubert param = os_strstr(pos, "stype=");
165785732ac8SCy Schubert if (param) {
165885732ac8SCy Schubert param += 6;
165985732ac8SCy Schubert stype = atoi(param);
166085732ac8SCy Schubert }
166185732ac8SCy Schubert
166285732ac8SCy Schubert param = os_strstr(pos, " ok=");
166385732ac8SCy Schubert if (param) {
166485732ac8SCy Schubert param += 4;
166585732ac8SCy Schubert ok = atoi(param);
166685732ac8SCy Schubert }
166785732ac8SCy Schubert
166885732ac8SCy Schubert param = os_strstr(pos, " buf=");
166985732ac8SCy Schubert if (!param)
167085732ac8SCy Schubert return -1;
167185732ac8SCy Schubert param += 5;
167285732ac8SCy Schubert
167385732ac8SCy Schubert len = os_strlen(param);
167485732ac8SCy Schubert if (len & 1)
167585732ac8SCy Schubert return -1;
167685732ac8SCy Schubert len /= 2;
167785732ac8SCy Schubert
167885732ac8SCy Schubert buf = os_malloc(len);
167985732ac8SCy Schubert if (!buf || hexstr2bin(param, buf, len) < 0) {
168085732ac8SCy Schubert os_free(buf);
168185732ac8SCy Schubert return -1;
168285732ac8SCy Schubert }
168385732ac8SCy Schubert
168485732ac8SCy Schubert os_memset(&event, 0, sizeof(event));
168585732ac8SCy Schubert event.tx_status.type = WLAN_FC_TYPE_MGMT;
168685732ac8SCy Schubert event.tx_status.data = buf;
168785732ac8SCy Schubert event.tx_status.data_len = len;
168885732ac8SCy Schubert event.tx_status.stype = stype;
168985732ac8SCy Schubert event.tx_status.ack = ok;
169085732ac8SCy Schubert hapd->ext_mgmt_frame_handling = 0;
169185732ac8SCy Schubert wpa_supplicant_event(hapd, EVENT_TX_STATUS, &event);
169285732ac8SCy Schubert hapd->ext_mgmt_frame_handling = 1;
169385732ac8SCy Schubert
169485732ac8SCy Schubert os_free(buf);
169585732ac8SCy Schubert
169685732ac8SCy Schubert return 0;
169785732ac8SCy Schubert }
169885732ac8SCy Schubert
169985732ac8SCy Schubert
hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data * hapd,char * cmd)170085732ac8SCy Schubert static int hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data *hapd,
170185732ac8SCy Schubert char *cmd)
170285732ac8SCy Schubert {
170385732ac8SCy Schubert char *pos, *param;
170485732ac8SCy Schubert size_t len;
170585732ac8SCy Schubert u8 *buf;
170685732ac8SCy Schubert int freq = 0, datarate = 0, ssi_signal = 0;
170785732ac8SCy Schubert union wpa_event_data event;
170885732ac8SCy Schubert
170985732ac8SCy Schubert if (!hapd->ext_mgmt_frame_handling)
171085732ac8SCy Schubert return -1;
171185732ac8SCy Schubert
171285732ac8SCy Schubert /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
171385732ac8SCy Schubert
171485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
171585732ac8SCy Schubert
171685732ac8SCy Schubert pos = cmd;
171785732ac8SCy Schubert param = os_strstr(pos, "freq=");
171885732ac8SCy Schubert if (param) {
171985732ac8SCy Schubert param += 5;
172085732ac8SCy Schubert freq = atoi(param);
172185732ac8SCy Schubert }
172285732ac8SCy Schubert
172385732ac8SCy Schubert param = os_strstr(pos, " datarate=");
172485732ac8SCy Schubert if (param) {
172585732ac8SCy Schubert param += 10;
172685732ac8SCy Schubert datarate = atoi(param);
172785732ac8SCy Schubert }
172885732ac8SCy Schubert
172985732ac8SCy Schubert param = os_strstr(pos, " ssi_signal=");
173085732ac8SCy Schubert if (param) {
173185732ac8SCy Schubert param += 12;
173285732ac8SCy Schubert ssi_signal = atoi(param);
173385732ac8SCy Schubert }
173485732ac8SCy Schubert
173585732ac8SCy Schubert param = os_strstr(pos, " frame=");
173685732ac8SCy Schubert if (param == NULL)
173785732ac8SCy Schubert return -1;
173885732ac8SCy Schubert param += 7;
173985732ac8SCy Schubert
174085732ac8SCy Schubert len = os_strlen(param);
174185732ac8SCy Schubert if (len & 1)
174285732ac8SCy Schubert return -1;
174385732ac8SCy Schubert len /= 2;
174485732ac8SCy Schubert
174585732ac8SCy Schubert buf = os_malloc(len);
174685732ac8SCy Schubert if (buf == NULL)
174785732ac8SCy Schubert return -1;
174885732ac8SCy Schubert
174985732ac8SCy Schubert if (hexstr2bin(param, buf, len) < 0) {
175085732ac8SCy Schubert os_free(buf);
175185732ac8SCy Schubert return -1;
175285732ac8SCy Schubert }
175385732ac8SCy Schubert
175485732ac8SCy Schubert os_memset(&event, 0, sizeof(event));
175585732ac8SCy Schubert event.rx_mgmt.freq = freq;
175685732ac8SCy Schubert event.rx_mgmt.frame = buf;
175785732ac8SCy Schubert event.rx_mgmt.frame_len = len;
175885732ac8SCy Schubert event.rx_mgmt.ssi_signal = ssi_signal;
175985732ac8SCy Schubert event.rx_mgmt.datarate = datarate;
176085732ac8SCy Schubert hapd->ext_mgmt_frame_handling = 0;
176185732ac8SCy Schubert wpa_supplicant_event(hapd, EVENT_RX_MGMT, &event);
176285732ac8SCy Schubert hapd->ext_mgmt_frame_handling = 1;
176385732ac8SCy Schubert
176485732ac8SCy Schubert os_free(buf);
176585732ac8SCy Schubert
176685732ac8SCy Schubert return 0;
176785732ac8SCy Schubert }
176885732ac8SCy Schubert
176985732ac8SCy Schubert
hostapd_ctrl_iface_eapol_rx(struct hostapd_data * hapd,char * cmd)17705b9c547cSRui Paulo static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
17715b9c547cSRui Paulo {
17725b9c547cSRui Paulo char *pos;
17735b9c547cSRui Paulo u8 src[ETH_ALEN], *buf;
17745b9c547cSRui Paulo int used;
17755b9c547cSRui Paulo size_t len;
17765b9c547cSRui Paulo
17775b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
17785b9c547cSRui Paulo
17795b9c547cSRui Paulo pos = cmd;
17805b9c547cSRui Paulo used = hwaddr_aton2(pos, src);
17815b9c547cSRui Paulo if (used < 0)
17825b9c547cSRui Paulo return -1;
17835b9c547cSRui Paulo pos += used;
17845b9c547cSRui Paulo while (*pos == ' ')
17855b9c547cSRui Paulo pos++;
17865b9c547cSRui Paulo
17875b9c547cSRui Paulo len = os_strlen(pos);
17885b9c547cSRui Paulo if (len & 1)
17895b9c547cSRui Paulo return -1;
17905b9c547cSRui Paulo len /= 2;
17915b9c547cSRui Paulo
17925b9c547cSRui Paulo buf = os_malloc(len);
17935b9c547cSRui Paulo if (buf == NULL)
17945b9c547cSRui Paulo return -1;
17955b9c547cSRui Paulo
17965b9c547cSRui Paulo if (hexstr2bin(pos, buf, len) < 0) {
17975b9c547cSRui Paulo os_free(buf);
17985b9c547cSRui Paulo return -1;
17995b9c547cSRui Paulo }
18005b9c547cSRui Paulo
1801*a90b9d01SCy Schubert ieee802_1x_receive(hapd, src, buf, len, FRAME_ENCRYPTION_UNKNOWN);
18025b9c547cSRui Paulo os_free(buf);
18035b9c547cSRui Paulo
18045b9c547cSRui Paulo return 0;
18055b9c547cSRui Paulo }
18065b9c547cSRui Paulo
18075b9c547cSRui Paulo
hostapd_ctrl_iface_eapol_tx(struct hostapd_data * hapd,char * cmd)1808c1d255d3SCy Schubert static int hostapd_ctrl_iface_eapol_tx(struct hostapd_data *hapd, char *cmd)
1809c1d255d3SCy Schubert {
1810c1d255d3SCy Schubert char *pos, *pos2;
1811c1d255d3SCy Schubert u8 dst[ETH_ALEN], *buf;
1812c1d255d3SCy Schubert int used, ret;
1813c1d255d3SCy Schubert size_t len;
1814c1d255d3SCy Schubert unsigned int prev;
1815c1d255d3SCy Schubert int encrypt = 0;
1816c1d255d3SCy Schubert
1817c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "External EAPOL TX: %s", cmd);
1818c1d255d3SCy Schubert
1819c1d255d3SCy Schubert pos = cmd;
1820c1d255d3SCy Schubert used = hwaddr_aton2(pos, dst);
1821c1d255d3SCy Schubert if (used < 0)
1822c1d255d3SCy Schubert return -1;
1823c1d255d3SCy Schubert pos += used;
1824c1d255d3SCy Schubert while (*pos == ' ')
1825c1d255d3SCy Schubert pos++;
1826c1d255d3SCy Schubert
1827c1d255d3SCy Schubert pos2 = os_strchr(pos, ' ');
1828c1d255d3SCy Schubert if (pos2) {
1829c1d255d3SCy Schubert len = pos2 - pos;
1830c1d255d3SCy Schubert encrypt = os_strstr(pos2, "encrypt=1") != NULL;
1831c1d255d3SCy Schubert } else {
1832c1d255d3SCy Schubert len = os_strlen(pos);
1833c1d255d3SCy Schubert }
1834c1d255d3SCy Schubert if (len & 1)
1835c1d255d3SCy Schubert return -1;
1836c1d255d3SCy Schubert len /= 2;
1837c1d255d3SCy Schubert
1838c1d255d3SCy Schubert buf = os_malloc(len);
1839c1d255d3SCy Schubert if (!buf || hexstr2bin(pos, buf, len) < 0) {
1840c1d255d3SCy Schubert os_free(buf);
1841c1d255d3SCy Schubert return -1;
1842c1d255d3SCy Schubert }
1843c1d255d3SCy Schubert
1844c1d255d3SCy Schubert prev = hapd->ext_eapol_frame_io;
1845c1d255d3SCy Schubert hapd->ext_eapol_frame_io = 0;
1846c1d255d3SCy Schubert ret = hostapd_wpa_auth_send_eapol(hapd, dst, buf, len, encrypt);
1847c1d255d3SCy Schubert hapd->ext_eapol_frame_io = prev;
1848c1d255d3SCy Schubert os_free(buf);
1849c1d255d3SCy Schubert
1850c1d255d3SCy Schubert return ret;
1851c1d255d3SCy Schubert }
1852c1d255d3SCy Schubert
1853c1d255d3SCy Schubert
ipv4_hdr_checksum(const void * buf,size_t len)18545b9c547cSRui Paulo static u16 ipv4_hdr_checksum(const void *buf, size_t len)
18555b9c547cSRui Paulo {
18565b9c547cSRui Paulo size_t i;
18575b9c547cSRui Paulo u32 sum = 0;
18585b9c547cSRui Paulo const u16 *pos = buf;
18595b9c547cSRui Paulo
18605b9c547cSRui Paulo for (i = 0; i < len / 2; i++)
18615b9c547cSRui Paulo sum += *pos++;
18625b9c547cSRui Paulo
18635b9c547cSRui Paulo while (sum >> 16)
18645b9c547cSRui Paulo sum = (sum & 0xffff) + (sum >> 16);
18655b9c547cSRui Paulo
18665b9c547cSRui Paulo return sum ^ 0xffff;
18675b9c547cSRui Paulo }
18685b9c547cSRui Paulo
18695b9c547cSRui Paulo
18705b9c547cSRui Paulo #define HWSIM_PACKETLEN 1500
18715b9c547cSRui Paulo #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
18725b9c547cSRui Paulo
hostapd_data_test_rx(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)1873780fb4a2SCy Schubert static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
18745b9c547cSRui Paulo size_t len)
18755b9c547cSRui Paulo {
18765b9c547cSRui Paulo struct hostapd_data *hapd = ctx;
18775b9c547cSRui Paulo const struct ether_header *eth;
1878c1d255d3SCy Schubert struct ip ip;
18795b9c547cSRui Paulo const u8 *pos;
18805b9c547cSRui Paulo unsigned int i;
1881206b73d0SCy Schubert char extra[30];
18825b9c547cSRui Paulo
1883206b73d0SCy Schubert if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
1884206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1885206b73d0SCy Schubert "test data: RX - ignore unexpected length %d",
1886206b73d0SCy Schubert (int) len);
18875b9c547cSRui Paulo return;
1888206b73d0SCy Schubert }
18895b9c547cSRui Paulo
18905b9c547cSRui Paulo eth = (const struct ether_header *) buf;
1891325151a3SRui Paulo os_memcpy(&ip, eth + 1, sizeof(ip));
1892325151a3SRui Paulo pos = &buf[sizeof(*eth) + sizeof(ip)];
18935b9c547cSRui Paulo
1894c1d255d3SCy Schubert if (ip.ip_hl != 5 || ip.ip_v != 4 ||
1895c1d255d3SCy Schubert ntohs(ip.ip_len) > HWSIM_IP_LEN) {
1896206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1897c1d255d3SCy Schubert "test data: RX - ignore unexpected IP header");
18985b9c547cSRui Paulo return;
1899206b73d0SCy Schubert }
19005b9c547cSRui Paulo
1901c1d255d3SCy Schubert for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
1902206b73d0SCy Schubert if (*pos != (u8) i) {
1903206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
1904206b73d0SCy Schubert "test data: RX - ignore mismatching payload");
19055b9c547cSRui Paulo return;
1906206b73d0SCy Schubert }
19075b9c547cSRui Paulo pos++;
19085b9c547cSRui Paulo }
19095b9c547cSRui Paulo
1910206b73d0SCy Schubert extra[0] = '\0';
1911c1d255d3SCy Schubert if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
1912c1d255d3SCy Schubert os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
1913206b73d0SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
1914206b73d0SCy Schubert MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
19155b9c547cSRui Paulo }
19165b9c547cSRui Paulo
19175b9c547cSRui Paulo
hostapd_ctrl_iface_data_test_config(struct hostapd_data * hapd,char * cmd)19185b9c547cSRui Paulo static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
19195b9c547cSRui Paulo char *cmd)
19205b9c547cSRui Paulo {
19215b9c547cSRui Paulo int enabled = atoi(cmd);
19225b9c547cSRui Paulo char *pos;
19235b9c547cSRui Paulo const char *ifname;
1924*a90b9d01SCy Schubert const u8 *addr = hapd->own_addr;
19255b9c547cSRui Paulo
19265b9c547cSRui Paulo if (!enabled) {
19275b9c547cSRui Paulo if (hapd->l2_test) {
19285b9c547cSRui Paulo l2_packet_deinit(hapd->l2_test);
19295b9c547cSRui Paulo hapd->l2_test = NULL;
19305b9c547cSRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
19315b9c547cSRui Paulo "test data: Disabled");
19325b9c547cSRui Paulo }
19335b9c547cSRui Paulo return 0;
19345b9c547cSRui Paulo }
19355b9c547cSRui Paulo
19365b9c547cSRui Paulo if (hapd->l2_test)
19375b9c547cSRui Paulo return 0;
19385b9c547cSRui Paulo
19395b9c547cSRui Paulo pos = os_strstr(cmd, " ifname=");
19405b9c547cSRui Paulo if (pos)
19415b9c547cSRui Paulo ifname = pos + 8;
19425b9c547cSRui Paulo else
19435b9c547cSRui Paulo ifname = hapd->conf->iface;
19445b9c547cSRui Paulo
1945*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
1946*a90b9d01SCy Schubert if (hapd->conf->mld_ap)
1947*a90b9d01SCy Schubert addr = hapd->mld->mld_addr;
1948*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
1949*a90b9d01SCy Schubert hapd->l2_test = l2_packet_init(ifname, addr,
19505b9c547cSRui Paulo ETHERTYPE_IP, hostapd_data_test_rx,
19515b9c547cSRui Paulo hapd, 1);
19525b9c547cSRui Paulo if (hapd->l2_test == NULL)
19535b9c547cSRui Paulo return -1;
19545b9c547cSRui Paulo
19555b9c547cSRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
19565b9c547cSRui Paulo
19575b9c547cSRui Paulo return 0;
19585b9c547cSRui Paulo }
19595b9c547cSRui Paulo
19605b9c547cSRui Paulo
hostapd_ctrl_iface_data_test_tx(struct hostapd_data * hapd,char * cmd)19615b9c547cSRui Paulo static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
19625b9c547cSRui Paulo {
19635b9c547cSRui Paulo u8 dst[ETH_ALEN], src[ETH_ALEN];
1964206b73d0SCy Schubert char *pos, *pos2;
19655b9c547cSRui Paulo int used;
19665b9c547cSRui Paulo long int val;
19675b9c547cSRui Paulo u8 tos;
1968325151a3SRui Paulo u8 buf[2 + HWSIM_PACKETLEN];
19695b9c547cSRui Paulo struct ether_header *eth;
1970c1d255d3SCy Schubert struct ip *ip;
19715b9c547cSRui Paulo u8 *dpos;
19725b9c547cSRui Paulo unsigned int i;
1973206b73d0SCy Schubert size_t send_len = HWSIM_IP_LEN;
19745b9c547cSRui Paulo
19755b9c547cSRui Paulo if (hapd->l2_test == NULL)
19765b9c547cSRui Paulo return -1;
19775b9c547cSRui Paulo
1978206b73d0SCy Schubert /* format: <dst> <src> <tos> [len=<length>] */
19795b9c547cSRui Paulo
19805b9c547cSRui Paulo pos = cmd;
19815b9c547cSRui Paulo used = hwaddr_aton2(pos, dst);
19825b9c547cSRui Paulo if (used < 0)
19835b9c547cSRui Paulo return -1;
19845b9c547cSRui Paulo pos += used;
19855b9c547cSRui Paulo while (*pos == ' ')
19865b9c547cSRui Paulo pos++;
19875b9c547cSRui Paulo used = hwaddr_aton2(pos, src);
19885b9c547cSRui Paulo if (used < 0)
19895b9c547cSRui Paulo return -1;
19905b9c547cSRui Paulo pos += used;
19915b9c547cSRui Paulo
1992206b73d0SCy Schubert val = strtol(pos, &pos2, 0);
19935b9c547cSRui Paulo if (val < 0 || val > 0xff)
19945b9c547cSRui Paulo return -1;
19955b9c547cSRui Paulo tos = val;
19965b9c547cSRui Paulo
1997206b73d0SCy Schubert pos = os_strstr(pos2, " len=");
1998206b73d0SCy Schubert if (pos) {
1999206b73d0SCy Schubert i = atoi(pos + 5);
2000206b73d0SCy Schubert if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
2001206b73d0SCy Schubert return -1;
2002206b73d0SCy Schubert send_len = i;
2003206b73d0SCy Schubert }
2004206b73d0SCy Schubert
2005325151a3SRui Paulo eth = (struct ether_header *) &buf[2];
20065b9c547cSRui Paulo os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
20075b9c547cSRui Paulo os_memcpy(eth->ether_shost, src, ETH_ALEN);
20085b9c547cSRui Paulo eth->ether_type = htons(ETHERTYPE_IP);
2009c1d255d3SCy Schubert ip = (struct ip *) (eth + 1);
20105b9c547cSRui Paulo os_memset(ip, 0, sizeof(*ip));
2011c1d255d3SCy Schubert ip->ip_hl = 5;
2012c1d255d3SCy Schubert ip->ip_v = 4;
2013c1d255d3SCy Schubert ip->ip_ttl = 64;
2014c1d255d3SCy Schubert ip->ip_tos = tos;
2015c1d255d3SCy Schubert ip->ip_len = htons(send_len);
2016c1d255d3SCy Schubert ip->ip_p = 1;
2017c1d255d3SCy Schubert ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
2018c1d255d3SCy Schubert ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
2019c1d255d3SCy Schubert ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
20205b9c547cSRui Paulo dpos = (u8 *) (ip + 1);
2021206b73d0SCy Schubert for (i = 0; i < send_len - sizeof(*ip); i++)
20225b9c547cSRui Paulo *dpos++ = i;
20235b9c547cSRui Paulo
2024325151a3SRui Paulo if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
2025206b73d0SCy Schubert sizeof(struct ether_header) + send_len) < 0)
20265b9c547cSRui Paulo return -1;
20275b9c547cSRui Paulo
20285b9c547cSRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
20295b9c547cSRui Paulo " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
20305b9c547cSRui Paulo
20315b9c547cSRui Paulo return 0;
20325b9c547cSRui Paulo }
20335b9c547cSRui Paulo
20345b9c547cSRui Paulo
hostapd_ctrl_iface_data_test_frame(struct hostapd_data * hapd,char * cmd)20355b9c547cSRui Paulo static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
20365b9c547cSRui Paulo char *cmd)
20375b9c547cSRui Paulo {
20385b9c547cSRui Paulo u8 *buf;
20395b9c547cSRui Paulo struct ether_header *eth;
20405b9c547cSRui Paulo struct l2_packet_data *l2 = NULL;
20415b9c547cSRui Paulo size_t len;
20425b9c547cSRui Paulo u16 ethertype;
20435b9c547cSRui Paulo int res = -1;
20445b9c547cSRui Paulo const char *ifname = hapd->conf->iface;
20455b9c547cSRui Paulo
20465b9c547cSRui Paulo if (os_strncmp(cmd, "ifname=", 7) == 0) {
20475b9c547cSRui Paulo cmd += 7;
20485b9c547cSRui Paulo ifname = cmd;
20495b9c547cSRui Paulo cmd = os_strchr(cmd, ' ');
20505b9c547cSRui Paulo if (cmd == NULL)
20515b9c547cSRui Paulo return -1;
20525b9c547cSRui Paulo *cmd++ = '\0';
20535b9c547cSRui Paulo }
20545b9c547cSRui Paulo
20555b9c547cSRui Paulo len = os_strlen(cmd);
20565b9c547cSRui Paulo if (len & 1 || len < ETH_HLEN * 2)
20575b9c547cSRui Paulo return -1;
20585b9c547cSRui Paulo len /= 2;
20595b9c547cSRui Paulo
20605b9c547cSRui Paulo buf = os_malloc(len);
20615b9c547cSRui Paulo if (buf == NULL)
20625b9c547cSRui Paulo return -1;
20635b9c547cSRui Paulo
20645b9c547cSRui Paulo if (hexstr2bin(cmd, buf, len) < 0)
20655b9c547cSRui Paulo goto done;
20665b9c547cSRui Paulo
20675b9c547cSRui Paulo eth = (struct ether_header *) buf;
20685b9c547cSRui Paulo ethertype = ntohs(eth->ether_type);
20695b9c547cSRui Paulo
20705b9c547cSRui Paulo l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
20715b9c547cSRui Paulo hostapd_data_test_rx, hapd, 1);
20725b9c547cSRui Paulo if (l2 == NULL)
20735b9c547cSRui Paulo goto done;
20745b9c547cSRui Paulo
20755b9c547cSRui Paulo res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
20765b9c547cSRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
20775b9c547cSRui Paulo done:
20785b9c547cSRui Paulo if (l2)
20795b9c547cSRui Paulo l2_packet_deinit(l2);
20805b9c547cSRui Paulo os_free(buf);
20815b9c547cSRui Paulo
20825b9c547cSRui Paulo return res < 0 ? -1 : 0;
20835b9c547cSRui Paulo }
20845b9c547cSRui Paulo
20855b9c547cSRui Paulo
hostapd_ctrl_reset_pn(struct hostapd_data * hapd,const char * cmd)208685732ac8SCy Schubert static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
208785732ac8SCy Schubert {
208885732ac8SCy Schubert struct sta_info *sta;
208985732ac8SCy Schubert u8 addr[ETH_ALEN];
209085732ac8SCy Schubert u8 zero[WPA_TK_MAX_LEN];
209185732ac8SCy Schubert
209285732ac8SCy Schubert os_memset(zero, 0, sizeof(zero));
209385732ac8SCy Schubert
209485732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
209585732ac8SCy Schubert return -1;
209685732ac8SCy Schubert
2097c1d255d3SCy Schubert if (is_broadcast_ether_addr(addr) && os_strstr(cmd, " BIGTK")) {
2098c1d255d3SCy Schubert if (hapd->last_bigtk_alg == WPA_ALG_NONE)
2099c1d255d3SCy Schubert return -1;
2100c1d255d3SCy Schubert
2101c1d255d3SCy Schubert wpa_printf(MSG_INFO, "TESTING: Reset BIPN for BIGTK");
2102c1d255d3SCy Schubert
2103c1d255d3SCy Schubert /* First, use a zero key to avoid any possible duplicate key
2104c1d255d3SCy Schubert * avoidance in the driver. */
2105c1d255d3SCy Schubert if (hostapd_drv_set_key(hapd->conf->iface, hapd,
2106c1d255d3SCy Schubert hapd->last_bigtk_alg,
2107c1d255d3SCy Schubert broadcast_ether_addr,
2108c1d255d3SCy Schubert hapd->last_bigtk_key_idx, 0, 1, NULL, 0,
2109c1d255d3SCy Schubert zero, hapd->last_bigtk_len,
2110c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT) < 0)
2111c1d255d3SCy Schubert return -1;
2112c1d255d3SCy Schubert
2113c1d255d3SCy Schubert /* Set the previously configured key to reset its TSC */
2114c1d255d3SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd,
2115c1d255d3SCy Schubert hapd->last_bigtk_alg,
2116c1d255d3SCy Schubert broadcast_ether_addr,
2117c1d255d3SCy Schubert hapd->last_bigtk_key_idx, 0, 1, NULL,
2118c1d255d3SCy Schubert 0, hapd->last_bigtk,
2119c1d255d3SCy Schubert hapd->last_bigtk_len,
2120c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT);
2121c1d255d3SCy Schubert }
2122c1d255d3SCy Schubert
212385732ac8SCy Schubert if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
212485732ac8SCy Schubert if (hapd->last_igtk_alg == WPA_ALG_NONE)
212585732ac8SCy Schubert return -1;
212685732ac8SCy Schubert
212785732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Reset IPN for IGTK");
212885732ac8SCy Schubert
212985732ac8SCy Schubert /* First, use a zero key to avoid any possible duplicate key
213085732ac8SCy Schubert * avoidance in the driver. */
213185732ac8SCy Schubert if (hostapd_drv_set_key(hapd->conf->iface, hapd,
213285732ac8SCy Schubert hapd->last_igtk_alg,
213385732ac8SCy Schubert broadcast_ether_addr,
2134c1d255d3SCy Schubert hapd->last_igtk_key_idx, 0, 1, NULL, 0,
2135c1d255d3SCy Schubert zero, hapd->last_igtk_len,
2136c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT) < 0)
213785732ac8SCy Schubert return -1;
213885732ac8SCy Schubert
213985732ac8SCy Schubert /* Set the previously configured key to reset its TSC */
214085732ac8SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd,
214185732ac8SCy Schubert hapd->last_igtk_alg,
214285732ac8SCy Schubert broadcast_ether_addr,
2143c1d255d3SCy Schubert hapd->last_igtk_key_idx, 0, 1, NULL,
2144c1d255d3SCy Schubert 0, hapd->last_igtk,
2145c1d255d3SCy Schubert hapd->last_igtk_len,
2146c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT);
214785732ac8SCy Schubert }
214885732ac8SCy Schubert
214985732ac8SCy Schubert if (is_broadcast_ether_addr(addr)) {
215085732ac8SCy Schubert if (hapd->last_gtk_alg == WPA_ALG_NONE)
215185732ac8SCy Schubert return -1;
215285732ac8SCy Schubert
215385732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Reset PN for GTK");
215485732ac8SCy Schubert
215585732ac8SCy Schubert /* First, use a zero key to avoid any possible duplicate key
215685732ac8SCy Schubert * avoidance in the driver. */
215785732ac8SCy Schubert if (hostapd_drv_set_key(hapd->conf->iface, hapd,
215885732ac8SCy Schubert hapd->last_gtk_alg,
215985732ac8SCy Schubert broadcast_ether_addr,
2160c1d255d3SCy Schubert hapd->last_gtk_key_idx, 0, 1, NULL, 0,
2161c1d255d3SCy Schubert zero, hapd->last_gtk_len,
2162c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT) < 0)
216385732ac8SCy Schubert return -1;
216485732ac8SCy Schubert
216585732ac8SCy Schubert /* Set the previously configured key to reset its TSC */
216685732ac8SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd,
216785732ac8SCy Schubert hapd->last_gtk_alg,
216885732ac8SCy Schubert broadcast_ether_addr,
2169c1d255d3SCy Schubert hapd->last_gtk_key_idx, 0, 1, NULL,
2170c1d255d3SCy Schubert 0, hapd->last_gtk,
2171c1d255d3SCy Schubert hapd->last_gtk_len,
2172c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT);
217385732ac8SCy Schubert }
217485732ac8SCy Schubert
217585732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
217685732ac8SCy Schubert if (!sta)
217785732ac8SCy Schubert return -1;
217885732ac8SCy Schubert
217985732ac8SCy Schubert if (sta->last_tk_alg == WPA_ALG_NONE)
218085732ac8SCy Schubert return -1;
218185732ac8SCy Schubert
218285732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Reset PN for " MACSTR,
218385732ac8SCy Schubert MAC2STR(sta->addr));
218485732ac8SCy Schubert
218585732ac8SCy Schubert /* First, use a zero key to avoid any possible duplicate key avoidance
218685732ac8SCy Schubert * in the driver. */
218785732ac8SCy Schubert if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
2188c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
2189c1d255d3SCy Schubert zero, sta->last_tk_len,
2190c1d255d3SCy Schubert KEY_FLAG_PAIRWISE_RX_TX) < 0)
219185732ac8SCy Schubert return -1;
219285732ac8SCy Schubert
219385732ac8SCy Schubert /* Set the previously configured key to reset its TSC/RSC */
219485732ac8SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
2195c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 1, NULL,
2196c1d255d3SCy Schubert 0, sta->last_tk, sta->last_tk_len,
2197c1d255d3SCy Schubert KEY_FLAG_PAIRWISE_RX_TX);
219885732ac8SCy Schubert }
219985732ac8SCy Schubert
220085732ac8SCy Schubert
hostapd_ctrl_set_key(struct hostapd_data * hapd,const char * cmd)220185732ac8SCy Schubert static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
220285732ac8SCy Schubert {
220385732ac8SCy Schubert u8 addr[ETH_ALEN];
220485732ac8SCy Schubert const char *pos = cmd;
220585732ac8SCy Schubert enum wpa_alg alg;
2206c1d255d3SCy Schubert enum key_flag key_flag;
220785732ac8SCy Schubert int idx, set_tx;
220885732ac8SCy Schubert u8 seq[6], key[WPA_TK_MAX_LEN];
220985732ac8SCy Schubert size_t key_len;
221085732ac8SCy Schubert
2211c1d255d3SCy Schubert /* parameters: alg addr idx set_tx seq key key_flag */
221285732ac8SCy Schubert
221385732ac8SCy Schubert alg = atoi(pos);
221485732ac8SCy Schubert pos = os_strchr(pos, ' ');
221585732ac8SCy Schubert if (!pos)
221685732ac8SCy Schubert return -1;
221785732ac8SCy Schubert pos++;
221885732ac8SCy Schubert if (hwaddr_aton(pos, addr))
221985732ac8SCy Schubert return -1;
222085732ac8SCy Schubert pos += 17;
222185732ac8SCy Schubert if (*pos != ' ')
222285732ac8SCy Schubert return -1;
222385732ac8SCy Schubert pos++;
222485732ac8SCy Schubert idx = atoi(pos);
222585732ac8SCy Schubert pos = os_strchr(pos, ' ');
222685732ac8SCy Schubert if (!pos)
222785732ac8SCy Schubert return -1;
222885732ac8SCy Schubert pos++;
222985732ac8SCy Schubert set_tx = atoi(pos);
223085732ac8SCy Schubert pos = os_strchr(pos, ' ');
223185732ac8SCy Schubert if (!pos)
223285732ac8SCy Schubert return -1;
223385732ac8SCy Schubert pos++;
223485732ac8SCy Schubert if (hexstr2bin(pos, seq, sizeof(seq)) < 0)
223585732ac8SCy Schubert return -1;
223685732ac8SCy Schubert pos += 2 * 6;
223785732ac8SCy Schubert if (*pos != ' ')
223885732ac8SCy Schubert return -1;
223985732ac8SCy Schubert pos++;
2240c1d255d3SCy Schubert if (!os_strchr(pos, ' '))
2241c1d255d3SCy Schubert return -1;
2242c1d255d3SCy Schubert key_len = (os_strchr(pos, ' ') - pos) / 2;
224385732ac8SCy Schubert if (hexstr2bin(pos, key, key_len) < 0)
224485732ac8SCy Schubert return -1;
2245c1d255d3SCy Schubert pos += 2 * key_len;
2246c1d255d3SCy Schubert if (*pos != ' ')
2247c1d255d3SCy Schubert return -1;
2248c1d255d3SCy Schubert
2249c1d255d3SCy Schubert pos++;
2250c1d255d3SCy Schubert key_flag = atoi(pos);
2251c1d255d3SCy Schubert pos = os_strchr(pos, ' ');
2252c1d255d3SCy Schubert if (pos)
2253c1d255d3SCy Schubert return -1;
225485732ac8SCy Schubert
225585732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Set key");
2256c1d255d3SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx, 0,
2257c1d255d3SCy Schubert set_tx, seq, 6, key, key_len, key_flag);
225885732ac8SCy Schubert }
225985732ac8SCy Schubert
226085732ac8SCy Schubert
restore_tk(void * ctx1,void * ctx2)226185732ac8SCy Schubert static void restore_tk(void *ctx1, void *ctx2)
226285732ac8SCy Schubert {
226385732ac8SCy Schubert struct hostapd_data *hapd = ctx1;
226485732ac8SCy Schubert struct sta_info *sta = ctx2;
226585732ac8SCy Schubert
226685732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Restore TK for " MACSTR,
226785732ac8SCy Schubert MAC2STR(sta->addr));
226885732ac8SCy Schubert /* This does not really restore the TSC properly, so this will result
226985732ac8SCy Schubert * in replay protection issues for now since there is no clean way of
227085732ac8SCy Schubert * preventing encryption of a single EAPOL frame. */
227185732ac8SCy Schubert hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
2272c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
2273c1d255d3SCy Schubert sta->last_tk, sta->last_tk_len,
2274c1d255d3SCy Schubert KEY_FLAG_PAIRWISE_RX_TX);
227585732ac8SCy Schubert }
227685732ac8SCy Schubert
227785732ac8SCy Schubert
hostapd_ctrl_resend_m1(struct hostapd_data * hapd,const char * cmd)227885732ac8SCy Schubert static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
227985732ac8SCy Schubert {
228085732ac8SCy Schubert struct sta_info *sta;
228185732ac8SCy Schubert u8 addr[ETH_ALEN];
228285732ac8SCy Schubert int plain = os_strstr(cmd, "plaintext") != NULL;
228385732ac8SCy Schubert
228485732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
228585732ac8SCy Schubert return -1;
228685732ac8SCy Schubert
228785732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
228885732ac8SCy Schubert if (!sta || !sta->wpa_sm)
228985732ac8SCy Schubert return -1;
229085732ac8SCy Schubert
229185732ac8SCy Schubert if (plain && sta->last_tk_alg == WPA_ALG_NONE)
229285732ac8SCy Schubert plain = 0; /* no need for special processing */
229385732ac8SCy Schubert if (plain) {
229485732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
229585732ac8SCy Schubert MAC2STR(sta->addr));
229685732ac8SCy Schubert hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
2297c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
2298c1d255d3SCy Schubert 0, NULL, 0, KEY_FLAG_PAIRWISE);
229985732ac8SCy Schubert }
230085732ac8SCy Schubert
230185732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
230285732ac8SCy Schubert return wpa_auth_resend_m1(sta->wpa_sm,
230385732ac8SCy Schubert os_strstr(cmd, "change-anonce") != NULL,
230485732ac8SCy Schubert plain ? restore_tk : NULL, hapd, sta);
230585732ac8SCy Schubert }
230685732ac8SCy Schubert
230785732ac8SCy Schubert
hostapd_ctrl_resend_m3(struct hostapd_data * hapd,const char * cmd)230885732ac8SCy Schubert static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
230985732ac8SCy Schubert {
231085732ac8SCy Schubert struct sta_info *sta;
231185732ac8SCy Schubert u8 addr[ETH_ALEN];
231285732ac8SCy Schubert int plain = os_strstr(cmd, "plaintext") != NULL;
231385732ac8SCy Schubert
231485732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
231585732ac8SCy Schubert return -1;
231685732ac8SCy Schubert
231785732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
231885732ac8SCy Schubert if (!sta || !sta->wpa_sm)
231985732ac8SCy Schubert return -1;
232085732ac8SCy Schubert
232185732ac8SCy Schubert if (plain && sta->last_tk_alg == WPA_ALG_NONE)
232285732ac8SCy Schubert plain = 0; /* no need for special processing */
232385732ac8SCy Schubert if (plain) {
232485732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
232585732ac8SCy Schubert MAC2STR(sta->addr));
232685732ac8SCy Schubert hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
2327c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
2328c1d255d3SCy Schubert 0, NULL, 0, KEY_FLAG_PAIRWISE);
232985732ac8SCy Schubert }
233085732ac8SCy Schubert
233185732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
233285732ac8SCy Schubert return wpa_auth_resend_m3(sta->wpa_sm,
233385732ac8SCy Schubert plain ? restore_tk : NULL, hapd, sta);
233485732ac8SCy Schubert }
233585732ac8SCy Schubert
233685732ac8SCy Schubert
hostapd_ctrl_resend_group_m1(struct hostapd_data * hapd,const char * cmd)233785732ac8SCy Schubert static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
233885732ac8SCy Schubert const char *cmd)
233985732ac8SCy Schubert {
234085732ac8SCy Schubert struct sta_info *sta;
234185732ac8SCy Schubert u8 addr[ETH_ALEN];
234285732ac8SCy Schubert int plain = os_strstr(cmd, "plaintext") != NULL;
234385732ac8SCy Schubert
234485732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
234585732ac8SCy Schubert return -1;
234685732ac8SCy Schubert
234785732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
234885732ac8SCy Schubert if (!sta || !sta->wpa_sm)
234985732ac8SCy Schubert return -1;
235085732ac8SCy Schubert
235185732ac8SCy Schubert if (plain && sta->last_tk_alg == WPA_ALG_NONE)
235285732ac8SCy Schubert plain = 0; /* no need for special processing */
235385732ac8SCy Schubert if (plain) {
235485732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
235585732ac8SCy Schubert MAC2STR(sta->addr));
235685732ac8SCy Schubert hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
2357c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
2358c1d255d3SCy Schubert 0, NULL, 0, KEY_FLAG_PAIRWISE);
235985732ac8SCy Schubert }
236085732ac8SCy Schubert
236185732ac8SCy Schubert wpa_printf(MSG_INFO,
236285732ac8SCy Schubert "TESTING: Send group M1 for the same GTK and zero RSC to "
236385732ac8SCy Schubert MACSTR, MAC2STR(sta->addr));
236485732ac8SCy Schubert return wpa_auth_resend_group_m1(sta->wpa_sm,
236585732ac8SCy Schubert plain ? restore_tk : NULL, hapd, sta);
236685732ac8SCy Schubert }
236785732ac8SCy Schubert
2368c1d255d3SCy Schubert
hostapd_ctrl_rekey_ptk(struct hostapd_data * hapd,const char * cmd)2369c1d255d3SCy Schubert static int hostapd_ctrl_rekey_ptk(struct hostapd_data *hapd, const char *cmd)
2370c1d255d3SCy Schubert {
2371c1d255d3SCy Schubert struct sta_info *sta;
2372c1d255d3SCy Schubert u8 addr[ETH_ALEN];
2373c1d255d3SCy Schubert
2374c1d255d3SCy Schubert if (hwaddr_aton(cmd, addr))
2375c1d255d3SCy Schubert return -1;
2376c1d255d3SCy Schubert
2377c1d255d3SCy Schubert sta = ap_get_sta(hapd, addr);
2378c1d255d3SCy Schubert if (!sta || !sta->wpa_sm)
2379c1d255d3SCy Schubert return -1;
2380c1d255d3SCy Schubert
2381c1d255d3SCy Schubert return wpa_auth_rekey_ptk(hapd->wpa_auth, sta->wpa_sm);
2382c1d255d3SCy Schubert }
2383c1d255d3SCy Schubert
2384c1d255d3SCy Schubert
hostapd_ctrl_get_pmksa_pmk(struct hostapd_data * hapd,const u8 * addr,char * buf,size_t buflen)2385c1d255d3SCy Schubert static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr,
2386c1d255d3SCy Schubert char *buf, size_t buflen)
2387c1d255d3SCy Schubert {
2388c1d255d3SCy Schubert struct rsn_pmksa_cache_entry *pmksa;
2389c1d255d3SCy Schubert
2390c1d255d3SCy Schubert pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, addr, NULL);
2391c1d255d3SCy Schubert if (!pmksa)
2392c1d255d3SCy Schubert return -1;
2393c1d255d3SCy Schubert
2394c1d255d3SCy Schubert return wpa_snprintf_hex(buf, buflen, pmksa->pmk, pmksa->pmk_len);
2395c1d255d3SCy Schubert }
2396c1d255d3SCy Schubert
2397c1d255d3SCy Schubert
hostapd_ctrl_get_pmk(struct hostapd_data * hapd,const char * cmd,char * buf,size_t buflen)2398c1d255d3SCy Schubert static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
2399c1d255d3SCy Schubert char *buf, size_t buflen)
2400c1d255d3SCy Schubert {
2401c1d255d3SCy Schubert struct sta_info *sta;
2402c1d255d3SCy Schubert u8 addr[ETH_ALEN];
2403c1d255d3SCy Schubert const u8 *pmk;
2404c1d255d3SCy Schubert int pmk_len;
2405c1d255d3SCy Schubert
2406c1d255d3SCy Schubert if (hwaddr_aton(cmd, addr))
2407c1d255d3SCy Schubert return -1;
2408c1d255d3SCy Schubert
2409c1d255d3SCy Schubert sta = ap_get_sta(hapd, addr);
2410c1d255d3SCy Schubert if (!sta || !sta->wpa_sm) {
2411c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
2412c1d255d3SCy Schubert MAC2STR(addr));
2413c1d255d3SCy Schubert return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
2414c1d255d3SCy Schubert }
2415c1d255d3SCy Schubert pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
2416c1d255d3SCy Schubert if (!pmk || !pmk_len) {
2417c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
2418c1d255d3SCy Schubert MAC2STR(addr));
2419c1d255d3SCy Schubert return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
2420c1d255d3SCy Schubert }
2421c1d255d3SCy Schubert
2422c1d255d3SCy Schubert return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
2423c1d255d3SCy Schubert }
2424c1d255d3SCy Schubert
2425c1d255d3SCy Schubert
hostapd_ctrl_register_frame(struct hostapd_data * hapd,const char * cmd)2426c1d255d3SCy Schubert static int hostapd_ctrl_register_frame(struct hostapd_data *hapd,
2427c1d255d3SCy Schubert const char *cmd)
2428c1d255d3SCy Schubert {
2429c1d255d3SCy Schubert u16 type;
2430c1d255d3SCy Schubert char *pos, *end;
2431c1d255d3SCy Schubert u8 match[10];
2432c1d255d3SCy Schubert size_t match_len;
2433c1d255d3SCy Schubert bool multicast = false;
2434c1d255d3SCy Schubert
2435c1d255d3SCy Schubert type = strtol(cmd, &pos, 16);
2436c1d255d3SCy Schubert if (*pos != ' ')
2437c1d255d3SCy Schubert return -1;
2438c1d255d3SCy Schubert pos++;
2439c1d255d3SCy Schubert end = os_strchr(pos, ' ');
2440c1d255d3SCy Schubert if (end) {
2441c1d255d3SCy Schubert match_len = end - pos;
2442c1d255d3SCy Schubert multicast = os_strstr(end, "multicast") != NULL;
2443c1d255d3SCy Schubert } else {
2444c1d255d3SCy Schubert match_len = os_strlen(pos) / 2;
2445c1d255d3SCy Schubert }
2446c1d255d3SCy Schubert if (hexstr2bin(pos, match, match_len))
2447c1d255d3SCy Schubert return -1;
2448c1d255d3SCy Schubert
2449c1d255d3SCy Schubert return hostapd_drv_register_frame(hapd, type, match, match_len,
2450c1d255d3SCy Schubert multicast);
2451c1d255d3SCy Schubert }
2452c1d255d3SCy Schubert
24535b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
24545b9c547cSRui Paulo
24555b9c547cSRui Paulo
2456c1d255d3SCy Schubert #ifdef NEED_AP_MLME
hostapd_ctrl_check_freq_params(struct hostapd_freq_params * params,u16 punct_bitmap)2457*a90b9d01SCy Schubert static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
2458*a90b9d01SCy Schubert u16 punct_bitmap)
2459c1d255d3SCy Schubert {
2460*a90b9d01SCy Schubert u32 start_freq;
2461*a90b9d01SCy Schubert
2462*a90b9d01SCy Schubert if (is_6ghz_freq(params->freq)) {
2463*a90b9d01SCy Schubert const int bw_idx[] = { 20, 40, 80, 160, 320 };
2464*a90b9d01SCy Schubert int idx, bw;
2465*a90b9d01SCy Schubert
2466*a90b9d01SCy Schubert /* The 6 GHz band requires HE to be enabled. */
2467*a90b9d01SCy Schubert params->he_enabled = 1;
2468*a90b9d01SCy Schubert
2469*a90b9d01SCy Schubert if (params->center_freq1) {
2470*a90b9d01SCy Schubert if (params->freq == 5935)
2471*a90b9d01SCy Schubert idx = (params->center_freq1 - 5925) / 5;
2472*a90b9d01SCy Schubert else
2473*a90b9d01SCy Schubert idx = (params->center_freq1 - 5950) / 5;
2474*a90b9d01SCy Schubert
2475*a90b9d01SCy Schubert bw = center_idx_to_bw_6ghz(idx);
2476*a90b9d01SCy Schubert if (bw < 0 || bw > (int) ARRAY_SIZE(bw_idx) ||
2477*a90b9d01SCy Schubert bw_idx[bw] != params->bandwidth)
2478*a90b9d01SCy Schubert return -1;
2479*a90b9d01SCy Schubert }
2480*a90b9d01SCy Schubert } else { /* Non-6 GHz channel */
2481*a90b9d01SCy Schubert /* An EHT STA is also an HE STA as defined in
2482*a90b9d01SCy Schubert * IEEE P802.11be/D5.0, 4.3.16a. */
2483*a90b9d01SCy Schubert if (params->he_enabled || params->eht_enabled) {
2484*a90b9d01SCy Schubert params->he_enabled = 1;
2485*a90b9d01SCy Schubert /* An HE STA is also a VHT STA if operating in the 5 GHz
2486*a90b9d01SCy Schubert * band and an HE STA is also an HT STA in the 2.4 GHz
2487*a90b9d01SCy Schubert * band as defined in IEEE Std 802.11ax-2021, 4.3.15a.
2488*a90b9d01SCy Schubert * A VHT STA is an HT STA as defined in IEEE
2489*a90b9d01SCy Schubert * Std 802.11, 4.3.15. */
2490*a90b9d01SCy Schubert if (IS_5GHZ(params->freq))
2491*a90b9d01SCy Schubert params->vht_enabled = 1;
2492*a90b9d01SCy Schubert
2493*a90b9d01SCy Schubert params->ht_enabled = 1;
2494*a90b9d01SCy Schubert }
2495*a90b9d01SCy Schubert }
2496*a90b9d01SCy Schubert
2497c1d255d3SCy Schubert switch (params->bandwidth) {
2498c1d255d3SCy Schubert case 0:
2499c1d255d3SCy Schubert /* bandwidth not specified: use 20 MHz by default */
2500c1d255d3SCy Schubert /* fall-through */
2501c1d255d3SCy Schubert case 20:
2502c1d255d3SCy Schubert if (params->center_freq1 &&
2503c1d255d3SCy Schubert params->center_freq1 != params->freq)
2504c1d255d3SCy Schubert return -1;
2505c1d255d3SCy Schubert
2506c1d255d3SCy Schubert if (params->center_freq2 || params->sec_channel_offset)
2507c1d255d3SCy Schubert return -1;
2508*a90b9d01SCy Schubert
2509*a90b9d01SCy Schubert if (punct_bitmap)
2510*a90b9d01SCy Schubert return -1;
2511c1d255d3SCy Schubert break;
2512c1d255d3SCy Schubert case 40:
2513c1d255d3SCy Schubert if (params->center_freq2 || !params->sec_channel_offset)
2514c1d255d3SCy Schubert return -1;
2515c1d255d3SCy Schubert
2516*a90b9d01SCy Schubert if (punct_bitmap)
2517*a90b9d01SCy Schubert return -1;
2518*a90b9d01SCy Schubert
2519c1d255d3SCy Schubert if (!params->center_freq1)
2520c1d255d3SCy Schubert break;
2521c1d255d3SCy Schubert switch (params->sec_channel_offset) {
2522c1d255d3SCy Schubert case 1:
2523c1d255d3SCy Schubert if (params->freq + 10 != params->center_freq1)
2524c1d255d3SCy Schubert return -1;
2525c1d255d3SCy Schubert break;
2526c1d255d3SCy Schubert case -1:
2527c1d255d3SCy Schubert if (params->freq - 10 != params->center_freq1)
2528c1d255d3SCy Schubert return -1;
2529c1d255d3SCy Schubert break;
2530c1d255d3SCy Schubert default:
2531c1d255d3SCy Schubert return -1;
2532c1d255d3SCy Schubert }
2533c1d255d3SCy Schubert break;
2534c1d255d3SCy Schubert case 80:
2535c1d255d3SCy Schubert if (!params->center_freq1 || !params->sec_channel_offset)
2536c1d255d3SCy Schubert return 1;
2537c1d255d3SCy Schubert
2538c1d255d3SCy Schubert switch (params->sec_channel_offset) {
2539c1d255d3SCy Schubert case 1:
2540c1d255d3SCy Schubert if (params->freq - 10 != params->center_freq1 &&
2541c1d255d3SCy Schubert params->freq + 30 != params->center_freq1)
2542c1d255d3SCy Schubert return 1;
2543c1d255d3SCy Schubert break;
2544c1d255d3SCy Schubert case -1:
2545c1d255d3SCy Schubert if (params->freq + 10 != params->center_freq1 &&
2546c1d255d3SCy Schubert params->freq - 30 != params->center_freq1)
2547c1d255d3SCy Schubert return -1;
2548c1d255d3SCy Schubert break;
2549c1d255d3SCy Schubert default:
2550c1d255d3SCy Schubert return -1;
2551c1d255d3SCy Schubert }
2552c1d255d3SCy Schubert
2553*a90b9d01SCy Schubert if (params->center_freq2 && punct_bitmap)
2554*a90b9d01SCy Schubert return -1;
2555*a90b9d01SCy Schubert
2556c1d255d3SCy Schubert /* Adjacent and overlapped are not allowed for 80+80 */
2557c1d255d3SCy Schubert if (params->center_freq2 &&
2558c1d255d3SCy Schubert params->center_freq1 - params->center_freq2 <= 80 &&
2559c1d255d3SCy Schubert params->center_freq2 - params->center_freq1 <= 80)
2560c1d255d3SCy Schubert return 1;
2561c1d255d3SCy Schubert break;
2562c1d255d3SCy Schubert case 160:
2563c1d255d3SCy Schubert if (!params->center_freq1 || params->center_freq2 ||
2564c1d255d3SCy Schubert !params->sec_channel_offset)
2565c1d255d3SCy Schubert return -1;
2566c1d255d3SCy Schubert
2567c1d255d3SCy Schubert switch (params->sec_channel_offset) {
2568c1d255d3SCy Schubert case 1:
2569c1d255d3SCy Schubert if (params->freq + 70 != params->center_freq1 &&
2570c1d255d3SCy Schubert params->freq + 30 != params->center_freq1 &&
2571c1d255d3SCy Schubert params->freq - 10 != params->center_freq1 &&
2572c1d255d3SCy Schubert params->freq - 50 != params->center_freq1)
2573c1d255d3SCy Schubert return -1;
2574c1d255d3SCy Schubert break;
2575c1d255d3SCy Schubert case -1:
2576c1d255d3SCy Schubert if (params->freq + 50 != params->center_freq1 &&
2577c1d255d3SCy Schubert params->freq + 10 != params->center_freq1 &&
2578c1d255d3SCy Schubert params->freq - 30 != params->center_freq1 &&
2579c1d255d3SCy Schubert params->freq - 70 != params->center_freq1)
2580c1d255d3SCy Schubert return -1;
2581c1d255d3SCy Schubert break;
2582c1d255d3SCy Schubert default:
2583c1d255d3SCy Schubert return -1;
2584c1d255d3SCy Schubert }
2585c1d255d3SCy Schubert break;
2586*a90b9d01SCy Schubert case 320:
2587*a90b9d01SCy Schubert if (!params->center_freq1 || params->center_freq2 ||
2588*a90b9d01SCy Schubert !params->sec_channel_offset)
2589*a90b9d01SCy Schubert return -1;
2590*a90b9d01SCy Schubert
2591*a90b9d01SCy Schubert switch (params->sec_channel_offset) {
2592*a90b9d01SCy Schubert case 1:
2593*a90b9d01SCy Schubert if (params->freq + 150 != params->center_freq1 &&
2594*a90b9d01SCy Schubert params->freq + 110 != params->center_freq1 &&
2595*a90b9d01SCy Schubert params->freq + 70 != params->center_freq1 &&
2596*a90b9d01SCy Schubert params->freq + 30 != params->center_freq1 &&
2597*a90b9d01SCy Schubert params->freq - 10 != params->center_freq1 &&
2598*a90b9d01SCy Schubert params->freq - 50 != params->center_freq1 &&
2599*a90b9d01SCy Schubert params->freq - 90 != params->center_freq1 &&
2600*a90b9d01SCy Schubert params->freq - 130 != params->center_freq1)
2601*a90b9d01SCy Schubert return -1;
2602*a90b9d01SCy Schubert break;
2603*a90b9d01SCy Schubert case -1:
2604*a90b9d01SCy Schubert if (params->freq + 130 != params->center_freq1 &&
2605*a90b9d01SCy Schubert params->freq + 90 != params->center_freq1 &&
2606*a90b9d01SCy Schubert params->freq + 50 != params->center_freq1 &&
2607*a90b9d01SCy Schubert params->freq + 10 != params->center_freq1 &&
2608*a90b9d01SCy Schubert params->freq - 30 != params->center_freq1 &&
2609*a90b9d01SCy Schubert params->freq - 70 != params->center_freq1 &&
2610*a90b9d01SCy Schubert params->freq - 110 != params->center_freq1 &&
2611*a90b9d01SCy Schubert params->freq - 150 != params->center_freq1)
2612*a90b9d01SCy Schubert return -1;
2613*a90b9d01SCy Schubert break;
2614*a90b9d01SCy Schubert }
2615*a90b9d01SCy Schubert break;
2616c1d255d3SCy Schubert default:
2617c1d255d3SCy Schubert return -1;
2618c1d255d3SCy Schubert }
2619c1d255d3SCy Schubert
2620*a90b9d01SCy Schubert if (!punct_bitmap)
2621*a90b9d01SCy Schubert return 0;
2622*a90b9d01SCy Schubert
2623*a90b9d01SCy Schubert if (!params->eht_enabled) {
2624*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
2625*a90b9d01SCy Schubert "Preamble puncturing supported only in EHT");
2626*a90b9d01SCy Schubert return -1;
2627*a90b9d01SCy Schubert }
2628*a90b9d01SCy Schubert
2629*a90b9d01SCy Schubert if (params->freq >= 2412 && params->freq <= 2484) {
2630*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
2631*a90b9d01SCy Schubert "Preamble puncturing is not supported in 2.4 GHz");
2632*a90b9d01SCy Schubert return -1;
2633*a90b9d01SCy Schubert }
2634*a90b9d01SCy Schubert
2635*a90b9d01SCy Schubert start_freq = params->center_freq1 - (params->bandwidth / 2);
2636*a90b9d01SCy Schubert if (!is_punct_bitmap_valid(params->bandwidth,
2637*a90b9d01SCy Schubert (params->freq - start_freq) / 20,
2638*a90b9d01SCy Schubert punct_bitmap)) {
2639*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "Invalid preamble puncturing bitmap");
2640*a90b9d01SCy Schubert return -1;
2641*a90b9d01SCy Schubert }
2642*a90b9d01SCy Schubert
2643c1d255d3SCy Schubert return 0;
2644c1d255d3SCy Schubert }
2645c1d255d3SCy Schubert #endif /* NEED_AP_MLME */
2646c1d255d3SCy Schubert
2647c1d255d3SCy Schubert
hostapd_ctrl_iface_chan_switch(struct hostapd_iface * iface,char * pos)26485b9c547cSRui Paulo static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
26495b9c547cSRui Paulo char *pos)
26505b9c547cSRui Paulo {
26515b9c547cSRui Paulo #ifdef NEED_AP_MLME
26525b9c547cSRui Paulo struct csa_settings settings;
26535b9c547cSRui Paulo int ret;
2654c1d255d3SCy Schubert int dfs_range = 0;
26555b9c547cSRui Paulo unsigned int i;
2656c1d255d3SCy Schubert int bandwidth;
2657c1d255d3SCy Schubert u8 chan;
2658*a90b9d01SCy Schubert unsigned int num_err = 0;
2659*a90b9d01SCy Schubert int err = 0;
26605b9c547cSRui Paulo
26615b9c547cSRui Paulo ret = hostapd_parse_csa_settings(pos, &settings);
26625b9c547cSRui Paulo if (ret)
26635b9c547cSRui Paulo return ret;
26645b9c547cSRui Paulo
2665*a90b9d01SCy Schubert settings.link_id = -1;
2666*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
2667*a90b9d01SCy Schubert if (iface->num_bss && iface->bss[0]->conf->mld_ap)
2668*a90b9d01SCy Schubert settings.link_id = iface->bss[0]->mld_link_id;
2669*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
2670*a90b9d01SCy Schubert
2671*a90b9d01SCy Schubert ret = hostapd_ctrl_check_freq_params(&settings.freq_params,
2672*a90b9d01SCy Schubert settings.punct_bitmap);
2673c1d255d3SCy Schubert if (ret) {
2674c1d255d3SCy Schubert wpa_printf(MSG_INFO,
2675c1d255d3SCy Schubert "chanswitch: invalid frequency settings provided");
2676c1d255d3SCy Schubert return ret;
2677c1d255d3SCy Schubert }
2678c1d255d3SCy Schubert
2679c1d255d3SCy Schubert switch (settings.freq_params.bandwidth) {
2680c1d255d3SCy Schubert case 40:
2681c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_40;
2682c1d255d3SCy Schubert break;
2683c1d255d3SCy Schubert case 80:
2684c1d255d3SCy Schubert if (settings.freq_params.center_freq2)
2685c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_80P80;
2686c1d255d3SCy Schubert else
2687c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_80;
2688c1d255d3SCy Schubert break;
2689c1d255d3SCy Schubert case 160:
2690c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_160;
2691c1d255d3SCy Schubert break;
2692*a90b9d01SCy Schubert case 320:
2693*a90b9d01SCy Schubert bandwidth = CHAN_WIDTH_320;
2694*a90b9d01SCy Schubert break;
2695c1d255d3SCy Schubert default:
2696c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_20;
2697c1d255d3SCy Schubert break;
2698c1d255d3SCy Schubert }
2699c1d255d3SCy Schubert
2700c1d255d3SCy Schubert if (settings.freq_params.center_freq1)
2701c1d255d3SCy Schubert dfs_range += hostapd_is_dfs_overlap(
2702c1d255d3SCy Schubert iface, bandwidth, settings.freq_params.center_freq1);
2703c1d255d3SCy Schubert else
2704c1d255d3SCy Schubert dfs_range += hostapd_is_dfs_overlap(
2705c1d255d3SCy Schubert iface, bandwidth, settings.freq_params.freq);
2706c1d255d3SCy Schubert
2707c1d255d3SCy Schubert if (settings.freq_params.center_freq2)
2708c1d255d3SCy Schubert dfs_range += hostapd_is_dfs_overlap(
2709c1d255d3SCy Schubert iface, bandwidth, settings.freq_params.center_freq2);
2710c1d255d3SCy Schubert
2711c1d255d3SCy Schubert if (dfs_range) {
2712c1d255d3SCy Schubert ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
2713c1d255d3SCy Schubert if (ret == NUM_HOSTAPD_MODES) {
2714c1d255d3SCy Schubert wpa_printf(MSG_ERROR,
2715c1d255d3SCy Schubert "Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
2716c1d255d3SCy Schubert settings.freq_params.freq,
2717c1d255d3SCy Schubert settings.freq_params.sec_channel_offset,
2718c1d255d3SCy Schubert settings.freq_params.bandwidth);
2719c1d255d3SCy Schubert return -1;
2720c1d255d3SCy Schubert }
2721c1d255d3SCy Schubert
2722c1d255d3SCy Schubert settings.freq_params.channel = chan;
2723c1d255d3SCy Schubert
2724c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2725c1d255d3SCy Schubert "DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
2726c1d255d3SCy Schubert settings.freq_params.channel,
2727c1d255d3SCy Schubert settings.freq_params.freq,
2728c1d255d3SCy Schubert settings.freq_params.sec_channel_offset,
2729c1d255d3SCy Schubert settings.freq_params.bandwidth,
2730c1d255d3SCy Schubert settings.freq_params.center_freq1);
2731c1d255d3SCy Schubert
2732c1d255d3SCy Schubert /* Perform CAC and switch channel */
2733*a90b9d01SCy Schubert iface->is_ch_switch_dfs = true;
2734c1d255d3SCy Schubert hostapd_switch_channel_fallback(iface, &settings.freq_params);
2735c1d255d3SCy Schubert return 0;
2736c1d255d3SCy Schubert }
2737c1d255d3SCy Schubert
27385b9c547cSRui Paulo for (i = 0; i < iface->num_bss; i++) {
273985732ac8SCy Schubert
2740*a90b9d01SCy Schubert /* Save CHAN_SWITCH VHT, HE, and EHT config */
2741c1d255d3SCy Schubert hostapd_chan_switch_config(iface->bss[i],
2742c1d255d3SCy Schubert &settings.freq_params);
274385732ac8SCy Schubert
2744*a90b9d01SCy Schubert err = hostapd_switch_channel(iface->bss[i], &settings);
2745*a90b9d01SCy Schubert if (err) {
2746*a90b9d01SCy Schubert ret = err;
2747*a90b9d01SCy Schubert num_err++;
27485b9c547cSRui Paulo }
27495b9c547cSRui Paulo }
27505b9c547cSRui Paulo
2751*a90b9d01SCy Schubert return (iface->num_bss == num_err) ? ret : 0;
2752*a90b9d01SCy Schubert #else /* NEED_AP_MLME */
2753*a90b9d01SCy Schubert return -1;
2754*a90b9d01SCy Schubert #endif /* NEED_AP_MLME */
2755*a90b9d01SCy Schubert }
2756*a90b9d01SCy Schubert
2757*a90b9d01SCy Schubert
2758*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211AX
hostapd_ctrl_iface_color_change(struct hostapd_iface * iface,const char * pos)2759*a90b9d01SCy Schubert static int hostapd_ctrl_iface_color_change(struct hostapd_iface *iface,
2760*a90b9d01SCy Schubert const char *pos)
2761*a90b9d01SCy Schubert {
2762*a90b9d01SCy Schubert #ifdef NEED_AP_MLME
2763*a90b9d01SCy Schubert struct cca_settings settings;
2764*a90b9d01SCy Schubert struct hostapd_data *hapd = iface->bss[0];
2765*a90b9d01SCy Schubert int ret, color;
2766*a90b9d01SCy Schubert unsigned int i;
2767*a90b9d01SCy Schubert char *end;
2768*a90b9d01SCy Schubert
2769*a90b9d01SCy Schubert os_memset(&settings, 0, sizeof(settings));
2770*a90b9d01SCy Schubert
2771*a90b9d01SCy Schubert color = strtol(pos, &end, 10);
2772*a90b9d01SCy Schubert if (pos == end || color < 0 || color > 63) {
2773*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "color_change: Invalid color provided");
2774*a90b9d01SCy Schubert return -1;
2775*a90b9d01SCy Schubert }
2776*a90b9d01SCy Schubert
2777*a90b9d01SCy Schubert /* Color value is expected to be [1-63]. If 0 comes, assumption is this
2778*a90b9d01SCy Schubert * is to disable the color. In this case no need to do CCA, just
2779*a90b9d01SCy Schubert * changing Beacon frames is sufficient. */
2780*a90b9d01SCy Schubert if (color == 0) {
2781*a90b9d01SCy Schubert if (iface->conf->he_op.he_bss_color_disabled) {
2782*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
2783*a90b9d01SCy Schubert "color_change: Color is already disabled");
2784*a90b9d01SCy Schubert return -1;
2785*a90b9d01SCy Schubert }
2786*a90b9d01SCy Schubert
2787*a90b9d01SCy Schubert iface->conf->he_op.he_bss_color_disabled = 1;
2788*a90b9d01SCy Schubert
2789*a90b9d01SCy Schubert for (i = 0; i < iface->num_bss; i++)
2790*a90b9d01SCy Schubert ieee802_11_set_beacon(iface->bss[i]);
2791*a90b9d01SCy Schubert
2792*a90b9d01SCy Schubert return 0;
2793*a90b9d01SCy Schubert }
2794*a90b9d01SCy Schubert
2795*a90b9d01SCy Schubert if (color == iface->conf->he_op.he_bss_color) {
2796*a90b9d01SCy Schubert if (!iface->conf->he_op.he_bss_color_disabled) {
2797*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
2798*a90b9d01SCy Schubert "color_change: Provided color is already set");
2799*a90b9d01SCy Schubert return -1;
2800*a90b9d01SCy Schubert }
2801*a90b9d01SCy Schubert
2802*a90b9d01SCy Schubert iface->conf->he_op.he_bss_color_disabled = 0;
2803*a90b9d01SCy Schubert
2804*a90b9d01SCy Schubert for (i = 0; i < iface->num_bss; i++)
2805*a90b9d01SCy Schubert ieee802_11_set_beacon(iface->bss[i]);
2806*a90b9d01SCy Schubert
2807*a90b9d01SCy Schubert return 0;
2808*a90b9d01SCy Schubert }
2809*a90b9d01SCy Schubert
2810*a90b9d01SCy Schubert if (hapd->cca_in_progress) {
2811*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
2812*a90b9d01SCy Schubert "color_change: CCA is already in progress");
2813*a90b9d01SCy Schubert return -1;
2814*a90b9d01SCy Schubert }
2815*a90b9d01SCy Schubert
2816*a90b9d01SCy Schubert iface->conf->he_op.he_bss_color_disabled = 0;
2817*a90b9d01SCy Schubert
2818*a90b9d01SCy Schubert for (i = 0; i < iface->num_bss; i++) {
2819*a90b9d01SCy Schubert struct hostapd_data *bss = iface->bss[i];
2820*a90b9d01SCy Schubert
2821*a90b9d01SCy Schubert hostapd_cleanup_cca_params(bss);
2822*a90b9d01SCy Schubert
2823*a90b9d01SCy Schubert bss->cca_color = color;
2824*a90b9d01SCy Schubert bss->cca_count = 10;
2825*a90b9d01SCy Schubert
2826*a90b9d01SCy Schubert if (hostapd_fill_cca_settings(bss, &settings)) {
2827*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
2828*a90b9d01SCy Schubert "color_change: Filling CCA settings failed for color: %d\n",
2829*a90b9d01SCy Schubert color);
2830*a90b9d01SCy Schubert hostapd_cleanup_cca_params(bss);
2831*a90b9d01SCy Schubert continue;
2832*a90b9d01SCy Schubert }
2833*a90b9d01SCy Schubert
2834*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "Setting user selected color: %d", color);
2835*a90b9d01SCy Schubert ret = hostapd_drv_switch_color(bss, &settings);
2836*a90b9d01SCy Schubert if (ret)
2837*a90b9d01SCy Schubert hostapd_cleanup_cca_params(bss);
2838*a90b9d01SCy Schubert
2839*a90b9d01SCy Schubert free_beacon_data(&settings.beacon_cca);
2840*a90b9d01SCy Schubert free_beacon_data(&settings.beacon_after);
2841*a90b9d01SCy Schubert }
2842*a90b9d01SCy Schubert
28435b9c547cSRui Paulo return 0;
28445b9c547cSRui Paulo #else /* NEED_AP_MLME */
28455b9c547cSRui Paulo return -1;
28465b9c547cSRui Paulo #endif /* NEED_AP_MLME */
28475b9c547cSRui Paulo }
2848*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211AX */
2849*a90b9d01SCy Schubert
2850*a90b9d01SCy Schubert
hostapd_maxnss(struct hostapd_data * hapd,struct sta_info * sta)2851*a90b9d01SCy Schubert static u8 hostapd_maxnss(struct hostapd_data *hapd, struct sta_info *sta)
2852*a90b9d01SCy Schubert {
2853*a90b9d01SCy Schubert u8 *mcs_set = NULL;
2854*a90b9d01SCy Schubert u16 mcs_map;
2855*a90b9d01SCy Schubert u8 ht_rx_nss = 0;
2856*a90b9d01SCy Schubert u8 vht_rx_nss = 1;
2857*a90b9d01SCy Schubert u8 mcs;
2858*a90b9d01SCy Schubert bool ht_supported = false;
2859*a90b9d01SCy Schubert bool vht_supported = false;
2860*a90b9d01SCy Schubert int i;
2861*a90b9d01SCy Schubert
2862*a90b9d01SCy Schubert if (sta->ht_capabilities && (sta->flags & WLAN_STA_HT)) {
2863*a90b9d01SCy Schubert mcs_set = sta->ht_capabilities->supported_mcs_set;
2864*a90b9d01SCy Schubert ht_supported = true;
2865*a90b9d01SCy Schubert }
2866*a90b9d01SCy Schubert
2867*a90b9d01SCy Schubert if (sta->vht_capabilities && (sta->flags & WLAN_STA_VHT)) {
2868*a90b9d01SCy Schubert mcs_map = le_to_host16(
2869*a90b9d01SCy Schubert sta->vht_capabilities->vht_supported_mcs_set.rx_map);
2870*a90b9d01SCy Schubert vht_supported = true;
2871*a90b9d01SCy Schubert }
2872*a90b9d01SCy Schubert
2873*a90b9d01SCy Schubert if (ht_supported && mcs_set) {
2874*a90b9d01SCy Schubert if (mcs_set[0])
2875*a90b9d01SCy Schubert ht_rx_nss++;
2876*a90b9d01SCy Schubert if (mcs_set[1])
2877*a90b9d01SCy Schubert ht_rx_nss++;
2878*a90b9d01SCy Schubert if (mcs_set[2])
2879*a90b9d01SCy Schubert ht_rx_nss++;
2880*a90b9d01SCy Schubert if (mcs_set[3])
2881*a90b9d01SCy Schubert ht_rx_nss++;
2882*a90b9d01SCy Schubert }
2883*a90b9d01SCy Schubert if (vht_supported) {
2884*a90b9d01SCy Schubert for (i = 7; i >= 0; i--) {
2885*a90b9d01SCy Schubert mcs = (mcs_map >> (2 * i)) & 0x03;
2886*a90b9d01SCy Schubert if (mcs != 0x03) {
2887*a90b9d01SCy Schubert vht_rx_nss = i + 1;
2888*a90b9d01SCy Schubert break;
2889*a90b9d01SCy Schubert }
2890*a90b9d01SCy Schubert }
2891*a90b9d01SCy Schubert }
2892*a90b9d01SCy Schubert
2893*a90b9d01SCy Schubert return ht_rx_nss > vht_rx_nss ? ht_rx_nss : vht_rx_nss;
2894*a90b9d01SCy Schubert }
2895*a90b9d01SCy Schubert
2896*a90b9d01SCy Schubert
hostapd_ctrl_iface_notify_cw_htaction(struct hostapd_data * hapd,const u8 * addr,u8 width)2897*a90b9d01SCy Schubert static char hostapd_ctrl_iface_notify_cw_htaction(struct hostapd_data *hapd,
2898*a90b9d01SCy Schubert const u8 *addr, u8 width)
2899*a90b9d01SCy Schubert {
2900*a90b9d01SCy Schubert u8 buf[3];
2901*a90b9d01SCy Schubert char ret;
2902*a90b9d01SCy Schubert
2903*a90b9d01SCy Schubert width = width >= 1 ? 1 : 0;
2904*a90b9d01SCy Schubert
2905*a90b9d01SCy Schubert buf[0] = WLAN_ACTION_HT;
2906*a90b9d01SCy Schubert buf[1] = WLAN_HT_ACTION_NOTIFY_CHANWIDTH;
2907*a90b9d01SCy Schubert buf[2] = width;
2908*a90b9d01SCy Schubert
2909*a90b9d01SCy Schubert ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
2910*a90b9d01SCy Schubert buf, sizeof(buf));
2911*a90b9d01SCy Schubert if (ret)
2912*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
2913*a90b9d01SCy Schubert "Failed to send Notify Channel Width frame to "
2914*a90b9d01SCy Schubert MACSTR, MAC2STR(addr));
2915*a90b9d01SCy Schubert
2916*a90b9d01SCy Schubert return ret;
2917*a90b9d01SCy Schubert }
2918*a90b9d01SCy Schubert
2919*a90b9d01SCy Schubert
hostapd_ctrl_iface_notify_cw_vhtaction(struct hostapd_data * hapd,const u8 * addr,u8 width)2920*a90b9d01SCy Schubert static char hostapd_ctrl_iface_notify_cw_vhtaction(struct hostapd_data *hapd,
2921*a90b9d01SCy Schubert const u8 *addr, u8 width)
2922*a90b9d01SCy Schubert {
2923*a90b9d01SCy Schubert u8 buf[3];
2924*a90b9d01SCy Schubert char ret;
2925*a90b9d01SCy Schubert
2926*a90b9d01SCy Schubert buf[0] = WLAN_ACTION_VHT;
2927*a90b9d01SCy Schubert buf[1] = WLAN_VHT_ACTION_OPMODE_NOTIF;
2928*a90b9d01SCy Schubert buf[2] = width;
2929*a90b9d01SCy Schubert
2930*a90b9d01SCy Schubert ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
2931*a90b9d01SCy Schubert buf, sizeof(buf));
2932*a90b9d01SCy Schubert if (ret)
2933*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
2934*a90b9d01SCy Schubert "Failed to send Opeating Mode Notification frame to "
2935*a90b9d01SCy Schubert MACSTR, MAC2STR(addr));
2936*a90b9d01SCy Schubert
2937*a90b9d01SCy Schubert return ret;
2938*a90b9d01SCy Schubert }
2939*a90b9d01SCy Schubert
2940*a90b9d01SCy Schubert
hostapd_ctrl_iface_notify_cw_change(struct hostapd_data * hapd,const char * cmd)2941*a90b9d01SCy Schubert static char hostapd_ctrl_iface_notify_cw_change(struct hostapd_data *hapd,
2942*a90b9d01SCy Schubert const char *cmd)
2943*a90b9d01SCy Schubert {
2944*a90b9d01SCy Schubert u8 cw, operating_mode = 0, nss;
2945*a90b9d01SCy Schubert struct sta_info *sta;
2946*a90b9d01SCy Schubert enum hostapd_hw_mode hw_mode;
2947*a90b9d01SCy Schubert
2948*a90b9d01SCy Schubert if (is_6ghz_freq(hapd->iface->freq)) {
2949*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "20/40 BSS coex not supported in 6 GHz");
2950*a90b9d01SCy Schubert return -1;
2951*a90b9d01SCy Schubert }
2952*a90b9d01SCy Schubert
2953*a90b9d01SCy Schubert cw = atoi(cmd);
2954*a90b9d01SCy Schubert hw_mode = hapd->iface->current_mode->mode;
2955*a90b9d01SCy Schubert if ((hw_mode == HOSTAPD_MODE_IEEE80211G ||
2956*a90b9d01SCy Schubert hw_mode == HOSTAPD_MODE_IEEE80211B) &&
2957*a90b9d01SCy Schubert !(cw == 0 || cw == 1)) {
2958*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
2959*a90b9d01SCy Schubert "Channel width should be either 20 MHz or 40 MHz for 2.4 GHz band");
2960*a90b9d01SCy Schubert return -1;
2961*a90b9d01SCy Schubert }
2962*a90b9d01SCy Schubert
2963*a90b9d01SCy Schubert switch (cw) {
2964*a90b9d01SCy Schubert case 0:
2965*a90b9d01SCy Schubert operating_mode = 0;
2966*a90b9d01SCy Schubert break;
2967*a90b9d01SCy Schubert case 1:
2968*a90b9d01SCy Schubert operating_mode = VHT_OPMODE_CHANNEL_40MHZ;
2969*a90b9d01SCy Schubert break;
2970*a90b9d01SCy Schubert case 2:
2971*a90b9d01SCy Schubert operating_mode = VHT_OPMODE_CHANNEL_80MHZ;
2972*a90b9d01SCy Schubert break;
2973*a90b9d01SCy Schubert case 3:
2974*a90b9d01SCy Schubert operating_mode = VHT_OPMODE_CHANNEL_160MHZ;
2975*a90b9d01SCy Schubert break;
2976*a90b9d01SCy Schubert default:
2977*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "Channel width should be between 0 to 3");
2978*a90b9d01SCy Schubert return -1;
2979*a90b9d01SCy Schubert }
2980*a90b9d01SCy Schubert
2981*a90b9d01SCy Schubert for (sta = hapd->sta_list; sta; sta = sta->next) {
2982*a90b9d01SCy Schubert if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
2983*a90b9d01SCy Schubert nss = hostapd_maxnss(hapd, sta) - 1;
2984*a90b9d01SCy Schubert hostapd_ctrl_iface_notify_cw_vhtaction(hapd, sta->addr,
2985*a90b9d01SCy Schubert operating_mode |
2986*a90b9d01SCy Schubert (u8) (nss << 4));
2987*a90b9d01SCy Schubert continue;
2988*a90b9d01SCy Schubert }
2989*a90b9d01SCy Schubert
2990*a90b9d01SCy Schubert if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) ==
2991*a90b9d01SCy Schubert WLAN_STA_HT && sta->ht_capabilities)
2992*a90b9d01SCy Schubert hostapd_ctrl_iface_notify_cw_htaction(hapd, sta->addr,
2993*a90b9d01SCy Schubert cw);
2994*a90b9d01SCy Schubert }
2995*a90b9d01SCy Schubert
2996*a90b9d01SCy Schubert return 0;
2997*a90b9d01SCy Schubert }
29985b9c547cSRui Paulo
29995b9c547cSRui Paulo
hostapd_ctrl_iface_mib(struct hostapd_data * hapd,char * reply,int reply_size,const char * param)30005b9c547cSRui Paulo static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
30015b9c547cSRui Paulo int reply_size, const char *param)
30025b9c547cSRui Paulo {
30035b9c547cSRui Paulo #ifdef RADIUS_SERVER
30045b9c547cSRui Paulo if (os_strcmp(param, "radius_server") == 0) {
30055b9c547cSRui Paulo return radius_server_get_mib(hapd->radius_srv, reply,
30065b9c547cSRui Paulo reply_size);
30075b9c547cSRui Paulo }
30085b9c547cSRui Paulo #endif /* RADIUS_SERVER */
30095b9c547cSRui Paulo return -1;
30105b9c547cSRui Paulo }
30115b9c547cSRui Paulo
30125b9c547cSRui Paulo
hostapd_ctrl_iface_vendor(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)30135b9c547cSRui Paulo static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
30145b9c547cSRui Paulo char *buf, size_t buflen)
30155b9c547cSRui Paulo {
30165b9c547cSRui Paulo int ret;
3017c1d255d3SCy Schubert char *pos, *temp = NULL;
30185b9c547cSRui Paulo u8 *data = NULL;
30195b9c547cSRui Paulo unsigned int vendor_id, subcmd;
3020c1d255d3SCy Schubert enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
30215b9c547cSRui Paulo struct wpabuf *reply;
30225b9c547cSRui Paulo size_t data_len = 0;
30235b9c547cSRui Paulo
3024c1d255d3SCy Schubert /**
3025c1d255d3SCy Schubert * cmd: <vendor id> <subcommand id> [<hex formatted data>]
3026c1d255d3SCy Schubert * [nested=<0|1>]
3027c1d255d3SCy Schubert */
30285b9c547cSRui Paulo vendor_id = strtoul(cmd, &pos, 16);
3029780fb4a2SCy Schubert if (!isblank((unsigned char) *pos))
30305b9c547cSRui Paulo return -EINVAL;
30315b9c547cSRui Paulo
30325b9c547cSRui Paulo subcmd = strtoul(pos, &pos, 10);
30335b9c547cSRui Paulo
30345b9c547cSRui Paulo if (*pos != '\0') {
3035780fb4a2SCy Schubert if (!isblank((unsigned char) *pos++))
30365b9c547cSRui Paulo return -EINVAL;
3037c1d255d3SCy Schubert
3038c1d255d3SCy Schubert temp = os_strchr(pos, ' ');
3039c1d255d3SCy Schubert data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
30405b9c547cSRui Paulo }
30415b9c547cSRui Paulo
30425b9c547cSRui Paulo if (data_len) {
30435b9c547cSRui Paulo data_len /= 2;
30445b9c547cSRui Paulo data = os_malloc(data_len);
30455b9c547cSRui Paulo if (!data)
30465b9c547cSRui Paulo return -ENOBUFS;
30475b9c547cSRui Paulo
30485b9c547cSRui Paulo if (hexstr2bin(pos, data, data_len)) {
30495b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
30505b9c547cSRui Paulo "Vendor command: wrong parameter format");
30515b9c547cSRui Paulo os_free(data);
30525b9c547cSRui Paulo return -EINVAL;
30535b9c547cSRui Paulo }
30545b9c547cSRui Paulo }
30555b9c547cSRui Paulo
3056c1d255d3SCy Schubert pos = os_strstr(cmd, "nested=");
3057c1d255d3SCy Schubert if (pos)
3058c1d255d3SCy Schubert nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED :
3059c1d255d3SCy Schubert NESTED_ATTR_NOT_USED;
3060c1d255d3SCy Schubert
30615b9c547cSRui Paulo reply = wpabuf_alloc((buflen - 1) / 2);
30625b9c547cSRui Paulo if (!reply) {
30635b9c547cSRui Paulo os_free(data);
30645b9c547cSRui Paulo return -ENOBUFS;
30655b9c547cSRui Paulo }
30665b9c547cSRui Paulo
30675b9c547cSRui Paulo ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
3068c1d255d3SCy Schubert nested_attr_flag, reply);
30695b9c547cSRui Paulo
30705b9c547cSRui Paulo if (ret == 0)
30715b9c547cSRui Paulo ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
30725b9c547cSRui Paulo wpabuf_len(reply));
30735b9c547cSRui Paulo
30745b9c547cSRui Paulo wpabuf_free(reply);
30755b9c547cSRui Paulo os_free(data);
30765b9c547cSRui Paulo
30775b9c547cSRui Paulo return ret;
30785b9c547cSRui Paulo }
30795b9c547cSRui Paulo
30805b9c547cSRui Paulo
hostapd_ctrl_iface_eapol_reauth(struct hostapd_data * hapd,const char * cmd)3081325151a3SRui Paulo static int hostapd_ctrl_iface_eapol_reauth(struct hostapd_data *hapd,
3082325151a3SRui Paulo const char *cmd)
308339beb93cSSam Leffler {
3084325151a3SRui Paulo u8 addr[ETH_ALEN];
3085325151a3SRui Paulo struct sta_info *sta;
308639beb93cSSam Leffler
3087325151a3SRui Paulo if (hwaddr_aton(cmd, addr))
3088325151a3SRui Paulo return -1;
308939beb93cSSam Leffler
3090325151a3SRui Paulo sta = ap_get_sta(hapd, addr);
3091325151a3SRui Paulo if (!sta || !sta->eapol_sm)
3092325151a3SRui Paulo return -1;
3093325151a3SRui Paulo
3094325151a3SRui Paulo eapol_auth_reauthenticate(sta->eapol_sm);
3095325151a3SRui Paulo return 0;
30965b9c547cSRui Paulo }
3097325151a3SRui Paulo
3098325151a3SRui Paulo
hostapd_ctrl_iface_eapol_set(struct hostapd_data * hapd,char * cmd)3099325151a3SRui Paulo static int hostapd_ctrl_iface_eapol_set(struct hostapd_data *hapd, char *cmd)
3100325151a3SRui Paulo {
3101325151a3SRui Paulo u8 addr[ETH_ALEN];
3102325151a3SRui Paulo struct sta_info *sta;
3103325151a3SRui Paulo char *pos = cmd, *param;
3104325151a3SRui Paulo
3105325151a3SRui Paulo if (hwaddr_aton(pos, addr) || pos[17] != ' ')
3106325151a3SRui Paulo return -1;
3107325151a3SRui Paulo pos += 18;
3108325151a3SRui Paulo param = pos;
3109325151a3SRui Paulo pos = os_strchr(pos, ' ');
3110325151a3SRui Paulo if (!pos)
3111325151a3SRui Paulo return -1;
3112325151a3SRui Paulo *pos++ = '\0';
3113325151a3SRui Paulo
3114325151a3SRui Paulo sta = ap_get_sta(hapd, addr);
3115325151a3SRui Paulo if (!sta || !sta->eapol_sm)
3116325151a3SRui Paulo return -1;
3117325151a3SRui Paulo
3118325151a3SRui Paulo return eapol_auth_set_conf(sta->eapol_sm, param, pos);
311939beb93cSSam Leffler }
312039beb93cSSam Leffler
3121325151a3SRui Paulo
hostapd_ctrl_iface_log_level(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)3122325151a3SRui Paulo static int hostapd_ctrl_iface_log_level(struct hostapd_data *hapd, char *cmd,
3123325151a3SRui Paulo char *buf, size_t buflen)
3124325151a3SRui Paulo {
3125325151a3SRui Paulo char *pos, *end, *stamp;
3126325151a3SRui Paulo int ret;
3127325151a3SRui Paulo
3128325151a3SRui Paulo /* cmd: "LOG_LEVEL [<level>]" */
3129325151a3SRui Paulo if (*cmd == '\0') {
3130325151a3SRui Paulo pos = buf;
3131325151a3SRui Paulo end = buf + buflen;
3132325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "Current level: %s\n"
3133325151a3SRui Paulo "Timestamp: %d\n",
3134325151a3SRui Paulo debug_level_str(wpa_debug_level),
3135325151a3SRui Paulo wpa_debug_timestamp);
3136325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
3137325151a3SRui Paulo ret = 0;
3138325151a3SRui Paulo
3139325151a3SRui Paulo return ret;
3140325151a3SRui Paulo }
3141325151a3SRui Paulo
3142325151a3SRui Paulo while (*cmd == ' ')
3143325151a3SRui Paulo cmd++;
3144325151a3SRui Paulo
3145325151a3SRui Paulo stamp = os_strchr(cmd, ' ');
3146325151a3SRui Paulo if (stamp) {
3147325151a3SRui Paulo *stamp++ = '\0';
3148325151a3SRui Paulo while (*stamp == ' ') {
3149325151a3SRui Paulo stamp++;
3150325151a3SRui Paulo }
3151325151a3SRui Paulo }
3152325151a3SRui Paulo
3153325151a3SRui Paulo if (os_strlen(cmd)) {
3154325151a3SRui Paulo int level = str_to_debug_level(cmd);
3155325151a3SRui Paulo if (level < 0)
3156325151a3SRui Paulo return -1;
3157325151a3SRui Paulo wpa_debug_level = level;
3158325151a3SRui Paulo }
3159325151a3SRui Paulo
3160325151a3SRui Paulo if (stamp && os_strlen(stamp))
3161325151a3SRui Paulo wpa_debug_timestamp = atoi(stamp);
3162325151a3SRui Paulo
3163325151a3SRui Paulo os_memcpy(buf, "OK\n", 3);
3164325151a3SRui Paulo return 3;
3165325151a3SRui Paulo }
3166325151a3SRui Paulo
3167325151a3SRui Paulo
3168325151a3SRui Paulo #ifdef NEED_AP_MLME
hostapd_ctrl_iface_track_sta_list(struct hostapd_data * hapd,char * buf,size_t buflen)3169325151a3SRui Paulo static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
3170325151a3SRui Paulo char *buf, size_t buflen)
3171325151a3SRui Paulo {
3172325151a3SRui Paulo struct hostapd_iface *iface = hapd->iface;
3173325151a3SRui Paulo char *pos, *end;
3174325151a3SRui Paulo struct hostapd_sta_info *info;
3175325151a3SRui Paulo struct os_reltime now;
3176325151a3SRui Paulo
3177780fb4a2SCy Schubert if (!iface->num_sta_seen)
3178780fb4a2SCy Schubert return 0;
3179780fb4a2SCy Schubert
3180325151a3SRui Paulo sta_track_expire(iface, 0);
3181325151a3SRui Paulo
3182325151a3SRui Paulo pos = buf;
3183325151a3SRui Paulo end = buf + buflen;
3184325151a3SRui Paulo
3185325151a3SRui Paulo os_get_reltime(&now);
3186325151a3SRui Paulo dl_list_for_each_reverse(info, &iface->sta_seen,
3187325151a3SRui Paulo struct hostapd_sta_info, list) {
3188325151a3SRui Paulo struct os_reltime age;
3189325151a3SRui Paulo int ret;
3190325151a3SRui Paulo
3191325151a3SRui Paulo os_reltime_sub(&now, &info->last_seen, &age);
319285732ac8SCy Schubert ret = os_snprintf(pos, end - pos, MACSTR " %u %d\n",
319385732ac8SCy Schubert MAC2STR(info->addr), (unsigned int) age.sec,
319485732ac8SCy Schubert info->ssi_signal);
3195325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
3196325151a3SRui Paulo break;
3197325151a3SRui Paulo pos += ret;
3198325151a3SRui Paulo }
3199325151a3SRui Paulo
3200325151a3SRui Paulo return pos - buf;
3201325151a3SRui Paulo }
3202325151a3SRui Paulo #endif /* NEED_AP_MLME */
3203325151a3SRui Paulo
3204325151a3SRui Paulo
hostapd_ctrl_iface_req_lci(struct hostapd_data * hapd,const char * cmd)3205780fb4a2SCy Schubert static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
3206780fb4a2SCy Schubert const char *cmd)
3207780fb4a2SCy Schubert {
3208780fb4a2SCy Schubert u8 addr[ETH_ALEN];
3209780fb4a2SCy Schubert
3210780fb4a2SCy Schubert if (hwaddr_aton(cmd, addr)) {
3211780fb4a2SCy Schubert wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
3212780fb4a2SCy Schubert return -1;
3213780fb4a2SCy Schubert }
3214780fb4a2SCy Schubert
3215780fb4a2SCy Schubert return hostapd_send_lci_req(hapd, addr);
3216780fb4a2SCy Schubert }
3217780fb4a2SCy Schubert
3218780fb4a2SCy Schubert
hostapd_ctrl_iface_req_range(struct hostapd_data * hapd,char * cmd)3219780fb4a2SCy Schubert static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
3220780fb4a2SCy Schubert {
3221780fb4a2SCy Schubert u8 addr[ETH_ALEN];
3222780fb4a2SCy Schubert char *token, *context = NULL;
3223780fb4a2SCy Schubert int random_interval, min_ap;
3224780fb4a2SCy Schubert u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
3225780fb4a2SCy Schubert unsigned int n_responders;
3226780fb4a2SCy Schubert
3227780fb4a2SCy Schubert token = str_token(cmd, " ", &context);
3228780fb4a2SCy Schubert if (!token || hwaddr_aton(token, addr)) {
3229780fb4a2SCy Schubert wpa_printf(MSG_INFO,
3230780fb4a2SCy Schubert "CTRL: REQ_RANGE - Bad destination address");
3231780fb4a2SCy Schubert return -1;
3232780fb4a2SCy Schubert }
3233780fb4a2SCy Schubert
3234780fb4a2SCy Schubert token = str_token(cmd, " ", &context);
3235780fb4a2SCy Schubert if (!token)
3236780fb4a2SCy Schubert return -1;
3237780fb4a2SCy Schubert
3238780fb4a2SCy Schubert random_interval = atoi(token);
3239780fb4a2SCy Schubert if (random_interval < 0 || random_interval > 0xffff)
3240780fb4a2SCy Schubert return -1;
3241780fb4a2SCy Schubert
3242780fb4a2SCy Schubert token = str_token(cmd, " ", &context);
3243780fb4a2SCy Schubert if (!token)
3244780fb4a2SCy Schubert return -1;
3245780fb4a2SCy Schubert
3246780fb4a2SCy Schubert min_ap = atoi(token);
3247780fb4a2SCy Schubert if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
3248780fb4a2SCy Schubert return -1;
3249780fb4a2SCy Schubert
3250780fb4a2SCy Schubert n_responders = 0;
3251780fb4a2SCy Schubert while ((token = str_token(cmd, " ", &context))) {
3252780fb4a2SCy Schubert if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
3253780fb4a2SCy Schubert wpa_printf(MSG_INFO,
3254780fb4a2SCy Schubert "CTRL: REQ_RANGE: Too many responders");
3255780fb4a2SCy Schubert return -1;
3256780fb4a2SCy Schubert }
3257780fb4a2SCy Schubert
3258780fb4a2SCy Schubert if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
3259780fb4a2SCy Schubert wpa_printf(MSG_INFO,
3260780fb4a2SCy Schubert "CTRL: REQ_RANGE: Bad responder address");
3261780fb4a2SCy Schubert return -1;
3262780fb4a2SCy Schubert }
3263780fb4a2SCy Schubert
3264780fb4a2SCy Schubert n_responders++;
3265780fb4a2SCy Schubert }
3266780fb4a2SCy Schubert
3267780fb4a2SCy Schubert if (!n_responders) {
3268780fb4a2SCy Schubert wpa_printf(MSG_INFO,
3269780fb4a2SCy Schubert "CTRL: REQ_RANGE - No FTM responder address");
3270780fb4a2SCy Schubert return -1;
3271780fb4a2SCy Schubert }
3272780fb4a2SCy Schubert
3273780fb4a2SCy Schubert return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
3274780fb4a2SCy Schubert responders, n_responders);
3275780fb4a2SCy Schubert }
3276780fb4a2SCy Schubert
3277780fb4a2SCy Schubert
hostapd_ctrl_iface_req_beacon(struct hostapd_data * hapd,const char * cmd,char * reply,size_t reply_size)327885732ac8SCy Schubert static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd,
327985732ac8SCy Schubert const char *cmd, char *reply,
328085732ac8SCy Schubert size_t reply_size)
328185732ac8SCy Schubert {
328285732ac8SCy Schubert u8 addr[ETH_ALEN];
328385732ac8SCy Schubert const char *pos;
328485732ac8SCy Schubert struct wpabuf *req;
328585732ac8SCy Schubert int ret;
328685732ac8SCy Schubert u8 req_mode = 0;
328785732ac8SCy Schubert
328885732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
328985732ac8SCy Schubert return -1;
329085732ac8SCy Schubert pos = os_strchr(cmd, ' ');
329185732ac8SCy Schubert if (!pos)
329285732ac8SCy Schubert return -1;
329385732ac8SCy Schubert pos++;
329485732ac8SCy Schubert if (os_strncmp(pos, "req_mode=", 9) == 0) {
329585732ac8SCy Schubert int val = hex2byte(pos + 9);
329685732ac8SCy Schubert
329785732ac8SCy Schubert if (val < 0)
329885732ac8SCy Schubert return -1;
329985732ac8SCy Schubert req_mode = val;
330085732ac8SCy Schubert pos += 11;
330185732ac8SCy Schubert pos = os_strchr(pos, ' ');
330285732ac8SCy Schubert if (!pos)
330385732ac8SCy Schubert return -1;
330485732ac8SCy Schubert pos++;
330585732ac8SCy Schubert }
330685732ac8SCy Schubert req = wpabuf_parse_bin(pos);
330785732ac8SCy Schubert if (!req)
330885732ac8SCy Schubert return -1;
330985732ac8SCy Schubert
331085732ac8SCy Schubert ret = hostapd_send_beacon_req(hapd, addr, req_mode, req);
331185732ac8SCy Schubert wpabuf_free(req);
331285732ac8SCy Schubert if (ret >= 0)
331385732ac8SCy Schubert ret = os_snprintf(reply, reply_size, "%d", ret);
331485732ac8SCy Schubert return ret;
331585732ac8SCy Schubert }
331685732ac8SCy Schubert
331785732ac8SCy Schubert
hostapd_ctrl_iface_req_link_measurement(struct hostapd_data * hapd,const char * cmd,char * reply,size_t reply_size)3318*a90b9d01SCy Schubert static int hostapd_ctrl_iface_req_link_measurement(struct hostapd_data *hapd,
3319*a90b9d01SCy Schubert const char *cmd, char *reply,
3320*a90b9d01SCy Schubert size_t reply_size)
3321*a90b9d01SCy Schubert {
3322*a90b9d01SCy Schubert u8 addr[ETH_ALEN];
3323*a90b9d01SCy Schubert int ret;
3324*a90b9d01SCy Schubert
3325*a90b9d01SCy Schubert if (hwaddr_aton(cmd, addr)) {
3326*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
3327*a90b9d01SCy Schubert "CTRL: REQ_LINK_MEASUREMENT: Invalid MAC address");
3328*a90b9d01SCy Schubert return -1;
3329*a90b9d01SCy Schubert }
3330*a90b9d01SCy Schubert
3331*a90b9d01SCy Schubert ret = hostapd_send_link_measurement_req(hapd, addr);
3332*a90b9d01SCy Schubert if (ret >= 0)
3333*a90b9d01SCy Schubert ret = os_snprintf(reply, reply_size, "%d", ret);
3334*a90b9d01SCy Schubert return ret;
3335*a90b9d01SCy Schubert }
3336*a90b9d01SCy Schubert
3337*a90b9d01SCy Schubert
hostapd_ctrl_iface_show_neighbor(struct hostapd_data * hapd,char * buf,size_t buflen)3338c1d255d3SCy Schubert static int hostapd_ctrl_iface_show_neighbor(struct hostapd_data *hapd,
3339c1d255d3SCy Schubert char *buf, size_t buflen)
3340c1d255d3SCy Schubert {
3341c1d255d3SCy Schubert if (!(hapd->conf->radio_measurements[0] &
3342c1d255d3SCy Schubert WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
3343c1d255d3SCy Schubert wpa_printf(MSG_ERROR,
3344c1d255d3SCy Schubert "CTRL: SHOW_NEIGHBOR: Neighbor report is not enabled");
3345c1d255d3SCy Schubert return -1;
3346c1d255d3SCy Schubert }
3347c1d255d3SCy Schubert
3348c1d255d3SCy Schubert return hostapd_neighbor_show(hapd, buf, buflen);
3349c1d255d3SCy Schubert }
3350c1d255d3SCy Schubert
3351c1d255d3SCy Schubert
hostapd_ctrl_iface_set_neighbor(struct hostapd_data * hapd,char * buf)3352780fb4a2SCy Schubert static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
3353780fb4a2SCy Schubert {
3354780fb4a2SCy Schubert struct wpa_ssid_value ssid;
3355780fb4a2SCy Schubert u8 bssid[ETH_ALEN];
3356780fb4a2SCy Schubert struct wpabuf *nr, *lci = NULL, *civic = NULL;
335785732ac8SCy Schubert int stationary = 0;
33584b72b91aSCy Schubert int bss_parameters = 0;
3359780fb4a2SCy Schubert char *tmp;
33604b72b91aSCy Schubert int ret = -1;
3361780fb4a2SCy Schubert
3362780fb4a2SCy Schubert if (!(hapd->conf->radio_measurements[0] &
3363780fb4a2SCy Schubert WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
3364780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3365780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
3366780fb4a2SCy Schubert return -1;
3367780fb4a2SCy Schubert }
3368780fb4a2SCy Schubert
3369780fb4a2SCy Schubert if (hwaddr_aton(buf, bssid)) {
3370780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
3371780fb4a2SCy Schubert return -1;
3372780fb4a2SCy Schubert }
3373780fb4a2SCy Schubert
3374780fb4a2SCy Schubert tmp = os_strstr(buf, "ssid=");
3375780fb4a2SCy Schubert if (!tmp || ssid_parse(tmp + 5, &ssid)) {
3376780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3377780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Bad or missing SSID");
3378780fb4a2SCy Schubert return -1;
3379780fb4a2SCy Schubert }
3380780fb4a2SCy Schubert buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
3381780fb4a2SCy Schubert if (!buf)
3382780fb4a2SCy Schubert return -1;
3383780fb4a2SCy Schubert
3384780fb4a2SCy Schubert tmp = os_strstr(buf, "nr=");
3385780fb4a2SCy Schubert if (!tmp) {
3386780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3387780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
3388780fb4a2SCy Schubert return -1;
3389780fb4a2SCy Schubert }
3390780fb4a2SCy Schubert
3391780fb4a2SCy Schubert buf = os_strchr(tmp, ' ');
3392780fb4a2SCy Schubert if (buf)
3393780fb4a2SCy Schubert *buf++ = '\0';
3394780fb4a2SCy Schubert
3395780fb4a2SCy Schubert nr = wpabuf_parse_bin(tmp + 3);
3396780fb4a2SCy Schubert if (!nr) {
3397780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3398780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
3399780fb4a2SCy Schubert return -1;
3400780fb4a2SCy Schubert }
3401780fb4a2SCy Schubert
3402780fb4a2SCy Schubert if (!buf)
3403780fb4a2SCy Schubert goto set;
3404780fb4a2SCy Schubert
3405780fb4a2SCy Schubert tmp = os_strstr(buf, "lci=");
3406780fb4a2SCy Schubert if (tmp) {
3407780fb4a2SCy Schubert buf = os_strchr(tmp, ' ');
3408780fb4a2SCy Schubert if (buf)
3409780fb4a2SCy Schubert *buf++ = '\0';
3410780fb4a2SCy Schubert lci = wpabuf_parse_bin(tmp + 4);
3411780fb4a2SCy Schubert if (!lci) {
3412780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3413780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Bad LCI subelement");
34144b72b91aSCy Schubert goto fail;
3415780fb4a2SCy Schubert }
3416780fb4a2SCy Schubert }
3417780fb4a2SCy Schubert
3418780fb4a2SCy Schubert if (!buf)
3419780fb4a2SCy Schubert goto set;
3420780fb4a2SCy Schubert
3421780fb4a2SCy Schubert tmp = os_strstr(buf, "civic=");
3422780fb4a2SCy Schubert if (tmp) {
3423780fb4a2SCy Schubert buf = os_strchr(tmp, ' ');
3424780fb4a2SCy Schubert if (buf)
3425780fb4a2SCy Schubert *buf++ = '\0';
3426780fb4a2SCy Schubert civic = wpabuf_parse_bin(tmp + 6);
3427780fb4a2SCy Schubert if (!civic) {
3428780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3429780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Bad civic subelement");
34304b72b91aSCy Schubert goto fail;
3431780fb4a2SCy Schubert }
3432780fb4a2SCy Schubert }
3433780fb4a2SCy Schubert
343485732ac8SCy Schubert if (!buf)
343585732ac8SCy Schubert goto set;
343685732ac8SCy Schubert
343785732ac8SCy Schubert if (os_strstr(buf, "stat"))
343885732ac8SCy Schubert stationary = 1;
343985732ac8SCy Schubert
34404b72b91aSCy Schubert tmp = os_strstr(buf, "bss_parameter=");
34414b72b91aSCy Schubert if (tmp) {
34424b72b91aSCy Schubert bss_parameters = atoi(tmp + 14);
34434b72b91aSCy Schubert if (bss_parameters < 0 || bss_parameters > 0xff) {
34444b72b91aSCy Schubert wpa_printf(MSG_ERROR,
34454b72b91aSCy Schubert "CTRL: SET_NEIGHBOR: Bad bss_parameters subelement");
34464b72b91aSCy Schubert goto fail;
34474b72b91aSCy Schubert }
34484b72b91aSCy Schubert }
34494b72b91aSCy Schubert
3450780fb4a2SCy Schubert set:
345185732ac8SCy Schubert ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic,
34524b72b91aSCy Schubert stationary, bss_parameters);
3453780fb4a2SCy Schubert
34544b72b91aSCy Schubert fail:
3455780fb4a2SCy Schubert wpabuf_free(nr);
3456780fb4a2SCy Schubert wpabuf_free(lci);
3457780fb4a2SCy Schubert wpabuf_free(civic);
3458780fb4a2SCy Schubert
3459780fb4a2SCy Schubert return ret;
3460780fb4a2SCy Schubert }
3461780fb4a2SCy Schubert
3462780fb4a2SCy Schubert
hostapd_ctrl_iface_remove_neighbor(struct hostapd_data * hapd,char * buf)3463780fb4a2SCy Schubert static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
3464780fb4a2SCy Schubert char *buf)
3465780fb4a2SCy Schubert {
3466780fb4a2SCy Schubert struct wpa_ssid_value ssid;
3467c1d255d3SCy Schubert struct wpa_ssid_value *ssidp = NULL;
3468780fb4a2SCy Schubert u8 bssid[ETH_ALEN];
3469780fb4a2SCy Schubert char *tmp;
3470780fb4a2SCy Schubert
3471780fb4a2SCy Schubert if (hwaddr_aton(buf, bssid)) {
3472780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
3473780fb4a2SCy Schubert return -1;
3474780fb4a2SCy Schubert }
3475780fb4a2SCy Schubert
3476780fb4a2SCy Schubert tmp = os_strstr(buf, "ssid=");
3477c1d255d3SCy Schubert if (tmp) {
3478c1d255d3SCy Schubert ssidp = &ssid;
3479c1d255d3SCy Schubert if (ssid_parse(tmp + 5, &ssid)) {
3480780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3481c1d255d3SCy Schubert "CTRL: REMOVE_NEIGHBOR: Bad SSID");
3482780fb4a2SCy Schubert return -1;
3483780fb4a2SCy Schubert }
3484c1d255d3SCy Schubert }
3485780fb4a2SCy Schubert
3486c1d255d3SCy Schubert return hostapd_neighbor_remove(hapd, bssid, ssidp);
3487780fb4a2SCy Schubert }
3488780fb4a2SCy Schubert
3489780fb4a2SCy Schubert
hostapd_ctrl_driver_flags(struct hostapd_iface * iface,char * buf,size_t buflen)3490780fb4a2SCy Schubert static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
3491780fb4a2SCy Schubert size_t buflen)
3492780fb4a2SCy Schubert {
3493780fb4a2SCy Schubert int ret, i;
3494780fb4a2SCy Schubert char *pos, *end;
3495780fb4a2SCy Schubert
3496780fb4a2SCy Schubert ret = os_snprintf(buf, buflen, "%016llX:\n",
3497780fb4a2SCy Schubert (long long unsigned) iface->drv_flags);
3498780fb4a2SCy Schubert if (os_snprintf_error(buflen, ret))
3499780fb4a2SCy Schubert return -1;
3500780fb4a2SCy Schubert
3501780fb4a2SCy Schubert pos = buf + ret;
3502780fb4a2SCy Schubert end = buf + buflen;
3503780fb4a2SCy Schubert
3504780fb4a2SCy Schubert for (i = 0; i < 64; i++) {
3505780fb4a2SCy Schubert if (iface->drv_flags & (1LLU << i)) {
3506780fb4a2SCy Schubert ret = os_snprintf(pos, end - pos, "%s\n",
3507780fb4a2SCy Schubert driver_flag_to_string(1LLU << i));
3508780fb4a2SCy Schubert if (os_snprintf_error(end - pos, ret))
3509780fb4a2SCy Schubert return -1;
3510780fb4a2SCy Schubert pos += ret;
3511780fb4a2SCy Schubert }
3512780fb4a2SCy Schubert }
3513780fb4a2SCy Schubert
3514780fb4a2SCy Schubert return pos - buf;
3515780fb4a2SCy Schubert }
3516780fb4a2SCy Schubert
3517780fb4a2SCy Schubert
hostapd_ctrl_driver_flags2(struct hostapd_iface * iface,char * buf,size_t buflen)3518c1d255d3SCy Schubert static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf,
3519c1d255d3SCy Schubert size_t buflen)
3520c1d255d3SCy Schubert {
3521c1d255d3SCy Schubert int ret, i;
3522c1d255d3SCy Schubert char *pos, *end;
3523c1d255d3SCy Schubert
3524c1d255d3SCy Schubert ret = os_snprintf(buf, buflen, "%016llX:\n",
3525c1d255d3SCy Schubert (long long unsigned) iface->drv_flags2);
3526c1d255d3SCy Schubert if (os_snprintf_error(buflen, ret))
3527c1d255d3SCy Schubert return -1;
3528c1d255d3SCy Schubert
3529c1d255d3SCy Schubert pos = buf + ret;
3530c1d255d3SCy Schubert end = buf + buflen;
3531c1d255d3SCy Schubert
3532c1d255d3SCy Schubert for (i = 0; i < 64; i++) {
3533c1d255d3SCy Schubert if (iface->drv_flags2 & (1LLU << i)) {
3534c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos, "%s\n",
3535c1d255d3SCy Schubert driver_flag2_to_string(1LLU << i));
3536c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
3537c1d255d3SCy Schubert return -1;
3538c1d255d3SCy Schubert pos += ret;
3539c1d255d3SCy Schubert }
3540c1d255d3SCy Schubert }
3541c1d255d3SCy Schubert
3542c1d255d3SCy Schubert return pos - buf;
3543c1d255d3SCy Schubert }
3544c1d255d3SCy Schubert
3545c1d255d3SCy Schubert
hostapd_ctrl_iface_get_capability(struct hostapd_data * hapd,const char * field,char * buf,size_t buflen)35464bc52338SCy Schubert static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
35474bc52338SCy Schubert const char *field, char *buf,
35484bc52338SCy Schubert size_t buflen)
35494bc52338SCy Schubert {
35504bc52338SCy Schubert wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field);
35514bc52338SCy Schubert
35524bc52338SCy Schubert #ifdef CONFIG_DPP
35534bc52338SCy Schubert if (os_strcmp(field, "dpp") == 0) {
35544bc52338SCy Schubert int res;
35554bc52338SCy Schubert
355632a95656SCy Schubert #ifdef CONFIG_DPP3
355732a95656SCy Schubert res = os_snprintf(buf, buflen, "DPP=3");
355832a95656SCy Schubert #elif defined(CONFIG_DPP2)
35594bc52338SCy Schubert res = os_snprintf(buf, buflen, "DPP=2");
35604bc52338SCy Schubert #else /* CONFIG_DPP2 */
35614bc52338SCy Schubert res = os_snprintf(buf, buflen, "DPP=1");
35624bc52338SCy Schubert #endif /* CONFIG_DPP2 */
35634bc52338SCy Schubert if (os_snprintf_error(buflen, res))
35644bc52338SCy Schubert return -1;
35654bc52338SCy Schubert return res;
35664bc52338SCy Schubert }
35674bc52338SCy Schubert #endif /* CONFIG_DPP */
35684bc52338SCy Schubert
35694bc52338SCy Schubert wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
35704bc52338SCy Schubert field);
35714bc52338SCy Schubert
35724bc52338SCy Schubert return -1;
35734bc52338SCy Schubert }
35744bc52338SCy Schubert
35754bc52338SCy Schubert
3576c1d255d3SCy Schubert #ifdef ANDROID
hostapd_ctrl_iface_driver_cmd(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)3577c1d255d3SCy Schubert static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd,
3578c1d255d3SCy Schubert char *buf, size_t buflen)
3579c1d255d3SCy Schubert {
3580c1d255d3SCy Schubert int ret;
3581c1d255d3SCy Schubert
3582c1d255d3SCy Schubert ret = hostapd_drv_driver_cmd(hapd, cmd, buf, buflen);
3583c1d255d3SCy Schubert if (ret == 0) {
3584c1d255d3SCy Schubert ret = os_snprintf(buf, buflen, "%s\n", "OK");
3585c1d255d3SCy Schubert if (os_snprintf_error(buflen, ret))
3586c1d255d3SCy Schubert ret = -1;
3587c1d255d3SCy Schubert }
3588c1d255d3SCy Schubert return ret;
3589c1d255d3SCy Schubert }
3590c1d255d3SCy Schubert #endif /* ANDROID */
3591c1d255d3SCy Schubert
3592c1d255d3SCy Schubert
3593*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
3594*a90b9d01SCy Schubert
hostapd_ctrl_iface_enable_mld(struct hostapd_iface * iface)3595*a90b9d01SCy Schubert static int hostapd_ctrl_iface_enable_mld(struct hostapd_iface *iface)
3596*a90b9d01SCy Schubert {
3597*a90b9d01SCy Schubert unsigned int i;
3598*a90b9d01SCy Schubert
3599*a90b9d01SCy Schubert if (!iface || !iface->bss[0]->conf->mld_ap) {
3600*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
3601*a90b9d01SCy Schubert "Trying to enable AP MLD on an interface that is not affiliated with an AP MLD");
3602*a90b9d01SCy Schubert return -1;
3603*a90b9d01SCy Schubert }
3604*a90b9d01SCy Schubert
3605*a90b9d01SCy Schubert for (i = 0; i < iface->interfaces->count; ++i) {
3606*a90b9d01SCy Schubert struct hostapd_iface *h_iface = iface->interfaces->iface[i];
3607*a90b9d01SCy Schubert struct hostapd_data *h_hapd = h_iface->bss[0];
3608*a90b9d01SCy Schubert
3609*a90b9d01SCy Schubert if (!hostapd_is_ml_partner(h_hapd, iface->bss[0]))
3610*a90b9d01SCy Schubert continue;
3611*a90b9d01SCy Schubert
3612*a90b9d01SCy Schubert if (hostapd_enable_iface(h_iface)) {
3613*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "Enabling of AP MLD failed");
3614*a90b9d01SCy Schubert return -1;
3615*a90b9d01SCy Schubert }
3616*a90b9d01SCy Schubert }
3617*a90b9d01SCy Schubert return 0;
3618*a90b9d01SCy Schubert }
3619*a90b9d01SCy Schubert
3620*a90b9d01SCy Schubert
hostapd_disable_iface_bss(struct hostapd_iface * iface)3621*a90b9d01SCy Schubert static void hostapd_disable_iface_bss(struct hostapd_iface *iface)
3622*a90b9d01SCy Schubert {
3623*a90b9d01SCy Schubert unsigned int i;
3624*a90b9d01SCy Schubert
3625*a90b9d01SCy Schubert for (i = 0; i < iface->num_bss; i++)
3626*a90b9d01SCy Schubert hostapd_bss_deinit_no_free(iface->bss[i]);
3627*a90b9d01SCy Schubert }
3628*a90b9d01SCy Schubert
3629*a90b9d01SCy Schubert
hostapd_ctrl_iface_disable_mld(struct hostapd_iface * iface)3630*a90b9d01SCy Schubert static int hostapd_ctrl_iface_disable_mld(struct hostapd_iface *iface)
3631*a90b9d01SCy Schubert {
3632*a90b9d01SCy Schubert unsigned int i;
3633*a90b9d01SCy Schubert
3634*a90b9d01SCy Schubert if (!iface || !iface->bss[0]->conf->mld_ap) {
3635*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
3636*a90b9d01SCy Schubert "Trying to disable AP MLD on an interface that is not affiliated with an AP MLD.");
3637*a90b9d01SCy Schubert return -1;
3638*a90b9d01SCy Schubert }
3639*a90b9d01SCy Schubert
3640*a90b9d01SCy Schubert /* First, disable BSSs before stopping beaconing and doing driver
3641*a90b9d01SCy Schubert * deinit so that the broadcast Deauthentication frames go out. */
3642*a90b9d01SCy Schubert
3643*a90b9d01SCy Schubert for (i = 0; i < iface->interfaces->count; ++i) {
3644*a90b9d01SCy Schubert struct hostapd_iface *h_iface = iface->interfaces->iface[i];
3645*a90b9d01SCy Schubert struct hostapd_data *h_hapd = h_iface->bss[0];
3646*a90b9d01SCy Schubert
3647*a90b9d01SCy Schubert if (!hostapd_is_ml_partner(h_hapd, iface->bss[0]))
3648*a90b9d01SCy Schubert continue;
3649*a90b9d01SCy Schubert
3650*a90b9d01SCy Schubert hostapd_disable_iface_bss(iface);
3651*a90b9d01SCy Schubert }
3652*a90b9d01SCy Schubert
3653*a90b9d01SCy Schubert /* Then, fully disable interfaces */
3654*a90b9d01SCy Schubert for (i = 0; i < iface->interfaces->count; ++i) {
3655*a90b9d01SCy Schubert struct hostapd_iface *h_iface = iface->interfaces->iface[i];
3656*a90b9d01SCy Schubert struct hostapd_data *h_hapd = h_iface->bss[0];
3657*a90b9d01SCy Schubert
3658*a90b9d01SCy Schubert if (!hostapd_is_ml_partner(h_hapd, iface->bss[0]))
3659*a90b9d01SCy Schubert continue;
3660*a90b9d01SCy Schubert
3661*a90b9d01SCy Schubert if (hostapd_disable_iface(h_iface)) {
3662*a90b9d01SCy Schubert wpa_printf(MSG_ERROR, "Disabling AP MLD failed");
3663*a90b9d01SCy Schubert return -1;
3664*a90b9d01SCy Schubert }
3665*a90b9d01SCy Schubert }
3666*a90b9d01SCy Schubert
3667*a90b9d01SCy Schubert return 0;
3668*a90b9d01SCy Schubert }
3669*a90b9d01SCy Schubert
3670*a90b9d01SCy Schubert
3671*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
hostapd_ctrl_iface_link_remove(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)3672*a90b9d01SCy Schubert static int hostapd_ctrl_iface_link_remove(struct hostapd_data *hapd, char *cmd,
3673*a90b9d01SCy Schubert char *buf, size_t buflen)
3674*a90b9d01SCy Schubert {
3675*a90b9d01SCy Schubert int ret;
3676*a90b9d01SCy Schubert u32 count = atoi(cmd);
3677*a90b9d01SCy Schubert
3678*a90b9d01SCy Schubert if (!count)
3679*a90b9d01SCy Schubert count = 1;
3680*a90b9d01SCy Schubert
3681*a90b9d01SCy Schubert ret = hostapd_link_remove(hapd, count);
3682*a90b9d01SCy Schubert if (ret == 0) {
3683*a90b9d01SCy Schubert ret = os_snprintf(buf, buflen, "%s\n", "OK");
3684*a90b9d01SCy Schubert if (os_snprintf_error(buflen, ret))
3685*a90b9d01SCy Schubert ret = -1;
3686*a90b9d01SCy Schubert else
3687*a90b9d01SCy Schubert ret = 0;
3688*a90b9d01SCy Schubert }
3689*a90b9d01SCy Schubert
3690*a90b9d01SCy Schubert return ret;
3691*a90b9d01SCy Schubert }
3692*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
3693*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
3694*a90b9d01SCy Schubert
3695*a90b9d01SCy Schubert
3696*a90b9d01SCy Schubert #ifdef CONFIG_NAN_USD
3697*a90b9d01SCy Schubert
hostapd_ctrl_nan_publish(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)3698*a90b9d01SCy Schubert static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd,
3699*a90b9d01SCy Schubert char *buf, size_t buflen)
3700*a90b9d01SCy Schubert {
3701*a90b9d01SCy Schubert char *token, *context = NULL;
3702*a90b9d01SCy Schubert int publish_id;
3703*a90b9d01SCy Schubert struct nan_publish_params params;
3704*a90b9d01SCy Schubert const char *service_name = NULL;
3705*a90b9d01SCy Schubert struct wpabuf *ssi = NULL;
3706*a90b9d01SCy Schubert int ret = -1;
3707*a90b9d01SCy Schubert enum nan_service_protocol_type srv_proto_type = 0;
3708*a90b9d01SCy Schubert
3709*a90b9d01SCy Schubert os_memset(¶ms, 0, sizeof(params));
3710*a90b9d01SCy Schubert /* USD shall use both solicited and unsolicited transmissions */
3711*a90b9d01SCy Schubert params.unsolicited = true;
3712*a90b9d01SCy Schubert params.solicited = true;
3713*a90b9d01SCy Schubert /* USD shall require FSD without GAS */
3714*a90b9d01SCy Schubert params.fsd = true;
3715*a90b9d01SCy Schubert
3716*a90b9d01SCy Schubert while ((token = str_token(cmd, " ", &context))) {
3717*a90b9d01SCy Schubert if (os_strncmp(token, "service_name=", 13) == 0) {
3718*a90b9d01SCy Schubert service_name = token + 13;
3719*a90b9d01SCy Schubert continue;
3720*a90b9d01SCy Schubert }
3721*a90b9d01SCy Schubert
3722*a90b9d01SCy Schubert if (os_strncmp(token, "ttl=", 4) == 0) {
3723*a90b9d01SCy Schubert params.ttl = atoi(token + 4);
3724*a90b9d01SCy Schubert continue;
3725*a90b9d01SCy Schubert }
3726*a90b9d01SCy Schubert
3727*a90b9d01SCy Schubert if (os_strncmp(token, "srv_proto_type=", 15) == 0) {
3728*a90b9d01SCy Schubert srv_proto_type = atoi(token + 15);
3729*a90b9d01SCy Schubert continue;
3730*a90b9d01SCy Schubert }
3731*a90b9d01SCy Schubert
3732*a90b9d01SCy Schubert if (os_strncmp(token, "ssi=", 4) == 0) {
3733*a90b9d01SCy Schubert if (ssi)
3734*a90b9d01SCy Schubert goto fail;
3735*a90b9d01SCy Schubert ssi = wpabuf_parse_bin(token + 4);
3736*a90b9d01SCy Schubert if (!ssi)
3737*a90b9d01SCy Schubert goto fail;
3738*a90b9d01SCy Schubert continue;
3739*a90b9d01SCy Schubert }
3740*a90b9d01SCy Schubert
3741*a90b9d01SCy Schubert if (os_strcmp(token, "solicited=0") == 0) {
3742*a90b9d01SCy Schubert params.solicited = false;
3743*a90b9d01SCy Schubert continue;
3744*a90b9d01SCy Schubert }
3745*a90b9d01SCy Schubert
3746*a90b9d01SCy Schubert if (os_strcmp(token, "unsolicited=0") == 0) {
3747*a90b9d01SCy Schubert params.unsolicited = false;
3748*a90b9d01SCy Schubert continue;
3749*a90b9d01SCy Schubert }
3750*a90b9d01SCy Schubert
3751*a90b9d01SCy Schubert if (os_strcmp(token, "fsd=0") == 0) {
3752*a90b9d01SCy Schubert params.fsd = false;
3753*a90b9d01SCy Schubert continue;
3754*a90b9d01SCy Schubert }
3755*a90b9d01SCy Schubert
3756*a90b9d01SCy Schubert wpa_printf(MSG_INFO, "CTRL: Invalid NAN_PUBLISH parameter: %s",
3757*a90b9d01SCy Schubert token);
3758*a90b9d01SCy Schubert goto fail;
3759*a90b9d01SCy Schubert }
3760*a90b9d01SCy Schubert
3761*a90b9d01SCy Schubert publish_id = hostapd_nan_usd_publish(hapd, service_name, srv_proto_type,
3762*a90b9d01SCy Schubert ssi, ¶ms);
3763*a90b9d01SCy Schubert if (publish_id > 0)
3764*a90b9d01SCy Schubert ret = os_snprintf(buf, buflen, "%d", publish_id);
3765*a90b9d01SCy Schubert fail:
3766*a90b9d01SCy Schubert wpabuf_free(ssi);
3767*a90b9d01SCy Schubert return ret;
3768*a90b9d01SCy Schubert }
3769*a90b9d01SCy Schubert
3770*a90b9d01SCy Schubert
hostapd_ctrl_nan_cancel_publish(struct hostapd_data * hapd,char * cmd)3771*a90b9d01SCy Schubert static int hostapd_ctrl_nan_cancel_publish(struct hostapd_data *hapd,
3772*a90b9d01SCy Schubert char *cmd)
3773*a90b9d01SCy Schubert {
3774*a90b9d01SCy Schubert char *token, *context = NULL;
3775*a90b9d01SCy Schubert int publish_id = 0;
3776*a90b9d01SCy Schubert
3777*a90b9d01SCy Schubert while ((token = str_token(cmd, " ", &context))) {
3778*a90b9d01SCy Schubert if (sscanf(token, "publish_id=%i", &publish_id) == 1)
3779*a90b9d01SCy Schubert continue;
3780*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3781*a90b9d01SCy Schubert "CTRL: Invalid NAN_CANCEL_PUBLISH parameter: %s",
3782*a90b9d01SCy Schubert token);
3783*a90b9d01SCy Schubert return -1;
3784*a90b9d01SCy Schubert }
3785*a90b9d01SCy Schubert
3786*a90b9d01SCy Schubert if (publish_id <= 0) {
3787*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3788*a90b9d01SCy Schubert "CTRL: Invalid or missing NAN_CANCEL_PUBLISH publish_id");
3789*a90b9d01SCy Schubert return -1;
3790*a90b9d01SCy Schubert }
3791*a90b9d01SCy Schubert
3792*a90b9d01SCy Schubert hostapd_nan_usd_cancel_publish(hapd, publish_id);
3793*a90b9d01SCy Schubert return 0;
3794*a90b9d01SCy Schubert }
3795*a90b9d01SCy Schubert
3796*a90b9d01SCy Schubert
hostapd_ctrl_nan_update_publish(struct hostapd_data * hapd,char * cmd)3797*a90b9d01SCy Schubert static int hostapd_ctrl_nan_update_publish(struct hostapd_data *hapd,
3798*a90b9d01SCy Schubert char *cmd)
3799*a90b9d01SCy Schubert {
3800*a90b9d01SCy Schubert char *token, *context = NULL;
3801*a90b9d01SCy Schubert int publish_id = 0;
3802*a90b9d01SCy Schubert struct wpabuf *ssi = NULL;
3803*a90b9d01SCy Schubert int ret = -1;
3804*a90b9d01SCy Schubert
3805*a90b9d01SCy Schubert while ((token = str_token(cmd, " ", &context))) {
3806*a90b9d01SCy Schubert if (sscanf(token, "publish_id=%i", &publish_id) == 1)
3807*a90b9d01SCy Schubert continue;
3808*a90b9d01SCy Schubert if (os_strncmp(token, "ssi=", 4) == 0) {
3809*a90b9d01SCy Schubert if (ssi)
3810*a90b9d01SCy Schubert goto fail;
3811*a90b9d01SCy Schubert ssi = wpabuf_parse_bin(token + 4);
3812*a90b9d01SCy Schubert if (!ssi)
3813*a90b9d01SCy Schubert goto fail;
3814*a90b9d01SCy Schubert continue;
3815*a90b9d01SCy Schubert }
3816*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3817*a90b9d01SCy Schubert "CTRL: Invalid NAN_UPDATE_PUBLISH parameter: %s",
3818*a90b9d01SCy Schubert token);
3819*a90b9d01SCy Schubert goto fail;
3820*a90b9d01SCy Schubert }
3821*a90b9d01SCy Schubert
3822*a90b9d01SCy Schubert if (publish_id <= 0) {
3823*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3824*a90b9d01SCy Schubert "CTRL: Invalid or missing NAN_UPDATE_PUBLISH publish_id");
3825*a90b9d01SCy Schubert goto fail;
3826*a90b9d01SCy Schubert }
3827*a90b9d01SCy Schubert
3828*a90b9d01SCy Schubert ret = hostapd_nan_usd_update_publish(hapd, publish_id, ssi);
3829*a90b9d01SCy Schubert fail:
3830*a90b9d01SCy Schubert wpabuf_free(ssi);
3831*a90b9d01SCy Schubert return ret;
3832*a90b9d01SCy Schubert }
3833*a90b9d01SCy Schubert
3834*a90b9d01SCy Schubert
hostapd_ctrl_nan_subscribe(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)3835*a90b9d01SCy Schubert static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd,
3836*a90b9d01SCy Schubert char *buf, size_t buflen)
3837*a90b9d01SCy Schubert {
3838*a90b9d01SCy Schubert char *token, *context = NULL;
3839*a90b9d01SCy Schubert int subscribe_id;
3840*a90b9d01SCy Schubert struct nan_subscribe_params params;
3841*a90b9d01SCy Schubert const char *service_name = NULL;
3842*a90b9d01SCy Schubert struct wpabuf *ssi = NULL;
3843*a90b9d01SCy Schubert int ret = -1;
3844*a90b9d01SCy Schubert enum nan_service_protocol_type srv_proto_type = 0;
3845*a90b9d01SCy Schubert
3846*a90b9d01SCy Schubert os_memset(¶ms, 0, sizeof(params));
3847*a90b9d01SCy Schubert
3848*a90b9d01SCy Schubert while ((token = str_token(cmd, " ", &context))) {
3849*a90b9d01SCy Schubert if (os_strncmp(token, "service_name=", 13) == 0) {
3850*a90b9d01SCy Schubert service_name = token + 13;
3851*a90b9d01SCy Schubert continue;
3852*a90b9d01SCy Schubert }
3853*a90b9d01SCy Schubert
3854*a90b9d01SCy Schubert if (os_strcmp(token, "active=1") == 0) {
3855*a90b9d01SCy Schubert params.active = true;
3856*a90b9d01SCy Schubert continue;
3857*a90b9d01SCy Schubert }
3858*a90b9d01SCy Schubert
3859*a90b9d01SCy Schubert if (os_strncmp(token, "ttl=", 4) == 0) {
3860*a90b9d01SCy Schubert params.ttl = atoi(token + 4);
3861*a90b9d01SCy Schubert continue;
3862*a90b9d01SCy Schubert }
3863*a90b9d01SCy Schubert
3864*a90b9d01SCy Schubert if (os_strncmp(token, "srv_proto_type=", 15) == 0) {
3865*a90b9d01SCy Schubert srv_proto_type = atoi(token + 15);
3866*a90b9d01SCy Schubert continue;
3867*a90b9d01SCy Schubert }
3868*a90b9d01SCy Schubert
3869*a90b9d01SCy Schubert if (os_strncmp(token, "ssi=", 4) == 0) {
3870*a90b9d01SCy Schubert if (ssi)
3871*a90b9d01SCy Schubert goto fail;
3872*a90b9d01SCy Schubert ssi = wpabuf_parse_bin(token + 4);
3873*a90b9d01SCy Schubert if (!ssi)
3874*a90b9d01SCy Schubert goto fail;
3875*a90b9d01SCy Schubert continue;
3876*a90b9d01SCy Schubert }
3877*a90b9d01SCy Schubert
3878*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3879*a90b9d01SCy Schubert "CTRL: Invalid NAN_SUBSCRIBE parameter: %s",
3880*a90b9d01SCy Schubert token);
3881*a90b9d01SCy Schubert goto fail;
3882*a90b9d01SCy Schubert }
3883*a90b9d01SCy Schubert
3884*a90b9d01SCy Schubert subscribe_id = hostapd_nan_usd_subscribe(hapd, service_name,
3885*a90b9d01SCy Schubert srv_proto_type, ssi,
3886*a90b9d01SCy Schubert ¶ms);
3887*a90b9d01SCy Schubert if (subscribe_id > 0)
3888*a90b9d01SCy Schubert ret = os_snprintf(buf, buflen, "%d", subscribe_id);
3889*a90b9d01SCy Schubert fail:
3890*a90b9d01SCy Schubert wpabuf_free(ssi);
3891*a90b9d01SCy Schubert return ret;
3892*a90b9d01SCy Schubert }
3893*a90b9d01SCy Schubert
3894*a90b9d01SCy Schubert
hostapd_ctrl_nan_cancel_subscribe(struct hostapd_data * hapd,char * cmd)3895*a90b9d01SCy Schubert static int hostapd_ctrl_nan_cancel_subscribe(struct hostapd_data *hapd,
3896*a90b9d01SCy Schubert char *cmd)
3897*a90b9d01SCy Schubert {
3898*a90b9d01SCy Schubert char *token, *context = NULL;
3899*a90b9d01SCy Schubert int subscribe_id = 0;
3900*a90b9d01SCy Schubert
3901*a90b9d01SCy Schubert while ((token = str_token(cmd, " ", &context))) {
3902*a90b9d01SCy Schubert if (sscanf(token, "subscribe_id=%i", &subscribe_id) == 1)
3903*a90b9d01SCy Schubert continue;
3904*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3905*a90b9d01SCy Schubert "CTRL: Invalid NAN_CANCEL_SUBSCRIBE parameter: %s",
3906*a90b9d01SCy Schubert token);
3907*a90b9d01SCy Schubert return -1;
3908*a90b9d01SCy Schubert }
3909*a90b9d01SCy Schubert
3910*a90b9d01SCy Schubert if (subscribe_id <= 0) {
3911*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3912*a90b9d01SCy Schubert "CTRL: Invalid or missing NAN_CANCEL_SUBSCRIBE subscribe_id");
3913*a90b9d01SCy Schubert return -1;
3914*a90b9d01SCy Schubert }
3915*a90b9d01SCy Schubert
3916*a90b9d01SCy Schubert hostapd_nan_usd_cancel_subscribe(hapd, subscribe_id);
3917*a90b9d01SCy Schubert return 0;
3918*a90b9d01SCy Schubert }
3919*a90b9d01SCy Schubert
3920*a90b9d01SCy Schubert
hostapd_ctrl_nan_transmit(struct hostapd_data * hapd,char * cmd)3921*a90b9d01SCy Schubert static int hostapd_ctrl_nan_transmit(struct hostapd_data *hapd, char *cmd)
3922*a90b9d01SCy Schubert {
3923*a90b9d01SCy Schubert char *token, *context = NULL;
3924*a90b9d01SCy Schubert int handle = 0;
3925*a90b9d01SCy Schubert int req_instance_id = 0;
3926*a90b9d01SCy Schubert struct wpabuf *ssi = NULL;
3927*a90b9d01SCy Schubert u8 peer_addr[ETH_ALEN];
3928*a90b9d01SCy Schubert int ret = -1;
3929*a90b9d01SCy Schubert
3930*a90b9d01SCy Schubert os_memset(peer_addr, 0, ETH_ALEN);
3931*a90b9d01SCy Schubert
3932*a90b9d01SCy Schubert while ((token = str_token(cmd, " ", &context))) {
3933*a90b9d01SCy Schubert if (sscanf(token, "handle=%i", &handle) == 1)
3934*a90b9d01SCy Schubert continue;
3935*a90b9d01SCy Schubert
3936*a90b9d01SCy Schubert if (sscanf(token, "req_instance_id=%i", &req_instance_id) == 1)
3937*a90b9d01SCy Schubert continue;
3938*a90b9d01SCy Schubert
3939*a90b9d01SCy Schubert if (os_strncmp(token, "address=", 8) == 0) {
3940*a90b9d01SCy Schubert if (hwaddr_aton(token + 8, peer_addr) < 0)
3941*a90b9d01SCy Schubert return -1;
3942*a90b9d01SCy Schubert continue;
3943*a90b9d01SCy Schubert }
3944*a90b9d01SCy Schubert
3945*a90b9d01SCy Schubert if (os_strncmp(token, "ssi=", 4) == 0) {
3946*a90b9d01SCy Schubert if (ssi)
3947*a90b9d01SCy Schubert goto fail;
3948*a90b9d01SCy Schubert ssi = wpabuf_parse_bin(token + 4);
3949*a90b9d01SCy Schubert if (!ssi)
3950*a90b9d01SCy Schubert goto fail;
3951*a90b9d01SCy Schubert continue;
3952*a90b9d01SCy Schubert }
3953*a90b9d01SCy Schubert
3954*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3955*a90b9d01SCy Schubert "CTRL: Invalid NAN_TRANSMIT parameter: %s",
3956*a90b9d01SCy Schubert token);
3957*a90b9d01SCy Schubert goto fail;
3958*a90b9d01SCy Schubert }
3959*a90b9d01SCy Schubert
3960*a90b9d01SCy Schubert if (handle <= 0) {
3961*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3962*a90b9d01SCy Schubert "CTRL: Invalid or missing NAN_TRANSMIT handle");
3963*a90b9d01SCy Schubert goto fail;
3964*a90b9d01SCy Schubert }
3965*a90b9d01SCy Schubert
3966*a90b9d01SCy Schubert if (is_zero_ether_addr(peer_addr)) {
3967*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
3968*a90b9d01SCy Schubert "CTRL: Invalid or missing NAN_TRANSMIT address");
3969*a90b9d01SCy Schubert goto fail;
3970*a90b9d01SCy Schubert }
3971*a90b9d01SCy Schubert
3972*a90b9d01SCy Schubert ret = hostapd_nan_usd_transmit(hapd, handle, ssi, NULL, peer_addr,
3973*a90b9d01SCy Schubert req_instance_id);
3974*a90b9d01SCy Schubert fail:
3975*a90b9d01SCy Schubert wpabuf_free(ssi);
3976*a90b9d01SCy Schubert return ret;
3977*a90b9d01SCy Schubert }
3978*a90b9d01SCy Schubert
3979*a90b9d01SCy Schubert #endif /* CONFIG_NAN_USD */
3980*a90b9d01SCy Schubert
3981*a90b9d01SCy Schubert
hostapd_ctrl_iface_receive_process(struct hostapd_data * hapd,char * buf,char * reply,int reply_size,struct sockaddr_storage * from,socklen_t fromlen)3982325151a3SRui Paulo static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
3983325151a3SRui Paulo char *buf, char *reply,
3984325151a3SRui Paulo int reply_size,
3985780fb4a2SCy Schubert struct sockaddr_storage *from,
3986325151a3SRui Paulo socklen_t fromlen)
3987325151a3SRui Paulo {
3988325151a3SRui Paulo int reply_len, res;
3989325151a3SRui Paulo
399039beb93cSSam Leffler os_memcpy(reply, "OK\n", 3);
399139beb93cSSam Leffler reply_len = 3;
399239beb93cSSam Leffler
399339beb93cSSam Leffler if (os_strcmp(buf, "PING") == 0) {
399439beb93cSSam Leffler os_memcpy(reply, "PONG\n", 5);
399539beb93cSSam Leffler reply_len = 5;
3996f05cddf9SRui Paulo } else if (os_strncmp(buf, "RELOG", 5) == 0) {
3997f05cddf9SRui Paulo if (wpa_debug_reopen_file() < 0)
3998f05cddf9SRui Paulo reply_len = -1;
3999*a90b9d01SCy Schubert } else if (os_strcmp(buf, "CLOSE_LOG") == 0) {
4000*a90b9d01SCy Schubert wpa_debug_stop_log();
400185732ac8SCy Schubert } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
400285732ac8SCy Schubert wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
40035b9c547cSRui Paulo } else if (os_strcmp(buf, "STATUS") == 0) {
40045b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_status(hapd, reply,
40055b9c547cSRui Paulo reply_size);
40065b9c547cSRui Paulo } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
40075b9c547cSRui Paulo reply_len = hostapd_drv_status(hapd, reply, reply_size);
400839beb93cSSam Leffler } else if (os_strcmp(buf, "MIB") == 0) {
400939beb93cSSam Leffler reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
401039beb93cSSam Leffler if (reply_len >= 0) {
401139beb93cSSam Leffler res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
401239beb93cSSam Leffler reply_size - reply_len);
401339beb93cSSam Leffler if (res < 0)
401439beb93cSSam Leffler reply_len = -1;
401539beb93cSSam Leffler else
401639beb93cSSam Leffler reply_len += res;
401739beb93cSSam Leffler }
401839beb93cSSam Leffler if (reply_len >= 0) {
401939beb93cSSam Leffler res = ieee802_1x_get_mib(hapd, reply + reply_len,
402039beb93cSSam Leffler reply_size - reply_len);
402139beb93cSSam Leffler if (res < 0)
402239beb93cSSam Leffler reply_len = -1;
402339beb93cSSam Leffler else
402439beb93cSSam Leffler reply_len += res;
402539beb93cSSam Leffler }
4026e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS
402739beb93cSSam Leffler if (reply_len >= 0) {
402839beb93cSSam Leffler res = radius_client_get_mib(hapd->radius,
402939beb93cSSam Leffler reply + reply_len,
403039beb93cSSam Leffler reply_size - reply_len);
403139beb93cSSam Leffler if (res < 0)
403239beb93cSSam Leffler reply_len = -1;
403339beb93cSSam Leffler else
403439beb93cSSam Leffler reply_len += res;
403539beb93cSSam Leffler }
4036e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */
40375b9c547cSRui Paulo } else if (os_strncmp(buf, "MIB ", 4) == 0) {
40385b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
40395b9c547cSRui Paulo buf + 4);
404039beb93cSSam Leffler } else if (os_strcmp(buf, "STA-FIRST") == 0) {
404139beb93cSSam Leffler reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
404239beb93cSSam Leffler reply_size);
404339beb93cSSam Leffler } else if (os_strncmp(buf, "STA ", 4) == 0) {
404439beb93cSSam Leffler reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
404539beb93cSSam Leffler reply_size);
404639beb93cSSam Leffler } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
404739beb93cSSam Leffler reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
404839beb93cSSam Leffler reply_size);
404939beb93cSSam Leffler } else if (os_strcmp(buf, "ATTACH") == 0) {
405085732ac8SCy Schubert if (hostapd_ctrl_iface_attach(hapd, from, fromlen, NULL))
405185732ac8SCy Schubert reply_len = -1;
405285732ac8SCy Schubert } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
405385732ac8SCy Schubert if (hostapd_ctrl_iface_attach(hapd, from, fromlen, buf + 7))
405439beb93cSSam Leffler reply_len = -1;
405539beb93cSSam Leffler } else if (os_strcmp(buf, "DETACH") == 0) {
4056325151a3SRui Paulo if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
405739beb93cSSam Leffler reply_len = -1;
405839beb93cSSam Leffler } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
4059325151a3SRui Paulo if (hostapd_ctrl_iface_level(hapd, from, fromlen,
406039beb93cSSam Leffler buf + 6))
406139beb93cSSam Leffler reply_len = -1;
406239beb93cSSam Leffler } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
406339beb93cSSam Leffler if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
406439beb93cSSam Leffler reply_len = -1;
4065e28a4053SRui Paulo } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
4066e28a4053SRui Paulo if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
4067e28a4053SRui Paulo reply_len = -1;
4068e28a4053SRui Paulo } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
4069e28a4053SRui Paulo if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
4070e28a4053SRui Paulo reply_len = -1;
4071780fb4a2SCy Schubert #ifdef CONFIG_TAXONOMY
4072780fb4a2SCy Schubert } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) {
4073780fb4a2SCy Schubert reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10,
4074780fb4a2SCy Schubert reply, reply_size);
4075780fb4a2SCy Schubert #endif /* CONFIG_TAXONOMY */
4076780fb4a2SCy Schubert } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
4077780fb4a2SCy Schubert if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
4078780fb4a2SCy Schubert reply_len = -1;
40795b9c547cSRui Paulo } else if (os_strcmp(buf, "STOP_AP") == 0) {
40805b9c547cSRui Paulo if (hostapd_ctrl_iface_stop_ap(hapd))
40815b9c547cSRui Paulo reply_len = -1;
4082e28a4053SRui Paulo #ifdef NEED_AP_MLME
408339beb93cSSam Leffler } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
408439beb93cSSam Leffler if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
408539beb93cSSam Leffler reply_len = -1;
4086e28a4053SRui Paulo #endif /* NEED_AP_MLME */
408739beb93cSSam Leffler #ifdef CONFIG_WPS
408839beb93cSSam Leffler } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
408939beb93cSSam Leffler if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
409039beb93cSSam Leffler reply_len = -1;
4091f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
4092f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_wps_check_pin(
4093f05cddf9SRui Paulo hapd, buf + 14, reply, reply_size);
409439beb93cSSam Leffler } else if (os_strcmp(buf, "WPS_PBC") == 0) {
4095f05cddf9SRui Paulo if (hostapd_wps_button_pushed(hapd, NULL))
409639beb93cSSam Leffler reply_len = -1;
4097f05cddf9SRui Paulo } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
4098f05cddf9SRui Paulo if (hostapd_wps_cancel(hapd))
4099e28a4053SRui Paulo reply_len = -1;
4100e28a4053SRui Paulo } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
4101e28a4053SRui Paulo reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
4102e28a4053SRui Paulo reply, reply_size);
4103f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
4104f05cddf9SRui Paulo if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
4105f05cddf9SRui Paulo reply_len = -1;
41065b9c547cSRui Paulo } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
41075b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
41085b9c547cSRui Paulo reply_size);
4109f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
4110f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
4111f05cddf9SRui Paulo if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
4112f05cddf9SRui Paulo reply_len = -1;
4113f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
4114f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
4115f05cddf9SRui Paulo hapd, buf + 21, reply, reply_size);
4116f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
4117f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_wps_nfc_token(
4118f05cddf9SRui Paulo hapd, buf + 14, reply, reply_size);
41195b9c547cSRui Paulo } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
41205b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
41215b9c547cSRui Paulo hapd, buf + 21, reply, reply_size);
41225b9c547cSRui Paulo } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
41235b9c547cSRui Paulo if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
41245b9c547cSRui Paulo reply_len = -1;
4125f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
412639beb93cSSam Leffler #endif /* CONFIG_WPS */
41275b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING
41285b9c547cSRui Paulo } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
41295b9c547cSRui Paulo if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
41305b9c547cSRui Paulo reply_len = -1;
41315b9c547cSRui Paulo } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
41325b9c547cSRui Paulo if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
41335b9c547cSRui Paulo reply_len = -1;
41345b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */
41355b9c547cSRui Paulo #ifdef CONFIG_HS20
41365b9c547cSRui Paulo } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
41375b9c547cSRui Paulo if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
41385b9c547cSRui Paulo reply_len = -1;
41395b9c547cSRui Paulo } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
41405b9c547cSRui Paulo if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
41415b9c547cSRui Paulo reply_len = -1;
41425b9c547cSRui Paulo #endif /* CONFIG_HS20 */
414385732ac8SCy Schubert #ifdef CONFIG_WNM_AP
4144f05cddf9SRui Paulo } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
4145f05cddf9SRui Paulo if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
4146f05cddf9SRui Paulo reply_len = -1;
4147f05cddf9SRui Paulo } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
4148f05cddf9SRui Paulo if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
4149f05cddf9SRui Paulo reply_len = -1;
41505b9c547cSRui Paulo } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
41515b9c547cSRui Paulo if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
41525b9c547cSRui Paulo reply_len = -1;
415385732ac8SCy Schubert } else if (os_strncmp(buf, "COLOC_INTF_REQ ", 15) == 0) {
415485732ac8SCy Schubert if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
415585732ac8SCy Schubert reply_len = -1;
415685732ac8SCy Schubert #endif /* CONFIG_WNM_AP */
4157f05cddf9SRui Paulo } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
4158f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
4159f05cddf9SRui Paulo reply_size);
4160f05cddf9SRui Paulo } else if (os_strncmp(buf, "SET ", 4) == 0) {
4161f05cddf9SRui Paulo if (hostapd_ctrl_iface_set(hapd, buf + 4))
4162f05cddf9SRui Paulo reply_len = -1;
4163f05cddf9SRui Paulo } else if (os_strncmp(buf, "GET ", 4) == 0) {
4164f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
4165f05cddf9SRui Paulo reply_size);
4166*a90b9d01SCy Schubert } else if (os_strcmp(buf, "ENABLE") == 0) {
4167f05cddf9SRui Paulo if (hostapd_ctrl_iface_enable(hapd->iface))
4168f05cddf9SRui Paulo reply_len = -1;
41694bc52338SCy Schubert } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) {
41704bc52338SCy Schubert if (hostapd_ctrl_iface_reload_wpa_psk(hapd))
41714bc52338SCy Schubert reply_len = -1;
4172*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R_AP
4173*a90b9d01SCy Schubert } else if (os_strcmp(buf, "GET_RXKHS") == 0) {
4174*a90b9d01SCy Schubert reply_len = hostapd_ctrl_iface_get_rxkhs(hapd, reply,
4175*a90b9d01SCy Schubert reply_size);
4176*a90b9d01SCy Schubert } else if (os_strcmp(buf, "RELOAD_RXKHS") == 0) {
4177*a90b9d01SCy Schubert if (hostapd_ctrl_iface_reload_rxkhs(hapd))
4178*a90b9d01SCy Schubert reply_len = -1;
4179*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
4180*a90b9d01SCy Schubert } else if (os_strcmp(buf, "RELOAD_BSS") == 0) {
4181*a90b9d01SCy Schubert if (hostapd_ctrl_iface_reload_bss(hapd))
4182*a90b9d01SCy Schubert reply_len = -1;
4183*a90b9d01SCy Schubert } else if (os_strcmp(buf, "RELOAD_CONFIG") == 0) {
4184*a90b9d01SCy Schubert if (hostapd_reload_config(hapd->iface))
4185*a90b9d01SCy Schubert reply_len = -1;
4186*a90b9d01SCy Schubert } else if (os_strcmp(buf, "RELOAD") == 0) {
4187f05cddf9SRui Paulo if (hostapd_ctrl_iface_reload(hapd->iface))
4188f05cddf9SRui Paulo reply_len = -1;
4189*a90b9d01SCy Schubert } else if (os_strcmp(buf, "DISABLE") == 0) {
4190f05cddf9SRui Paulo if (hostapd_ctrl_iface_disable(hapd->iface))
4191f05cddf9SRui Paulo reply_len = -1;
41925b9c547cSRui Paulo } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
41935b9c547cSRui Paulo if (ieee802_11_set_beacon(hapd))
41945b9c547cSRui Paulo reply_len = -1;
41955b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
41965b9c547cSRui Paulo } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
41975b9c547cSRui Paulo if (hostapd_ctrl_iface_radar(hapd, buf + 6))
41985b9c547cSRui Paulo reply_len = -1;
41995b9c547cSRui Paulo } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
42005b9c547cSRui Paulo if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
42015b9c547cSRui Paulo reply_len = -1;
420285732ac8SCy Schubert } else if (os_strncmp(buf, "MGMT_TX_STATUS_PROCESS ", 23) == 0) {
420385732ac8SCy Schubert if (hostapd_ctrl_iface_mgmt_tx_status_process(hapd,
420485732ac8SCy Schubert buf + 23) < 0)
420585732ac8SCy Schubert reply_len = -1;
420685732ac8SCy Schubert } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
420785732ac8SCy Schubert if (hostapd_ctrl_iface_mgmt_rx_process(hapd, buf + 16) < 0)
420885732ac8SCy Schubert reply_len = -1;
42095b9c547cSRui Paulo } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
42105b9c547cSRui Paulo if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
42115b9c547cSRui Paulo reply_len = -1;
4212c1d255d3SCy Schubert } else if (os_strncmp(buf, "EAPOL_TX ", 9) == 0) {
4213c1d255d3SCy Schubert if (hostapd_ctrl_iface_eapol_tx(hapd, buf + 9) < 0)
4214c1d255d3SCy Schubert reply_len = -1;
42155b9c547cSRui Paulo } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
42165b9c547cSRui Paulo if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
42175b9c547cSRui Paulo reply_len = -1;
42185b9c547cSRui Paulo } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
42195b9c547cSRui Paulo if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
42205b9c547cSRui Paulo reply_len = -1;
42215b9c547cSRui Paulo } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
42225b9c547cSRui Paulo if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
42235b9c547cSRui Paulo reply_len = -1;
42245b9c547cSRui Paulo } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
4225*a90b9d01SCy Schubert if (testing_set_fail_pattern(true, buf + 16) < 0)
42265b9c547cSRui Paulo reply_len = -1;
42275b9c547cSRui Paulo } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
4228*a90b9d01SCy Schubert reply_len = testing_get_fail_pattern(true, reply, reply_size);
4229325151a3SRui Paulo } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
4230*a90b9d01SCy Schubert if (testing_set_fail_pattern(false, buf + 10) < 0)
4231325151a3SRui Paulo reply_len = -1;
4232325151a3SRui Paulo } else if (os_strcmp(buf, "GET_FAIL") == 0) {
4233*a90b9d01SCy Schubert reply_len = testing_get_fail_pattern(false, reply, reply_size);
423485732ac8SCy Schubert } else if (os_strncmp(buf, "RESET_PN ", 9) == 0) {
423585732ac8SCy Schubert if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 0)
423685732ac8SCy Schubert reply_len = -1;
423785732ac8SCy Schubert } else if (os_strncmp(buf, "SET_KEY ", 8) == 0) {
423885732ac8SCy Schubert if (hostapd_ctrl_set_key(hapd, buf + 8) < 0)
423985732ac8SCy Schubert reply_len = -1;
424085732ac8SCy Schubert } else if (os_strncmp(buf, "RESEND_M1 ", 10) == 0) {
424185732ac8SCy Schubert if (hostapd_ctrl_resend_m1(hapd, buf + 10) < 0)
424285732ac8SCy Schubert reply_len = -1;
424385732ac8SCy Schubert } else if (os_strncmp(buf, "RESEND_M3 ", 10) == 0) {
424485732ac8SCy Schubert if (hostapd_ctrl_resend_m3(hapd, buf + 10) < 0)
424585732ac8SCy Schubert reply_len = -1;
424685732ac8SCy Schubert } else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) {
424785732ac8SCy Schubert if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0)
424885732ac8SCy Schubert reply_len = -1;
4249c1d255d3SCy Schubert } else if (os_strncmp(buf, "REKEY_PTK ", 10) == 0) {
4250c1d255d3SCy Schubert if (hostapd_ctrl_rekey_ptk(hapd, buf + 10) < 0)
4251c1d255d3SCy Schubert reply_len = -1;
425285732ac8SCy Schubert } else if (os_strcmp(buf, "REKEY_GTK") == 0) {
425385732ac8SCy Schubert if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
425485732ac8SCy Schubert reply_len = -1;
4255c1d255d3SCy Schubert } else if (os_strncmp(buf, "GET_PMK ", 8) == 0) {
4256c1d255d3SCy Schubert reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply,
4257c1d255d3SCy Schubert reply_size);
4258c1d255d3SCy Schubert } else if (os_strncmp(buf, "REGISTER_FRAME ", 15) == 0) {
4259c1d255d3SCy Schubert if (hostapd_ctrl_register_frame(hapd, buf + 16) < 0)
4260c1d255d3SCy Schubert reply_len = -1;
42615b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
42625b9c547cSRui Paulo } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
42635b9c547cSRui Paulo if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
42645b9c547cSRui Paulo reply_len = -1;
4265*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211AX
4266*a90b9d01SCy Schubert } else if (os_strncmp(buf, "COLOR_CHANGE ", 13) == 0) {
4267*a90b9d01SCy Schubert if (hostapd_ctrl_iface_color_change(hapd->iface, buf + 13))
4268*a90b9d01SCy Schubert reply_len = -1;
4269*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211AX */
4270*a90b9d01SCy Schubert } else if (os_strncmp(buf, "NOTIFY_CW_CHANGE ", 17) == 0) {
4271*a90b9d01SCy Schubert if (hostapd_ctrl_iface_notify_cw_change(hapd, buf + 17))
4272*a90b9d01SCy Schubert reply_len = -1;
42735b9c547cSRui Paulo } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
42745b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
42755b9c547cSRui Paulo reply_size);
42765b9c547cSRui Paulo } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
42775b9c547cSRui Paulo ieee802_1x_erp_flush(hapd);
42785b9c547cSRui Paulo #ifdef RADIUS_SERVER
42795b9c547cSRui Paulo radius_server_erp_flush(hapd->radius_srv);
42805b9c547cSRui Paulo #endif /* RADIUS_SERVER */
4281325151a3SRui Paulo } else if (os_strncmp(buf, "EAPOL_REAUTH ", 13) == 0) {
4282325151a3SRui Paulo if (hostapd_ctrl_iface_eapol_reauth(hapd, buf + 13))
4283325151a3SRui Paulo reply_len = -1;
4284325151a3SRui Paulo } else if (os_strncmp(buf, "EAPOL_SET ", 10) == 0) {
4285325151a3SRui Paulo if (hostapd_ctrl_iface_eapol_set(hapd, buf + 10))
4286325151a3SRui Paulo reply_len = -1;
4287325151a3SRui Paulo } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
4288325151a3SRui Paulo reply_len = hostapd_ctrl_iface_log_level(
4289325151a3SRui Paulo hapd, buf + 9, reply, reply_size);
4290325151a3SRui Paulo #ifdef NEED_AP_MLME
4291325151a3SRui Paulo } else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
4292325151a3SRui Paulo reply_len = hostapd_ctrl_iface_track_sta_list(
4293325151a3SRui Paulo hapd, reply, reply_size);
4294325151a3SRui Paulo #endif /* NEED_AP_MLME */
4295780fb4a2SCy Schubert } else if (os_strcmp(buf, "PMKSA") == 0) {
4296780fb4a2SCy Schubert reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
4297780fb4a2SCy Schubert reply_size);
4298780fb4a2SCy Schubert } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
4299780fb4a2SCy Schubert hostapd_ctrl_iface_pmksa_flush(hapd);
430085732ac8SCy Schubert } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
430185732ac8SCy Schubert if (hostapd_ctrl_iface_pmksa_add(hapd, buf + 10) < 0)
430285732ac8SCy Schubert reply_len = -1;
4303780fb4a2SCy Schubert } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
4304780fb4a2SCy Schubert if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
4305780fb4a2SCy Schubert reply_len = -1;
4306c1d255d3SCy Schubert } else if (os_strcmp(buf, "SHOW_NEIGHBOR") == 0) {
4307c1d255d3SCy Schubert reply_len = hostapd_ctrl_iface_show_neighbor(hapd, reply,
4308c1d255d3SCy Schubert reply_size);
4309780fb4a2SCy Schubert } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
4310780fb4a2SCy Schubert if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
4311780fb4a2SCy Schubert reply_len = -1;
4312780fb4a2SCy Schubert } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
4313780fb4a2SCy Schubert if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
4314780fb4a2SCy Schubert reply_len = -1;
4315780fb4a2SCy Schubert } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
4316780fb4a2SCy Schubert if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
4317780fb4a2SCy Schubert reply_len = -1;
431885732ac8SCy Schubert } else if (os_strncmp(buf, "REQ_BEACON ", 11) == 0) {
431985732ac8SCy Schubert reply_len = hostapd_ctrl_iface_req_beacon(hapd, buf + 11,
432085732ac8SCy Schubert reply, reply_size);
4321*a90b9d01SCy Schubert } else if (os_strncmp(buf, "REQ_LINK_MEASUREMENT ", 21) == 0) {
4322*a90b9d01SCy Schubert reply_len = hostapd_ctrl_iface_req_link_measurement(
4323*a90b9d01SCy Schubert hapd, buf + 21, reply, reply_size);
4324780fb4a2SCy Schubert } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
4325780fb4a2SCy Schubert reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
4326780fb4a2SCy Schubert reply_size);
4327c1d255d3SCy Schubert } else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
4328c1d255d3SCy Schubert reply_len = hostapd_ctrl_driver_flags2(hapd->iface, reply,
4329c1d255d3SCy Schubert reply_size);
433085732ac8SCy Schubert } else if (os_strcmp(buf, "TERMINATE") == 0) {
433185732ac8SCy Schubert eloop_terminate();
433285732ac8SCy Schubert } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
433385732ac8SCy Schubert if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
4334c1d255d3SCy Schubert if (hostapd_ctrl_iface_acl_add_mac(
4335c1d255d3SCy Schubert &hapd->conf->accept_mac,
4336*a90b9d01SCy Schubert &hapd->conf->num_accept_mac, buf + 19) ||
4337*a90b9d01SCy Schubert hostapd_set_acl(hapd))
4338c1d255d3SCy Schubert reply_len = -1;
4339c1d255d3SCy Schubert } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
4340*a90b9d01SCy Schubert if (hostapd_ctrl_iface_acl_del_mac(
434185732ac8SCy Schubert &hapd->conf->accept_mac,
4342*a90b9d01SCy Schubert &hapd->conf->num_accept_mac, buf + 19) ||
4343*a90b9d01SCy Schubert hostapd_set_acl(hapd) ||
4344*a90b9d01SCy Schubert hostapd_disassoc_accept_mac(hapd))
434585732ac8SCy Schubert reply_len = -1;
434685732ac8SCy Schubert } else if (os_strcmp(buf + 11, "SHOW") == 0) {
434785732ac8SCy Schubert reply_len = hostapd_ctrl_iface_acl_show_mac(
434885732ac8SCy Schubert hapd->conf->accept_mac,
434985732ac8SCy Schubert hapd->conf->num_accept_mac, reply, reply_size);
435085732ac8SCy Schubert } else if (os_strcmp(buf + 11, "CLEAR") == 0) {
435185732ac8SCy Schubert hostapd_ctrl_iface_acl_clear_list(
435285732ac8SCy Schubert &hapd->conf->accept_mac,
435385732ac8SCy Schubert &hapd->conf->num_accept_mac);
4354*a90b9d01SCy Schubert if (hostapd_set_acl(hapd) ||
4355*a90b9d01SCy Schubert hostapd_disassoc_accept_mac(hapd))
4356*a90b9d01SCy Schubert reply_len = -1;
4357*a90b9d01SCy Schubert } else {
4358*a90b9d01SCy Schubert reply_len = -1;
435985732ac8SCy Schubert }
436085732ac8SCy Schubert } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
436185732ac8SCy Schubert if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
4362*a90b9d01SCy Schubert if (hostapd_ctrl_iface_acl_add_mac(
436385732ac8SCy Schubert &hapd->conf->deny_mac,
4364*a90b9d01SCy Schubert &hapd->conf->num_deny_mac, buf + 17) ||
4365*a90b9d01SCy Schubert hostapd_set_acl(hapd) ||
4366*a90b9d01SCy Schubert hostapd_disassoc_deny_mac(hapd))
4367c1d255d3SCy Schubert reply_len = -1;
436885732ac8SCy Schubert } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
4369c1d255d3SCy Schubert if (hostapd_ctrl_iface_acl_del_mac(
437085732ac8SCy Schubert &hapd->conf->deny_mac,
4371*a90b9d01SCy Schubert &hapd->conf->num_deny_mac, buf + 17) ||
4372*a90b9d01SCy Schubert hostapd_set_acl(hapd))
4373c1d255d3SCy Schubert reply_len = -1;
437485732ac8SCy Schubert } else if (os_strcmp(buf + 9, "SHOW") == 0) {
437585732ac8SCy Schubert reply_len = hostapd_ctrl_iface_acl_show_mac(
437685732ac8SCy Schubert hapd->conf->deny_mac,
437785732ac8SCy Schubert hapd->conf->num_deny_mac, reply, reply_size);
437885732ac8SCy Schubert } else if (os_strcmp(buf + 9, "CLEAR") == 0) {
437985732ac8SCy Schubert hostapd_ctrl_iface_acl_clear_list(
438085732ac8SCy Schubert &hapd->conf->deny_mac,
438185732ac8SCy Schubert &hapd->conf->num_deny_mac);
4382*a90b9d01SCy Schubert if (hostapd_set_acl(hapd))
4383*a90b9d01SCy Schubert reply_len = -1;
4384*a90b9d01SCy Schubert } else {
4385*a90b9d01SCy Schubert reply_len = -1;
438685732ac8SCy Schubert }
438785732ac8SCy Schubert #ifdef CONFIG_DPP
438885732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
438985732ac8SCy Schubert res = hostapd_dpp_qr_code(hapd, buf + 12);
439085732ac8SCy Schubert if (res < 0) {
439185732ac8SCy Schubert reply_len = -1;
439285732ac8SCy Schubert } else {
439385732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
439485732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
439585732ac8SCy Schubert reply_len = -1;
439685732ac8SCy Schubert }
4397c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_NFC_URI ", 12) == 0) {
4398c1d255d3SCy Schubert res = hostapd_dpp_nfc_uri(hapd, buf + 12);
4399c1d255d3SCy Schubert if (res < 0) {
4400c1d255d3SCy Schubert reply_len = -1;
4401c1d255d3SCy Schubert } else {
4402c1d255d3SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
4403c1d255d3SCy Schubert if (os_snprintf_error(reply_size, reply_len))
4404c1d255d3SCy Schubert reply_len = -1;
4405c1d255d3SCy Schubert }
4406c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
4407c1d255d3SCy Schubert res = hostapd_dpp_nfc_handover_req(hapd, buf + 20);
4408c1d255d3SCy Schubert if (res < 0) {
4409c1d255d3SCy Schubert reply_len = -1;
4410c1d255d3SCy Schubert } else {
4411c1d255d3SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
4412c1d255d3SCy Schubert if (os_snprintf_error(reply_size, reply_len))
4413c1d255d3SCy Schubert reply_len = -1;
4414c1d255d3SCy Schubert }
4415c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
4416c1d255d3SCy Schubert res = hostapd_dpp_nfc_handover_sel(hapd, buf + 20);
4417c1d255d3SCy Schubert if (res < 0) {
4418c1d255d3SCy Schubert reply_len = -1;
4419c1d255d3SCy Schubert } else {
4420c1d255d3SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
4421c1d255d3SCy Schubert if (os_snprintf_error(reply_size, reply_len))
4422c1d255d3SCy Schubert reply_len = -1;
4423c1d255d3SCy Schubert }
442485732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
44254bc52338SCy Schubert res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
442685732ac8SCy Schubert if (res < 0) {
442785732ac8SCy Schubert reply_len = -1;
442885732ac8SCy Schubert } else {
442985732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
443085732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
443185732ac8SCy Schubert reply_len = -1;
443285732ac8SCy Schubert }
443385732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
44344bc52338SCy Schubert if (dpp_bootstrap_remove(hapd->iface->interfaces->dpp,
44354bc52338SCy Schubert buf + 21) < 0)
443685732ac8SCy Schubert reply_len = -1;
443785732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
443885732ac8SCy Schubert const char *uri;
443985732ac8SCy Schubert
44404bc52338SCy Schubert uri = dpp_bootstrap_get_uri(hapd->iface->interfaces->dpp,
44414bc52338SCy Schubert atoi(buf + 22));
444285732ac8SCy Schubert if (!uri) {
444385732ac8SCy Schubert reply_len = -1;
444485732ac8SCy Schubert } else {
444585732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%s", uri);
444685732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
444785732ac8SCy Schubert reply_len = -1;
444885732ac8SCy Schubert }
444985732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
44504bc52338SCy Schubert reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
44514bc52338SCy Schubert atoi(buf + 19),
445285732ac8SCy Schubert reply, reply_size);
4453c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
4454c1d255d3SCy Schubert if (dpp_bootstrap_set(hapd->iface->interfaces->dpp,
4455c1d255d3SCy Schubert atoi(buf + 18),
4456c1d255d3SCy Schubert os_strchr(buf + 18, ' ')) < 0)
4457c1d255d3SCy Schubert reply_len = -1;
445885732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
445985732ac8SCy Schubert if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
446085732ac8SCy Schubert reply_len = -1;
446185732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
446285732ac8SCy Schubert if (hostapd_dpp_listen(hapd, buf + 11) < 0)
446385732ac8SCy Schubert reply_len = -1;
446485732ac8SCy Schubert } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
446585732ac8SCy Schubert hostapd_dpp_stop(hapd);
446685732ac8SCy Schubert hostapd_dpp_listen_stop(hapd);
446785732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
44684bc52338SCy Schubert res = dpp_configurator_add(hapd->iface->interfaces->dpp,
44694bc52338SCy Schubert buf + 20);
447085732ac8SCy Schubert if (res < 0) {
447185732ac8SCy Schubert reply_len = -1;
447285732ac8SCy Schubert } else {
447385732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
447485732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
447585732ac8SCy Schubert reply_len = -1;
447685732ac8SCy Schubert }
4477*a90b9d01SCy Schubert } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) {
4478*a90b9d01SCy Schubert if (dpp_configurator_set(hapd->iface->interfaces->dpp,
4479*a90b9d01SCy Schubert buf + 20) < 0)
4480*a90b9d01SCy Schubert reply_len = -1;
448185732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
44824bc52338SCy Schubert if (dpp_configurator_remove(hapd->iface->interfaces->dpp,
44834bc52338SCy Schubert buf + 24) < 0)
448485732ac8SCy Schubert reply_len = -1;
448585732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
44864bc52338SCy Schubert if (hostapd_dpp_configurator_sign(hapd, buf + 21) < 0)
448785732ac8SCy Schubert reply_len = -1;
448885732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
44894bc52338SCy Schubert reply_len = dpp_configurator_get_key_id(
44904bc52338SCy Schubert hapd->iface->interfaces->dpp,
449185732ac8SCy Schubert atoi(buf + 25),
449285732ac8SCy Schubert reply, reply_size);
449385732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
449485732ac8SCy Schubert res = hostapd_dpp_pkex_add(hapd, buf + 12);
449585732ac8SCy Schubert if (res < 0) {
449685732ac8SCy Schubert reply_len = -1;
449785732ac8SCy Schubert } else {
449885732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
449985732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
450085732ac8SCy Schubert reply_len = -1;
450185732ac8SCy Schubert }
450285732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
450385732ac8SCy Schubert if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
450485732ac8SCy Schubert reply_len = -1;
4505c1d255d3SCy Schubert #ifdef CONFIG_DPP2
4506c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
4507c1d255d3SCy Schubert if (hostapd_dpp_controller_start(hapd, buf + 20) < 0)
4508c1d255d3SCy Schubert reply_len = -1;
4509c1d255d3SCy Schubert } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
4510c1d255d3SCy Schubert if (hostapd_dpp_controller_start(hapd, NULL) < 0)
4511c1d255d3SCy Schubert reply_len = -1;
4512c1d255d3SCy Schubert } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
4513c1d255d3SCy Schubert dpp_controller_stop(hapd->iface->interfaces->dpp);
4514c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
4515c1d255d3SCy Schubert if (hostapd_dpp_chirp(hapd, buf + 9) < 0)
4516c1d255d3SCy Schubert reply_len = -1;
4517c1d255d3SCy Schubert } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
4518c1d255d3SCy Schubert hostapd_dpp_chirp_stop(hapd);
4519*a90b9d01SCy Schubert } else if (os_strncmp(buf, "DPP_RELAY_ADD_CONTROLLER ", 25) == 0) {
4520*a90b9d01SCy Schubert if (hostapd_dpp_add_controller(hapd, buf + 25) < 0)
4521*a90b9d01SCy Schubert reply_len = -1;
4522*a90b9d01SCy Schubert } else if (os_strncmp(buf, "DPP_RELAY_REMOVE_CONTROLLER ", 28) == 0) {
4523*a90b9d01SCy Schubert hostapd_dpp_remove_controller(hapd, buf + 28);
4524c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
4525*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
4526*a90b9d01SCy Schubert } else if (os_strcmp(buf, "DPP_PUSH_BUTTON") == 0) {
4527*a90b9d01SCy Schubert if (hostapd_dpp_push_button(hapd, NULL) < 0)
4528*a90b9d01SCy Schubert reply_len = -1;
4529*a90b9d01SCy Schubert } else if (os_strncmp(buf, "DPP_PUSH_BUTTON ", 16) == 0) {
4530*a90b9d01SCy Schubert if (hostapd_dpp_push_button(hapd, buf + 15) < 0)
4531*a90b9d01SCy Schubert reply_len = -1;
4532*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
453385732ac8SCy Schubert #endif /* CONFIG_DPP */
4534*a90b9d01SCy Schubert #ifdef CONFIG_NAN_USD
4535*a90b9d01SCy Schubert } else if (os_strncmp(buf, "NAN_PUBLISH ", 12) == 0) {
4536*a90b9d01SCy Schubert reply_len = hostapd_ctrl_nan_publish(hapd, buf + 12, reply,
4537*a90b9d01SCy Schubert reply_size);
4538*a90b9d01SCy Schubert } else if (os_strncmp(buf, "NAN_CANCEL_PUBLISH ", 19) == 0) {
4539*a90b9d01SCy Schubert if (hostapd_ctrl_nan_cancel_publish(hapd, buf + 19) < 0)
4540*a90b9d01SCy Schubert reply_len = -1;
4541*a90b9d01SCy Schubert } else if (os_strncmp(buf, "NAN_UPDATE_PUBLISH ", 19) == 0) {
4542*a90b9d01SCy Schubert if (hostapd_ctrl_nan_update_publish(hapd, buf + 19) < 0)
4543*a90b9d01SCy Schubert reply_len = -1;
4544*a90b9d01SCy Schubert } else if (os_strncmp(buf, "NAN_SUBSCRIBE ", 14) == 0) {
4545*a90b9d01SCy Schubert reply_len = hostapd_ctrl_nan_subscribe(hapd, buf + 14, reply,
4546*a90b9d01SCy Schubert reply_size);
4547*a90b9d01SCy Schubert } else if (os_strncmp(buf, "NAN_CANCEL_SUBSCRIBE ", 21) == 0) {
4548*a90b9d01SCy Schubert if (hostapd_ctrl_nan_cancel_subscribe(hapd, buf + 21) < 0)
4549*a90b9d01SCy Schubert reply_len = -1;
4550*a90b9d01SCy Schubert } else if (os_strncmp(buf, "NAN_TRANSMIT ", 13) == 0) {
4551*a90b9d01SCy Schubert if (hostapd_ctrl_nan_transmit(hapd, buf + 13) < 0)
4552*a90b9d01SCy Schubert reply_len = -1;
4553*a90b9d01SCy Schubert #endif /* CONFIG_NAN_USD */
455485732ac8SCy Schubert #ifdef RADIUS_SERVER
455585732ac8SCy Schubert } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
455685732ac8SCy Schubert if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
455785732ac8SCy Schubert reply_len = -1;
455885732ac8SCy Schubert #endif /* RADIUS_SERVER */
45594bc52338SCy Schubert } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
45604bc52338SCy Schubert reply_len = hostapd_ctrl_iface_get_capability(
45614bc52338SCy Schubert hapd, buf + 15, reply, reply_size);
4562c1d255d3SCy Schubert #ifdef CONFIG_PASN
4563c1d255d3SCy Schubert } else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) {
4564c1d255d3SCy Schubert reply_len = ptksa_cache_list(hapd->ptksa, reply, reply_size);
4565c1d255d3SCy Schubert #endif /* CONFIG_PASN */
4566c1d255d3SCy Schubert #ifdef ANDROID
4567c1d255d3SCy Schubert } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
4568c1d255d3SCy Schubert reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply,
4569c1d255d3SCy Schubert reply_size);
4570c1d255d3SCy Schubert #endif /* ANDROID */
4571*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211BE
4572*a90b9d01SCy Schubert } else if (os_strcmp(buf, "ENABLE_MLD") == 0) {
4573*a90b9d01SCy Schubert if (hostapd_ctrl_iface_enable_mld(hapd->iface))
4574*a90b9d01SCy Schubert reply_len = -1;
4575*a90b9d01SCy Schubert } else if (os_strcmp(buf, "DISABLE_MLD") == 0) {
4576*a90b9d01SCy Schubert if (hostapd_ctrl_iface_disable_mld(hapd->iface))
4577*a90b9d01SCy Schubert reply_len = -1;
4578*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
4579*a90b9d01SCy Schubert } else if (os_strncmp(buf, "LINK_REMOVE ", 12) == 0) {
4580*a90b9d01SCy Schubert if (hostapd_ctrl_iface_link_remove(hapd, buf + 12,
4581*a90b9d01SCy Schubert reply, reply_size))
4582*a90b9d01SCy Schubert reply_len = -1;
4583*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
4584*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211BE */
458539beb93cSSam Leffler } else {
458639beb93cSSam Leffler os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
458739beb93cSSam Leffler reply_len = 16;
458839beb93cSSam Leffler }
458939beb93cSSam Leffler
459039beb93cSSam Leffler if (reply_len < 0) {
459139beb93cSSam Leffler os_memcpy(reply, "FAIL\n", 5);
459239beb93cSSam Leffler reply_len = 5;
459339beb93cSSam Leffler }
4594325151a3SRui Paulo
4595325151a3SRui Paulo return reply_len;
4596325151a3SRui Paulo }
4597325151a3SRui Paulo
4598325151a3SRui Paulo
hostapd_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)4599325151a3SRui Paulo static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
4600325151a3SRui Paulo void *sock_ctx)
4601325151a3SRui Paulo {
4602325151a3SRui Paulo struct hostapd_data *hapd = eloop_ctx;
4603325151a3SRui Paulo char buf[4096];
4604325151a3SRui Paulo int res;
4605780fb4a2SCy Schubert struct sockaddr_storage from;
4606325151a3SRui Paulo socklen_t fromlen = sizeof(from);
4607780fb4a2SCy Schubert char *reply, *pos = buf;
4608325151a3SRui Paulo const int reply_size = 4096;
4609325151a3SRui Paulo int reply_len;
4610325151a3SRui Paulo int level = MSG_DEBUG;
4611780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4612c1d255d3SCy Schubert unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
4613780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
4614325151a3SRui Paulo
4615325151a3SRui Paulo res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
4616325151a3SRui Paulo (struct sockaddr *) &from, &fromlen);
4617325151a3SRui Paulo if (res < 0) {
4618325151a3SRui Paulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
4619325151a3SRui Paulo strerror(errno));
4620325151a3SRui Paulo return;
4621325151a3SRui Paulo }
4622325151a3SRui Paulo buf[res] = '\0';
4623325151a3SRui Paulo
4624325151a3SRui Paulo reply = os_malloc(reply_size);
4625325151a3SRui Paulo if (reply == NULL) {
4626325151a3SRui Paulo if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
4627325151a3SRui Paulo fromlen) < 0) {
4628325151a3SRui Paulo wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
4629325151a3SRui Paulo strerror(errno));
4630325151a3SRui Paulo }
4631325151a3SRui Paulo return;
4632325151a3SRui Paulo }
4633325151a3SRui Paulo
4634780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4635780fb4a2SCy Schubert if (os_strcmp(buf, "GET_COOKIE") == 0) {
4636780fb4a2SCy Schubert os_memcpy(reply, "COOKIE=", 7);
4637c1d255d3SCy Schubert wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
4638c1d255d3SCy Schubert hapd->ctrl_iface_cookie,
4639c1d255d3SCy Schubert CTRL_IFACE_COOKIE_LEN);
4640c1d255d3SCy Schubert reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
4641780fb4a2SCy Schubert goto done;
4642780fb4a2SCy Schubert }
4643780fb4a2SCy Schubert
4644780fb4a2SCy Schubert if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
4645c1d255d3SCy Schubert hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
4646780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
4647780fb4a2SCy Schubert "CTRL: No cookie in the request - drop request");
4648780fb4a2SCy Schubert os_free(reply);
4649780fb4a2SCy Schubert return;
4650780fb4a2SCy Schubert }
4651780fb4a2SCy Schubert
4652c1d255d3SCy Schubert if (os_memcmp(hapd->ctrl_iface_cookie, lcookie,
4653c1d255d3SCy Schubert CTRL_IFACE_COOKIE_LEN) != 0) {
4654780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
4655780fb4a2SCy Schubert "CTRL: Invalid cookie in the request - drop request");
4656780fb4a2SCy Schubert os_free(reply);
4657780fb4a2SCy Schubert return;
4658780fb4a2SCy Schubert }
4659780fb4a2SCy Schubert
4660c1d255d3SCy Schubert pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
4661780fb4a2SCy Schubert while (*pos == ' ')
4662780fb4a2SCy Schubert pos++;
4663780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
4664780fb4a2SCy Schubert
4665780fb4a2SCy Schubert if (os_strcmp(pos, "PING") == 0)
4666780fb4a2SCy Schubert level = MSG_EXCESSIVE;
4667780fb4a2SCy Schubert wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
4668780fb4a2SCy Schubert
4669780fb4a2SCy Schubert reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
4670325151a3SRui Paulo reply, reply_size,
4671325151a3SRui Paulo &from, fromlen);
4672325151a3SRui Paulo
4673780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4674780fb4a2SCy Schubert done:
4675780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
46765b9c547cSRui Paulo if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
46775b9c547cSRui Paulo fromlen) < 0) {
46785b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
46795b9c547cSRui Paulo strerror(errno));
46805b9c547cSRui Paulo }
468139beb93cSSam Leffler os_free(reply);
468239beb93cSSam Leffler }
468339beb93cSSam Leffler
468439beb93cSSam Leffler
4685780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
hostapd_ctrl_iface_path(struct hostapd_data * hapd)468639beb93cSSam Leffler static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
468739beb93cSSam Leffler {
468839beb93cSSam Leffler char *buf;
468939beb93cSSam Leffler size_t len;
469039beb93cSSam Leffler
469139beb93cSSam Leffler if (hapd->conf->ctrl_interface == NULL)
469239beb93cSSam Leffler return NULL;
469339beb93cSSam Leffler
469439beb93cSSam Leffler len = os_strlen(hapd->conf->ctrl_interface) +
469539beb93cSSam Leffler os_strlen(hapd->conf->iface) + 2;
469639beb93cSSam Leffler buf = os_malloc(len);
469739beb93cSSam Leffler if (buf == NULL)
469839beb93cSSam Leffler return NULL;
469939beb93cSSam Leffler
470039beb93cSSam Leffler os_snprintf(buf, len, "%s/%s",
470139beb93cSSam Leffler hapd->conf->ctrl_interface, hapd->conf->iface);
470239beb93cSSam Leffler buf[len - 1] = '\0';
470339beb93cSSam Leffler return buf;
470439beb93cSSam Leffler }
4705780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
470639beb93cSSam Leffler
470739beb93cSSam Leffler
hostapd_ctrl_iface_msg_cb(void * ctx,int level,enum wpa_msg_type type,const char * txt,size_t len)4708325151a3SRui Paulo static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
4709325151a3SRui Paulo enum wpa_msg_type type,
471039beb93cSSam Leffler const char *txt, size_t len)
471139beb93cSSam Leffler {
471239beb93cSSam Leffler struct hostapd_data *hapd = ctx;
471339beb93cSSam Leffler if (hapd == NULL)
471439beb93cSSam Leffler return;
4715325151a3SRui Paulo hostapd_ctrl_iface_send(hapd, level, type, txt, len);
471639beb93cSSam Leffler }
471739beb93cSSam Leffler
471839beb93cSSam Leffler
hostapd_ctrl_iface_init(struct hostapd_data * hapd)471939beb93cSSam Leffler int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
472039beb93cSSam Leffler {
4721780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4722780fb4a2SCy Schubert int port = HOSTAPD_CTRL_IFACE_PORT;
4723780fb4a2SCy Schubert char p[32] = { 0 };
4724780fb4a2SCy Schubert char port_str[40], *tmp;
4725780fb4a2SCy Schubert char *pos;
4726780fb4a2SCy Schubert struct addrinfo hints = { 0 }, *res, *saveres;
4727780fb4a2SCy Schubert int n;
4728780fb4a2SCy Schubert
4729780fb4a2SCy Schubert if (hapd->ctrl_sock > -1) {
4730780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
4731780fb4a2SCy Schubert return 0;
4732780fb4a2SCy Schubert }
4733780fb4a2SCy Schubert
4734780fb4a2SCy Schubert if (hapd->conf->ctrl_interface == NULL)
4735780fb4a2SCy Schubert return 0;
4736780fb4a2SCy Schubert
4737780fb4a2SCy Schubert pos = os_strstr(hapd->conf->ctrl_interface, "udp:");
4738780fb4a2SCy Schubert if (pos) {
4739780fb4a2SCy Schubert pos += 4;
4740780fb4a2SCy Schubert port = atoi(pos);
4741780fb4a2SCy Schubert if (port <= 0) {
4742780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port");
4743780fb4a2SCy Schubert goto fail;
4744780fb4a2SCy Schubert }
4745780fb4a2SCy Schubert }
4746780fb4a2SCy Schubert
4747780fb4a2SCy Schubert dl_list_init(&hapd->ctrl_dst);
4748780fb4a2SCy Schubert hapd->ctrl_sock = -1;
4749c1d255d3SCy Schubert os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
4750780fb4a2SCy Schubert
4751780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
4752780fb4a2SCy Schubert hints.ai_flags = AI_PASSIVE;
4753780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
4754780fb4a2SCy Schubert
4755780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
4756780fb4a2SCy Schubert hints.ai_family = AF_INET6;
4757780fb4a2SCy Schubert #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4758780fb4a2SCy Schubert hints.ai_family = AF_INET;
4759780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4760780fb4a2SCy Schubert hints.ai_socktype = SOCK_DGRAM;
4761780fb4a2SCy Schubert
4762780fb4a2SCy Schubert try_again:
4763780fb4a2SCy Schubert os_snprintf(p, sizeof(p), "%d", port);
4764780fb4a2SCy Schubert n = getaddrinfo(NULL, p, &hints, &res);
4765780fb4a2SCy Schubert if (n) {
4766780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
4767780fb4a2SCy Schubert goto fail;
4768780fb4a2SCy Schubert }
4769780fb4a2SCy Schubert
4770780fb4a2SCy Schubert saveres = res;
4771780fb4a2SCy Schubert hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
4772780fb4a2SCy Schubert res->ai_protocol);
4773780fb4a2SCy Schubert if (hapd->ctrl_sock < 0) {
4774780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
4775780fb4a2SCy Schubert goto fail;
4776780fb4a2SCy Schubert }
4777780fb4a2SCy Schubert
4778780fb4a2SCy Schubert if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
4779780fb4a2SCy Schubert port--;
4780780fb4a2SCy Schubert if ((HOSTAPD_CTRL_IFACE_PORT - port) <
4781780fb4a2SCy Schubert HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos)
4782780fb4a2SCy Schubert goto try_again;
4783780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
4784780fb4a2SCy Schubert goto fail;
4785780fb4a2SCy Schubert }
4786780fb4a2SCy Schubert
4787780fb4a2SCy Schubert freeaddrinfo(saveres);
4788780fb4a2SCy Schubert
4789780fb4a2SCy Schubert os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
4790780fb4a2SCy Schubert tmp = os_strdup(port_str);
4791780fb4a2SCy Schubert if (tmp) {
4792780fb4a2SCy Schubert os_free(hapd->conf->ctrl_interface);
4793780fb4a2SCy Schubert hapd->conf->ctrl_interface = tmp;
4794780fb4a2SCy Schubert }
4795780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
4796780fb4a2SCy Schubert
4797780fb4a2SCy Schubert if (eloop_register_read_sock(hapd->ctrl_sock,
4798780fb4a2SCy Schubert hostapd_ctrl_iface_receive, hapd, NULL) <
4799780fb4a2SCy Schubert 0) {
4800780fb4a2SCy Schubert hostapd_ctrl_iface_deinit(hapd);
4801780fb4a2SCy Schubert return -1;
4802780fb4a2SCy Schubert }
4803780fb4a2SCy Schubert
4804780fb4a2SCy Schubert hapd->msg_ctx = hapd;
4805780fb4a2SCy Schubert wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
4806780fb4a2SCy Schubert
4807780fb4a2SCy Schubert return 0;
4808780fb4a2SCy Schubert
4809780fb4a2SCy Schubert fail:
4810780fb4a2SCy Schubert if (hapd->ctrl_sock >= 0)
4811780fb4a2SCy Schubert close(hapd->ctrl_sock);
4812780fb4a2SCy Schubert return -1;
4813780fb4a2SCy Schubert #else /* CONFIG_CTRL_IFACE_UDP */
481439beb93cSSam Leffler struct sockaddr_un addr;
481539beb93cSSam Leffler int s = -1;
481639beb93cSSam Leffler char *fname = NULL;
481739beb93cSSam Leffler
4818f05cddf9SRui Paulo if (hapd->ctrl_sock > -1) {
4819f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
4820f05cddf9SRui Paulo return 0;
4821f05cddf9SRui Paulo }
482239beb93cSSam Leffler
4823780fb4a2SCy Schubert dl_list_init(&hapd->ctrl_dst);
4824780fb4a2SCy Schubert
482539beb93cSSam Leffler if (hapd->conf->ctrl_interface == NULL)
482639beb93cSSam Leffler return 0;
482739beb93cSSam Leffler
482839beb93cSSam Leffler if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
482939beb93cSSam Leffler if (errno == EEXIST) {
483039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Using existing control "
483139beb93cSSam Leffler "interface directory.");
483239beb93cSSam Leffler } else {
48335b9c547cSRui Paulo wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
48345b9c547cSRui Paulo strerror(errno));
483539beb93cSSam Leffler goto fail;
483639beb93cSSam Leffler }
483739beb93cSSam Leffler }
483839beb93cSSam Leffler
483939beb93cSSam Leffler if (hapd->conf->ctrl_interface_gid_set &&
48404bc52338SCy Schubert lchown(hapd->conf->ctrl_interface, -1,
484139beb93cSSam Leffler hapd->conf->ctrl_interface_gid) < 0) {
48424bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
48435b9c547cSRui Paulo strerror(errno));
48445b9c547cSRui Paulo return -1;
48455b9c547cSRui Paulo }
48465b9c547cSRui Paulo
48475b9c547cSRui Paulo if (!hapd->conf->ctrl_interface_gid_set &&
48485b9c547cSRui Paulo hapd->iface->interfaces->ctrl_iface_group &&
48494bc52338SCy Schubert lchown(hapd->conf->ctrl_interface, -1,
48505b9c547cSRui Paulo hapd->iface->interfaces->ctrl_iface_group) < 0) {
48514bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
48525b9c547cSRui Paulo strerror(errno));
485339beb93cSSam Leffler return -1;
485439beb93cSSam Leffler }
485539beb93cSSam Leffler
4856f05cddf9SRui Paulo #ifdef ANDROID
4857f05cddf9SRui Paulo /*
4858f05cddf9SRui Paulo * Android is using umask 0077 which would leave the control interface
4859f05cddf9SRui Paulo * directory without group access. This breaks things since Wi-Fi
4860f05cddf9SRui Paulo * framework assumes that this directory can be accessed by other
4861f05cddf9SRui Paulo * applications in the wifi group. Fix this by adding group access even
4862f05cddf9SRui Paulo * if umask value would prevent this.
4863f05cddf9SRui Paulo */
4864f05cddf9SRui Paulo if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
4865f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
4866f05cddf9SRui Paulo strerror(errno));
4867f05cddf9SRui Paulo /* Try to continue anyway */
4868f05cddf9SRui Paulo }
4869f05cddf9SRui Paulo #endif /* ANDROID */
4870f05cddf9SRui Paulo
487139beb93cSSam Leffler if (os_strlen(hapd->conf->ctrl_interface) + 1 +
487239beb93cSSam Leffler os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
487339beb93cSSam Leffler goto fail;
487439beb93cSSam Leffler
487539beb93cSSam Leffler s = socket(PF_UNIX, SOCK_DGRAM, 0);
487639beb93cSSam Leffler if (s < 0) {
48775b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
487839beb93cSSam Leffler goto fail;
487939beb93cSSam Leffler }
488039beb93cSSam Leffler
488139beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr));
48823157ba21SRui Paulo #ifdef __FreeBSD__
48833157ba21SRui Paulo addr.sun_len = sizeof(addr);
48843157ba21SRui Paulo #endif /* __FreeBSD__ */
488539beb93cSSam Leffler addr.sun_family = AF_UNIX;
488639beb93cSSam Leffler fname = hostapd_ctrl_iface_path(hapd);
488739beb93cSSam Leffler if (fname == NULL)
488839beb93cSSam Leffler goto fail;
488939beb93cSSam Leffler os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
489039beb93cSSam Leffler if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
48913157ba21SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
48923157ba21SRui Paulo strerror(errno));
48933157ba21SRui Paulo if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
48943157ba21SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
48953157ba21SRui Paulo " allow connections - assuming it was left"
48963157ba21SRui Paulo "over from forced program termination");
48973157ba21SRui Paulo if (unlink(fname) < 0) {
48985b9c547cSRui Paulo wpa_printf(MSG_ERROR,
48995b9c547cSRui Paulo "Could not unlink existing ctrl_iface socket '%s': %s",
49005b9c547cSRui Paulo fname, strerror(errno));
49013157ba21SRui Paulo goto fail;
49023157ba21SRui Paulo }
49033157ba21SRui Paulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
49043157ba21SRui Paulo 0) {
49055b9c547cSRui Paulo wpa_printf(MSG_ERROR,
49065b9c547cSRui Paulo "hostapd-ctrl-iface: bind(PF_UNIX): %s",
49075b9c547cSRui Paulo strerror(errno));
490839beb93cSSam Leffler goto fail;
490939beb93cSSam Leffler }
49103157ba21SRui Paulo wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
49113157ba21SRui Paulo "ctrl_iface socket '%s'", fname);
49123157ba21SRui Paulo } else {
49133157ba21SRui Paulo wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
49143157ba21SRui Paulo "be in use - cannot override it");
49153157ba21SRui Paulo wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
49163157ba21SRui Paulo "not used anymore", fname);
49173157ba21SRui Paulo os_free(fname);
49183157ba21SRui Paulo fname = NULL;
49193157ba21SRui Paulo goto fail;
49203157ba21SRui Paulo }
49213157ba21SRui Paulo }
492239beb93cSSam Leffler
492339beb93cSSam Leffler if (hapd->conf->ctrl_interface_gid_set &&
49244bc52338SCy Schubert lchown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
49254bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
49265b9c547cSRui Paulo strerror(errno));
49275b9c547cSRui Paulo goto fail;
49285b9c547cSRui Paulo }
49295b9c547cSRui Paulo
49305b9c547cSRui Paulo if (!hapd->conf->ctrl_interface_gid_set &&
49315b9c547cSRui Paulo hapd->iface->interfaces->ctrl_iface_group &&
49324bc52338SCy Schubert lchown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
49334bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
49345b9c547cSRui Paulo strerror(errno));
493539beb93cSSam Leffler goto fail;
493639beb93cSSam Leffler }
493739beb93cSSam Leffler
493839beb93cSSam Leffler if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
49395b9c547cSRui Paulo wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
49405b9c547cSRui Paulo strerror(errno));
494139beb93cSSam Leffler goto fail;
494239beb93cSSam Leffler }
494339beb93cSSam Leffler os_free(fname);
494439beb93cSSam Leffler
494539beb93cSSam Leffler hapd->ctrl_sock = s;
49465b9c547cSRui Paulo if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
49475b9c547cSRui Paulo NULL) < 0) {
49485b9c547cSRui Paulo hostapd_ctrl_iface_deinit(hapd);
49495b9c547cSRui Paulo return -1;
49505b9c547cSRui Paulo }
4951e28a4053SRui Paulo hapd->msg_ctx = hapd;
495239beb93cSSam Leffler wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
495339beb93cSSam Leffler
495439beb93cSSam Leffler return 0;
495539beb93cSSam Leffler
495639beb93cSSam Leffler fail:
495739beb93cSSam Leffler if (s >= 0)
495839beb93cSSam Leffler close(s);
495939beb93cSSam Leffler if (fname) {
496039beb93cSSam Leffler unlink(fname);
496139beb93cSSam Leffler os_free(fname);
496239beb93cSSam Leffler }
496339beb93cSSam Leffler return -1;
4964780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
496539beb93cSSam Leffler }
496639beb93cSSam Leffler
496739beb93cSSam Leffler
hostapd_ctrl_iface_deinit(struct hostapd_data * hapd)496839beb93cSSam Leffler void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
496939beb93cSSam Leffler {
497039beb93cSSam Leffler struct wpa_ctrl_dst *dst, *prev;
497139beb93cSSam Leffler
497239beb93cSSam Leffler if (hapd->ctrl_sock > -1) {
4973780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
497439beb93cSSam Leffler char *fname;
4975780fb4a2SCy Schubert #endif /* !CONFIG_CTRL_IFACE_UDP */
4976780fb4a2SCy Schubert
497739beb93cSSam Leffler eloop_unregister_read_sock(hapd->ctrl_sock);
497839beb93cSSam Leffler close(hapd->ctrl_sock);
497939beb93cSSam Leffler hapd->ctrl_sock = -1;
4980780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
498139beb93cSSam Leffler fname = hostapd_ctrl_iface_path(hapd);
498239beb93cSSam Leffler if (fname)
498339beb93cSSam Leffler unlink(fname);
498439beb93cSSam Leffler os_free(fname);
498539beb93cSSam Leffler
498639beb93cSSam Leffler if (hapd->conf->ctrl_interface &&
498739beb93cSSam Leffler rmdir(hapd->conf->ctrl_interface) < 0) {
498839beb93cSSam Leffler if (errno == ENOTEMPTY) {
498939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Control interface "
499039beb93cSSam Leffler "directory not empty - leaving it "
499139beb93cSSam Leffler "behind");
499239beb93cSSam Leffler } else {
49935b9c547cSRui Paulo wpa_printf(MSG_ERROR,
49945b9c547cSRui Paulo "rmdir[ctrl_interface=%s]: %s",
49955b9c547cSRui Paulo hapd->conf->ctrl_interface,
49965b9c547cSRui Paulo strerror(errno));
499739beb93cSSam Leffler }
499839beb93cSSam Leffler }
4999780fb4a2SCy Schubert #endif /* !CONFIG_CTRL_IFACE_UDP */
500039beb93cSSam Leffler }
500139beb93cSSam Leffler
5002780fb4a2SCy Schubert dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
5003780fb4a2SCy Schubert list)
5004780fb4a2SCy Schubert os_free(dst);
50055b9c547cSRui Paulo
50065b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
50075b9c547cSRui Paulo l2_packet_deinit(hapd->l2_test);
50085b9c547cSRui Paulo hapd->l2_test = NULL;
50095b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
501039beb93cSSam Leffler }
501139beb93cSSam Leffler
501239beb93cSSam Leffler
hostapd_ctrl_iface_add(struct hapd_interfaces * interfaces,char * buf)5013f05cddf9SRui Paulo static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
5014f05cddf9SRui Paulo char *buf)
5015f05cddf9SRui Paulo {
5016f05cddf9SRui Paulo if (hostapd_add_iface(interfaces, buf) < 0) {
5017f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
5018f05cddf9SRui Paulo return -1;
5019f05cddf9SRui Paulo }
5020f05cddf9SRui Paulo return 0;
5021f05cddf9SRui Paulo }
5022f05cddf9SRui Paulo
5023f05cddf9SRui Paulo
hostapd_ctrl_iface_remove(struct hapd_interfaces * interfaces,char * buf)5024f05cddf9SRui Paulo static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
5025f05cddf9SRui Paulo char *buf)
5026f05cddf9SRui Paulo {
5027f05cddf9SRui Paulo if (hostapd_remove_iface(interfaces, buf) < 0) {
5028f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
5029f05cddf9SRui Paulo return -1;
5030f05cddf9SRui Paulo }
5031f05cddf9SRui Paulo return 0;
5032f05cddf9SRui Paulo }
5033f05cddf9SRui Paulo
5034f05cddf9SRui Paulo
hostapd_global_ctrl_iface_attach(struct hapd_interfaces * interfaces,struct sockaddr_storage * from,socklen_t fromlen,char * input)5035325151a3SRui Paulo static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
5036780fb4a2SCy Schubert struct sockaddr_storage *from,
503785732ac8SCy Schubert socklen_t fromlen, char *input)
5038325151a3SRui Paulo {
503985732ac8SCy Schubert return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen,
504085732ac8SCy Schubert input);
5041325151a3SRui Paulo }
5042325151a3SRui Paulo
5043325151a3SRui Paulo
hostapd_global_ctrl_iface_detach(struct hapd_interfaces * interfaces,struct sockaddr_storage * from,socklen_t fromlen)5044325151a3SRui Paulo static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
5045780fb4a2SCy Schubert struct sockaddr_storage *from,
5046325151a3SRui Paulo socklen_t fromlen)
5047325151a3SRui Paulo {
5048780fb4a2SCy Schubert return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen);
5049325151a3SRui Paulo }
5050325151a3SRui Paulo
5051325151a3SRui Paulo
hostapd_ctrl_iface_flush(struct hapd_interfaces * interfaces)50525b9c547cSRui Paulo static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
50535b9c547cSRui Paulo {
50545b9c547cSRui Paulo #ifdef CONFIG_WPS_TESTING
50555b9c547cSRui Paulo wps_version_number = 0x20;
50564b72b91aSCy Schubert wps_testing_stub_cred = 0;
50575b9c547cSRui Paulo wps_corrupt_pkhash = 0;
50585b9c547cSRui Paulo #endif /* CONFIG_WPS_TESTING */
505985732ac8SCy Schubert
506085732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
506185732ac8SCy Schubert #ifdef CONFIG_DPP
506285732ac8SCy Schubert dpp_test = DPP_TEST_DISABLED;
506332a95656SCy Schubert #ifdef CONFIG_DPP3
506432a95656SCy Schubert dpp_version_override = 3;
506532a95656SCy Schubert #elif defined(CONFIG_DPP2)
5066c1d255d3SCy Schubert dpp_version_override = 2;
5067c1d255d3SCy Schubert #else /* CONFIG_DPP2 */
5068c1d255d3SCy Schubert dpp_version_override = 1;
5069c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
507085732ac8SCy Schubert #endif /* CONFIG_DPP */
507185732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
507285732ac8SCy Schubert
507385732ac8SCy Schubert #ifdef CONFIG_DPP
50744bc52338SCy Schubert dpp_global_clear(interfaces->dpp);
5075*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
5076*a90b9d01SCy Schubert interfaces->dpp_pb_bi = NULL;
5077*a90b9d01SCy Schubert {
5078*a90b9d01SCy Schubert int i;
5079*a90b9d01SCy Schubert
5080*a90b9d01SCy Schubert for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
5081*a90b9d01SCy Schubert struct dpp_pb_info *info;
5082*a90b9d01SCy Schubert
5083*a90b9d01SCy Schubert info = &interfaces->dpp_pb[i];
5084*a90b9d01SCy Schubert info->rx_time.sec = 0;
5085*a90b9d01SCy Schubert info->rx_time.usec = 0;
5086*a90b9d01SCy Schubert }
5087*a90b9d01SCy Schubert }
5088*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
508985732ac8SCy Schubert #endif /* CONFIG_DPP */
50905b9c547cSRui Paulo }
50915b9c547cSRui Paulo
50925b9c547cSRui Paulo
5093325151a3SRui Paulo #ifdef CONFIG_FST
5094325151a3SRui Paulo
5095325151a3SRui Paulo static int
hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces * interfaces,const char * cmd)5096325151a3SRui Paulo hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces *interfaces,
5097325151a3SRui Paulo const char *cmd)
5098325151a3SRui Paulo {
5099325151a3SRui Paulo char ifname[IFNAMSIZ + 1];
5100325151a3SRui Paulo struct fst_iface_cfg cfg;
5101325151a3SRui Paulo struct hostapd_data *hapd;
5102325151a3SRui Paulo struct fst_wpa_obj iface_obj;
5103325151a3SRui Paulo
5104325151a3SRui Paulo if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
5105325151a3SRui Paulo hapd = hostapd_get_iface(interfaces, ifname);
5106325151a3SRui Paulo if (hapd) {
5107325151a3SRui Paulo if (hapd->iface->fst) {
5108325151a3SRui Paulo wpa_printf(MSG_INFO, "FST: Already attached");
5109325151a3SRui Paulo return -1;
5110325151a3SRui Paulo }
5111325151a3SRui Paulo fst_hostapd_fill_iface_obj(hapd, &iface_obj);
5112325151a3SRui Paulo hapd->iface->fst = fst_attach(ifname, hapd->own_addr,
5113325151a3SRui Paulo &iface_obj, &cfg);
5114325151a3SRui Paulo if (hapd->iface->fst)
5115325151a3SRui Paulo return 0;
5116325151a3SRui Paulo }
5117325151a3SRui Paulo }
5118325151a3SRui Paulo
5119325151a3SRui Paulo return -EINVAL;
5120325151a3SRui Paulo }
5121325151a3SRui Paulo
5122325151a3SRui Paulo
5123325151a3SRui Paulo static int
hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces * interfaces,const char * cmd)5124325151a3SRui Paulo hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces *interfaces,
5125325151a3SRui Paulo const char *cmd)
5126325151a3SRui Paulo {
5127325151a3SRui Paulo char ifname[IFNAMSIZ + 1];
5128325151a3SRui Paulo struct hostapd_data * hapd;
5129325151a3SRui Paulo
5130325151a3SRui Paulo if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
5131325151a3SRui Paulo hapd = hostapd_get_iface(interfaces, ifname);
5132325151a3SRui Paulo if (hapd) {
5133325151a3SRui Paulo if (!fst_iface_detach(ifname)) {
5134325151a3SRui Paulo hapd->iface->fst = NULL;
5135325151a3SRui Paulo hapd->iface->fst_ies = NULL;
5136325151a3SRui Paulo return 0;
5137325151a3SRui Paulo }
5138325151a3SRui Paulo }
5139325151a3SRui Paulo }
5140325151a3SRui Paulo
5141325151a3SRui Paulo return -EINVAL;
5142325151a3SRui Paulo }
5143325151a3SRui Paulo
5144325151a3SRui Paulo #endif /* CONFIG_FST */
5145325151a3SRui Paulo
5146325151a3SRui Paulo
5147325151a3SRui Paulo static struct hostapd_data *
hostapd_interfaces_get_hapd(struct hapd_interfaces * interfaces,const char * ifname)5148325151a3SRui Paulo hostapd_interfaces_get_hapd(struct hapd_interfaces *interfaces,
5149325151a3SRui Paulo const char *ifname)
5150325151a3SRui Paulo {
5151325151a3SRui Paulo size_t i, j;
5152325151a3SRui Paulo
5153325151a3SRui Paulo for (i = 0; i < interfaces->count; i++) {
5154325151a3SRui Paulo struct hostapd_iface *iface = interfaces->iface[i];
5155325151a3SRui Paulo
5156325151a3SRui Paulo for (j = 0; j < iface->num_bss; j++) {
5157325151a3SRui Paulo struct hostapd_data *hapd;
5158325151a3SRui Paulo
5159325151a3SRui Paulo hapd = iface->bss[j];
5160325151a3SRui Paulo if (os_strcmp(ifname, hapd->conf->iface) == 0)
5161325151a3SRui Paulo return hapd;
5162325151a3SRui Paulo }
5163325151a3SRui Paulo }
5164325151a3SRui Paulo
5165325151a3SRui Paulo return NULL;
5166325151a3SRui Paulo }
5167325151a3SRui Paulo
5168325151a3SRui Paulo
hostapd_ctrl_iface_dup_param(struct hostapd_data * src_hapd,struct hostapd_data * dst_hapd,const char * param)5169325151a3SRui Paulo static int hostapd_ctrl_iface_dup_param(struct hostapd_data *src_hapd,
5170325151a3SRui Paulo struct hostapd_data *dst_hapd,
5171325151a3SRui Paulo const char *param)
5172325151a3SRui Paulo {
5173325151a3SRui Paulo int res;
5174325151a3SRui Paulo char *value;
5175325151a3SRui Paulo
5176325151a3SRui Paulo value = os_zalloc(HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
5177325151a3SRui Paulo if (!value) {
5178325151a3SRui Paulo wpa_printf(MSG_ERROR,
5179325151a3SRui Paulo "DUP: cannot allocate buffer to stringify %s",
5180325151a3SRui Paulo param);
5181325151a3SRui Paulo goto error_return;
5182325151a3SRui Paulo }
5183325151a3SRui Paulo
5184325151a3SRui Paulo if (os_strcmp(param, "wpa") == 0) {
5185325151a3SRui Paulo os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%d",
5186325151a3SRui Paulo src_hapd->conf->wpa);
5187325151a3SRui Paulo } else if (os_strcmp(param, "wpa_key_mgmt") == 0 &&
5188325151a3SRui Paulo src_hapd->conf->wpa_key_mgmt) {
5189325151a3SRui Paulo res = hostapd_ctrl_iface_get_key_mgmt(
5190325151a3SRui Paulo src_hapd, value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
5191325151a3SRui Paulo if (os_snprintf_error(HOSTAPD_CLI_DUP_VALUE_MAX_LEN, res))
5192325151a3SRui Paulo goto error_stringify;
5193325151a3SRui Paulo } else if (os_strcmp(param, "wpa_pairwise") == 0 &&
5194325151a3SRui Paulo src_hapd->conf->wpa_pairwise) {
5195325151a3SRui Paulo res = wpa_write_ciphers(value,
5196325151a3SRui Paulo value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
5197325151a3SRui Paulo src_hapd->conf->wpa_pairwise, " ");
5198325151a3SRui Paulo if (res < 0)
5199325151a3SRui Paulo goto error_stringify;
5200325151a3SRui Paulo } else if (os_strcmp(param, "rsn_pairwise") == 0 &&
5201325151a3SRui Paulo src_hapd->conf->rsn_pairwise) {
5202325151a3SRui Paulo res = wpa_write_ciphers(value,
5203325151a3SRui Paulo value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
5204325151a3SRui Paulo src_hapd->conf->rsn_pairwise, " ");
5205325151a3SRui Paulo if (res < 0)
5206325151a3SRui Paulo goto error_stringify;
5207325151a3SRui Paulo } else if (os_strcmp(param, "wpa_passphrase") == 0 &&
5208325151a3SRui Paulo src_hapd->conf->ssid.wpa_passphrase) {
5209325151a3SRui Paulo os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%s",
5210325151a3SRui Paulo src_hapd->conf->ssid.wpa_passphrase);
5211325151a3SRui Paulo } else if (os_strcmp(param, "wpa_psk") == 0 &&
5212325151a3SRui Paulo src_hapd->conf->ssid.wpa_psk_set) {
5213325151a3SRui Paulo wpa_snprintf_hex(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
5214325151a3SRui Paulo src_hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
5215325151a3SRui Paulo } else {
5216325151a3SRui Paulo wpa_printf(MSG_WARNING, "DUP: %s cannot be duplicated", param);
5217325151a3SRui Paulo goto error_return;
5218325151a3SRui Paulo }
5219325151a3SRui Paulo
5220325151a3SRui Paulo res = hostapd_set_iface(dst_hapd->iconf, dst_hapd->conf, param, value);
5221325151a3SRui Paulo os_free(value);
5222325151a3SRui Paulo return res;
5223325151a3SRui Paulo
5224325151a3SRui Paulo error_stringify:
5225325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: cannot stringify %s", param);
5226325151a3SRui Paulo error_return:
5227325151a3SRui Paulo os_free(value);
5228325151a3SRui Paulo return -1;
5229325151a3SRui Paulo }
5230325151a3SRui Paulo
5231325151a3SRui Paulo
5232325151a3SRui Paulo static int
hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces * interfaces,const char * input,char * reply,int reply_size)5233780fb4a2SCy Schubert hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces,
5234780fb4a2SCy Schubert const char *input,
5235780fb4a2SCy Schubert char *reply, int reply_size)
5236780fb4a2SCy Schubert {
5237780fb4a2SCy Schubert size_t i, j;
5238780fb4a2SCy Schubert int res;
5239780fb4a2SCy Schubert char *pos, *end;
5240780fb4a2SCy Schubert struct hostapd_iface *iface;
5241780fb4a2SCy Schubert int show_ctrl = 0;
5242780fb4a2SCy Schubert
5243780fb4a2SCy Schubert if (input)
5244780fb4a2SCy Schubert show_ctrl = !!os_strstr(input, "ctrl");
5245780fb4a2SCy Schubert
5246780fb4a2SCy Schubert pos = reply;
5247780fb4a2SCy Schubert end = reply + reply_size;
5248780fb4a2SCy Schubert
5249780fb4a2SCy Schubert for (i = 0; i < interfaces->count; i++) {
5250780fb4a2SCy Schubert iface = interfaces->iface[i];
5251780fb4a2SCy Schubert
5252780fb4a2SCy Schubert for (j = 0; j < iface->num_bss; j++) {
5253780fb4a2SCy Schubert struct hostapd_bss_config *conf;
5254780fb4a2SCy Schubert
5255780fb4a2SCy Schubert conf = iface->conf->bss[j];
5256780fb4a2SCy Schubert if (show_ctrl)
5257780fb4a2SCy Schubert res = os_snprintf(pos, end - pos,
5258780fb4a2SCy Schubert "%s ctrl_iface=%s\n",
5259780fb4a2SCy Schubert conf->iface,
5260780fb4a2SCy Schubert conf->ctrl_interface ?
5261780fb4a2SCy Schubert conf->ctrl_interface : "N/A");
5262780fb4a2SCy Schubert else
5263780fb4a2SCy Schubert res = os_snprintf(pos, end - pos, "%s\n",
5264780fb4a2SCy Schubert conf->iface);
5265780fb4a2SCy Schubert if (os_snprintf_error(end - pos, res)) {
5266780fb4a2SCy Schubert *pos = '\0';
5267780fb4a2SCy Schubert return pos - reply;
5268780fb4a2SCy Schubert }
5269780fb4a2SCy Schubert pos += res;
5270780fb4a2SCy Schubert }
5271780fb4a2SCy Schubert }
5272780fb4a2SCy Schubert
5273780fb4a2SCy Schubert return pos - reply;
5274780fb4a2SCy Schubert }
5275780fb4a2SCy Schubert
5276780fb4a2SCy Schubert
5277780fb4a2SCy Schubert static int
hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces * interfaces,char * cmd)5278325151a3SRui Paulo hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
5279325151a3SRui Paulo char *cmd)
5280325151a3SRui Paulo {
5281325151a3SRui Paulo char *p_start = cmd, *p_end;
5282325151a3SRui Paulo struct hostapd_data *src_hapd, *dst_hapd;
5283325151a3SRui Paulo
5284325151a3SRui Paulo /* cmd: "<src ifname> <dst ifname> <variable name> */
5285325151a3SRui Paulo
5286325151a3SRui Paulo p_end = os_strchr(p_start, ' ');
5287325151a3SRui Paulo if (!p_end) {
5288325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: no src ifname found in cmd: '%s'",
5289325151a3SRui Paulo cmd);
5290325151a3SRui Paulo return -1;
5291325151a3SRui Paulo }
5292325151a3SRui Paulo
5293325151a3SRui Paulo *p_end = '\0';
5294325151a3SRui Paulo src_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
5295325151a3SRui Paulo if (!src_hapd) {
5296325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: no src ifname found: '%s'",
5297325151a3SRui Paulo p_start);
5298325151a3SRui Paulo return -1;
5299325151a3SRui Paulo }
5300325151a3SRui Paulo
5301325151a3SRui Paulo p_start = p_end + 1;
5302325151a3SRui Paulo p_end = os_strchr(p_start, ' ');
5303325151a3SRui Paulo if (!p_end) {
5304325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: no dst ifname found in cmd: '%s'",
5305325151a3SRui Paulo cmd);
5306325151a3SRui Paulo return -1;
5307325151a3SRui Paulo }
5308325151a3SRui Paulo
5309325151a3SRui Paulo *p_end = '\0';
5310325151a3SRui Paulo dst_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
5311325151a3SRui Paulo if (!dst_hapd) {
5312325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: no dst ifname found: '%s'",
5313325151a3SRui Paulo p_start);
5314325151a3SRui Paulo return -1;
5315325151a3SRui Paulo }
5316325151a3SRui Paulo
5317325151a3SRui Paulo p_start = p_end + 1;
5318325151a3SRui Paulo return hostapd_ctrl_iface_dup_param(src_hapd, dst_hapd, p_start);
5319325151a3SRui Paulo }
5320325151a3SRui Paulo
5321325151a3SRui Paulo
hostapd_global_ctrl_iface_ifname(struct hapd_interfaces * interfaces,const char * ifname,char * buf,char * reply,int reply_size,struct sockaddr_storage * from,socklen_t fromlen)5322325151a3SRui Paulo static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
5323325151a3SRui Paulo const char *ifname,
5324325151a3SRui Paulo char *buf, char *reply,
5325325151a3SRui Paulo int reply_size,
5326780fb4a2SCy Schubert struct sockaddr_storage *from,
5327325151a3SRui Paulo socklen_t fromlen)
5328325151a3SRui Paulo {
5329325151a3SRui Paulo struct hostapd_data *hapd;
5330325151a3SRui Paulo
5331325151a3SRui Paulo hapd = hostapd_interfaces_get_hapd(interfaces, ifname);
5332325151a3SRui Paulo if (hapd == NULL) {
5333325151a3SRui Paulo int res;
5334325151a3SRui Paulo
5335325151a3SRui Paulo res = os_snprintf(reply, reply_size, "FAIL-NO-IFNAME-MATCH\n");
5336325151a3SRui Paulo if (os_snprintf_error(reply_size, res))
5337325151a3SRui Paulo return -1;
5338325151a3SRui Paulo return res;
5339325151a3SRui Paulo }
5340325151a3SRui Paulo
5341325151a3SRui Paulo return hostapd_ctrl_iface_receive_process(hapd, buf, reply,reply_size,
5342325151a3SRui Paulo from, fromlen);
5343325151a3SRui Paulo }
5344325151a3SRui Paulo
5345325151a3SRui Paulo
hostapd_global_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)5346f05cddf9SRui Paulo static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
5347f05cddf9SRui Paulo void *sock_ctx)
5348f05cddf9SRui Paulo {
5349c1d255d3SCy Schubert struct hapd_interfaces *interfaces = eloop_ctx;
5350780fb4a2SCy Schubert char buffer[256], *buf = buffer;
5351f05cddf9SRui Paulo int res;
5352780fb4a2SCy Schubert struct sockaddr_storage from;
5353f05cddf9SRui Paulo socklen_t fromlen = sizeof(from);
5354325151a3SRui Paulo char *reply;
5355f05cddf9SRui Paulo int reply_len;
5356325151a3SRui Paulo const int reply_size = 4096;
5357780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
5358c1d255d3SCy Schubert unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
5359780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
5360f05cddf9SRui Paulo
5361780fb4a2SCy Schubert res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
5362f05cddf9SRui Paulo (struct sockaddr *) &from, &fromlen);
5363f05cddf9SRui Paulo if (res < 0) {
53645b9c547cSRui Paulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
53655b9c547cSRui Paulo strerror(errno));
5366f05cddf9SRui Paulo return;
5367f05cddf9SRui Paulo }
5368f05cddf9SRui Paulo buf[res] = '\0';
53695b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
5370f05cddf9SRui Paulo
5371325151a3SRui Paulo reply = os_malloc(reply_size);
5372325151a3SRui Paulo if (reply == NULL) {
5373325151a3SRui Paulo if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
5374325151a3SRui Paulo fromlen) < 0) {
5375325151a3SRui Paulo wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
5376325151a3SRui Paulo strerror(errno));
5377325151a3SRui Paulo }
5378325151a3SRui Paulo return;
5379325151a3SRui Paulo }
5380325151a3SRui Paulo
5381f05cddf9SRui Paulo os_memcpy(reply, "OK\n", 3);
5382f05cddf9SRui Paulo reply_len = 3;
5383f05cddf9SRui Paulo
5384780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
5385780fb4a2SCy Schubert if (os_strcmp(buf, "GET_COOKIE") == 0) {
5386780fb4a2SCy Schubert os_memcpy(reply, "COOKIE=", 7);
5387c1d255d3SCy Schubert wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
5388c1d255d3SCy Schubert interfaces->ctrl_iface_cookie,
5389c1d255d3SCy Schubert CTRL_IFACE_COOKIE_LEN);
5390c1d255d3SCy Schubert reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
5391780fb4a2SCy Schubert goto send_reply;
5392780fb4a2SCy Schubert }
5393780fb4a2SCy Schubert
5394780fb4a2SCy Schubert if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
5395c1d255d3SCy Schubert hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
5396780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
5397780fb4a2SCy Schubert "CTRL: No cookie in the request - drop request");
5398780fb4a2SCy Schubert os_free(reply);
5399780fb4a2SCy Schubert return;
5400780fb4a2SCy Schubert }
5401780fb4a2SCy Schubert
5402c1d255d3SCy Schubert if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie,
5403c1d255d3SCy Schubert CTRL_IFACE_COOKIE_LEN) != 0) {
5404780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
5405780fb4a2SCy Schubert "CTRL: Invalid cookie in the request - drop request");
5406780fb4a2SCy Schubert os_free(reply);
5407780fb4a2SCy Schubert return;
5408780fb4a2SCy Schubert }
5409780fb4a2SCy Schubert
5410c1d255d3SCy Schubert buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
5411780fb4a2SCy Schubert while (*buf == ' ')
5412780fb4a2SCy Schubert buf++;
5413780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
5414780fb4a2SCy Schubert
5415325151a3SRui Paulo if (os_strncmp(buf, "IFNAME=", 7) == 0) {
5416325151a3SRui Paulo char *pos = os_strchr(buf + 7, ' ');
5417325151a3SRui Paulo
5418325151a3SRui Paulo if (pos) {
5419325151a3SRui Paulo *pos++ = '\0';
5420325151a3SRui Paulo reply_len = hostapd_global_ctrl_iface_ifname(
5421325151a3SRui Paulo interfaces, buf + 7, pos, reply, reply_size,
5422325151a3SRui Paulo &from, fromlen);
5423325151a3SRui Paulo goto send_reply;
5424325151a3SRui Paulo }
5425325151a3SRui Paulo }
5426325151a3SRui Paulo
5427f05cddf9SRui Paulo if (os_strcmp(buf, "PING") == 0) {
5428f05cddf9SRui Paulo os_memcpy(reply, "PONG\n", 5);
5429f05cddf9SRui Paulo reply_len = 5;
54305b9c547cSRui Paulo } else if (os_strncmp(buf, "RELOG", 5) == 0) {
54315b9c547cSRui Paulo if (wpa_debug_reopen_file() < 0)
54325b9c547cSRui Paulo reply_len = -1;
54335b9c547cSRui Paulo } else if (os_strcmp(buf, "FLUSH") == 0) {
54345b9c547cSRui Paulo hostapd_ctrl_iface_flush(interfaces);
5435f05cddf9SRui Paulo } else if (os_strncmp(buf, "ADD ", 4) == 0) {
5436f05cddf9SRui Paulo if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
5437f05cddf9SRui Paulo reply_len = -1;
5438f05cddf9SRui Paulo } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
5439f05cddf9SRui Paulo if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
5440f05cddf9SRui Paulo reply_len = -1;
5441325151a3SRui Paulo } else if (os_strcmp(buf, "ATTACH") == 0) {
5442325151a3SRui Paulo if (hostapd_global_ctrl_iface_attach(interfaces, &from,
544385732ac8SCy Schubert fromlen, NULL))
544485732ac8SCy Schubert reply_len = -1;
544585732ac8SCy Schubert } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
544685732ac8SCy Schubert if (hostapd_global_ctrl_iface_attach(interfaces, &from,
544785732ac8SCy Schubert fromlen, buf + 7))
5448325151a3SRui Paulo reply_len = -1;
5449325151a3SRui Paulo } else if (os_strcmp(buf, "DETACH") == 0) {
5450325151a3SRui Paulo if (hostapd_global_ctrl_iface_detach(interfaces, &from,
5451325151a3SRui Paulo fromlen))
5452325151a3SRui Paulo reply_len = -1;
54535b9c547cSRui Paulo #ifdef CONFIG_MODULE_TESTS
54545b9c547cSRui Paulo } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
54555b9c547cSRui Paulo if (hapd_module_tests() < 0)
54565b9c547cSRui Paulo reply_len = -1;
54575b9c547cSRui Paulo #endif /* CONFIG_MODULE_TESTS */
5458325151a3SRui Paulo #ifdef CONFIG_FST
5459325151a3SRui Paulo } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
5460325151a3SRui Paulo if (!hostapd_global_ctrl_iface_fst_attach(interfaces, buf + 11))
5461325151a3SRui Paulo reply_len = os_snprintf(reply, reply_size, "OK\n");
5462325151a3SRui Paulo else
5463325151a3SRui Paulo reply_len = -1;
5464325151a3SRui Paulo } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
5465325151a3SRui Paulo if (!hostapd_global_ctrl_iface_fst_detach(interfaces, buf + 11))
5466325151a3SRui Paulo reply_len = os_snprintf(reply, reply_size, "OK\n");
5467325151a3SRui Paulo else
5468325151a3SRui Paulo reply_len = -1;
5469325151a3SRui Paulo } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
5470325151a3SRui Paulo reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
5471325151a3SRui Paulo #endif /* CONFIG_FST */
5472325151a3SRui Paulo } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
5473325151a3SRui Paulo if (!hostapd_global_ctrl_iface_dup_network(interfaces,
5474325151a3SRui Paulo buf + 12))
5475325151a3SRui Paulo reply_len = os_snprintf(reply, reply_size, "OK\n");
5476325151a3SRui Paulo else
5477325151a3SRui Paulo reply_len = -1;
5478780fb4a2SCy Schubert } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
5479780fb4a2SCy Schubert reply_len = hostapd_global_ctrl_iface_interfaces(
5480*a90b9d01SCy Schubert interfaces, buf + 10, reply, reply_size);
5481780fb4a2SCy Schubert } else if (os_strcmp(buf, "TERMINATE") == 0) {
5482780fb4a2SCy Schubert eloop_terminate();
5483f05cddf9SRui Paulo } else {
5484f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
5485f05cddf9SRui Paulo "ignored");
5486f05cddf9SRui Paulo reply_len = -1;
5487f05cddf9SRui Paulo }
5488f05cddf9SRui Paulo
5489325151a3SRui Paulo send_reply:
5490f05cddf9SRui Paulo if (reply_len < 0) {
5491f05cddf9SRui Paulo os_memcpy(reply, "FAIL\n", 5);
5492f05cddf9SRui Paulo reply_len = 5;
5493f05cddf9SRui Paulo }
5494f05cddf9SRui Paulo
54955b9c547cSRui Paulo if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
54965b9c547cSRui Paulo fromlen) < 0) {
54975b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
54985b9c547cSRui Paulo strerror(errno));
54995b9c547cSRui Paulo }
5500325151a3SRui Paulo os_free(reply);
5501f05cddf9SRui Paulo }
5502f05cddf9SRui Paulo
5503f05cddf9SRui Paulo
5504780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
hostapd_global_ctrl_iface_path(struct hapd_interfaces * interface)5505f05cddf9SRui Paulo static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
5506f05cddf9SRui Paulo {
5507f05cddf9SRui Paulo char *buf;
5508f05cddf9SRui Paulo size_t len;
5509f05cddf9SRui Paulo
5510f05cddf9SRui Paulo if (interface->global_iface_path == NULL)
5511f05cddf9SRui Paulo return NULL;
5512f05cddf9SRui Paulo
5513f05cddf9SRui Paulo len = os_strlen(interface->global_iface_path) +
5514f05cddf9SRui Paulo os_strlen(interface->global_iface_name) + 2;
5515f05cddf9SRui Paulo buf = os_malloc(len);
5516f05cddf9SRui Paulo if (buf == NULL)
5517f05cddf9SRui Paulo return NULL;
5518f05cddf9SRui Paulo
5519f05cddf9SRui Paulo os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
5520f05cddf9SRui Paulo interface->global_iface_name);
5521f05cddf9SRui Paulo buf[len - 1] = '\0';
5522f05cddf9SRui Paulo return buf;
5523f05cddf9SRui Paulo }
5524780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
5525f05cddf9SRui Paulo
5526f05cddf9SRui Paulo
hostapd_global_ctrl_iface_init(struct hapd_interfaces * interface)5527f05cddf9SRui Paulo int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
5528f05cddf9SRui Paulo {
5529780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
5530780fb4a2SCy Schubert int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
5531780fb4a2SCy Schubert char p[32] = { 0 };
5532780fb4a2SCy Schubert char *pos;
5533780fb4a2SCy Schubert struct addrinfo hints = { 0 }, *res, *saveres;
5534780fb4a2SCy Schubert int n;
5535780fb4a2SCy Schubert
5536780fb4a2SCy Schubert if (interface->global_ctrl_sock > -1) {
5537780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
5538780fb4a2SCy Schubert return 0;
5539780fb4a2SCy Schubert }
5540780fb4a2SCy Schubert
5541780fb4a2SCy Schubert if (interface->global_iface_path == NULL)
5542780fb4a2SCy Schubert return 0;
5543780fb4a2SCy Schubert
5544780fb4a2SCy Schubert pos = os_strstr(interface->global_iface_path, "udp:");
5545780fb4a2SCy Schubert if (pos) {
5546780fb4a2SCy Schubert pos += 4;
5547780fb4a2SCy Schubert port = atoi(pos);
5548780fb4a2SCy Schubert if (port <= 0) {
5549780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port");
5550780fb4a2SCy Schubert goto fail;
5551780fb4a2SCy Schubert }
5552780fb4a2SCy Schubert }
5553780fb4a2SCy Schubert
5554c1d255d3SCy Schubert os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
5555780fb4a2SCy Schubert
5556780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
5557780fb4a2SCy Schubert hints.ai_flags = AI_PASSIVE;
5558780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
5559780fb4a2SCy Schubert
5560780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
5561780fb4a2SCy Schubert hints.ai_family = AF_INET6;
5562780fb4a2SCy Schubert #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
5563780fb4a2SCy Schubert hints.ai_family = AF_INET;
5564780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
5565780fb4a2SCy Schubert hints.ai_socktype = SOCK_DGRAM;
5566780fb4a2SCy Schubert
5567780fb4a2SCy Schubert try_again:
5568780fb4a2SCy Schubert os_snprintf(p, sizeof(p), "%d", port);
5569780fb4a2SCy Schubert n = getaddrinfo(NULL, p, &hints, &res);
5570780fb4a2SCy Schubert if (n) {
5571780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
5572780fb4a2SCy Schubert goto fail;
5573780fb4a2SCy Schubert }
5574780fb4a2SCy Schubert
5575780fb4a2SCy Schubert saveres = res;
5576780fb4a2SCy Schubert interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
5577780fb4a2SCy Schubert res->ai_protocol);
5578780fb4a2SCy Schubert if (interface->global_ctrl_sock < 0) {
5579780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
5580780fb4a2SCy Schubert goto fail;
5581780fb4a2SCy Schubert }
5582780fb4a2SCy Schubert
5583780fb4a2SCy Schubert if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
5584780fb4a2SCy Schubert 0) {
5585780fb4a2SCy Schubert port++;
5586780fb4a2SCy Schubert if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
5587780fb4a2SCy Schubert HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
5588780fb4a2SCy Schubert goto try_again;
5589780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
5590780fb4a2SCy Schubert goto fail;
5591780fb4a2SCy Schubert }
5592780fb4a2SCy Schubert
5593780fb4a2SCy Schubert freeaddrinfo(saveres);
5594780fb4a2SCy Schubert
5595780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
5596780fb4a2SCy Schubert
5597780fb4a2SCy Schubert if (eloop_register_read_sock(interface->global_ctrl_sock,
5598780fb4a2SCy Schubert hostapd_global_ctrl_iface_receive,
5599780fb4a2SCy Schubert interface, NULL) < 0) {
5600780fb4a2SCy Schubert hostapd_global_ctrl_iface_deinit(interface);
5601780fb4a2SCy Schubert return -1;
5602780fb4a2SCy Schubert }
5603780fb4a2SCy Schubert
5604c1d255d3SCy Schubert wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
5605c1d255d3SCy Schubert
5606780fb4a2SCy Schubert return 0;
5607780fb4a2SCy Schubert
5608780fb4a2SCy Schubert fail:
5609780fb4a2SCy Schubert if (interface->global_ctrl_sock >= 0)
5610780fb4a2SCy Schubert close(interface->global_ctrl_sock);
5611780fb4a2SCy Schubert return -1;
5612780fb4a2SCy Schubert #else /* CONFIG_CTRL_IFACE_UDP */
5613f05cddf9SRui Paulo struct sockaddr_un addr;
5614f05cddf9SRui Paulo int s = -1;
5615f05cddf9SRui Paulo char *fname = NULL;
5616f05cddf9SRui Paulo
5617f05cddf9SRui Paulo if (interface->global_iface_path == NULL) {
5618f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
5619f05cddf9SRui Paulo return 0;
5620f05cddf9SRui Paulo }
5621f05cddf9SRui Paulo
5622f05cddf9SRui Paulo if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
5623f05cddf9SRui Paulo if (errno == EEXIST) {
5624f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Using existing control "
5625f05cddf9SRui Paulo "interface directory.");
5626f05cddf9SRui Paulo } else {
56275b9c547cSRui Paulo wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
56285b9c547cSRui Paulo strerror(errno));
5629f05cddf9SRui Paulo goto fail;
5630f05cddf9SRui Paulo }
56315b9c547cSRui Paulo } else if (interface->ctrl_iface_group &&
56324bc52338SCy Schubert lchown(interface->global_iface_path, -1,
56335b9c547cSRui Paulo interface->ctrl_iface_group) < 0) {
56344bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
56355b9c547cSRui Paulo strerror(errno));
56365b9c547cSRui Paulo goto fail;
5637f05cddf9SRui Paulo }
5638f05cddf9SRui Paulo
5639f05cddf9SRui Paulo if (os_strlen(interface->global_iface_path) + 1 +
5640f05cddf9SRui Paulo os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
5641f05cddf9SRui Paulo goto fail;
5642f05cddf9SRui Paulo
5643f05cddf9SRui Paulo s = socket(PF_UNIX, SOCK_DGRAM, 0);
5644f05cddf9SRui Paulo if (s < 0) {
56455b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
5646f05cddf9SRui Paulo goto fail;
5647f05cddf9SRui Paulo }
5648f05cddf9SRui Paulo
5649f05cddf9SRui Paulo os_memset(&addr, 0, sizeof(addr));
5650f05cddf9SRui Paulo #ifdef __FreeBSD__
5651f05cddf9SRui Paulo addr.sun_len = sizeof(addr);
5652f05cddf9SRui Paulo #endif /* __FreeBSD__ */
5653f05cddf9SRui Paulo addr.sun_family = AF_UNIX;
5654f05cddf9SRui Paulo fname = hostapd_global_ctrl_iface_path(interface);
5655f05cddf9SRui Paulo if (fname == NULL)
5656f05cddf9SRui Paulo goto fail;
5657f05cddf9SRui Paulo os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
5658f05cddf9SRui Paulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
5659f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
5660f05cddf9SRui Paulo strerror(errno));
5661f05cddf9SRui Paulo if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
5662f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
5663f05cddf9SRui Paulo " allow connections - assuming it was left"
5664f05cddf9SRui Paulo "over from forced program termination");
5665f05cddf9SRui Paulo if (unlink(fname) < 0) {
56665b9c547cSRui Paulo wpa_printf(MSG_ERROR,
56675b9c547cSRui Paulo "Could not unlink existing ctrl_iface socket '%s': %s",
56685b9c547cSRui Paulo fname, strerror(errno));
5669f05cddf9SRui Paulo goto fail;
5670f05cddf9SRui Paulo }
5671f05cddf9SRui Paulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
5672f05cddf9SRui Paulo 0) {
56735b9c547cSRui Paulo wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
56745b9c547cSRui Paulo strerror(errno));
5675f05cddf9SRui Paulo goto fail;
5676f05cddf9SRui Paulo }
5677f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
5678f05cddf9SRui Paulo "ctrl_iface socket '%s'", fname);
5679f05cddf9SRui Paulo } else {
5680f05cddf9SRui Paulo wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
5681f05cddf9SRui Paulo "be in use - cannot override it");
5682f05cddf9SRui Paulo wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
5683f05cddf9SRui Paulo "not used anymore", fname);
5684f05cddf9SRui Paulo os_free(fname);
5685f05cddf9SRui Paulo fname = NULL;
5686f05cddf9SRui Paulo goto fail;
5687f05cddf9SRui Paulo }
5688f05cddf9SRui Paulo }
5689f05cddf9SRui Paulo
56905b9c547cSRui Paulo if (interface->ctrl_iface_group &&
56914bc52338SCy Schubert lchown(fname, -1, interface->ctrl_iface_group) < 0) {
56924bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
56935b9c547cSRui Paulo strerror(errno));
56945b9c547cSRui Paulo goto fail;
56955b9c547cSRui Paulo }
56965b9c547cSRui Paulo
5697f05cddf9SRui Paulo if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
56985b9c547cSRui Paulo wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
56995b9c547cSRui Paulo strerror(errno));
5700f05cddf9SRui Paulo goto fail;
5701f05cddf9SRui Paulo }
5702f05cddf9SRui Paulo os_free(fname);
5703f05cddf9SRui Paulo
5704f05cddf9SRui Paulo interface->global_ctrl_sock = s;
5705f05cddf9SRui Paulo eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
5706f05cddf9SRui Paulo interface, NULL);
5707f05cddf9SRui Paulo
5708c1d255d3SCy Schubert wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
5709c1d255d3SCy Schubert
5710f05cddf9SRui Paulo return 0;
5711f05cddf9SRui Paulo
5712f05cddf9SRui Paulo fail:
5713f05cddf9SRui Paulo if (s >= 0)
5714f05cddf9SRui Paulo close(s);
5715f05cddf9SRui Paulo if (fname) {
5716f05cddf9SRui Paulo unlink(fname);
5717f05cddf9SRui Paulo os_free(fname);
5718f05cddf9SRui Paulo }
5719f05cddf9SRui Paulo return -1;
5720780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
5721f05cddf9SRui Paulo }
5722f05cddf9SRui Paulo
5723f05cddf9SRui Paulo
hostapd_global_ctrl_iface_deinit(struct hapd_interfaces * interfaces)5724f05cddf9SRui Paulo void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
5725f05cddf9SRui Paulo {
5726780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
5727f05cddf9SRui Paulo char *fname = NULL;
5728780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
5729325151a3SRui Paulo struct wpa_ctrl_dst *dst, *prev;
5730f05cddf9SRui Paulo
5731f05cddf9SRui Paulo if (interfaces->global_ctrl_sock > -1) {
5732f05cddf9SRui Paulo eloop_unregister_read_sock(interfaces->global_ctrl_sock);
5733f05cddf9SRui Paulo close(interfaces->global_ctrl_sock);
5734f05cddf9SRui Paulo interfaces->global_ctrl_sock = -1;
5735780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
5736f05cddf9SRui Paulo fname = hostapd_global_ctrl_iface_path(interfaces);
5737f05cddf9SRui Paulo if (fname) {
5738f05cddf9SRui Paulo unlink(fname);
5739f05cddf9SRui Paulo os_free(fname);
5740f05cddf9SRui Paulo }
5741f05cddf9SRui Paulo
5742f05cddf9SRui Paulo if (interfaces->global_iface_path &&
5743f05cddf9SRui Paulo rmdir(interfaces->global_iface_path) < 0) {
5744f05cddf9SRui Paulo if (errno == ENOTEMPTY) {
5745f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Control interface "
5746f05cddf9SRui Paulo "directory not empty - leaving it "
5747f05cddf9SRui Paulo "behind");
5748f05cddf9SRui Paulo } else {
57495b9c547cSRui Paulo wpa_printf(MSG_ERROR,
57505b9c547cSRui Paulo "rmdir[ctrl_interface=%s]: %s",
57515b9c547cSRui Paulo interfaces->global_iface_path,
57525b9c547cSRui Paulo strerror(errno));
5753f05cddf9SRui Paulo }
5754f05cddf9SRui Paulo }
5755780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
5756325151a3SRui Paulo }
5757325151a3SRui Paulo
5758f05cddf9SRui Paulo os_free(interfaces->global_iface_path);
5759f05cddf9SRui Paulo interfaces->global_iface_path = NULL;
5760325151a3SRui Paulo
5761780fb4a2SCy Schubert dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst,
5762780fb4a2SCy Schubert struct wpa_ctrl_dst, list)
5763780fb4a2SCy Schubert os_free(dst);
5764f05cddf9SRui Paulo }
5765f05cddf9SRui Paulo
5766f05cddf9SRui Paulo
hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst * dst,const char * buf)576785732ac8SCy Schubert static int hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst *dst,
576885732ac8SCy Schubert const char *buf)
576985732ac8SCy Schubert {
577085732ac8SCy Schubert /* Enable Probe Request events based on explicit request.
577185732ac8SCy Schubert * Other events are enabled by default.
577285732ac8SCy Schubert */
577385732ac8SCy Schubert if (str_starts(buf, RX_PROBE_REQUEST))
577485732ac8SCy Schubert return !!(dst->events & WPA_EVENT_RX_PROBE_REQUEST);
577585732ac8SCy Schubert return 1;
577685732ac8SCy Schubert }
577785732ac8SCy Schubert
577885732ac8SCy Schubert
hostapd_ctrl_iface_send_internal(int sock,struct dl_list * ctrl_dst,const char * ifname,int level,const char * buf,size_t len)5779c1d255d3SCy Schubert static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst,
5780c1d255d3SCy Schubert const char *ifname, int level,
578139beb93cSSam Leffler const char *buf, size_t len)
578239beb93cSSam Leffler {
578339beb93cSSam Leffler struct wpa_ctrl_dst *dst, *next;
578439beb93cSSam Leffler struct msghdr msg;
5785c1d255d3SCy Schubert int idx, res;
5786c1d255d3SCy Schubert struct iovec io[5];
578739beb93cSSam Leffler char levelstr[10];
578839beb93cSSam Leffler
5789c1d255d3SCy Schubert if (sock < 0 || dl_list_empty(ctrl_dst))
579039beb93cSSam Leffler return;
579139beb93cSSam Leffler
5792c1d255d3SCy Schubert res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
5793c1d255d3SCy Schubert if (os_snprintf_error(sizeof(levelstr), res))
5794c1d255d3SCy Schubert return;
5795c1d255d3SCy Schubert idx = 0;
5796c1d255d3SCy Schubert if (ifname) {
5797c1d255d3SCy Schubert io[idx].iov_base = "IFNAME=";
5798c1d255d3SCy Schubert io[idx].iov_len = 7;
5799c1d255d3SCy Schubert idx++;
5800c1d255d3SCy Schubert io[idx].iov_base = (char *) ifname;
5801c1d255d3SCy Schubert io[idx].iov_len = os_strlen(ifname);
5802c1d255d3SCy Schubert idx++;
5803c1d255d3SCy Schubert io[idx].iov_base = " ";
5804c1d255d3SCy Schubert io[idx].iov_len = 1;
5805c1d255d3SCy Schubert idx++;
5806c1d255d3SCy Schubert }
5807c1d255d3SCy Schubert io[idx].iov_base = levelstr;
5808c1d255d3SCy Schubert io[idx].iov_len = os_strlen(levelstr);
5809c1d255d3SCy Schubert idx++;
5810c1d255d3SCy Schubert io[idx].iov_base = (char *) buf;
5811c1d255d3SCy Schubert io[idx].iov_len = len;
5812c1d255d3SCy Schubert idx++;
581339beb93cSSam Leffler os_memset(&msg, 0, sizeof(msg));
581439beb93cSSam Leffler msg.msg_iov = io;
5815c1d255d3SCy Schubert msg.msg_iovlen = idx;
581639beb93cSSam Leffler
581739beb93cSSam Leffler idx = 0;
5818780fb4a2SCy Schubert dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
581985732ac8SCy Schubert if ((level >= dst->debug_level) &&
582085732ac8SCy Schubert hostapd_ctrl_check_event_enabled(dst, buf)) {
5821780fb4a2SCy Schubert sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
5822780fb4a2SCy Schubert &dst->addr, dst->addrlen);
582339beb93cSSam Leffler msg.msg_name = &dst->addr;
582439beb93cSSam Leffler msg.msg_namelen = dst->addrlen;
5825c1d255d3SCy Schubert if (sendmsg(sock, &msg, 0) < 0) {
58263157ba21SRui Paulo int _errno = errno;
58273157ba21SRui Paulo wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
58283157ba21SRui Paulo "%d - %s",
58293157ba21SRui Paulo idx, errno, strerror(errno));
583039beb93cSSam Leffler dst->errors++;
58313157ba21SRui Paulo if (dst->errors > 10 || _errno == ENOENT) {
5832c1d255d3SCy Schubert ctrl_iface_detach(ctrl_dst,
5833325151a3SRui Paulo &dst->addr,
5834325151a3SRui Paulo dst->addrlen);
583539beb93cSSam Leffler }
583639beb93cSSam Leffler } else
583739beb93cSSam Leffler dst->errors = 0;
583839beb93cSSam Leffler }
583939beb93cSSam Leffler idx++;
584039beb93cSSam Leffler }
584139beb93cSSam Leffler }
584239beb93cSSam Leffler
5843c1d255d3SCy Schubert
hostapd_ctrl_iface_send(struct hostapd_data * hapd,int level,enum wpa_msg_type type,const char * buf,size_t len)5844c1d255d3SCy Schubert static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
5845c1d255d3SCy Schubert enum wpa_msg_type type,
5846c1d255d3SCy Schubert const char *buf, size_t len)
5847c1d255d3SCy Schubert {
5848c1d255d3SCy Schubert if (type != WPA_MSG_NO_GLOBAL) {
5849c1d255d3SCy Schubert hostapd_ctrl_iface_send_internal(
5850c1d255d3SCy Schubert hapd->iface->interfaces->global_ctrl_sock,
5851c1d255d3SCy Schubert &hapd->iface->interfaces->global_ctrl_dst,
5852c1d255d3SCy Schubert type != WPA_MSG_PER_INTERFACE ?
5853c1d255d3SCy Schubert NULL : hapd->conf->iface,
5854c1d255d3SCy Schubert level, buf, len);
5855c1d255d3SCy Schubert }
5856c1d255d3SCy Schubert
5857c1d255d3SCy Schubert if (type != WPA_MSG_ONLY_GLOBAL) {
5858c1d255d3SCy Schubert hostapd_ctrl_iface_send_internal(
5859c1d255d3SCy Schubert hapd->ctrl_sock, &hapd->ctrl_dst,
5860c1d255d3SCy Schubert NULL, level, buf, len);
5861c1d255d3SCy Schubert }
5862c1d255d3SCy Schubert }
5863c1d255d3SCy Schubert
586439beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
5865