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"
415b9c547cSRui Paulo #include "crypto/tls.h"
42e28a4053SRui Paulo #include "drivers/driver.h"
43325151a3SRui Paulo #include "eapol_auth/eapol_auth_sm.h"
4439beb93cSSam Leffler #include "radius/radius_client.h"
455b9c547cSRui Paulo #include "radius/radius_server.h"
465b9c547cSRui Paulo #include "l2_packet/l2_packet.h"
47e28a4053SRui Paulo #include "ap/hostapd.h"
48e28a4053SRui Paulo #include "ap/ap_config.h"
49e28a4053SRui Paulo #include "ap/ieee802_1x.h"
50e28a4053SRui Paulo #include "ap/wpa_auth.h"
51c1d255d3SCy Schubert #include "ap/pmksa_cache_auth.h"
52e28a4053SRui Paulo #include "ap/ieee802_11.h"
53e28a4053SRui Paulo #include "ap/sta_info.h"
54e28a4053SRui Paulo #include "ap/wps_hostapd.h"
55e28a4053SRui Paulo #include "ap/ctrl_iface_ap.h"
56f05cddf9SRui Paulo #include "ap/ap_drv_ops.h"
575b9c547cSRui Paulo #include "ap/hs20.h"
585b9c547cSRui Paulo #include "ap/wnm_ap.h"
595b9c547cSRui Paulo #include "ap/wpa_auth.h"
605b9c547cSRui Paulo #include "ap/beacon.h"
61780fb4a2SCy Schubert #include "ap/neighbor_db.h"
62780fb4a2SCy Schubert #include "ap/rrm.h"
6385732ac8SCy Schubert #include "ap/dpp_hostapd.h"
64c1d255d3SCy Schubert #include "ap/dfs.h"
65f05cddf9SRui Paulo #include "wps/wps_defs.h"
66f05cddf9SRui Paulo #include "wps/wps.h"
67325151a3SRui Paulo #include "fst/fst_ctrl_iface.h"
68f05cddf9SRui Paulo #include "config_file.h"
6939beb93cSSam Leffler #include "ctrl_iface.h"
7039beb93cSSam Leffler
7139beb93cSSam Leffler
72325151a3SRui Paulo #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
73325151a3SRui Paulo
74780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
75780fb4a2SCy Schubert #define HOSTAPD_CTRL_IFACE_PORT 8877
76780fb4a2SCy Schubert #define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
77780fb4a2SCy Schubert #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
78780fb4a2SCy Schubert #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT 50
79780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
8039beb93cSSam Leffler
8139beb93cSSam Leffler static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
82325151a3SRui Paulo enum wpa_msg_type type,
8339beb93cSSam Leffler const char *buf, size_t len);
8439beb93cSSam Leffler
8539beb93cSSam Leffler
hostapd_ctrl_iface_attach(struct hostapd_data * hapd,struct sockaddr_storage * from,socklen_t fromlen,const char * input)8639beb93cSSam Leffler static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
87780fb4a2SCy Schubert struct sockaddr_storage *from,
8885732ac8SCy Schubert socklen_t fromlen, const char *input)
8939beb93cSSam Leffler {
9085732ac8SCy Schubert return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen, input);
9139beb93cSSam Leffler }
9239beb93cSSam Leffler
9339beb93cSSam Leffler
hostapd_ctrl_iface_detach(struct hostapd_data * hapd,struct sockaddr_storage * from,socklen_t fromlen)9439beb93cSSam Leffler static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
95780fb4a2SCy Schubert struct sockaddr_storage *from,
9639beb93cSSam Leffler socklen_t fromlen)
9739beb93cSSam Leffler {
98780fb4a2SCy Schubert return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen);
9939beb93cSSam Leffler }
10039beb93cSSam Leffler
10139beb93cSSam Leffler
hostapd_ctrl_iface_level(struct hostapd_data * hapd,struct sockaddr_storage * from,socklen_t fromlen,char * level)10239beb93cSSam Leffler static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
103780fb4a2SCy Schubert struct sockaddr_storage *from,
10439beb93cSSam Leffler socklen_t fromlen,
10539beb93cSSam Leffler char *level)
10639beb93cSSam Leffler {
107780fb4a2SCy Schubert return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level);
10839beb93cSSam Leffler }
10939beb93cSSam Leffler
11039beb93cSSam Leffler
hostapd_ctrl_iface_new_sta(struct hostapd_data * hapd,const char * txtaddr)11139beb93cSSam Leffler static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
11239beb93cSSam Leffler const char *txtaddr)
11339beb93cSSam Leffler {
11439beb93cSSam Leffler u8 addr[ETH_ALEN];
11539beb93cSSam Leffler struct sta_info *sta;
11639beb93cSSam Leffler
11739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
11839beb93cSSam Leffler
11939beb93cSSam Leffler if (hwaddr_aton(txtaddr, addr))
12039beb93cSSam Leffler return -1;
12139beb93cSSam Leffler
12239beb93cSSam Leffler sta = ap_get_sta(hapd, addr);
12339beb93cSSam Leffler if (sta)
12439beb93cSSam Leffler return 0;
12539beb93cSSam Leffler
12639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
12739beb93cSSam Leffler "notification", MAC2STR(addr));
12839beb93cSSam Leffler sta = ap_sta_add(hapd, addr);
12939beb93cSSam Leffler if (sta == NULL)
13039beb93cSSam Leffler return -1;
13139beb93cSSam Leffler
13239beb93cSSam Leffler hostapd_new_assoc_sta(hapd, sta, 0);
13339beb93cSSam Leffler return 0;
13439beb93cSSam Leffler }
13539beb93cSSam Leffler
13639beb93cSSam Leffler
137e28a4053SRui Paulo #ifdef NEED_AP_MLME
hostapd_ctrl_iface_sa_query(struct hostapd_data * hapd,const char * txtaddr)13839beb93cSSam Leffler static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
13939beb93cSSam Leffler const char *txtaddr)
14039beb93cSSam Leffler {
14139beb93cSSam Leffler u8 addr[ETH_ALEN];
14239beb93cSSam Leffler u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
14339beb93cSSam Leffler
14439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
14539beb93cSSam Leffler
146e28a4053SRui Paulo if (hwaddr_aton(txtaddr, addr) ||
147e28a4053SRui Paulo os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
14839beb93cSSam Leffler return -1;
14939beb93cSSam Leffler
15039beb93cSSam Leffler ieee802_11_send_sa_query_req(hapd, addr, trans_id);
15139beb93cSSam Leffler
15239beb93cSSam Leffler return 0;
15339beb93cSSam Leffler }
154e28a4053SRui Paulo #endif /* NEED_AP_MLME */
15539beb93cSSam Leffler
15639beb93cSSam Leffler
15739beb93cSSam Leffler #ifdef CONFIG_WPS
hostapd_ctrl_iface_wps_pin(struct hostapd_data * hapd,char * txt)15839beb93cSSam Leffler static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
15939beb93cSSam Leffler {
16039beb93cSSam Leffler char *pin = os_strchr(txt, ' ');
1613157ba21SRui Paulo char *timeout_txt;
1623157ba21SRui Paulo int timeout;
163f05cddf9SRui Paulo u8 addr_buf[ETH_ALEN], *addr = NULL;
164f05cddf9SRui Paulo char *pos;
1653157ba21SRui Paulo
16639beb93cSSam Leffler if (pin == NULL)
16739beb93cSSam Leffler return -1;
16839beb93cSSam Leffler *pin++ = '\0';
1693157ba21SRui Paulo
1703157ba21SRui Paulo timeout_txt = os_strchr(pin, ' ');
1713157ba21SRui Paulo if (timeout_txt) {
1723157ba21SRui Paulo *timeout_txt++ = '\0';
1733157ba21SRui Paulo timeout = atoi(timeout_txt);
174f05cddf9SRui Paulo pos = os_strchr(timeout_txt, ' ');
175f05cddf9SRui Paulo if (pos) {
176f05cddf9SRui Paulo *pos++ = '\0';
177f05cddf9SRui Paulo if (hwaddr_aton(pos, addr_buf) == 0)
178f05cddf9SRui Paulo addr = addr_buf;
179f05cddf9SRui Paulo }
1803157ba21SRui Paulo } else
1813157ba21SRui Paulo timeout = 0;
1823157ba21SRui Paulo
183f05cddf9SRui Paulo return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
18439beb93cSSam Leffler }
185e28a4053SRui Paulo
186e28a4053SRui Paulo
hostapd_ctrl_iface_wps_check_pin(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)187f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_check_pin(
188f05cddf9SRui Paulo struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
189e28a4053SRui Paulo {
190f05cddf9SRui Paulo char pin[9];
191f05cddf9SRui Paulo size_t len;
192f05cddf9SRui Paulo char *pos;
193f05cddf9SRui Paulo int ret;
194e28a4053SRui Paulo
195f05cddf9SRui Paulo wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
196f05cddf9SRui Paulo (u8 *) cmd, os_strlen(cmd));
197f05cddf9SRui Paulo for (pos = cmd, len = 0; *pos != '\0'; pos++) {
198f05cddf9SRui Paulo if (*pos < '0' || *pos > '9')
199f05cddf9SRui Paulo continue;
200f05cddf9SRui Paulo pin[len++] = *pos;
201f05cddf9SRui Paulo if (len == 9) {
202f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
203e28a4053SRui Paulo return -1;
204e28a4053SRui Paulo }
205f05cddf9SRui Paulo }
206f05cddf9SRui Paulo if (len != 4 && len != 8) {
207f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
208f05cddf9SRui Paulo return -1;
209f05cddf9SRui Paulo }
210f05cddf9SRui Paulo pin[len] = '\0';
211f05cddf9SRui Paulo
212f05cddf9SRui Paulo if (len == 8) {
213f05cddf9SRui Paulo unsigned int pin_val;
214f05cddf9SRui Paulo pin_val = atoi(pin);
215f05cddf9SRui Paulo if (!wps_pin_valid(pin_val)) {
216f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
217f05cddf9SRui Paulo ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
2185b9c547cSRui Paulo if (os_snprintf_error(buflen, ret))
219f05cddf9SRui Paulo return -1;
220f05cddf9SRui Paulo return ret;
221f05cddf9SRui Paulo }
222f05cddf9SRui Paulo }
223f05cddf9SRui Paulo
224f05cddf9SRui Paulo ret = os_snprintf(buf, buflen, "%s", pin);
2255b9c547cSRui Paulo if (os_snprintf_error(buflen, ret))
226f05cddf9SRui Paulo return -1;
227f05cddf9SRui Paulo
228f05cddf9SRui Paulo return ret;
229f05cddf9SRui Paulo }
230f05cddf9SRui Paulo
231f05cddf9SRui Paulo
232f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data * hapd,char * pos)233f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
234f05cddf9SRui Paulo char *pos)
235f05cddf9SRui Paulo {
236f05cddf9SRui Paulo size_t len;
237f05cddf9SRui Paulo struct wpabuf *buf;
238f05cddf9SRui Paulo int ret;
239f05cddf9SRui Paulo
240f05cddf9SRui Paulo len = os_strlen(pos);
241f05cddf9SRui Paulo if (len & 0x01)
242f05cddf9SRui Paulo return -1;
243f05cddf9SRui Paulo len /= 2;
244f05cddf9SRui Paulo
245f05cddf9SRui Paulo buf = wpabuf_alloc(len);
246f05cddf9SRui Paulo if (buf == NULL)
247f05cddf9SRui Paulo return -1;
248f05cddf9SRui Paulo if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
249f05cddf9SRui Paulo wpabuf_free(buf);
250f05cddf9SRui Paulo return -1;
251f05cddf9SRui Paulo }
252f05cddf9SRui Paulo
253f05cddf9SRui Paulo ret = hostapd_wps_nfc_tag_read(hapd, buf);
254f05cddf9SRui Paulo wpabuf_free(buf);
255f05cddf9SRui Paulo
256f05cddf9SRui Paulo return ret;
257f05cddf9SRui Paulo }
258f05cddf9SRui Paulo
259f05cddf9SRui Paulo
hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data * hapd,char * cmd,char * reply,size_t max_len)260f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
261f05cddf9SRui Paulo char *cmd, char *reply,
262f05cddf9SRui Paulo size_t max_len)
263f05cddf9SRui Paulo {
264f05cddf9SRui Paulo int ndef;
265f05cddf9SRui Paulo struct wpabuf *buf;
266f05cddf9SRui Paulo int res;
267f05cddf9SRui Paulo
268f05cddf9SRui Paulo if (os_strcmp(cmd, "WPS") == 0)
269f05cddf9SRui Paulo ndef = 0;
270f05cddf9SRui Paulo else if (os_strcmp(cmd, "NDEF") == 0)
271f05cddf9SRui Paulo ndef = 1;
272f05cddf9SRui Paulo else
273f05cddf9SRui Paulo return -1;
274f05cddf9SRui Paulo
275f05cddf9SRui Paulo buf = hostapd_wps_nfc_config_token(hapd, ndef);
276f05cddf9SRui Paulo if (buf == NULL)
277f05cddf9SRui Paulo return -1;
278f05cddf9SRui Paulo
279f05cddf9SRui Paulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
280f05cddf9SRui Paulo wpabuf_len(buf));
281f05cddf9SRui Paulo reply[res++] = '\n';
282f05cddf9SRui Paulo reply[res] = '\0';
283f05cddf9SRui Paulo
284f05cddf9SRui Paulo wpabuf_free(buf);
285f05cddf9SRui Paulo
286f05cddf9SRui Paulo return res;
287f05cddf9SRui Paulo }
288f05cddf9SRui Paulo
289f05cddf9SRui Paulo
hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data * hapd,char * reply,size_t max_len,int ndef)290f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
291f05cddf9SRui Paulo char *reply, size_t max_len,
292f05cddf9SRui Paulo int ndef)
293f05cddf9SRui Paulo {
294f05cddf9SRui Paulo struct wpabuf *buf;
295f05cddf9SRui Paulo int res;
296f05cddf9SRui Paulo
297f05cddf9SRui Paulo buf = hostapd_wps_nfc_token_gen(hapd, ndef);
298f05cddf9SRui Paulo if (buf == NULL)
299f05cddf9SRui Paulo return -1;
300f05cddf9SRui Paulo
301f05cddf9SRui Paulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
302f05cddf9SRui Paulo wpabuf_len(buf));
303f05cddf9SRui Paulo reply[res++] = '\n';
304f05cddf9SRui Paulo reply[res] = '\0';
305f05cddf9SRui Paulo
306f05cddf9SRui Paulo wpabuf_free(buf);
307f05cddf9SRui Paulo
308f05cddf9SRui Paulo return res;
309f05cddf9SRui Paulo }
310f05cddf9SRui Paulo
311f05cddf9SRui Paulo
hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data * hapd,char * cmd,char * reply,size_t max_len)312f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
313f05cddf9SRui Paulo char *cmd, char *reply,
314f05cddf9SRui Paulo size_t max_len)
315f05cddf9SRui Paulo {
316f05cddf9SRui Paulo if (os_strcmp(cmd, "WPS") == 0)
317f05cddf9SRui Paulo return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
318f05cddf9SRui Paulo max_len, 0);
319f05cddf9SRui Paulo
320f05cddf9SRui Paulo if (os_strcmp(cmd, "NDEF") == 0)
321f05cddf9SRui Paulo return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
322f05cddf9SRui Paulo max_len, 1);
323f05cddf9SRui Paulo
324f05cddf9SRui Paulo if (os_strcmp(cmd, "enable") == 0)
325f05cddf9SRui Paulo return hostapd_wps_nfc_token_enable(hapd);
326f05cddf9SRui Paulo
327f05cddf9SRui Paulo if (os_strcmp(cmd, "disable") == 0) {
328f05cddf9SRui Paulo hostapd_wps_nfc_token_disable(hapd);
329f05cddf9SRui Paulo return 0;
330f05cddf9SRui Paulo }
331f05cddf9SRui Paulo
332f05cddf9SRui Paulo return -1;
333f05cddf9SRui Paulo }
3345b9c547cSRui Paulo
3355b9c547cSRui Paulo
hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data * hapd,char * cmd,char * reply,size_t max_len)3365b9c547cSRui Paulo static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
3375b9c547cSRui Paulo char *cmd, char *reply,
3385b9c547cSRui Paulo size_t max_len)
3395b9c547cSRui Paulo {
3405b9c547cSRui Paulo struct wpabuf *buf;
3415b9c547cSRui Paulo int res;
3425b9c547cSRui Paulo char *pos;
3435b9c547cSRui Paulo int ndef;
3445b9c547cSRui Paulo
3455b9c547cSRui Paulo pos = os_strchr(cmd, ' ');
3465b9c547cSRui Paulo if (pos == NULL)
3475b9c547cSRui Paulo return -1;
3485b9c547cSRui Paulo *pos++ = '\0';
3495b9c547cSRui Paulo
3505b9c547cSRui Paulo if (os_strcmp(cmd, "WPS") == 0)
3515b9c547cSRui Paulo ndef = 0;
3525b9c547cSRui Paulo else if (os_strcmp(cmd, "NDEF") == 0)
3535b9c547cSRui Paulo ndef = 1;
3545b9c547cSRui Paulo else
3555b9c547cSRui Paulo return -1;
3565b9c547cSRui Paulo
3575b9c547cSRui Paulo if (os_strcmp(pos, "WPS-CR") == 0)
3585b9c547cSRui Paulo buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
3595b9c547cSRui Paulo else
3605b9c547cSRui Paulo buf = NULL;
3615b9c547cSRui Paulo if (buf == NULL)
3625b9c547cSRui Paulo return -1;
3635b9c547cSRui Paulo
3645b9c547cSRui Paulo res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
3655b9c547cSRui Paulo wpabuf_len(buf));
3665b9c547cSRui Paulo reply[res++] = '\n';
3675b9c547cSRui Paulo reply[res] = '\0';
3685b9c547cSRui Paulo
3695b9c547cSRui Paulo wpabuf_free(buf);
3705b9c547cSRui Paulo
3715b9c547cSRui Paulo return res;
3725b9c547cSRui Paulo }
3735b9c547cSRui Paulo
3745b9c547cSRui Paulo
hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data * hapd,char * cmd)3755b9c547cSRui Paulo static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
3765b9c547cSRui Paulo char *cmd)
3775b9c547cSRui Paulo {
3785b9c547cSRui Paulo size_t len;
3795b9c547cSRui Paulo struct wpabuf *req, *sel;
3805b9c547cSRui Paulo int ret;
3815b9c547cSRui Paulo char *pos, *role, *type, *pos2;
3825b9c547cSRui Paulo
3835b9c547cSRui Paulo role = cmd;
3845b9c547cSRui Paulo pos = os_strchr(role, ' ');
3855b9c547cSRui Paulo if (pos == NULL)
3865b9c547cSRui Paulo return -1;
3875b9c547cSRui Paulo *pos++ = '\0';
3885b9c547cSRui Paulo
3895b9c547cSRui Paulo type = pos;
3905b9c547cSRui Paulo pos = os_strchr(type, ' ');
3915b9c547cSRui Paulo if (pos == NULL)
3925b9c547cSRui Paulo return -1;
3935b9c547cSRui Paulo *pos++ = '\0';
3945b9c547cSRui Paulo
3955b9c547cSRui Paulo pos2 = os_strchr(pos, ' ');
3965b9c547cSRui Paulo if (pos2 == NULL)
3975b9c547cSRui Paulo return -1;
3985b9c547cSRui Paulo *pos2++ = '\0';
3995b9c547cSRui Paulo
4005b9c547cSRui Paulo len = os_strlen(pos);
4015b9c547cSRui Paulo if (len & 0x01)
4025b9c547cSRui Paulo return -1;
4035b9c547cSRui Paulo len /= 2;
4045b9c547cSRui Paulo
4055b9c547cSRui Paulo req = wpabuf_alloc(len);
4065b9c547cSRui Paulo if (req == NULL)
4075b9c547cSRui Paulo return -1;
4085b9c547cSRui Paulo if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
4095b9c547cSRui Paulo wpabuf_free(req);
4105b9c547cSRui Paulo return -1;
4115b9c547cSRui Paulo }
4125b9c547cSRui Paulo
4135b9c547cSRui Paulo len = os_strlen(pos2);
4145b9c547cSRui Paulo if (len & 0x01) {
4155b9c547cSRui Paulo wpabuf_free(req);
4165b9c547cSRui Paulo return -1;
4175b9c547cSRui Paulo }
4185b9c547cSRui Paulo len /= 2;
4195b9c547cSRui Paulo
4205b9c547cSRui Paulo sel = wpabuf_alloc(len);
4215b9c547cSRui Paulo if (sel == NULL) {
4225b9c547cSRui Paulo wpabuf_free(req);
4235b9c547cSRui Paulo return -1;
4245b9c547cSRui Paulo }
4255b9c547cSRui Paulo if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
4265b9c547cSRui Paulo wpabuf_free(req);
4275b9c547cSRui Paulo wpabuf_free(sel);
4285b9c547cSRui Paulo return -1;
4295b9c547cSRui Paulo }
4305b9c547cSRui Paulo
4315b9c547cSRui Paulo if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
4325b9c547cSRui Paulo ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
4335b9c547cSRui Paulo } else {
4345b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
4355b9c547cSRui Paulo "reported: role=%s type=%s", role, type);
4365b9c547cSRui Paulo ret = -1;
4375b9c547cSRui Paulo }
4385b9c547cSRui Paulo wpabuf_free(req);
4395b9c547cSRui Paulo wpabuf_free(sel);
4405b9c547cSRui Paulo
4415b9c547cSRui Paulo return ret;
4425b9c547cSRui Paulo }
4435b9c547cSRui Paulo
444f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
445e28a4053SRui Paulo
446e28a4053SRui Paulo
hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data * hapd,char * txt,char * buf,size_t buflen)447e28a4053SRui Paulo static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
448e28a4053SRui Paulo char *buf, size_t buflen)
449e28a4053SRui Paulo {
450e28a4053SRui Paulo int timeout = 300;
451e28a4053SRui Paulo char *pos;
452e28a4053SRui Paulo const char *pin_txt;
453e28a4053SRui Paulo
454e28a4053SRui Paulo pos = os_strchr(txt, ' ');
455e28a4053SRui Paulo if (pos)
456e28a4053SRui Paulo *pos++ = '\0';
457e28a4053SRui Paulo
458e28a4053SRui Paulo if (os_strcmp(txt, "disable") == 0) {
459e28a4053SRui Paulo hostapd_wps_ap_pin_disable(hapd);
460e28a4053SRui Paulo return os_snprintf(buf, buflen, "OK\n");
461e28a4053SRui Paulo }
462e28a4053SRui Paulo
463e28a4053SRui Paulo if (os_strcmp(txt, "random") == 0) {
464e28a4053SRui Paulo if (pos)
465e28a4053SRui Paulo timeout = atoi(pos);
466e28a4053SRui Paulo pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
467e28a4053SRui Paulo if (pin_txt == NULL)
468e28a4053SRui Paulo return -1;
469e28a4053SRui Paulo return os_snprintf(buf, buflen, "%s", pin_txt);
470e28a4053SRui Paulo }
471e28a4053SRui Paulo
472e28a4053SRui Paulo if (os_strcmp(txt, "get") == 0) {
473e28a4053SRui Paulo pin_txt = hostapd_wps_ap_pin_get(hapd);
474e28a4053SRui Paulo if (pin_txt == NULL)
475e28a4053SRui Paulo return -1;
476e28a4053SRui Paulo return os_snprintf(buf, buflen, "%s", pin_txt);
477e28a4053SRui Paulo }
478e28a4053SRui Paulo
479e28a4053SRui Paulo if (os_strcmp(txt, "set") == 0) {
480e28a4053SRui Paulo char *pin;
481e28a4053SRui Paulo if (pos == NULL)
482e28a4053SRui Paulo return -1;
483e28a4053SRui Paulo pin = pos;
484e28a4053SRui Paulo pos = os_strchr(pos, ' ');
485e28a4053SRui Paulo if (pos) {
486e28a4053SRui Paulo *pos++ = '\0';
487e28a4053SRui Paulo timeout = atoi(pos);
488e28a4053SRui Paulo }
489e28a4053SRui Paulo if (os_strlen(pin) > buflen)
490e28a4053SRui Paulo return -1;
491e28a4053SRui Paulo if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
492e28a4053SRui Paulo return -1;
493e28a4053SRui Paulo return os_snprintf(buf, buflen, "%s", pin);
494e28a4053SRui Paulo }
495e28a4053SRui Paulo
496e28a4053SRui Paulo return -1;
497e28a4053SRui Paulo }
498f05cddf9SRui Paulo
499f05cddf9SRui Paulo
hostapd_ctrl_iface_wps_config(struct hostapd_data * hapd,char * txt)500f05cddf9SRui Paulo static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
501f05cddf9SRui Paulo {
502f05cddf9SRui Paulo char *pos;
503f05cddf9SRui Paulo char *ssid, *auth, *encr = NULL, *key = NULL;
504f05cddf9SRui Paulo
505f05cddf9SRui Paulo ssid = txt;
506f05cddf9SRui Paulo pos = os_strchr(txt, ' ');
507f05cddf9SRui Paulo if (!pos)
508f05cddf9SRui Paulo return -1;
509f05cddf9SRui Paulo *pos++ = '\0';
510f05cddf9SRui Paulo
511f05cddf9SRui Paulo auth = pos;
512f05cddf9SRui Paulo pos = os_strchr(pos, ' ');
513f05cddf9SRui Paulo if (pos) {
514f05cddf9SRui Paulo *pos++ = '\0';
515f05cddf9SRui Paulo encr = pos;
516f05cddf9SRui Paulo pos = os_strchr(pos, ' ');
517f05cddf9SRui Paulo if (pos) {
518f05cddf9SRui Paulo *pos++ = '\0';
519f05cddf9SRui Paulo key = pos;
520f05cddf9SRui Paulo }
521f05cddf9SRui Paulo }
522f05cddf9SRui Paulo
523f05cddf9SRui Paulo return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
524f05cddf9SRui Paulo }
5255b9c547cSRui Paulo
5265b9c547cSRui Paulo
pbc_status_str(enum pbc_status status)5275b9c547cSRui Paulo static const char * pbc_status_str(enum pbc_status status)
5285b9c547cSRui Paulo {
5295b9c547cSRui Paulo switch (status) {
5305b9c547cSRui Paulo case WPS_PBC_STATUS_DISABLE:
5315b9c547cSRui Paulo return "Disabled";
5325b9c547cSRui Paulo case WPS_PBC_STATUS_ACTIVE:
5335b9c547cSRui Paulo return "Active";
5345b9c547cSRui Paulo case WPS_PBC_STATUS_TIMEOUT:
5355b9c547cSRui Paulo return "Timed-out";
5365b9c547cSRui Paulo case WPS_PBC_STATUS_OVERLAP:
5375b9c547cSRui Paulo return "Overlap";
5385b9c547cSRui Paulo default:
5395b9c547cSRui Paulo return "Unknown";
5405b9c547cSRui Paulo }
5415b9c547cSRui Paulo }
5425b9c547cSRui Paulo
5435b9c547cSRui Paulo
hostapd_ctrl_iface_wps_get_status(struct hostapd_data * hapd,char * buf,size_t buflen)5445b9c547cSRui Paulo static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
5455b9c547cSRui Paulo char *buf, size_t buflen)
5465b9c547cSRui Paulo {
5475b9c547cSRui Paulo int ret;
5485b9c547cSRui Paulo char *pos, *end;
5495b9c547cSRui Paulo
5505b9c547cSRui Paulo pos = buf;
5515b9c547cSRui Paulo end = buf + buflen;
5525b9c547cSRui Paulo
5535b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
5545b9c547cSRui Paulo pbc_status_str(hapd->wps_stats.pbc_status));
5555b9c547cSRui Paulo
5565b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
5575b9c547cSRui Paulo return pos - buf;
5585b9c547cSRui Paulo pos += ret;
5595b9c547cSRui Paulo
5605b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
5615b9c547cSRui Paulo (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
5625b9c547cSRui Paulo "Success":
5635b9c547cSRui Paulo (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
5645b9c547cSRui Paulo "Failed" : "None")));
5655b9c547cSRui Paulo
5665b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
5675b9c547cSRui Paulo return pos - buf;
5685b9c547cSRui Paulo pos += ret;
5695b9c547cSRui Paulo
5705b9c547cSRui Paulo /* If status == Failure - Add possible Reasons */
5715b9c547cSRui Paulo if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
5725b9c547cSRui Paulo hapd->wps_stats.failure_reason > 0) {
5735b9c547cSRui Paulo ret = os_snprintf(pos, end - pos,
5745b9c547cSRui Paulo "Failure Reason: %s\n",
5755b9c547cSRui Paulo wps_ei_str(hapd->wps_stats.failure_reason));
5765b9c547cSRui Paulo
5775b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
5785b9c547cSRui Paulo return pos - buf;
5795b9c547cSRui Paulo pos += ret;
5805b9c547cSRui Paulo }
5815b9c547cSRui Paulo
5825b9c547cSRui Paulo if (hapd->wps_stats.status) {
5835b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
5845b9c547cSRui Paulo MAC2STR(hapd->wps_stats.peer_addr));
5855b9c547cSRui Paulo
5865b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
5875b9c547cSRui Paulo return pos - buf;
5885b9c547cSRui Paulo pos += ret;
5895b9c547cSRui Paulo }
5905b9c547cSRui Paulo
5915b9c547cSRui Paulo return pos - buf;
5925b9c547cSRui Paulo }
5935b9c547cSRui Paulo
59439beb93cSSam Leffler #endif /* CONFIG_WPS */
59539beb93cSSam Leffler
5965b9c547cSRui Paulo #ifdef CONFIG_HS20
5975b9c547cSRui Paulo
hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data * hapd,const char * cmd)5985b9c547cSRui Paulo static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
5995b9c547cSRui Paulo const char *cmd)
6005b9c547cSRui Paulo {
6015b9c547cSRui Paulo u8 addr[ETH_ALEN];
6025b9c547cSRui Paulo const char *url;
6035b9c547cSRui Paulo
6045b9c547cSRui Paulo if (hwaddr_aton(cmd, addr))
6055b9c547cSRui Paulo return -1;
6065b9c547cSRui Paulo url = cmd + 17;
6075b9c547cSRui Paulo if (*url == '\0') {
6085b9c547cSRui Paulo url = NULL;
6095b9c547cSRui Paulo } else {
6105b9c547cSRui Paulo if (*url != ' ')
6115b9c547cSRui Paulo return -1;
6125b9c547cSRui Paulo url++;
6135b9c547cSRui Paulo if (*url == '\0')
6145b9c547cSRui Paulo url = NULL;
6155b9c547cSRui Paulo }
6165b9c547cSRui Paulo
6175b9c547cSRui Paulo return hs20_send_wnm_notification(hapd, addr, 1, url);
6185b9c547cSRui Paulo }
6195b9c547cSRui Paulo
6205b9c547cSRui Paulo
hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data * hapd,const char * cmd)6215b9c547cSRui Paulo static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
6225b9c547cSRui Paulo const char *cmd)
6235b9c547cSRui Paulo {
6245b9c547cSRui Paulo u8 addr[ETH_ALEN];
6255b9c547cSRui Paulo int code, reauth_delay, ret;
6265b9c547cSRui Paulo const char *pos;
6275b9c547cSRui Paulo size_t url_len;
6285b9c547cSRui Paulo struct wpabuf *req;
6295b9c547cSRui Paulo
6305b9c547cSRui Paulo /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
6315b9c547cSRui Paulo if (hwaddr_aton(cmd, addr))
6325b9c547cSRui Paulo return -1;
6335b9c547cSRui Paulo
6345b9c547cSRui Paulo pos = os_strchr(cmd, ' ');
6355b9c547cSRui Paulo if (pos == NULL)
6365b9c547cSRui Paulo return -1;
6375b9c547cSRui Paulo pos++;
6385b9c547cSRui Paulo code = atoi(pos);
6395b9c547cSRui Paulo
6405b9c547cSRui Paulo pos = os_strchr(pos, ' ');
6415b9c547cSRui Paulo if (pos == NULL)
6425b9c547cSRui Paulo return -1;
6435b9c547cSRui Paulo pos++;
6445b9c547cSRui Paulo reauth_delay = atoi(pos);
6455b9c547cSRui Paulo
6465b9c547cSRui Paulo url_len = 0;
6475b9c547cSRui Paulo pos = os_strchr(pos, ' ');
6485b9c547cSRui Paulo if (pos) {
6495b9c547cSRui Paulo pos++;
6505b9c547cSRui Paulo url_len = os_strlen(pos);
6515b9c547cSRui Paulo }
6525b9c547cSRui Paulo
6535b9c547cSRui Paulo req = wpabuf_alloc(4 + url_len);
6545b9c547cSRui Paulo if (req == NULL)
6555b9c547cSRui Paulo return -1;
6565b9c547cSRui Paulo wpabuf_put_u8(req, code);
6575b9c547cSRui Paulo wpabuf_put_le16(req, reauth_delay);
6585b9c547cSRui Paulo wpabuf_put_u8(req, url_len);
6595b9c547cSRui Paulo if (pos)
6605b9c547cSRui Paulo wpabuf_put_data(req, pos, url_len);
6615b9c547cSRui Paulo
6625b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
6635b9c547cSRui Paulo " to indicate imminent deauthentication (code=%d "
6645b9c547cSRui Paulo "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
6655b9c547cSRui Paulo ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
6665b9c547cSRui Paulo wpabuf_free(req);
6675b9c547cSRui Paulo return ret;
6685b9c547cSRui Paulo }
6695b9c547cSRui Paulo
6705b9c547cSRui Paulo #endif /* CONFIG_HS20 */
6715b9c547cSRui Paulo
6725b9c547cSRui Paulo
6735b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING
6745b9c547cSRui Paulo
hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data * hapd,const char * cmd)6755b9c547cSRui Paulo static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
6765b9c547cSRui Paulo const char *cmd)
6775b9c547cSRui Paulo {
6785b9c547cSRui Paulo u8 qos_map_set[16 + 2 * 21], count = 0;
6795b9c547cSRui Paulo const char *pos = cmd;
6805b9c547cSRui Paulo int val, ret;
6815b9c547cSRui Paulo
6825b9c547cSRui Paulo for (;;) {
6835b9c547cSRui Paulo if (count == sizeof(qos_map_set)) {
6845b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
6855b9c547cSRui Paulo return -1;
6865b9c547cSRui Paulo }
6875b9c547cSRui Paulo
6885b9c547cSRui Paulo val = atoi(pos);
6895b9c547cSRui Paulo if (val < 0 || val > 255) {
6905b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid QoS Map Set");
6915b9c547cSRui Paulo return -1;
6925b9c547cSRui Paulo }
6935b9c547cSRui Paulo
6945b9c547cSRui Paulo qos_map_set[count++] = val;
6955b9c547cSRui Paulo pos = os_strchr(pos, ',');
6965b9c547cSRui Paulo if (!pos)
6975b9c547cSRui Paulo break;
6985b9c547cSRui Paulo pos++;
6995b9c547cSRui Paulo }
7005b9c547cSRui Paulo
7015b9c547cSRui Paulo if (count < 16 || count & 1) {
7025b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid QoS Map Set");
7035b9c547cSRui Paulo return -1;
7045b9c547cSRui Paulo }
7055b9c547cSRui Paulo
7065b9c547cSRui Paulo ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
7075b9c547cSRui Paulo if (ret) {
7085b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
7095b9c547cSRui Paulo return -1;
7105b9c547cSRui Paulo }
7115b9c547cSRui Paulo
7125b9c547cSRui Paulo os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
7135b9c547cSRui Paulo hapd->conf->qos_map_set_len = count;
7145b9c547cSRui Paulo
7155b9c547cSRui Paulo return 0;
7165b9c547cSRui Paulo }
7175b9c547cSRui Paulo
7185b9c547cSRui Paulo
hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data * hapd,const char * cmd)7195b9c547cSRui Paulo static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
7205b9c547cSRui Paulo const char *cmd)
7215b9c547cSRui Paulo {
7225b9c547cSRui Paulo u8 addr[ETH_ALEN];
7235b9c547cSRui Paulo struct sta_info *sta;
7245b9c547cSRui Paulo struct wpabuf *buf;
7255b9c547cSRui Paulo u8 *qos_map_set = hapd->conf->qos_map_set;
7265b9c547cSRui Paulo u8 qos_map_set_len = hapd->conf->qos_map_set_len;
7275b9c547cSRui Paulo int ret;
7285b9c547cSRui Paulo
7295b9c547cSRui Paulo if (!qos_map_set_len) {
7305b9c547cSRui Paulo wpa_printf(MSG_INFO, "QoS Map Set is not set");
7315b9c547cSRui Paulo return -1;
7325b9c547cSRui Paulo }
7335b9c547cSRui Paulo
7345b9c547cSRui Paulo if (hwaddr_aton(cmd, addr))
7355b9c547cSRui Paulo return -1;
7365b9c547cSRui Paulo
7375b9c547cSRui Paulo sta = ap_get_sta(hapd, addr);
7385b9c547cSRui Paulo if (sta == NULL) {
7395b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
7405b9c547cSRui Paulo "for QoS Map Configuration message",
7415b9c547cSRui Paulo MAC2STR(addr));
7425b9c547cSRui Paulo return -1;
7435b9c547cSRui Paulo }
7445b9c547cSRui Paulo
7455b9c547cSRui Paulo if (!sta->qos_map_enabled) {
7465b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
7475b9c547cSRui Paulo "support for QoS Map", MAC2STR(addr));
7485b9c547cSRui Paulo return -1;
7495b9c547cSRui Paulo }
7505b9c547cSRui Paulo
7515b9c547cSRui Paulo buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
7525b9c547cSRui Paulo if (buf == NULL)
7535b9c547cSRui Paulo return -1;
7545b9c547cSRui Paulo
7555b9c547cSRui Paulo wpabuf_put_u8(buf, WLAN_ACTION_QOS);
7565b9c547cSRui Paulo wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
7575b9c547cSRui Paulo
7585b9c547cSRui Paulo /* QoS Map Set Element */
7595b9c547cSRui Paulo wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
7605b9c547cSRui Paulo wpabuf_put_u8(buf, qos_map_set_len);
7615b9c547cSRui Paulo wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
7625b9c547cSRui Paulo
7635b9c547cSRui Paulo ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
7645b9c547cSRui Paulo wpabuf_head(buf), wpabuf_len(buf));
7655b9c547cSRui Paulo wpabuf_free(buf);
7665b9c547cSRui Paulo
7675b9c547cSRui Paulo return ret;
7685b9c547cSRui Paulo }
7695b9c547cSRui Paulo
7705b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */
7715b9c547cSRui Paulo
77239beb93cSSam Leffler
77385732ac8SCy Schubert #ifdef CONFIG_WNM_AP
774f05cddf9SRui Paulo
hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data * hapd,const char * cmd)775f05cddf9SRui Paulo static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
776f05cddf9SRui Paulo const char *cmd)
777f05cddf9SRui Paulo {
778f05cddf9SRui Paulo u8 addr[ETH_ALEN];
779f05cddf9SRui Paulo int disassoc_timer;
7805b9c547cSRui Paulo struct sta_info *sta;
781f05cddf9SRui Paulo
782f05cddf9SRui Paulo if (hwaddr_aton(cmd, addr))
783f05cddf9SRui Paulo return -1;
784f05cddf9SRui Paulo if (cmd[17] != ' ')
785f05cddf9SRui Paulo return -1;
786f05cddf9SRui Paulo disassoc_timer = atoi(cmd + 17);
787f05cddf9SRui Paulo
7885b9c547cSRui Paulo sta = ap_get_sta(hapd, addr);
7895b9c547cSRui Paulo if (sta == NULL) {
7905b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Station " MACSTR
7915b9c547cSRui Paulo " not found for disassociation imminent message",
7925b9c547cSRui Paulo MAC2STR(addr));
793f05cddf9SRui Paulo return -1;
794f05cddf9SRui Paulo }
795f05cddf9SRui Paulo
7965b9c547cSRui Paulo return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
797f05cddf9SRui Paulo }
798f05cddf9SRui Paulo
799f05cddf9SRui Paulo
hostapd_ctrl_iface_ess_disassoc(struct hostapd_data * hapd,const char * cmd)800f05cddf9SRui Paulo static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
801f05cddf9SRui Paulo const char *cmd)
802f05cddf9SRui Paulo {
803f05cddf9SRui Paulo u8 addr[ETH_ALEN];
8045b9c547cSRui Paulo const char *url, *timerstr;
8055b9c547cSRui Paulo int disassoc_timer;
8065b9c547cSRui Paulo struct sta_info *sta;
807f05cddf9SRui Paulo
808f05cddf9SRui Paulo if (hwaddr_aton(cmd, addr))
809f05cddf9SRui Paulo return -1;
810f05cddf9SRui Paulo
8115b9c547cSRui Paulo sta = ap_get_sta(hapd, addr);
8125b9c547cSRui Paulo if (sta == NULL) {
8135b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Station " MACSTR
8145b9c547cSRui Paulo " not found for ESS disassociation imminent message",
8155b9c547cSRui Paulo MAC2STR(addr));
816f05cddf9SRui Paulo return -1;
817f05cddf9SRui Paulo }
818f05cddf9SRui Paulo
8195b9c547cSRui Paulo timerstr = cmd + 17;
8205b9c547cSRui Paulo if (*timerstr != ' ')
8215b9c547cSRui Paulo return -1;
8225b9c547cSRui Paulo timerstr++;
8235b9c547cSRui Paulo disassoc_timer = atoi(timerstr);
8245b9c547cSRui Paulo if (disassoc_timer < 0 || disassoc_timer > 65535)
8255b9c547cSRui Paulo return -1;
8265b9c547cSRui Paulo
8275b9c547cSRui Paulo url = os_strchr(timerstr, ' ');
8285b9c547cSRui Paulo if (url == NULL)
8295b9c547cSRui Paulo return -1;
8305b9c547cSRui Paulo url++;
8315b9c547cSRui Paulo
8325b9c547cSRui Paulo return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
8335b9c547cSRui Paulo }
8345b9c547cSRui Paulo
8355b9c547cSRui Paulo
hostapd_ctrl_iface_bss_tm_req(struct hostapd_data * hapd,const char * cmd)8365b9c547cSRui Paulo static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
8375b9c547cSRui Paulo const char *cmd)
8385b9c547cSRui Paulo {
8395b9c547cSRui Paulo u8 addr[ETH_ALEN];
8405b9c547cSRui Paulo const char *pos, *end;
8415b9c547cSRui Paulo int disassoc_timer = 0;
8425b9c547cSRui Paulo struct sta_info *sta;
8434b72b91aSCy Schubert u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
8445b9c547cSRui Paulo u8 bss_term_dur[12];
8455b9c547cSRui Paulo char *url = NULL;
8465b9c547cSRui Paulo int ret;
8475b9c547cSRui Paulo u8 nei_rep[1000];
84885732ac8SCy Schubert int nei_len;
849780fb4a2SCy Schubert u8 mbo[10];
850780fb4a2SCy Schubert size_t mbo_len = 0;
8515b9c547cSRui Paulo
8525b9c547cSRui Paulo if (hwaddr_aton(cmd, addr)) {
8535b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
8545b9c547cSRui Paulo return -1;
8555b9c547cSRui Paulo }
8565b9c547cSRui Paulo
8575b9c547cSRui Paulo sta = ap_get_sta(hapd, addr);
8585b9c547cSRui Paulo if (sta == NULL) {
8595b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Station " MACSTR
8605b9c547cSRui Paulo " not found for BSS TM Request message",
8615b9c547cSRui Paulo MAC2STR(addr));
8625b9c547cSRui Paulo return -1;
8635b9c547cSRui Paulo }
8645b9c547cSRui Paulo
8655b9c547cSRui Paulo pos = os_strstr(cmd, " disassoc_timer=");
8665b9c547cSRui Paulo if (pos) {
8675b9c547cSRui Paulo pos += 16;
8685b9c547cSRui Paulo disassoc_timer = atoi(pos);
8695b9c547cSRui Paulo if (disassoc_timer < 0 || disassoc_timer > 65535) {
8705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
8715b9c547cSRui Paulo return -1;
8725b9c547cSRui Paulo }
8735b9c547cSRui Paulo }
8745b9c547cSRui Paulo
8755b9c547cSRui Paulo pos = os_strstr(cmd, " valid_int=");
8765b9c547cSRui Paulo if (pos) {
8775b9c547cSRui Paulo pos += 11;
8785b9c547cSRui Paulo valid_int = atoi(pos);
8795b9c547cSRui Paulo }
8805b9c547cSRui Paulo
8814b72b91aSCy Schubert pos = os_strstr(cmd, " dialog_token=");
8824b72b91aSCy Schubert if (pos) {
8834b72b91aSCy Schubert pos += 14;
8844b72b91aSCy Schubert dialog_token = atoi(pos);
8854b72b91aSCy Schubert }
8864b72b91aSCy Schubert
8875b9c547cSRui Paulo pos = os_strstr(cmd, " bss_term=");
8885b9c547cSRui Paulo if (pos) {
8895b9c547cSRui Paulo pos += 10;
8905b9c547cSRui Paulo req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
8915b9c547cSRui Paulo /* TODO: TSF configurable/learnable */
8925b9c547cSRui Paulo bss_term_dur[0] = 4; /* Subelement ID */
8935b9c547cSRui Paulo bss_term_dur[1] = 10; /* Length */
8944bc52338SCy Schubert os_memset(&bss_term_dur[2], 0, 8);
8955b9c547cSRui Paulo end = os_strchr(pos, ',');
8965b9c547cSRui Paulo if (end == NULL) {
8975b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Invalid bss_term data");
8985b9c547cSRui Paulo return -1;
8995b9c547cSRui Paulo }
9005b9c547cSRui Paulo end++;
9015b9c547cSRui Paulo WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
9025b9c547cSRui Paulo }
9035b9c547cSRui Paulo
90485732ac8SCy Schubert nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
90585732ac8SCy Schubert sizeof(nei_rep));
90685732ac8SCy Schubert if (nei_len < 0)
9075b9c547cSRui Paulo return -1;
9085b9c547cSRui Paulo
9095b9c547cSRui Paulo pos = os_strstr(cmd, " url=");
9105b9c547cSRui Paulo if (pos) {
9115b9c547cSRui Paulo size_t len;
9125b9c547cSRui Paulo pos += 5;
9135b9c547cSRui Paulo end = os_strchr(pos, ' ');
9145b9c547cSRui Paulo if (end)
9155b9c547cSRui Paulo len = end - pos;
9165b9c547cSRui Paulo else
9175b9c547cSRui Paulo len = os_strlen(pos);
9185b9c547cSRui Paulo url = os_malloc(len + 1);
9195b9c547cSRui Paulo if (url == NULL)
9205b9c547cSRui Paulo return -1;
9215b9c547cSRui Paulo os_memcpy(url, pos, len);
9225b9c547cSRui Paulo url[len] = '\0';
9235b9c547cSRui Paulo req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
9245b9c547cSRui Paulo }
9255b9c547cSRui Paulo
9265b9c547cSRui Paulo if (os_strstr(cmd, " pref=1"))
9275b9c547cSRui Paulo req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
9285b9c547cSRui Paulo if (os_strstr(cmd, " abridged=1"))
9295b9c547cSRui Paulo req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
9305b9c547cSRui Paulo if (os_strstr(cmd, " disassoc_imminent=1"))
9315b9c547cSRui Paulo req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
9325b9c547cSRui Paulo
933780fb4a2SCy Schubert #ifdef CONFIG_MBO
934780fb4a2SCy Schubert pos = os_strstr(cmd, "mbo=");
935780fb4a2SCy Schubert if (pos) {
936780fb4a2SCy Schubert unsigned int mbo_reason, cell_pref, reassoc_delay;
937780fb4a2SCy Schubert u8 *mbo_pos = mbo;
938780fb4a2SCy Schubert
939780fb4a2SCy Schubert ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
940780fb4a2SCy Schubert &reassoc_delay, &cell_pref);
941780fb4a2SCy Schubert if (ret != 3) {
942780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
943780fb4a2SCy Schubert "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
94485732ac8SCy Schubert ret = -1;
94585732ac8SCy Schubert goto fail;
946780fb4a2SCy Schubert }
947780fb4a2SCy Schubert
948780fb4a2SCy Schubert if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
949780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
950780fb4a2SCy Schubert "Invalid MBO transition reason code %u",
951780fb4a2SCy Schubert mbo_reason);
95285732ac8SCy Schubert ret = -1;
95385732ac8SCy Schubert goto fail;
954780fb4a2SCy Schubert }
955780fb4a2SCy Schubert
956780fb4a2SCy Schubert /* Valid values for Cellular preference are: 0, 1, 255 */
957780fb4a2SCy Schubert if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
958780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
959780fb4a2SCy Schubert "Invalid MBO cellular capability %u",
960780fb4a2SCy Schubert cell_pref);
96185732ac8SCy Schubert ret = -1;
96285732ac8SCy Schubert goto fail;
963780fb4a2SCy Schubert }
964780fb4a2SCy Schubert
965780fb4a2SCy Schubert if (reassoc_delay > 65535 ||
966780fb4a2SCy Schubert (reassoc_delay &&
967780fb4a2SCy Schubert !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
968780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
969780fb4a2SCy Schubert "MBO: Assoc retry delay is only valid in disassoc imminent mode");
97085732ac8SCy Schubert ret = -1;
97185732ac8SCy Schubert goto fail;
972780fb4a2SCy Schubert }
973780fb4a2SCy Schubert
974780fb4a2SCy Schubert *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
975780fb4a2SCy Schubert *mbo_pos++ = 1;
976780fb4a2SCy Schubert *mbo_pos++ = mbo_reason;
977780fb4a2SCy Schubert *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
978780fb4a2SCy Schubert *mbo_pos++ = 1;
979780fb4a2SCy Schubert *mbo_pos++ = cell_pref;
980780fb4a2SCy Schubert
981780fb4a2SCy Schubert if (reassoc_delay) {
982780fb4a2SCy Schubert *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
983780fb4a2SCy Schubert *mbo_pos++ = 2;
984780fb4a2SCy Schubert WPA_PUT_LE16(mbo_pos, reassoc_delay);
985780fb4a2SCy Schubert mbo_pos += 2;
986780fb4a2SCy Schubert }
987780fb4a2SCy Schubert
988780fb4a2SCy Schubert mbo_len = mbo_pos - mbo;
989780fb4a2SCy Schubert }
990780fb4a2SCy Schubert #endif /* CONFIG_MBO */
991780fb4a2SCy Schubert
9925b9c547cSRui Paulo ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
9934b72b91aSCy Schubert valid_int, bss_term_dur, dialog_token, url,
99485732ac8SCy Schubert nei_len ? nei_rep : NULL, nei_len,
99585732ac8SCy Schubert mbo_len ? mbo : NULL, mbo_len);
99685732ac8SCy Schubert #ifdef CONFIG_MBO
99785732ac8SCy Schubert fail:
99885732ac8SCy Schubert #endif /* CONFIG_MBO */
9995b9c547cSRui Paulo os_free(url);
10005b9c547cSRui Paulo return ret;
1001f05cddf9SRui Paulo }
1002f05cddf9SRui Paulo
100385732ac8SCy Schubert
hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data * hapd,const char * cmd)100485732ac8SCy Schubert static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
100585732ac8SCy Schubert const char *cmd)
100685732ac8SCy Schubert {
100785732ac8SCy Schubert u8 addr[ETH_ALEN];
100885732ac8SCy Schubert struct sta_info *sta;
100985732ac8SCy Schubert const char *pos;
101085732ac8SCy Schubert unsigned int auto_report, timeout;
101185732ac8SCy Schubert
101285732ac8SCy Schubert if (hwaddr_aton(cmd, addr)) {
101385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
101485732ac8SCy Schubert return -1;
101585732ac8SCy Schubert }
101685732ac8SCy Schubert
101785732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
101885732ac8SCy Schubert if (!sta) {
101985732ac8SCy Schubert wpa_printf(MSG_DEBUG, "Station " MACSTR
102085732ac8SCy Schubert " not found for Collocated Interference Request",
102185732ac8SCy Schubert MAC2STR(addr));
102285732ac8SCy Schubert return -1;
102385732ac8SCy Schubert }
102485732ac8SCy Schubert
102585732ac8SCy Schubert pos = cmd + 17;
102685732ac8SCy Schubert if (*pos != ' ')
102785732ac8SCy Schubert return -1;
102885732ac8SCy Schubert pos++;
102985732ac8SCy Schubert auto_report = atoi(pos);
103085732ac8SCy Schubert pos = os_strchr(pos, ' ');
103185732ac8SCy Schubert if (!pos)
103285732ac8SCy Schubert return -1;
103385732ac8SCy Schubert pos++;
103485732ac8SCy Schubert timeout = atoi(pos);
103585732ac8SCy Schubert
103685732ac8SCy Schubert return wnm_send_coloc_intf_req(hapd, sta, auto_report, timeout);
103785732ac8SCy Schubert }
103885732ac8SCy Schubert
103985732ac8SCy Schubert #endif /* CONFIG_WNM_AP */
1040f05cddf9SRui Paulo
1041f05cddf9SRui Paulo
hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data * hapd,char * buf,size_t buflen)1042325151a3SRui Paulo static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
1043f05cddf9SRui Paulo char *buf, size_t buflen)
1044f05cddf9SRui Paulo {
1045325151a3SRui Paulo int ret = 0;
1046f05cddf9SRui Paulo char *pos, *end;
1047f05cddf9SRui Paulo
1048f05cddf9SRui Paulo pos = buf;
1049f05cddf9SRui Paulo end = buf + buflen;
1050f05cddf9SRui Paulo
1051325151a3SRui Paulo WPA_ASSERT(hapd->conf->wpa_key_mgmt);
1052f05cddf9SRui Paulo
1053f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
1054f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "WPA-PSK ");
10555b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1056f05cddf9SRui Paulo return pos - buf;
1057f05cddf9SRui Paulo pos += ret;
1058f05cddf9SRui Paulo }
1059f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
1060f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "WPA-EAP ");
10615b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1062f05cddf9SRui Paulo return pos - buf;
1063f05cddf9SRui Paulo pos += ret;
1064f05cddf9SRui Paulo }
106585732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
1066f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
1067f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "FT-PSK ");
10685b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1069f05cddf9SRui Paulo return pos - buf;
1070f05cddf9SRui Paulo pos += ret;
1071f05cddf9SRui Paulo }
1072f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
1073f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "FT-EAP ");
10745b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1075f05cddf9SRui Paulo return pos - buf;
1076f05cddf9SRui Paulo pos += ret;
1077f05cddf9SRui Paulo }
107885732ac8SCy Schubert #ifdef CONFIG_SHA384
107985732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
108085732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FT-EAP-SHA384 ");
108185732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
108285732ac8SCy Schubert return pos - buf;
108385732ac8SCy Schubert pos += ret;
108485732ac8SCy Schubert }
108585732ac8SCy Schubert #endif /* CONFIG_SHA384 */
10865b9c547cSRui Paulo #ifdef CONFIG_SAE
10875b9c547cSRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
10885b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "FT-SAE ");
10895b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
10905b9c547cSRui Paulo return pos - buf;
10915b9c547cSRui Paulo pos += ret;
10925b9c547cSRui Paulo }
10935b9c547cSRui Paulo #endif /* CONFIG_SAE */
109485732ac8SCy Schubert #ifdef CONFIG_FILS
109585732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
109685732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FT-FILS-SHA256 ");
109785732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
109885732ac8SCy Schubert return pos - buf;
109985732ac8SCy Schubert pos += ret;
110085732ac8SCy Schubert }
110185732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
110285732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FT-FILS-SHA384 ");
110385732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
110485732ac8SCy Schubert return pos - buf;
110585732ac8SCy Schubert pos += ret;
110685732ac8SCy Schubert }
110785732ac8SCy Schubert #endif /* CONFIG_FILS */
110885732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
1109f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
1110f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
11115b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1112f05cddf9SRui Paulo return pos - buf;
1113f05cddf9SRui Paulo pos += ret;
1114f05cddf9SRui Paulo }
1115f05cddf9SRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
1116f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
11175b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1118f05cddf9SRui Paulo return pos - buf;
1119f05cddf9SRui Paulo pos += ret;
1120f05cddf9SRui Paulo }
11215b9c547cSRui Paulo #ifdef CONFIG_SAE
11225b9c547cSRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
11235b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "SAE ");
11245b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
11255b9c547cSRui Paulo return pos - buf;
11265b9c547cSRui Paulo pos += ret;
11275b9c547cSRui Paulo }
11285b9c547cSRui Paulo #endif /* CONFIG_SAE */
11295b9c547cSRui Paulo if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
11305b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
11315b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
11325b9c547cSRui Paulo return pos - buf;
11335b9c547cSRui Paulo pos += ret;
11345b9c547cSRui Paulo }
11355b9c547cSRui Paulo if (hapd->conf->wpa_key_mgmt &
11365b9c547cSRui Paulo WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
11375b9c547cSRui Paulo ret = os_snprintf(pos, end - pos,
11385b9c547cSRui Paulo "WPA-EAP-SUITE-B-192 ");
11395b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1140f05cddf9SRui Paulo return pos - buf;
1141f05cddf9SRui Paulo pos += ret;
1142f05cddf9SRui Paulo }
114385732ac8SCy Schubert #ifdef CONFIG_FILS
114485732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
114585732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FILS-SHA256 ");
114685732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
114785732ac8SCy Schubert return pos - buf;
114885732ac8SCy Schubert pos += ret;
114985732ac8SCy Schubert }
115085732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
115185732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "FILS-SHA384 ");
115285732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
115385732ac8SCy Schubert return pos - buf;
115485732ac8SCy Schubert pos += ret;
115585732ac8SCy Schubert }
115685732ac8SCy Schubert #endif /* CONFIG_FILS */
115785732ac8SCy Schubert
115885732ac8SCy Schubert #ifdef CONFIG_OWE
115985732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
116085732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "OWE ");
116185732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
116285732ac8SCy Schubert return pos - buf;
116385732ac8SCy Schubert pos += ret;
116485732ac8SCy Schubert }
116585732ac8SCy Schubert #endif /* CONFIG_OWE */
116685732ac8SCy Schubert
116785732ac8SCy Schubert #ifdef CONFIG_DPP
116885732ac8SCy Schubert if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
116985732ac8SCy Schubert ret = os_snprintf(pos, end - pos, "DPP ");
117085732ac8SCy Schubert if (os_snprintf_error(end - pos, ret))
117185732ac8SCy Schubert return pos - buf;
117285732ac8SCy Schubert pos += ret;
117385732ac8SCy Schubert }
117485732ac8SCy Schubert #endif /* CONFIG_DPP */
1175f05cddf9SRui Paulo
1176325151a3SRui Paulo if (pos > buf && *(pos - 1) == ' ') {
1177325151a3SRui Paulo *(pos - 1) = '\0';
1178325151a3SRui Paulo pos--;
1179325151a3SRui Paulo }
1180325151a3SRui Paulo
1181325151a3SRui Paulo return pos - buf;
1182325151a3SRui Paulo }
1183325151a3SRui Paulo
1184325151a3SRui Paulo
hostapd_ctrl_iface_get_config(struct hostapd_data * hapd,char * buf,size_t buflen)1185325151a3SRui Paulo static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
1186325151a3SRui Paulo char *buf, size_t buflen)
1187325151a3SRui Paulo {
1188325151a3SRui Paulo int ret;
1189325151a3SRui Paulo char *pos, *end;
1190325151a3SRui Paulo
1191325151a3SRui Paulo pos = buf;
1192325151a3SRui Paulo end = buf + buflen;
1193325151a3SRui Paulo
1194325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
1195325151a3SRui Paulo "ssid=%s\n",
1196325151a3SRui Paulo MAC2STR(hapd->own_addr),
1197325151a3SRui Paulo wpa_ssid_txt(hapd->conf->ssid.ssid,
1198325151a3SRui Paulo hapd->conf->ssid.ssid_len));
1199325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1200325151a3SRui Paulo return pos - buf;
1201325151a3SRui Paulo pos += ret;
1202325151a3SRui Paulo
1203325151a3SRui Paulo #ifdef CONFIG_WPS
1204325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
1205325151a3SRui Paulo hapd->conf->wps_state == 0 ? "disabled" :
1206325151a3SRui Paulo (hapd->conf->wps_state == 1 ? "not configured" :
1207325151a3SRui Paulo "configured"));
1208325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1209325151a3SRui Paulo return pos - buf;
1210325151a3SRui Paulo pos += ret;
1211325151a3SRui Paulo
1212325151a3SRui Paulo if (hapd->conf->wps_state && hapd->conf->wpa &&
1213325151a3SRui Paulo hapd->conf->ssid.wpa_passphrase) {
1214325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
1215325151a3SRui Paulo hapd->conf->ssid.wpa_passphrase);
1216325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1217325151a3SRui Paulo return pos - buf;
1218325151a3SRui Paulo pos += ret;
1219325151a3SRui Paulo }
1220325151a3SRui Paulo
1221325151a3SRui Paulo if (hapd->conf->wps_state && hapd->conf->wpa &&
1222325151a3SRui Paulo hapd->conf->ssid.wpa_psk &&
1223325151a3SRui Paulo hapd->conf->ssid.wpa_psk->group) {
1224325151a3SRui Paulo char hex[PMK_LEN * 2 + 1];
1225325151a3SRui Paulo wpa_snprintf_hex(hex, sizeof(hex),
1226325151a3SRui Paulo hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
1227325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
1228325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1229325151a3SRui Paulo return pos - buf;
1230325151a3SRui Paulo pos += ret;
1231325151a3SRui Paulo }
1232c1d255d3SCy Schubert
1233c1d255d3SCy Schubert if (hapd->conf->multi_ap) {
1234c1d255d3SCy Schubert struct hostapd_ssid *ssid = &hapd->conf->multi_ap_backhaul_ssid;
1235c1d255d3SCy Schubert
1236c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos, "multi_ap=%d\n",
1237c1d255d3SCy Schubert hapd->conf->multi_ap);
1238c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1239c1d255d3SCy Schubert return pos - buf;
1240c1d255d3SCy Schubert pos += ret;
1241c1d255d3SCy Schubert
1242c1d255d3SCy Schubert if (ssid->ssid_len) {
1243c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos,
1244c1d255d3SCy Schubert "multi_ap_backhaul_ssid=%s\n",
1245c1d255d3SCy Schubert wpa_ssid_txt(ssid->ssid,
1246c1d255d3SCy Schubert ssid->ssid_len));
1247c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1248c1d255d3SCy Schubert return pos - buf;
1249c1d255d3SCy Schubert pos += ret;
1250c1d255d3SCy Schubert }
1251c1d255d3SCy Schubert
1252c1d255d3SCy Schubert if (hapd->conf->wps_state && hapd->conf->wpa &&
1253c1d255d3SCy Schubert ssid->wpa_passphrase) {
1254c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos,
1255c1d255d3SCy Schubert "multi_ap_backhaul_wpa_passphrase=%s\n",
1256c1d255d3SCy Schubert ssid->wpa_passphrase);
1257c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1258c1d255d3SCy Schubert return pos - buf;
1259c1d255d3SCy Schubert pos += ret;
1260c1d255d3SCy Schubert }
1261c1d255d3SCy Schubert
1262c1d255d3SCy Schubert if (hapd->conf->wps_state && hapd->conf->wpa &&
1263c1d255d3SCy Schubert ssid->wpa_psk &&
1264c1d255d3SCy Schubert ssid->wpa_psk->group) {
1265c1d255d3SCy Schubert char hex[PMK_LEN * 2 + 1];
1266c1d255d3SCy Schubert
1267c1d255d3SCy Schubert wpa_snprintf_hex(hex, sizeof(hex), ssid->wpa_psk->psk,
1268c1d255d3SCy Schubert PMK_LEN);
1269c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos,
1270c1d255d3SCy Schubert "multi_ap_backhaul_wpa_psk=%s\n",
1271c1d255d3SCy Schubert hex);
1272c1d255d3SCy Schubert forced_memzero(hex, sizeof(hex));
1273c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1274c1d255d3SCy Schubert return pos - buf;
1275c1d255d3SCy Schubert pos += ret;
1276c1d255d3SCy Schubert }
1277c1d255d3SCy Schubert }
1278325151a3SRui Paulo #endif /* CONFIG_WPS */
1279325151a3SRui Paulo
1280325151a3SRui Paulo if (hapd->conf->wpa) {
1281325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "wpa=%d\n", hapd->conf->wpa);
1282325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1283325151a3SRui Paulo return pos - buf;
1284325151a3SRui Paulo pos += ret;
1285325151a3SRui Paulo }
1286325151a3SRui Paulo
1287325151a3SRui Paulo if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
1288325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "key_mgmt=");
1289325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
1290325151a3SRui Paulo return pos - buf;
1291325151a3SRui Paulo pos += ret;
1292325151a3SRui Paulo
1293325151a3SRui Paulo pos += hostapd_ctrl_iface_get_key_mgmt(hapd, pos, end - pos);
1294325151a3SRui Paulo
12955b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "\n");
12965b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1297f05cddf9SRui Paulo return pos - buf;
1298f05cddf9SRui Paulo pos += ret;
12995b9c547cSRui Paulo }
13005b9c547cSRui Paulo
13015b9c547cSRui Paulo if (hapd->conf->wpa) {
13025b9c547cSRui Paulo ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
13035b9c547cSRui Paulo wpa_cipher_txt(hapd->conf->wpa_group));
13045b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1305f05cddf9SRui Paulo return pos - buf;
1306f05cddf9SRui Paulo pos += ret;
1307f05cddf9SRui Paulo }
1308f05cddf9SRui Paulo
1309f05cddf9SRui Paulo if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
1310f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
13115b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1312f05cddf9SRui Paulo return pos - buf;
1313f05cddf9SRui Paulo pos += ret;
1314f05cddf9SRui Paulo
13155b9c547cSRui Paulo ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
13165b9c547cSRui Paulo " ");
13175b9c547cSRui Paulo if (ret < 0)
1318f05cddf9SRui Paulo return pos - buf;
1319f05cddf9SRui Paulo pos += ret;
1320f05cddf9SRui Paulo
1321f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "\n");
13225b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1323f05cddf9SRui Paulo return pos - buf;
1324f05cddf9SRui Paulo pos += ret;
1325f05cddf9SRui Paulo }
1326f05cddf9SRui Paulo
1327f05cddf9SRui Paulo if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
1328f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
13295b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1330f05cddf9SRui Paulo return pos - buf;
1331f05cddf9SRui Paulo pos += ret;
1332f05cddf9SRui Paulo
13335b9c547cSRui Paulo ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise,
13345b9c547cSRui Paulo " ");
13355b9c547cSRui Paulo if (ret < 0)
1336f05cddf9SRui Paulo return pos - buf;
1337f05cddf9SRui Paulo pos += ret;
1338f05cddf9SRui Paulo
1339f05cddf9SRui Paulo ret = os_snprintf(pos, end - pos, "\n");
13405b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret))
1341f05cddf9SRui Paulo return pos - buf;
1342f05cddf9SRui Paulo pos += ret;
1343f05cddf9SRui Paulo }
1344f05cddf9SRui Paulo
1345c1d255d3SCy Schubert if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
1346c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
1347c1d255d3SCy Schubert hapd->conf->wpa_deny_ptk0_rekey);
1348c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1349c1d255d3SCy Schubert return pos - buf;
1350c1d255d3SCy Schubert pos += ret;
1351c1d255d3SCy Schubert }
1352c1d255d3SCy Schubert
1353c1d255d3SCy Schubert if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
1354c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
1355c1d255d3SCy Schubert hapd->conf->extended_key_id);
1356c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
1357c1d255d3SCy Schubert return pos - buf;
1358c1d255d3SCy Schubert pos += ret;
1359c1d255d3SCy Schubert }
1360c1d255d3SCy Schubert
1361f05cddf9SRui Paulo return pos - buf;
1362f05cddf9SRui Paulo }
1363f05cddf9SRui Paulo
1364f05cddf9SRui Paulo
hostapd_disassoc_accept_mac(struct hostapd_data * hapd)136585732ac8SCy Schubert static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
136685732ac8SCy Schubert {
136785732ac8SCy Schubert struct sta_info *sta;
136885732ac8SCy Schubert struct vlan_description vlan_id;
136985732ac8SCy Schubert
137085732ac8SCy Schubert if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
137185732ac8SCy Schubert return;
137285732ac8SCy Schubert
137385732ac8SCy Schubert for (sta = hapd->sta_list; sta; sta = sta->next) {
137485732ac8SCy Schubert if (!hostapd_maclist_found(hapd->conf->accept_mac,
137585732ac8SCy Schubert hapd->conf->num_accept_mac,
137685732ac8SCy Schubert sta->addr, &vlan_id) ||
137785732ac8SCy Schubert (vlan_id.notempty &&
137885732ac8SCy Schubert vlan_compare(&vlan_id, sta->vlan_desc)))
137985732ac8SCy Schubert ap_sta_disconnect(hapd, sta, sta->addr,
138085732ac8SCy Schubert WLAN_REASON_UNSPECIFIED);
138185732ac8SCy Schubert }
138285732ac8SCy Schubert }
138385732ac8SCy Schubert
138485732ac8SCy Schubert
hostapd_disassoc_deny_mac(struct hostapd_data * hapd)138585732ac8SCy Schubert static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
138685732ac8SCy Schubert {
138785732ac8SCy Schubert struct sta_info *sta;
138885732ac8SCy Schubert struct vlan_description vlan_id;
138985732ac8SCy Schubert
139085732ac8SCy Schubert for (sta = hapd->sta_list; sta; sta = sta->next) {
139185732ac8SCy Schubert if (hostapd_maclist_found(hapd->conf->deny_mac,
139285732ac8SCy Schubert hapd->conf->num_deny_mac, sta->addr,
139385732ac8SCy Schubert &vlan_id) &&
139485732ac8SCy Schubert (!vlan_id.notempty ||
139585732ac8SCy Schubert !vlan_compare(&vlan_id, sta->vlan_desc)))
139685732ac8SCy Schubert ap_sta_disconnect(hapd, sta, sta->addr,
139785732ac8SCy Schubert WLAN_REASON_UNSPECIFIED);
139885732ac8SCy Schubert }
139985732ac8SCy Schubert }
140085732ac8SCy Schubert
1401c1d255d3SCy Schubert
hostapd_ctrl_iface_set_band(struct hostapd_data * hapd,const char * bands)1402c1d255d3SCy Schubert static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
1403c1d255d3SCy Schubert const char *bands)
1404c1d255d3SCy Schubert {
1405c1d255d3SCy Schubert union wpa_event_data event;
1406c1d255d3SCy Schubert u32 setband_mask = WPA_SETBAND_AUTO;
1407c1d255d3SCy Schubert
1408c1d255d3SCy Schubert /*
1409c1d255d3SCy Schubert * For example:
1410c1d255d3SCy Schubert * SET setband 2G,6G
1411c1d255d3SCy Schubert * SET setband 5G
1412c1d255d3SCy Schubert * SET setband AUTO
1413c1d255d3SCy Schubert */
1414c1d255d3SCy Schubert if (!os_strstr(bands, "AUTO")) {
1415c1d255d3SCy Schubert if (os_strstr(bands, "5G"))
1416c1d255d3SCy Schubert setband_mask |= WPA_SETBAND_5G;
1417c1d255d3SCy Schubert if (os_strstr(bands, "6G"))
1418c1d255d3SCy Schubert setband_mask |= WPA_SETBAND_6G;
1419c1d255d3SCy Schubert if (os_strstr(bands, "2G"))
1420c1d255d3SCy Schubert setband_mask |= WPA_SETBAND_2G;
1421c1d255d3SCy Schubert if (setband_mask == WPA_SETBAND_AUTO)
1422c1d255d3SCy Schubert return -1;
1423c1d255d3SCy Schubert }
1424c1d255d3SCy Schubert
1425c1d255d3SCy Schubert if (hostapd_drv_set_band(hapd, setband_mask) == 0) {
1426c1d255d3SCy Schubert os_memset(&event, 0, sizeof(event));
1427c1d255d3SCy Schubert event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
1428c1d255d3SCy Schubert event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
1429c1d255d3SCy Schubert wpa_supplicant_event(hapd, EVENT_CHANNEL_LIST_CHANGED, &event);
1430c1d255d3SCy Schubert }
1431c1d255d3SCy Schubert
1432c1d255d3SCy Schubert return 0;
1433c1d255d3SCy Schubert }
1434c1d255d3SCy Schubert
1435c1d255d3SCy Schubert
hostapd_ctrl_iface_set(struct hostapd_data * hapd,char * cmd)1436f05cddf9SRui Paulo static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
1437f05cddf9SRui Paulo {
1438f05cddf9SRui Paulo char *value;
1439f05cddf9SRui Paulo int ret = 0;
1440f05cddf9SRui Paulo
1441f05cddf9SRui Paulo value = os_strchr(cmd, ' ');
1442f05cddf9SRui Paulo if (value == NULL)
1443f05cddf9SRui Paulo return -1;
1444f05cddf9SRui Paulo *value++ = '\0';
1445f05cddf9SRui Paulo
1446f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
1447f05cddf9SRui Paulo if (0) {
1448f05cddf9SRui Paulo #ifdef CONFIG_WPS_TESTING
1449f05cddf9SRui Paulo } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
1450f05cddf9SRui Paulo long int val;
1451f05cddf9SRui Paulo val = strtol(value, NULL, 0);
1452f05cddf9SRui Paulo if (val < 0 || val > 0xff) {
1453f05cddf9SRui Paulo ret = -1;
1454f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid "
1455f05cddf9SRui Paulo "wps_version_number %ld", val);
1456f05cddf9SRui Paulo } else {
1457f05cddf9SRui Paulo wps_version_number = val;
1458f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
1459f05cddf9SRui Paulo "version %u.%u",
1460f05cddf9SRui Paulo (wps_version_number & 0xf0) >> 4,
1461f05cddf9SRui Paulo wps_version_number & 0x0f);
1462f05cddf9SRui Paulo hostapd_wps_update_ie(hapd);
1463f05cddf9SRui Paulo }
14644b72b91aSCy Schubert } else if (os_strcasecmp(cmd, "wps_testing_stub_cred") == 0) {
14654b72b91aSCy Schubert wps_testing_stub_cred = atoi(value);
14664b72b91aSCy Schubert wpa_printf(MSG_DEBUG, "WPS: Testing - stub_cred=%d",
14674b72b91aSCy Schubert wps_testing_stub_cred);
14685b9c547cSRui Paulo } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
14695b9c547cSRui Paulo wps_corrupt_pkhash = atoi(value);
14705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
14715b9c547cSRui Paulo wps_corrupt_pkhash);
1472f05cddf9SRui Paulo #endif /* CONFIG_WPS_TESTING */
14735b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
14745b9c547cSRui Paulo } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
14755b9c547cSRui Paulo hapd->ext_mgmt_frame_handling = atoi(value);
14765b9c547cSRui Paulo } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
14775b9c547cSRui Paulo hapd->ext_eapol_frame_io = atoi(value);
1478c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "force_backlog_bytes") == 0) {
1479c1d255d3SCy Schubert hapd->force_backlog_bytes = atoi(value);
148085732ac8SCy Schubert #ifdef CONFIG_DPP
148185732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
148285732ac8SCy Schubert os_free(hapd->dpp_config_obj_override);
148385732ac8SCy Schubert hapd->dpp_config_obj_override = os_strdup(value);
148485732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
148585732ac8SCy Schubert os_free(hapd->dpp_discovery_override);
148685732ac8SCy Schubert hapd->dpp_discovery_override = os_strdup(value);
148785732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
148885732ac8SCy Schubert os_free(hapd->dpp_groups_override);
148985732ac8SCy Schubert hapd->dpp_groups_override = os_strdup(value);
149085732ac8SCy Schubert } else if (os_strcasecmp(cmd,
149185732ac8SCy Schubert "dpp_ignore_netaccesskey_mismatch") == 0) {
149285732ac8SCy Schubert hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
149385732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
149485732ac8SCy Schubert dpp_test = atoi(value);
1495c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
1496c1d255d3SCy Schubert dpp_version_override = atoi(value);
149785732ac8SCy Schubert #endif /* CONFIG_DPP */
14985b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
1499780fb4a2SCy Schubert #ifdef CONFIG_MBO
1500780fb4a2SCy Schubert } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) {
1501780fb4a2SCy Schubert int val;
1502780fb4a2SCy Schubert
1503780fb4a2SCy Schubert if (!hapd->conf->mbo_enabled)
1504780fb4a2SCy Schubert return -1;
1505780fb4a2SCy Schubert
1506780fb4a2SCy Schubert val = atoi(value);
150732a95656SCy Schubert if (val < 0 || val > MBO_ASSOC_DISALLOW_REASON_LOW_RSSI)
1508780fb4a2SCy Schubert return -1;
1509780fb4a2SCy Schubert
1510780fb4a2SCy Schubert hapd->mbo_assoc_disallow = val;
1511780fb4a2SCy Schubert ieee802_11_update_beacons(hapd->iface);
1512780fb4a2SCy Schubert
1513780fb4a2SCy Schubert /*
1514780fb4a2SCy Schubert * TODO: Need to configure drivers that do AP MLME offload with
1515780fb4a2SCy Schubert * disallowing station logic.
1516780fb4a2SCy Schubert */
1517780fb4a2SCy Schubert #endif /* CONFIG_MBO */
151885732ac8SCy Schubert #ifdef CONFIG_DPP
151985732ac8SCy Schubert } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
152085732ac8SCy Schubert os_free(hapd->dpp_configurator_params);
152185732ac8SCy Schubert hapd->dpp_configurator_params = os_strdup(value);
1522c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
1523c1d255d3SCy Schubert hapd->dpp_init_max_tries = atoi(value);
1524c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
1525c1d255d3SCy Schubert hapd->dpp_init_retry_time = atoi(value);
1526c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
1527c1d255d3SCy Schubert hapd->dpp_resp_wait_time = atoi(value);
1528c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
1529c1d255d3SCy Schubert hapd->dpp_resp_max_tries = atoi(value);
1530c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
1531c1d255d3SCy Schubert hapd->dpp_resp_retry_time = atoi(value);
153285732ac8SCy Schubert #endif /* CONFIG_DPP */
1533c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "setband") == 0) {
1534c1d255d3SCy Schubert ret = hostapd_ctrl_iface_set_band(hapd, value);
1535f05cddf9SRui Paulo } else {
1536f05cddf9SRui Paulo ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
15375b9c547cSRui Paulo if (ret)
15385b9c547cSRui Paulo return ret;
15395b9c547cSRui Paulo
15405b9c547cSRui Paulo if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
154185732ac8SCy Schubert hostapd_disassoc_deny_mac(hapd);
154285732ac8SCy Schubert } else if (os_strcasecmp(cmd, "accept_mac_file") == 0) {
154385732ac8SCy Schubert hostapd_disassoc_accept_mac(hapd);
154485732ac8SCy Schubert } else if (os_strncmp(cmd, "wme_ac_", 7) == 0 ||
154585732ac8SCy Schubert os_strncmp(cmd, "wmm_ac_", 7) == 0) {
154685732ac8SCy Schubert hapd->parameter_set_count++;
154785732ac8SCy Schubert if (ieee802_11_update_beacons(hapd->iface))
154885732ac8SCy Schubert wpa_printf(MSG_DEBUG,
154985732ac8SCy Schubert "Failed to update beacons with WMM parameters");
1550c1d255d3SCy Schubert } else if (os_strcmp(cmd, "wpa_passphrase") == 0 ||
1551c1d255d3SCy Schubert os_strcmp(cmd, "sae_password") == 0 ||
1552c1d255d3SCy Schubert os_strcmp(cmd, "sae_pwe") == 0) {
1553c1d255d3SCy Schubert if (hapd->started)
1554c1d255d3SCy Schubert hostapd_setup_sae_pt(hapd->conf);
1555c1d255d3SCy Schubert } else if (os_strcasecmp(cmd, "transition_disable") == 0) {
1556c1d255d3SCy Schubert wpa_auth_set_transition_disable(hapd->wpa_auth,
1557c1d255d3SCy Schubert hapd->conf->transition_disable);
15585b9c547cSRui Paulo }
1559c1d255d3SCy Schubert
1560c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1561c1d255d3SCy Schubert if (os_strcmp(cmd, "ft_rsnxe_used") == 0)
1562c1d255d3SCy Schubert wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth,
1563c1d255d3SCy Schubert hapd->conf->ft_rsnxe_used);
1564c1d255d3SCy Schubert else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0)
1565c1d255d3SCy Schubert wpa_auth_set_ocv_override_freq(
1566c1d255d3SCy Schubert hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
1567c1d255d3SCy Schubert atoi(value));
1568c1d255d3SCy Schubert else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0)
1569c1d255d3SCy Schubert wpa_auth_set_ocv_override_freq(
1570c1d255d3SCy Schubert hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
1571c1d255d3SCy Schubert atoi(value));
1572c1d255d3SCy Schubert else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0)
1573c1d255d3SCy Schubert wpa_auth_set_ocv_override_freq(
1574c1d255d3SCy Schubert hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
1575c1d255d3SCy Schubert atoi(value));
1576c1d255d3SCy Schubert else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0)
1577c1d255d3SCy Schubert wpa_auth_set_ocv_override_freq(
1578c1d255d3SCy Schubert hapd->wpa_auth,
1579c1d255d3SCy Schubert WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value));
1580c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1581f05cddf9SRui Paulo }
1582f05cddf9SRui Paulo
1583f05cddf9SRui Paulo return ret;
1584f05cddf9SRui Paulo }
1585f05cddf9SRui Paulo
1586f05cddf9SRui Paulo
hostapd_ctrl_iface_get(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)1587f05cddf9SRui Paulo static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
1588f05cddf9SRui Paulo char *buf, size_t buflen)
1589f05cddf9SRui Paulo {
1590f05cddf9SRui Paulo int res;
1591f05cddf9SRui Paulo
1592f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
1593f05cddf9SRui Paulo
1594f05cddf9SRui Paulo if (os_strcmp(cmd, "version") == 0) {
1595f05cddf9SRui Paulo res = os_snprintf(buf, buflen, "%s", VERSION_STR);
15965b9c547cSRui Paulo if (os_snprintf_error(buflen, res))
15975b9c547cSRui Paulo return -1;
15985b9c547cSRui Paulo return res;
15995b9c547cSRui Paulo } else if (os_strcmp(cmd, "tls_library") == 0) {
16005b9c547cSRui Paulo res = tls_get_library_version(buf, buflen);
16015b9c547cSRui Paulo if (os_snprintf_error(buflen, res))
1602f05cddf9SRui Paulo return -1;
1603f05cddf9SRui Paulo return res;
1604f05cddf9SRui Paulo }
1605f05cddf9SRui Paulo
1606f05cddf9SRui Paulo return -1;
1607f05cddf9SRui Paulo }
1608f05cddf9SRui Paulo
1609f05cddf9SRui Paulo
hostapd_ctrl_iface_enable(struct hostapd_iface * iface)1610f05cddf9SRui Paulo static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
1611f05cddf9SRui Paulo {
1612f05cddf9SRui Paulo if (hostapd_enable_iface(iface) < 0) {
1613f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Enabling of interface failed");
1614f05cddf9SRui Paulo return -1;
1615f05cddf9SRui Paulo }
1616f05cddf9SRui Paulo return 0;
1617f05cddf9SRui Paulo }
1618f05cddf9SRui Paulo
1619f05cddf9SRui Paulo
hostapd_ctrl_iface_reload(struct hostapd_iface * iface)1620f05cddf9SRui Paulo static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
1621f05cddf9SRui Paulo {
1622f05cddf9SRui Paulo if (hostapd_reload_iface(iface) < 0) {
1623f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Reloading of interface failed");
1624f05cddf9SRui Paulo return -1;
1625f05cddf9SRui Paulo }
1626f05cddf9SRui Paulo return 0;
1627f05cddf9SRui Paulo }
1628f05cddf9SRui Paulo
1629f05cddf9SRui Paulo
hostapd_ctrl_iface_disable(struct hostapd_iface * iface)1630f05cddf9SRui Paulo static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
1631f05cddf9SRui Paulo {
1632f05cddf9SRui Paulo if (hostapd_disable_iface(iface) < 0) {
1633f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Disabling of interface failed");
1634f05cddf9SRui Paulo return -1;
1635f05cddf9SRui Paulo }
1636f05cddf9SRui Paulo return 0;
1637f05cddf9SRui Paulo }
1638f05cddf9SRui Paulo
1639f05cddf9SRui Paulo
16404bc52338SCy Schubert static int
hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data * hapd,struct sta_info * sta,void * ctx)16414bc52338SCy Schubert hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd,
16424bc52338SCy Schubert struct sta_info *sta, void *ctx)
16434bc52338SCy Schubert {
16444bc52338SCy Schubert struct hostapd_wpa_psk *psk;
16454bc52338SCy Schubert const u8 *pmk;
16464bc52338SCy Schubert int pmk_len;
16474bc52338SCy Schubert int pmk_match;
16484bc52338SCy Schubert int sta_match;
16494bc52338SCy Schubert int bss_match;
16504bc52338SCy Schubert int reason;
16514bc52338SCy Schubert
16524bc52338SCy Schubert pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
16534bc52338SCy Schubert
16544bc52338SCy Schubert for (psk = hapd->conf->ssid.wpa_psk; pmk && psk; psk = psk->next) {
16554bc52338SCy Schubert pmk_match = PMK_LEN == pmk_len &&
16564bc52338SCy Schubert os_memcmp(psk->psk, pmk, pmk_len) == 0;
16574bc52338SCy Schubert sta_match = psk->group == 0 &&
16584bc52338SCy Schubert os_memcmp(sta->addr, psk->addr, ETH_ALEN) == 0;
16594bc52338SCy Schubert bss_match = psk->group == 1;
16604bc52338SCy Schubert
16614bc52338SCy Schubert if (pmk_match && (sta_match || bss_match))
16624bc52338SCy Schubert return 0;
16634bc52338SCy Schubert }
16644bc52338SCy Schubert
16654bc52338SCy Schubert wpa_printf(MSG_INFO, "STA " MACSTR
16664bc52338SCy Schubert " PSK/passphrase no longer valid - disconnect",
16674bc52338SCy Schubert MAC2STR(sta->addr));
16684bc52338SCy Schubert reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
16694bc52338SCy Schubert hostapd_drv_sta_deauth(hapd, sta->addr, reason);
16704bc52338SCy Schubert ap_sta_deauthenticate(hapd, sta, reason);
16714bc52338SCy Schubert
16724bc52338SCy Schubert return 0;
16734bc52338SCy Schubert }
16744bc52338SCy Schubert
16754bc52338SCy Schubert
hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data * hapd)16764bc52338SCy Schubert static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd)
16774bc52338SCy Schubert {
16784bc52338SCy Schubert struct hostapd_bss_config *conf = hapd->conf;
16794bc52338SCy Schubert int err;
16804bc52338SCy Schubert
16814bc52338SCy Schubert hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
16824bc52338SCy Schubert
16834bc52338SCy Schubert err = hostapd_setup_wpa_psk(conf);
16844bc52338SCy Schubert if (err < 0) {
16854bc52338SCy Schubert wpa_printf(MSG_ERROR, "Reloading WPA-PSK passwords failed: %d",
16864bc52338SCy Schubert err);
16874bc52338SCy Schubert return -1;
16884bc52338SCy Schubert }
16894bc52338SCy Schubert
16904bc52338SCy Schubert ap_for_each_sta(hapd, hostapd_ctrl_iface_kick_mismatch_psk_sta_iter,
16914bc52338SCy Schubert NULL);
16924bc52338SCy Schubert
16934bc52338SCy Schubert return 0;
16944bc52338SCy Schubert }
16954bc52338SCy Schubert
16964bc52338SCy Schubert
16975b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
16985b9c547cSRui Paulo
hostapd_ctrl_iface_radar(struct hostapd_data * hapd,char * cmd)16995b9c547cSRui Paulo static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
17005b9c547cSRui Paulo {
17015b9c547cSRui Paulo union wpa_event_data data;
17025b9c547cSRui Paulo char *pos, *param;
17035b9c547cSRui Paulo enum wpa_event_type event;
17045b9c547cSRui Paulo
17055b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
17065b9c547cSRui Paulo
17075b9c547cSRui Paulo os_memset(&data, 0, sizeof(data));
17085b9c547cSRui Paulo
17095b9c547cSRui Paulo param = os_strchr(cmd, ' ');
17105b9c547cSRui Paulo if (param == NULL)
17115b9c547cSRui Paulo return -1;
17125b9c547cSRui Paulo *param++ = '\0';
17135b9c547cSRui Paulo
17145b9c547cSRui Paulo if (os_strcmp(cmd, "DETECTED") == 0)
17155b9c547cSRui Paulo event = EVENT_DFS_RADAR_DETECTED;
17165b9c547cSRui Paulo else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
17175b9c547cSRui Paulo event = EVENT_DFS_CAC_FINISHED;
17185b9c547cSRui Paulo else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
17195b9c547cSRui Paulo event = EVENT_DFS_CAC_ABORTED;
17205b9c547cSRui Paulo else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
17215b9c547cSRui Paulo event = EVENT_DFS_NOP_FINISHED;
17225b9c547cSRui Paulo else {
17235b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
17245b9c547cSRui Paulo cmd);
17255b9c547cSRui Paulo return -1;
17265b9c547cSRui Paulo }
17275b9c547cSRui Paulo
17285b9c547cSRui Paulo pos = os_strstr(param, "freq=");
17295b9c547cSRui Paulo if (pos)
17305b9c547cSRui Paulo data.dfs_event.freq = atoi(pos + 5);
17315b9c547cSRui Paulo
17325b9c547cSRui Paulo pos = os_strstr(param, "ht_enabled=1");
17335b9c547cSRui Paulo if (pos)
17345b9c547cSRui Paulo data.dfs_event.ht_enabled = 1;
17355b9c547cSRui Paulo
17365b9c547cSRui Paulo pos = os_strstr(param, "chan_offset=");
17375b9c547cSRui Paulo if (pos)
17385b9c547cSRui Paulo data.dfs_event.chan_offset = atoi(pos + 12);
17395b9c547cSRui Paulo
17405b9c547cSRui Paulo pos = os_strstr(param, "chan_width=");
17415b9c547cSRui Paulo if (pos)
17425b9c547cSRui Paulo data.dfs_event.chan_width = atoi(pos + 11);
17435b9c547cSRui Paulo
17445b9c547cSRui Paulo pos = os_strstr(param, "cf1=");
17455b9c547cSRui Paulo if (pos)
17465b9c547cSRui Paulo data.dfs_event.cf1 = atoi(pos + 4);
17475b9c547cSRui Paulo
17485b9c547cSRui Paulo pos = os_strstr(param, "cf2=");
17495b9c547cSRui Paulo if (pos)
17505b9c547cSRui Paulo data.dfs_event.cf2 = atoi(pos + 4);
17515b9c547cSRui Paulo
17525b9c547cSRui Paulo wpa_supplicant_event(hapd, event, &data);
17535b9c547cSRui Paulo
17545b9c547cSRui Paulo return 0;
17555b9c547cSRui Paulo }
17565b9c547cSRui Paulo
17575b9c547cSRui Paulo
hostapd_ctrl_iface_mgmt_tx(struct hostapd_data * hapd,char * cmd)17585b9c547cSRui Paulo static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
17595b9c547cSRui Paulo {
17605b9c547cSRui Paulo size_t len;
17615b9c547cSRui Paulo u8 *buf;
17625b9c547cSRui Paulo int res;
17635b9c547cSRui Paulo
17645b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
17655b9c547cSRui Paulo
17665b9c547cSRui Paulo len = os_strlen(cmd);
17675b9c547cSRui Paulo if (len & 1)
17685b9c547cSRui Paulo return -1;
17695b9c547cSRui Paulo len /= 2;
17705b9c547cSRui Paulo
17715b9c547cSRui Paulo buf = os_malloc(len);
17725b9c547cSRui Paulo if (buf == NULL)
17735b9c547cSRui Paulo return -1;
17745b9c547cSRui Paulo
17755b9c547cSRui Paulo if (hexstr2bin(cmd, buf, len) < 0) {
17765b9c547cSRui Paulo os_free(buf);
17775b9c547cSRui Paulo return -1;
17785b9c547cSRui Paulo }
17795b9c547cSRui Paulo
1780c1d255d3SCy Schubert res = hostapd_drv_send_mlme(hapd, buf, len, 0, NULL, 0, 0);
17815b9c547cSRui Paulo os_free(buf);
17825b9c547cSRui Paulo return res;
17835b9c547cSRui Paulo }
17845b9c547cSRui Paulo
17855b9c547cSRui Paulo
hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data * hapd,char * cmd)178685732ac8SCy Schubert static int hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data *hapd,
178785732ac8SCy Schubert char *cmd)
178885732ac8SCy Schubert {
178985732ac8SCy Schubert char *pos, *param;
179085732ac8SCy Schubert size_t len;
179185732ac8SCy Schubert u8 *buf;
179285732ac8SCy Schubert int stype = 0, ok = 0;
179385732ac8SCy Schubert union wpa_event_data event;
179485732ac8SCy Schubert
179585732ac8SCy Schubert if (!hapd->ext_mgmt_frame_handling)
179685732ac8SCy Schubert return -1;
179785732ac8SCy Schubert
179885732ac8SCy Schubert /* stype=<val> ok=<0/1> buf=<frame hexdump> */
179985732ac8SCy Schubert
180085732ac8SCy Schubert wpa_printf(MSG_DEBUG, "External MGMT TX status process: %s", cmd);
180185732ac8SCy Schubert
180285732ac8SCy Schubert pos = cmd;
180385732ac8SCy Schubert param = os_strstr(pos, "stype=");
180485732ac8SCy Schubert if (param) {
180585732ac8SCy Schubert param += 6;
180685732ac8SCy Schubert stype = atoi(param);
180785732ac8SCy Schubert }
180885732ac8SCy Schubert
180985732ac8SCy Schubert param = os_strstr(pos, " ok=");
181085732ac8SCy Schubert if (param) {
181185732ac8SCy Schubert param += 4;
181285732ac8SCy Schubert ok = atoi(param);
181385732ac8SCy Schubert }
181485732ac8SCy Schubert
181585732ac8SCy Schubert param = os_strstr(pos, " buf=");
181685732ac8SCy Schubert if (!param)
181785732ac8SCy Schubert return -1;
181885732ac8SCy Schubert param += 5;
181985732ac8SCy Schubert
182085732ac8SCy Schubert len = os_strlen(param);
182185732ac8SCy Schubert if (len & 1)
182285732ac8SCy Schubert return -1;
182385732ac8SCy Schubert len /= 2;
182485732ac8SCy Schubert
182585732ac8SCy Schubert buf = os_malloc(len);
182685732ac8SCy Schubert if (!buf || hexstr2bin(param, buf, len) < 0) {
182785732ac8SCy Schubert os_free(buf);
182885732ac8SCy Schubert return -1;
182985732ac8SCy Schubert }
183085732ac8SCy Schubert
183185732ac8SCy Schubert os_memset(&event, 0, sizeof(event));
183285732ac8SCy Schubert event.tx_status.type = WLAN_FC_TYPE_MGMT;
183385732ac8SCy Schubert event.tx_status.data = buf;
183485732ac8SCy Schubert event.tx_status.data_len = len;
183585732ac8SCy Schubert event.tx_status.stype = stype;
183685732ac8SCy Schubert event.tx_status.ack = ok;
183785732ac8SCy Schubert hapd->ext_mgmt_frame_handling = 0;
183885732ac8SCy Schubert wpa_supplicant_event(hapd, EVENT_TX_STATUS, &event);
183985732ac8SCy Schubert hapd->ext_mgmt_frame_handling = 1;
184085732ac8SCy Schubert
184185732ac8SCy Schubert os_free(buf);
184285732ac8SCy Schubert
184385732ac8SCy Schubert return 0;
184485732ac8SCy Schubert }
184585732ac8SCy Schubert
184685732ac8SCy Schubert
hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data * hapd,char * cmd)184785732ac8SCy Schubert static int hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data *hapd,
184885732ac8SCy Schubert char *cmd)
184985732ac8SCy Schubert {
185085732ac8SCy Schubert char *pos, *param;
185185732ac8SCy Schubert size_t len;
185285732ac8SCy Schubert u8 *buf;
185385732ac8SCy Schubert int freq = 0, datarate = 0, ssi_signal = 0;
185485732ac8SCy Schubert union wpa_event_data event;
185585732ac8SCy Schubert
185685732ac8SCy Schubert if (!hapd->ext_mgmt_frame_handling)
185785732ac8SCy Schubert return -1;
185885732ac8SCy Schubert
185985732ac8SCy Schubert /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
186085732ac8SCy Schubert
186185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
186285732ac8SCy Schubert
186385732ac8SCy Schubert pos = cmd;
186485732ac8SCy Schubert param = os_strstr(pos, "freq=");
186585732ac8SCy Schubert if (param) {
186685732ac8SCy Schubert param += 5;
186785732ac8SCy Schubert freq = atoi(param);
186885732ac8SCy Schubert }
186985732ac8SCy Schubert
187085732ac8SCy Schubert param = os_strstr(pos, " datarate=");
187185732ac8SCy Schubert if (param) {
187285732ac8SCy Schubert param += 10;
187385732ac8SCy Schubert datarate = atoi(param);
187485732ac8SCy Schubert }
187585732ac8SCy Schubert
187685732ac8SCy Schubert param = os_strstr(pos, " ssi_signal=");
187785732ac8SCy Schubert if (param) {
187885732ac8SCy Schubert param += 12;
187985732ac8SCy Schubert ssi_signal = atoi(param);
188085732ac8SCy Schubert }
188185732ac8SCy Schubert
188285732ac8SCy Schubert param = os_strstr(pos, " frame=");
188385732ac8SCy Schubert if (param == NULL)
188485732ac8SCy Schubert return -1;
188585732ac8SCy Schubert param += 7;
188685732ac8SCy Schubert
188785732ac8SCy Schubert len = os_strlen(param);
188885732ac8SCy Schubert if (len & 1)
188985732ac8SCy Schubert return -1;
189085732ac8SCy Schubert len /= 2;
189185732ac8SCy Schubert
189285732ac8SCy Schubert buf = os_malloc(len);
189385732ac8SCy Schubert if (buf == NULL)
189485732ac8SCy Schubert return -1;
189585732ac8SCy Schubert
189685732ac8SCy Schubert if (hexstr2bin(param, buf, len) < 0) {
189785732ac8SCy Schubert os_free(buf);
189885732ac8SCy Schubert return -1;
189985732ac8SCy Schubert }
190085732ac8SCy Schubert
190185732ac8SCy Schubert os_memset(&event, 0, sizeof(event));
190285732ac8SCy Schubert event.rx_mgmt.freq = freq;
190385732ac8SCy Schubert event.rx_mgmt.frame = buf;
190485732ac8SCy Schubert event.rx_mgmt.frame_len = len;
190585732ac8SCy Schubert event.rx_mgmt.ssi_signal = ssi_signal;
190685732ac8SCy Schubert event.rx_mgmt.datarate = datarate;
190785732ac8SCy Schubert hapd->ext_mgmt_frame_handling = 0;
190885732ac8SCy Schubert wpa_supplicant_event(hapd, EVENT_RX_MGMT, &event);
190985732ac8SCy Schubert hapd->ext_mgmt_frame_handling = 1;
191085732ac8SCy Schubert
191185732ac8SCy Schubert os_free(buf);
191285732ac8SCy Schubert
191385732ac8SCy Schubert return 0;
191485732ac8SCy Schubert }
191585732ac8SCy Schubert
191685732ac8SCy Schubert
hostapd_ctrl_iface_eapol_rx(struct hostapd_data * hapd,char * cmd)19175b9c547cSRui Paulo static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
19185b9c547cSRui Paulo {
19195b9c547cSRui Paulo char *pos;
19205b9c547cSRui Paulo u8 src[ETH_ALEN], *buf;
19215b9c547cSRui Paulo int used;
19225b9c547cSRui Paulo size_t len;
19235b9c547cSRui Paulo
19245b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
19255b9c547cSRui Paulo
19265b9c547cSRui Paulo pos = cmd;
19275b9c547cSRui Paulo used = hwaddr_aton2(pos, src);
19285b9c547cSRui Paulo if (used < 0)
19295b9c547cSRui Paulo return -1;
19305b9c547cSRui Paulo pos += used;
19315b9c547cSRui Paulo while (*pos == ' ')
19325b9c547cSRui Paulo pos++;
19335b9c547cSRui Paulo
19345b9c547cSRui Paulo len = os_strlen(pos);
19355b9c547cSRui Paulo if (len & 1)
19365b9c547cSRui Paulo return -1;
19375b9c547cSRui Paulo len /= 2;
19385b9c547cSRui Paulo
19395b9c547cSRui Paulo buf = os_malloc(len);
19405b9c547cSRui Paulo if (buf == NULL)
19415b9c547cSRui Paulo return -1;
19425b9c547cSRui Paulo
19435b9c547cSRui Paulo if (hexstr2bin(pos, buf, len) < 0) {
19445b9c547cSRui Paulo os_free(buf);
19455b9c547cSRui Paulo return -1;
19465b9c547cSRui Paulo }
19475b9c547cSRui Paulo
19485b9c547cSRui Paulo ieee802_1x_receive(hapd, src, buf, len);
19495b9c547cSRui Paulo os_free(buf);
19505b9c547cSRui Paulo
19515b9c547cSRui Paulo return 0;
19525b9c547cSRui Paulo }
19535b9c547cSRui Paulo
19545b9c547cSRui Paulo
hostapd_ctrl_iface_eapol_tx(struct hostapd_data * hapd,char * cmd)1955c1d255d3SCy Schubert static int hostapd_ctrl_iface_eapol_tx(struct hostapd_data *hapd, char *cmd)
1956c1d255d3SCy Schubert {
1957c1d255d3SCy Schubert char *pos, *pos2;
1958c1d255d3SCy Schubert u8 dst[ETH_ALEN], *buf;
1959c1d255d3SCy Schubert int used, ret;
1960c1d255d3SCy Schubert size_t len;
1961c1d255d3SCy Schubert unsigned int prev;
1962c1d255d3SCy Schubert int encrypt = 0;
1963c1d255d3SCy Schubert
1964c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "External EAPOL TX: %s", cmd);
1965c1d255d3SCy Schubert
1966c1d255d3SCy Schubert pos = cmd;
1967c1d255d3SCy Schubert used = hwaddr_aton2(pos, dst);
1968c1d255d3SCy Schubert if (used < 0)
1969c1d255d3SCy Schubert return -1;
1970c1d255d3SCy Schubert pos += used;
1971c1d255d3SCy Schubert while (*pos == ' ')
1972c1d255d3SCy Schubert pos++;
1973c1d255d3SCy Schubert
1974c1d255d3SCy Schubert pos2 = os_strchr(pos, ' ');
1975c1d255d3SCy Schubert if (pos2) {
1976c1d255d3SCy Schubert len = pos2 - pos;
1977c1d255d3SCy Schubert encrypt = os_strstr(pos2, "encrypt=1") != NULL;
1978c1d255d3SCy Schubert } else {
1979c1d255d3SCy Schubert len = os_strlen(pos);
1980c1d255d3SCy Schubert }
1981c1d255d3SCy Schubert if (len & 1)
1982c1d255d3SCy Schubert return -1;
1983c1d255d3SCy Schubert len /= 2;
1984c1d255d3SCy Schubert
1985c1d255d3SCy Schubert buf = os_malloc(len);
1986c1d255d3SCy Schubert if (!buf || hexstr2bin(pos, buf, len) < 0) {
1987c1d255d3SCy Schubert os_free(buf);
1988c1d255d3SCy Schubert return -1;
1989c1d255d3SCy Schubert }
1990c1d255d3SCy Schubert
1991c1d255d3SCy Schubert prev = hapd->ext_eapol_frame_io;
1992c1d255d3SCy Schubert hapd->ext_eapol_frame_io = 0;
1993c1d255d3SCy Schubert ret = hostapd_wpa_auth_send_eapol(hapd, dst, buf, len, encrypt);
1994c1d255d3SCy Schubert hapd->ext_eapol_frame_io = prev;
1995c1d255d3SCy Schubert os_free(buf);
1996c1d255d3SCy Schubert
1997c1d255d3SCy Schubert return ret;
1998c1d255d3SCy Schubert }
1999c1d255d3SCy Schubert
2000c1d255d3SCy Schubert
ipv4_hdr_checksum(const void * buf,size_t len)20015b9c547cSRui Paulo static u16 ipv4_hdr_checksum(const void *buf, size_t len)
20025b9c547cSRui Paulo {
20035b9c547cSRui Paulo size_t i;
20045b9c547cSRui Paulo u32 sum = 0;
20055b9c547cSRui Paulo const u16 *pos = buf;
20065b9c547cSRui Paulo
20075b9c547cSRui Paulo for (i = 0; i < len / 2; i++)
20085b9c547cSRui Paulo sum += *pos++;
20095b9c547cSRui Paulo
20105b9c547cSRui Paulo while (sum >> 16)
20115b9c547cSRui Paulo sum = (sum & 0xffff) + (sum >> 16);
20125b9c547cSRui Paulo
20135b9c547cSRui Paulo return sum ^ 0xffff;
20145b9c547cSRui Paulo }
20155b9c547cSRui Paulo
20165b9c547cSRui Paulo
20175b9c547cSRui Paulo #define HWSIM_PACKETLEN 1500
20185b9c547cSRui Paulo #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
20195b9c547cSRui Paulo
hostapd_data_test_rx(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)2020780fb4a2SCy Schubert static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
20215b9c547cSRui Paulo size_t len)
20225b9c547cSRui Paulo {
20235b9c547cSRui Paulo struct hostapd_data *hapd = ctx;
20245b9c547cSRui Paulo const struct ether_header *eth;
2025c1d255d3SCy Schubert struct ip ip;
20265b9c547cSRui Paulo const u8 *pos;
20275b9c547cSRui Paulo unsigned int i;
2028206b73d0SCy Schubert char extra[30];
20295b9c547cSRui Paulo
2030206b73d0SCy Schubert if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
2031206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
2032206b73d0SCy Schubert "test data: RX - ignore unexpected length %d",
2033206b73d0SCy Schubert (int) len);
20345b9c547cSRui Paulo return;
2035206b73d0SCy Schubert }
20365b9c547cSRui Paulo
20375b9c547cSRui Paulo eth = (const struct ether_header *) buf;
2038325151a3SRui Paulo os_memcpy(&ip, eth + 1, sizeof(ip));
2039325151a3SRui Paulo pos = &buf[sizeof(*eth) + sizeof(ip)];
20405b9c547cSRui Paulo
2041c1d255d3SCy Schubert if (ip.ip_hl != 5 || ip.ip_v != 4 ||
2042c1d255d3SCy Schubert ntohs(ip.ip_len) > HWSIM_IP_LEN) {
2043206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
2044c1d255d3SCy Schubert "test data: RX - ignore unexpected IP header");
20455b9c547cSRui Paulo return;
2046206b73d0SCy Schubert }
20475b9c547cSRui Paulo
2048c1d255d3SCy Schubert for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
2049206b73d0SCy Schubert if (*pos != (u8) i) {
2050206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
2051206b73d0SCy Schubert "test data: RX - ignore mismatching payload");
20525b9c547cSRui Paulo return;
2053206b73d0SCy Schubert }
20545b9c547cSRui Paulo pos++;
20555b9c547cSRui Paulo }
20565b9c547cSRui Paulo
2057206b73d0SCy Schubert extra[0] = '\0';
2058c1d255d3SCy Schubert if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
2059c1d255d3SCy Schubert os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
2060206b73d0SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
2061206b73d0SCy Schubert MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
20625b9c547cSRui Paulo }
20635b9c547cSRui Paulo
20645b9c547cSRui Paulo
hostapd_ctrl_iface_data_test_config(struct hostapd_data * hapd,char * cmd)20655b9c547cSRui Paulo static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
20665b9c547cSRui Paulo char *cmd)
20675b9c547cSRui Paulo {
20685b9c547cSRui Paulo int enabled = atoi(cmd);
20695b9c547cSRui Paulo char *pos;
20705b9c547cSRui Paulo const char *ifname;
20715b9c547cSRui Paulo
20725b9c547cSRui Paulo if (!enabled) {
20735b9c547cSRui Paulo if (hapd->l2_test) {
20745b9c547cSRui Paulo l2_packet_deinit(hapd->l2_test);
20755b9c547cSRui Paulo hapd->l2_test = NULL;
20765b9c547cSRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
20775b9c547cSRui Paulo "test data: Disabled");
20785b9c547cSRui Paulo }
20795b9c547cSRui Paulo return 0;
20805b9c547cSRui Paulo }
20815b9c547cSRui Paulo
20825b9c547cSRui Paulo if (hapd->l2_test)
20835b9c547cSRui Paulo return 0;
20845b9c547cSRui Paulo
20855b9c547cSRui Paulo pos = os_strstr(cmd, " ifname=");
20865b9c547cSRui Paulo if (pos)
20875b9c547cSRui Paulo ifname = pos + 8;
20885b9c547cSRui Paulo else
20895b9c547cSRui Paulo ifname = hapd->conf->iface;
20905b9c547cSRui Paulo
20915b9c547cSRui Paulo hapd->l2_test = l2_packet_init(ifname, hapd->own_addr,
20925b9c547cSRui Paulo ETHERTYPE_IP, hostapd_data_test_rx,
20935b9c547cSRui Paulo hapd, 1);
20945b9c547cSRui Paulo if (hapd->l2_test == NULL)
20955b9c547cSRui Paulo return -1;
20965b9c547cSRui Paulo
20975b9c547cSRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
20985b9c547cSRui Paulo
20995b9c547cSRui Paulo return 0;
21005b9c547cSRui Paulo }
21015b9c547cSRui Paulo
21025b9c547cSRui Paulo
hostapd_ctrl_iface_data_test_tx(struct hostapd_data * hapd,char * cmd)21035b9c547cSRui Paulo static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
21045b9c547cSRui Paulo {
21055b9c547cSRui Paulo u8 dst[ETH_ALEN], src[ETH_ALEN];
2106206b73d0SCy Schubert char *pos, *pos2;
21075b9c547cSRui Paulo int used;
21085b9c547cSRui Paulo long int val;
21095b9c547cSRui Paulo u8 tos;
2110325151a3SRui Paulo u8 buf[2 + HWSIM_PACKETLEN];
21115b9c547cSRui Paulo struct ether_header *eth;
2112c1d255d3SCy Schubert struct ip *ip;
21135b9c547cSRui Paulo u8 *dpos;
21145b9c547cSRui Paulo unsigned int i;
2115206b73d0SCy Schubert size_t send_len = HWSIM_IP_LEN;
21165b9c547cSRui Paulo
21175b9c547cSRui Paulo if (hapd->l2_test == NULL)
21185b9c547cSRui Paulo return -1;
21195b9c547cSRui Paulo
2120206b73d0SCy Schubert /* format: <dst> <src> <tos> [len=<length>] */
21215b9c547cSRui Paulo
21225b9c547cSRui Paulo pos = cmd;
21235b9c547cSRui Paulo used = hwaddr_aton2(pos, dst);
21245b9c547cSRui Paulo if (used < 0)
21255b9c547cSRui Paulo return -1;
21265b9c547cSRui Paulo pos += used;
21275b9c547cSRui Paulo while (*pos == ' ')
21285b9c547cSRui Paulo pos++;
21295b9c547cSRui Paulo used = hwaddr_aton2(pos, src);
21305b9c547cSRui Paulo if (used < 0)
21315b9c547cSRui Paulo return -1;
21325b9c547cSRui Paulo pos += used;
21335b9c547cSRui Paulo
2134206b73d0SCy Schubert val = strtol(pos, &pos2, 0);
21355b9c547cSRui Paulo if (val < 0 || val > 0xff)
21365b9c547cSRui Paulo return -1;
21375b9c547cSRui Paulo tos = val;
21385b9c547cSRui Paulo
2139206b73d0SCy Schubert pos = os_strstr(pos2, " len=");
2140206b73d0SCy Schubert if (pos) {
2141206b73d0SCy Schubert i = atoi(pos + 5);
2142206b73d0SCy Schubert if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
2143206b73d0SCy Schubert return -1;
2144206b73d0SCy Schubert send_len = i;
2145206b73d0SCy Schubert }
2146206b73d0SCy Schubert
2147325151a3SRui Paulo eth = (struct ether_header *) &buf[2];
21485b9c547cSRui Paulo os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
21495b9c547cSRui Paulo os_memcpy(eth->ether_shost, src, ETH_ALEN);
21505b9c547cSRui Paulo eth->ether_type = htons(ETHERTYPE_IP);
2151c1d255d3SCy Schubert ip = (struct ip *) (eth + 1);
21525b9c547cSRui Paulo os_memset(ip, 0, sizeof(*ip));
2153c1d255d3SCy Schubert ip->ip_hl = 5;
2154c1d255d3SCy Schubert ip->ip_v = 4;
2155c1d255d3SCy Schubert ip->ip_ttl = 64;
2156c1d255d3SCy Schubert ip->ip_tos = tos;
2157c1d255d3SCy Schubert ip->ip_len = htons(send_len);
2158c1d255d3SCy Schubert ip->ip_p = 1;
2159c1d255d3SCy Schubert ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
2160c1d255d3SCy Schubert ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
2161c1d255d3SCy Schubert ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
21625b9c547cSRui Paulo dpos = (u8 *) (ip + 1);
2163206b73d0SCy Schubert for (i = 0; i < send_len - sizeof(*ip); i++)
21645b9c547cSRui Paulo *dpos++ = i;
21655b9c547cSRui Paulo
2166325151a3SRui Paulo if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
2167206b73d0SCy Schubert sizeof(struct ether_header) + send_len) < 0)
21685b9c547cSRui Paulo return -1;
21695b9c547cSRui Paulo
21705b9c547cSRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
21715b9c547cSRui Paulo " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
21725b9c547cSRui Paulo
21735b9c547cSRui Paulo return 0;
21745b9c547cSRui Paulo }
21755b9c547cSRui Paulo
21765b9c547cSRui Paulo
hostapd_ctrl_iface_data_test_frame(struct hostapd_data * hapd,char * cmd)21775b9c547cSRui Paulo static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
21785b9c547cSRui Paulo char *cmd)
21795b9c547cSRui Paulo {
21805b9c547cSRui Paulo u8 *buf;
21815b9c547cSRui Paulo struct ether_header *eth;
21825b9c547cSRui Paulo struct l2_packet_data *l2 = NULL;
21835b9c547cSRui Paulo size_t len;
21845b9c547cSRui Paulo u16 ethertype;
21855b9c547cSRui Paulo int res = -1;
21865b9c547cSRui Paulo const char *ifname = hapd->conf->iface;
21875b9c547cSRui Paulo
21885b9c547cSRui Paulo if (os_strncmp(cmd, "ifname=", 7) == 0) {
21895b9c547cSRui Paulo cmd += 7;
21905b9c547cSRui Paulo ifname = cmd;
21915b9c547cSRui Paulo cmd = os_strchr(cmd, ' ');
21925b9c547cSRui Paulo if (cmd == NULL)
21935b9c547cSRui Paulo return -1;
21945b9c547cSRui Paulo *cmd++ = '\0';
21955b9c547cSRui Paulo }
21965b9c547cSRui Paulo
21975b9c547cSRui Paulo len = os_strlen(cmd);
21985b9c547cSRui Paulo if (len & 1 || len < ETH_HLEN * 2)
21995b9c547cSRui Paulo return -1;
22005b9c547cSRui Paulo len /= 2;
22015b9c547cSRui Paulo
22025b9c547cSRui Paulo buf = os_malloc(len);
22035b9c547cSRui Paulo if (buf == NULL)
22045b9c547cSRui Paulo return -1;
22055b9c547cSRui Paulo
22065b9c547cSRui Paulo if (hexstr2bin(cmd, buf, len) < 0)
22075b9c547cSRui Paulo goto done;
22085b9c547cSRui Paulo
22095b9c547cSRui Paulo eth = (struct ether_header *) buf;
22105b9c547cSRui Paulo ethertype = ntohs(eth->ether_type);
22115b9c547cSRui Paulo
22125b9c547cSRui Paulo l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
22135b9c547cSRui Paulo hostapd_data_test_rx, hapd, 1);
22145b9c547cSRui Paulo if (l2 == NULL)
22155b9c547cSRui Paulo goto done;
22165b9c547cSRui Paulo
22175b9c547cSRui Paulo res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
22185b9c547cSRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
22195b9c547cSRui Paulo done:
22205b9c547cSRui Paulo if (l2)
22215b9c547cSRui Paulo l2_packet_deinit(l2);
22225b9c547cSRui Paulo os_free(buf);
22235b9c547cSRui Paulo
22245b9c547cSRui Paulo return res < 0 ? -1 : 0;
22255b9c547cSRui Paulo }
22265b9c547cSRui Paulo
22275b9c547cSRui Paulo
hostapd_ctrl_test_alloc_fail(struct hostapd_data * hapd,char * cmd)22285b9c547cSRui Paulo static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
22295b9c547cSRui Paulo {
22305b9c547cSRui Paulo #ifdef WPA_TRACE_BFD
22315b9c547cSRui Paulo char *pos;
22325b9c547cSRui Paulo
22335b9c547cSRui Paulo wpa_trace_fail_after = atoi(cmd);
22345b9c547cSRui Paulo pos = os_strchr(cmd, ':');
22355b9c547cSRui Paulo if (pos) {
22365b9c547cSRui Paulo pos++;
22375b9c547cSRui Paulo os_strlcpy(wpa_trace_fail_func, pos,
22385b9c547cSRui Paulo sizeof(wpa_trace_fail_func));
22395b9c547cSRui Paulo } else {
22405b9c547cSRui Paulo wpa_trace_fail_after = 0;
22415b9c547cSRui Paulo }
22425b9c547cSRui Paulo
22435b9c547cSRui Paulo return 0;
22445b9c547cSRui Paulo #else /* WPA_TRACE_BFD */
22455b9c547cSRui Paulo return -1;
22465b9c547cSRui Paulo #endif /* WPA_TRACE_BFD */
22475b9c547cSRui Paulo }
22485b9c547cSRui Paulo
22495b9c547cSRui Paulo
hostapd_ctrl_get_alloc_fail(struct hostapd_data * hapd,char * buf,size_t buflen)22505b9c547cSRui Paulo static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
22515b9c547cSRui Paulo char *buf, size_t buflen)
22525b9c547cSRui Paulo {
22535b9c547cSRui Paulo #ifdef WPA_TRACE_BFD
22545b9c547cSRui Paulo return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
22555b9c547cSRui Paulo wpa_trace_fail_func);
22565b9c547cSRui Paulo #else /* WPA_TRACE_BFD */
22575b9c547cSRui Paulo return -1;
22585b9c547cSRui Paulo #endif /* WPA_TRACE_BFD */
22595b9c547cSRui Paulo }
22605b9c547cSRui Paulo
2261325151a3SRui Paulo
hostapd_ctrl_test_fail(struct hostapd_data * hapd,char * cmd)2262325151a3SRui Paulo static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd)
2263325151a3SRui Paulo {
2264325151a3SRui Paulo #ifdef WPA_TRACE_BFD
2265325151a3SRui Paulo char *pos;
2266325151a3SRui Paulo
2267325151a3SRui Paulo wpa_trace_test_fail_after = atoi(cmd);
2268325151a3SRui Paulo pos = os_strchr(cmd, ':');
2269325151a3SRui Paulo if (pos) {
2270325151a3SRui Paulo pos++;
2271325151a3SRui Paulo os_strlcpy(wpa_trace_test_fail_func, pos,
2272325151a3SRui Paulo sizeof(wpa_trace_test_fail_func));
2273325151a3SRui Paulo } else {
2274325151a3SRui Paulo wpa_trace_test_fail_after = 0;
2275325151a3SRui Paulo }
2276325151a3SRui Paulo
2277325151a3SRui Paulo return 0;
2278325151a3SRui Paulo #else /* WPA_TRACE_BFD */
2279325151a3SRui Paulo return -1;
2280325151a3SRui Paulo #endif /* WPA_TRACE_BFD */
2281325151a3SRui Paulo }
2282325151a3SRui Paulo
2283325151a3SRui Paulo
hostapd_ctrl_get_fail(struct hostapd_data * hapd,char * buf,size_t buflen)2284325151a3SRui Paulo static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
2285325151a3SRui Paulo char *buf, size_t buflen)
2286325151a3SRui Paulo {
2287325151a3SRui Paulo #ifdef WPA_TRACE_BFD
2288325151a3SRui Paulo return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
2289325151a3SRui Paulo wpa_trace_test_fail_func);
2290325151a3SRui Paulo #else /* WPA_TRACE_BFD */
2291325151a3SRui Paulo return -1;
2292325151a3SRui Paulo #endif /* WPA_TRACE_BFD */
2293325151a3SRui Paulo }
2294325151a3SRui Paulo
229585732ac8SCy Schubert
hostapd_ctrl_reset_pn(struct hostapd_data * hapd,const char * cmd)229685732ac8SCy Schubert static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
229785732ac8SCy Schubert {
229885732ac8SCy Schubert struct sta_info *sta;
229985732ac8SCy Schubert u8 addr[ETH_ALEN];
230085732ac8SCy Schubert u8 zero[WPA_TK_MAX_LEN];
230185732ac8SCy Schubert
230285732ac8SCy Schubert os_memset(zero, 0, sizeof(zero));
230385732ac8SCy Schubert
230485732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
230585732ac8SCy Schubert return -1;
230685732ac8SCy Schubert
2307c1d255d3SCy Schubert if (is_broadcast_ether_addr(addr) && os_strstr(cmd, " BIGTK")) {
2308c1d255d3SCy Schubert if (hapd->last_bigtk_alg == WPA_ALG_NONE)
2309c1d255d3SCy Schubert return -1;
2310c1d255d3SCy Schubert
2311c1d255d3SCy Schubert wpa_printf(MSG_INFO, "TESTING: Reset BIPN for BIGTK");
2312c1d255d3SCy Schubert
2313c1d255d3SCy Schubert /* First, use a zero key to avoid any possible duplicate key
2314c1d255d3SCy Schubert * avoidance in the driver. */
2315c1d255d3SCy Schubert if (hostapd_drv_set_key(hapd->conf->iface, hapd,
2316c1d255d3SCy Schubert hapd->last_bigtk_alg,
2317c1d255d3SCy Schubert broadcast_ether_addr,
2318c1d255d3SCy Schubert hapd->last_bigtk_key_idx, 0, 1, NULL, 0,
2319c1d255d3SCy Schubert zero, hapd->last_bigtk_len,
2320c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT) < 0)
2321c1d255d3SCy Schubert return -1;
2322c1d255d3SCy Schubert
2323c1d255d3SCy Schubert /* Set the previously configured key to reset its TSC */
2324c1d255d3SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd,
2325c1d255d3SCy Schubert hapd->last_bigtk_alg,
2326c1d255d3SCy Schubert broadcast_ether_addr,
2327c1d255d3SCy Schubert hapd->last_bigtk_key_idx, 0, 1, NULL,
2328c1d255d3SCy Schubert 0, hapd->last_bigtk,
2329c1d255d3SCy Schubert hapd->last_bigtk_len,
2330c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT);
2331c1d255d3SCy Schubert }
2332c1d255d3SCy Schubert
233385732ac8SCy Schubert if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
233485732ac8SCy Schubert if (hapd->last_igtk_alg == WPA_ALG_NONE)
233585732ac8SCy Schubert return -1;
233685732ac8SCy Schubert
233785732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Reset IPN for IGTK");
233885732ac8SCy Schubert
233985732ac8SCy Schubert /* First, use a zero key to avoid any possible duplicate key
234085732ac8SCy Schubert * avoidance in the driver. */
234185732ac8SCy Schubert if (hostapd_drv_set_key(hapd->conf->iface, hapd,
234285732ac8SCy Schubert hapd->last_igtk_alg,
234385732ac8SCy Schubert broadcast_ether_addr,
2344c1d255d3SCy Schubert hapd->last_igtk_key_idx, 0, 1, NULL, 0,
2345c1d255d3SCy Schubert zero, hapd->last_igtk_len,
2346c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT) < 0)
234785732ac8SCy Schubert return -1;
234885732ac8SCy Schubert
234985732ac8SCy Schubert /* Set the previously configured key to reset its TSC */
235085732ac8SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd,
235185732ac8SCy Schubert hapd->last_igtk_alg,
235285732ac8SCy Schubert broadcast_ether_addr,
2353c1d255d3SCy Schubert hapd->last_igtk_key_idx, 0, 1, NULL,
2354c1d255d3SCy Schubert 0, hapd->last_igtk,
2355c1d255d3SCy Schubert hapd->last_igtk_len,
2356c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT);
235785732ac8SCy Schubert }
235885732ac8SCy Schubert
235985732ac8SCy Schubert if (is_broadcast_ether_addr(addr)) {
236085732ac8SCy Schubert if (hapd->last_gtk_alg == WPA_ALG_NONE)
236185732ac8SCy Schubert return -1;
236285732ac8SCy Schubert
236385732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Reset PN for GTK");
236485732ac8SCy Schubert
236585732ac8SCy Schubert /* First, use a zero key to avoid any possible duplicate key
236685732ac8SCy Schubert * avoidance in the driver. */
236785732ac8SCy Schubert if (hostapd_drv_set_key(hapd->conf->iface, hapd,
236885732ac8SCy Schubert hapd->last_gtk_alg,
236985732ac8SCy Schubert broadcast_ether_addr,
2370c1d255d3SCy Schubert hapd->last_gtk_key_idx, 0, 1, NULL, 0,
2371c1d255d3SCy Schubert zero, hapd->last_gtk_len,
2372c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT) < 0)
237385732ac8SCy Schubert return -1;
237485732ac8SCy Schubert
237585732ac8SCy Schubert /* Set the previously configured key to reset its TSC */
237685732ac8SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd,
237785732ac8SCy Schubert hapd->last_gtk_alg,
237885732ac8SCy Schubert broadcast_ether_addr,
2379c1d255d3SCy Schubert hapd->last_gtk_key_idx, 0, 1, NULL,
2380c1d255d3SCy Schubert 0, hapd->last_gtk,
2381c1d255d3SCy Schubert hapd->last_gtk_len,
2382c1d255d3SCy Schubert KEY_FLAG_GROUP_TX_DEFAULT);
238385732ac8SCy Schubert }
238485732ac8SCy Schubert
238585732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
238685732ac8SCy Schubert if (!sta)
238785732ac8SCy Schubert return -1;
238885732ac8SCy Schubert
238985732ac8SCy Schubert if (sta->last_tk_alg == WPA_ALG_NONE)
239085732ac8SCy Schubert return -1;
239185732ac8SCy Schubert
239285732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Reset PN for " MACSTR,
239385732ac8SCy Schubert MAC2STR(sta->addr));
239485732ac8SCy Schubert
239585732ac8SCy Schubert /* First, use a zero key to avoid any possible duplicate key avoidance
239685732ac8SCy Schubert * in the driver. */
239785732ac8SCy Schubert if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
2398c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
2399c1d255d3SCy Schubert zero, sta->last_tk_len,
2400c1d255d3SCy Schubert KEY_FLAG_PAIRWISE_RX_TX) < 0)
240185732ac8SCy Schubert return -1;
240285732ac8SCy Schubert
240385732ac8SCy Schubert /* Set the previously configured key to reset its TSC/RSC */
240485732ac8SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
2405c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 1, NULL,
2406c1d255d3SCy Schubert 0, sta->last_tk, sta->last_tk_len,
2407c1d255d3SCy Schubert KEY_FLAG_PAIRWISE_RX_TX);
240885732ac8SCy Schubert }
240985732ac8SCy Schubert
241085732ac8SCy Schubert
hostapd_ctrl_set_key(struct hostapd_data * hapd,const char * cmd)241185732ac8SCy Schubert static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
241285732ac8SCy Schubert {
241385732ac8SCy Schubert u8 addr[ETH_ALEN];
241485732ac8SCy Schubert const char *pos = cmd;
241585732ac8SCy Schubert enum wpa_alg alg;
2416c1d255d3SCy Schubert enum key_flag key_flag;
241785732ac8SCy Schubert int idx, set_tx;
241885732ac8SCy Schubert u8 seq[6], key[WPA_TK_MAX_LEN];
241985732ac8SCy Schubert size_t key_len;
242085732ac8SCy Schubert
2421c1d255d3SCy Schubert /* parameters: alg addr idx set_tx seq key key_flag */
242285732ac8SCy Schubert
242385732ac8SCy Schubert alg = atoi(pos);
242485732ac8SCy Schubert pos = os_strchr(pos, ' ');
242585732ac8SCy Schubert if (!pos)
242685732ac8SCy Schubert return -1;
242785732ac8SCy Schubert pos++;
242885732ac8SCy Schubert if (hwaddr_aton(pos, addr))
242985732ac8SCy Schubert return -1;
243085732ac8SCy Schubert pos += 17;
243185732ac8SCy Schubert if (*pos != ' ')
243285732ac8SCy Schubert return -1;
243385732ac8SCy Schubert pos++;
243485732ac8SCy Schubert idx = atoi(pos);
243585732ac8SCy Schubert pos = os_strchr(pos, ' ');
243685732ac8SCy Schubert if (!pos)
243785732ac8SCy Schubert return -1;
243885732ac8SCy Schubert pos++;
243985732ac8SCy Schubert set_tx = atoi(pos);
244085732ac8SCy Schubert pos = os_strchr(pos, ' ');
244185732ac8SCy Schubert if (!pos)
244285732ac8SCy Schubert return -1;
244385732ac8SCy Schubert pos++;
244485732ac8SCy Schubert if (hexstr2bin(pos, seq, sizeof(seq)) < 0)
244585732ac8SCy Schubert return -1;
244685732ac8SCy Schubert pos += 2 * 6;
244785732ac8SCy Schubert if (*pos != ' ')
244885732ac8SCy Schubert return -1;
244985732ac8SCy Schubert pos++;
2450c1d255d3SCy Schubert if (!os_strchr(pos, ' '))
2451c1d255d3SCy Schubert return -1;
2452c1d255d3SCy Schubert key_len = (os_strchr(pos, ' ') - pos) / 2;
245385732ac8SCy Schubert if (hexstr2bin(pos, key, key_len) < 0)
245485732ac8SCy Schubert return -1;
2455c1d255d3SCy Schubert pos += 2 * key_len;
2456c1d255d3SCy Schubert if (*pos != ' ')
2457c1d255d3SCy Schubert return -1;
2458c1d255d3SCy Schubert
2459c1d255d3SCy Schubert pos++;
2460c1d255d3SCy Schubert key_flag = atoi(pos);
2461c1d255d3SCy Schubert pos = os_strchr(pos, ' ');
2462c1d255d3SCy Schubert if (pos)
2463c1d255d3SCy Schubert return -1;
246485732ac8SCy Schubert
246585732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Set key");
2466c1d255d3SCy Schubert return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx, 0,
2467c1d255d3SCy Schubert set_tx, seq, 6, key, key_len, key_flag);
246885732ac8SCy Schubert }
246985732ac8SCy Schubert
247085732ac8SCy Schubert
restore_tk(void * ctx1,void * ctx2)247185732ac8SCy Schubert static void restore_tk(void *ctx1, void *ctx2)
247285732ac8SCy Schubert {
247385732ac8SCy Schubert struct hostapd_data *hapd = ctx1;
247485732ac8SCy Schubert struct sta_info *sta = ctx2;
247585732ac8SCy Schubert
247685732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Restore TK for " MACSTR,
247785732ac8SCy Schubert MAC2STR(sta->addr));
247885732ac8SCy Schubert /* This does not really restore the TSC properly, so this will result
247985732ac8SCy Schubert * in replay protection issues for now since there is no clean way of
248085732ac8SCy Schubert * preventing encryption of a single EAPOL frame. */
248185732ac8SCy Schubert hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
2482c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
2483c1d255d3SCy Schubert sta->last_tk, sta->last_tk_len,
2484c1d255d3SCy Schubert KEY_FLAG_PAIRWISE_RX_TX);
248585732ac8SCy Schubert }
248685732ac8SCy Schubert
248785732ac8SCy Schubert
hostapd_ctrl_resend_m1(struct hostapd_data * hapd,const char * cmd)248885732ac8SCy Schubert static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
248985732ac8SCy Schubert {
249085732ac8SCy Schubert struct sta_info *sta;
249185732ac8SCy Schubert u8 addr[ETH_ALEN];
249285732ac8SCy Schubert int plain = os_strstr(cmd, "plaintext") != NULL;
249385732ac8SCy Schubert
249485732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
249585732ac8SCy Schubert return -1;
249685732ac8SCy Schubert
249785732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
249885732ac8SCy Schubert if (!sta || !sta->wpa_sm)
249985732ac8SCy Schubert return -1;
250085732ac8SCy Schubert
250185732ac8SCy Schubert if (plain && sta->last_tk_alg == WPA_ALG_NONE)
250285732ac8SCy Schubert plain = 0; /* no need for special processing */
250385732ac8SCy Schubert if (plain) {
250485732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
250585732ac8SCy Schubert MAC2STR(sta->addr));
250685732ac8SCy Schubert hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
2507c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
2508c1d255d3SCy Schubert 0, NULL, 0, KEY_FLAG_PAIRWISE);
250985732ac8SCy Schubert }
251085732ac8SCy Schubert
251185732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
251285732ac8SCy Schubert return wpa_auth_resend_m1(sta->wpa_sm,
251385732ac8SCy Schubert os_strstr(cmd, "change-anonce") != NULL,
251485732ac8SCy Schubert plain ? restore_tk : NULL, hapd, sta);
251585732ac8SCy Schubert }
251685732ac8SCy Schubert
251785732ac8SCy Schubert
hostapd_ctrl_resend_m3(struct hostapd_data * hapd,const char * cmd)251885732ac8SCy Schubert static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
251985732ac8SCy Schubert {
252085732ac8SCy Schubert struct sta_info *sta;
252185732ac8SCy Schubert u8 addr[ETH_ALEN];
252285732ac8SCy Schubert int plain = os_strstr(cmd, "plaintext") != NULL;
252385732ac8SCy Schubert
252485732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
252585732ac8SCy Schubert return -1;
252685732ac8SCy Schubert
252785732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
252885732ac8SCy Schubert if (!sta || !sta->wpa_sm)
252985732ac8SCy Schubert return -1;
253085732ac8SCy Schubert
253185732ac8SCy Schubert if (plain && sta->last_tk_alg == WPA_ALG_NONE)
253285732ac8SCy Schubert plain = 0; /* no need for special processing */
253385732ac8SCy Schubert if (plain) {
253485732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
253585732ac8SCy Schubert MAC2STR(sta->addr));
253685732ac8SCy Schubert hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
2537c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
2538c1d255d3SCy Schubert 0, NULL, 0, KEY_FLAG_PAIRWISE);
253985732ac8SCy Schubert }
254085732ac8SCy Schubert
254185732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
254285732ac8SCy Schubert return wpa_auth_resend_m3(sta->wpa_sm,
254385732ac8SCy Schubert plain ? restore_tk : NULL, hapd, sta);
254485732ac8SCy Schubert }
254585732ac8SCy Schubert
254685732ac8SCy Schubert
hostapd_ctrl_resend_group_m1(struct hostapd_data * hapd,const char * cmd)254785732ac8SCy Schubert static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
254885732ac8SCy Schubert const char *cmd)
254985732ac8SCy Schubert {
255085732ac8SCy Schubert struct sta_info *sta;
255185732ac8SCy Schubert u8 addr[ETH_ALEN];
255285732ac8SCy Schubert int plain = os_strstr(cmd, "plaintext") != NULL;
255385732ac8SCy Schubert
255485732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
255585732ac8SCy Schubert return -1;
255685732ac8SCy Schubert
255785732ac8SCy Schubert sta = ap_get_sta(hapd, addr);
255885732ac8SCy Schubert if (!sta || !sta->wpa_sm)
255985732ac8SCy Schubert return -1;
256085732ac8SCy Schubert
256185732ac8SCy Schubert if (plain && sta->last_tk_alg == WPA_ALG_NONE)
256285732ac8SCy Schubert plain = 0; /* no need for special processing */
256385732ac8SCy Schubert if (plain) {
256485732ac8SCy Schubert wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
256585732ac8SCy Schubert MAC2STR(sta->addr));
256685732ac8SCy Schubert hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
2567c1d255d3SCy Schubert sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
2568c1d255d3SCy Schubert 0, NULL, 0, KEY_FLAG_PAIRWISE);
256985732ac8SCy Schubert }
257085732ac8SCy Schubert
257185732ac8SCy Schubert wpa_printf(MSG_INFO,
257285732ac8SCy Schubert "TESTING: Send group M1 for the same GTK and zero RSC to "
257385732ac8SCy Schubert MACSTR, MAC2STR(sta->addr));
257485732ac8SCy Schubert return wpa_auth_resend_group_m1(sta->wpa_sm,
257585732ac8SCy Schubert plain ? restore_tk : NULL, hapd, sta);
257685732ac8SCy Schubert }
257785732ac8SCy Schubert
2578c1d255d3SCy Schubert
hostapd_ctrl_rekey_ptk(struct hostapd_data * hapd,const char * cmd)2579c1d255d3SCy Schubert static int hostapd_ctrl_rekey_ptk(struct hostapd_data *hapd, const char *cmd)
2580c1d255d3SCy Schubert {
2581c1d255d3SCy Schubert struct sta_info *sta;
2582c1d255d3SCy Schubert u8 addr[ETH_ALEN];
2583c1d255d3SCy Schubert
2584c1d255d3SCy Schubert if (hwaddr_aton(cmd, addr))
2585c1d255d3SCy Schubert return -1;
2586c1d255d3SCy Schubert
2587c1d255d3SCy Schubert sta = ap_get_sta(hapd, addr);
2588c1d255d3SCy Schubert if (!sta || !sta->wpa_sm)
2589c1d255d3SCy Schubert return -1;
2590c1d255d3SCy Schubert
2591c1d255d3SCy Schubert return wpa_auth_rekey_ptk(hapd->wpa_auth, sta->wpa_sm);
2592c1d255d3SCy Schubert }
2593c1d255d3SCy Schubert
2594c1d255d3SCy Schubert
hostapd_ctrl_get_pmksa_pmk(struct hostapd_data * hapd,const u8 * addr,char * buf,size_t buflen)2595c1d255d3SCy Schubert static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr,
2596c1d255d3SCy Schubert char *buf, size_t buflen)
2597c1d255d3SCy Schubert {
2598c1d255d3SCy Schubert struct rsn_pmksa_cache_entry *pmksa;
2599c1d255d3SCy Schubert
2600c1d255d3SCy Schubert pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, addr, NULL);
2601c1d255d3SCy Schubert if (!pmksa)
2602c1d255d3SCy Schubert return -1;
2603c1d255d3SCy Schubert
2604c1d255d3SCy Schubert return wpa_snprintf_hex(buf, buflen, pmksa->pmk, pmksa->pmk_len);
2605c1d255d3SCy Schubert }
2606c1d255d3SCy Schubert
2607c1d255d3SCy Schubert
hostapd_ctrl_get_pmk(struct hostapd_data * hapd,const char * cmd,char * buf,size_t buflen)2608c1d255d3SCy Schubert static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
2609c1d255d3SCy Schubert char *buf, size_t buflen)
2610c1d255d3SCy Schubert {
2611c1d255d3SCy Schubert struct sta_info *sta;
2612c1d255d3SCy Schubert u8 addr[ETH_ALEN];
2613c1d255d3SCy Schubert const u8 *pmk;
2614c1d255d3SCy Schubert int pmk_len;
2615c1d255d3SCy Schubert
2616c1d255d3SCy Schubert if (hwaddr_aton(cmd, addr))
2617c1d255d3SCy Schubert return -1;
2618c1d255d3SCy Schubert
2619c1d255d3SCy Schubert sta = ap_get_sta(hapd, addr);
2620c1d255d3SCy Schubert if (!sta || !sta->wpa_sm) {
2621c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
2622c1d255d3SCy Schubert MAC2STR(addr));
2623c1d255d3SCy Schubert return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
2624c1d255d3SCy Schubert }
2625c1d255d3SCy Schubert pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
2626c1d255d3SCy Schubert if (!pmk || !pmk_len) {
2627c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
2628c1d255d3SCy Schubert MAC2STR(addr));
2629c1d255d3SCy Schubert return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
2630c1d255d3SCy Schubert }
2631c1d255d3SCy Schubert
2632c1d255d3SCy Schubert return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
2633c1d255d3SCy Schubert }
2634c1d255d3SCy Schubert
2635c1d255d3SCy Schubert
hostapd_ctrl_register_frame(struct hostapd_data * hapd,const char * cmd)2636c1d255d3SCy Schubert static int hostapd_ctrl_register_frame(struct hostapd_data *hapd,
2637c1d255d3SCy Schubert const char *cmd)
2638c1d255d3SCy Schubert {
2639c1d255d3SCy Schubert u16 type;
2640c1d255d3SCy Schubert char *pos, *end;
2641c1d255d3SCy Schubert u8 match[10];
2642c1d255d3SCy Schubert size_t match_len;
2643c1d255d3SCy Schubert bool multicast = false;
2644c1d255d3SCy Schubert
2645c1d255d3SCy Schubert type = strtol(cmd, &pos, 16);
2646c1d255d3SCy Schubert if (*pos != ' ')
2647c1d255d3SCy Schubert return -1;
2648c1d255d3SCy Schubert pos++;
2649c1d255d3SCy Schubert end = os_strchr(pos, ' ');
2650c1d255d3SCy Schubert if (end) {
2651c1d255d3SCy Schubert match_len = end - pos;
2652c1d255d3SCy Schubert multicast = os_strstr(end, "multicast") != NULL;
2653c1d255d3SCy Schubert } else {
2654c1d255d3SCy Schubert match_len = os_strlen(pos) / 2;
2655c1d255d3SCy Schubert }
2656c1d255d3SCy Schubert if (hexstr2bin(pos, match, match_len))
2657c1d255d3SCy Schubert return -1;
2658c1d255d3SCy Schubert
2659c1d255d3SCy Schubert return hostapd_drv_register_frame(hapd, type, match, match_len,
2660c1d255d3SCy Schubert multicast);
2661c1d255d3SCy Schubert }
2662c1d255d3SCy Schubert
26635b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
26645b9c547cSRui Paulo
26655b9c547cSRui Paulo
2666c1d255d3SCy Schubert #ifdef NEED_AP_MLME
hostapd_ctrl_check_freq_params(struct hostapd_freq_params * params)2667c1d255d3SCy Schubert static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params)
2668c1d255d3SCy Schubert {
2669c1d255d3SCy Schubert switch (params->bandwidth) {
2670c1d255d3SCy Schubert case 0:
2671c1d255d3SCy Schubert /* bandwidth not specified: use 20 MHz by default */
2672c1d255d3SCy Schubert /* fall-through */
2673c1d255d3SCy Schubert case 20:
2674c1d255d3SCy Schubert if (params->center_freq1 &&
2675c1d255d3SCy Schubert params->center_freq1 != params->freq)
2676c1d255d3SCy Schubert return -1;
2677c1d255d3SCy Schubert
2678c1d255d3SCy Schubert if (params->center_freq2 || params->sec_channel_offset)
2679c1d255d3SCy Schubert return -1;
2680c1d255d3SCy Schubert break;
2681c1d255d3SCy Schubert case 40:
2682c1d255d3SCy Schubert if (params->center_freq2 || !params->sec_channel_offset)
2683c1d255d3SCy Schubert return -1;
2684c1d255d3SCy Schubert
2685c1d255d3SCy Schubert if (!params->center_freq1)
2686c1d255d3SCy Schubert break;
2687c1d255d3SCy Schubert switch (params->sec_channel_offset) {
2688c1d255d3SCy Schubert case 1:
2689c1d255d3SCy Schubert if (params->freq + 10 != params->center_freq1)
2690c1d255d3SCy Schubert return -1;
2691c1d255d3SCy Schubert break;
2692c1d255d3SCy Schubert case -1:
2693c1d255d3SCy Schubert if (params->freq - 10 != params->center_freq1)
2694c1d255d3SCy Schubert return -1;
2695c1d255d3SCy Schubert break;
2696c1d255d3SCy Schubert default:
2697c1d255d3SCy Schubert return -1;
2698c1d255d3SCy Schubert }
2699c1d255d3SCy Schubert break;
2700c1d255d3SCy Schubert case 80:
2701c1d255d3SCy Schubert if (!params->center_freq1 || !params->sec_channel_offset)
2702c1d255d3SCy Schubert return 1;
2703c1d255d3SCy Schubert
2704c1d255d3SCy Schubert switch (params->sec_channel_offset) {
2705c1d255d3SCy Schubert case 1:
2706c1d255d3SCy Schubert if (params->freq - 10 != params->center_freq1 &&
2707c1d255d3SCy Schubert params->freq + 30 != params->center_freq1)
2708c1d255d3SCy Schubert return 1;
2709c1d255d3SCy Schubert break;
2710c1d255d3SCy Schubert case -1:
2711c1d255d3SCy Schubert if (params->freq + 10 != params->center_freq1 &&
2712c1d255d3SCy Schubert params->freq - 30 != params->center_freq1)
2713c1d255d3SCy Schubert return -1;
2714c1d255d3SCy Schubert break;
2715c1d255d3SCy Schubert default:
2716c1d255d3SCy Schubert return -1;
2717c1d255d3SCy Schubert }
2718c1d255d3SCy Schubert
2719c1d255d3SCy Schubert /* Adjacent and overlapped are not allowed for 80+80 */
2720c1d255d3SCy Schubert if (params->center_freq2 &&
2721c1d255d3SCy Schubert params->center_freq1 - params->center_freq2 <= 80 &&
2722c1d255d3SCy Schubert params->center_freq2 - params->center_freq1 <= 80)
2723c1d255d3SCy Schubert return 1;
2724c1d255d3SCy Schubert break;
2725c1d255d3SCy Schubert case 160:
2726c1d255d3SCy Schubert if (!params->center_freq1 || params->center_freq2 ||
2727c1d255d3SCy Schubert !params->sec_channel_offset)
2728c1d255d3SCy Schubert return -1;
2729c1d255d3SCy Schubert
2730c1d255d3SCy Schubert switch (params->sec_channel_offset) {
2731c1d255d3SCy Schubert case 1:
2732c1d255d3SCy Schubert if (params->freq + 70 != params->center_freq1 &&
2733c1d255d3SCy Schubert params->freq + 30 != params->center_freq1 &&
2734c1d255d3SCy Schubert params->freq - 10 != params->center_freq1 &&
2735c1d255d3SCy Schubert params->freq - 50 != params->center_freq1)
2736c1d255d3SCy Schubert return -1;
2737c1d255d3SCy Schubert break;
2738c1d255d3SCy Schubert case -1:
2739c1d255d3SCy Schubert if (params->freq + 50 != params->center_freq1 &&
2740c1d255d3SCy Schubert params->freq + 10 != params->center_freq1 &&
2741c1d255d3SCy Schubert params->freq - 30 != params->center_freq1 &&
2742c1d255d3SCy Schubert params->freq - 70 != params->center_freq1)
2743c1d255d3SCy Schubert return -1;
2744c1d255d3SCy Schubert break;
2745c1d255d3SCy Schubert default:
2746c1d255d3SCy Schubert return -1;
2747c1d255d3SCy Schubert }
2748c1d255d3SCy Schubert break;
2749c1d255d3SCy Schubert default:
2750c1d255d3SCy Schubert return -1;
2751c1d255d3SCy Schubert }
2752c1d255d3SCy Schubert
2753c1d255d3SCy Schubert return 0;
2754c1d255d3SCy Schubert }
2755c1d255d3SCy Schubert #endif /* NEED_AP_MLME */
2756c1d255d3SCy Schubert
2757c1d255d3SCy Schubert
hostapd_ctrl_iface_chan_switch(struct hostapd_iface * iface,char * pos)27585b9c547cSRui Paulo static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
27595b9c547cSRui Paulo char *pos)
27605b9c547cSRui Paulo {
27615b9c547cSRui Paulo #ifdef NEED_AP_MLME
27625b9c547cSRui Paulo struct csa_settings settings;
27635b9c547cSRui Paulo int ret;
2764c1d255d3SCy Schubert int dfs_range = 0;
27655b9c547cSRui Paulo unsigned int i;
2766c1d255d3SCy Schubert int bandwidth;
2767c1d255d3SCy Schubert u8 chan;
27685b9c547cSRui Paulo
27695b9c547cSRui Paulo ret = hostapd_parse_csa_settings(pos, &settings);
27705b9c547cSRui Paulo if (ret)
27715b9c547cSRui Paulo return ret;
27725b9c547cSRui Paulo
2773c1d255d3SCy Schubert ret = hostapd_ctrl_check_freq_params(&settings.freq_params);
2774c1d255d3SCy Schubert if (ret) {
2775c1d255d3SCy Schubert wpa_printf(MSG_INFO,
2776c1d255d3SCy Schubert "chanswitch: invalid frequency settings provided");
2777c1d255d3SCy Schubert return ret;
2778c1d255d3SCy Schubert }
2779c1d255d3SCy Schubert
2780c1d255d3SCy Schubert switch (settings.freq_params.bandwidth) {
2781c1d255d3SCy Schubert case 40:
2782c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_40;
2783c1d255d3SCy Schubert break;
2784c1d255d3SCy Schubert case 80:
2785c1d255d3SCy Schubert if (settings.freq_params.center_freq2)
2786c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_80P80;
2787c1d255d3SCy Schubert else
2788c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_80;
2789c1d255d3SCy Schubert break;
2790c1d255d3SCy Schubert case 160:
2791c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_160;
2792c1d255d3SCy Schubert break;
2793c1d255d3SCy Schubert default:
2794c1d255d3SCy Schubert bandwidth = CHAN_WIDTH_20;
2795c1d255d3SCy Schubert break;
2796c1d255d3SCy Schubert }
2797c1d255d3SCy Schubert
2798c1d255d3SCy Schubert if (settings.freq_params.center_freq1)
2799c1d255d3SCy Schubert dfs_range += hostapd_is_dfs_overlap(
2800c1d255d3SCy Schubert iface, bandwidth, settings.freq_params.center_freq1);
2801c1d255d3SCy Schubert else
2802c1d255d3SCy Schubert dfs_range += hostapd_is_dfs_overlap(
2803c1d255d3SCy Schubert iface, bandwidth, settings.freq_params.freq);
2804c1d255d3SCy Schubert
2805c1d255d3SCy Schubert if (settings.freq_params.center_freq2)
2806c1d255d3SCy Schubert dfs_range += hostapd_is_dfs_overlap(
2807c1d255d3SCy Schubert iface, bandwidth, settings.freq_params.center_freq2);
2808c1d255d3SCy Schubert
2809c1d255d3SCy Schubert if (dfs_range) {
2810c1d255d3SCy Schubert ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
2811c1d255d3SCy Schubert if (ret == NUM_HOSTAPD_MODES) {
2812c1d255d3SCy Schubert wpa_printf(MSG_ERROR,
2813c1d255d3SCy Schubert "Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
2814c1d255d3SCy Schubert settings.freq_params.freq,
2815c1d255d3SCy Schubert settings.freq_params.sec_channel_offset,
2816c1d255d3SCy Schubert settings.freq_params.bandwidth);
2817c1d255d3SCy Schubert return -1;
2818c1d255d3SCy Schubert }
2819c1d255d3SCy Schubert
2820c1d255d3SCy Schubert settings.freq_params.channel = chan;
2821c1d255d3SCy Schubert
2822c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
2823c1d255d3SCy Schubert "DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
2824c1d255d3SCy Schubert settings.freq_params.channel,
2825c1d255d3SCy Schubert settings.freq_params.freq,
2826c1d255d3SCy Schubert settings.freq_params.sec_channel_offset,
2827c1d255d3SCy Schubert settings.freq_params.bandwidth,
2828c1d255d3SCy Schubert settings.freq_params.center_freq1);
2829c1d255d3SCy Schubert
2830c1d255d3SCy Schubert /* Perform CAC and switch channel */
2831c1d255d3SCy Schubert hostapd_switch_channel_fallback(iface, &settings.freq_params);
2832c1d255d3SCy Schubert return 0;
2833c1d255d3SCy Schubert }
2834c1d255d3SCy Schubert
28355b9c547cSRui Paulo for (i = 0; i < iface->num_bss; i++) {
283685732ac8SCy Schubert
2837c1d255d3SCy Schubert /* Save CHAN_SWITCH VHT and HE config */
2838c1d255d3SCy Schubert hostapd_chan_switch_config(iface->bss[i],
2839c1d255d3SCy Schubert &settings.freq_params);
284085732ac8SCy Schubert
28415b9c547cSRui Paulo ret = hostapd_switch_channel(iface->bss[i], &settings);
28425b9c547cSRui Paulo if (ret) {
28435b9c547cSRui Paulo /* FIX: What do we do if CSA fails in the middle of
28445b9c547cSRui Paulo * submitting multi-BSS CSA requests? */
28455b9c547cSRui Paulo return ret;
28465b9c547cSRui Paulo }
28475b9c547cSRui Paulo }
28485b9c547cSRui Paulo
28495b9c547cSRui Paulo return 0;
28505b9c547cSRui Paulo #else /* NEED_AP_MLME */
28515b9c547cSRui Paulo return -1;
28525b9c547cSRui Paulo #endif /* NEED_AP_MLME */
28535b9c547cSRui Paulo }
28545b9c547cSRui Paulo
28555b9c547cSRui Paulo
hostapd_ctrl_iface_mib(struct hostapd_data * hapd,char * reply,int reply_size,const char * param)28565b9c547cSRui Paulo static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
28575b9c547cSRui Paulo int reply_size, const char *param)
28585b9c547cSRui Paulo {
28595b9c547cSRui Paulo #ifdef RADIUS_SERVER
28605b9c547cSRui Paulo if (os_strcmp(param, "radius_server") == 0) {
28615b9c547cSRui Paulo return radius_server_get_mib(hapd->radius_srv, reply,
28625b9c547cSRui Paulo reply_size);
28635b9c547cSRui Paulo }
28645b9c547cSRui Paulo #endif /* RADIUS_SERVER */
28655b9c547cSRui Paulo return -1;
28665b9c547cSRui Paulo }
28675b9c547cSRui Paulo
28685b9c547cSRui Paulo
hostapd_ctrl_iface_vendor(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)28695b9c547cSRui Paulo static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
28705b9c547cSRui Paulo char *buf, size_t buflen)
28715b9c547cSRui Paulo {
28725b9c547cSRui Paulo int ret;
2873c1d255d3SCy Schubert char *pos, *temp = NULL;
28745b9c547cSRui Paulo u8 *data = NULL;
28755b9c547cSRui Paulo unsigned int vendor_id, subcmd;
2876c1d255d3SCy Schubert enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
28775b9c547cSRui Paulo struct wpabuf *reply;
28785b9c547cSRui Paulo size_t data_len = 0;
28795b9c547cSRui Paulo
2880c1d255d3SCy Schubert /**
2881c1d255d3SCy Schubert * cmd: <vendor id> <subcommand id> [<hex formatted data>]
2882c1d255d3SCy Schubert * [nested=<0|1>]
2883c1d255d3SCy Schubert */
28845b9c547cSRui Paulo vendor_id = strtoul(cmd, &pos, 16);
2885780fb4a2SCy Schubert if (!isblank((unsigned char) *pos))
28865b9c547cSRui Paulo return -EINVAL;
28875b9c547cSRui Paulo
28885b9c547cSRui Paulo subcmd = strtoul(pos, &pos, 10);
28895b9c547cSRui Paulo
28905b9c547cSRui Paulo if (*pos != '\0') {
2891780fb4a2SCy Schubert if (!isblank((unsigned char) *pos++))
28925b9c547cSRui Paulo return -EINVAL;
2893c1d255d3SCy Schubert
2894c1d255d3SCy Schubert temp = os_strchr(pos, ' ');
2895c1d255d3SCy Schubert data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
28965b9c547cSRui Paulo }
28975b9c547cSRui Paulo
28985b9c547cSRui Paulo if (data_len) {
28995b9c547cSRui Paulo data_len /= 2;
29005b9c547cSRui Paulo data = os_malloc(data_len);
29015b9c547cSRui Paulo if (!data)
29025b9c547cSRui Paulo return -ENOBUFS;
29035b9c547cSRui Paulo
29045b9c547cSRui Paulo if (hexstr2bin(pos, data, data_len)) {
29055b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
29065b9c547cSRui Paulo "Vendor command: wrong parameter format");
29075b9c547cSRui Paulo os_free(data);
29085b9c547cSRui Paulo return -EINVAL;
29095b9c547cSRui Paulo }
29105b9c547cSRui Paulo }
29115b9c547cSRui Paulo
2912c1d255d3SCy Schubert pos = os_strstr(cmd, "nested=");
2913c1d255d3SCy Schubert if (pos)
2914c1d255d3SCy Schubert nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED :
2915c1d255d3SCy Schubert NESTED_ATTR_NOT_USED;
2916c1d255d3SCy Schubert
29175b9c547cSRui Paulo reply = wpabuf_alloc((buflen - 1) / 2);
29185b9c547cSRui Paulo if (!reply) {
29195b9c547cSRui Paulo os_free(data);
29205b9c547cSRui Paulo return -ENOBUFS;
29215b9c547cSRui Paulo }
29225b9c547cSRui Paulo
29235b9c547cSRui Paulo ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
2924c1d255d3SCy Schubert nested_attr_flag, reply);
29255b9c547cSRui Paulo
29265b9c547cSRui Paulo if (ret == 0)
29275b9c547cSRui Paulo ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
29285b9c547cSRui Paulo wpabuf_len(reply));
29295b9c547cSRui Paulo
29305b9c547cSRui Paulo wpabuf_free(reply);
29315b9c547cSRui Paulo os_free(data);
29325b9c547cSRui Paulo
29335b9c547cSRui Paulo return ret;
29345b9c547cSRui Paulo }
29355b9c547cSRui Paulo
29365b9c547cSRui Paulo
hostapd_ctrl_iface_eapol_reauth(struct hostapd_data * hapd,const char * cmd)2937325151a3SRui Paulo static int hostapd_ctrl_iface_eapol_reauth(struct hostapd_data *hapd,
2938325151a3SRui Paulo const char *cmd)
293939beb93cSSam Leffler {
2940325151a3SRui Paulo u8 addr[ETH_ALEN];
2941325151a3SRui Paulo struct sta_info *sta;
294239beb93cSSam Leffler
2943325151a3SRui Paulo if (hwaddr_aton(cmd, addr))
2944325151a3SRui Paulo return -1;
294539beb93cSSam Leffler
2946325151a3SRui Paulo sta = ap_get_sta(hapd, addr);
2947325151a3SRui Paulo if (!sta || !sta->eapol_sm)
2948325151a3SRui Paulo return -1;
2949325151a3SRui Paulo
2950325151a3SRui Paulo eapol_auth_reauthenticate(sta->eapol_sm);
2951325151a3SRui Paulo return 0;
29525b9c547cSRui Paulo }
2953325151a3SRui Paulo
2954325151a3SRui Paulo
hostapd_ctrl_iface_eapol_set(struct hostapd_data * hapd,char * cmd)2955325151a3SRui Paulo static int hostapd_ctrl_iface_eapol_set(struct hostapd_data *hapd, char *cmd)
2956325151a3SRui Paulo {
2957325151a3SRui Paulo u8 addr[ETH_ALEN];
2958325151a3SRui Paulo struct sta_info *sta;
2959325151a3SRui Paulo char *pos = cmd, *param;
2960325151a3SRui Paulo
2961325151a3SRui Paulo if (hwaddr_aton(pos, addr) || pos[17] != ' ')
2962325151a3SRui Paulo return -1;
2963325151a3SRui Paulo pos += 18;
2964325151a3SRui Paulo param = pos;
2965325151a3SRui Paulo pos = os_strchr(pos, ' ');
2966325151a3SRui Paulo if (!pos)
2967325151a3SRui Paulo return -1;
2968325151a3SRui Paulo *pos++ = '\0';
2969325151a3SRui Paulo
2970325151a3SRui Paulo sta = ap_get_sta(hapd, addr);
2971325151a3SRui Paulo if (!sta || !sta->eapol_sm)
2972325151a3SRui Paulo return -1;
2973325151a3SRui Paulo
2974325151a3SRui Paulo return eapol_auth_set_conf(sta->eapol_sm, param, pos);
297539beb93cSSam Leffler }
297639beb93cSSam Leffler
2977325151a3SRui Paulo
hostapd_ctrl_iface_log_level(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)2978325151a3SRui Paulo static int hostapd_ctrl_iface_log_level(struct hostapd_data *hapd, char *cmd,
2979325151a3SRui Paulo char *buf, size_t buflen)
2980325151a3SRui Paulo {
2981325151a3SRui Paulo char *pos, *end, *stamp;
2982325151a3SRui Paulo int ret;
2983325151a3SRui Paulo
2984325151a3SRui Paulo /* cmd: "LOG_LEVEL [<level>]" */
2985325151a3SRui Paulo if (*cmd == '\0') {
2986325151a3SRui Paulo pos = buf;
2987325151a3SRui Paulo end = buf + buflen;
2988325151a3SRui Paulo ret = os_snprintf(pos, end - pos, "Current level: %s\n"
2989325151a3SRui Paulo "Timestamp: %d\n",
2990325151a3SRui Paulo debug_level_str(wpa_debug_level),
2991325151a3SRui Paulo wpa_debug_timestamp);
2992325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
2993325151a3SRui Paulo ret = 0;
2994325151a3SRui Paulo
2995325151a3SRui Paulo return ret;
2996325151a3SRui Paulo }
2997325151a3SRui Paulo
2998325151a3SRui Paulo while (*cmd == ' ')
2999325151a3SRui Paulo cmd++;
3000325151a3SRui Paulo
3001325151a3SRui Paulo stamp = os_strchr(cmd, ' ');
3002325151a3SRui Paulo if (stamp) {
3003325151a3SRui Paulo *stamp++ = '\0';
3004325151a3SRui Paulo while (*stamp == ' ') {
3005325151a3SRui Paulo stamp++;
3006325151a3SRui Paulo }
3007325151a3SRui Paulo }
3008325151a3SRui Paulo
3009325151a3SRui Paulo if (os_strlen(cmd)) {
3010325151a3SRui Paulo int level = str_to_debug_level(cmd);
3011325151a3SRui Paulo if (level < 0)
3012325151a3SRui Paulo return -1;
3013325151a3SRui Paulo wpa_debug_level = level;
3014325151a3SRui Paulo }
3015325151a3SRui Paulo
3016325151a3SRui Paulo if (stamp && os_strlen(stamp))
3017325151a3SRui Paulo wpa_debug_timestamp = atoi(stamp);
3018325151a3SRui Paulo
3019325151a3SRui Paulo os_memcpy(buf, "OK\n", 3);
3020325151a3SRui Paulo return 3;
3021325151a3SRui Paulo }
3022325151a3SRui Paulo
3023325151a3SRui Paulo
3024325151a3SRui Paulo #ifdef NEED_AP_MLME
hostapd_ctrl_iface_track_sta_list(struct hostapd_data * hapd,char * buf,size_t buflen)3025325151a3SRui Paulo static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
3026325151a3SRui Paulo char *buf, size_t buflen)
3027325151a3SRui Paulo {
3028325151a3SRui Paulo struct hostapd_iface *iface = hapd->iface;
3029325151a3SRui Paulo char *pos, *end;
3030325151a3SRui Paulo struct hostapd_sta_info *info;
3031325151a3SRui Paulo struct os_reltime now;
3032325151a3SRui Paulo
3033780fb4a2SCy Schubert if (!iface->num_sta_seen)
3034780fb4a2SCy Schubert return 0;
3035780fb4a2SCy Schubert
3036325151a3SRui Paulo sta_track_expire(iface, 0);
3037325151a3SRui Paulo
3038325151a3SRui Paulo pos = buf;
3039325151a3SRui Paulo end = buf + buflen;
3040325151a3SRui Paulo
3041325151a3SRui Paulo os_get_reltime(&now);
3042325151a3SRui Paulo dl_list_for_each_reverse(info, &iface->sta_seen,
3043325151a3SRui Paulo struct hostapd_sta_info, list) {
3044325151a3SRui Paulo struct os_reltime age;
3045325151a3SRui Paulo int ret;
3046325151a3SRui Paulo
3047325151a3SRui Paulo os_reltime_sub(&now, &info->last_seen, &age);
304885732ac8SCy Schubert ret = os_snprintf(pos, end - pos, MACSTR " %u %d\n",
304985732ac8SCy Schubert MAC2STR(info->addr), (unsigned int) age.sec,
305085732ac8SCy Schubert info->ssi_signal);
3051325151a3SRui Paulo if (os_snprintf_error(end - pos, ret))
3052325151a3SRui Paulo break;
3053325151a3SRui Paulo pos += ret;
3054325151a3SRui Paulo }
3055325151a3SRui Paulo
3056325151a3SRui Paulo return pos - buf;
3057325151a3SRui Paulo }
3058325151a3SRui Paulo #endif /* NEED_AP_MLME */
3059325151a3SRui Paulo
3060325151a3SRui Paulo
hostapd_ctrl_iface_req_lci(struct hostapd_data * hapd,const char * cmd)3061780fb4a2SCy Schubert static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
3062780fb4a2SCy Schubert const char *cmd)
3063780fb4a2SCy Schubert {
3064780fb4a2SCy Schubert u8 addr[ETH_ALEN];
3065780fb4a2SCy Schubert
3066780fb4a2SCy Schubert if (hwaddr_aton(cmd, addr)) {
3067780fb4a2SCy Schubert wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
3068780fb4a2SCy Schubert return -1;
3069780fb4a2SCy Schubert }
3070780fb4a2SCy Schubert
3071780fb4a2SCy Schubert return hostapd_send_lci_req(hapd, addr);
3072780fb4a2SCy Schubert }
3073780fb4a2SCy Schubert
3074780fb4a2SCy Schubert
hostapd_ctrl_iface_req_range(struct hostapd_data * hapd,char * cmd)3075780fb4a2SCy Schubert static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
3076780fb4a2SCy Schubert {
3077780fb4a2SCy Schubert u8 addr[ETH_ALEN];
3078780fb4a2SCy Schubert char *token, *context = NULL;
3079780fb4a2SCy Schubert int random_interval, min_ap;
3080780fb4a2SCy Schubert u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
3081780fb4a2SCy Schubert unsigned int n_responders;
3082780fb4a2SCy Schubert
3083780fb4a2SCy Schubert token = str_token(cmd, " ", &context);
3084780fb4a2SCy Schubert if (!token || hwaddr_aton(token, addr)) {
3085780fb4a2SCy Schubert wpa_printf(MSG_INFO,
3086780fb4a2SCy Schubert "CTRL: REQ_RANGE - Bad destination address");
3087780fb4a2SCy Schubert return -1;
3088780fb4a2SCy Schubert }
3089780fb4a2SCy Schubert
3090780fb4a2SCy Schubert token = str_token(cmd, " ", &context);
3091780fb4a2SCy Schubert if (!token)
3092780fb4a2SCy Schubert return -1;
3093780fb4a2SCy Schubert
3094780fb4a2SCy Schubert random_interval = atoi(token);
3095780fb4a2SCy Schubert if (random_interval < 0 || random_interval > 0xffff)
3096780fb4a2SCy Schubert return -1;
3097780fb4a2SCy Schubert
3098780fb4a2SCy Schubert token = str_token(cmd, " ", &context);
3099780fb4a2SCy Schubert if (!token)
3100780fb4a2SCy Schubert return -1;
3101780fb4a2SCy Schubert
3102780fb4a2SCy Schubert min_ap = atoi(token);
3103780fb4a2SCy Schubert if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
3104780fb4a2SCy Schubert return -1;
3105780fb4a2SCy Schubert
3106780fb4a2SCy Schubert n_responders = 0;
3107780fb4a2SCy Schubert while ((token = str_token(cmd, " ", &context))) {
3108780fb4a2SCy Schubert if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
3109780fb4a2SCy Schubert wpa_printf(MSG_INFO,
3110780fb4a2SCy Schubert "CTRL: REQ_RANGE: Too many responders");
3111780fb4a2SCy Schubert return -1;
3112780fb4a2SCy Schubert }
3113780fb4a2SCy Schubert
3114780fb4a2SCy Schubert if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
3115780fb4a2SCy Schubert wpa_printf(MSG_INFO,
3116780fb4a2SCy Schubert "CTRL: REQ_RANGE: Bad responder address");
3117780fb4a2SCy Schubert return -1;
3118780fb4a2SCy Schubert }
3119780fb4a2SCy Schubert
3120780fb4a2SCy Schubert n_responders++;
3121780fb4a2SCy Schubert }
3122780fb4a2SCy Schubert
3123780fb4a2SCy Schubert if (!n_responders) {
3124780fb4a2SCy Schubert wpa_printf(MSG_INFO,
3125780fb4a2SCy Schubert "CTRL: REQ_RANGE - No FTM responder address");
3126780fb4a2SCy Schubert return -1;
3127780fb4a2SCy Schubert }
3128780fb4a2SCy Schubert
3129780fb4a2SCy Schubert return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
3130780fb4a2SCy Schubert responders, n_responders);
3131780fb4a2SCy Schubert }
3132780fb4a2SCy Schubert
3133780fb4a2SCy Schubert
hostapd_ctrl_iface_req_beacon(struct hostapd_data * hapd,const char * cmd,char * reply,size_t reply_size)313485732ac8SCy Schubert static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd,
313585732ac8SCy Schubert const char *cmd, char *reply,
313685732ac8SCy Schubert size_t reply_size)
313785732ac8SCy Schubert {
313885732ac8SCy Schubert u8 addr[ETH_ALEN];
313985732ac8SCy Schubert const char *pos;
314085732ac8SCy Schubert struct wpabuf *req;
314185732ac8SCy Schubert int ret;
314285732ac8SCy Schubert u8 req_mode = 0;
314385732ac8SCy Schubert
314485732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
314585732ac8SCy Schubert return -1;
314685732ac8SCy Schubert pos = os_strchr(cmd, ' ');
314785732ac8SCy Schubert if (!pos)
314885732ac8SCy Schubert return -1;
314985732ac8SCy Schubert pos++;
315085732ac8SCy Schubert if (os_strncmp(pos, "req_mode=", 9) == 0) {
315185732ac8SCy Schubert int val = hex2byte(pos + 9);
315285732ac8SCy Schubert
315385732ac8SCy Schubert if (val < 0)
315485732ac8SCy Schubert return -1;
315585732ac8SCy Schubert req_mode = val;
315685732ac8SCy Schubert pos += 11;
315785732ac8SCy Schubert pos = os_strchr(pos, ' ');
315885732ac8SCy Schubert if (!pos)
315985732ac8SCy Schubert return -1;
316085732ac8SCy Schubert pos++;
316185732ac8SCy Schubert }
316285732ac8SCy Schubert req = wpabuf_parse_bin(pos);
316385732ac8SCy Schubert if (!req)
316485732ac8SCy Schubert return -1;
316585732ac8SCy Schubert
316685732ac8SCy Schubert ret = hostapd_send_beacon_req(hapd, addr, req_mode, req);
316785732ac8SCy Schubert wpabuf_free(req);
316885732ac8SCy Schubert if (ret >= 0)
316985732ac8SCy Schubert ret = os_snprintf(reply, reply_size, "%d", ret);
317085732ac8SCy Schubert return ret;
317185732ac8SCy Schubert }
317285732ac8SCy Schubert
317385732ac8SCy Schubert
hostapd_ctrl_iface_show_neighbor(struct hostapd_data * hapd,char * buf,size_t buflen)3174c1d255d3SCy Schubert static int hostapd_ctrl_iface_show_neighbor(struct hostapd_data *hapd,
3175c1d255d3SCy Schubert char *buf, size_t buflen)
3176c1d255d3SCy Schubert {
3177c1d255d3SCy Schubert if (!(hapd->conf->radio_measurements[0] &
3178c1d255d3SCy Schubert WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
3179c1d255d3SCy Schubert wpa_printf(MSG_ERROR,
3180c1d255d3SCy Schubert "CTRL: SHOW_NEIGHBOR: Neighbor report is not enabled");
3181c1d255d3SCy Schubert return -1;
3182c1d255d3SCy Schubert }
3183c1d255d3SCy Schubert
3184c1d255d3SCy Schubert return hostapd_neighbor_show(hapd, buf, buflen);
3185c1d255d3SCy Schubert }
3186c1d255d3SCy Schubert
3187c1d255d3SCy Schubert
hostapd_ctrl_iface_set_neighbor(struct hostapd_data * hapd,char * buf)3188780fb4a2SCy Schubert static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
3189780fb4a2SCy Schubert {
3190780fb4a2SCy Schubert struct wpa_ssid_value ssid;
3191780fb4a2SCy Schubert u8 bssid[ETH_ALEN];
3192780fb4a2SCy Schubert struct wpabuf *nr, *lci = NULL, *civic = NULL;
319385732ac8SCy Schubert int stationary = 0;
31944b72b91aSCy Schubert int bss_parameters = 0;
3195780fb4a2SCy Schubert char *tmp;
31964b72b91aSCy Schubert int ret = -1;
3197780fb4a2SCy Schubert
3198780fb4a2SCy Schubert if (!(hapd->conf->radio_measurements[0] &
3199780fb4a2SCy Schubert WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
3200780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3201780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
3202780fb4a2SCy Schubert return -1;
3203780fb4a2SCy Schubert }
3204780fb4a2SCy Schubert
3205780fb4a2SCy Schubert if (hwaddr_aton(buf, bssid)) {
3206780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
3207780fb4a2SCy Schubert return -1;
3208780fb4a2SCy Schubert }
3209780fb4a2SCy Schubert
3210780fb4a2SCy Schubert tmp = os_strstr(buf, "ssid=");
3211780fb4a2SCy Schubert if (!tmp || ssid_parse(tmp + 5, &ssid)) {
3212780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3213780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Bad or missing SSID");
3214780fb4a2SCy Schubert return -1;
3215780fb4a2SCy Schubert }
3216780fb4a2SCy Schubert buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
3217780fb4a2SCy Schubert if (!buf)
3218780fb4a2SCy Schubert return -1;
3219780fb4a2SCy Schubert
3220780fb4a2SCy Schubert tmp = os_strstr(buf, "nr=");
3221780fb4a2SCy Schubert if (!tmp) {
3222780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3223780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
3224780fb4a2SCy Schubert return -1;
3225780fb4a2SCy Schubert }
3226780fb4a2SCy Schubert
3227780fb4a2SCy Schubert buf = os_strchr(tmp, ' ');
3228780fb4a2SCy Schubert if (buf)
3229780fb4a2SCy Schubert *buf++ = '\0';
3230780fb4a2SCy Schubert
3231780fb4a2SCy Schubert nr = wpabuf_parse_bin(tmp + 3);
3232780fb4a2SCy Schubert if (!nr) {
3233780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3234780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
3235780fb4a2SCy Schubert return -1;
3236780fb4a2SCy Schubert }
3237780fb4a2SCy Schubert
3238780fb4a2SCy Schubert if (!buf)
3239780fb4a2SCy Schubert goto set;
3240780fb4a2SCy Schubert
3241780fb4a2SCy Schubert tmp = os_strstr(buf, "lci=");
3242780fb4a2SCy Schubert if (tmp) {
3243780fb4a2SCy Schubert buf = os_strchr(tmp, ' ');
3244780fb4a2SCy Schubert if (buf)
3245780fb4a2SCy Schubert *buf++ = '\0';
3246780fb4a2SCy Schubert lci = wpabuf_parse_bin(tmp + 4);
3247780fb4a2SCy Schubert if (!lci) {
3248780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3249780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Bad LCI subelement");
32504b72b91aSCy Schubert goto fail;
3251780fb4a2SCy Schubert }
3252780fb4a2SCy Schubert }
3253780fb4a2SCy Schubert
3254780fb4a2SCy Schubert if (!buf)
3255780fb4a2SCy Schubert goto set;
3256780fb4a2SCy Schubert
3257780fb4a2SCy Schubert tmp = os_strstr(buf, "civic=");
3258780fb4a2SCy Schubert if (tmp) {
3259780fb4a2SCy Schubert buf = os_strchr(tmp, ' ');
3260780fb4a2SCy Schubert if (buf)
3261780fb4a2SCy Schubert *buf++ = '\0';
3262780fb4a2SCy Schubert civic = wpabuf_parse_bin(tmp + 6);
3263780fb4a2SCy Schubert if (!civic) {
3264780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3265780fb4a2SCy Schubert "CTRL: SET_NEIGHBOR: Bad civic subelement");
32664b72b91aSCy Schubert goto fail;
3267780fb4a2SCy Schubert }
3268780fb4a2SCy Schubert }
3269780fb4a2SCy Schubert
327085732ac8SCy Schubert if (!buf)
327185732ac8SCy Schubert goto set;
327285732ac8SCy Schubert
327385732ac8SCy Schubert if (os_strstr(buf, "stat"))
327485732ac8SCy Schubert stationary = 1;
327585732ac8SCy Schubert
32764b72b91aSCy Schubert tmp = os_strstr(buf, "bss_parameter=");
32774b72b91aSCy Schubert if (tmp) {
32784b72b91aSCy Schubert bss_parameters = atoi(tmp + 14);
32794b72b91aSCy Schubert if (bss_parameters < 0 || bss_parameters > 0xff) {
32804b72b91aSCy Schubert wpa_printf(MSG_ERROR,
32814b72b91aSCy Schubert "CTRL: SET_NEIGHBOR: Bad bss_parameters subelement");
32824b72b91aSCy Schubert goto fail;
32834b72b91aSCy Schubert }
32844b72b91aSCy Schubert }
32854b72b91aSCy Schubert
3286780fb4a2SCy Schubert set:
328785732ac8SCy Schubert ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic,
32884b72b91aSCy Schubert stationary, bss_parameters);
3289780fb4a2SCy Schubert
32904b72b91aSCy Schubert fail:
3291780fb4a2SCy Schubert wpabuf_free(nr);
3292780fb4a2SCy Schubert wpabuf_free(lci);
3293780fb4a2SCy Schubert wpabuf_free(civic);
3294780fb4a2SCy Schubert
3295780fb4a2SCy Schubert return ret;
3296780fb4a2SCy Schubert }
3297780fb4a2SCy Schubert
3298780fb4a2SCy Schubert
hostapd_ctrl_iface_remove_neighbor(struct hostapd_data * hapd,char * buf)3299780fb4a2SCy Schubert static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
3300780fb4a2SCy Schubert char *buf)
3301780fb4a2SCy Schubert {
3302780fb4a2SCy Schubert struct wpa_ssid_value ssid;
3303c1d255d3SCy Schubert struct wpa_ssid_value *ssidp = NULL;
3304780fb4a2SCy Schubert u8 bssid[ETH_ALEN];
3305780fb4a2SCy Schubert char *tmp;
3306780fb4a2SCy Schubert
3307780fb4a2SCy Schubert if (hwaddr_aton(buf, bssid)) {
3308780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
3309780fb4a2SCy Schubert return -1;
3310780fb4a2SCy Schubert }
3311780fb4a2SCy Schubert
3312780fb4a2SCy Schubert tmp = os_strstr(buf, "ssid=");
3313c1d255d3SCy Schubert if (tmp) {
3314c1d255d3SCy Schubert ssidp = &ssid;
3315c1d255d3SCy Schubert if (ssid_parse(tmp + 5, &ssid)) {
3316780fb4a2SCy Schubert wpa_printf(MSG_ERROR,
3317c1d255d3SCy Schubert "CTRL: REMOVE_NEIGHBOR: Bad SSID");
3318780fb4a2SCy Schubert return -1;
3319780fb4a2SCy Schubert }
3320c1d255d3SCy Schubert }
3321780fb4a2SCy Schubert
3322c1d255d3SCy Schubert return hostapd_neighbor_remove(hapd, bssid, ssidp);
3323780fb4a2SCy Schubert }
3324780fb4a2SCy Schubert
3325780fb4a2SCy Schubert
hostapd_ctrl_driver_flags(struct hostapd_iface * iface,char * buf,size_t buflen)3326780fb4a2SCy Schubert static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
3327780fb4a2SCy Schubert size_t buflen)
3328780fb4a2SCy Schubert {
3329780fb4a2SCy Schubert int ret, i;
3330780fb4a2SCy Schubert char *pos, *end;
3331780fb4a2SCy Schubert
3332780fb4a2SCy Schubert ret = os_snprintf(buf, buflen, "%016llX:\n",
3333780fb4a2SCy Schubert (long long unsigned) iface->drv_flags);
3334780fb4a2SCy Schubert if (os_snprintf_error(buflen, ret))
3335780fb4a2SCy Schubert return -1;
3336780fb4a2SCy Schubert
3337780fb4a2SCy Schubert pos = buf + ret;
3338780fb4a2SCy Schubert end = buf + buflen;
3339780fb4a2SCy Schubert
3340780fb4a2SCy Schubert for (i = 0; i < 64; i++) {
3341780fb4a2SCy Schubert if (iface->drv_flags & (1LLU << i)) {
3342780fb4a2SCy Schubert ret = os_snprintf(pos, end - pos, "%s\n",
3343780fb4a2SCy Schubert driver_flag_to_string(1LLU << i));
3344780fb4a2SCy Schubert if (os_snprintf_error(end - pos, ret))
3345780fb4a2SCy Schubert return -1;
3346780fb4a2SCy Schubert pos += ret;
3347780fb4a2SCy Schubert }
3348780fb4a2SCy Schubert }
3349780fb4a2SCy Schubert
3350780fb4a2SCy Schubert return pos - buf;
3351780fb4a2SCy Schubert }
3352780fb4a2SCy Schubert
3353780fb4a2SCy Schubert
hostapd_ctrl_driver_flags2(struct hostapd_iface * iface,char * buf,size_t buflen)3354c1d255d3SCy Schubert static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf,
3355c1d255d3SCy Schubert size_t buflen)
3356c1d255d3SCy Schubert {
3357c1d255d3SCy Schubert int ret, i;
3358c1d255d3SCy Schubert char *pos, *end;
3359c1d255d3SCy Schubert
3360c1d255d3SCy Schubert ret = os_snprintf(buf, buflen, "%016llX:\n",
3361c1d255d3SCy Schubert (long long unsigned) iface->drv_flags2);
3362c1d255d3SCy Schubert if (os_snprintf_error(buflen, ret))
3363c1d255d3SCy Schubert return -1;
3364c1d255d3SCy Schubert
3365c1d255d3SCy Schubert pos = buf + ret;
3366c1d255d3SCy Schubert end = buf + buflen;
3367c1d255d3SCy Schubert
3368c1d255d3SCy Schubert for (i = 0; i < 64; i++) {
3369c1d255d3SCy Schubert if (iface->drv_flags2 & (1LLU << i)) {
3370c1d255d3SCy Schubert ret = os_snprintf(pos, end - pos, "%s\n",
3371c1d255d3SCy Schubert driver_flag2_to_string(1LLU << i));
3372c1d255d3SCy Schubert if (os_snprintf_error(end - pos, ret))
3373c1d255d3SCy Schubert return -1;
3374c1d255d3SCy Schubert pos += ret;
3375c1d255d3SCy Schubert }
3376c1d255d3SCy Schubert }
3377c1d255d3SCy Schubert
3378c1d255d3SCy Schubert return pos - buf;
3379c1d255d3SCy Schubert }
3380c1d255d3SCy Schubert
3381c1d255d3SCy Schubert
hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry ** acl,int * num,const char * txtaddr)338285732ac8SCy Schubert static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
338385732ac8SCy Schubert const char *txtaddr)
338485732ac8SCy Schubert {
338585732ac8SCy Schubert u8 addr[ETH_ALEN];
338685732ac8SCy Schubert struct vlan_description vlan_id;
338785732ac8SCy Schubert
338885732ac8SCy Schubert if (!(*num))
338985732ac8SCy Schubert return 0;
339085732ac8SCy Schubert
339185732ac8SCy Schubert if (hwaddr_aton(txtaddr, addr))
339285732ac8SCy Schubert return -1;
339385732ac8SCy Schubert
339485732ac8SCy Schubert if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
339585732ac8SCy Schubert hostapd_remove_acl_mac(acl, num, addr);
339685732ac8SCy Schubert
339785732ac8SCy Schubert return 0;
339885732ac8SCy Schubert }
339985732ac8SCy Schubert
340085732ac8SCy Schubert
hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry ** acl,int * num)340185732ac8SCy Schubert static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
340285732ac8SCy Schubert int *num)
340385732ac8SCy Schubert {
340485732ac8SCy Schubert while (*num)
340585732ac8SCy Schubert hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
340685732ac8SCy Schubert }
340785732ac8SCy Schubert
340885732ac8SCy Schubert
hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry * acl,int num,char * buf,size_t buflen)340985732ac8SCy Schubert static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
341085732ac8SCy Schubert char *buf, size_t buflen)
341185732ac8SCy Schubert {
341285732ac8SCy Schubert int i = 0, len = 0, ret = 0;
341385732ac8SCy Schubert
341485732ac8SCy Schubert if (!acl)
341585732ac8SCy Schubert return 0;
341685732ac8SCy Schubert
341785732ac8SCy Schubert while (i < num) {
341885732ac8SCy Schubert ret = os_snprintf(buf + len, buflen - len,
341985732ac8SCy Schubert MACSTR " VLAN_ID=%d\n",
342085732ac8SCy Schubert MAC2STR(acl[i].addr),
342185732ac8SCy Schubert acl[i].vlan_id.untagged);
342285732ac8SCy Schubert if (ret < 0 || (size_t) ret >= buflen - len)
342385732ac8SCy Schubert return len;
342485732ac8SCy Schubert i++;
342585732ac8SCy Schubert len += ret;
342685732ac8SCy Schubert }
342785732ac8SCy Schubert return len;
342885732ac8SCy Schubert }
342985732ac8SCy Schubert
343085732ac8SCy Schubert
hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry ** acl,int * num,const char * cmd)343185732ac8SCy Schubert static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
343285732ac8SCy Schubert const char *cmd)
343385732ac8SCy Schubert {
343485732ac8SCy Schubert u8 addr[ETH_ALEN];
343585732ac8SCy Schubert struct vlan_description vlan_id;
343685732ac8SCy Schubert int ret = 0, vlanid = 0;
343785732ac8SCy Schubert const char *pos;
343885732ac8SCy Schubert
343985732ac8SCy Schubert if (hwaddr_aton(cmd, addr))
344085732ac8SCy Schubert return -1;
344185732ac8SCy Schubert
344285732ac8SCy Schubert pos = os_strstr(cmd, "VLAN_ID=");
344385732ac8SCy Schubert if (pos)
344485732ac8SCy Schubert vlanid = atoi(pos + 8);
344585732ac8SCy Schubert
344685732ac8SCy Schubert if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
344785732ac8SCy Schubert ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
344885732ac8SCy Schubert if (ret != -1 && *acl)
344985732ac8SCy Schubert qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
345085732ac8SCy Schubert }
345185732ac8SCy Schubert
345285732ac8SCy Schubert return ret < 0 ? -1 : 0;
345385732ac8SCy Schubert }
345485732ac8SCy Schubert
345585732ac8SCy Schubert
hostapd_ctrl_iface_get_capability(struct hostapd_data * hapd,const char * field,char * buf,size_t buflen)34564bc52338SCy Schubert static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
34574bc52338SCy Schubert const char *field, char *buf,
34584bc52338SCy Schubert size_t buflen)
34594bc52338SCy Schubert {
34604bc52338SCy Schubert wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field);
34614bc52338SCy Schubert
34624bc52338SCy Schubert #ifdef CONFIG_DPP
34634bc52338SCy Schubert if (os_strcmp(field, "dpp") == 0) {
34644bc52338SCy Schubert int res;
34654bc52338SCy Schubert
346632a95656SCy Schubert #ifdef CONFIG_DPP3
346732a95656SCy Schubert res = os_snprintf(buf, buflen, "DPP=3");
346832a95656SCy Schubert #elif defined(CONFIG_DPP2)
34694bc52338SCy Schubert res = os_snprintf(buf, buflen, "DPP=2");
34704bc52338SCy Schubert #else /* CONFIG_DPP2 */
34714bc52338SCy Schubert res = os_snprintf(buf, buflen, "DPP=1");
34724bc52338SCy Schubert #endif /* CONFIG_DPP2 */
34734bc52338SCy Schubert if (os_snprintf_error(buflen, res))
34744bc52338SCy Schubert return -1;
34754bc52338SCy Schubert return res;
34764bc52338SCy Schubert }
34774bc52338SCy Schubert #endif /* CONFIG_DPP */
34784bc52338SCy Schubert
34794bc52338SCy Schubert wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
34804bc52338SCy Schubert field);
34814bc52338SCy Schubert
34824bc52338SCy Schubert return -1;
34834bc52338SCy Schubert }
34844bc52338SCy Schubert
34854bc52338SCy Schubert
3486c1d255d3SCy Schubert #ifdef ANDROID
hostapd_ctrl_iface_driver_cmd(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)3487c1d255d3SCy Schubert static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd,
3488c1d255d3SCy Schubert char *buf, size_t buflen)
3489c1d255d3SCy Schubert {
3490c1d255d3SCy Schubert int ret;
3491c1d255d3SCy Schubert
3492c1d255d3SCy Schubert ret = hostapd_drv_driver_cmd(hapd, cmd, buf, buflen);
3493c1d255d3SCy Schubert if (ret == 0) {
3494c1d255d3SCy Schubert ret = os_snprintf(buf, buflen, "%s\n", "OK");
3495c1d255d3SCy Schubert if (os_snprintf_error(buflen, ret))
3496c1d255d3SCy Schubert ret = -1;
3497c1d255d3SCy Schubert }
3498c1d255d3SCy Schubert return ret;
3499c1d255d3SCy Schubert }
3500c1d255d3SCy Schubert #endif /* ANDROID */
3501c1d255d3SCy Schubert
3502c1d255d3SCy Schubert
hostapd_ctrl_iface_receive_process(struct hostapd_data * hapd,char * buf,char * reply,int reply_size,struct sockaddr_storage * from,socklen_t fromlen)3503325151a3SRui Paulo static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
3504325151a3SRui Paulo char *buf, char *reply,
3505325151a3SRui Paulo int reply_size,
3506780fb4a2SCy Schubert struct sockaddr_storage *from,
3507325151a3SRui Paulo socklen_t fromlen)
3508325151a3SRui Paulo {
3509325151a3SRui Paulo int reply_len, res;
3510325151a3SRui Paulo
351139beb93cSSam Leffler os_memcpy(reply, "OK\n", 3);
351239beb93cSSam Leffler reply_len = 3;
351339beb93cSSam Leffler
351439beb93cSSam Leffler if (os_strcmp(buf, "PING") == 0) {
351539beb93cSSam Leffler os_memcpy(reply, "PONG\n", 5);
351639beb93cSSam Leffler reply_len = 5;
3517f05cddf9SRui Paulo } else if (os_strncmp(buf, "RELOG", 5) == 0) {
3518f05cddf9SRui Paulo if (wpa_debug_reopen_file() < 0)
3519f05cddf9SRui Paulo reply_len = -1;
352085732ac8SCy Schubert } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
352185732ac8SCy Schubert wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
35225b9c547cSRui Paulo } else if (os_strcmp(buf, "STATUS") == 0) {
35235b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_status(hapd, reply,
35245b9c547cSRui Paulo reply_size);
35255b9c547cSRui Paulo } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
35265b9c547cSRui Paulo reply_len = hostapd_drv_status(hapd, reply, reply_size);
352739beb93cSSam Leffler } else if (os_strcmp(buf, "MIB") == 0) {
352839beb93cSSam Leffler reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
352939beb93cSSam Leffler if (reply_len >= 0) {
353039beb93cSSam Leffler res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
353139beb93cSSam Leffler reply_size - reply_len);
353239beb93cSSam Leffler if (res < 0)
353339beb93cSSam Leffler reply_len = -1;
353439beb93cSSam Leffler else
353539beb93cSSam Leffler reply_len += res;
353639beb93cSSam Leffler }
353739beb93cSSam Leffler if (reply_len >= 0) {
353839beb93cSSam Leffler res = ieee802_1x_get_mib(hapd, reply + reply_len,
353939beb93cSSam Leffler reply_size - reply_len);
354039beb93cSSam Leffler if (res < 0)
354139beb93cSSam Leffler reply_len = -1;
354239beb93cSSam Leffler else
354339beb93cSSam Leffler reply_len += res;
354439beb93cSSam Leffler }
3545e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS
354639beb93cSSam Leffler if (reply_len >= 0) {
354739beb93cSSam Leffler res = radius_client_get_mib(hapd->radius,
354839beb93cSSam Leffler reply + reply_len,
354939beb93cSSam Leffler reply_size - reply_len);
355039beb93cSSam Leffler if (res < 0)
355139beb93cSSam Leffler reply_len = -1;
355239beb93cSSam Leffler else
355339beb93cSSam Leffler reply_len += res;
355439beb93cSSam Leffler }
3555e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */
35565b9c547cSRui Paulo } else if (os_strncmp(buf, "MIB ", 4) == 0) {
35575b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
35585b9c547cSRui Paulo buf + 4);
355939beb93cSSam Leffler } else if (os_strcmp(buf, "STA-FIRST") == 0) {
356039beb93cSSam Leffler reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
356139beb93cSSam Leffler reply_size);
356239beb93cSSam Leffler } else if (os_strncmp(buf, "STA ", 4) == 0) {
356339beb93cSSam Leffler reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
356439beb93cSSam Leffler reply_size);
356539beb93cSSam Leffler } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
356639beb93cSSam Leffler reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
356739beb93cSSam Leffler reply_size);
356839beb93cSSam Leffler } else if (os_strcmp(buf, "ATTACH") == 0) {
356985732ac8SCy Schubert if (hostapd_ctrl_iface_attach(hapd, from, fromlen, NULL))
357085732ac8SCy Schubert reply_len = -1;
357185732ac8SCy Schubert } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
357285732ac8SCy Schubert if (hostapd_ctrl_iface_attach(hapd, from, fromlen, buf + 7))
357339beb93cSSam Leffler reply_len = -1;
357439beb93cSSam Leffler } else if (os_strcmp(buf, "DETACH") == 0) {
3575325151a3SRui Paulo if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
357639beb93cSSam Leffler reply_len = -1;
357739beb93cSSam Leffler } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
3578325151a3SRui Paulo if (hostapd_ctrl_iface_level(hapd, from, fromlen,
357939beb93cSSam Leffler buf + 6))
358039beb93cSSam Leffler reply_len = -1;
358139beb93cSSam Leffler } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
358239beb93cSSam Leffler if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
358339beb93cSSam Leffler reply_len = -1;
3584e28a4053SRui Paulo } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
3585e28a4053SRui Paulo if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
3586e28a4053SRui Paulo reply_len = -1;
3587e28a4053SRui Paulo } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
3588e28a4053SRui Paulo if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
3589e28a4053SRui Paulo reply_len = -1;
3590780fb4a2SCy Schubert #ifdef CONFIG_TAXONOMY
3591780fb4a2SCy Schubert } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) {
3592780fb4a2SCy Schubert reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10,
3593780fb4a2SCy Schubert reply, reply_size);
3594780fb4a2SCy Schubert #endif /* CONFIG_TAXONOMY */
3595780fb4a2SCy Schubert } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
3596780fb4a2SCy Schubert if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
3597780fb4a2SCy Schubert reply_len = -1;
35985b9c547cSRui Paulo } else if (os_strcmp(buf, "STOP_AP") == 0) {
35995b9c547cSRui Paulo if (hostapd_ctrl_iface_stop_ap(hapd))
36005b9c547cSRui Paulo reply_len = -1;
3601e28a4053SRui Paulo #ifdef NEED_AP_MLME
360239beb93cSSam Leffler } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
360339beb93cSSam Leffler if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
360439beb93cSSam Leffler reply_len = -1;
3605e28a4053SRui Paulo #endif /* NEED_AP_MLME */
360639beb93cSSam Leffler #ifdef CONFIG_WPS
360739beb93cSSam Leffler } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
360839beb93cSSam Leffler if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
360939beb93cSSam Leffler reply_len = -1;
3610f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
3611f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_wps_check_pin(
3612f05cddf9SRui Paulo hapd, buf + 14, reply, reply_size);
361339beb93cSSam Leffler } else if (os_strcmp(buf, "WPS_PBC") == 0) {
3614f05cddf9SRui Paulo if (hostapd_wps_button_pushed(hapd, NULL))
361539beb93cSSam Leffler reply_len = -1;
3616f05cddf9SRui Paulo } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
3617f05cddf9SRui Paulo if (hostapd_wps_cancel(hapd))
3618e28a4053SRui Paulo reply_len = -1;
3619e28a4053SRui Paulo } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
3620e28a4053SRui Paulo reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
3621e28a4053SRui Paulo reply, reply_size);
3622f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
3623f05cddf9SRui Paulo if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
3624f05cddf9SRui Paulo reply_len = -1;
36255b9c547cSRui Paulo } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
36265b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
36275b9c547cSRui Paulo reply_size);
3628f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
3629f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
3630f05cddf9SRui Paulo if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
3631f05cddf9SRui Paulo reply_len = -1;
3632f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
3633f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
3634f05cddf9SRui Paulo hapd, buf + 21, reply, reply_size);
3635f05cddf9SRui Paulo } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
3636f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_wps_nfc_token(
3637f05cddf9SRui Paulo hapd, buf + 14, reply, reply_size);
36385b9c547cSRui Paulo } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
36395b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
36405b9c547cSRui Paulo hapd, buf + 21, reply, reply_size);
36415b9c547cSRui Paulo } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
36425b9c547cSRui Paulo if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
36435b9c547cSRui Paulo reply_len = -1;
3644f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
364539beb93cSSam Leffler #endif /* CONFIG_WPS */
36465b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING
36475b9c547cSRui Paulo } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
36485b9c547cSRui Paulo if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
36495b9c547cSRui Paulo reply_len = -1;
36505b9c547cSRui Paulo } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
36515b9c547cSRui Paulo if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
36525b9c547cSRui Paulo reply_len = -1;
36535b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */
36545b9c547cSRui Paulo #ifdef CONFIG_HS20
36555b9c547cSRui Paulo } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
36565b9c547cSRui Paulo if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
36575b9c547cSRui Paulo reply_len = -1;
36585b9c547cSRui Paulo } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
36595b9c547cSRui Paulo if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
36605b9c547cSRui Paulo reply_len = -1;
36615b9c547cSRui Paulo #endif /* CONFIG_HS20 */
366285732ac8SCy Schubert #ifdef CONFIG_WNM_AP
3663f05cddf9SRui Paulo } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
3664f05cddf9SRui Paulo if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
3665f05cddf9SRui Paulo reply_len = -1;
3666f05cddf9SRui Paulo } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
3667f05cddf9SRui Paulo if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
3668f05cddf9SRui Paulo reply_len = -1;
36695b9c547cSRui Paulo } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
36705b9c547cSRui Paulo if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
36715b9c547cSRui Paulo reply_len = -1;
367285732ac8SCy Schubert } else if (os_strncmp(buf, "COLOC_INTF_REQ ", 15) == 0) {
367385732ac8SCy Schubert if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
367485732ac8SCy Schubert reply_len = -1;
367585732ac8SCy Schubert #endif /* CONFIG_WNM_AP */
3676f05cddf9SRui Paulo } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
3677f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
3678f05cddf9SRui Paulo reply_size);
3679f05cddf9SRui Paulo } else if (os_strncmp(buf, "SET ", 4) == 0) {
3680f05cddf9SRui Paulo if (hostapd_ctrl_iface_set(hapd, buf + 4))
3681f05cddf9SRui Paulo reply_len = -1;
3682f05cddf9SRui Paulo } else if (os_strncmp(buf, "GET ", 4) == 0) {
3683f05cddf9SRui Paulo reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
3684f05cddf9SRui Paulo reply_size);
3685f05cddf9SRui Paulo } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
3686f05cddf9SRui Paulo if (hostapd_ctrl_iface_enable(hapd->iface))
3687f05cddf9SRui Paulo reply_len = -1;
36884bc52338SCy Schubert } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) {
36894bc52338SCy Schubert if (hostapd_ctrl_iface_reload_wpa_psk(hapd))
36904bc52338SCy Schubert reply_len = -1;
3691f05cddf9SRui Paulo } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
3692f05cddf9SRui Paulo if (hostapd_ctrl_iface_reload(hapd->iface))
3693f05cddf9SRui Paulo reply_len = -1;
3694f05cddf9SRui Paulo } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
3695f05cddf9SRui Paulo if (hostapd_ctrl_iface_disable(hapd->iface))
3696f05cddf9SRui Paulo reply_len = -1;
36975b9c547cSRui Paulo } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
36985b9c547cSRui Paulo if (ieee802_11_set_beacon(hapd))
36995b9c547cSRui Paulo reply_len = -1;
37005b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
37015b9c547cSRui Paulo } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
37025b9c547cSRui Paulo if (hostapd_ctrl_iface_radar(hapd, buf + 6))
37035b9c547cSRui Paulo reply_len = -1;
37045b9c547cSRui Paulo } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
37055b9c547cSRui Paulo if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
37065b9c547cSRui Paulo reply_len = -1;
370785732ac8SCy Schubert } else if (os_strncmp(buf, "MGMT_TX_STATUS_PROCESS ", 23) == 0) {
370885732ac8SCy Schubert if (hostapd_ctrl_iface_mgmt_tx_status_process(hapd,
370985732ac8SCy Schubert buf + 23) < 0)
371085732ac8SCy Schubert reply_len = -1;
371185732ac8SCy Schubert } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
371285732ac8SCy Schubert if (hostapd_ctrl_iface_mgmt_rx_process(hapd, buf + 16) < 0)
371385732ac8SCy Schubert reply_len = -1;
37145b9c547cSRui Paulo } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
37155b9c547cSRui Paulo if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
37165b9c547cSRui Paulo reply_len = -1;
3717c1d255d3SCy Schubert } else if (os_strncmp(buf, "EAPOL_TX ", 9) == 0) {
3718c1d255d3SCy Schubert if (hostapd_ctrl_iface_eapol_tx(hapd, buf + 9) < 0)
3719c1d255d3SCy Schubert reply_len = -1;
37205b9c547cSRui Paulo } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
37215b9c547cSRui Paulo if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
37225b9c547cSRui Paulo reply_len = -1;
37235b9c547cSRui Paulo } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
37245b9c547cSRui Paulo if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
37255b9c547cSRui Paulo reply_len = -1;
37265b9c547cSRui Paulo } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
37275b9c547cSRui Paulo if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
37285b9c547cSRui Paulo reply_len = -1;
37295b9c547cSRui Paulo } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
37305b9c547cSRui Paulo if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
37315b9c547cSRui Paulo reply_len = -1;
37325b9c547cSRui Paulo } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
37335b9c547cSRui Paulo reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
37345b9c547cSRui Paulo reply_size);
3735325151a3SRui Paulo } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
3736325151a3SRui Paulo if (hostapd_ctrl_test_fail(hapd, buf + 10) < 0)
3737325151a3SRui Paulo reply_len = -1;
3738325151a3SRui Paulo } else if (os_strcmp(buf, "GET_FAIL") == 0) {
3739325151a3SRui Paulo reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size);
374085732ac8SCy Schubert } else if (os_strncmp(buf, "RESET_PN ", 9) == 0) {
374185732ac8SCy Schubert if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 0)
374285732ac8SCy Schubert reply_len = -1;
374385732ac8SCy Schubert } else if (os_strncmp(buf, "SET_KEY ", 8) == 0) {
374485732ac8SCy Schubert if (hostapd_ctrl_set_key(hapd, buf + 8) < 0)
374585732ac8SCy Schubert reply_len = -1;
374685732ac8SCy Schubert } else if (os_strncmp(buf, "RESEND_M1 ", 10) == 0) {
374785732ac8SCy Schubert if (hostapd_ctrl_resend_m1(hapd, buf + 10) < 0)
374885732ac8SCy Schubert reply_len = -1;
374985732ac8SCy Schubert } else if (os_strncmp(buf, "RESEND_M3 ", 10) == 0) {
375085732ac8SCy Schubert if (hostapd_ctrl_resend_m3(hapd, buf + 10) < 0)
375185732ac8SCy Schubert reply_len = -1;
375285732ac8SCy Schubert } else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) {
375385732ac8SCy Schubert if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0)
375485732ac8SCy Schubert reply_len = -1;
3755c1d255d3SCy Schubert } else if (os_strncmp(buf, "REKEY_PTK ", 10) == 0) {
3756c1d255d3SCy Schubert if (hostapd_ctrl_rekey_ptk(hapd, buf + 10) < 0)
3757c1d255d3SCy Schubert reply_len = -1;
375885732ac8SCy Schubert } else if (os_strcmp(buf, "REKEY_GTK") == 0) {
375985732ac8SCy Schubert if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
376085732ac8SCy Schubert reply_len = -1;
3761c1d255d3SCy Schubert } else if (os_strncmp(buf, "GET_PMK ", 8) == 0) {
3762c1d255d3SCy Schubert reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply,
3763c1d255d3SCy Schubert reply_size);
3764c1d255d3SCy Schubert } else if (os_strncmp(buf, "REGISTER_FRAME ", 15) == 0) {
3765c1d255d3SCy Schubert if (hostapd_ctrl_register_frame(hapd, buf + 16) < 0)
3766c1d255d3SCy Schubert reply_len = -1;
37675b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
37685b9c547cSRui Paulo } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
37695b9c547cSRui Paulo if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
37705b9c547cSRui Paulo reply_len = -1;
37715b9c547cSRui Paulo } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
37725b9c547cSRui Paulo reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
37735b9c547cSRui Paulo reply_size);
37745b9c547cSRui Paulo } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
37755b9c547cSRui Paulo ieee802_1x_erp_flush(hapd);
37765b9c547cSRui Paulo #ifdef RADIUS_SERVER
37775b9c547cSRui Paulo radius_server_erp_flush(hapd->radius_srv);
37785b9c547cSRui Paulo #endif /* RADIUS_SERVER */
3779325151a3SRui Paulo } else if (os_strncmp(buf, "EAPOL_REAUTH ", 13) == 0) {
3780325151a3SRui Paulo if (hostapd_ctrl_iface_eapol_reauth(hapd, buf + 13))
3781325151a3SRui Paulo reply_len = -1;
3782325151a3SRui Paulo } else if (os_strncmp(buf, "EAPOL_SET ", 10) == 0) {
3783325151a3SRui Paulo if (hostapd_ctrl_iface_eapol_set(hapd, buf + 10))
3784325151a3SRui Paulo reply_len = -1;
3785325151a3SRui Paulo } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
3786325151a3SRui Paulo reply_len = hostapd_ctrl_iface_log_level(
3787325151a3SRui Paulo hapd, buf + 9, reply, reply_size);
3788325151a3SRui Paulo #ifdef NEED_AP_MLME
3789325151a3SRui Paulo } else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
3790325151a3SRui Paulo reply_len = hostapd_ctrl_iface_track_sta_list(
3791325151a3SRui Paulo hapd, reply, reply_size);
3792325151a3SRui Paulo #endif /* NEED_AP_MLME */
3793780fb4a2SCy Schubert } else if (os_strcmp(buf, "PMKSA") == 0) {
3794780fb4a2SCy Schubert reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
3795780fb4a2SCy Schubert reply_size);
3796780fb4a2SCy Schubert } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
3797780fb4a2SCy Schubert hostapd_ctrl_iface_pmksa_flush(hapd);
379885732ac8SCy Schubert } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
379985732ac8SCy Schubert if (hostapd_ctrl_iface_pmksa_add(hapd, buf + 10) < 0)
380085732ac8SCy Schubert reply_len = -1;
3801780fb4a2SCy Schubert } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
3802780fb4a2SCy Schubert if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
3803780fb4a2SCy Schubert reply_len = -1;
3804c1d255d3SCy Schubert } else if (os_strcmp(buf, "SHOW_NEIGHBOR") == 0) {
3805c1d255d3SCy Schubert reply_len = hostapd_ctrl_iface_show_neighbor(hapd, reply,
3806c1d255d3SCy Schubert reply_size);
3807780fb4a2SCy Schubert } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
3808780fb4a2SCy Schubert if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
3809780fb4a2SCy Schubert reply_len = -1;
3810780fb4a2SCy Schubert } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
3811780fb4a2SCy Schubert if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
3812780fb4a2SCy Schubert reply_len = -1;
3813780fb4a2SCy Schubert } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
3814780fb4a2SCy Schubert if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
3815780fb4a2SCy Schubert reply_len = -1;
381685732ac8SCy Schubert } else if (os_strncmp(buf, "REQ_BEACON ", 11) == 0) {
381785732ac8SCy Schubert reply_len = hostapd_ctrl_iface_req_beacon(hapd, buf + 11,
381885732ac8SCy Schubert reply, reply_size);
3819780fb4a2SCy Schubert } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
3820780fb4a2SCy Schubert reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
3821780fb4a2SCy Schubert reply_size);
3822c1d255d3SCy Schubert } else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
3823c1d255d3SCy Schubert reply_len = hostapd_ctrl_driver_flags2(hapd->iface, reply,
3824c1d255d3SCy Schubert reply_size);
382585732ac8SCy Schubert } else if (os_strcmp(buf, "TERMINATE") == 0) {
382685732ac8SCy Schubert eloop_terminate();
382785732ac8SCy Schubert } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
382885732ac8SCy Schubert if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
3829c1d255d3SCy Schubert if (hostapd_ctrl_iface_acl_add_mac(
3830c1d255d3SCy Schubert &hapd->conf->accept_mac,
3831c1d255d3SCy Schubert &hapd->conf->num_accept_mac, buf + 19))
3832c1d255d3SCy Schubert reply_len = -1;
3833c1d255d3SCy Schubert } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
3834c1d255d3SCy Schubert if (!hostapd_ctrl_iface_acl_del_mac(
383585732ac8SCy Schubert &hapd->conf->accept_mac,
383685732ac8SCy Schubert &hapd->conf->num_accept_mac, buf + 19))
383785732ac8SCy Schubert hostapd_disassoc_accept_mac(hapd);
383885732ac8SCy Schubert else
383985732ac8SCy Schubert reply_len = -1;
384085732ac8SCy Schubert } else if (os_strcmp(buf + 11, "SHOW") == 0) {
384185732ac8SCy Schubert reply_len = hostapd_ctrl_iface_acl_show_mac(
384285732ac8SCy Schubert hapd->conf->accept_mac,
384385732ac8SCy Schubert hapd->conf->num_accept_mac, reply, reply_size);
384485732ac8SCy Schubert } else if (os_strcmp(buf + 11, "CLEAR") == 0) {
384585732ac8SCy Schubert hostapd_ctrl_iface_acl_clear_list(
384685732ac8SCy Schubert &hapd->conf->accept_mac,
384785732ac8SCy Schubert &hapd->conf->num_accept_mac);
3848c1d255d3SCy Schubert hostapd_disassoc_accept_mac(hapd);
384985732ac8SCy Schubert }
385085732ac8SCy Schubert } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
385185732ac8SCy Schubert if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
385285732ac8SCy Schubert if (!hostapd_ctrl_iface_acl_add_mac(
385385732ac8SCy Schubert &hapd->conf->deny_mac,
385485732ac8SCy Schubert &hapd->conf->num_deny_mac, buf + 17))
385585732ac8SCy Schubert hostapd_disassoc_deny_mac(hapd);
3856c1d255d3SCy Schubert else
3857c1d255d3SCy Schubert reply_len = -1;
385885732ac8SCy Schubert } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
3859c1d255d3SCy Schubert if (hostapd_ctrl_iface_acl_del_mac(
386085732ac8SCy Schubert &hapd->conf->deny_mac,
3861c1d255d3SCy Schubert &hapd->conf->num_deny_mac, buf + 17))
3862c1d255d3SCy Schubert reply_len = -1;
386385732ac8SCy Schubert } else if (os_strcmp(buf + 9, "SHOW") == 0) {
386485732ac8SCy Schubert reply_len = hostapd_ctrl_iface_acl_show_mac(
386585732ac8SCy Schubert hapd->conf->deny_mac,
386685732ac8SCy Schubert hapd->conf->num_deny_mac, reply, reply_size);
386785732ac8SCy Schubert } else if (os_strcmp(buf + 9, "CLEAR") == 0) {
386885732ac8SCy Schubert hostapd_ctrl_iface_acl_clear_list(
386985732ac8SCy Schubert &hapd->conf->deny_mac,
387085732ac8SCy Schubert &hapd->conf->num_deny_mac);
387185732ac8SCy Schubert }
387285732ac8SCy Schubert #ifdef CONFIG_DPP
387385732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
387485732ac8SCy Schubert res = hostapd_dpp_qr_code(hapd, buf + 12);
387585732ac8SCy Schubert if (res < 0) {
387685732ac8SCy Schubert reply_len = -1;
387785732ac8SCy Schubert } else {
387885732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
387985732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
388085732ac8SCy Schubert reply_len = -1;
388185732ac8SCy Schubert }
3882c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_NFC_URI ", 12) == 0) {
3883c1d255d3SCy Schubert res = hostapd_dpp_nfc_uri(hapd, buf + 12);
3884c1d255d3SCy Schubert if (res < 0) {
3885c1d255d3SCy Schubert reply_len = -1;
3886c1d255d3SCy Schubert } else {
3887c1d255d3SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
3888c1d255d3SCy Schubert if (os_snprintf_error(reply_size, reply_len))
3889c1d255d3SCy Schubert reply_len = -1;
3890c1d255d3SCy Schubert }
3891c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
3892c1d255d3SCy Schubert res = hostapd_dpp_nfc_handover_req(hapd, buf + 20);
3893c1d255d3SCy Schubert if (res < 0) {
3894c1d255d3SCy Schubert reply_len = -1;
3895c1d255d3SCy Schubert } else {
3896c1d255d3SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
3897c1d255d3SCy Schubert if (os_snprintf_error(reply_size, reply_len))
3898c1d255d3SCy Schubert reply_len = -1;
3899c1d255d3SCy Schubert }
3900c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
3901c1d255d3SCy Schubert res = hostapd_dpp_nfc_handover_sel(hapd, buf + 20);
3902c1d255d3SCy Schubert if (res < 0) {
3903c1d255d3SCy Schubert reply_len = -1;
3904c1d255d3SCy Schubert } else {
3905c1d255d3SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
3906c1d255d3SCy Schubert if (os_snprintf_error(reply_size, reply_len))
3907c1d255d3SCy Schubert reply_len = -1;
3908c1d255d3SCy Schubert }
390985732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
39104bc52338SCy Schubert res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
391185732ac8SCy Schubert if (res < 0) {
391285732ac8SCy Schubert reply_len = -1;
391385732ac8SCy Schubert } else {
391485732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
391585732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
391685732ac8SCy Schubert reply_len = -1;
391785732ac8SCy Schubert }
391885732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
39194bc52338SCy Schubert if (dpp_bootstrap_remove(hapd->iface->interfaces->dpp,
39204bc52338SCy Schubert buf + 21) < 0)
392185732ac8SCy Schubert reply_len = -1;
392285732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
392385732ac8SCy Schubert const char *uri;
392485732ac8SCy Schubert
39254bc52338SCy Schubert uri = dpp_bootstrap_get_uri(hapd->iface->interfaces->dpp,
39264bc52338SCy Schubert atoi(buf + 22));
392785732ac8SCy Schubert if (!uri) {
392885732ac8SCy Schubert reply_len = -1;
392985732ac8SCy Schubert } else {
393085732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%s", uri);
393185732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
393285732ac8SCy Schubert reply_len = -1;
393385732ac8SCy Schubert }
393485732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
39354bc52338SCy Schubert reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
39364bc52338SCy Schubert atoi(buf + 19),
393785732ac8SCy Schubert reply, reply_size);
3938c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
3939c1d255d3SCy Schubert if (dpp_bootstrap_set(hapd->iface->interfaces->dpp,
3940c1d255d3SCy Schubert atoi(buf + 18),
3941c1d255d3SCy Schubert os_strchr(buf + 18, ' ')) < 0)
3942c1d255d3SCy Schubert reply_len = -1;
394385732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
394485732ac8SCy Schubert if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
394585732ac8SCy Schubert reply_len = -1;
394685732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
394785732ac8SCy Schubert if (hostapd_dpp_listen(hapd, buf + 11) < 0)
394885732ac8SCy Schubert reply_len = -1;
394985732ac8SCy Schubert } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
395085732ac8SCy Schubert hostapd_dpp_stop(hapd);
395185732ac8SCy Schubert hostapd_dpp_listen_stop(hapd);
395285732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
39534bc52338SCy Schubert res = dpp_configurator_add(hapd->iface->interfaces->dpp,
39544bc52338SCy Schubert buf + 20);
395585732ac8SCy Schubert if (res < 0) {
395685732ac8SCy Schubert reply_len = -1;
395785732ac8SCy Schubert } else {
395885732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
395985732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
396085732ac8SCy Schubert reply_len = -1;
396185732ac8SCy Schubert }
396285732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
39634bc52338SCy Schubert if (dpp_configurator_remove(hapd->iface->interfaces->dpp,
39644bc52338SCy Schubert buf + 24) < 0)
396585732ac8SCy Schubert reply_len = -1;
396685732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
39674bc52338SCy Schubert if (hostapd_dpp_configurator_sign(hapd, buf + 21) < 0)
396885732ac8SCy Schubert reply_len = -1;
396985732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
39704bc52338SCy Schubert reply_len = dpp_configurator_get_key_id(
39714bc52338SCy Schubert hapd->iface->interfaces->dpp,
397285732ac8SCy Schubert atoi(buf + 25),
397385732ac8SCy Schubert reply, reply_size);
397485732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
397585732ac8SCy Schubert res = hostapd_dpp_pkex_add(hapd, buf + 12);
397685732ac8SCy Schubert if (res < 0) {
397785732ac8SCy Schubert reply_len = -1;
397885732ac8SCy Schubert } else {
397985732ac8SCy Schubert reply_len = os_snprintf(reply, reply_size, "%d", res);
398085732ac8SCy Schubert if (os_snprintf_error(reply_size, reply_len))
398185732ac8SCy Schubert reply_len = -1;
398285732ac8SCy Schubert }
398385732ac8SCy Schubert } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
398485732ac8SCy Schubert if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
398585732ac8SCy Schubert reply_len = -1;
3986c1d255d3SCy Schubert #ifdef CONFIG_DPP2
3987c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
3988c1d255d3SCy Schubert if (hostapd_dpp_controller_start(hapd, buf + 20) < 0)
3989c1d255d3SCy Schubert reply_len = -1;
3990c1d255d3SCy Schubert } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
3991c1d255d3SCy Schubert if (hostapd_dpp_controller_start(hapd, NULL) < 0)
3992c1d255d3SCy Schubert reply_len = -1;
3993c1d255d3SCy Schubert } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
3994c1d255d3SCy Schubert dpp_controller_stop(hapd->iface->interfaces->dpp);
3995c1d255d3SCy Schubert } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
3996c1d255d3SCy Schubert if (hostapd_dpp_chirp(hapd, buf + 9) < 0)
3997c1d255d3SCy Schubert reply_len = -1;
3998c1d255d3SCy Schubert } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
3999c1d255d3SCy Schubert hostapd_dpp_chirp_stop(hapd);
4000c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
400185732ac8SCy Schubert #endif /* CONFIG_DPP */
400285732ac8SCy Schubert #ifdef RADIUS_SERVER
400385732ac8SCy Schubert } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
400485732ac8SCy Schubert if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
400585732ac8SCy Schubert reply_len = -1;
400685732ac8SCy Schubert #endif /* RADIUS_SERVER */
40074bc52338SCy Schubert } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
40084bc52338SCy Schubert reply_len = hostapd_ctrl_iface_get_capability(
40094bc52338SCy Schubert hapd, buf + 15, reply, reply_size);
4010c1d255d3SCy Schubert #ifdef CONFIG_PASN
4011c1d255d3SCy Schubert } else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) {
4012c1d255d3SCy Schubert reply_len = ptksa_cache_list(hapd->ptksa, reply, reply_size);
4013c1d255d3SCy Schubert #endif /* CONFIG_PASN */
4014c1d255d3SCy Schubert #ifdef ANDROID
4015c1d255d3SCy Schubert } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
4016c1d255d3SCy Schubert reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply,
4017c1d255d3SCy Schubert reply_size);
4018c1d255d3SCy Schubert #endif /* ANDROID */
401939beb93cSSam Leffler } else {
402039beb93cSSam Leffler os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
402139beb93cSSam Leffler reply_len = 16;
402239beb93cSSam Leffler }
402339beb93cSSam Leffler
402439beb93cSSam Leffler if (reply_len < 0) {
402539beb93cSSam Leffler os_memcpy(reply, "FAIL\n", 5);
402639beb93cSSam Leffler reply_len = 5;
402739beb93cSSam Leffler }
4028325151a3SRui Paulo
4029325151a3SRui Paulo return reply_len;
4030325151a3SRui Paulo }
4031325151a3SRui Paulo
4032325151a3SRui Paulo
hostapd_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)4033325151a3SRui Paulo static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
4034325151a3SRui Paulo void *sock_ctx)
4035325151a3SRui Paulo {
4036325151a3SRui Paulo struct hostapd_data *hapd = eloop_ctx;
4037325151a3SRui Paulo char buf[4096];
4038325151a3SRui Paulo int res;
4039780fb4a2SCy Schubert struct sockaddr_storage from;
4040325151a3SRui Paulo socklen_t fromlen = sizeof(from);
4041780fb4a2SCy Schubert char *reply, *pos = buf;
4042325151a3SRui Paulo const int reply_size = 4096;
4043325151a3SRui Paulo int reply_len;
4044325151a3SRui Paulo int level = MSG_DEBUG;
4045780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4046c1d255d3SCy Schubert unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
4047780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
4048325151a3SRui Paulo
4049325151a3SRui Paulo res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
4050325151a3SRui Paulo (struct sockaddr *) &from, &fromlen);
4051325151a3SRui Paulo if (res < 0) {
4052325151a3SRui Paulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
4053325151a3SRui Paulo strerror(errno));
4054325151a3SRui Paulo return;
4055325151a3SRui Paulo }
4056325151a3SRui Paulo buf[res] = '\0';
4057325151a3SRui Paulo
4058325151a3SRui Paulo reply = os_malloc(reply_size);
4059325151a3SRui Paulo if (reply == NULL) {
4060325151a3SRui Paulo if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
4061325151a3SRui Paulo fromlen) < 0) {
4062325151a3SRui Paulo wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
4063325151a3SRui Paulo strerror(errno));
4064325151a3SRui Paulo }
4065325151a3SRui Paulo return;
4066325151a3SRui Paulo }
4067325151a3SRui Paulo
4068780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4069780fb4a2SCy Schubert if (os_strcmp(buf, "GET_COOKIE") == 0) {
4070780fb4a2SCy Schubert os_memcpy(reply, "COOKIE=", 7);
4071c1d255d3SCy Schubert wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
4072c1d255d3SCy Schubert hapd->ctrl_iface_cookie,
4073c1d255d3SCy Schubert CTRL_IFACE_COOKIE_LEN);
4074c1d255d3SCy Schubert reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
4075780fb4a2SCy Schubert goto done;
4076780fb4a2SCy Schubert }
4077780fb4a2SCy Schubert
4078780fb4a2SCy Schubert if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
4079c1d255d3SCy Schubert hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
4080780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
4081780fb4a2SCy Schubert "CTRL: No cookie in the request - drop request");
4082780fb4a2SCy Schubert os_free(reply);
4083780fb4a2SCy Schubert return;
4084780fb4a2SCy Schubert }
4085780fb4a2SCy Schubert
4086c1d255d3SCy Schubert if (os_memcmp(hapd->ctrl_iface_cookie, lcookie,
4087c1d255d3SCy Schubert CTRL_IFACE_COOKIE_LEN) != 0) {
4088780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
4089780fb4a2SCy Schubert "CTRL: Invalid cookie in the request - drop request");
4090780fb4a2SCy Schubert os_free(reply);
4091780fb4a2SCy Schubert return;
4092780fb4a2SCy Schubert }
4093780fb4a2SCy Schubert
4094c1d255d3SCy Schubert pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
4095780fb4a2SCy Schubert while (*pos == ' ')
4096780fb4a2SCy Schubert pos++;
4097780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
4098780fb4a2SCy Schubert
4099780fb4a2SCy Schubert if (os_strcmp(pos, "PING") == 0)
4100780fb4a2SCy Schubert level = MSG_EXCESSIVE;
4101780fb4a2SCy Schubert wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
4102780fb4a2SCy Schubert
4103780fb4a2SCy Schubert reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
4104325151a3SRui Paulo reply, reply_size,
4105325151a3SRui Paulo &from, fromlen);
4106325151a3SRui Paulo
4107780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4108780fb4a2SCy Schubert done:
4109780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
41105b9c547cSRui Paulo if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
41115b9c547cSRui Paulo fromlen) < 0) {
41125b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
41135b9c547cSRui Paulo strerror(errno));
41145b9c547cSRui Paulo }
411539beb93cSSam Leffler os_free(reply);
411639beb93cSSam Leffler }
411739beb93cSSam Leffler
411839beb93cSSam Leffler
4119780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
hostapd_ctrl_iface_path(struct hostapd_data * hapd)412039beb93cSSam Leffler static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
412139beb93cSSam Leffler {
412239beb93cSSam Leffler char *buf;
412339beb93cSSam Leffler size_t len;
412439beb93cSSam Leffler
412539beb93cSSam Leffler if (hapd->conf->ctrl_interface == NULL)
412639beb93cSSam Leffler return NULL;
412739beb93cSSam Leffler
412839beb93cSSam Leffler len = os_strlen(hapd->conf->ctrl_interface) +
412939beb93cSSam Leffler os_strlen(hapd->conf->iface) + 2;
413039beb93cSSam Leffler buf = os_malloc(len);
413139beb93cSSam Leffler if (buf == NULL)
413239beb93cSSam Leffler return NULL;
413339beb93cSSam Leffler
413439beb93cSSam Leffler os_snprintf(buf, len, "%s/%s",
413539beb93cSSam Leffler hapd->conf->ctrl_interface, hapd->conf->iface);
413639beb93cSSam Leffler buf[len - 1] = '\0';
413739beb93cSSam Leffler return buf;
413839beb93cSSam Leffler }
4139780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
414039beb93cSSam Leffler
414139beb93cSSam Leffler
hostapd_ctrl_iface_msg_cb(void * ctx,int level,enum wpa_msg_type type,const char * txt,size_t len)4142325151a3SRui Paulo static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
4143325151a3SRui Paulo enum wpa_msg_type type,
414439beb93cSSam Leffler const char *txt, size_t len)
414539beb93cSSam Leffler {
414639beb93cSSam Leffler struct hostapd_data *hapd = ctx;
414739beb93cSSam Leffler if (hapd == NULL)
414839beb93cSSam Leffler return;
4149325151a3SRui Paulo hostapd_ctrl_iface_send(hapd, level, type, txt, len);
415039beb93cSSam Leffler }
415139beb93cSSam Leffler
415239beb93cSSam Leffler
hostapd_ctrl_iface_init(struct hostapd_data * hapd)415339beb93cSSam Leffler int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
415439beb93cSSam Leffler {
4155780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4156780fb4a2SCy Schubert int port = HOSTAPD_CTRL_IFACE_PORT;
4157780fb4a2SCy Schubert char p[32] = { 0 };
4158780fb4a2SCy Schubert char port_str[40], *tmp;
4159780fb4a2SCy Schubert char *pos;
4160780fb4a2SCy Schubert struct addrinfo hints = { 0 }, *res, *saveres;
4161780fb4a2SCy Schubert int n;
4162780fb4a2SCy Schubert
4163780fb4a2SCy Schubert if (hapd->ctrl_sock > -1) {
4164780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
4165780fb4a2SCy Schubert return 0;
4166780fb4a2SCy Schubert }
4167780fb4a2SCy Schubert
4168780fb4a2SCy Schubert if (hapd->conf->ctrl_interface == NULL)
4169780fb4a2SCy Schubert return 0;
4170780fb4a2SCy Schubert
4171780fb4a2SCy Schubert pos = os_strstr(hapd->conf->ctrl_interface, "udp:");
4172780fb4a2SCy Schubert if (pos) {
4173780fb4a2SCy Schubert pos += 4;
4174780fb4a2SCy Schubert port = atoi(pos);
4175780fb4a2SCy Schubert if (port <= 0) {
4176780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port");
4177780fb4a2SCy Schubert goto fail;
4178780fb4a2SCy Schubert }
4179780fb4a2SCy Schubert }
4180780fb4a2SCy Schubert
4181780fb4a2SCy Schubert dl_list_init(&hapd->ctrl_dst);
4182780fb4a2SCy Schubert hapd->ctrl_sock = -1;
4183c1d255d3SCy Schubert os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
4184780fb4a2SCy Schubert
4185780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
4186780fb4a2SCy Schubert hints.ai_flags = AI_PASSIVE;
4187780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
4188780fb4a2SCy Schubert
4189780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
4190780fb4a2SCy Schubert hints.ai_family = AF_INET6;
4191780fb4a2SCy Schubert #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4192780fb4a2SCy Schubert hints.ai_family = AF_INET;
4193780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4194780fb4a2SCy Schubert hints.ai_socktype = SOCK_DGRAM;
4195780fb4a2SCy Schubert
4196780fb4a2SCy Schubert try_again:
4197780fb4a2SCy Schubert os_snprintf(p, sizeof(p), "%d", port);
4198780fb4a2SCy Schubert n = getaddrinfo(NULL, p, &hints, &res);
4199780fb4a2SCy Schubert if (n) {
4200780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
4201780fb4a2SCy Schubert goto fail;
4202780fb4a2SCy Schubert }
4203780fb4a2SCy Schubert
4204780fb4a2SCy Schubert saveres = res;
4205780fb4a2SCy Schubert hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
4206780fb4a2SCy Schubert res->ai_protocol);
4207780fb4a2SCy Schubert if (hapd->ctrl_sock < 0) {
4208780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
4209780fb4a2SCy Schubert goto fail;
4210780fb4a2SCy Schubert }
4211780fb4a2SCy Schubert
4212780fb4a2SCy Schubert if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
4213780fb4a2SCy Schubert port--;
4214780fb4a2SCy Schubert if ((HOSTAPD_CTRL_IFACE_PORT - port) <
4215780fb4a2SCy Schubert HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos)
4216780fb4a2SCy Schubert goto try_again;
4217780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
4218780fb4a2SCy Schubert goto fail;
4219780fb4a2SCy Schubert }
4220780fb4a2SCy Schubert
4221780fb4a2SCy Schubert freeaddrinfo(saveres);
4222780fb4a2SCy Schubert
4223780fb4a2SCy Schubert os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
4224780fb4a2SCy Schubert tmp = os_strdup(port_str);
4225780fb4a2SCy Schubert if (tmp) {
4226780fb4a2SCy Schubert os_free(hapd->conf->ctrl_interface);
4227780fb4a2SCy Schubert hapd->conf->ctrl_interface = tmp;
4228780fb4a2SCy Schubert }
4229780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
4230780fb4a2SCy Schubert
4231780fb4a2SCy Schubert if (eloop_register_read_sock(hapd->ctrl_sock,
4232780fb4a2SCy Schubert hostapd_ctrl_iface_receive, hapd, NULL) <
4233780fb4a2SCy Schubert 0) {
4234780fb4a2SCy Schubert hostapd_ctrl_iface_deinit(hapd);
4235780fb4a2SCy Schubert return -1;
4236780fb4a2SCy Schubert }
4237780fb4a2SCy Schubert
4238780fb4a2SCy Schubert hapd->msg_ctx = hapd;
4239780fb4a2SCy Schubert wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
4240780fb4a2SCy Schubert
4241780fb4a2SCy Schubert return 0;
4242780fb4a2SCy Schubert
4243780fb4a2SCy Schubert fail:
4244780fb4a2SCy Schubert if (hapd->ctrl_sock >= 0)
4245780fb4a2SCy Schubert close(hapd->ctrl_sock);
4246780fb4a2SCy Schubert return -1;
4247780fb4a2SCy Schubert #else /* CONFIG_CTRL_IFACE_UDP */
424839beb93cSSam Leffler struct sockaddr_un addr;
424939beb93cSSam Leffler int s = -1;
425039beb93cSSam Leffler char *fname = NULL;
425139beb93cSSam Leffler
4252f05cddf9SRui Paulo if (hapd->ctrl_sock > -1) {
4253f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
4254f05cddf9SRui Paulo return 0;
4255f05cddf9SRui Paulo }
425639beb93cSSam Leffler
4257780fb4a2SCy Schubert dl_list_init(&hapd->ctrl_dst);
4258780fb4a2SCy Schubert
425939beb93cSSam Leffler if (hapd->conf->ctrl_interface == NULL)
426039beb93cSSam Leffler return 0;
426139beb93cSSam Leffler
426239beb93cSSam Leffler if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
426339beb93cSSam Leffler if (errno == EEXIST) {
426439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Using existing control "
426539beb93cSSam Leffler "interface directory.");
426639beb93cSSam Leffler } else {
42675b9c547cSRui Paulo wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
42685b9c547cSRui Paulo strerror(errno));
426939beb93cSSam Leffler goto fail;
427039beb93cSSam Leffler }
427139beb93cSSam Leffler }
427239beb93cSSam Leffler
427339beb93cSSam Leffler if (hapd->conf->ctrl_interface_gid_set &&
42744bc52338SCy Schubert lchown(hapd->conf->ctrl_interface, -1,
427539beb93cSSam Leffler hapd->conf->ctrl_interface_gid) < 0) {
42764bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
42775b9c547cSRui Paulo strerror(errno));
42785b9c547cSRui Paulo return -1;
42795b9c547cSRui Paulo }
42805b9c547cSRui Paulo
42815b9c547cSRui Paulo if (!hapd->conf->ctrl_interface_gid_set &&
42825b9c547cSRui Paulo hapd->iface->interfaces->ctrl_iface_group &&
42834bc52338SCy Schubert lchown(hapd->conf->ctrl_interface, -1,
42845b9c547cSRui Paulo hapd->iface->interfaces->ctrl_iface_group) < 0) {
42854bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
42865b9c547cSRui Paulo strerror(errno));
428739beb93cSSam Leffler return -1;
428839beb93cSSam Leffler }
428939beb93cSSam Leffler
4290f05cddf9SRui Paulo #ifdef ANDROID
4291f05cddf9SRui Paulo /*
4292f05cddf9SRui Paulo * Android is using umask 0077 which would leave the control interface
4293f05cddf9SRui Paulo * directory without group access. This breaks things since Wi-Fi
4294f05cddf9SRui Paulo * framework assumes that this directory can be accessed by other
4295f05cddf9SRui Paulo * applications in the wifi group. Fix this by adding group access even
4296f05cddf9SRui Paulo * if umask value would prevent this.
4297f05cddf9SRui Paulo */
4298f05cddf9SRui Paulo if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
4299f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
4300f05cddf9SRui Paulo strerror(errno));
4301f05cddf9SRui Paulo /* Try to continue anyway */
4302f05cddf9SRui Paulo }
4303f05cddf9SRui Paulo #endif /* ANDROID */
4304f05cddf9SRui Paulo
430539beb93cSSam Leffler if (os_strlen(hapd->conf->ctrl_interface) + 1 +
430639beb93cSSam Leffler os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
430739beb93cSSam Leffler goto fail;
430839beb93cSSam Leffler
430939beb93cSSam Leffler s = socket(PF_UNIX, SOCK_DGRAM, 0);
431039beb93cSSam Leffler if (s < 0) {
43115b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
431239beb93cSSam Leffler goto fail;
431339beb93cSSam Leffler }
431439beb93cSSam Leffler
431539beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr));
43163157ba21SRui Paulo #ifdef __FreeBSD__
43173157ba21SRui Paulo addr.sun_len = sizeof(addr);
43183157ba21SRui Paulo #endif /* __FreeBSD__ */
431939beb93cSSam Leffler addr.sun_family = AF_UNIX;
432039beb93cSSam Leffler fname = hostapd_ctrl_iface_path(hapd);
432139beb93cSSam Leffler if (fname == NULL)
432239beb93cSSam Leffler goto fail;
432339beb93cSSam Leffler os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
432439beb93cSSam Leffler if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
43253157ba21SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
43263157ba21SRui Paulo strerror(errno));
43273157ba21SRui Paulo if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
43283157ba21SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
43293157ba21SRui Paulo " allow connections - assuming it was left"
43303157ba21SRui Paulo "over from forced program termination");
43313157ba21SRui Paulo if (unlink(fname) < 0) {
43325b9c547cSRui Paulo wpa_printf(MSG_ERROR,
43335b9c547cSRui Paulo "Could not unlink existing ctrl_iface socket '%s': %s",
43345b9c547cSRui Paulo fname, strerror(errno));
43353157ba21SRui Paulo goto fail;
43363157ba21SRui Paulo }
43373157ba21SRui Paulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
43383157ba21SRui Paulo 0) {
43395b9c547cSRui Paulo wpa_printf(MSG_ERROR,
43405b9c547cSRui Paulo "hostapd-ctrl-iface: bind(PF_UNIX): %s",
43415b9c547cSRui Paulo strerror(errno));
434239beb93cSSam Leffler goto fail;
434339beb93cSSam Leffler }
43443157ba21SRui Paulo wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
43453157ba21SRui Paulo "ctrl_iface socket '%s'", fname);
43463157ba21SRui Paulo } else {
43473157ba21SRui Paulo wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
43483157ba21SRui Paulo "be in use - cannot override it");
43493157ba21SRui Paulo wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
43503157ba21SRui Paulo "not used anymore", fname);
43513157ba21SRui Paulo os_free(fname);
43523157ba21SRui Paulo fname = NULL;
43533157ba21SRui Paulo goto fail;
43543157ba21SRui Paulo }
43553157ba21SRui Paulo }
435639beb93cSSam Leffler
435739beb93cSSam Leffler if (hapd->conf->ctrl_interface_gid_set &&
43584bc52338SCy Schubert lchown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
43594bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
43605b9c547cSRui Paulo strerror(errno));
43615b9c547cSRui Paulo goto fail;
43625b9c547cSRui Paulo }
43635b9c547cSRui Paulo
43645b9c547cSRui Paulo if (!hapd->conf->ctrl_interface_gid_set &&
43655b9c547cSRui Paulo hapd->iface->interfaces->ctrl_iface_group &&
43664bc52338SCy Schubert lchown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
43674bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
43685b9c547cSRui Paulo strerror(errno));
436939beb93cSSam Leffler goto fail;
437039beb93cSSam Leffler }
437139beb93cSSam Leffler
437239beb93cSSam Leffler if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
43735b9c547cSRui Paulo wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
43745b9c547cSRui Paulo strerror(errno));
437539beb93cSSam Leffler goto fail;
437639beb93cSSam Leffler }
437739beb93cSSam Leffler os_free(fname);
437839beb93cSSam Leffler
437939beb93cSSam Leffler hapd->ctrl_sock = s;
43805b9c547cSRui Paulo if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
43815b9c547cSRui Paulo NULL) < 0) {
43825b9c547cSRui Paulo hostapd_ctrl_iface_deinit(hapd);
43835b9c547cSRui Paulo return -1;
43845b9c547cSRui Paulo }
4385e28a4053SRui Paulo hapd->msg_ctx = hapd;
438639beb93cSSam Leffler wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
438739beb93cSSam Leffler
438839beb93cSSam Leffler return 0;
438939beb93cSSam Leffler
439039beb93cSSam Leffler fail:
439139beb93cSSam Leffler if (s >= 0)
439239beb93cSSam Leffler close(s);
439339beb93cSSam Leffler if (fname) {
439439beb93cSSam Leffler unlink(fname);
439539beb93cSSam Leffler os_free(fname);
439639beb93cSSam Leffler }
439739beb93cSSam Leffler return -1;
4398780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
439939beb93cSSam Leffler }
440039beb93cSSam Leffler
440139beb93cSSam Leffler
hostapd_ctrl_iface_deinit(struct hostapd_data * hapd)440239beb93cSSam Leffler void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
440339beb93cSSam Leffler {
440439beb93cSSam Leffler struct wpa_ctrl_dst *dst, *prev;
440539beb93cSSam Leffler
440639beb93cSSam Leffler if (hapd->ctrl_sock > -1) {
4407780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
440839beb93cSSam Leffler char *fname;
4409780fb4a2SCy Schubert #endif /* !CONFIG_CTRL_IFACE_UDP */
4410780fb4a2SCy Schubert
441139beb93cSSam Leffler eloop_unregister_read_sock(hapd->ctrl_sock);
441239beb93cSSam Leffler close(hapd->ctrl_sock);
441339beb93cSSam Leffler hapd->ctrl_sock = -1;
4414780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
441539beb93cSSam Leffler fname = hostapd_ctrl_iface_path(hapd);
441639beb93cSSam Leffler if (fname)
441739beb93cSSam Leffler unlink(fname);
441839beb93cSSam Leffler os_free(fname);
441939beb93cSSam Leffler
442039beb93cSSam Leffler if (hapd->conf->ctrl_interface &&
442139beb93cSSam Leffler rmdir(hapd->conf->ctrl_interface) < 0) {
442239beb93cSSam Leffler if (errno == ENOTEMPTY) {
442339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Control interface "
442439beb93cSSam Leffler "directory not empty - leaving it "
442539beb93cSSam Leffler "behind");
442639beb93cSSam Leffler } else {
44275b9c547cSRui Paulo wpa_printf(MSG_ERROR,
44285b9c547cSRui Paulo "rmdir[ctrl_interface=%s]: %s",
44295b9c547cSRui Paulo hapd->conf->ctrl_interface,
44305b9c547cSRui Paulo strerror(errno));
443139beb93cSSam Leffler }
443239beb93cSSam Leffler }
4433780fb4a2SCy Schubert #endif /* !CONFIG_CTRL_IFACE_UDP */
443439beb93cSSam Leffler }
443539beb93cSSam Leffler
4436780fb4a2SCy Schubert dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
4437780fb4a2SCy Schubert list)
4438780fb4a2SCy Schubert os_free(dst);
44395b9c547cSRui Paulo
44405b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
44415b9c547cSRui Paulo l2_packet_deinit(hapd->l2_test);
44425b9c547cSRui Paulo hapd->l2_test = NULL;
44435b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
444439beb93cSSam Leffler }
444539beb93cSSam Leffler
444639beb93cSSam Leffler
hostapd_ctrl_iface_add(struct hapd_interfaces * interfaces,char * buf)4447f05cddf9SRui Paulo static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
4448f05cddf9SRui Paulo char *buf)
4449f05cddf9SRui Paulo {
4450f05cddf9SRui Paulo if (hostapd_add_iface(interfaces, buf) < 0) {
4451f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
4452f05cddf9SRui Paulo return -1;
4453f05cddf9SRui Paulo }
4454f05cddf9SRui Paulo return 0;
4455f05cddf9SRui Paulo }
4456f05cddf9SRui Paulo
4457f05cddf9SRui Paulo
hostapd_ctrl_iface_remove(struct hapd_interfaces * interfaces,char * buf)4458f05cddf9SRui Paulo static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
4459f05cddf9SRui Paulo char *buf)
4460f05cddf9SRui Paulo {
4461f05cddf9SRui Paulo if (hostapd_remove_iface(interfaces, buf) < 0) {
4462f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
4463f05cddf9SRui Paulo return -1;
4464f05cddf9SRui Paulo }
4465f05cddf9SRui Paulo return 0;
4466f05cddf9SRui Paulo }
4467f05cddf9SRui Paulo
4468f05cddf9SRui Paulo
hostapd_global_ctrl_iface_attach(struct hapd_interfaces * interfaces,struct sockaddr_storage * from,socklen_t fromlen,char * input)4469325151a3SRui Paulo static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
4470780fb4a2SCy Schubert struct sockaddr_storage *from,
447185732ac8SCy Schubert socklen_t fromlen, char *input)
4472325151a3SRui Paulo {
447385732ac8SCy Schubert return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen,
447485732ac8SCy Schubert input);
4475325151a3SRui Paulo }
4476325151a3SRui Paulo
4477325151a3SRui Paulo
hostapd_global_ctrl_iface_detach(struct hapd_interfaces * interfaces,struct sockaddr_storage * from,socklen_t fromlen)4478325151a3SRui Paulo static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
4479780fb4a2SCy Schubert struct sockaddr_storage *from,
4480325151a3SRui Paulo socklen_t fromlen)
4481325151a3SRui Paulo {
4482780fb4a2SCy Schubert return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen);
4483325151a3SRui Paulo }
4484325151a3SRui Paulo
4485325151a3SRui Paulo
hostapd_ctrl_iface_flush(struct hapd_interfaces * interfaces)44865b9c547cSRui Paulo static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
44875b9c547cSRui Paulo {
44885b9c547cSRui Paulo #ifdef CONFIG_WPS_TESTING
44895b9c547cSRui Paulo wps_version_number = 0x20;
44904b72b91aSCy Schubert wps_testing_stub_cred = 0;
44915b9c547cSRui Paulo wps_corrupt_pkhash = 0;
44925b9c547cSRui Paulo #endif /* CONFIG_WPS_TESTING */
449385732ac8SCy Schubert
449485732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
449585732ac8SCy Schubert #ifdef CONFIG_DPP
449685732ac8SCy Schubert dpp_test = DPP_TEST_DISABLED;
449732a95656SCy Schubert #ifdef CONFIG_DPP3
449832a95656SCy Schubert dpp_version_override = 3;
449932a95656SCy Schubert #elif defined(CONFIG_DPP2)
4500c1d255d3SCy Schubert dpp_version_override = 2;
4501c1d255d3SCy Schubert #else /* CONFIG_DPP2 */
4502c1d255d3SCy Schubert dpp_version_override = 1;
4503c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
450485732ac8SCy Schubert #endif /* CONFIG_DPP */
450585732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
450685732ac8SCy Schubert
450785732ac8SCy Schubert #ifdef CONFIG_DPP
45084bc52338SCy Schubert dpp_global_clear(interfaces->dpp);
450985732ac8SCy Schubert #endif /* CONFIG_DPP */
45105b9c547cSRui Paulo }
45115b9c547cSRui Paulo
45125b9c547cSRui Paulo
4513325151a3SRui Paulo #ifdef CONFIG_FST
4514325151a3SRui Paulo
4515325151a3SRui Paulo static int
hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces * interfaces,const char * cmd)4516325151a3SRui Paulo hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces *interfaces,
4517325151a3SRui Paulo const char *cmd)
4518325151a3SRui Paulo {
4519325151a3SRui Paulo char ifname[IFNAMSIZ + 1];
4520325151a3SRui Paulo struct fst_iface_cfg cfg;
4521325151a3SRui Paulo struct hostapd_data *hapd;
4522325151a3SRui Paulo struct fst_wpa_obj iface_obj;
4523325151a3SRui Paulo
4524325151a3SRui Paulo if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
4525325151a3SRui Paulo hapd = hostapd_get_iface(interfaces, ifname);
4526325151a3SRui Paulo if (hapd) {
4527325151a3SRui Paulo if (hapd->iface->fst) {
4528325151a3SRui Paulo wpa_printf(MSG_INFO, "FST: Already attached");
4529325151a3SRui Paulo return -1;
4530325151a3SRui Paulo }
4531325151a3SRui Paulo fst_hostapd_fill_iface_obj(hapd, &iface_obj);
4532325151a3SRui Paulo hapd->iface->fst = fst_attach(ifname, hapd->own_addr,
4533325151a3SRui Paulo &iface_obj, &cfg);
4534325151a3SRui Paulo if (hapd->iface->fst)
4535325151a3SRui Paulo return 0;
4536325151a3SRui Paulo }
4537325151a3SRui Paulo }
4538325151a3SRui Paulo
4539325151a3SRui Paulo return -EINVAL;
4540325151a3SRui Paulo }
4541325151a3SRui Paulo
4542325151a3SRui Paulo
4543325151a3SRui Paulo static int
hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces * interfaces,const char * cmd)4544325151a3SRui Paulo hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces *interfaces,
4545325151a3SRui Paulo const char *cmd)
4546325151a3SRui Paulo {
4547325151a3SRui Paulo char ifname[IFNAMSIZ + 1];
4548325151a3SRui Paulo struct hostapd_data * hapd;
4549325151a3SRui Paulo
4550325151a3SRui Paulo if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
4551325151a3SRui Paulo hapd = hostapd_get_iface(interfaces, ifname);
4552325151a3SRui Paulo if (hapd) {
4553325151a3SRui Paulo if (!fst_iface_detach(ifname)) {
4554325151a3SRui Paulo hapd->iface->fst = NULL;
4555325151a3SRui Paulo hapd->iface->fst_ies = NULL;
4556325151a3SRui Paulo return 0;
4557325151a3SRui Paulo }
4558325151a3SRui Paulo }
4559325151a3SRui Paulo }
4560325151a3SRui Paulo
4561325151a3SRui Paulo return -EINVAL;
4562325151a3SRui Paulo }
4563325151a3SRui Paulo
4564325151a3SRui Paulo #endif /* CONFIG_FST */
4565325151a3SRui Paulo
4566325151a3SRui Paulo
4567325151a3SRui Paulo static struct hostapd_data *
hostapd_interfaces_get_hapd(struct hapd_interfaces * interfaces,const char * ifname)4568325151a3SRui Paulo hostapd_interfaces_get_hapd(struct hapd_interfaces *interfaces,
4569325151a3SRui Paulo const char *ifname)
4570325151a3SRui Paulo {
4571325151a3SRui Paulo size_t i, j;
4572325151a3SRui Paulo
4573325151a3SRui Paulo for (i = 0; i < interfaces->count; i++) {
4574325151a3SRui Paulo struct hostapd_iface *iface = interfaces->iface[i];
4575325151a3SRui Paulo
4576325151a3SRui Paulo for (j = 0; j < iface->num_bss; j++) {
4577325151a3SRui Paulo struct hostapd_data *hapd;
4578325151a3SRui Paulo
4579325151a3SRui Paulo hapd = iface->bss[j];
4580325151a3SRui Paulo if (os_strcmp(ifname, hapd->conf->iface) == 0)
4581325151a3SRui Paulo return hapd;
4582325151a3SRui Paulo }
4583325151a3SRui Paulo }
4584325151a3SRui Paulo
4585325151a3SRui Paulo return NULL;
4586325151a3SRui Paulo }
4587325151a3SRui Paulo
4588325151a3SRui Paulo
hostapd_ctrl_iface_dup_param(struct hostapd_data * src_hapd,struct hostapd_data * dst_hapd,const char * param)4589325151a3SRui Paulo static int hostapd_ctrl_iface_dup_param(struct hostapd_data *src_hapd,
4590325151a3SRui Paulo struct hostapd_data *dst_hapd,
4591325151a3SRui Paulo const char *param)
4592325151a3SRui Paulo {
4593325151a3SRui Paulo int res;
4594325151a3SRui Paulo char *value;
4595325151a3SRui Paulo
4596325151a3SRui Paulo value = os_zalloc(HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
4597325151a3SRui Paulo if (!value) {
4598325151a3SRui Paulo wpa_printf(MSG_ERROR,
4599325151a3SRui Paulo "DUP: cannot allocate buffer to stringify %s",
4600325151a3SRui Paulo param);
4601325151a3SRui Paulo goto error_return;
4602325151a3SRui Paulo }
4603325151a3SRui Paulo
4604325151a3SRui Paulo if (os_strcmp(param, "wpa") == 0) {
4605325151a3SRui Paulo os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%d",
4606325151a3SRui Paulo src_hapd->conf->wpa);
4607325151a3SRui Paulo } else if (os_strcmp(param, "wpa_key_mgmt") == 0 &&
4608325151a3SRui Paulo src_hapd->conf->wpa_key_mgmt) {
4609325151a3SRui Paulo res = hostapd_ctrl_iface_get_key_mgmt(
4610325151a3SRui Paulo src_hapd, value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
4611325151a3SRui Paulo if (os_snprintf_error(HOSTAPD_CLI_DUP_VALUE_MAX_LEN, res))
4612325151a3SRui Paulo goto error_stringify;
4613325151a3SRui Paulo } else if (os_strcmp(param, "wpa_pairwise") == 0 &&
4614325151a3SRui Paulo src_hapd->conf->wpa_pairwise) {
4615325151a3SRui Paulo res = wpa_write_ciphers(value,
4616325151a3SRui Paulo value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
4617325151a3SRui Paulo src_hapd->conf->wpa_pairwise, " ");
4618325151a3SRui Paulo if (res < 0)
4619325151a3SRui Paulo goto error_stringify;
4620325151a3SRui Paulo } else if (os_strcmp(param, "rsn_pairwise") == 0 &&
4621325151a3SRui Paulo src_hapd->conf->rsn_pairwise) {
4622325151a3SRui Paulo res = wpa_write_ciphers(value,
4623325151a3SRui Paulo value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
4624325151a3SRui Paulo src_hapd->conf->rsn_pairwise, " ");
4625325151a3SRui Paulo if (res < 0)
4626325151a3SRui Paulo goto error_stringify;
4627325151a3SRui Paulo } else if (os_strcmp(param, "wpa_passphrase") == 0 &&
4628325151a3SRui Paulo src_hapd->conf->ssid.wpa_passphrase) {
4629325151a3SRui Paulo os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%s",
4630325151a3SRui Paulo src_hapd->conf->ssid.wpa_passphrase);
4631325151a3SRui Paulo } else if (os_strcmp(param, "wpa_psk") == 0 &&
4632325151a3SRui Paulo src_hapd->conf->ssid.wpa_psk_set) {
4633325151a3SRui Paulo wpa_snprintf_hex(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
4634325151a3SRui Paulo src_hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
4635325151a3SRui Paulo } else {
4636325151a3SRui Paulo wpa_printf(MSG_WARNING, "DUP: %s cannot be duplicated", param);
4637325151a3SRui Paulo goto error_return;
4638325151a3SRui Paulo }
4639325151a3SRui Paulo
4640325151a3SRui Paulo res = hostapd_set_iface(dst_hapd->iconf, dst_hapd->conf, param, value);
4641325151a3SRui Paulo os_free(value);
4642325151a3SRui Paulo return res;
4643325151a3SRui Paulo
4644325151a3SRui Paulo error_stringify:
4645325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: cannot stringify %s", param);
4646325151a3SRui Paulo error_return:
4647325151a3SRui Paulo os_free(value);
4648325151a3SRui Paulo return -1;
4649325151a3SRui Paulo }
4650325151a3SRui Paulo
4651325151a3SRui Paulo
4652325151a3SRui Paulo static int
hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces * interfaces,const char * input,char * reply,int reply_size)4653780fb4a2SCy Schubert hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces,
4654780fb4a2SCy Schubert const char *input,
4655780fb4a2SCy Schubert char *reply, int reply_size)
4656780fb4a2SCy Schubert {
4657780fb4a2SCy Schubert size_t i, j;
4658780fb4a2SCy Schubert int res;
4659780fb4a2SCy Schubert char *pos, *end;
4660780fb4a2SCy Schubert struct hostapd_iface *iface;
4661780fb4a2SCy Schubert int show_ctrl = 0;
4662780fb4a2SCy Schubert
4663780fb4a2SCy Schubert if (input)
4664780fb4a2SCy Schubert show_ctrl = !!os_strstr(input, "ctrl");
4665780fb4a2SCy Schubert
4666780fb4a2SCy Schubert pos = reply;
4667780fb4a2SCy Schubert end = reply + reply_size;
4668780fb4a2SCy Schubert
4669780fb4a2SCy Schubert for (i = 0; i < interfaces->count; i++) {
4670780fb4a2SCy Schubert iface = interfaces->iface[i];
4671780fb4a2SCy Schubert
4672780fb4a2SCy Schubert for (j = 0; j < iface->num_bss; j++) {
4673780fb4a2SCy Schubert struct hostapd_bss_config *conf;
4674780fb4a2SCy Schubert
4675780fb4a2SCy Schubert conf = iface->conf->bss[j];
4676780fb4a2SCy Schubert if (show_ctrl)
4677780fb4a2SCy Schubert res = os_snprintf(pos, end - pos,
4678780fb4a2SCy Schubert "%s ctrl_iface=%s\n",
4679780fb4a2SCy Schubert conf->iface,
4680780fb4a2SCy Schubert conf->ctrl_interface ?
4681780fb4a2SCy Schubert conf->ctrl_interface : "N/A");
4682780fb4a2SCy Schubert else
4683780fb4a2SCy Schubert res = os_snprintf(pos, end - pos, "%s\n",
4684780fb4a2SCy Schubert conf->iface);
4685780fb4a2SCy Schubert if (os_snprintf_error(end - pos, res)) {
4686780fb4a2SCy Schubert *pos = '\0';
4687780fb4a2SCy Schubert return pos - reply;
4688780fb4a2SCy Schubert }
4689780fb4a2SCy Schubert pos += res;
4690780fb4a2SCy Schubert }
4691780fb4a2SCy Schubert }
4692780fb4a2SCy Schubert
4693780fb4a2SCy Schubert return pos - reply;
4694780fb4a2SCy Schubert }
4695780fb4a2SCy Schubert
4696780fb4a2SCy Schubert
4697780fb4a2SCy Schubert static int
hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces * interfaces,char * cmd)4698325151a3SRui Paulo hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
4699325151a3SRui Paulo char *cmd)
4700325151a3SRui Paulo {
4701325151a3SRui Paulo char *p_start = cmd, *p_end;
4702325151a3SRui Paulo struct hostapd_data *src_hapd, *dst_hapd;
4703325151a3SRui Paulo
4704325151a3SRui Paulo /* cmd: "<src ifname> <dst ifname> <variable name> */
4705325151a3SRui Paulo
4706325151a3SRui Paulo p_end = os_strchr(p_start, ' ');
4707325151a3SRui Paulo if (!p_end) {
4708325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: no src ifname found in cmd: '%s'",
4709325151a3SRui Paulo cmd);
4710325151a3SRui Paulo return -1;
4711325151a3SRui Paulo }
4712325151a3SRui Paulo
4713325151a3SRui Paulo *p_end = '\0';
4714325151a3SRui Paulo src_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
4715325151a3SRui Paulo if (!src_hapd) {
4716325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: no src ifname found: '%s'",
4717325151a3SRui Paulo p_start);
4718325151a3SRui Paulo return -1;
4719325151a3SRui Paulo }
4720325151a3SRui Paulo
4721325151a3SRui Paulo p_start = p_end + 1;
4722325151a3SRui Paulo p_end = os_strchr(p_start, ' ');
4723325151a3SRui Paulo if (!p_end) {
4724325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: no dst ifname found in cmd: '%s'",
4725325151a3SRui Paulo cmd);
4726325151a3SRui Paulo return -1;
4727325151a3SRui Paulo }
4728325151a3SRui Paulo
4729325151a3SRui Paulo *p_end = '\0';
4730325151a3SRui Paulo dst_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
4731325151a3SRui Paulo if (!dst_hapd) {
4732325151a3SRui Paulo wpa_printf(MSG_ERROR, "DUP: no dst ifname found: '%s'",
4733325151a3SRui Paulo p_start);
4734325151a3SRui Paulo return -1;
4735325151a3SRui Paulo }
4736325151a3SRui Paulo
4737325151a3SRui Paulo p_start = p_end + 1;
4738325151a3SRui Paulo return hostapd_ctrl_iface_dup_param(src_hapd, dst_hapd, p_start);
4739325151a3SRui Paulo }
4740325151a3SRui Paulo
4741325151a3SRui 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)4742325151a3SRui Paulo static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
4743325151a3SRui Paulo const char *ifname,
4744325151a3SRui Paulo char *buf, char *reply,
4745325151a3SRui Paulo int reply_size,
4746780fb4a2SCy Schubert struct sockaddr_storage *from,
4747325151a3SRui Paulo socklen_t fromlen)
4748325151a3SRui Paulo {
4749325151a3SRui Paulo struct hostapd_data *hapd;
4750325151a3SRui Paulo
4751325151a3SRui Paulo hapd = hostapd_interfaces_get_hapd(interfaces, ifname);
4752325151a3SRui Paulo if (hapd == NULL) {
4753325151a3SRui Paulo int res;
4754325151a3SRui Paulo
4755325151a3SRui Paulo res = os_snprintf(reply, reply_size, "FAIL-NO-IFNAME-MATCH\n");
4756325151a3SRui Paulo if (os_snprintf_error(reply_size, res))
4757325151a3SRui Paulo return -1;
4758325151a3SRui Paulo return res;
4759325151a3SRui Paulo }
4760325151a3SRui Paulo
4761325151a3SRui Paulo return hostapd_ctrl_iface_receive_process(hapd, buf, reply,reply_size,
4762325151a3SRui Paulo from, fromlen);
4763325151a3SRui Paulo }
4764325151a3SRui Paulo
4765325151a3SRui Paulo
hostapd_global_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)4766f05cddf9SRui Paulo static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
4767f05cddf9SRui Paulo void *sock_ctx)
4768f05cddf9SRui Paulo {
4769c1d255d3SCy Schubert struct hapd_interfaces *interfaces = eloop_ctx;
4770780fb4a2SCy Schubert char buffer[256], *buf = buffer;
4771f05cddf9SRui Paulo int res;
4772780fb4a2SCy Schubert struct sockaddr_storage from;
4773f05cddf9SRui Paulo socklen_t fromlen = sizeof(from);
4774325151a3SRui Paulo char *reply;
4775f05cddf9SRui Paulo int reply_len;
4776325151a3SRui Paulo const int reply_size = 4096;
4777780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4778c1d255d3SCy Schubert unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
4779780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
4780f05cddf9SRui Paulo
4781780fb4a2SCy Schubert res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
4782f05cddf9SRui Paulo (struct sockaddr *) &from, &fromlen);
4783f05cddf9SRui Paulo if (res < 0) {
47845b9c547cSRui Paulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
47855b9c547cSRui Paulo strerror(errno));
4786f05cddf9SRui Paulo return;
4787f05cddf9SRui Paulo }
4788f05cddf9SRui Paulo buf[res] = '\0';
47895b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
4790f05cddf9SRui Paulo
4791325151a3SRui Paulo reply = os_malloc(reply_size);
4792325151a3SRui Paulo if (reply == NULL) {
4793325151a3SRui Paulo if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
4794325151a3SRui Paulo fromlen) < 0) {
4795325151a3SRui Paulo wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
4796325151a3SRui Paulo strerror(errno));
4797325151a3SRui Paulo }
4798325151a3SRui Paulo return;
4799325151a3SRui Paulo }
4800325151a3SRui Paulo
4801f05cddf9SRui Paulo os_memcpy(reply, "OK\n", 3);
4802f05cddf9SRui Paulo reply_len = 3;
4803f05cddf9SRui Paulo
4804780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4805780fb4a2SCy Schubert if (os_strcmp(buf, "GET_COOKIE") == 0) {
4806780fb4a2SCy Schubert os_memcpy(reply, "COOKIE=", 7);
4807c1d255d3SCy Schubert wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
4808c1d255d3SCy Schubert interfaces->ctrl_iface_cookie,
4809c1d255d3SCy Schubert CTRL_IFACE_COOKIE_LEN);
4810c1d255d3SCy Schubert reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
4811780fb4a2SCy Schubert goto send_reply;
4812780fb4a2SCy Schubert }
4813780fb4a2SCy Schubert
4814780fb4a2SCy Schubert if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
4815c1d255d3SCy Schubert hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
4816780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
4817780fb4a2SCy Schubert "CTRL: No cookie in the request - drop request");
4818780fb4a2SCy Schubert os_free(reply);
4819780fb4a2SCy Schubert return;
4820780fb4a2SCy Schubert }
4821780fb4a2SCy Schubert
4822c1d255d3SCy Schubert if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie,
4823c1d255d3SCy Schubert CTRL_IFACE_COOKIE_LEN) != 0) {
4824780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
4825780fb4a2SCy Schubert "CTRL: Invalid cookie in the request - drop request");
4826780fb4a2SCy Schubert os_free(reply);
4827780fb4a2SCy Schubert return;
4828780fb4a2SCy Schubert }
4829780fb4a2SCy Schubert
4830c1d255d3SCy Schubert buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
4831780fb4a2SCy Schubert while (*buf == ' ')
4832780fb4a2SCy Schubert buf++;
4833780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
4834780fb4a2SCy Schubert
4835325151a3SRui Paulo if (os_strncmp(buf, "IFNAME=", 7) == 0) {
4836325151a3SRui Paulo char *pos = os_strchr(buf + 7, ' ');
4837325151a3SRui Paulo
4838325151a3SRui Paulo if (pos) {
4839325151a3SRui Paulo *pos++ = '\0';
4840325151a3SRui Paulo reply_len = hostapd_global_ctrl_iface_ifname(
4841325151a3SRui Paulo interfaces, buf + 7, pos, reply, reply_size,
4842325151a3SRui Paulo &from, fromlen);
4843325151a3SRui Paulo goto send_reply;
4844325151a3SRui Paulo }
4845325151a3SRui Paulo }
4846325151a3SRui Paulo
4847f05cddf9SRui Paulo if (os_strcmp(buf, "PING") == 0) {
4848f05cddf9SRui Paulo os_memcpy(reply, "PONG\n", 5);
4849f05cddf9SRui Paulo reply_len = 5;
48505b9c547cSRui Paulo } else if (os_strncmp(buf, "RELOG", 5) == 0) {
48515b9c547cSRui Paulo if (wpa_debug_reopen_file() < 0)
48525b9c547cSRui Paulo reply_len = -1;
48535b9c547cSRui Paulo } else if (os_strcmp(buf, "FLUSH") == 0) {
48545b9c547cSRui Paulo hostapd_ctrl_iface_flush(interfaces);
4855f05cddf9SRui Paulo } else if (os_strncmp(buf, "ADD ", 4) == 0) {
4856f05cddf9SRui Paulo if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
4857f05cddf9SRui Paulo reply_len = -1;
4858f05cddf9SRui Paulo } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
4859f05cddf9SRui Paulo if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
4860f05cddf9SRui Paulo reply_len = -1;
4861325151a3SRui Paulo } else if (os_strcmp(buf, "ATTACH") == 0) {
4862325151a3SRui Paulo if (hostapd_global_ctrl_iface_attach(interfaces, &from,
486385732ac8SCy Schubert fromlen, NULL))
486485732ac8SCy Schubert reply_len = -1;
486585732ac8SCy Schubert } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
486685732ac8SCy Schubert if (hostapd_global_ctrl_iface_attach(interfaces, &from,
486785732ac8SCy Schubert fromlen, buf + 7))
4868325151a3SRui Paulo reply_len = -1;
4869325151a3SRui Paulo } else if (os_strcmp(buf, "DETACH") == 0) {
4870325151a3SRui Paulo if (hostapd_global_ctrl_iface_detach(interfaces, &from,
4871325151a3SRui Paulo fromlen))
4872325151a3SRui Paulo reply_len = -1;
48735b9c547cSRui Paulo #ifdef CONFIG_MODULE_TESTS
48745b9c547cSRui Paulo } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
48755b9c547cSRui Paulo if (hapd_module_tests() < 0)
48765b9c547cSRui Paulo reply_len = -1;
48775b9c547cSRui Paulo #endif /* CONFIG_MODULE_TESTS */
4878325151a3SRui Paulo #ifdef CONFIG_FST
4879325151a3SRui Paulo } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
4880325151a3SRui Paulo if (!hostapd_global_ctrl_iface_fst_attach(interfaces, buf + 11))
4881325151a3SRui Paulo reply_len = os_snprintf(reply, reply_size, "OK\n");
4882325151a3SRui Paulo else
4883325151a3SRui Paulo reply_len = -1;
4884325151a3SRui Paulo } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
4885325151a3SRui Paulo if (!hostapd_global_ctrl_iface_fst_detach(interfaces, buf + 11))
4886325151a3SRui Paulo reply_len = os_snprintf(reply, reply_size, "OK\n");
4887325151a3SRui Paulo else
4888325151a3SRui Paulo reply_len = -1;
4889325151a3SRui Paulo } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
4890325151a3SRui Paulo reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
4891325151a3SRui Paulo #endif /* CONFIG_FST */
4892325151a3SRui Paulo } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
4893325151a3SRui Paulo if (!hostapd_global_ctrl_iface_dup_network(interfaces,
4894325151a3SRui Paulo buf + 12))
4895325151a3SRui Paulo reply_len = os_snprintf(reply, reply_size, "OK\n");
4896325151a3SRui Paulo else
4897325151a3SRui Paulo reply_len = -1;
4898780fb4a2SCy Schubert } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
4899780fb4a2SCy Schubert reply_len = hostapd_global_ctrl_iface_interfaces(
4900780fb4a2SCy Schubert interfaces, buf + 10, reply, sizeof(buffer));
4901780fb4a2SCy Schubert } else if (os_strcmp(buf, "TERMINATE") == 0) {
4902780fb4a2SCy Schubert eloop_terminate();
4903f05cddf9SRui Paulo } else {
4904f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
4905f05cddf9SRui Paulo "ignored");
4906f05cddf9SRui Paulo reply_len = -1;
4907f05cddf9SRui Paulo }
4908f05cddf9SRui Paulo
4909325151a3SRui Paulo send_reply:
4910f05cddf9SRui Paulo if (reply_len < 0) {
4911f05cddf9SRui Paulo os_memcpy(reply, "FAIL\n", 5);
4912f05cddf9SRui Paulo reply_len = 5;
4913f05cddf9SRui Paulo }
4914f05cddf9SRui Paulo
49155b9c547cSRui Paulo if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
49165b9c547cSRui Paulo fromlen) < 0) {
49175b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
49185b9c547cSRui Paulo strerror(errno));
49195b9c547cSRui Paulo }
4920325151a3SRui Paulo os_free(reply);
4921f05cddf9SRui Paulo }
4922f05cddf9SRui Paulo
4923f05cddf9SRui Paulo
4924780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
hostapd_global_ctrl_iface_path(struct hapd_interfaces * interface)4925f05cddf9SRui Paulo static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
4926f05cddf9SRui Paulo {
4927f05cddf9SRui Paulo char *buf;
4928f05cddf9SRui Paulo size_t len;
4929f05cddf9SRui Paulo
4930f05cddf9SRui Paulo if (interface->global_iface_path == NULL)
4931f05cddf9SRui Paulo return NULL;
4932f05cddf9SRui Paulo
4933f05cddf9SRui Paulo len = os_strlen(interface->global_iface_path) +
4934f05cddf9SRui Paulo os_strlen(interface->global_iface_name) + 2;
4935f05cddf9SRui Paulo buf = os_malloc(len);
4936f05cddf9SRui Paulo if (buf == NULL)
4937f05cddf9SRui Paulo return NULL;
4938f05cddf9SRui Paulo
4939f05cddf9SRui Paulo os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
4940f05cddf9SRui Paulo interface->global_iface_name);
4941f05cddf9SRui Paulo buf[len - 1] = '\0';
4942f05cddf9SRui Paulo return buf;
4943f05cddf9SRui Paulo }
4944780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
4945f05cddf9SRui Paulo
4946f05cddf9SRui Paulo
hostapd_global_ctrl_iface_init(struct hapd_interfaces * interface)4947f05cddf9SRui Paulo int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
4948f05cddf9SRui Paulo {
4949780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP
4950780fb4a2SCy Schubert int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
4951780fb4a2SCy Schubert char p[32] = { 0 };
4952780fb4a2SCy Schubert char *pos;
4953780fb4a2SCy Schubert struct addrinfo hints = { 0 }, *res, *saveres;
4954780fb4a2SCy Schubert int n;
4955780fb4a2SCy Schubert
4956780fb4a2SCy Schubert if (interface->global_ctrl_sock > -1) {
4957780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
4958780fb4a2SCy Schubert return 0;
4959780fb4a2SCy Schubert }
4960780fb4a2SCy Schubert
4961780fb4a2SCy Schubert if (interface->global_iface_path == NULL)
4962780fb4a2SCy Schubert return 0;
4963780fb4a2SCy Schubert
4964780fb4a2SCy Schubert pos = os_strstr(interface->global_iface_path, "udp:");
4965780fb4a2SCy Schubert if (pos) {
4966780fb4a2SCy Schubert pos += 4;
4967780fb4a2SCy Schubert port = atoi(pos);
4968780fb4a2SCy Schubert if (port <= 0) {
4969780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port");
4970780fb4a2SCy Schubert goto fail;
4971780fb4a2SCy Schubert }
4972780fb4a2SCy Schubert }
4973780fb4a2SCy Schubert
4974c1d255d3SCy Schubert os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
4975780fb4a2SCy Schubert
4976780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
4977780fb4a2SCy Schubert hints.ai_flags = AI_PASSIVE;
4978780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
4979780fb4a2SCy Schubert
4980780fb4a2SCy Schubert #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
4981780fb4a2SCy Schubert hints.ai_family = AF_INET6;
4982780fb4a2SCy Schubert #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4983780fb4a2SCy Schubert hints.ai_family = AF_INET;
4984780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4985780fb4a2SCy Schubert hints.ai_socktype = SOCK_DGRAM;
4986780fb4a2SCy Schubert
4987780fb4a2SCy Schubert try_again:
4988780fb4a2SCy Schubert os_snprintf(p, sizeof(p), "%d", port);
4989780fb4a2SCy Schubert n = getaddrinfo(NULL, p, &hints, &res);
4990780fb4a2SCy Schubert if (n) {
4991780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
4992780fb4a2SCy Schubert goto fail;
4993780fb4a2SCy Schubert }
4994780fb4a2SCy Schubert
4995780fb4a2SCy Schubert saveres = res;
4996780fb4a2SCy Schubert interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
4997780fb4a2SCy Schubert res->ai_protocol);
4998780fb4a2SCy Schubert if (interface->global_ctrl_sock < 0) {
4999780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
5000780fb4a2SCy Schubert goto fail;
5001780fb4a2SCy Schubert }
5002780fb4a2SCy Schubert
5003780fb4a2SCy Schubert if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
5004780fb4a2SCy Schubert 0) {
5005780fb4a2SCy Schubert port++;
5006780fb4a2SCy Schubert if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
5007780fb4a2SCy Schubert HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
5008780fb4a2SCy Schubert goto try_again;
5009780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
5010780fb4a2SCy Schubert goto fail;
5011780fb4a2SCy Schubert }
5012780fb4a2SCy Schubert
5013780fb4a2SCy Schubert freeaddrinfo(saveres);
5014780fb4a2SCy Schubert
5015780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
5016780fb4a2SCy Schubert
5017780fb4a2SCy Schubert if (eloop_register_read_sock(interface->global_ctrl_sock,
5018780fb4a2SCy Schubert hostapd_global_ctrl_iface_receive,
5019780fb4a2SCy Schubert interface, NULL) < 0) {
5020780fb4a2SCy Schubert hostapd_global_ctrl_iface_deinit(interface);
5021780fb4a2SCy Schubert return -1;
5022780fb4a2SCy Schubert }
5023780fb4a2SCy Schubert
5024c1d255d3SCy Schubert wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
5025c1d255d3SCy Schubert
5026780fb4a2SCy Schubert return 0;
5027780fb4a2SCy Schubert
5028780fb4a2SCy Schubert fail:
5029780fb4a2SCy Schubert if (interface->global_ctrl_sock >= 0)
5030780fb4a2SCy Schubert close(interface->global_ctrl_sock);
5031780fb4a2SCy Schubert return -1;
5032780fb4a2SCy Schubert #else /* CONFIG_CTRL_IFACE_UDP */
5033f05cddf9SRui Paulo struct sockaddr_un addr;
5034f05cddf9SRui Paulo int s = -1;
5035f05cddf9SRui Paulo char *fname = NULL;
5036f05cddf9SRui Paulo
5037f05cddf9SRui Paulo if (interface->global_iface_path == NULL) {
5038f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
5039f05cddf9SRui Paulo return 0;
5040f05cddf9SRui Paulo }
5041f05cddf9SRui Paulo
5042f05cddf9SRui Paulo if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
5043f05cddf9SRui Paulo if (errno == EEXIST) {
5044f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Using existing control "
5045f05cddf9SRui Paulo "interface directory.");
5046f05cddf9SRui Paulo } else {
50475b9c547cSRui Paulo wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
50485b9c547cSRui Paulo strerror(errno));
5049f05cddf9SRui Paulo goto fail;
5050f05cddf9SRui Paulo }
50515b9c547cSRui Paulo } else if (interface->ctrl_iface_group &&
50524bc52338SCy Schubert lchown(interface->global_iface_path, -1,
50535b9c547cSRui Paulo interface->ctrl_iface_group) < 0) {
50544bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
50555b9c547cSRui Paulo strerror(errno));
50565b9c547cSRui Paulo goto fail;
5057f05cddf9SRui Paulo }
5058f05cddf9SRui Paulo
5059f05cddf9SRui Paulo if (os_strlen(interface->global_iface_path) + 1 +
5060f05cddf9SRui Paulo os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
5061f05cddf9SRui Paulo goto fail;
5062f05cddf9SRui Paulo
5063f05cddf9SRui Paulo s = socket(PF_UNIX, SOCK_DGRAM, 0);
5064f05cddf9SRui Paulo if (s < 0) {
50655b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
5066f05cddf9SRui Paulo goto fail;
5067f05cddf9SRui Paulo }
5068f05cddf9SRui Paulo
5069f05cddf9SRui Paulo os_memset(&addr, 0, sizeof(addr));
5070f05cddf9SRui Paulo #ifdef __FreeBSD__
5071f05cddf9SRui Paulo addr.sun_len = sizeof(addr);
5072f05cddf9SRui Paulo #endif /* __FreeBSD__ */
5073f05cddf9SRui Paulo addr.sun_family = AF_UNIX;
5074f05cddf9SRui Paulo fname = hostapd_global_ctrl_iface_path(interface);
5075f05cddf9SRui Paulo if (fname == NULL)
5076f05cddf9SRui Paulo goto fail;
5077f05cddf9SRui Paulo os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
5078f05cddf9SRui Paulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
5079f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
5080f05cddf9SRui Paulo strerror(errno));
5081f05cddf9SRui Paulo if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
5082f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
5083f05cddf9SRui Paulo " allow connections - assuming it was left"
5084f05cddf9SRui Paulo "over from forced program termination");
5085f05cddf9SRui Paulo if (unlink(fname) < 0) {
50865b9c547cSRui Paulo wpa_printf(MSG_ERROR,
50875b9c547cSRui Paulo "Could not unlink existing ctrl_iface socket '%s': %s",
50885b9c547cSRui Paulo fname, strerror(errno));
5089f05cddf9SRui Paulo goto fail;
5090f05cddf9SRui Paulo }
5091f05cddf9SRui Paulo if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
5092f05cddf9SRui Paulo 0) {
50935b9c547cSRui Paulo wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
50945b9c547cSRui Paulo strerror(errno));
5095f05cddf9SRui Paulo goto fail;
5096f05cddf9SRui Paulo }
5097f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
5098f05cddf9SRui Paulo "ctrl_iface socket '%s'", fname);
5099f05cddf9SRui Paulo } else {
5100f05cddf9SRui Paulo wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
5101f05cddf9SRui Paulo "be in use - cannot override it");
5102f05cddf9SRui Paulo wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
5103f05cddf9SRui Paulo "not used anymore", fname);
5104f05cddf9SRui Paulo os_free(fname);
5105f05cddf9SRui Paulo fname = NULL;
5106f05cddf9SRui Paulo goto fail;
5107f05cddf9SRui Paulo }
5108f05cddf9SRui Paulo }
5109f05cddf9SRui Paulo
51105b9c547cSRui Paulo if (interface->ctrl_iface_group &&
51114bc52338SCy Schubert lchown(fname, -1, interface->ctrl_iface_group) < 0) {
51124bc52338SCy Schubert wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
51135b9c547cSRui Paulo strerror(errno));
51145b9c547cSRui Paulo goto fail;
51155b9c547cSRui Paulo }
51165b9c547cSRui Paulo
5117f05cddf9SRui Paulo if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
51185b9c547cSRui Paulo wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
51195b9c547cSRui Paulo strerror(errno));
5120f05cddf9SRui Paulo goto fail;
5121f05cddf9SRui Paulo }
5122f05cddf9SRui Paulo os_free(fname);
5123f05cddf9SRui Paulo
5124f05cddf9SRui Paulo interface->global_ctrl_sock = s;
5125f05cddf9SRui Paulo eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
5126f05cddf9SRui Paulo interface, NULL);
5127f05cddf9SRui Paulo
5128c1d255d3SCy Schubert wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
5129c1d255d3SCy Schubert
5130f05cddf9SRui Paulo return 0;
5131f05cddf9SRui Paulo
5132f05cddf9SRui Paulo fail:
5133f05cddf9SRui Paulo if (s >= 0)
5134f05cddf9SRui Paulo close(s);
5135f05cddf9SRui Paulo if (fname) {
5136f05cddf9SRui Paulo unlink(fname);
5137f05cddf9SRui Paulo os_free(fname);
5138f05cddf9SRui Paulo }
5139f05cddf9SRui Paulo return -1;
5140780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
5141f05cddf9SRui Paulo }
5142f05cddf9SRui Paulo
5143f05cddf9SRui Paulo
hostapd_global_ctrl_iface_deinit(struct hapd_interfaces * interfaces)5144f05cddf9SRui Paulo void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
5145f05cddf9SRui Paulo {
5146780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
5147f05cddf9SRui Paulo char *fname = NULL;
5148780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
5149325151a3SRui Paulo struct wpa_ctrl_dst *dst, *prev;
5150f05cddf9SRui Paulo
5151f05cddf9SRui Paulo if (interfaces->global_ctrl_sock > -1) {
5152f05cddf9SRui Paulo eloop_unregister_read_sock(interfaces->global_ctrl_sock);
5153f05cddf9SRui Paulo close(interfaces->global_ctrl_sock);
5154f05cddf9SRui Paulo interfaces->global_ctrl_sock = -1;
5155780fb4a2SCy Schubert #ifndef CONFIG_CTRL_IFACE_UDP
5156f05cddf9SRui Paulo fname = hostapd_global_ctrl_iface_path(interfaces);
5157f05cddf9SRui Paulo if (fname) {
5158f05cddf9SRui Paulo unlink(fname);
5159f05cddf9SRui Paulo os_free(fname);
5160f05cddf9SRui Paulo }
5161f05cddf9SRui Paulo
5162f05cddf9SRui Paulo if (interfaces->global_iface_path &&
5163f05cddf9SRui Paulo rmdir(interfaces->global_iface_path) < 0) {
5164f05cddf9SRui Paulo if (errno == ENOTEMPTY) {
5165f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Control interface "
5166f05cddf9SRui Paulo "directory not empty - leaving it "
5167f05cddf9SRui Paulo "behind");
5168f05cddf9SRui Paulo } else {
51695b9c547cSRui Paulo wpa_printf(MSG_ERROR,
51705b9c547cSRui Paulo "rmdir[ctrl_interface=%s]: %s",
51715b9c547cSRui Paulo interfaces->global_iface_path,
51725b9c547cSRui Paulo strerror(errno));
5173f05cddf9SRui Paulo }
5174f05cddf9SRui Paulo }
5175780fb4a2SCy Schubert #endif /* CONFIG_CTRL_IFACE_UDP */
5176325151a3SRui Paulo }
5177325151a3SRui Paulo
5178f05cddf9SRui Paulo os_free(interfaces->global_iface_path);
5179f05cddf9SRui Paulo interfaces->global_iface_path = NULL;
5180325151a3SRui Paulo
5181780fb4a2SCy Schubert dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst,
5182780fb4a2SCy Schubert struct wpa_ctrl_dst, list)
5183780fb4a2SCy Schubert os_free(dst);
5184f05cddf9SRui Paulo }
5185f05cddf9SRui Paulo
5186f05cddf9SRui Paulo
hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst * dst,const char * buf)518785732ac8SCy Schubert static int hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst *dst,
518885732ac8SCy Schubert const char *buf)
518985732ac8SCy Schubert {
519085732ac8SCy Schubert /* Enable Probe Request events based on explicit request.
519185732ac8SCy Schubert * Other events are enabled by default.
519285732ac8SCy Schubert */
519385732ac8SCy Schubert if (str_starts(buf, RX_PROBE_REQUEST))
519485732ac8SCy Schubert return !!(dst->events & WPA_EVENT_RX_PROBE_REQUEST);
519585732ac8SCy Schubert return 1;
519685732ac8SCy Schubert }
519785732ac8SCy Schubert
519885732ac8SCy Schubert
hostapd_ctrl_iface_send_internal(int sock,struct dl_list * ctrl_dst,const char * ifname,int level,const char * buf,size_t len)5199c1d255d3SCy Schubert static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst,
5200c1d255d3SCy Schubert const char *ifname, int level,
520139beb93cSSam Leffler const char *buf, size_t len)
520239beb93cSSam Leffler {
520339beb93cSSam Leffler struct wpa_ctrl_dst *dst, *next;
520439beb93cSSam Leffler struct msghdr msg;
5205c1d255d3SCy Schubert int idx, res;
5206c1d255d3SCy Schubert struct iovec io[5];
520739beb93cSSam Leffler char levelstr[10];
520839beb93cSSam Leffler
5209c1d255d3SCy Schubert if (sock < 0 || dl_list_empty(ctrl_dst))
521039beb93cSSam Leffler return;
521139beb93cSSam Leffler
5212c1d255d3SCy Schubert res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
5213c1d255d3SCy Schubert if (os_snprintf_error(sizeof(levelstr), res))
5214c1d255d3SCy Schubert return;
5215c1d255d3SCy Schubert idx = 0;
5216c1d255d3SCy Schubert if (ifname) {
5217c1d255d3SCy Schubert io[idx].iov_base = "IFNAME=";
5218c1d255d3SCy Schubert io[idx].iov_len = 7;
5219c1d255d3SCy Schubert idx++;
5220c1d255d3SCy Schubert io[idx].iov_base = (char *) ifname;
5221c1d255d3SCy Schubert io[idx].iov_len = os_strlen(ifname);
5222c1d255d3SCy Schubert idx++;
5223c1d255d3SCy Schubert io[idx].iov_base = " ";
5224c1d255d3SCy Schubert io[idx].iov_len = 1;
5225c1d255d3SCy Schubert idx++;
5226c1d255d3SCy Schubert }
5227c1d255d3SCy Schubert io[idx].iov_base = levelstr;
5228c1d255d3SCy Schubert io[idx].iov_len = os_strlen(levelstr);
5229c1d255d3SCy Schubert idx++;
5230c1d255d3SCy Schubert io[idx].iov_base = (char *) buf;
5231c1d255d3SCy Schubert io[idx].iov_len = len;
5232c1d255d3SCy Schubert idx++;
523339beb93cSSam Leffler os_memset(&msg, 0, sizeof(msg));
523439beb93cSSam Leffler msg.msg_iov = io;
5235c1d255d3SCy Schubert msg.msg_iovlen = idx;
523639beb93cSSam Leffler
523739beb93cSSam Leffler idx = 0;
5238780fb4a2SCy Schubert dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
523985732ac8SCy Schubert if ((level >= dst->debug_level) &&
524085732ac8SCy Schubert hostapd_ctrl_check_event_enabled(dst, buf)) {
5241780fb4a2SCy Schubert sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
5242780fb4a2SCy Schubert &dst->addr, dst->addrlen);
524339beb93cSSam Leffler msg.msg_name = &dst->addr;
524439beb93cSSam Leffler msg.msg_namelen = dst->addrlen;
5245c1d255d3SCy Schubert if (sendmsg(sock, &msg, 0) < 0) {
52463157ba21SRui Paulo int _errno = errno;
52473157ba21SRui Paulo wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
52483157ba21SRui Paulo "%d - %s",
52493157ba21SRui Paulo idx, errno, strerror(errno));
525039beb93cSSam Leffler dst->errors++;
52513157ba21SRui Paulo if (dst->errors > 10 || _errno == ENOENT) {
5252c1d255d3SCy Schubert ctrl_iface_detach(ctrl_dst,
5253325151a3SRui Paulo &dst->addr,
5254325151a3SRui Paulo dst->addrlen);
525539beb93cSSam Leffler }
525639beb93cSSam Leffler } else
525739beb93cSSam Leffler dst->errors = 0;
525839beb93cSSam Leffler }
525939beb93cSSam Leffler idx++;
526039beb93cSSam Leffler }
526139beb93cSSam Leffler }
526239beb93cSSam Leffler
5263c1d255d3SCy Schubert
hostapd_ctrl_iface_send(struct hostapd_data * hapd,int level,enum wpa_msg_type type,const char * buf,size_t len)5264c1d255d3SCy Schubert static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
5265c1d255d3SCy Schubert enum wpa_msg_type type,
5266c1d255d3SCy Schubert const char *buf, size_t len)
5267c1d255d3SCy Schubert {
5268c1d255d3SCy Schubert if (type != WPA_MSG_NO_GLOBAL) {
5269c1d255d3SCy Schubert hostapd_ctrl_iface_send_internal(
5270c1d255d3SCy Schubert hapd->iface->interfaces->global_ctrl_sock,
5271c1d255d3SCy Schubert &hapd->iface->interfaces->global_ctrl_dst,
5272c1d255d3SCy Schubert type != WPA_MSG_PER_INTERFACE ?
5273c1d255d3SCy Schubert NULL : hapd->conf->iface,
5274c1d255d3SCy Schubert level, buf, len);
5275c1d255d3SCy Schubert }
5276c1d255d3SCy Schubert
5277c1d255d3SCy Schubert if (type != WPA_MSG_ONLY_GLOBAL) {
5278c1d255d3SCy Schubert hostapd_ctrl_iface_send_internal(
5279c1d255d3SCy Schubert hapd->ctrl_sock, &hapd->ctrl_dst,
5280c1d255d3SCy Schubert NULL, level, buf, len);
5281c1d255d3SCy Schubert }
5282c1d255d3SCy Schubert }
5283c1d255d3SCy Schubert
528439beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
5285