18dbcf02cSchristos /*
28dbcf02cSchristos * hostapd / UNIX domain socket -based control interface
3ebb5671cSchristos * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
48dbcf02cSchristos *
562a52023Schristos * This software may be distributed under the terms of the BSD license.
662a52023Schristos * See README for more details.
78dbcf02cSchristos */
88dbcf02cSchristos
98dbcf02cSchristos #include "utils/includes.h"
108dbcf02cSchristos
118dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS
128dbcf02cSchristos
139a53cbbeSchristos #ifdef CONFIG_TESTING_OPTIONS
149a53cbbeSchristos #include <net/ethernet.h>
159a53cbbeSchristos #include <netinet/ip.h>
169a53cbbeSchristos #endif /* CONFIG_TESTING_OPTIONS */
179a53cbbeSchristos
188dbcf02cSchristos #include <sys/un.h>
198dbcf02cSchristos #include <sys/stat.h>
208dbcf02cSchristos #include <stddef.h>
218dbcf02cSchristos
22928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP
23928750b6Schristos #include <netdb.h>
24928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
25928750b6Schristos
268dbcf02cSchristos #include "utils/common.h"
278dbcf02cSchristos #include "utils/eloop.h"
28928750b6Schristos #include "utils/module_tests.h"
2942669be3Schristos #include "common/version.h"
308dbcf02cSchristos #include "common/ieee802_11_defs.h"
31928750b6Schristos #include "common/ctrl_iface_common.h"
32ebb5671cSchristos #ifdef CONFIG_DPP
33ebb5671cSchristos #include "common/dpp.h"
34ebb5671cSchristos #endif /* CONFIG_DPP */
35ebb5671cSchristos #include "common/wpa_ctrl.h"
369a53cbbeSchristos #include "crypto/tls.h"
378dbcf02cSchristos #include "drivers/driver.h"
38928750b6Schristos #include "eapol_auth/eapol_auth_sm.h"
398dbcf02cSchristos #include "radius/radius_client.h"
4036d97821Schristos #include "radius/radius_server.h"
419a53cbbeSchristos #include "l2_packet/l2_packet.h"
428dbcf02cSchristos #include "ap/hostapd.h"
438dbcf02cSchristos #include "ap/ap_config.h"
448dbcf02cSchristos #include "ap/ieee802_1x.h"
458dbcf02cSchristos #include "ap/wpa_auth.h"
468dbcf02cSchristos #include "ap/ieee802_11.h"
478dbcf02cSchristos #include "ap/sta_info.h"
488dbcf02cSchristos #include "ap/wps_hostapd.h"
498dbcf02cSchristos #include "ap/ctrl_iface_ap.h"
5042669be3Schristos #include "ap/ap_drv_ops.h"
5136d97821Schristos #include "ap/hs20.h"
5236d97821Schristos #include "ap/wnm_ap.h"
5336d97821Schristos #include "ap/wpa_auth.h"
549a53cbbeSchristos #include "ap/beacon.h"
55928750b6Schristos #include "ap/neighbor_db.h"
56928750b6Schristos #include "ap/rrm.h"
57ebb5671cSchristos #include "ap/dpp_hostapd.h"
5842669be3Schristos #include "wps/wps_defs.h"
5942669be3Schristos #include "wps/wps.h"
60928750b6Schristos #include "fst/fst_ctrl_iface.h"
6162a52023Schristos #include "config_file.h"
628dbcf02cSchristos #include "ctrl_iface.h"
638dbcf02cSchristos
648dbcf02cSchristos
65928750b6Schristos #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
668dbcf02cSchristos
67928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP
68928750b6Schristos #define COOKIE_LEN 8
69928750b6Schristos static unsigned char cookie[COOKIE_LEN];
70928750b6Schristos static unsigned char gcookie[COOKIE_LEN];
71928750b6Schristos #define HOSTAPD_CTRL_IFACE_PORT 8877
72928750b6Schristos #define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
73928750b6Schristos #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
74928750b6Schristos #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT 50
75928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
768dbcf02cSchristos
778dbcf02cSchristos static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
78928750b6Schristos enum wpa_msg_type type,
798dbcf02cSchristos const char *buf, size_t len);
808dbcf02cSchristos
818dbcf02cSchristos
hostapd_ctrl_iface_attach(struct hostapd_data * hapd,struct sockaddr_storage * from,socklen_t fromlen,const char * input)828dbcf02cSchristos static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
83928750b6Schristos struct sockaddr_storage *from,
84ebb5671cSchristos socklen_t fromlen, const char *input)
858dbcf02cSchristos {
86ebb5671cSchristos return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen, input);
878dbcf02cSchristos }
888dbcf02cSchristos
898dbcf02cSchristos
hostapd_ctrl_iface_detach(struct hostapd_data * hapd,struct sockaddr_storage * from,socklen_t fromlen)908dbcf02cSchristos static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
91928750b6Schristos struct sockaddr_storage *from,
928dbcf02cSchristos socklen_t fromlen)
938dbcf02cSchristos {
94928750b6Schristos return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen);
958dbcf02cSchristos }
968dbcf02cSchristos
978dbcf02cSchristos
hostapd_ctrl_iface_level(struct hostapd_data * hapd,struct sockaddr_storage * from,socklen_t fromlen,char * level)988dbcf02cSchristos static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
99928750b6Schristos struct sockaddr_storage *from,
1008dbcf02cSchristos socklen_t fromlen,
1018dbcf02cSchristos char *level)
1028dbcf02cSchristos {
103928750b6Schristos return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level);
1048dbcf02cSchristos }
1058dbcf02cSchristos
1068dbcf02cSchristos
hostapd_ctrl_iface_new_sta(struct hostapd_data * hapd,const char * txtaddr)1078dbcf02cSchristos static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
1088dbcf02cSchristos const char *txtaddr)
1098dbcf02cSchristos {
1108dbcf02cSchristos u8 addr[ETH_ALEN];
1118dbcf02cSchristos struct sta_info *sta;
1128dbcf02cSchristos
1138dbcf02cSchristos wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
1148dbcf02cSchristos
1158dbcf02cSchristos if (hwaddr_aton(txtaddr, addr))
1168dbcf02cSchristos return -1;
1178dbcf02cSchristos
1188dbcf02cSchristos sta = ap_get_sta(hapd, addr);
1198dbcf02cSchristos if (sta)
1208dbcf02cSchristos return 0;
1218dbcf02cSchristos
1228dbcf02cSchristos wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
1238dbcf02cSchristos "notification", MAC2STR(addr));
1248dbcf02cSchristos sta = ap_sta_add(hapd, addr);
1258dbcf02cSchristos if (sta == NULL)
1268dbcf02cSchristos return -1;
1278dbcf02cSchristos
1288dbcf02cSchristos hostapd_new_assoc_sta(hapd, sta, 0);
1298dbcf02cSchristos return 0;
1308dbcf02cSchristos }
1318dbcf02cSchristos
1328dbcf02cSchristos
1338dbcf02cSchristos #ifdef CONFIG_IEEE80211W
1348dbcf02cSchristos #ifdef NEED_AP_MLME
hostapd_ctrl_iface_sa_query(struct hostapd_data * hapd,const char * txtaddr)1358dbcf02cSchristos static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
1368dbcf02cSchristos const char *txtaddr)
1378dbcf02cSchristos {
1388dbcf02cSchristos u8 addr[ETH_ALEN];
1398dbcf02cSchristos u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
1408dbcf02cSchristos
1418dbcf02cSchristos wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
1428dbcf02cSchristos
1438dbcf02cSchristos if (hwaddr_aton(txtaddr, addr) ||
1448dbcf02cSchristos os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
1458dbcf02cSchristos return -1;
1468dbcf02cSchristos
1478dbcf02cSchristos ieee802_11_send_sa_query_req(hapd, addr, trans_id);
1488dbcf02cSchristos
1498dbcf02cSchristos return 0;
1508dbcf02cSchristos }
1518dbcf02cSchristos #endif /* NEED_AP_MLME */
1528dbcf02cSchristos #endif /* CONFIG_IEEE80211W */
1538dbcf02cSchristos
1548dbcf02cSchristos
1558dbcf02cSchristos #ifdef CONFIG_WPS
hostapd_ctrl_iface_wps_pin(struct hostapd_data * hapd,char * txt)1568dbcf02cSchristos static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
1578dbcf02cSchristos {
1588dbcf02cSchristos char *pin = os_strchr(txt, ' ');
1598dbcf02cSchristos char *timeout_txt;
1608dbcf02cSchristos int timeout;
16142669be3Schristos u8 addr_buf[ETH_ALEN], *addr = NULL;
16242669be3Schristos char *pos;
1638dbcf02cSchristos
1648dbcf02cSchristos if (pin == NULL)
1658dbcf02cSchristos return -1;
1668dbcf02cSchristos *pin++ = '\0';
1678dbcf02cSchristos
1688dbcf02cSchristos timeout_txt = os_strchr(pin, ' ');
1698dbcf02cSchristos if (timeout_txt) {
1708dbcf02cSchristos *timeout_txt++ = '\0';
1718dbcf02cSchristos timeout = atoi(timeout_txt);
17242669be3Schristos pos = os_strchr(timeout_txt, ' ');
17342669be3Schristos if (pos) {
17442669be3Schristos *pos++ = '\0';
17542669be3Schristos if (hwaddr_aton(pos, addr_buf) == 0)
17642669be3Schristos addr = addr_buf;
17742669be3Schristos }
1788dbcf02cSchristos } else
1798dbcf02cSchristos timeout = 0;
1808dbcf02cSchristos
18142669be3Schristos return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
18242669be3Schristos }
18342669be3Schristos
18442669be3Schristos
hostapd_ctrl_iface_wps_check_pin(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)18542669be3Schristos static int hostapd_ctrl_iface_wps_check_pin(
18642669be3Schristos struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
18742669be3Schristos {
18842669be3Schristos char pin[9];
18942669be3Schristos size_t len;
19042669be3Schristos char *pos;
19142669be3Schristos int ret;
19242669be3Schristos
19342669be3Schristos wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
19442669be3Schristos (u8 *) cmd, os_strlen(cmd));
19542669be3Schristos for (pos = cmd, len = 0; *pos != '\0'; pos++) {
19642669be3Schristos if (*pos < '0' || *pos > '9')
19742669be3Schristos continue;
19842669be3Schristos pin[len++] = *pos;
19942669be3Schristos if (len == 9) {
20042669be3Schristos wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
20142669be3Schristos return -1;
20242669be3Schristos }
20342669be3Schristos }
20442669be3Schristos if (len != 4 && len != 8) {
20542669be3Schristos wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
20642669be3Schristos return -1;
20742669be3Schristos }
20842669be3Schristos pin[len] = '\0';
20942669be3Schristos
21042669be3Schristos if (len == 8) {
21142669be3Schristos unsigned int pin_val;
21242669be3Schristos pin_val = atoi(pin);
21342669be3Schristos if (!wps_pin_valid(pin_val)) {
21442669be3Schristos wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
21542669be3Schristos ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
2169a53cbbeSchristos if (os_snprintf_error(buflen, ret))
21742669be3Schristos return -1;
21842669be3Schristos return ret;
21942669be3Schristos }
22042669be3Schristos }
22142669be3Schristos
22242669be3Schristos ret = os_snprintf(buf, buflen, "%s", pin);
2239a53cbbeSchristos if (os_snprintf_error(buflen, ret))
22442669be3Schristos return -1;
22542669be3Schristos
22642669be3Schristos return ret;
2278dbcf02cSchristos }
2288dbcf02cSchristos
2298dbcf02cSchristos
23062a52023Schristos #ifdef CONFIG_WPS_NFC
hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data * hapd,char * pos)23162a52023Schristos static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
23262a52023Schristos char *pos)
2338dbcf02cSchristos {
23462a52023Schristos size_t len;
23562a52023Schristos struct wpabuf *buf;
23662a52023Schristos int ret;
2378dbcf02cSchristos
23862a52023Schristos len = os_strlen(pos);
23962a52023Schristos if (len & 0x01)
2408dbcf02cSchristos return -1;
24162a52023Schristos len /= 2;
2428dbcf02cSchristos
24362a52023Schristos buf = wpabuf_alloc(len);
24462a52023Schristos if (buf == NULL)
2458dbcf02cSchristos return -1;
24662a52023Schristos if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
24762a52023Schristos wpabuf_free(buf);
24862a52023Schristos return -1;
2498dbcf02cSchristos }
25062a52023Schristos
25162a52023Schristos ret = hostapd_wps_nfc_tag_read(hapd, buf);
25262a52023Schristos wpabuf_free(buf);
25362a52023Schristos
25462a52023Schristos return ret;
25562a52023Schristos }
25662a52023Schristos
25762a52023Schristos
hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data * hapd,char * cmd,char * reply,size_t max_len)25862a52023Schristos static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
25962a52023Schristos char *cmd, char *reply,
26062a52023Schristos size_t max_len)
26162a52023Schristos {
26262a52023Schristos int ndef;
26362a52023Schristos struct wpabuf *buf;
26462a52023Schristos int res;
26562a52023Schristos
26662a52023Schristos if (os_strcmp(cmd, "WPS") == 0)
26762a52023Schristos ndef = 0;
26862a52023Schristos else if (os_strcmp(cmd, "NDEF") == 0)
26962a52023Schristos ndef = 1;
27062a52023Schristos else
27162a52023Schristos return -1;
27262a52023Schristos
27362a52023Schristos buf = hostapd_wps_nfc_config_token(hapd, ndef);
27462a52023Schristos if (buf == NULL)
27562a52023Schristos return -1;
27662a52023Schristos
27762a52023Schristos res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
27862a52023Schristos wpabuf_len(buf));
27962a52023Schristos reply[res++] = '\n';
28062a52023Schristos reply[res] = '\0';
28162a52023Schristos
28262a52023Schristos wpabuf_free(buf);
28362a52023Schristos
28462a52023Schristos return res;
28562a52023Schristos }
28662a52023Schristos
28762a52023Schristos
hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data * hapd,char * reply,size_t max_len,int ndef)28862a52023Schristos static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
28962a52023Schristos char *reply, size_t max_len,
29062a52023Schristos int ndef)
29162a52023Schristos {
29262a52023Schristos struct wpabuf *buf;
29362a52023Schristos int res;
29462a52023Schristos
29562a52023Schristos buf = hostapd_wps_nfc_token_gen(hapd, ndef);
29662a52023Schristos if (buf == NULL)
29762a52023Schristos return -1;
29862a52023Schristos
29962a52023Schristos res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
30062a52023Schristos wpabuf_len(buf));
30162a52023Schristos reply[res++] = '\n';
30262a52023Schristos reply[res] = '\0';
30362a52023Schristos
30462a52023Schristos wpabuf_free(buf);
30562a52023Schristos
30662a52023Schristos return res;
30762a52023Schristos }
30862a52023Schristos
30962a52023Schristos
hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data * hapd,char * cmd,char * reply,size_t max_len)31062a52023Schristos static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
31162a52023Schristos char *cmd, char *reply,
31262a52023Schristos size_t max_len)
31362a52023Schristos {
31462a52023Schristos if (os_strcmp(cmd, "WPS") == 0)
31562a52023Schristos return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
31662a52023Schristos max_len, 0);
31762a52023Schristos
31862a52023Schristos if (os_strcmp(cmd, "NDEF") == 0)
31962a52023Schristos return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
32062a52023Schristos max_len, 1);
32162a52023Schristos
32262a52023Schristos if (os_strcmp(cmd, "enable") == 0)
32362a52023Schristos return hostapd_wps_nfc_token_enable(hapd);
32462a52023Schristos
32562a52023Schristos if (os_strcmp(cmd, "disable") == 0) {
32662a52023Schristos hostapd_wps_nfc_token_disable(hapd);
32762a52023Schristos return 0;
32862a52023Schristos }
32962a52023Schristos
33062a52023Schristos return -1;
33162a52023Schristos }
33236d97821Schristos
33336d97821Schristos
hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data * hapd,char * cmd,char * reply,size_t max_len)33436d97821Schristos static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
33536d97821Schristos char *cmd, char *reply,
33636d97821Schristos size_t max_len)
33736d97821Schristos {
33836d97821Schristos struct wpabuf *buf;
33936d97821Schristos int res;
34036d97821Schristos char *pos;
34136d97821Schristos int ndef;
34236d97821Schristos
34336d97821Schristos pos = os_strchr(cmd, ' ');
34436d97821Schristos if (pos == NULL)
34536d97821Schristos return -1;
34636d97821Schristos *pos++ = '\0';
34736d97821Schristos
34836d97821Schristos if (os_strcmp(cmd, "WPS") == 0)
34936d97821Schristos ndef = 0;
35036d97821Schristos else if (os_strcmp(cmd, "NDEF") == 0)
35136d97821Schristos ndef = 1;
35236d97821Schristos else
35336d97821Schristos return -1;
35436d97821Schristos
35536d97821Schristos if (os_strcmp(pos, "WPS-CR") == 0)
35636d97821Schristos buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
35736d97821Schristos else
35836d97821Schristos buf = NULL;
35936d97821Schristos if (buf == NULL)
36036d97821Schristos return -1;
36136d97821Schristos
36236d97821Schristos res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
36336d97821Schristos wpabuf_len(buf));
36436d97821Schristos reply[res++] = '\n';
36536d97821Schristos reply[res] = '\0';
36636d97821Schristos
36736d97821Schristos wpabuf_free(buf);
36836d97821Schristos
36936d97821Schristos return res;
37036d97821Schristos }
37136d97821Schristos
37236d97821Schristos
hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data * hapd,char * cmd)37336d97821Schristos static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
37436d97821Schristos char *cmd)
37536d97821Schristos {
37636d97821Schristos size_t len;
37736d97821Schristos struct wpabuf *req, *sel;
37836d97821Schristos int ret;
37936d97821Schristos char *pos, *role, *type, *pos2;
38036d97821Schristos
38136d97821Schristos role = cmd;
38236d97821Schristos pos = os_strchr(role, ' ');
38336d97821Schristos if (pos == NULL)
38436d97821Schristos return -1;
38536d97821Schristos *pos++ = '\0';
38636d97821Schristos
38736d97821Schristos type = pos;
38836d97821Schristos pos = os_strchr(type, ' ');
38936d97821Schristos if (pos == NULL)
39036d97821Schristos return -1;
39136d97821Schristos *pos++ = '\0';
39236d97821Schristos
39336d97821Schristos pos2 = os_strchr(pos, ' ');
39436d97821Schristos if (pos2 == NULL)
39536d97821Schristos return -1;
39636d97821Schristos *pos2++ = '\0';
39736d97821Schristos
39836d97821Schristos len = os_strlen(pos);
39936d97821Schristos if (len & 0x01)
40036d97821Schristos return -1;
40136d97821Schristos len /= 2;
40236d97821Schristos
40336d97821Schristos req = wpabuf_alloc(len);
40436d97821Schristos if (req == NULL)
40536d97821Schristos return -1;
40636d97821Schristos if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
40736d97821Schristos wpabuf_free(req);
40836d97821Schristos return -1;
40936d97821Schristos }
41036d97821Schristos
41136d97821Schristos len = os_strlen(pos2);
41236d97821Schristos if (len & 0x01) {
41336d97821Schristos wpabuf_free(req);
41436d97821Schristos return -1;
41536d97821Schristos }
41636d97821Schristos len /= 2;
41736d97821Schristos
41836d97821Schristos sel = wpabuf_alloc(len);
41936d97821Schristos if (sel == NULL) {
42036d97821Schristos wpabuf_free(req);
42136d97821Schristos return -1;
42236d97821Schristos }
42336d97821Schristos if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
42436d97821Schristos wpabuf_free(req);
42536d97821Schristos wpabuf_free(sel);
42636d97821Schristos return -1;
42736d97821Schristos }
42836d97821Schristos
42936d97821Schristos if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
43036d97821Schristos ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
43136d97821Schristos } else {
43236d97821Schristos wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
43336d97821Schristos "reported: role=%s type=%s", role, type);
43436d97821Schristos ret = -1;
43536d97821Schristos }
43636d97821Schristos wpabuf_free(req);
43736d97821Schristos wpabuf_free(sel);
43836d97821Schristos
43936d97821Schristos return ret;
44036d97821Schristos }
44136d97821Schristos
44262a52023Schristos #endif /* CONFIG_WPS_NFC */
4431b7205bfSchristos
4441b7205bfSchristos
hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data * hapd,char * txt,char * buf,size_t buflen)4451b7205bfSchristos static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
4461b7205bfSchristos char *buf, size_t buflen)
4471b7205bfSchristos {
4481b7205bfSchristos int timeout = 300;
4491b7205bfSchristos char *pos;
4501b7205bfSchristos const char *pin_txt;
4511b7205bfSchristos
4521b7205bfSchristos pos = os_strchr(txt, ' ');
4531b7205bfSchristos if (pos)
4541b7205bfSchristos *pos++ = '\0';
4551b7205bfSchristos
4561b7205bfSchristos if (os_strcmp(txt, "disable") == 0) {
4571b7205bfSchristos hostapd_wps_ap_pin_disable(hapd);
4581b7205bfSchristos return os_snprintf(buf, buflen, "OK\n");
4591b7205bfSchristos }
4601b7205bfSchristos
4611b7205bfSchristos if (os_strcmp(txt, "random") == 0) {
4621b7205bfSchristos if (pos)
4631b7205bfSchristos timeout = atoi(pos);
4641b7205bfSchristos pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
4651b7205bfSchristos if (pin_txt == NULL)
4661b7205bfSchristos return -1;
4671b7205bfSchristos return os_snprintf(buf, buflen, "%s", pin_txt);
4681b7205bfSchristos }
4691b7205bfSchristos
4701b7205bfSchristos if (os_strcmp(txt, "get") == 0) {
4711b7205bfSchristos pin_txt = hostapd_wps_ap_pin_get(hapd);
4721b7205bfSchristos if (pin_txt == NULL)
4731b7205bfSchristos return -1;
4741b7205bfSchristos return os_snprintf(buf, buflen, "%s", pin_txt);
4751b7205bfSchristos }
4761b7205bfSchristos
4771b7205bfSchristos if (os_strcmp(txt, "set") == 0) {
4781b7205bfSchristos char *pin;
4791b7205bfSchristos if (pos == NULL)
4801b7205bfSchristos return -1;
4811b7205bfSchristos pin = pos;
4821b7205bfSchristos pos = os_strchr(pos, ' ');
4831b7205bfSchristos if (pos) {
4841b7205bfSchristos *pos++ = '\0';
4851b7205bfSchristos timeout = atoi(pos);
4861b7205bfSchristos }
4871b7205bfSchristos if (os_strlen(pin) > buflen)
4881b7205bfSchristos return -1;
4891b7205bfSchristos if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
4901b7205bfSchristos return -1;
4911b7205bfSchristos return os_snprintf(buf, buflen, "%s", pin);
4921b7205bfSchristos }
4931b7205bfSchristos
4941b7205bfSchristos return -1;
4951b7205bfSchristos }
49642669be3Schristos
49742669be3Schristos
hostapd_ctrl_iface_wps_config(struct hostapd_data * hapd,char * txt)49842669be3Schristos static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
49942669be3Schristos {
50042669be3Schristos char *pos;
50142669be3Schristos char *ssid, *auth, *encr = NULL, *key = NULL;
50242669be3Schristos
50342669be3Schristos ssid = txt;
50442669be3Schristos pos = os_strchr(txt, ' ');
50542669be3Schristos if (!pos)
50642669be3Schristos return -1;
50742669be3Schristos *pos++ = '\0';
50842669be3Schristos
50942669be3Schristos auth = pos;
51042669be3Schristos pos = os_strchr(pos, ' ');
51142669be3Schristos if (pos) {
51242669be3Schristos *pos++ = '\0';
51342669be3Schristos encr = pos;
51442669be3Schristos pos = os_strchr(pos, ' ');
51542669be3Schristos if (pos) {
51642669be3Schristos *pos++ = '\0';
51742669be3Schristos key = pos;
51842669be3Schristos }
51942669be3Schristos }
52042669be3Schristos
52142669be3Schristos return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
52242669be3Schristos }
52336d97821Schristos
52436d97821Schristos
pbc_status_str(enum pbc_status status)52536d97821Schristos static const char * pbc_status_str(enum pbc_status status)
52636d97821Schristos {
52736d97821Schristos switch (status) {
52836d97821Schristos case WPS_PBC_STATUS_DISABLE:
52936d97821Schristos return "Disabled";
53036d97821Schristos case WPS_PBC_STATUS_ACTIVE:
53136d97821Schristos return "Active";
53236d97821Schristos case WPS_PBC_STATUS_TIMEOUT:
53336d97821Schristos return "Timed-out";
53436d97821Schristos case WPS_PBC_STATUS_OVERLAP:
53536d97821Schristos return "Overlap";
53636d97821Schristos default:
53736d97821Schristos return "Unknown";
53836d97821Schristos }
53936d97821Schristos }
54036d97821Schristos
54136d97821Schristos
hostapd_ctrl_iface_wps_get_status(struct hostapd_data * hapd,char * buf,size_t buflen)54236d97821Schristos static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
54336d97821Schristos char *buf, size_t buflen)
54436d97821Schristos {
54536d97821Schristos int ret;
54636d97821Schristos char *pos, *end;
54736d97821Schristos
54836d97821Schristos pos = buf;
54936d97821Schristos end = buf + buflen;
55036d97821Schristos
55136d97821Schristos ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
55236d97821Schristos pbc_status_str(hapd->wps_stats.pbc_status));
55336d97821Schristos
5549a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
55536d97821Schristos return pos - buf;
55636d97821Schristos pos += ret;
55736d97821Schristos
55836d97821Schristos ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
55936d97821Schristos (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
56036d97821Schristos "Success":
56136d97821Schristos (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
56236d97821Schristos "Failed" : "None")));
56336d97821Schristos
5649a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
56536d97821Schristos return pos - buf;
56636d97821Schristos pos += ret;
56736d97821Schristos
56836d97821Schristos /* If status == Failure - Add possible Reasons */
56936d97821Schristos if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
57036d97821Schristos hapd->wps_stats.failure_reason > 0) {
57136d97821Schristos ret = os_snprintf(pos, end - pos,
57236d97821Schristos "Failure Reason: %s\n",
57336d97821Schristos wps_ei_str(hapd->wps_stats.failure_reason));
57436d97821Schristos
5759a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
57636d97821Schristos return pos - buf;
57736d97821Schristos pos += ret;
57836d97821Schristos }
57936d97821Schristos
58036d97821Schristos if (hapd->wps_stats.status) {
58136d97821Schristos ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
58236d97821Schristos MAC2STR(hapd->wps_stats.peer_addr));
58336d97821Schristos
5849a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
58536d97821Schristos return pos - buf;
58636d97821Schristos pos += ret;
58736d97821Schristos }
58836d97821Schristos
58936d97821Schristos return pos - buf;
59036d97821Schristos }
59136d97821Schristos
5928dbcf02cSchristos #endif /* CONFIG_WPS */
5938dbcf02cSchristos
59436d97821Schristos #ifdef CONFIG_HS20
59536d97821Schristos
hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data * hapd,const char * cmd)59636d97821Schristos static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
59736d97821Schristos const char *cmd)
59836d97821Schristos {
59936d97821Schristos u8 addr[ETH_ALEN];
60036d97821Schristos const char *url;
60136d97821Schristos
60236d97821Schristos if (hwaddr_aton(cmd, addr))
60336d97821Schristos return -1;
60436d97821Schristos url = cmd + 17;
60536d97821Schristos if (*url == '\0') {
60636d97821Schristos url = NULL;
60736d97821Schristos } else {
60836d97821Schristos if (*url != ' ')
60936d97821Schristos return -1;
61036d97821Schristos url++;
61136d97821Schristos if (*url == '\0')
61236d97821Schristos url = NULL;
61336d97821Schristos }
61436d97821Schristos
61536d97821Schristos return hs20_send_wnm_notification(hapd, addr, 1, url);
61636d97821Schristos }
61736d97821Schristos
61836d97821Schristos
hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data * hapd,const char * cmd)61936d97821Schristos static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
62036d97821Schristos const char *cmd)
62136d97821Schristos {
62236d97821Schristos u8 addr[ETH_ALEN];
62336d97821Schristos int code, reauth_delay, ret;
62436d97821Schristos const char *pos;
62536d97821Schristos size_t url_len;
62636d97821Schristos struct wpabuf *req;
62736d97821Schristos
62836d97821Schristos /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
62936d97821Schristos if (hwaddr_aton(cmd, addr))
63036d97821Schristos return -1;
63136d97821Schristos
63236d97821Schristos pos = os_strchr(cmd, ' ');
63336d97821Schristos if (pos == NULL)
63436d97821Schristos return -1;
63536d97821Schristos pos++;
63636d97821Schristos code = atoi(pos);
63736d97821Schristos
63836d97821Schristos pos = os_strchr(pos, ' ');
63936d97821Schristos if (pos == NULL)
64036d97821Schristos return -1;
64136d97821Schristos pos++;
64236d97821Schristos reauth_delay = atoi(pos);
64336d97821Schristos
64436d97821Schristos url_len = 0;
64536d97821Schristos pos = os_strchr(pos, ' ');
64636d97821Schristos if (pos) {
64736d97821Schristos pos++;
64836d97821Schristos url_len = os_strlen(pos);
64936d97821Schristos }
65036d97821Schristos
65136d97821Schristos req = wpabuf_alloc(4 + url_len);
65236d97821Schristos if (req == NULL)
65336d97821Schristos return -1;
65436d97821Schristos wpabuf_put_u8(req, code);
65536d97821Schristos wpabuf_put_le16(req, reauth_delay);
65636d97821Schristos wpabuf_put_u8(req, url_len);
65736d97821Schristos if (pos)
65836d97821Schristos wpabuf_put_data(req, pos, url_len);
65936d97821Schristos
66036d97821Schristos wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
66136d97821Schristos " to indicate imminent deauthentication (code=%d "
66236d97821Schristos "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
66336d97821Schristos ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
66436d97821Schristos wpabuf_free(req);
66536d97821Schristos return ret;
66636d97821Schristos }
66736d97821Schristos
66836d97821Schristos #endif /* CONFIG_HS20 */
66936d97821Schristos
67036d97821Schristos
67136d97821Schristos #ifdef CONFIG_INTERWORKING
67236d97821Schristos
hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data * hapd,const char * cmd)67336d97821Schristos static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
67436d97821Schristos const char *cmd)
67536d97821Schristos {
67636d97821Schristos u8 qos_map_set[16 + 2 * 21], count = 0;
67736d97821Schristos const char *pos = cmd;
67836d97821Schristos int val, ret;
67936d97821Schristos
68036d97821Schristos for (;;) {
68136d97821Schristos if (count == sizeof(qos_map_set)) {
68236d97821Schristos wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
68336d97821Schristos return -1;
68436d97821Schristos }
68536d97821Schristos
68636d97821Schristos val = atoi(pos);
68736d97821Schristos if (val < 0 || val > 255) {
68836d97821Schristos wpa_printf(MSG_INFO, "Invalid QoS Map Set");
68936d97821Schristos return -1;
69036d97821Schristos }
69136d97821Schristos
69236d97821Schristos qos_map_set[count++] = val;
69336d97821Schristos pos = os_strchr(pos, ',');
69436d97821Schristos if (!pos)
69536d97821Schristos break;
69636d97821Schristos pos++;
69736d97821Schristos }
69836d97821Schristos
69936d97821Schristos if (count < 16 || count & 1) {
70036d97821Schristos wpa_printf(MSG_INFO, "Invalid QoS Map Set");
70136d97821Schristos return -1;
70236d97821Schristos }
70336d97821Schristos
70436d97821Schristos ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
70536d97821Schristos if (ret) {
70636d97821Schristos wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
70736d97821Schristos return -1;
70836d97821Schristos }
70936d97821Schristos
71036d97821Schristos os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
71136d97821Schristos hapd->conf->qos_map_set_len = count;
71236d97821Schristos
71336d97821Schristos return 0;
71436d97821Schristos }
71536d97821Schristos
71636d97821Schristos
hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data * hapd,const char * cmd)71736d97821Schristos static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
71836d97821Schristos const char *cmd)
71936d97821Schristos {
72036d97821Schristos u8 addr[ETH_ALEN];
72136d97821Schristos struct sta_info *sta;
72236d97821Schristos struct wpabuf *buf;
72336d97821Schristos u8 *qos_map_set = hapd->conf->qos_map_set;
72436d97821Schristos u8 qos_map_set_len = hapd->conf->qos_map_set_len;
72536d97821Schristos int ret;
72636d97821Schristos
72736d97821Schristos if (!qos_map_set_len) {
72836d97821Schristos wpa_printf(MSG_INFO, "QoS Map Set is not set");
72936d97821Schristos return -1;
73036d97821Schristos }
73136d97821Schristos
73236d97821Schristos if (hwaddr_aton(cmd, addr))
73336d97821Schristos return -1;
73436d97821Schristos
73536d97821Schristos sta = ap_get_sta(hapd, addr);
73636d97821Schristos if (sta == NULL) {
73736d97821Schristos wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
73836d97821Schristos "for QoS Map Configuration message",
73936d97821Schristos MAC2STR(addr));
74036d97821Schristos return -1;
74136d97821Schristos }
74236d97821Schristos
74336d97821Schristos if (!sta->qos_map_enabled) {
74436d97821Schristos wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
74536d97821Schristos "support for QoS Map", MAC2STR(addr));
74636d97821Schristos return -1;
74736d97821Schristos }
74836d97821Schristos
74936d97821Schristos buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
75036d97821Schristos if (buf == NULL)
75136d97821Schristos return -1;
75236d97821Schristos
75336d97821Schristos wpabuf_put_u8(buf, WLAN_ACTION_QOS);
75436d97821Schristos wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
75536d97821Schristos
75636d97821Schristos /* QoS Map Set Element */
75736d97821Schristos wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
75836d97821Schristos wpabuf_put_u8(buf, qos_map_set_len);
75936d97821Schristos wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
76036d97821Schristos
76136d97821Schristos ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
76236d97821Schristos wpabuf_head(buf), wpabuf_len(buf));
76336d97821Schristos wpabuf_free(buf);
76436d97821Schristos
76536d97821Schristos return ret;
76636d97821Schristos }
76736d97821Schristos
76836d97821Schristos #endif /* CONFIG_INTERWORKING */
76936d97821Schristos
7708dbcf02cSchristos
771ebb5671cSchristos #ifdef CONFIG_WNM_AP
77262a52023Schristos
hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data * hapd,const char * cmd)77362a52023Schristos static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
77462a52023Schristos const char *cmd)
77562a52023Schristos {
77662a52023Schristos u8 addr[ETH_ALEN];
77762a52023Schristos int disassoc_timer;
77836d97821Schristos struct sta_info *sta;
77962a52023Schristos
78062a52023Schristos if (hwaddr_aton(cmd, addr))
78162a52023Schristos return -1;
78262a52023Schristos if (cmd[17] != ' ')
78362a52023Schristos return -1;
78462a52023Schristos disassoc_timer = atoi(cmd + 17);
78562a52023Schristos
78636d97821Schristos sta = ap_get_sta(hapd, addr);
78736d97821Schristos if (sta == NULL) {
78836d97821Schristos wpa_printf(MSG_DEBUG, "Station " MACSTR
78936d97821Schristos " not found for disassociation imminent message",
79036d97821Schristos MAC2STR(addr));
79162a52023Schristos return -1;
79262a52023Schristos }
79362a52023Schristos
79436d97821Schristos return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
79562a52023Schristos }
79662a52023Schristos
79762a52023Schristos
hostapd_ctrl_iface_ess_disassoc(struct hostapd_data * hapd,const char * cmd)79842669be3Schristos static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
79942669be3Schristos const char *cmd)
80042669be3Schristos {
80142669be3Schristos u8 addr[ETH_ALEN];
80236d97821Schristos const char *url, *timerstr;
80336d97821Schristos int disassoc_timer;
80436d97821Schristos struct sta_info *sta;
80542669be3Schristos
80642669be3Schristos if (hwaddr_aton(cmd, addr))
80742669be3Schristos return -1;
80842669be3Schristos
80936d97821Schristos sta = ap_get_sta(hapd, addr);
81036d97821Schristos if (sta == NULL) {
81136d97821Schristos wpa_printf(MSG_DEBUG, "Station " MACSTR
81236d97821Schristos " not found for ESS disassociation imminent message",
81336d97821Schristos MAC2STR(addr));
81442669be3Schristos return -1;
81542669be3Schristos }
81642669be3Schristos
81736d97821Schristos timerstr = cmd + 17;
81836d97821Schristos if (*timerstr != ' ')
81936d97821Schristos return -1;
82036d97821Schristos timerstr++;
82136d97821Schristos disassoc_timer = atoi(timerstr);
82236d97821Schristos if (disassoc_timer < 0 || disassoc_timer > 65535)
82336d97821Schristos return -1;
82436d97821Schristos
82536d97821Schristos url = os_strchr(timerstr, ' ');
82636d97821Schristos if (url == NULL)
82736d97821Schristos return -1;
82836d97821Schristos url++;
82936d97821Schristos
83036d97821Schristos return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
83142669be3Schristos }
83242669be3Schristos
8339a53cbbeSchristos
hostapd_ctrl_iface_bss_tm_req(struct hostapd_data * hapd,const char * cmd)8349a53cbbeSchristos static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
8359a53cbbeSchristos const char *cmd)
8369a53cbbeSchristos {
8379a53cbbeSchristos u8 addr[ETH_ALEN];
8389a53cbbeSchristos const char *pos, *end;
8399a53cbbeSchristos int disassoc_timer = 0;
8409a53cbbeSchristos struct sta_info *sta;
8419a53cbbeSchristos u8 req_mode = 0, valid_int = 0x01;
8429a53cbbeSchristos u8 bss_term_dur[12];
8439a53cbbeSchristos char *url = NULL;
8449a53cbbeSchristos int ret;
8459a53cbbeSchristos u8 nei_rep[1000];
846ebb5671cSchristos int nei_len;
847928750b6Schristos u8 mbo[10];
848928750b6Schristos size_t mbo_len = 0;
8499a53cbbeSchristos
8509a53cbbeSchristos if (hwaddr_aton(cmd, addr)) {
8519a53cbbeSchristos wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
8529a53cbbeSchristos return -1;
8539a53cbbeSchristos }
8549a53cbbeSchristos
8559a53cbbeSchristos sta = ap_get_sta(hapd, addr);
8569a53cbbeSchristos if (sta == NULL) {
8579a53cbbeSchristos wpa_printf(MSG_DEBUG, "Station " MACSTR
8589a53cbbeSchristos " not found for BSS TM Request message",
8599a53cbbeSchristos MAC2STR(addr));
8609a53cbbeSchristos return -1;
8619a53cbbeSchristos }
8629a53cbbeSchristos
8639a53cbbeSchristos pos = os_strstr(cmd, " disassoc_timer=");
8649a53cbbeSchristos if (pos) {
8659a53cbbeSchristos pos += 16;
8669a53cbbeSchristos disassoc_timer = atoi(pos);
8679a53cbbeSchristos if (disassoc_timer < 0 || disassoc_timer > 65535) {
8689a53cbbeSchristos wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
8699a53cbbeSchristos return -1;
8709a53cbbeSchristos }
8719a53cbbeSchristos }
8729a53cbbeSchristos
8739a53cbbeSchristos pos = os_strstr(cmd, " valid_int=");
8749a53cbbeSchristos if (pos) {
8759a53cbbeSchristos pos += 11;
8769a53cbbeSchristos valid_int = atoi(pos);
8779a53cbbeSchristos }
8789a53cbbeSchristos
8799a53cbbeSchristos pos = os_strstr(cmd, " bss_term=");
8809a53cbbeSchristos if (pos) {
8819a53cbbeSchristos pos += 10;
8829a53cbbeSchristos req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
8839a53cbbeSchristos /* TODO: TSF configurable/learnable */
8849a53cbbeSchristos bss_term_dur[0] = 4; /* Subelement ID */
8859a53cbbeSchristos bss_term_dur[1] = 10; /* Length */
886*0d69f216Schristos os_memset(&bss_term_dur[2], 0, 8);
8879a53cbbeSchristos end = os_strchr(pos, ',');
8889a53cbbeSchristos if (end == NULL) {
8899a53cbbeSchristos wpa_printf(MSG_DEBUG, "Invalid bss_term data");
8909a53cbbeSchristos return -1;
8919a53cbbeSchristos }
8929a53cbbeSchristos end++;
8939a53cbbeSchristos WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
8949a53cbbeSchristos }
8959a53cbbeSchristos
896ebb5671cSchristos nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
897ebb5671cSchristos sizeof(nei_rep));
898ebb5671cSchristos if (nei_len < 0)
8999a53cbbeSchristos return -1;
9009a53cbbeSchristos
9019a53cbbeSchristos pos = os_strstr(cmd, " url=");
9029a53cbbeSchristos if (pos) {
9039a53cbbeSchristos size_t len;
9049a53cbbeSchristos pos += 5;
9059a53cbbeSchristos end = os_strchr(pos, ' ');
9069a53cbbeSchristos if (end)
9079a53cbbeSchristos len = end - pos;
9089a53cbbeSchristos else
9099a53cbbeSchristos len = os_strlen(pos);
9109a53cbbeSchristos url = os_malloc(len + 1);
9119a53cbbeSchristos if (url == NULL)
9129a53cbbeSchristos return -1;
9139a53cbbeSchristos os_memcpy(url, pos, len);
9149a53cbbeSchristos url[len] = '\0';
9159a53cbbeSchristos req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
9169a53cbbeSchristos }
9179a53cbbeSchristos
9189a53cbbeSchristos if (os_strstr(cmd, " pref=1"))
9199a53cbbeSchristos req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
9209a53cbbeSchristos if (os_strstr(cmd, " abridged=1"))
9219a53cbbeSchristos req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
9229a53cbbeSchristos if (os_strstr(cmd, " disassoc_imminent=1"))
9239a53cbbeSchristos req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
9249a53cbbeSchristos
925928750b6Schristos #ifdef CONFIG_MBO
926928750b6Schristos pos = os_strstr(cmd, "mbo=");
927928750b6Schristos if (pos) {
928928750b6Schristos unsigned int mbo_reason, cell_pref, reassoc_delay;
929928750b6Schristos u8 *mbo_pos = mbo;
930928750b6Schristos
931928750b6Schristos ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
932928750b6Schristos &reassoc_delay, &cell_pref);
933928750b6Schristos if (ret != 3) {
934928750b6Schristos wpa_printf(MSG_DEBUG,
935928750b6Schristos "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
936ebb5671cSchristos ret = -1;
937ebb5671cSchristos goto fail;
938928750b6Schristos }
939928750b6Schristos
940928750b6Schristos if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
941928750b6Schristos wpa_printf(MSG_DEBUG,
942928750b6Schristos "Invalid MBO transition reason code %u",
943928750b6Schristos mbo_reason);
944ebb5671cSchristos ret = -1;
945ebb5671cSchristos goto fail;
946928750b6Schristos }
947928750b6Schristos
948928750b6Schristos /* Valid values for Cellular preference are: 0, 1, 255 */
949928750b6Schristos if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
950928750b6Schristos wpa_printf(MSG_DEBUG,
951928750b6Schristos "Invalid MBO cellular capability %u",
952928750b6Schristos cell_pref);
953ebb5671cSchristos ret = -1;
954ebb5671cSchristos goto fail;
955928750b6Schristos }
956928750b6Schristos
957928750b6Schristos if (reassoc_delay > 65535 ||
958928750b6Schristos (reassoc_delay &&
959928750b6Schristos !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
960928750b6Schristos wpa_printf(MSG_DEBUG,
961928750b6Schristos "MBO: Assoc retry delay is only valid in disassoc imminent mode");
962ebb5671cSchristos ret = -1;
963ebb5671cSchristos goto fail;
964928750b6Schristos }
965928750b6Schristos
966928750b6Schristos *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
967928750b6Schristos *mbo_pos++ = 1;
968928750b6Schristos *mbo_pos++ = mbo_reason;
969928750b6Schristos *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
970928750b6Schristos *mbo_pos++ = 1;
971928750b6Schristos *mbo_pos++ = cell_pref;
972928750b6Schristos
973928750b6Schristos if (reassoc_delay) {
974928750b6Schristos *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
975928750b6Schristos *mbo_pos++ = 2;
976928750b6Schristos WPA_PUT_LE16(mbo_pos, reassoc_delay);
977928750b6Schristos mbo_pos += 2;
978928750b6Schristos }
979928750b6Schristos
980928750b6Schristos mbo_len = mbo_pos - mbo;
981928750b6Schristos }
982928750b6Schristos #endif /* CONFIG_MBO */
983928750b6Schristos
9849a53cbbeSchristos ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
9859a53cbbeSchristos valid_int, bss_term_dur, url,
986ebb5671cSchristos nei_len ? nei_rep : NULL, nei_len,
987ebb5671cSchristos mbo_len ? mbo : NULL, mbo_len);
988ebb5671cSchristos #ifdef CONFIG_MBO
989ebb5671cSchristos fail:
990ebb5671cSchristos #endif /* CONFIG_MBO */
9919a53cbbeSchristos os_free(url);
9929a53cbbeSchristos return ret;
9939a53cbbeSchristos }
9949a53cbbeSchristos
995ebb5671cSchristos
hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data * hapd,const char * cmd)996ebb5671cSchristos static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
997ebb5671cSchristos const char *cmd)
998ebb5671cSchristos {
999ebb5671cSchristos u8 addr[ETH_ALEN];
1000ebb5671cSchristos struct sta_info *sta;
1001ebb5671cSchristos const char *pos;
1002ebb5671cSchristos unsigned int auto_report, timeout;
1003ebb5671cSchristos
1004ebb5671cSchristos if (hwaddr_aton(cmd, addr)) {
1005ebb5671cSchristos wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
1006ebb5671cSchristos return -1;
1007ebb5671cSchristos }
1008ebb5671cSchristos
1009ebb5671cSchristos sta = ap_get_sta(hapd, addr);
1010ebb5671cSchristos if (!sta) {
1011ebb5671cSchristos wpa_printf(MSG_DEBUG, "Station " MACSTR
1012ebb5671cSchristos " not found for Collocated Interference Request",
1013ebb5671cSchristos MAC2STR(addr));
1014ebb5671cSchristos return -1;
1015ebb5671cSchristos }
1016ebb5671cSchristos
1017ebb5671cSchristos pos = cmd + 17;
1018ebb5671cSchristos if (*pos != ' ')
1019ebb5671cSchristos return -1;
1020ebb5671cSchristos pos++;
1021ebb5671cSchristos auto_report = atoi(pos);
1022ebb5671cSchristos pos = os_strchr(pos, ' ');
1023ebb5671cSchristos if (!pos)
1024ebb5671cSchristos return -1;
1025ebb5671cSchristos pos++;
1026ebb5671cSchristos timeout = atoi(pos);
1027ebb5671cSchristos
1028ebb5671cSchristos return wnm_send_coloc_intf_req(hapd, sta, auto_report, timeout);
1029ebb5671cSchristos }
1030ebb5671cSchristos
1031ebb5671cSchristos #endif /* CONFIG_WNM_AP */
103262a52023Schristos
103342669be3Schristos
hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data * hapd,char * buf,size_t buflen)1034928750b6Schristos static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
103542669be3Schristos char *buf, size_t buflen)
103642669be3Schristos {
1037928750b6Schristos int ret = 0;
103842669be3Schristos char *pos, *end;
103942669be3Schristos
104042669be3Schristos pos = buf;
104142669be3Schristos end = buf + buflen;
104242669be3Schristos
1043928750b6Schristos WPA_ASSERT(hapd->conf->wpa_key_mgmt);
104442669be3Schristos
104542669be3Schristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
104642669be3Schristos ret = os_snprintf(pos, end - pos, "WPA-PSK ");
10479a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
104842669be3Schristos return pos - buf;
104942669be3Schristos pos += ret;
105042669be3Schristos }
105142669be3Schristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
105242669be3Schristos ret = os_snprintf(pos, end - pos, "WPA-EAP ");
10539a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
105442669be3Schristos return pos - buf;
105542669be3Schristos pos += ret;
105642669be3Schristos }
1057ebb5671cSchristos #ifdef CONFIG_IEEE80211R_AP
105842669be3Schristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
105942669be3Schristos ret = os_snprintf(pos, end - pos, "FT-PSK ");
10609a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
106142669be3Schristos return pos - buf;
106242669be3Schristos pos += ret;
106342669be3Schristos }
106442669be3Schristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
106542669be3Schristos ret = os_snprintf(pos, end - pos, "FT-EAP ");
10669a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
106742669be3Schristos return pos - buf;
106842669be3Schristos pos += ret;
106942669be3Schristos }
1070ebb5671cSchristos #ifdef CONFIG_SHA384
1071ebb5671cSchristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
1072ebb5671cSchristos ret = os_snprintf(pos, end - pos, "FT-EAP-SHA384 ");
1073ebb5671cSchristos if (os_snprintf_error(end - pos, ret))
1074ebb5671cSchristos return pos - buf;
1075ebb5671cSchristos pos += ret;
1076ebb5671cSchristos }
1077ebb5671cSchristos #endif /* CONFIG_SHA384 */
107836d97821Schristos #ifdef CONFIG_SAE
107936d97821Schristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
108036d97821Schristos ret = os_snprintf(pos, end - pos, "FT-SAE ");
10819a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
108236d97821Schristos return pos - buf;
108336d97821Schristos pos += ret;
108436d97821Schristos }
108536d97821Schristos #endif /* CONFIG_SAE */
1086ebb5671cSchristos #ifdef CONFIG_FILS
1087ebb5671cSchristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
1088ebb5671cSchristos ret = os_snprintf(pos, end - pos, "FT-FILS-SHA256 ");
1089ebb5671cSchristos if (os_snprintf_error(end - pos, ret))
1090ebb5671cSchristos return pos - buf;
1091ebb5671cSchristos pos += ret;
1092ebb5671cSchristos }
1093ebb5671cSchristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
1094ebb5671cSchristos ret = os_snprintf(pos, end - pos, "FT-FILS-SHA384 ");
1095ebb5671cSchristos if (os_snprintf_error(end - pos, ret))
1096ebb5671cSchristos return pos - buf;
1097ebb5671cSchristos pos += ret;
1098ebb5671cSchristos }
1099ebb5671cSchristos #endif /* CONFIG_FILS */
1100ebb5671cSchristos #endif /* CONFIG_IEEE80211R_AP */
110142669be3Schristos #ifdef CONFIG_IEEE80211W
110242669be3Schristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
110342669be3Schristos ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
11049a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
110542669be3Schristos return pos - buf;
110642669be3Schristos pos += ret;
110742669be3Schristos }
110842669be3Schristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
110942669be3Schristos ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
11109a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
111142669be3Schristos return pos - buf;
111242669be3Schristos pos += ret;
111342669be3Schristos }
111442669be3Schristos #endif /* CONFIG_IEEE80211W */
111536d97821Schristos #ifdef CONFIG_SAE
111636d97821Schristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
111736d97821Schristos ret = os_snprintf(pos, end - pos, "SAE ");
11189a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
111936d97821Schristos return pos - buf;
112036d97821Schristos pos += ret;
112136d97821Schristos }
112236d97821Schristos #endif /* CONFIG_SAE */
11239a53cbbeSchristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
11249a53cbbeSchristos ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
11259a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
11269a53cbbeSchristos return pos - buf;
11279a53cbbeSchristos pos += ret;
11289a53cbbeSchristos }
11299a53cbbeSchristos if (hapd->conf->wpa_key_mgmt &
11309a53cbbeSchristos WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
11319a53cbbeSchristos ret = os_snprintf(pos, end - pos,
11329a53cbbeSchristos "WPA-EAP-SUITE-B-192 ");
11339a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
11349a53cbbeSchristos return pos - buf;
11359a53cbbeSchristos pos += ret;
11369a53cbbeSchristos }
1137ebb5671cSchristos #ifdef CONFIG_FILS
1138ebb5671cSchristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
1139ebb5671cSchristos ret = os_snprintf(pos, end - pos, "FILS-SHA256 ");
1140ebb5671cSchristos if (os_snprintf_error(end - pos, ret))
1141ebb5671cSchristos return pos - buf;
1142ebb5671cSchristos pos += ret;
1143ebb5671cSchristos }
1144ebb5671cSchristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
1145ebb5671cSchristos ret = os_snprintf(pos, end - pos, "FILS-SHA384 ");
1146ebb5671cSchristos if (os_snprintf_error(end - pos, ret))
1147ebb5671cSchristos return pos - buf;
1148ebb5671cSchristos pos += ret;
1149ebb5671cSchristos }
1150ebb5671cSchristos #endif /* CONFIG_FILS */
1151ebb5671cSchristos
1152ebb5671cSchristos #ifdef CONFIG_OWE
1153ebb5671cSchristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
1154ebb5671cSchristos ret = os_snprintf(pos, end - pos, "OWE ");
1155ebb5671cSchristos if (os_snprintf_error(end - pos, ret))
1156ebb5671cSchristos return pos - buf;
1157ebb5671cSchristos pos += ret;
1158ebb5671cSchristos }
1159ebb5671cSchristos #endif /* CONFIG_OWE */
1160ebb5671cSchristos
1161ebb5671cSchristos #ifdef CONFIG_DPP
1162ebb5671cSchristos if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
1163ebb5671cSchristos ret = os_snprintf(pos, end - pos, "DPP ");
1164ebb5671cSchristos if (os_snprintf_error(end - pos, ret))
1165ebb5671cSchristos return pos - buf;
1166ebb5671cSchristos pos += ret;
1167ebb5671cSchristos }
1168ebb5671cSchristos #endif /* CONFIG_DPP */
116942669be3Schristos
1170928750b6Schristos if (pos > buf && *(pos - 1) == ' ') {
1171928750b6Schristos *(pos - 1) = '\0';
1172928750b6Schristos pos--;
1173928750b6Schristos }
1174928750b6Schristos
1175928750b6Schristos return pos - buf;
1176928750b6Schristos }
1177928750b6Schristos
1178928750b6Schristos
hostapd_ctrl_iface_get_config(struct hostapd_data * hapd,char * buf,size_t buflen)1179928750b6Schristos static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
1180928750b6Schristos char *buf, size_t buflen)
1181928750b6Schristos {
1182928750b6Schristos int ret;
1183928750b6Schristos char *pos, *end;
1184928750b6Schristos
1185928750b6Schristos pos = buf;
1186928750b6Schristos end = buf + buflen;
1187928750b6Schristos
1188928750b6Schristos ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
1189928750b6Schristos "ssid=%s\n",
1190928750b6Schristos MAC2STR(hapd->own_addr),
1191928750b6Schristos wpa_ssid_txt(hapd->conf->ssid.ssid,
1192928750b6Schristos hapd->conf->ssid.ssid_len));
1193928750b6Schristos if (os_snprintf_error(end - pos, ret))
1194928750b6Schristos return pos - buf;
1195928750b6Schristos pos += ret;
1196928750b6Schristos
1197928750b6Schristos #ifdef CONFIG_WPS
1198928750b6Schristos ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
1199928750b6Schristos hapd->conf->wps_state == 0 ? "disabled" :
1200928750b6Schristos (hapd->conf->wps_state == 1 ? "not configured" :
1201928750b6Schristos "configured"));
1202928750b6Schristos if (os_snprintf_error(end - pos, ret))
1203928750b6Schristos return pos - buf;
1204928750b6Schristos pos += ret;
1205928750b6Schristos
1206928750b6Schristos if (hapd->conf->wps_state && hapd->conf->wpa &&
1207928750b6Schristos hapd->conf->ssid.wpa_passphrase) {
1208928750b6Schristos ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
1209928750b6Schristos hapd->conf->ssid.wpa_passphrase);
1210928750b6Schristos if (os_snprintf_error(end - pos, ret))
1211928750b6Schristos return pos - buf;
1212928750b6Schristos pos += ret;
1213928750b6Schristos }
1214928750b6Schristos
1215928750b6Schristos if (hapd->conf->wps_state && hapd->conf->wpa &&
1216928750b6Schristos hapd->conf->ssid.wpa_psk &&
1217928750b6Schristos hapd->conf->ssid.wpa_psk->group) {
1218928750b6Schristos char hex[PMK_LEN * 2 + 1];
1219928750b6Schristos wpa_snprintf_hex(hex, sizeof(hex),
1220928750b6Schristos hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
1221928750b6Schristos ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
1222928750b6Schristos if (os_snprintf_error(end - pos, ret))
1223928750b6Schristos return pos - buf;
1224928750b6Schristos pos += ret;
1225928750b6Schristos }
1226928750b6Schristos #endif /* CONFIG_WPS */
1227928750b6Schristos
1228928750b6Schristos if (hapd->conf->wpa) {
1229928750b6Schristos ret = os_snprintf(pos, end - pos, "wpa=%d\n", hapd->conf->wpa);
1230928750b6Schristos if (os_snprintf_error(end - pos, ret))
1231928750b6Schristos return pos - buf;
1232928750b6Schristos pos += ret;
1233928750b6Schristos }
1234928750b6Schristos
1235928750b6Schristos if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
1236928750b6Schristos ret = os_snprintf(pos, end - pos, "key_mgmt=");
1237928750b6Schristos if (os_snprintf_error(end - pos, ret))
1238928750b6Schristos return pos - buf;
1239928750b6Schristos pos += ret;
1240928750b6Schristos
1241928750b6Schristos pos += hostapd_ctrl_iface_get_key_mgmt(hapd, pos, end - pos);
1242928750b6Schristos
124342669be3Schristos ret = os_snprintf(pos, end - pos, "\n");
12449a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
124542669be3Schristos return pos - buf;
124642669be3Schristos pos += ret;
124742669be3Schristos }
124842669be3Schristos
124936d97821Schristos if (hapd->conf->wpa) {
125036d97821Schristos ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
125136d97821Schristos wpa_cipher_txt(hapd->conf->wpa_group));
12529a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
125342669be3Schristos return pos - buf;
125442669be3Schristos pos += ret;
125542669be3Schristos }
125642669be3Schristos
125742669be3Schristos if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
125842669be3Schristos ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
12599a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
126042669be3Schristos return pos - buf;
126142669be3Schristos pos += ret;
126242669be3Schristos
126336d97821Schristos ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
126436d97821Schristos " ");
126536d97821Schristos if (ret < 0)
126642669be3Schristos return pos - buf;
126742669be3Schristos pos += ret;
126842669be3Schristos
126942669be3Schristos ret = os_snprintf(pos, end - pos, "\n");
12709a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
127142669be3Schristos return pos - buf;
127242669be3Schristos pos += ret;
127342669be3Schristos }
127442669be3Schristos
127542669be3Schristos if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
127642669be3Schristos ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
12779a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
127842669be3Schristos return pos - buf;
127942669be3Schristos pos += ret;
128042669be3Schristos
128136d97821Schristos ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise,
128236d97821Schristos " ");
128336d97821Schristos if (ret < 0)
128442669be3Schristos return pos - buf;
128542669be3Schristos pos += ret;
128642669be3Schristos
128742669be3Schristos ret = os_snprintf(pos, end - pos, "\n");
12889a53cbbeSchristos if (os_snprintf_error(end - pos, ret))
128942669be3Schristos return pos - buf;
129042669be3Schristos pos += ret;
129142669be3Schristos }
129242669be3Schristos
129342669be3Schristos return pos - buf;
129442669be3Schristos }
129542669be3Schristos
129642669be3Schristos
hostapd_disassoc_accept_mac(struct hostapd_data * hapd)1297ebb5671cSchristos static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
1298ebb5671cSchristos {
1299ebb5671cSchristos struct sta_info *sta;
1300ebb5671cSchristos struct vlan_description vlan_id;
1301ebb5671cSchristos
1302ebb5671cSchristos if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
1303ebb5671cSchristos return;
1304ebb5671cSchristos
1305ebb5671cSchristos for (sta = hapd->sta_list; sta; sta = sta->next) {
1306ebb5671cSchristos if (!hostapd_maclist_found(hapd->conf->accept_mac,
1307ebb5671cSchristos hapd->conf->num_accept_mac,
1308ebb5671cSchristos sta->addr, &vlan_id) ||
1309ebb5671cSchristos (vlan_id.notempty &&
1310ebb5671cSchristos vlan_compare(&vlan_id, sta->vlan_desc)))
1311ebb5671cSchristos ap_sta_disconnect(hapd, sta, sta->addr,
1312ebb5671cSchristos WLAN_REASON_UNSPECIFIED);
1313ebb5671cSchristos }
1314ebb5671cSchristos }
1315ebb5671cSchristos
1316ebb5671cSchristos
hostapd_disassoc_deny_mac(struct hostapd_data * hapd)1317ebb5671cSchristos static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
1318ebb5671cSchristos {
1319ebb5671cSchristos struct sta_info *sta;
1320ebb5671cSchristos struct vlan_description vlan_id;
1321ebb5671cSchristos
1322ebb5671cSchristos for (sta = hapd->sta_list; sta; sta = sta->next) {
1323ebb5671cSchristos if (hostapd_maclist_found(hapd->conf->deny_mac,
1324ebb5671cSchristos hapd->conf->num_deny_mac, sta->addr,
1325ebb5671cSchristos &vlan_id) &&
1326ebb5671cSchristos (!vlan_id.notempty ||
1327ebb5671cSchristos !vlan_compare(&vlan_id, sta->vlan_desc)))
1328ebb5671cSchristos ap_sta_disconnect(hapd, sta, sta->addr,
1329ebb5671cSchristos WLAN_REASON_UNSPECIFIED);
1330ebb5671cSchristos }
1331ebb5671cSchristos }
1332ebb5671cSchristos
hostapd_ctrl_iface_set(struct hostapd_data * hapd,char * cmd)133342669be3Schristos static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
133442669be3Schristos {
133542669be3Schristos char *value;
133642669be3Schristos int ret = 0;
133742669be3Schristos
133842669be3Schristos value = os_strchr(cmd, ' ');
133942669be3Schristos if (value == NULL)
134042669be3Schristos return -1;
134142669be3Schristos *value++ = '\0';
134242669be3Schristos
134342669be3Schristos wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
134442669be3Schristos if (0) {
134542669be3Schristos #ifdef CONFIG_WPS_TESTING
134642669be3Schristos } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
134742669be3Schristos long int val;
134842669be3Schristos val = strtol(value, NULL, 0);
134942669be3Schristos if (val < 0 || val > 0xff) {
135042669be3Schristos ret = -1;
135142669be3Schristos wpa_printf(MSG_DEBUG, "WPS: Invalid "
135242669be3Schristos "wps_version_number %ld", val);
135342669be3Schristos } else {
135442669be3Schristos wps_version_number = val;
135542669be3Schristos wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
135642669be3Schristos "version %u.%u",
135742669be3Schristos (wps_version_number & 0xf0) >> 4,
135842669be3Schristos wps_version_number & 0x0f);
135942669be3Schristos hostapd_wps_update_ie(hapd);
136042669be3Schristos }
136142669be3Schristos } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
136242669be3Schristos wps_testing_dummy_cred = atoi(value);
136342669be3Schristos wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
136442669be3Schristos wps_testing_dummy_cred);
136536d97821Schristos } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
136636d97821Schristos wps_corrupt_pkhash = atoi(value);
136736d97821Schristos wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
136836d97821Schristos wps_corrupt_pkhash);
136942669be3Schristos #endif /* CONFIG_WPS_TESTING */
137036d97821Schristos #ifdef CONFIG_TESTING_OPTIONS
137136d97821Schristos } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
137236d97821Schristos hapd->ext_mgmt_frame_handling = atoi(value);
13739a53cbbeSchristos } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
13749a53cbbeSchristos hapd->ext_eapol_frame_io = atoi(value);
1375ebb5671cSchristos #ifdef CONFIG_DPP
1376ebb5671cSchristos } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
1377ebb5671cSchristos os_free(hapd->dpp_config_obj_override);
1378ebb5671cSchristos hapd->dpp_config_obj_override = os_strdup(value);
1379ebb5671cSchristos } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
1380ebb5671cSchristos os_free(hapd->dpp_discovery_override);
1381ebb5671cSchristos hapd->dpp_discovery_override = os_strdup(value);
1382ebb5671cSchristos } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
1383ebb5671cSchristos os_free(hapd->dpp_groups_override);
1384ebb5671cSchristos hapd->dpp_groups_override = os_strdup(value);
1385ebb5671cSchristos } else if (os_strcasecmp(cmd,
1386ebb5671cSchristos "dpp_ignore_netaccesskey_mismatch") == 0) {
1387ebb5671cSchristos hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
1388ebb5671cSchristos } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
1389ebb5671cSchristos dpp_test = atoi(value);
1390ebb5671cSchristos #endif /* CONFIG_DPP */
139136d97821Schristos #endif /* CONFIG_TESTING_OPTIONS */
1392928750b6Schristos #ifdef CONFIG_MBO
1393928750b6Schristos } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) {
1394928750b6Schristos int val;
1395928750b6Schristos
1396928750b6Schristos if (!hapd->conf->mbo_enabled)
1397928750b6Schristos return -1;
1398928750b6Schristos
1399928750b6Schristos val = atoi(value);
1400928750b6Schristos if (val < 0 || val > 1)
1401928750b6Schristos return -1;
1402928750b6Schristos
1403928750b6Schristos hapd->mbo_assoc_disallow = val;
1404928750b6Schristos ieee802_11_update_beacons(hapd->iface);
1405928750b6Schristos
1406928750b6Schristos /*
1407928750b6Schristos * TODO: Need to configure drivers that do AP MLME offload with
1408928750b6Schristos * disallowing station logic.
1409928750b6Schristos */
1410928750b6Schristos #endif /* CONFIG_MBO */
1411ebb5671cSchristos #ifdef CONFIG_DPP
1412ebb5671cSchristos } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
1413ebb5671cSchristos os_free(hapd->dpp_configurator_params);
1414ebb5671cSchristos hapd->dpp_configurator_params = os_strdup(value);
1415ebb5671cSchristos #endif /* CONFIG_DPP */
141662a52023Schristos } else {
141762a52023Schristos ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
141836d97821Schristos if (ret)
141936d97821Schristos return ret;
142036d97821Schristos
142136d97821Schristos if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
1422ebb5671cSchristos hostapd_disassoc_deny_mac(hapd);
1423ebb5671cSchristos } else if (os_strcasecmp(cmd, "accept_mac_file") == 0) {
1424ebb5671cSchristos hostapd_disassoc_accept_mac(hapd);
1425ebb5671cSchristos } else if (os_strncmp(cmd, "wme_ac_", 7) == 0 ||
1426ebb5671cSchristos os_strncmp(cmd, "wmm_ac_", 7) == 0) {
1427ebb5671cSchristos hapd->parameter_set_count++;
1428ebb5671cSchristos if (ieee802_11_update_beacons(hapd->iface))
1429ebb5671cSchristos wpa_printf(MSG_DEBUG,
1430ebb5671cSchristos "Failed to update beacons with WMM parameters");
143136d97821Schristos }
143242669be3Schristos }
143342669be3Schristos
143442669be3Schristos return ret;
143542669be3Schristos }
143642669be3Schristos
143742669be3Schristos
hostapd_ctrl_iface_get(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)143842669be3Schristos static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
143942669be3Schristos char *buf, size_t buflen)
144042669be3Schristos {
144142669be3Schristos int res;
144242669be3Schristos
144342669be3Schristos wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
144442669be3Schristos
144542669be3Schristos if (os_strcmp(cmd, "version") == 0) {
144642669be3Schristos res = os_snprintf(buf, buflen, "%s", VERSION_STR);
14479a53cbbeSchristos if (os_snprintf_error(buflen, res))
14489a53cbbeSchristos return -1;
14499a53cbbeSchristos return res;
14509a53cbbeSchristos } else if (os_strcmp(cmd, "tls_library") == 0) {
14519a53cbbeSchristos res = tls_get_library_version(buf, buflen);
14529a53cbbeSchristos if (os_snprintf_error(buflen, res))
145342669be3Schristos return -1;
145442669be3Schristos return res;
145542669be3Schristos }
145642669be3Schristos
145742669be3Schristos return -1;
145842669be3Schristos }
145942669be3Schristos
146042669be3Schristos
hostapd_ctrl_iface_enable(struct hostapd_iface * iface)146162a52023Schristos static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
146262a52023Schristos {
146362a52023Schristos if (hostapd_enable_iface(iface) < 0) {
146462a52023Schristos wpa_printf(MSG_ERROR, "Enabling of interface failed");
146562a52023Schristos return -1;
146662a52023Schristos }
146762a52023Schristos return 0;
146862a52023Schristos }
146962a52023Schristos
147062a52023Schristos
hostapd_ctrl_iface_reload(struct hostapd_iface * iface)147162a52023Schristos static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
147262a52023Schristos {
147362a52023Schristos if (hostapd_reload_iface(iface) < 0) {
147462a52023Schristos wpa_printf(MSG_ERROR, "Reloading of interface failed");
147562a52023Schristos return -1;
147662a52023Schristos }
147762a52023Schristos return 0;
147862a52023Schristos }
147962a52023Schristos
148062a52023Schristos
hostapd_ctrl_iface_disable(struct hostapd_iface * iface)148162a52023Schristos static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
148262a52023Schristos {
148362a52023Schristos if (hostapd_disable_iface(iface) < 0) {
148462a52023Schristos wpa_printf(MSG_ERROR, "Disabling of interface failed");
148562a52023Schristos return -1;
148662a52023Schristos }
148762a52023Schristos return 0;
148862a52023Schristos }
148962a52023Schristos
149062a52023Schristos
1491*0d69f216Schristos static int
hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data * hapd,struct sta_info * sta,void * ctx)1492*0d69f216Schristos hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd,
1493*0d69f216Schristos struct sta_info *sta, void *ctx)
1494*0d69f216Schristos {
1495*0d69f216Schristos struct hostapd_wpa_psk *psk;
1496*0d69f216Schristos const u8 *pmk;
1497*0d69f216Schristos int pmk_len;
1498*0d69f216Schristos int pmk_match;
1499*0d69f216Schristos int sta_match;
1500*0d69f216Schristos int bss_match;
1501*0d69f216Schristos int reason;
1502*0d69f216Schristos
1503*0d69f216Schristos pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
1504*0d69f216Schristos
1505*0d69f216Schristos for (psk = hapd->conf->ssid.wpa_psk; pmk && psk; psk = psk->next) {
1506*0d69f216Schristos pmk_match = PMK_LEN == pmk_len &&
1507*0d69f216Schristos os_memcmp(psk->psk, pmk, pmk_len) == 0;
1508*0d69f216Schristos sta_match = psk->group == 0 &&
1509*0d69f216Schristos os_memcmp(sta->addr, psk->addr, ETH_ALEN) == 0;
1510*0d69f216Schristos bss_match = psk->group == 1;
1511*0d69f216Schristos
1512*0d69f216Schristos if (pmk_match && (sta_match || bss_match))
1513*0d69f216Schristos return 0;
1514*0d69f216Schristos }
1515*0d69f216Schristos
1516*0d69f216Schristos wpa_printf(MSG_INFO, "STA " MACSTR
1517*0d69f216Schristos " PSK/passphrase no longer valid - disconnect",
1518*0d69f216Schristos MAC2STR(sta->addr));
1519*0d69f216Schristos reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
1520*0d69f216Schristos hostapd_drv_sta_deauth(hapd, sta->addr, reason);
1521*0d69f216Schristos ap_sta_deauthenticate(hapd, sta, reason);
1522*0d69f216Schristos
1523*0d69f216Schristos return 0;
1524*0d69f216Schristos }
1525*0d69f216Schristos
1526*0d69f216Schristos
hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data * hapd)1527*0d69f216Schristos static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd)
1528*0d69f216Schristos {
1529*0d69f216Schristos struct hostapd_bss_config *conf = hapd->conf;
1530*0d69f216Schristos int err;
1531*0d69f216Schristos
1532*0d69f216Schristos hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
1533*0d69f216Schristos
1534*0d69f216Schristos err = hostapd_setup_wpa_psk(conf);
1535*0d69f216Schristos if (err < 0) {
1536*0d69f216Schristos wpa_printf(MSG_ERROR, "Reloading WPA-PSK passwords failed: %d",
1537*0d69f216Schristos err);
1538*0d69f216Schristos return -1;
1539*0d69f216Schristos }
1540*0d69f216Schristos
1541*0d69f216Schristos ap_for_each_sta(hapd, hostapd_ctrl_iface_kick_mismatch_psk_sta_iter,
1542*0d69f216Schristos NULL);
1543*0d69f216Schristos
1544*0d69f216Schristos return 0;
1545*0d69f216Schristos }
1546*0d69f216Schristos
1547*0d69f216Schristos
154836d97821Schristos #ifdef CONFIG_TESTING_OPTIONS
154936d97821Schristos
hostapd_ctrl_iface_radar(struct hostapd_data * hapd,char * cmd)155036d97821Schristos static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
155136d97821Schristos {
155236d97821Schristos union wpa_event_data data;
155336d97821Schristos char *pos, *param;
155436d97821Schristos enum wpa_event_type event;
155536d97821Schristos
155636d97821Schristos wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
155736d97821Schristos
155836d97821Schristos os_memset(&data, 0, sizeof(data));
155936d97821Schristos
156036d97821Schristos param = os_strchr(cmd, ' ');
156136d97821Schristos if (param == NULL)
156236d97821Schristos return -1;
156336d97821Schristos *param++ = '\0';
156436d97821Schristos
156536d97821Schristos if (os_strcmp(cmd, "DETECTED") == 0)
156636d97821Schristos event = EVENT_DFS_RADAR_DETECTED;
156736d97821Schristos else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
156836d97821Schristos event = EVENT_DFS_CAC_FINISHED;
156936d97821Schristos else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
157036d97821Schristos event = EVENT_DFS_CAC_ABORTED;
157136d97821Schristos else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
157236d97821Schristos event = EVENT_DFS_NOP_FINISHED;
157336d97821Schristos else {
157436d97821Schristos wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
157536d97821Schristos cmd);
157636d97821Schristos return -1;
157736d97821Schristos }
157836d97821Schristos
157936d97821Schristos pos = os_strstr(param, "freq=");
158036d97821Schristos if (pos)
158136d97821Schristos data.dfs_event.freq = atoi(pos + 5);
158236d97821Schristos
158336d97821Schristos pos = os_strstr(param, "ht_enabled=1");
158436d97821Schristos if (pos)
158536d97821Schristos data.dfs_event.ht_enabled = 1;
158636d97821Schristos
158736d97821Schristos pos = os_strstr(param, "chan_offset=");
158836d97821Schristos if (pos)
158936d97821Schristos data.dfs_event.chan_offset = atoi(pos + 12);
159036d97821Schristos
159136d97821Schristos pos = os_strstr(param, "chan_width=");
159236d97821Schristos if (pos)
159336d97821Schristos data.dfs_event.chan_width = atoi(pos + 11);
159436d97821Schristos
159536d97821Schristos pos = os_strstr(param, "cf1=");
159636d97821Schristos if (pos)
159736d97821Schristos data.dfs_event.cf1 = atoi(pos + 4);
159836d97821Schristos
159936d97821Schristos pos = os_strstr(param, "cf2=");
160036d97821Schristos if (pos)
160136d97821Schristos data.dfs_event.cf2 = atoi(pos + 4);
160236d97821Schristos
160336d97821Schristos wpa_supplicant_event(hapd, event, &data);
160436d97821Schristos
160536d97821Schristos return 0;
160636d97821Schristos }
160736d97821Schristos
160836d97821Schristos
hostapd_ctrl_iface_mgmt_tx(struct hostapd_data * hapd,char * cmd)160936d97821Schristos static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
161036d97821Schristos {
161136d97821Schristos size_t len;
161236d97821Schristos u8 *buf;
161336d97821Schristos int res;
161436d97821Schristos
161536d97821Schristos wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
161636d97821Schristos
161736d97821Schristos len = os_strlen(cmd);
161836d97821Schristos if (len & 1)
161936d97821Schristos return -1;
162036d97821Schristos len /= 2;
162136d97821Schristos
162236d97821Schristos buf = os_malloc(len);
162336d97821Schristos if (buf == NULL)
162436d97821Schristos return -1;
162536d97821Schristos
162636d97821Schristos if (hexstr2bin(cmd, buf, len) < 0) {
162736d97821Schristos os_free(buf);
162836d97821Schristos return -1;
162936d97821Schristos }
163036d97821Schristos
163136d97821Schristos res = hostapd_drv_send_mlme(hapd, buf, len, 0);
163236d97821Schristos os_free(buf);
163336d97821Schristos return res;
163436d97821Schristos }
163536d97821Schristos
16369a53cbbeSchristos
hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data * hapd,char * cmd)1637ebb5671cSchristos static int hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data *hapd,
1638ebb5671cSchristos char *cmd)
1639ebb5671cSchristos {
1640ebb5671cSchristos char *pos, *param;
1641ebb5671cSchristos size_t len;
1642ebb5671cSchristos u8 *buf;
1643ebb5671cSchristos int stype = 0, ok = 0;
1644ebb5671cSchristos union wpa_event_data event;
1645ebb5671cSchristos
1646ebb5671cSchristos if (!hapd->ext_mgmt_frame_handling)
1647ebb5671cSchristos return -1;
1648ebb5671cSchristos
1649ebb5671cSchristos /* stype=<val> ok=<0/1> buf=<frame hexdump> */
1650ebb5671cSchristos
1651ebb5671cSchristos wpa_printf(MSG_DEBUG, "External MGMT TX status process: %s", cmd);
1652ebb5671cSchristos
1653ebb5671cSchristos pos = cmd;
1654ebb5671cSchristos param = os_strstr(pos, "stype=");
1655ebb5671cSchristos if (param) {
1656ebb5671cSchristos param += 6;
1657ebb5671cSchristos stype = atoi(param);
1658ebb5671cSchristos }
1659ebb5671cSchristos
1660ebb5671cSchristos param = os_strstr(pos, " ok=");
1661ebb5671cSchristos if (param) {
1662ebb5671cSchristos param += 4;
1663ebb5671cSchristos ok = atoi(param);
1664ebb5671cSchristos }
1665ebb5671cSchristos
1666ebb5671cSchristos param = os_strstr(pos, " buf=");
1667ebb5671cSchristos if (!param)
1668ebb5671cSchristos return -1;
1669ebb5671cSchristos param += 5;
1670ebb5671cSchristos
1671ebb5671cSchristos len = os_strlen(param);
1672ebb5671cSchristos if (len & 1)
1673ebb5671cSchristos return -1;
1674ebb5671cSchristos len /= 2;
1675ebb5671cSchristos
1676ebb5671cSchristos buf = os_malloc(len);
1677ebb5671cSchristos if (!buf || hexstr2bin(param, buf, len) < 0) {
1678ebb5671cSchristos os_free(buf);
1679ebb5671cSchristos return -1;
1680ebb5671cSchristos }
1681ebb5671cSchristos
1682ebb5671cSchristos os_memset(&event, 0, sizeof(event));
1683ebb5671cSchristos event.tx_status.type = WLAN_FC_TYPE_MGMT;
1684ebb5671cSchristos event.tx_status.data = buf;
1685ebb5671cSchristos event.tx_status.data_len = len;
1686ebb5671cSchristos event.tx_status.stype = stype;
1687ebb5671cSchristos event.tx_status.ack = ok;
1688ebb5671cSchristos hapd->ext_mgmt_frame_handling = 0;
1689ebb5671cSchristos wpa_supplicant_event(hapd, EVENT_TX_STATUS, &event);
1690ebb5671cSchristos hapd->ext_mgmt_frame_handling = 1;
1691ebb5671cSchristos
1692ebb5671cSchristos os_free(buf);
1693ebb5671cSchristos
1694ebb5671cSchristos return 0;
1695ebb5671cSchristos }
1696ebb5671cSchristos
1697ebb5671cSchristos
hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data * hapd,char * cmd)1698ebb5671cSchristos static int hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data *hapd,
1699ebb5671cSchristos char *cmd)
1700ebb5671cSchristos {
1701ebb5671cSchristos char *pos, *param;
1702ebb5671cSchristos size_t len;
1703ebb5671cSchristos u8 *buf;
1704ebb5671cSchristos int freq = 0, datarate = 0, ssi_signal = 0;
1705ebb5671cSchristos union wpa_event_data event;
1706ebb5671cSchristos
1707ebb5671cSchristos if (!hapd->ext_mgmt_frame_handling)
1708ebb5671cSchristos return -1;
1709ebb5671cSchristos
1710ebb5671cSchristos /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
1711ebb5671cSchristos
1712ebb5671cSchristos wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
1713ebb5671cSchristos
1714ebb5671cSchristos pos = cmd;
1715ebb5671cSchristos param = os_strstr(pos, "freq=");
1716ebb5671cSchristos if (param) {
1717ebb5671cSchristos param += 5;
1718ebb5671cSchristos freq = atoi(param);
1719ebb5671cSchristos }
1720ebb5671cSchristos
1721ebb5671cSchristos param = os_strstr(pos, " datarate=");
1722ebb5671cSchristos if (param) {
1723ebb5671cSchristos param += 10;
1724ebb5671cSchristos datarate = atoi(param);
1725ebb5671cSchristos }
1726ebb5671cSchristos
1727ebb5671cSchristos param = os_strstr(pos, " ssi_signal=");
1728ebb5671cSchristos if (param) {
1729ebb5671cSchristos param += 12;
1730ebb5671cSchristos ssi_signal = atoi(param);
1731ebb5671cSchristos }
1732ebb5671cSchristos
1733ebb5671cSchristos param = os_strstr(pos, " frame=");
1734ebb5671cSchristos if (param == NULL)
1735ebb5671cSchristos return -1;
1736ebb5671cSchristos param += 7;
1737ebb5671cSchristos
1738ebb5671cSchristos len = os_strlen(param);
1739ebb5671cSchristos if (len & 1)
1740ebb5671cSchristos return -1;
1741ebb5671cSchristos len /= 2;
1742ebb5671cSchristos
1743ebb5671cSchristos buf = os_malloc(len);
1744ebb5671cSchristos if (buf == NULL)
1745ebb5671cSchristos return -1;
1746ebb5671cSchristos
1747ebb5671cSchristos if (hexstr2bin(param, buf, len) < 0) {
1748ebb5671cSchristos os_free(buf);
1749ebb5671cSchristos return -1;
1750ebb5671cSchristos }
1751ebb5671cSchristos
1752ebb5671cSchristos os_memset(&event, 0, sizeof(event));
1753ebb5671cSchristos event.rx_mgmt.freq = freq;
1754ebb5671cSchristos event.rx_mgmt.frame = buf;
1755ebb5671cSchristos event.rx_mgmt.frame_len = len;
1756ebb5671cSchristos event.rx_mgmt.ssi_signal = ssi_signal;
1757ebb5671cSchristos event.rx_mgmt.datarate = datarate;
1758ebb5671cSchristos hapd->ext_mgmt_frame_handling = 0;
1759ebb5671cSchristos wpa_supplicant_event(hapd, EVENT_RX_MGMT, &event);
1760ebb5671cSchristos hapd->ext_mgmt_frame_handling = 1;
1761ebb5671cSchristos
1762ebb5671cSchristos os_free(buf);
1763ebb5671cSchristos
1764ebb5671cSchristos return 0;
1765ebb5671cSchristos }
1766ebb5671cSchristos
1767ebb5671cSchristos
hostapd_ctrl_iface_eapol_rx(struct hostapd_data * hapd,char * cmd)17689a53cbbeSchristos static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
17699a53cbbeSchristos {
17709a53cbbeSchristos char *pos;
17719a53cbbeSchristos u8 src[ETH_ALEN], *buf;
17729a53cbbeSchristos int used;
17739a53cbbeSchristos size_t len;
17749a53cbbeSchristos
17759a53cbbeSchristos wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
17769a53cbbeSchristos
17779a53cbbeSchristos pos = cmd;
17789a53cbbeSchristos used = hwaddr_aton2(pos, src);
17799a53cbbeSchristos if (used < 0)
17809a53cbbeSchristos return -1;
17819a53cbbeSchristos pos += used;
17829a53cbbeSchristos while (*pos == ' ')
17839a53cbbeSchristos pos++;
17849a53cbbeSchristos
17859a53cbbeSchristos len = os_strlen(pos);
17869a53cbbeSchristos if (len & 1)
17879a53cbbeSchristos return -1;
17889a53cbbeSchristos len /= 2;
17899a53cbbeSchristos
17909a53cbbeSchristos buf = os_malloc(len);
17919a53cbbeSchristos if (buf == NULL)
17929a53cbbeSchristos return -1;
17939a53cbbeSchristos
17949a53cbbeSchristos if (hexstr2bin(pos, buf, len) < 0) {
17959a53cbbeSchristos os_free(buf);
17969a53cbbeSchristos return -1;
17979a53cbbeSchristos }
17989a53cbbeSchristos
17999a53cbbeSchristos ieee802_1x_receive(hapd, src, buf, len);
18009a53cbbeSchristos os_free(buf);
18019a53cbbeSchristos
18029a53cbbeSchristos return 0;
18039a53cbbeSchristos }
18049a53cbbeSchristos
18059a53cbbeSchristos
ipv4_hdr_checksum(const void * buf,size_t len)18069a53cbbeSchristos static u16 ipv4_hdr_checksum(const void *buf, size_t len)
18079a53cbbeSchristos {
18089a53cbbeSchristos size_t i;
18099a53cbbeSchristos u32 sum = 0;
18109a53cbbeSchristos const u16 *pos = buf;
18119a53cbbeSchristos
18129a53cbbeSchristos for (i = 0; i < len / 2; i++)
18139a53cbbeSchristos sum += *pos++;
18149a53cbbeSchristos
18159a53cbbeSchristos while (sum >> 16)
18169a53cbbeSchristos sum = (sum & 0xffff) + (sum >> 16);
18179a53cbbeSchristos
18189a53cbbeSchristos return sum ^ 0xffff;
18199a53cbbeSchristos }
18209a53cbbeSchristos
18219a53cbbeSchristos
18229a53cbbeSchristos #define HWSIM_PACKETLEN 1500
18239a53cbbeSchristos #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
18249a53cbbeSchristos
hostapd_data_test_rx(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)1825928750b6Schristos static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
18269a53cbbeSchristos size_t len)
18279a53cbbeSchristos {
18289a53cbbeSchristos struct hostapd_data *hapd = ctx;
18299a53cbbeSchristos const struct ether_header *eth;
1830928750b6Schristos struct iphdr ip;
18319a53cbbeSchristos const u8 *pos;
18329a53cbbeSchristos unsigned int i;
1833*0d69f216Schristos char extra[30];
18349a53cbbeSchristos
1835*0d69f216Schristos if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
1836*0d69f216Schristos wpa_printf(MSG_DEBUG,
1837*0d69f216Schristos "test data: RX - ignore unexpected length %d",
1838*0d69f216Schristos (int) len);
18399a53cbbeSchristos return;
1840*0d69f216Schristos }
18419a53cbbeSchristos
18429a53cbbeSchristos eth = (const struct ether_header *) buf;
1843928750b6Schristos os_memcpy(&ip, eth + 1, sizeof(ip));
1844928750b6Schristos pos = &buf[sizeof(*eth) + sizeof(ip)];
18459a53cbbeSchristos
1846928750b6Schristos if (ip.ihl != 5 || ip.version != 4 ||
1847*0d69f216Schristos ntohs(ip.tot_len) > HWSIM_IP_LEN) {
1848*0d69f216Schristos wpa_printf(MSG_DEBUG,
1849*0d69f216Schristos "test data: RX - ignore unexpect IP header");
18509a53cbbeSchristos return;
1851*0d69f216Schristos }
18529a53cbbeSchristos
1853*0d69f216Schristos for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
1854*0d69f216Schristos if (*pos != (u8) i) {
1855*0d69f216Schristos wpa_printf(MSG_DEBUG,
1856*0d69f216Schristos "test data: RX - ignore mismatching payload");
18579a53cbbeSchristos return;
1858*0d69f216Schristos }
18599a53cbbeSchristos pos++;
18609a53cbbeSchristos }
18619a53cbbeSchristos
1862*0d69f216Schristos extra[0] = '\0';
1863*0d69f216Schristos if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
1864*0d69f216Schristos os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
1865*0d69f216Schristos wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
1866*0d69f216Schristos MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
18679a53cbbeSchristos }
18689a53cbbeSchristos
18699a53cbbeSchristos
hostapd_ctrl_iface_data_test_config(struct hostapd_data * hapd,char * cmd)18709a53cbbeSchristos static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
18719a53cbbeSchristos char *cmd)
18729a53cbbeSchristos {
18739a53cbbeSchristos int enabled = atoi(cmd);
18749a53cbbeSchristos char *pos;
18759a53cbbeSchristos const char *ifname;
18769a53cbbeSchristos
18779a53cbbeSchristos if (!enabled) {
18789a53cbbeSchristos if (hapd->l2_test) {
18799a53cbbeSchristos l2_packet_deinit(hapd->l2_test);
18809a53cbbeSchristos hapd->l2_test = NULL;
18819a53cbbeSchristos wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
18829a53cbbeSchristos "test data: Disabled");
18839a53cbbeSchristos }
18849a53cbbeSchristos return 0;
18859a53cbbeSchristos }
18869a53cbbeSchristos
18879a53cbbeSchristos if (hapd->l2_test)
18889a53cbbeSchristos return 0;
18899a53cbbeSchristos
18909a53cbbeSchristos pos = os_strstr(cmd, " ifname=");
18919a53cbbeSchristos if (pos)
18929a53cbbeSchristos ifname = pos + 8;
18939a53cbbeSchristos else
18949a53cbbeSchristos ifname = hapd->conf->iface;
18959a53cbbeSchristos
18969a53cbbeSchristos hapd->l2_test = l2_packet_init(ifname, hapd->own_addr,
18979a53cbbeSchristos ETHERTYPE_IP, hostapd_data_test_rx,
18989a53cbbeSchristos hapd, 1);
18999a53cbbeSchristos if (hapd->l2_test == NULL)
19009a53cbbeSchristos return -1;
19019a53cbbeSchristos
19029a53cbbeSchristos wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
19039a53cbbeSchristos
19049a53cbbeSchristos return 0;
19059a53cbbeSchristos }
19069a53cbbeSchristos
19079a53cbbeSchristos
hostapd_ctrl_iface_data_test_tx(struct hostapd_data * hapd,char * cmd)19089a53cbbeSchristos static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
19099a53cbbeSchristos {
19109a53cbbeSchristos u8 dst[ETH_ALEN], src[ETH_ALEN];
1911*0d69f216Schristos char *pos, *pos2;
19129a53cbbeSchristos int used;
19139a53cbbeSchristos long int val;
19149a53cbbeSchristos u8 tos;
1915928750b6Schristos u8 buf[2 + HWSIM_PACKETLEN];
19169a53cbbeSchristos struct ether_header *eth;
19179a53cbbeSchristos struct iphdr *ip;
19189a53cbbeSchristos u8 *dpos;
19199a53cbbeSchristos unsigned int i;
1920*0d69f216Schristos size_t send_len = HWSIM_IP_LEN;
19219a53cbbeSchristos
19229a53cbbeSchristos if (hapd->l2_test == NULL)
19239a53cbbeSchristos return -1;
19249a53cbbeSchristos
1925*0d69f216Schristos /* format: <dst> <src> <tos> [len=<length>] */
19269a53cbbeSchristos
19279a53cbbeSchristos pos = cmd;
19289a53cbbeSchristos used = hwaddr_aton2(pos, dst);
19299a53cbbeSchristos if (used < 0)
19309a53cbbeSchristos return -1;
19319a53cbbeSchristos pos += used;
19329a53cbbeSchristos while (*pos == ' ')
19339a53cbbeSchristos pos++;
19349a53cbbeSchristos used = hwaddr_aton2(pos, src);
19359a53cbbeSchristos if (used < 0)
19369a53cbbeSchristos return -1;
19379a53cbbeSchristos pos += used;
19389a53cbbeSchristos
1939*0d69f216Schristos val = strtol(pos, &pos2, 0);
19409a53cbbeSchristos if (val < 0 || val > 0xff)
19419a53cbbeSchristos return -1;
19429a53cbbeSchristos tos = val;
19439a53cbbeSchristos
1944*0d69f216Schristos pos = os_strstr(pos2, " len=");
1945*0d69f216Schristos if (pos) {
1946*0d69f216Schristos i = atoi(pos + 5);
1947*0d69f216Schristos if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
1948*0d69f216Schristos return -1;
1949*0d69f216Schristos send_len = i;
1950*0d69f216Schristos }
1951*0d69f216Schristos
1952928750b6Schristos eth = (struct ether_header *) &buf[2];
19539a53cbbeSchristos os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
19549a53cbbeSchristos os_memcpy(eth->ether_shost, src, ETH_ALEN);
19559a53cbbeSchristos eth->ether_type = htons(ETHERTYPE_IP);
19569a53cbbeSchristos ip = (struct iphdr *) (eth + 1);
19579a53cbbeSchristos os_memset(ip, 0, sizeof(*ip));
19589a53cbbeSchristos ip->ihl = 5;
19599a53cbbeSchristos ip->version = 4;
19609a53cbbeSchristos ip->ttl = 64;
19619a53cbbeSchristos ip->tos = tos;
1962*0d69f216Schristos ip->tot_len = htons(send_len);
19639a53cbbeSchristos ip->protocol = 1;
1964928750b6Schristos ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
1965928750b6Schristos ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
19669a53cbbeSchristos ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
19679a53cbbeSchristos dpos = (u8 *) (ip + 1);
1968*0d69f216Schristos for (i = 0; i < send_len - sizeof(*ip); i++)
19699a53cbbeSchristos *dpos++ = i;
19709a53cbbeSchristos
1971928750b6Schristos if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
1972*0d69f216Schristos sizeof(struct ether_header) + send_len) < 0)
19739a53cbbeSchristos return -1;
19749a53cbbeSchristos
19759a53cbbeSchristos wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
19769a53cbbeSchristos " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
19779a53cbbeSchristos
19789a53cbbeSchristos return 0;
19799a53cbbeSchristos }
19809a53cbbeSchristos
19819a53cbbeSchristos
hostapd_ctrl_iface_data_test_frame(struct hostapd_data * hapd,char * cmd)19829a53cbbeSchristos static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
19839a53cbbeSchristos char *cmd)
19849a53cbbeSchristos {
19859a53cbbeSchristos u8 *buf;
19869a53cbbeSchristos struct ether_header *eth;
19879a53cbbeSchristos struct l2_packet_data *l2 = NULL;
19889a53cbbeSchristos size_t len;
19899a53cbbeSchristos u16 ethertype;
19909a53cbbeSchristos int res = -1;
19919a53cbbeSchristos const char *ifname = hapd->conf->iface;
19929a53cbbeSchristos
19939a53cbbeSchristos if (os_strncmp(cmd, "ifname=", 7) == 0) {
19949a53cbbeSchristos cmd += 7;
19959a53cbbeSchristos ifname = cmd;
19969a53cbbeSchristos cmd = os_strchr(cmd, ' ');
19979a53cbbeSchristos if (cmd == NULL)
19989a53cbbeSchristos return -1;
19999a53cbbeSchristos *cmd++ = '\0';
20009a53cbbeSchristos }
20019a53cbbeSchristos
20029a53cbbeSchristos len = os_strlen(cmd);
20039a53cbbeSchristos if (len & 1 || len < ETH_HLEN * 2)
20049a53cbbeSchristos return -1;
20059a53cbbeSchristos len /= 2;
20069a53cbbeSchristos
20079a53cbbeSchristos buf = os_malloc(len);
20089a53cbbeSchristos if (buf == NULL)
20099a53cbbeSchristos return -1;
20109a53cbbeSchristos
20119a53cbbeSchristos if (hexstr2bin(cmd, buf, len) < 0)
20129a53cbbeSchristos goto done;
20139a53cbbeSchristos
20149a53cbbeSchristos eth = (struct ether_header *) buf;
20159a53cbbeSchristos ethertype = ntohs(eth->ether_type);
20169a53cbbeSchristos
20179a53cbbeSchristos l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
20189a53cbbeSchristos hostapd_data_test_rx, hapd, 1);
20199a53cbbeSchristos if (l2 == NULL)
20209a53cbbeSchristos goto done;
20219a53cbbeSchristos
20229a53cbbeSchristos res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
20239a53cbbeSchristos wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
20249a53cbbeSchristos done:
20259a53cbbeSchristos if (l2)
20269a53cbbeSchristos l2_packet_deinit(l2);
20279a53cbbeSchristos os_free(buf);
20289a53cbbeSchristos
20299a53cbbeSchristos return res < 0 ? -1 : 0;
20309a53cbbeSchristos }
20319a53cbbeSchristos
20329a53cbbeSchristos
hostapd_ctrl_test_alloc_fail(struct hostapd_data * hapd,char * cmd)20339a53cbbeSchristos static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
20349a53cbbeSchristos {
20359a53cbbeSchristos #ifdef WPA_TRACE_BFD
20369a53cbbeSchristos char *pos;
20379a53cbbeSchristos
20389a53cbbeSchristos wpa_trace_fail_after = atoi(cmd);
20399a53cbbeSchristos pos = os_strchr(cmd, ':');
20409a53cbbeSchristos if (pos) {
20419a53cbbeSchristos pos++;
20429a53cbbeSchristos os_strlcpy(wpa_trace_fail_func, pos,
20439a53cbbeSchristos sizeof(wpa_trace_fail_func));
20449a53cbbeSchristos } else {
20459a53cbbeSchristos wpa_trace_fail_after = 0;
20469a53cbbeSchristos }
20479a53cbbeSchristos
20489a53cbbeSchristos return 0;
20499a53cbbeSchristos #else /* WPA_TRACE_BFD */
20509a53cbbeSchristos return -1;
20519a53cbbeSchristos #endif /* WPA_TRACE_BFD */
20529a53cbbeSchristos }
20539a53cbbeSchristos
20549a53cbbeSchristos
hostapd_ctrl_get_alloc_fail(struct hostapd_data * hapd,char * buf,size_t buflen)20559a53cbbeSchristos static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
20569a53cbbeSchristos char *buf, size_t buflen)
20579a53cbbeSchristos {
20589a53cbbeSchristos #ifdef WPA_TRACE_BFD
20599a53cbbeSchristos return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
20609a53cbbeSchristos wpa_trace_fail_func);
20619a53cbbeSchristos #else /* WPA_TRACE_BFD */
20629a53cbbeSchristos return -1;
20639a53cbbeSchristos #endif /* WPA_TRACE_BFD */
20649a53cbbeSchristos }
20659a53cbbeSchristos
2066928750b6Schristos
hostapd_ctrl_test_fail(struct hostapd_data * hapd,char * cmd)2067928750b6Schristos static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd)
2068928750b6Schristos {
2069928750b6Schristos #ifdef WPA_TRACE_BFD
2070928750b6Schristos char *pos;
2071928750b6Schristos
2072928750b6Schristos wpa_trace_test_fail_after = atoi(cmd);
2073928750b6Schristos pos = os_strchr(cmd, ':');
2074928750b6Schristos if (pos) {
2075928750b6Schristos pos++;
2076928750b6Schristos os_strlcpy(wpa_trace_test_fail_func, pos,
2077928750b6Schristos sizeof(wpa_trace_test_fail_func));
2078928750b6Schristos } else {
2079928750b6Schristos wpa_trace_test_fail_after = 0;
2080928750b6Schristos }
2081928750b6Schristos
2082928750b6Schristos return 0;
2083928750b6Schristos #else /* WPA_TRACE_BFD */
2084928750b6Schristos return -1;
2085928750b6Schristos #endif /* WPA_TRACE_BFD */
2086928750b6Schristos }
2087928750b6Schristos
2088928750b6Schristos
hostapd_ctrl_get_fail(struct hostapd_data * hapd,char * buf,size_t buflen)2089928750b6Schristos static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
2090928750b6Schristos char *buf, size_t buflen)
2091928750b6Schristos {
2092928750b6Schristos #ifdef WPA_TRACE_BFD
2093928750b6Schristos return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
2094928750b6Schristos wpa_trace_test_fail_func);
2095928750b6Schristos #else /* WPA_TRACE_BFD */
2096928750b6Schristos return -1;
2097928750b6Schristos #endif /* WPA_TRACE_BFD */
2098928750b6Schristos }
2099928750b6Schristos
2100ebb5671cSchristos
hostapd_ctrl_reset_pn(struct hostapd_data * hapd,const char * cmd)2101ebb5671cSchristos static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
2102ebb5671cSchristos {
2103ebb5671cSchristos struct sta_info *sta;
2104ebb5671cSchristos u8 addr[ETH_ALEN];
2105ebb5671cSchristos u8 zero[WPA_TK_MAX_LEN];
2106ebb5671cSchristos
2107ebb5671cSchristos os_memset(zero, 0, sizeof(zero));
2108ebb5671cSchristos
2109ebb5671cSchristos if (hwaddr_aton(cmd, addr))
2110ebb5671cSchristos return -1;
2111ebb5671cSchristos
2112ebb5671cSchristos #ifdef CONFIG_IEEE80211W
2113ebb5671cSchristos if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
2114ebb5671cSchristos if (hapd->last_igtk_alg == WPA_ALG_NONE)
2115ebb5671cSchristos return -1;
2116ebb5671cSchristos
2117ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Reset IPN for IGTK");
2118ebb5671cSchristos
2119ebb5671cSchristos /* First, use a zero key to avoid any possible duplicate key
2120ebb5671cSchristos * avoidance in the driver. */
2121ebb5671cSchristos if (hostapd_drv_set_key(hapd->conf->iface, hapd,
2122ebb5671cSchristos hapd->last_igtk_alg,
2123ebb5671cSchristos broadcast_ether_addr,
2124ebb5671cSchristos hapd->last_igtk_key_idx, 1, NULL, 0,
2125ebb5671cSchristos zero, hapd->last_igtk_len) < 0)
2126ebb5671cSchristos return -1;
2127ebb5671cSchristos
2128ebb5671cSchristos /* Set the previously configured key to reset its TSC */
2129ebb5671cSchristos return hostapd_drv_set_key(hapd->conf->iface, hapd,
2130ebb5671cSchristos hapd->last_igtk_alg,
2131ebb5671cSchristos broadcast_ether_addr,
2132ebb5671cSchristos hapd->last_igtk_key_idx, 1, NULL, 0,
2133ebb5671cSchristos hapd->last_igtk,
2134ebb5671cSchristos hapd->last_igtk_len);
2135ebb5671cSchristos }
2136ebb5671cSchristos #endif /* CONFIG_IEEE80211W */
2137ebb5671cSchristos
2138ebb5671cSchristos if (is_broadcast_ether_addr(addr)) {
2139ebb5671cSchristos if (hapd->last_gtk_alg == WPA_ALG_NONE)
2140ebb5671cSchristos return -1;
2141ebb5671cSchristos
2142ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Reset PN for GTK");
2143ebb5671cSchristos
2144ebb5671cSchristos /* First, use a zero key to avoid any possible duplicate key
2145ebb5671cSchristos * avoidance in the driver. */
2146ebb5671cSchristos if (hostapd_drv_set_key(hapd->conf->iface, hapd,
2147ebb5671cSchristos hapd->last_gtk_alg,
2148ebb5671cSchristos broadcast_ether_addr,
2149ebb5671cSchristos hapd->last_gtk_key_idx, 1, NULL, 0,
2150ebb5671cSchristos zero, hapd->last_gtk_len) < 0)
2151ebb5671cSchristos return -1;
2152ebb5671cSchristos
2153ebb5671cSchristos /* Set the previously configured key to reset its TSC */
2154ebb5671cSchristos return hostapd_drv_set_key(hapd->conf->iface, hapd,
2155ebb5671cSchristos hapd->last_gtk_alg,
2156ebb5671cSchristos broadcast_ether_addr,
2157ebb5671cSchristos hapd->last_gtk_key_idx, 1, NULL, 0,
2158ebb5671cSchristos hapd->last_gtk, hapd->last_gtk_len);
2159ebb5671cSchristos }
2160ebb5671cSchristos
2161ebb5671cSchristos sta = ap_get_sta(hapd, addr);
2162ebb5671cSchristos if (!sta)
2163ebb5671cSchristos return -1;
2164ebb5671cSchristos
2165ebb5671cSchristos if (sta->last_tk_alg == WPA_ALG_NONE)
2166ebb5671cSchristos return -1;
2167ebb5671cSchristos
2168ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Reset PN for " MACSTR,
2169ebb5671cSchristos MAC2STR(sta->addr));
2170ebb5671cSchristos
2171ebb5671cSchristos /* First, use a zero key to avoid any possible duplicate key avoidance
2172ebb5671cSchristos * in the driver. */
2173ebb5671cSchristos if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
2174ebb5671cSchristos sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
2175ebb5671cSchristos zero, sta->last_tk_len) < 0)
2176ebb5671cSchristos return -1;
2177ebb5671cSchristos
2178ebb5671cSchristos /* Set the previously configured key to reset its TSC/RSC */
2179ebb5671cSchristos return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
2180ebb5671cSchristos sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
2181ebb5671cSchristos sta->last_tk, sta->last_tk_len);
2182ebb5671cSchristos }
2183ebb5671cSchristos
2184ebb5671cSchristos
hostapd_ctrl_set_key(struct hostapd_data * hapd,const char * cmd)2185ebb5671cSchristos static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
2186ebb5671cSchristos {
2187ebb5671cSchristos u8 addr[ETH_ALEN];
2188ebb5671cSchristos const char *pos = cmd;
2189ebb5671cSchristos enum wpa_alg alg;
2190ebb5671cSchristos int idx, set_tx;
2191ebb5671cSchristos u8 seq[6], key[WPA_TK_MAX_LEN];
2192ebb5671cSchristos size_t key_len;
2193ebb5671cSchristos
2194ebb5671cSchristos /* parameters: alg addr idx set_tx seq key */
2195ebb5671cSchristos
2196ebb5671cSchristos alg = atoi(pos);
2197ebb5671cSchristos pos = os_strchr(pos, ' ');
2198ebb5671cSchristos if (!pos)
2199ebb5671cSchristos return -1;
2200ebb5671cSchristos pos++;
2201ebb5671cSchristos if (hwaddr_aton(pos, addr))
2202ebb5671cSchristos return -1;
2203ebb5671cSchristos pos += 17;
2204ebb5671cSchristos if (*pos != ' ')
2205ebb5671cSchristos return -1;
2206ebb5671cSchristos pos++;
2207ebb5671cSchristos idx = atoi(pos);
2208ebb5671cSchristos pos = os_strchr(pos, ' ');
2209ebb5671cSchristos if (!pos)
2210ebb5671cSchristos return -1;
2211ebb5671cSchristos pos++;
2212ebb5671cSchristos set_tx = atoi(pos);
2213ebb5671cSchristos pos = os_strchr(pos, ' ');
2214ebb5671cSchristos if (!pos)
2215ebb5671cSchristos return -1;
2216ebb5671cSchristos pos++;
2217ebb5671cSchristos if (hexstr2bin(pos, seq, sizeof(seq)) < 0)
2218ebb5671cSchristos return -1;
2219ebb5671cSchristos pos += 2 * 6;
2220ebb5671cSchristos if (*pos != ' ')
2221ebb5671cSchristos return -1;
2222ebb5671cSchristos pos++;
2223ebb5671cSchristos key_len = os_strlen(pos) / 2;
2224ebb5671cSchristos if (hexstr2bin(pos, key, key_len) < 0)
2225ebb5671cSchristos return -1;
2226ebb5671cSchristos
2227ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Set key");
2228ebb5671cSchristos return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx,
2229ebb5671cSchristos set_tx, seq, 6, key, key_len);
2230ebb5671cSchristos }
2231ebb5671cSchristos
2232ebb5671cSchristos
restore_tk(void * ctx1,void * ctx2)2233ebb5671cSchristos static void restore_tk(void *ctx1, void *ctx2)
2234ebb5671cSchristos {
2235ebb5671cSchristos struct hostapd_data *hapd = ctx1;
2236ebb5671cSchristos struct sta_info *sta = ctx2;
2237ebb5671cSchristos
2238ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Restore TK for " MACSTR,
2239ebb5671cSchristos MAC2STR(sta->addr));
2240ebb5671cSchristos /* This does not really restore the TSC properly, so this will result
2241ebb5671cSchristos * in replay protection issues for now since there is no clean way of
2242ebb5671cSchristos * preventing encryption of a single EAPOL frame. */
2243ebb5671cSchristos hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
2244ebb5671cSchristos sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
2245ebb5671cSchristos sta->last_tk, sta->last_tk_len);
2246ebb5671cSchristos }
2247ebb5671cSchristos
2248ebb5671cSchristos
hostapd_ctrl_resend_m1(struct hostapd_data * hapd,const char * cmd)2249ebb5671cSchristos static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
2250ebb5671cSchristos {
2251ebb5671cSchristos struct sta_info *sta;
2252ebb5671cSchristos u8 addr[ETH_ALEN];
2253ebb5671cSchristos int plain = os_strstr(cmd, "plaintext") != NULL;
2254ebb5671cSchristos
2255ebb5671cSchristos if (hwaddr_aton(cmd, addr))
2256ebb5671cSchristos return -1;
2257ebb5671cSchristos
2258ebb5671cSchristos sta = ap_get_sta(hapd, addr);
2259ebb5671cSchristos if (!sta || !sta->wpa_sm)
2260ebb5671cSchristos return -1;
2261ebb5671cSchristos
2262ebb5671cSchristos if (plain && sta->last_tk_alg == WPA_ALG_NONE)
2263ebb5671cSchristos plain = 0; /* no need for special processing */
2264ebb5671cSchristos if (plain) {
2265ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
2266ebb5671cSchristos MAC2STR(sta->addr));
2267ebb5671cSchristos hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
2268ebb5671cSchristos sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
2269ebb5671cSchristos NULL, 0);
2270ebb5671cSchristos }
2271ebb5671cSchristos
2272ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
2273ebb5671cSchristos return wpa_auth_resend_m1(sta->wpa_sm,
2274ebb5671cSchristos os_strstr(cmd, "change-anonce") != NULL,
2275ebb5671cSchristos plain ? restore_tk : NULL, hapd, sta);
2276ebb5671cSchristos }
2277ebb5671cSchristos
2278ebb5671cSchristos
hostapd_ctrl_resend_m3(struct hostapd_data * hapd,const char * cmd)2279ebb5671cSchristos static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
2280ebb5671cSchristos {
2281ebb5671cSchristos struct sta_info *sta;
2282ebb5671cSchristos u8 addr[ETH_ALEN];
2283ebb5671cSchristos int plain = os_strstr(cmd, "plaintext") != NULL;
2284ebb5671cSchristos
2285ebb5671cSchristos if (hwaddr_aton(cmd, addr))
2286ebb5671cSchristos return -1;
2287ebb5671cSchristos
2288ebb5671cSchristos sta = ap_get_sta(hapd, addr);
2289ebb5671cSchristos if (!sta || !sta->wpa_sm)
2290ebb5671cSchristos return -1;
2291ebb5671cSchristos
2292ebb5671cSchristos if (plain && sta->last_tk_alg == WPA_ALG_NONE)
2293ebb5671cSchristos plain = 0; /* no need for special processing */
2294ebb5671cSchristos if (plain) {
2295ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
2296ebb5671cSchristos MAC2STR(sta->addr));
2297ebb5671cSchristos hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
2298ebb5671cSchristos sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
2299ebb5671cSchristos NULL, 0);
2300ebb5671cSchristos }
2301ebb5671cSchristos
2302ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
2303ebb5671cSchristos return wpa_auth_resend_m3(sta->wpa_sm,
2304ebb5671cSchristos plain ? restore_tk : NULL, hapd, sta);
2305ebb5671cSchristos }
2306ebb5671cSchristos
2307ebb5671cSchristos
hostapd_ctrl_resend_group_m1(struct hostapd_data * hapd,const char * cmd)2308ebb5671cSchristos static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
2309ebb5671cSchristos const char *cmd)
2310ebb5671cSchristos {
2311ebb5671cSchristos struct sta_info *sta;
2312ebb5671cSchristos u8 addr[ETH_ALEN];
2313ebb5671cSchristos int plain = os_strstr(cmd, "plaintext") != NULL;
2314ebb5671cSchristos
2315ebb5671cSchristos if (hwaddr_aton(cmd, addr))
2316ebb5671cSchristos return -1;
2317ebb5671cSchristos
2318ebb5671cSchristos sta = ap_get_sta(hapd, addr);
2319ebb5671cSchristos if (!sta || !sta->wpa_sm)
2320ebb5671cSchristos return -1;
2321ebb5671cSchristos
2322ebb5671cSchristos if (plain && sta->last_tk_alg == WPA_ALG_NONE)
2323ebb5671cSchristos plain = 0; /* no need for special processing */
2324ebb5671cSchristos if (plain) {
2325ebb5671cSchristos wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
2326ebb5671cSchristos MAC2STR(sta->addr));
2327ebb5671cSchristos hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
2328ebb5671cSchristos sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
2329ebb5671cSchristos NULL, 0);
2330ebb5671cSchristos }
2331ebb5671cSchristos
2332ebb5671cSchristos wpa_printf(MSG_INFO,
2333ebb5671cSchristos "TESTING: Send group M1 for the same GTK and zero RSC to "
2334ebb5671cSchristos MACSTR, MAC2STR(sta->addr));
2335ebb5671cSchristos return wpa_auth_resend_group_m1(sta->wpa_sm,
2336ebb5671cSchristos plain ? restore_tk : NULL, hapd, sta);
2337ebb5671cSchristos }
2338ebb5671cSchristos
233936d97821Schristos #endif /* CONFIG_TESTING_OPTIONS */
234036d97821Schristos
234136d97821Schristos
hostapd_ctrl_iface_chan_switch(struct hostapd_iface * iface,char * pos)234236d97821Schristos static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
234336d97821Schristos char *pos)
234436d97821Schristos {
234536d97821Schristos #ifdef NEED_AP_MLME
234636d97821Schristos struct csa_settings settings;
234736d97821Schristos int ret;
234836d97821Schristos unsigned int i;
234936d97821Schristos
235036d97821Schristos ret = hostapd_parse_csa_settings(pos, &settings);
235136d97821Schristos if (ret)
235236d97821Schristos return ret;
235336d97821Schristos
235436d97821Schristos for (i = 0; i < iface->num_bss; i++) {
2355ebb5671cSchristos
2356ebb5671cSchristos /* Save CHAN_SWITCH VHT config */
2357ebb5671cSchristos hostapd_chan_switch_vht_config(
2358ebb5671cSchristos iface->bss[i], settings.freq_params.vht_enabled);
2359ebb5671cSchristos
236036d97821Schristos ret = hostapd_switch_channel(iface->bss[i], &settings);
236136d97821Schristos if (ret) {
236236d97821Schristos /* FIX: What do we do if CSA fails in the middle of
236336d97821Schristos * submitting multi-BSS CSA requests? */
236436d97821Schristos return ret;
236536d97821Schristos }
236636d97821Schristos }
236736d97821Schristos
236836d97821Schristos return 0;
236936d97821Schristos #else /* NEED_AP_MLME */
237036d97821Schristos return -1;
237136d97821Schristos #endif /* NEED_AP_MLME */
237236d97821Schristos }
237336d97821Schristos
237436d97821Schristos
hostapd_ctrl_iface_mib(struct hostapd_data * hapd,char * reply,int reply_size,const char * param)237536d97821Schristos static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
237636d97821Schristos int reply_size, const char *param)
237736d97821Schristos {
237836d97821Schristos #ifdef RADIUS_SERVER
237936d97821Schristos if (os_strcmp(param, "radius_server") == 0) {
238036d97821Schristos return radius_server_get_mib(hapd->radius_srv, reply,
238136d97821Schristos reply_size);
238236d97821Schristos }
238336d97821Schristos #endif /* RADIUS_SERVER */
238436d97821Schristos return -1;
238536d97821Schristos }
238636d97821Schristos
238736d97821Schristos
hostapd_ctrl_iface_vendor(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)238836d97821Schristos static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
238936d97821Schristos char *buf, size_t buflen)
239036d97821Schristos {
239136d97821Schristos int ret;
239236d97821Schristos char *pos;
239336d97821Schristos u8 *data = NULL;
239436d97821Schristos unsigned int vendor_id, subcmd;
239536d97821Schristos struct wpabuf *reply;
239636d97821Schristos size_t data_len = 0;
239736d97821Schristos
239836d97821Schristos /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
239936d97821Schristos vendor_id = strtoul(cmd, &pos, 16);
2400928750b6Schristos if (!isblank((unsigned char) *pos))
240136d97821Schristos return -EINVAL;
240236d97821Schristos
240336d97821Schristos subcmd = strtoul(pos, &pos, 10);
240436d97821Schristos
240536d97821Schristos if (*pos != '\0') {
2406928750b6Schristos if (!isblank((unsigned char) *pos++))
240736d97821Schristos return -EINVAL;
240836d97821Schristos data_len = os_strlen(pos);
240936d97821Schristos }
241036d97821Schristos
241136d97821Schristos if (data_len) {
241236d97821Schristos data_len /= 2;
241336d97821Schristos data = os_malloc(data_len);
241436d97821Schristos if (!data)
241536d97821Schristos return -ENOBUFS;
241636d97821Schristos
241736d97821Schristos if (hexstr2bin(pos, data, data_len)) {
241836d97821Schristos wpa_printf(MSG_DEBUG,
241936d97821Schristos "Vendor command: wrong parameter format");
242036d97821Schristos os_free(data);
242136d97821Schristos return -EINVAL;
242236d97821Schristos }
242336d97821Schristos }
242436d97821Schristos
242536d97821Schristos reply = wpabuf_alloc((buflen - 1) / 2);
242636d97821Schristos if (!reply) {
242736d97821Schristos os_free(data);
242836d97821Schristos return -ENOBUFS;
242936d97821Schristos }
243036d97821Schristos
243136d97821Schristos ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
243236d97821Schristos reply);
243336d97821Schristos
243436d97821Schristos if (ret == 0)
243536d97821Schristos ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
243636d97821Schristos wpabuf_len(reply));
243736d97821Schristos
243836d97821Schristos wpabuf_free(reply);
243936d97821Schristos os_free(data);
244036d97821Schristos
244136d97821Schristos return ret;
244236d97821Schristos }
244336d97821Schristos
244436d97821Schristos
hostapd_ctrl_iface_eapol_reauth(struct hostapd_data * hapd,const char * cmd)2445928750b6Schristos static int hostapd_ctrl_iface_eapol_reauth(struct hostapd_data *hapd,
2446928750b6Schristos const char *cmd)
24478dbcf02cSchristos {
2448928750b6Schristos u8 addr[ETH_ALEN];
2449928750b6Schristos struct sta_info *sta;
24508dbcf02cSchristos
2451928750b6Schristos if (hwaddr_aton(cmd, addr))
2452928750b6Schristos return -1;
24538dbcf02cSchristos
2454928750b6Schristos sta = ap_get_sta(hapd, addr);
2455928750b6Schristos if (!sta || !sta->eapol_sm)
2456928750b6Schristos return -1;
2457928750b6Schristos
2458928750b6Schristos eapol_auth_reauthenticate(sta->eapol_sm);
2459928750b6Schristos return 0;
24609a53cbbeSchristos }
2461928750b6Schristos
2462928750b6Schristos
hostapd_ctrl_iface_eapol_set(struct hostapd_data * hapd,char * cmd)2463928750b6Schristos static int hostapd_ctrl_iface_eapol_set(struct hostapd_data *hapd, char *cmd)
2464928750b6Schristos {
2465928750b6Schristos u8 addr[ETH_ALEN];
2466928750b6Schristos struct sta_info *sta;
2467928750b6Schristos char *pos = cmd, *param;
2468928750b6Schristos
2469928750b6Schristos if (hwaddr_aton(pos, addr) || pos[17] != ' ')
2470928750b6Schristos return -1;
2471928750b6Schristos pos += 18;
2472928750b6Schristos param = pos;
2473928750b6Schristos pos = os_strchr(pos, ' ');
2474928750b6Schristos if (!pos)
2475928750b6Schristos return -1;
2476928750b6Schristos *pos++ = '\0';
2477928750b6Schristos
2478928750b6Schristos sta = ap_get_sta(hapd, addr);
2479928750b6Schristos if (!sta || !sta->eapol_sm)
2480928750b6Schristos return -1;
2481928750b6Schristos
2482928750b6Schristos return eapol_auth_set_conf(sta->eapol_sm, param, pos);
24838dbcf02cSchristos }
24848dbcf02cSchristos
2485928750b6Schristos
hostapd_ctrl_iface_log_level(struct hostapd_data * hapd,char * cmd,char * buf,size_t buflen)2486928750b6Schristos static int hostapd_ctrl_iface_log_level(struct hostapd_data *hapd, char *cmd,
2487928750b6Schristos char *buf, size_t buflen)
2488928750b6Schristos {
2489928750b6Schristos char *pos, *end, *stamp;
2490928750b6Schristos int ret;
2491928750b6Schristos
2492928750b6Schristos /* cmd: "LOG_LEVEL [<level>]" */
2493928750b6Schristos if (*cmd == '\0') {
2494928750b6Schristos pos = buf;
2495928750b6Schristos end = buf + buflen;
2496928750b6Schristos ret = os_snprintf(pos, end - pos, "Current level: %s\n"
2497928750b6Schristos "Timestamp: %d\n",
2498928750b6Schristos debug_level_str(wpa_debug_level),
2499928750b6Schristos wpa_debug_timestamp);
2500928750b6Schristos if (os_snprintf_error(end - pos, ret))
2501928750b6Schristos ret = 0;
2502928750b6Schristos
2503928750b6Schristos return ret;
2504928750b6Schristos }
2505928750b6Schristos
2506928750b6Schristos while (*cmd == ' ')
2507928750b6Schristos cmd++;
2508928750b6Schristos
2509928750b6Schristos stamp = os_strchr(cmd, ' ');
2510928750b6Schristos if (stamp) {
2511928750b6Schristos *stamp++ = '\0';
2512928750b6Schristos while (*stamp == ' ') {
2513928750b6Schristos stamp++;
2514928750b6Schristos }
2515928750b6Schristos }
2516928750b6Schristos
2517928750b6Schristos if (os_strlen(cmd)) {
2518928750b6Schristos int level = str_to_debug_level(cmd);
2519928750b6Schristos if (level < 0)
2520928750b6Schristos return -1;
2521928750b6Schristos wpa_debug_level = level;
2522928750b6Schristos }
2523928750b6Schristos
2524928750b6Schristos if (stamp && os_strlen(stamp))
2525928750b6Schristos wpa_debug_timestamp = atoi(stamp);
2526928750b6Schristos
2527928750b6Schristos os_memcpy(buf, "OK\n", 3);
2528928750b6Schristos return 3;
2529928750b6Schristos }
2530928750b6Schristos
2531928750b6Schristos
2532928750b6Schristos #ifdef NEED_AP_MLME
hostapd_ctrl_iface_track_sta_list(struct hostapd_data * hapd,char * buf,size_t buflen)2533928750b6Schristos static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
2534928750b6Schristos char *buf, size_t buflen)
2535928750b6Schristos {
2536928750b6Schristos struct hostapd_iface *iface = hapd->iface;
2537928750b6Schristos char *pos, *end;
2538928750b6Schristos struct hostapd_sta_info *info;
2539928750b6Schristos struct os_reltime now;
2540928750b6Schristos
2541928750b6Schristos if (!iface->num_sta_seen)
2542928750b6Schristos return 0;
2543928750b6Schristos
2544928750b6Schristos sta_track_expire(iface, 0);
2545928750b6Schristos
2546928750b6Schristos pos = buf;
2547928750b6Schristos end = buf + buflen;
2548928750b6Schristos
2549928750b6Schristos os_get_reltime(&now);
2550928750b6Schristos dl_list_for_each_reverse(info, &iface->sta_seen,
2551928750b6Schristos struct hostapd_sta_info, list) {
2552928750b6Schristos struct os_reltime age;
2553928750b6Schristos int ret;
2554928750b6Schristos
2555928750b6Schristos os_reltime_sub(&now, &info->last_seen, &age);
2556ebb5671cSchristos ret = os_snprintf(pos, end - pos, MACSTR " %u %d\n",
2557ebb5671cSchristos MAC2STR(info->addr), (unsigned int) age.sec,
2558ebb5671cSchristos info->ssi_signal);
2559928750b6Schristos if (os_snprintf_error(end - pos, ret))
2560928750b6Schristos break;
2561928750b6Schristos pos += ret;
2562928750b6Schristos }
2563928750b6Schristos
2564928750b6Schristos return pos - buf;
2565928750b6Schristos }
2566928750b6Schristos #endif /* NEED_AP_MLME */
2567928750b6Schristos
2568928750b6Schristos
hostapd_ctrl_iface_req_lci(struct hostapd_data * hapd,const char * cmd)2569928750b6Schristos static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
2570928750b6Schristos const char *cmd)
2571928750b6Schristos {
2572928750b6Schristos u8 addr[ETH_ALEN];
2573928750b6Schristos
2574928750b6Schristos if (hwaddr_aton(cmd, addr)) {
2575928750b6Schristos wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
2576928750b6Schristos return -1;
2577928750b6Schristos }
2578928750b6Schristos
2579928750b6Schristos return hostapd_send_lci_req(hapd, addr);
2580928750b6Schristos }
2581928750b6Schristos
2582928750b6Schristos
hostapd_ctrl_iface_req_range(struct hostapd_data * hapd,char * cmd)2583928750b6Schristos static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
2584928750b6Schristos {
2585928750b6Schristos u8 addr[ETH_ALEN];
2586928750b6Schristos char *token, *context = NULL;
2587928750b6Schristos int random_interval, min_ap;
2588928750b6Schristos u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
2589928750b6Schristos unsigned int n_responders;
2590928750b6Schristos
2591928750b6Schristos token = str_token(cmd, " ", &context);
2592928750b6Schristos if (!token || hwaddr_aton(token, addr)) {
2593928750b6Schristos wpa_printf(MSG_INFO,
2594928750b6Schristos "CTRL: REQ_RANGE - Bad destination address");
2595928750b6Schristos return -1;
2596928750b6Schristos }
2597928750b6Schristos
2598928750b6Schristos token = str_token(cmd, " ", &context);
2599928750b6Schristos if (!token)
2600928750b6Schristos return -1;
2601928750b6Schristos
2602928750b6Schristos random_interval = atoi(token);
2603928750b6Schristos if (random_interval < 0 || random_interval > 0xffff)
2604928750b6Schristos return -1;
2605928750b6Schristos
2606928750b6Schristos token = str_token(cmd, " ", &context);
2607928750b6Schristos if (!token)
2608928750b6Schristos return -1;
2609928750b6Schristos
2610928750b6Schristos min_ap = atoi(token);
2611928750b6Schristos if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
2612928750b6Schristos return -1;
2613928750b6Schristos
2614928750b6Schristos n_responders = 0;
2615928750b6Schristos while ((token = str_token(cmd, " ", &context))) {
2616928750b6Schristos if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
2617928750b6Schristos wpa_printf(MSG_INFO,
2618928750b6Schristos "CTRL: REQ_RANGE: Too many responders");
2619928750b6Schristos return -1;
2620928750b6Schristos }
2621928750b6Schristos
2622928750b6Schristos if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
2623928750b6Schristos wpa_printf(MSG_INFO,
2624928750b6Schristos "CTRL: REQ_RANGE: Bad responder address");
2625928750b6Schristos return -1;
2626928750b6Schristos }
2627928750b6Schristos
2628928750b6Schristos n_responders++;
2629928750b6Schristos }
2630928750b6Schristos
2631928750b6Schristos if (!n_responders) {
2632928750b6Schristos wpa_printf(MSG_INFO,
2633928750b6Schristos "CTRL: REQ_RANGE - No FTM responder address");
2634928750b6Schristos return -1;
2635928750b6Schristos }
2636928750b6Schristos
2637928750b6Schristos return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
2638928750b6Schristos responders, n_responders);
2639928750b6Schristos }
2640928750b6Schristos
2641928750b6Schristos
hostapd_ctrl_iface_req_beacon(struct hostapd_data * hapd,const char * cmd,char * reply,size_t reply_size)2642ebb5671cSchristos static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd,
2643ebb5671cSchristos const char *cmd, char *reply,
2644ebb5671cSchristos size_t reply_size)
2645ebb5671cSchristos {
2646ebb5671cSchristos u8 addr[ETH_ALEN];
2647ebb5671cSchristos const char *pos;
2648ebb5671cSchristos struct wpabuf *req;
2649ebb5671cSchristos int ret;
2650ebb5671cSchristos u8 req_mode = 0;
2651ebb5671cSchristos
2652ebb5671cSchristos if (hwaddr_aton(cmd, addr))
2653ebb5671cSchristos return -1;
2654ebb5671cSchristos pos = os_strchr(cmd, ' ');
2655ebb5671cSchristos if (!pos)
2656ebb5671cSchristos return -1;
2657ebb5671cSchristos pos++;
2658ebb5671cSchristos if (os_strncmp(pos, "req_mode=", 9) == 0) {
2659ebb5671cSchristos int val = hex2byte(pos + 9);
2660ebb5671cSchristos
2661ebb5671cSchristos if (val < 0)
2662ebb5671cSchristos return -1;
2663ebb5671cSchristos req_mode = val;
2664ebb5671cSchristos pos += 11;
2665ebb5671cSchristos pos = os_strchr(pos, ' ');
2666ebb5671cSchristos if (!pos)
2667ebb5671cSchristos return -1;
2668ebb5671cSchristos pos++;
2669ebb5671cSchristos }
2670ebb5671cSchristos req = wpabuf_parse_bin(pos);
2671ebb5671cSchristos if (!req)
2672ebb5671cSchristos return -1;
2673ebb5671cSchristos
2674ebb5671cSchristos ret = hostapd_send_beacon_req(hapd, addr, req_mode, req);
2675ebb5671cSchristos wpabuf_free(req);
2676ebb5671cSchristos if (ret >= 0)
2677ebb5671cSchristos ret = os_snprintf(reply, reply_size, "%d", ret);
2678ebb5671cSchristos return ret;
2679ebb5671cSchristos }
2680ebb5671cSchristos
2681ebb5671cSchristos
hostapd_ctrl_iface_set_neighbor(struct hostapd_data * hapd,char * buf)2682928750b6Schristos static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
2683928750b6Schristos {
2684928750b6Schristos struct wpa_ssid_value ssid;
2685928750b6Schristos u8 bssid[ETH_ALEN];
2686928750b6Schristos struct wpabuf *nr, *lci = NULL, *civic = NULL;
2687ebb5671cSchristos int stationary = 0;
2688928750b6Schristos char *tmp;
2689928750b6Schristos int ret;
2690928750b6Schristos
2691928750b6Schristos if (!(hapd->conf->radio_measurements[0] &
2692928750b6Schristos WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
2693928750b6Schristos wpa_printf(MSG_ERROR,
2694928750b6Schristos "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
2695928750b6Schristos return -1;
2696928750b6Schristos }
2697928750b6Schristos
2698928750b6Schristos if (hwaddr_aton(buf, bssid)) {
2699928750b6Schristos wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
2700928750b6Schristos return -1;
2701928750b6Schristos }
2702928750b6Schristos
2703928750b6Schristos tmp = os_strstr(buf, "ssid=");
2704928750b6Schristos if (!tmp || ssid_parse(tmp + 5, &ssid)) {
2705928750b6Schristos wpa_printf(MSG_ERROR,
2706928750b6Schristos "CTRL: SET_NEIGHBOR: Bad or missing SSID");
2707928750b6Schristos return -1;
2708928750b6Schristos }
2709928750b6Schristos buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
2710928750b6Schristos if (!buf)
2711928750b6Schristos return -1;
2712928750b6Schristos
2713928750b6Schristos tmp = os_strstr(buf, "nr=");
2714928750b6Schristos if (!tmp) {
2715928750b6Schristos wpa_printf(MSG_ERROR,
2716928750b6Schristos "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
2717928750b6Schristos return -1;
2718928750b6Schristos }
2719928750b6Schristos
2720928750b6Schristos buf = os_strchr(tmp, ' ');
2721928750b6Schristos if (buf)
2722928750b6Schristos *buf++ = '\0';
2723928750b6Schristos
2724928750b6Schristos nr = wpabuf_parse_bin(tmp + 3);
2725928750b6Schristos if (!nr) {
2726928750b6Schristos wpa_printf(MSG_ERROR,
2727928750b6Schristos "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
2728928750b6Schristos return -1;
2729928750b6Schristos }
2730928750b6Schristos
2731928750b6Schristos if (!buf)
2732928750b6Schristos goto set;
2733928750b6Schristos
2734928750b6Schristos tmp = os_strstr(buf, "lci=");
2735928750b6Schristos if (tmp) {
2736928750b6Schristos buf = os_strchr(tmp, ' ');
2737928750b6Schristos if (buf)
2738928750b6Schristos *buf++ = '\0';
2739928750b6Schristos lci = wpabuf_parse_bin(tmp + 4);
2740928750b6Schristos if (!lci) {
2741928750b6Schristos wpa_printf(MSG_ERROR,
2742928750b6Schristos "CTRL: SET_NEIGHBOR: Bad LCI subelement");
2743928750b6Schristos wpabuf_free(nr);
2744928750b6Schristos return -1;
2745928750b6Schristos }
2746928750b6Schristos }
2747928750b6Schristos
2748928750b6Schristos if (!buf)
2749928750b6Schristos goto set;
2750928750b6Schristos
2751928750b6Schristos tmp = os_strstr(buf, "civic=");
2752928750b6Schristos if (tmp) {
2753928750b6Schristos buf = os_strchr(tmp, ' ');
2754928750b6Schristos if (buf)
2755928750b6Schristos *buf++ = '\0';
2756928750b6Schristos civic = wpabuf_parse_bin(tmp + 6);
2757928750b6Schristos if (!civic) {
2758928750b6Schristos wpa_printf(MSG_ERROR,
2759928750b6Schristos "CTRL: SET_NEIGHBOR: Bad civic subelement");
2760928750b6Schristos wpabuf_free(nr);
2761928750b6Schristos wpabuf_free(lci);
2762928750b6Schristos return -1;
2763928750b6Schristos }
2764928750b6Schristos }
2765928750b6Schristos
2766ebb5671cSchristos if (!buf)
2767ebb5671cSchristos goto set;
2768ebb5671cSchristos
2769ebb5671cSchristos if (os_strstr(buf, "stat"))
2770ebb5671cSchristos stationary = 1;
2771ebb5671cSchristos
2772928750b6Schristos set:
2773ebb5671cSchristos ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic,
2774ebb5671cSchristos stationary);
2775928750b6Schristos
2776928750b6Schristos wpabuf_free(nr);
2777928750b6Schristos wpabuf_free(lci);
2778928750b6Schristos wpabuf_free(civic);
2779928750b6Schristos
2780928750b6Schristos return ret;
2781928750b6Schristos }
2782928750b6Schristos
2783928750b6Schristos
hostapd_ctrl_iface_remove_neighbor(struct hostapd_data * hapd,char * buf)2784928750b6Schristos static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
2785928750b6Schristos char *buf)
2786928750b6Schristos {
2787928750b6Schristos struct wpa_ssid_value ssid;
2788928750b6Schristos u8 bssid[ETH_ALEN];
2789928750b6Schristos char *tmp;
2790928750b6Schristos
2791928750b6Schristos if (hwaddr_aton(buf, bssid)) {
2792928750b6Schristos wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
2793928750b6Schristos return -1;
2794928750b6Schristos }
2795928750b6Schristos
2796928750b6Schristos tmp = os_strstr(buf, "ssid=");
2797928750b6Schristos if (!tmp || ssid_parse(tmp + 5, &ssid)) {
2798928750b6Schristos wpa_printf(MSG_ERROR,
2799928750b6Schristos "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID");
2800928750b6Schristos return -1;
2801928750b6Schristos }
2802928750b6Schristos
2803928750b6Schristos return hostapd_neighbor_remove(hapd, bssid, &ssid);
2804928750b6Schristos }
2805928750b6Schristos
2806928750b6Schristos
hostapd_ctrl_driver_flags(struct hostapd_iface * iface,char * buf,size_t buflen)2807928750b6Schristos static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
2808928750b6Schristos size_t buflen)
2809928750b6Schristos {
2810928750b6Schristos int ret, i;
2811928750b6Schristos char *pos, *end;
2812928750b6Schristos
2813928750b6Schristos ret = os_snprintf(buf, buflen, "%016llX:\n",
2814928750b6Schristos (long long unsigned) iface->drv_flags);
2815928750b6Schristos if (os_snprintf_error(buflen, ret))
2816928750b6Schristos return -1;
2817928750b6Schristos
2818928750b6Schristos pos = buf + ret;
2819928750b6Schristos end = buf + buflen;
2820928750b6Schristos
2821928750b6Schristos for (i = 0; i < 64; i++) {
2822928750b6Schristos if (iface->drv_flags & (1LLU << i)) {
2823928750b6Schristos ret = os_snprintf(pos, end - pos, "%s\n",
2824928750b6Schristos driver_flag_to_string(1LLU << i));
2825928750b6Schristos if (os_snprintf_error(end - pos, ret))
2826928750b6Schristos return -1;
2827928750b6Schristos pos += ret;
2828928750b6Schristos }
2829928750b6Schristos }
2830928750b6Schristos
2831928750b6Schristos return pos - buf;
2832928750b6Schristos }
2833928750b6Schristos
2834928750b6Schristos
hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry ** acl,int * num,const char * txtaddr)2835ebb5671cSchristos static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
2836ebb5671cSchristos const char *txtaddr)
2837ebb5671cSchristos {
2838ebb5671cSchristos u8 addr[ETH_ALEN];
2839ebb5671cSchristos struct vlan_description vlan_id;
2840ebb5671cSchristos
2841ebb5671cSchristos if (!(*num))
2842ebb5671cSchristos return 0;
2843ebb5671cSchristos
2844ebb5671cSchristos if (hwaddr_aton(txtaddr, addr))
2845ebb5671cSchristos return -1;
2846ebb5671cSchristos
2847ebb5671cSchristos if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
2848ebb5671cSchristos hostapd_remove_acl_mac(acl, num, addr);
2849ebb5671cSchristos
2850ebb5671cSchristos return 0;
2851ebb5671cSchristos }
2852ebb5671cSchristos
2853ebb5671cSchristos
hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry ** acl,int * num)2854ebb5671cSchristos static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
2855ebb5671cSchristos int *num)
2856ebb5671cSchristos {
2857ebb5671cSchristos while (*num)
2858ebb5671cSchristos hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
2859ebb5671cSchristos }
2860ebb5671cSchristos
2861ebb5671cSchristos
hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry * acl,int num,char * buf,size_t buflen)2862ebb5671cSchristos static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
2863ebb5671cSchristos char *buf, size_t buflen)
2864ebb5671cSchristos {
2865ebb5671cSchristos int i = 0, len = 0, ret = 0;
2866ebb5671cSchristos
2867ebb5671cSchristos if (!acl)
2868ebb5671cSchristos return 0;
2869ebb5671cSchristos
2870ebb5671cSchristos while (i < num) {
2871ebb5671cSchristos ret = os_snprintf(buf + len, buflen - len,
2872ebb5671cSchristos MACSTR " VLAN_ID=%d\n",
2873ebb5671cSchristos MAC2STR(acl[i].addr),
2874ebb5671cSchristos acl[i].vlan_id.untagged);
2875ebb5671cSchristos if (ret < 0 || (size_t) ret >= buflen - len)
2876ebb5671cSchristos return len;
2877ebb5671cSchristos i++;
2878ebb5671cSchristos len += ret;
2879ebb5671cSchristos }
2880ebb5671cSchristos return len;
2881ebb5671cSchristos }
2882ebb5671cSchristos
2883ebb5671cSchristos
hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry ** acl,int * num,const char * cmd)2884ebb5671cSchristos static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
2885ebb5671cSchristos const char *cmd)
2886ebb5671cSchristos {
2887ebb5671cSchristos u8 addr[ETH_ALEN];
2888ebb5671cSchristos struct vlan_description vlan_id;
2889ebb5671cSchristos int ret = 0, vlanid = 0;
2890ebb5671cSchristos const char *pos;
2891ebb5671cSchristos
2892ebb5671cSchristos if (hwaddr_aton(cmd, addr))
2893ebb5671cSchristos return -1;
2894ebb5671cSchristos
2895ebb5671cSchristos pos = os_strstr(cmd, "VLAN_ID=");
2896ebb5671cSchristos if (pos)
2897ebb5671cSchristos vlanid = atoi(pos + 8);
2898ebb5671cSchristos
2899ebb5671cSchristos if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
2900ebb5671cSchristos ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
2901ebb5671cSchristos if (ret != -1 && *acl)
2902ebb5671cSchristos qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
2903ebb5671cSchristos }
2904ebb5671cSchristos
2905ebb5671cSchristos return ret < 0 ? -1 : 0;
2906ebb5671cSchristos }
2907ebb5671cSchristos
2908ebb5671cSchristos
hostapd_ctrl_iface_get_capability(struct hostapd_data * hapd,const char * field,char * buf,size_t buflen)2909*0d69f216Schristos static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
2910*0d69f216Schristos const char *field, char *buf,
2911*0d69f216Schristos size_t buflen)
2912*0d69f216Schristos {
2913*0d69f216Schristos wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field);
2914*0d69f216Schristos
2915*0d69f216Schristos #ifdef CONFIG_DPP
2916*0d69f216Schristos if (os_strcmp(field, "dpp") == 0) {
2917*0d69f216Schristos int res;
2918*0d69f216Schristos
2919*0d69f216Schristos #ifdef CONFIG_DPP2
2920*0d69f216Schristos res = os_snprintf(buf, buflen, "DPP=2");
2921*0d69f216Schristos #else /* CONFIG_DPP2 */
2922*0d69f216Schristos res = os_snprintf(buf, buflen, "DPP=1");
2923*0d69f216Schristos #endif /* CONFIG_DPP2 */
2924*0d69f216Schristos if (os_snprintf_error(buflen, res))
2925*0d69f216Schristos return -1;
2926*0d69f216Schristos return res;
2927*0d69f216Schristos }
2928*0d69f216Schristos #endif /* CONFIG_DPP */
2929*0d69f216Schristos
2930*0d69f216Schristos wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
2931*0d69f216Schristos field);
2932*0d69f216Schristos
2933*0d69f216Schristos return -1;
2934*0d69f216Schristos }
2935*0d69f216Schristos
2936*0d69f216Schristos
hostapd_ctrl_iface_receive_process(struct hostapd_data * hapd,char * buf,char * reply,int reply_size,struct sockaddr_storage * from,socklen_t fromlen)2937928750b6Schristos static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
2938928750b6Schristos char *buf, char *reply,
2939928750b6Schristos int reply_size,
2940928750b6Schristos struct sockaddr_storage *from,
2941928750b6Schristos socklen_t fromlen)
2942928750b6Schristos {
2943928750b6Schristos int reply_len, res;
2944928750b6Schristos
29458dbcf02cSchristos os_memcpy(reply, "OK\n", 3);
29468dbcf02cSchristos reply_len = 3;
29478dbcf02cSchristos
29488dbcf02cSchristos if (os_strcmp(buf, "PING") == 0) {
29498dbcf02cSchristos os_memcpy(reply, "PONG\n", 5);
29508dbcf02cSchristos reply_len = 5;
295142669be3Schristos } else if (os_strncmp(buf, "RELOG", 5) == 0) {
295242669be3Schristos if (wpa_debug_reopen_file() < 0)
295342669be3Schristos reply_len = -1;
2954ebb5671cSchristos } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
2955ebb5671cSchristos wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
295636d97821Schristos } else if (os_strcmp(buf, "STATUS") == 0) {
295736d97821Schristos reply_len = hostapd_ctrl_iface_status(hapd, reply,
295836d97821Schristos reply_size);
295936d97821Schristos } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
296036d97821Schristos reply_len = hostapd_drv_status(hapd, reply, reply_size);
29618dbcf02cSchristos } else if (os_strcmp(buf, "MIB") == 0) {
29628dbcf02cSchristos reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
29638dbcf02cSchristos if (reply_len >= 0) {
29648dbcf02cSchristos res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
29658dbcf02cSchristos reply_size - reply_len);
29668dbcf02cSchristos if (res < 0)
29678dbcf02cSchristos reply_len = -1;
29688dbcf02cSchristos else
29698dbcf02cSchristos reply_len += res;
29708dbcf02cSchristos }
29718dbcf02cSchristos if (reply_len >= 0) {
29728dbcf02cSchristos res = ieee802_1x_get_mib(hapd, reply + reply_len,
29738dbcf02cSchristos reply_size - reply_len);
29748dbcf02cSchristos if (res < 0)
29758dbcf02cSchristos reply_len = -1;
29768dbcf02cSchristos else
29778dbcf02cSchristos reply_len += res;
29788dbcf02cSchristos }
29798dbcf02cSchristos #ifndef CONFIG_NO_RADIUS
29808dbcf02cSchristos if (reply_len >= 0) {
29818dbcf02cSchristos res = radius_client_get_mib(hapd->radius,
29828dbcf02cSchristos reply + reply_len,
29838dbcf02cSchristos reply_size - reply_len);
29848dbcf02cSchristos if (res < 0)
29858dbcf02cSchristos reply_len = -1;
29868dbcf02cSchristos else
29878dbcf02cSchristos reply_len += res;
29888dbcf02cSchristos }
29898dbcf02cSchristos #endif /* CONFIG_NO_RADIUS */
299036d97821Schristos } else if (os_strncmp(buf, "MIB ", 4) == 0) {
299136d97821Schristos reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
299236d97821Schristos buf + 4);
29938dbcf02cSchristos } else if (os_strcmp(buf, "STA-FIRST") == 0) {
29948dbcf02cSchristos reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
29958dbcf02cSchristos reply_size);
29968dbcf02cSchristos } else if (os_strncmp(buf, "STA ", 4) == 0) {
29978dbcf02cSchristos reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
29988dbcf02cSchristos reply_size);
29998dbcf02cSchristos } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
30008dbcf02cSchristos reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
30018dbcf02cSchristos reply_size);
30028dbcf02cSchristos } else if (os_strcmp(buf, "ATTACH") == 0) {
3003ebb5671cSchristos if (hostapd_ctrl_iface_attach(hapd, from, fromlen, NULL))
3004ebb5671cSchristos reply_len = -1;
3005ebb5671cSchristos } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
3006ebb5671cSchristos if (hostapd_ctrl_iface_attach(hapd, from, fromlen, buf + 7))
30078dbcf02cSchristos reply_len = -1;
30088dbcf02cSchristos } else if (os_strcmp(buf, "DETACH") == 0) {
3009928750b6Schristos if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
30108dbcf02cSchristos reply_len = -1;
30118dbcf02cSchristos } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
3012928750b6Schristos if (hostapd_ctrl_iface_level(hapd, from, fromlen,
30138dbcf02cSchristos buf + 6))
30148dbcf02cSchristos reply_len = -1;
30158dbcf02cSchristos } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
30168dbcf02cSchristos if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
30178dbcf02cSchristos reply_len = -1;
30188dbcf02cSchristos } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
30198dbcf02cSchristos if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
30208dbcf02cSchristos reply_len = -1;
30218dbcf02cSchristos } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
30228dbcf02cSchristos if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
30238dbcf02cSchristos reply_len = -1;
3024928750b6Schristos #ifdef CONFIG_TAXONOMY
3025928750b6Schristos } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) {
3026928750b6Schristos reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10,
3027928750b6Schristos reply, reply_size);
3028928750b6Schristos #endif /* CONFIG_TAXONOMY */
3029928750b6Schristos } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
3030928750b6Schristos if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
3031928750b6Schristos reply_len = -1;
30329a53cbbeSchristos } else if (os_strcmp(buf, "STOP_AP") == 0) {
30339a53cbbeSchristos if (hostapd_ctrl_iface_stop_ap(hapd))
30349a53cbbeSchristos reply_len = -1;
30358dbcf02cSchristos #ifdef CONFIG_IEEE80211W
30368dbcf02cSchristos #ifdef NEED_AP_MLME
30378dbcf02cSchristos } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
30388dbcf02cSchristos if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
30398dbcf02cSchristos reply_len = -1;
30408dbcf02cSchristos #endif /* NEED_AP_MLME */
30418dbcf02cSchristos #endif /* CONFIG_IEEE80211W */
30428dbcf02cSchristos #ifdef CONFIG_WPS
30438dbcf02cSchristos } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
30448dbcf02cSchristos if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
30458dbcf02cSchristos reply_len = -1;
304642669be3Schristos } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
304742669be3Schristos reply_len = hostapd_ctrl_iface_wps_check_pin(
304842669be3Schristos hapd, buf + 14, reply, reply_size);
30498dbcf02cSchristos } else if (os_strcmp(buf, "WPS_PBC") == 0) {
305042669be3Schristos if (hostapd_wps_button_pushed(hapd, NULL))
30518dbcf02cSchristos reply_len = -1;
305262a52023Schristos } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
305362a52023Schristos if (hostapd_wps_cancel(hapd))
30548dbcf02cSchristos reply_len = -1;
30551b7205bfSchristos } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
30561b7205bfSchristos reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
30571b7205bfSchristos reply, reply_size);
305842669be3Schristos } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
305942669be3Schristos if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
306042669be3Schristos reply_len = -1;
306136d97821Schristos } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
306236d97821Schristos reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
306336d97821Schristos reply_size);
306462a52023Schristos #ifdef CONFIG_WPS_NFC
306562a52023Schristos } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
306662a52023Schristos if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
306762a52023Schristos reply_len = -1;
306862a52023Schristos } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
306962a52023Schristos reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
307062a52023Schristos hapd, buf + 21, reply, reply_size);
307162a52023Schristos } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
307262a52023Schristos reply_len = hostapd_ctrl_iface_wps_nfc_token(
307362a52023Schristos hapd, buf + 14, reply, reply_size);
307436d97821Schristos } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
307536d97821Schristos reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
307636d97821Schristos hapd, buf + 21, reply, reply_size);
307736d97821Schristos } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
307836d97821Schristos if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
307936d97821Schristos reply_len = -1;
308062a52023Schristos #endif /* CONFIG_WPS_NFC */
30818dbcf02cSchristos #endif /* CONFIG_WPS */
308236d97821Schristos #ifdef CONFIG_INTERWORKING
308336d97821Schristos } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
308436d97821Schristos if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
308536d97821Schristos reply_len = -1;
308636d97821Schristos } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
308736d97821Schristos if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
308836d97821Schristos reply_len = -1;
308936d97821Schristos #endif /* CONFIG_INTERWORKING */
309036d97821Schristos #ifdef CONFIG_HS20
309136d97821Schristos } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
309236d97821Schristos if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
309336d97821Schristos reply_len = -1;
309436d97821Schristos } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
309536d97821Schristos if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
309636d97821Schristos reply_len = -1;
309736d97821Schristos #endif /* CONFIG_HS20 */
3098ebb5671cSchristos #ifdef CONFIG_WNM_AP
309962a52023Schristos } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
310062a52023Schristos if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
310162a52023Schristos reply_len = -1;
310242669be3Schristos } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
310342669be3Schristos if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
310442669be3Schristos reply_len = -1;
31059a53cbbeSchristos } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
31069a53cbbeSchristos if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
31079a53cbbeSchristos reply_len = -1;
3108ebb5671cSchristos } else if (os_strncmp(buf, "COLOC_INTF_REQ ", 15) == 0) {
3109ebb5671cSchristos if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
3110ebb5671cSchristos reply_len = -1;
3111ebb5671cSchristos #endif /* CONFIG_WNM_AP */
311242669be3Schristos } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
311342669be3Schristos reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
311442669be3Schristos reply_size);
311542669be3Schristos } else if (os_strncmp(buf, "SET ", 4) == 0) {
311642669be3Schristos if (hostapd_ctrl_iface_set(hapd, buf + 4))
311742669be3Schristos reply_len = -1;
311842669be3Schristos } else if (os_strncmp(buf, "GET ", 4) == 0) {
311942669be3Schristos reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
312042669be3Schristos reply_size);
312162a52023Schristos } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
312262a52023Schristos if (hostapd_ctrl_iface_enable(hapd->iface))
312362a52023Schristos reply_len = -1;
3124*0d69f216Schristos } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) {
3125*0d69f216Schristos if (hostapd_ctrl_iface_reload_wpa_psk(hapd))
3126*0d69f216Schristos reply_len = -1;
312762a52023Schristos } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
312862a52023Schristos if (hostapd_ctrl_iface_reload(hapd->iface))
312962a52023Schristos reply_len = -1;
313062a52023Schristos } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
313162a52023Schristos if (hostapd_ctrl_iface_disable(hapd->iface))
313262a52023Schristos reply_len = -1;
31339a53cbbeSchristos } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
31349a53cbbeSchristos if (ieee802_11_set_beacon(hapd))
31359a53cbbeSchristos reply_len = -1;
313636d97821Schristos #ifdef CONFIG_TESTING_OPTIONS
313736d97821Schristos } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
313836d97821Schristos if (hostapd_ctrl_iface_radar(hapd, buf + 6))
313936d97821Schristos reply_len = -1;
314036d97821Schristos } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
314136d97821Schristos if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
314236d97821Schristos reply_len = -1;
3143ebb5671cSchristos } else if (os_strncmp(buf, "MGMT_TX_STATUS_PROCESS ", 23) == 0) {
3144ebb5671cSchristos if (hostapd_ctrl_iface_mgmt_tx_status_process(hapd,
3145ebb5671cSchristos buf + 23) < 0)
3146ebb5671cSchristos reply_len = -1;
3147ebb5671cSchristos } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
3148ebb5671cSchristos if (hostapd_ctrl_iface_mgmt_rx_process(hapd, buf + 16) < 0)
3149ebb5671cSchristos reply_len = -1;
31509a53cbbeSchristos } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
31519a53cbbeSchristos if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
31529a53cbbeSchristos reply_len = -1;
31539a53cbbeSchristos } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
31549a53cbbeSchristos if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
31559a53cbbeSchristos reply_len = -1;
31569a53cbbeSchristos } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
31579a53cbbeSchristos if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
31589a53cbbeSchristos reply_len = -1;
31599a53cbbeSchristos } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
31609a53cbbeSchristos if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
31619a53cbbeSchristos reply_len = -1;
31629a53cbbeSchristos } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
31639a53cbbeSchristos if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
31649a53cbbeSchristos reply_len = -1;
31659a53cbbeSchristos } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
31669a53cbbeSchristos reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
31679a53cbbeSchristos reply_size);
3168928750b6Schristos } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
3169928750b6Schristos if (hostapd_ctrl_test_fail(hapd, buf + 10) < 0)
3170928750b6Schristos reply_len = -1;
3171928750b6Schristos } else if (os_strcmp(buf, "GET_FAIL") == 0) {
3172928750b6Schristos reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size);
3173ebb5671cSchristos } else if (os_strncmp(buf, "RESET_PN ", 9) == 0) {
3174ebb5671cSchristos if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 0)
3175ebb5671cSchristos reply_len = -1;
3176ebb5671cSchristos } else if (os_strncmp(buf, "SET_KEY ", 8) == 0) {
3177ebb5671cSchristos if (hostapd_ctrl_set_key(hapd, buf + 8) < 0)
3178ebb5671cSchristos reply_len = -1;
3179ebb5671cSchristos } else if (os_strncmp(buf, "RESEND_M1 ", 10) == 0) {
3180ebb5671cSchristos if (hostapd_ctrl_resend_m1(hapd, buf + 10) < 0)
3181ebb5671cSchristos reply_len = -1;
3182ebb5671cSchristos } else if (os_strncmp(buf, "RESEND_M3 ", 10) == 0) {
3183ebb5671cSchristos if (hostapd_ctrl_resend_m3(hapd, buf + 10) < 0)
3184ebb5671cSchristos reply_len = -1;
3185ebb5671cSchristos } else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) {
3186ebb5671cSchristos if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0)
3187ebb5671cSchristos reply_len = -1;
3188ebb5671cSchristos } else if (os_strcmp(buf, "REKEY_GTK") == 0) {
3189ebb5671cSchristos if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
3190ebb5671cSchristos reply_len = -1;
319136d97821Schristos #endif /* CONFIG_TESTING_OPTIONS */
319236d97821Schristos } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
319336d97821Schristos if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
319436d97821Schristos reply_len = -1;
319536d97821Schristos } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
319636d97821Schristos reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
319736d97821Schristos reply_size);
31989a53cbbeSchristos } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
31999a53cbbeSchristos ieee802_1x_erp_flush(hapd);
32009a53cbbeSchristos #ifdef RADIUS_SERVER
32019a53cbbeSchristos radius_server_erp_flush(hapd->radius_srv);
32029a53cbbeSchristos #endif /* RADIUS_SERVER */
3203928750b6Schristos } else if (os_strncmp(buf, "EAPOL_REAUTH ", 13) == 0) {
3204928750b6Schristos if (hostapd_ctrl_iface_eapol_reauth(hapd, buf + 13))
3205928750b6Schristos reply_len = -1;
3206928750b6Schristos } else if (os_strncmp(buf, "EAPOL_SET ", 10) == 0) {
3207928750b6Schristos if (hostapd_ctrl_iface_eapol_set(hapd, buf + 10))
3208928750b6Schristos reply_len = -1;
3209928750b6Schristos } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
3210928750b6Schristos reply_len = hostapd_ctrl_iface_log_level(
3211928750b6Schristos hapd, buf + 9, reply, reply_size);
3212928750b6Schristos #ifdef NEED_AP_MLME
3213928750b6Schristos } else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
3214928750b6Schristos reply_len = hostapd_ctrl_iface_track_sta_list(
3215928750b6Schristos hapd, reply, reply_size);
3216928750b6Schristos #endif /* NEED_AP_MLME */
3217928750b6Schristos } else if (os_strcmp(buf, "PMKSA") == 0) {
3218928750b6Schristos reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
3219928750b6Schristos reply_size);
3220928750b6Schristos } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
3221928750b6Schristos hostapd_ctrl_iface_pmksa_flush(hapd);
3222ebb5671cSchristos } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
3223ebb5671cSchristos if (hostapd_ctrl_iface_pmksa_add(hapd, buf + 10) < 0)
3224ebb5671cSchristos reply_len = -1;
3225928750b6Schristos } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
3226928750b6Schristos if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
3227928750b6Schristos reply_len = -1;
3228928750b6Schristos } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
3229928750b6Schristos if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
3230928750b6Schristos reply_len = -1;
3231928750b6Schristos } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
3232928750b6Schristos if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
3233928750b6Schristos reply_len = -1;
3234928750b6Schristos } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
3235928750b6Schristos if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
3236928750b6Schristos reply_len = -1;
3237ebb5671cSchristos } else if (os_strncmp(buf, "REQ_BEACON ", 11) == 0) {
3238ebb5671cSchristos reply_len = hostapd_ctrl_iface_req_beacon(hapd, buf + 11,
3239ebb5671cSchristos reply, reply_size);
3240928750b6Schristos } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
3241928750b6Schristos reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
3242928750b6Schristos reply_size);
3243ebb5671cSchristos } else if (os_strcmp(buf, "TERMINATE") == 0) {
3244ebb5671cSchristos eloop_terminate();
3245ebb5671cSchristos } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
3246ebb5671cSchristos if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
3247ebb5671cSchristos if (!hostapd_ctrl_iface_acl_add_mac(
3248ebb5671cSchristos &hapd->conf->accept_mac,
3249ebb5671cSchristos &hapd->conf->num_accept_mac, buf + 19))
3250ebb5671cSchristos hostapd_disassoc_accept_mac(hapd);
3251ebb5671cSchristos else
3252ebb5671cSchristos reply_len = -1;
3253ebb5671cSchristos } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
3254ebb5671cSchristos hostapd_ctrl_iface_acl_del_mac(
3255ebb5671cSchristos &hapd->conf->accept_mac,
3256ebb5671cSchristos &hapd->conf->num_accept_mac, buf + 19);
3257ebb5671cSchristos } else if (os_strcmp(buf + 11, "SHOW") == 0) {
3258ebb5671cSchristos reply_len = hostapd_ctrl_iface_acl_show_mac(
3259ebb5671cSchristos hapd->conf->accept_mac,
3260ebb5671cSchristos hapd->conf->num_accept_mac, reply, reply_size);
3261ebb5671cSchristos } else if (os_strcmp(buf + 11, "CLEAR") == 0) {
3262ebb5671cSchristos hostapd_ctrl_iface_acl_clear_list(
3263ebb5671cSchristos &hapd->conf->accept_mac,
3264ebb5671cSchristos &hapd->conf->num_accept_mac);
3265ebb5671cSchristos }
3266ebb5671cSchristos } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
3267ebb5671cSchristos if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
3268ebb5671cSchristos if (!hostapd_ctrl_iface_acl_add_mac(
3269ebb5671cSchristos &hapd->conf->deny_mac,
3270ebb5671cSchristos &hapd->conf->num_deny_mac, buf + 17))
3271ebb5671cSchristos hostapd_disassoc_deny_mac(hapd);
3272ebb5671cSchristos } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
3273ebb5671cSchristos hostapd_ctrl_iface_acl_del_mac(
3274ebb5671cSchristos &hapd->conf->deny_mac,
3275ebb5671cSchristos &hapd->conf->num_deny_mac, buf + 17);
3276ebb5671cSchristos } else if (os_strcmp(buf + 9, "SHOW") == 0) {
3277ebb5671cSchristos reply_len = hostapd_ctrl_iface_acl_show_mac(
3278ebb5671cSchristos hapd->conf->deny_mac,
3279ebb5671cSchristos hapd->conf->num_deny_mac, reply, reply_size);
3280ebb5671cSchristos } else if (os_strcmp(buf + 9, "CLEAR") == 0) {
3281ebb5671cSchristos hostapd_ctrl_iface_acl_clear_list(
3282ebb5671cSchristos &hapd->conf->deny_mac,
3283ebb5671cSchristos &hapd->conf->num_deny_mac);
3284ebb5671cSchristos }
3285ebb5671cSchristos #ifdef CONFIG_DPP
3286ebb5671cSchristos } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
3287ebb5671cSchristos res = hostapd_dpp_qr_code(hapd, buf + 12);
3288ebb5671cSchristos if (res < 0) {
3289ebb5671cSchristos reply_len = -1;
3290ebb5671cSchristos } else {
3291ebb5671cSchristos reply_len = os_snprintf(reply, reply_size, "%d", res);
3292ebb5671cSchristos if (os_snprintf_error(reply_size, reply_len))
3293ebb5671cSchristos reply_len = -1;
3294ebb5671cSchristos }
3295ebb5671cSchristos } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
3296*0d69f216Schristos res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
3297ebb5671cSchristos if (res < 0) {
3298ebb5671cSchristos reply_len = -1;
3299ebb5671cSchristos } else {
3300ebb5671cSchristos reply_len = os_snprintf(reply, reply_size, "%d", res);
3301ebb5671cSchristos if (os_snprintf_error(reply_size, reply_len))
3302ebb5671cSchristos reply_len = -1;
3303ebb5671cSchristos }
3304ebb5671cSchristos } else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
3305*0d69f216Schristos if (dpp_bootstrap_remove(hapd->iface->interfaces->dpp,
3306*0d69f216Schristos buf + 21) < 0)
3307ebb5671cSchristos reply_len = -1;
3308ebb5671cSchristos } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
3309ebb5671cSchristos const char *uri;
3310ebb5671cSchristos
3311*0d69f216Schristos uri = dpp_bootstrap_get_uri(hapd->iface->interfaces->dpp,
3312*0d69f216Schristos atoi(buf + 22));
3313ebb5671cSchristos if (!uri) {
3314ebb5671cSchristos reply_len = -1;
3315ebb5671cSchristos } else {
3316ebb5671cSchristos reply_len = os_snprintf(reply, reply_size, "%s", uri);
3317ebb5671cSchristos if (os_snprintf_error(reply_size, reply_len))
3318ebb5671cSchristos reply_len = -1;
3319ebb5671cSchristos }
3320ebb5671cSchristos } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
3321*0d69f216Schristos reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
3322*0d69f216Schristos atoi(buf + 19),
3323ebb5671cSchristos reply, reply_size);
3324ebb5671cSchristos } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
3325ebb5671cSchristos if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
3326ebb5671cSchristos reply_len = -1;
3327ebb5671cSchristos } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
3328ebb5671cSchristos if (hostapd_dpp_listen(hapd, buf + 11) < 0)
3329ebb5671cSchristos reply_len = -1;
3330ebb5671cSchristos } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
3331ebb5671cSchristos hostapd_dpp_stop(hapd);
3332ebb5671cSchristos hostapd_dpp_listen_stop(hapd);
3333ebb5671cSchristos } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
3334*0d69f216Schristos res = dpp_configurator_add(hapd->iface->interfaces->dpp,
3335*0d69f216Schristos buf + 20);
3336ebb5671cSchristos if (res < 0) {
3337ebb5671cSchristos reply_len = -1;
3338ebb5671cSchristos } else {
3339ebb5671cSchristos reply_len = os_snprintf(reply, reply_size, "%d", res);
3340ebb5671cSchristos if (os_snprintf_error(reply_size, reply_len))
3341ebb5671cSchristos reply_len = -1;
3342ebb5671cSchristos }
3343ebb5671cSchristos } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
3344*0d69f216Schristos if (dpp_configurator_remove(hapd->iface->interfaces->dpp,
3345*0d69f216Schristos buf + 24) < 0)
3346ebb5671cSchristos reply_len = -1;
3347ebb5671cSchristos } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
3348*0d69f216Schristos if (hostapd_dpp_configurator_sign(hapd, buf + 21) < 0)
3349ebb5671cSchristos reply_len = -1;
3350ebb5671cSchristos } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
3351*0d69f216Schristos reply_len = dpp_configurator_get_key_id(
3352*0d69f216Schristos hapd->iface->interfaces->dpp,
3353ebb5671cSchristos atoi(buf + 25),
3354ebb5671cSchristos reply, reply_size);
3355ebb5671cSchristos } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
3356ebb5671cSchristos res = hostapd_dpp_pkex_add(hapd, buf + 12);
3357ebb5671cSchristos if (res < 0) {
3358ebb5671cSchristos reply_len = -1;
3359ebb5671cSchristos } else {
3360ebb5671cSchristos reply_len = os_snprintf(reply, reply_size, "%d", res);
3361ebb5671cSchristos if (os_snprintf_error(reply_size, reply_len))
3362ebb5671cSchristos reply_len = -1;
3363ebb5671cSchristos }
3364ebb5671cSchristos } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
3365ebb5671cSchristos if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
3366ebb5671cSchristos reply_len = -1;
3367ebb5671cSchristos #endif /* CONFIG_DPP */
3368ebb5671cSchristos #ifdef RADIUS_SERVER
3369ebb5671cSchristos } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
3370ebb5671cSchristos if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
3371ebb5671cSchristos reply_len = -1;
3372ebb5671cSchristos #endif /* RADIUS_SERVER */
3373*0d69f216Schristos } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
3374*0d69f216Schristos reply_len = hostapd_ctrl_iface_get_capability(
3375*0d69f216Schristos hapd, buf + 15, reply, reply_size);
33768dbcf02cSchristos } else {
33778dbcf02cSchristos os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
33788dbcf02cSchristos reply_len = 16;
33798dbcf02cSchristos }
33808dbcf02cSchristos
33818dbcf02cSchristos if (reply_len < 0) {
33828dbcf02cSchristos os_memcpy(reply, "FAIL\n", 5);
33838dbcf02cSchristos reply_len = 5;
33848dbcf02cSchristos }
3385928750b6Schristos
3386928750b6Schristos return reply_len;
3387928750b6Schristos }
3388928750b6Schristos
3389928750b6Schristos
hostapd_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)3390928750b6Schristos static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
3391928750b6Schristos void *sock_ctx)
3392928750b6Schristos {
3393928750b6Schristos struct hostapd_data *hapd = eloop_ctx;
3394928750b6Schristos char buf[4096];
3395928750b6Schristos int res;
3396928750b6Schristos struct sockaddr_storage from;
3397928750b6Schristos socklen_t fromlen = sizeof(from);
3398928750b6Schristos char *reply, *pos = buf;
3399928750b6Schristos const int reply_size = 4096;
3400928750b6Schristos int reply_len;
3401928750b6Schristos int level = MSG_DEBUG;
3402928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP
3403928750b6Schristos unsigned char lcookie[COOKIE_LEN];
3404928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
3405928750b6Schristos
3406928750b6Schristos res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
3407928750b6Schristos (struct sockaddr *) &from, &fromlen);
3408928750b6Schristos if (res < 0) {
3409928750b6Schristos wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
3410928750b6Schristos strerror(errno));
3411928750b6Schristos return;
3412928750b6Schristos }
3413928750b6Schristos buf[res] = '\0';
3414928750b6Schristos
3415928750b6Schristos reply = os_malloc(reply_size);
3416928750b6Schristos if (reply == NULL) {
3417928750b6Schristos if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
3418928750b6Schristos fromlen) < 0) {
3419928750b6Schristos wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
3420928750b6Schristos strerror(errno));
3421928750b6Schristos }
3422928750b6Schristos return;
3423928750b6Schristos }
3424928750b6Schristos
3425928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP
3426928750b6Schristos if (os_strcmp(buf, "GET_COOKIE") == 0) {
3427928750b6Schristos os_memcpy(reply, "COOKIE=", 7);
3428928750b6Schristos wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
3429928750b6Schristos cookie, COOKIE_LEN);
3430928750b6Schristos reply_len = 7 + 2 * COOKIE_LEN;
3431928750b6Schristos goto done;
3432928750b6Schristos }
3433928750b6Schristos
3434928750b6Schristos if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
3435928750b6Schristos hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
3436928750b6Schristos wpa_printf(MSG_DEBUG,
3437928750b6Schristos "CTRL: No cookie in the request - drop request");
3438928750b6Schristos os_free(reply);
3439928750b6Schristos return;
3440928750b6Schristos }
3441928750b6Schristos
3442928750b6Schristos if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
3443928750b6Schristos wpa_printf(MSG_DEBUG,
3444928750b6Schristos "CTRL: Invalid cookie in the request - drop request");
3445928750b6Schristos os_free(reply);
3446928750b6Schristos return;
3447928750b6Schristos }
3448928750b6Schristos
3449928750b6Schristos pos = buf + 7 + 2 * COOKIE_LEN;
3450928750b6Schristos while (*pos == ' ')
3451928750b6Schristos pos++;
3452928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
3453928750b6Schristos
3454928750b6Schristos if (os_strcmp(pos, "PING") == 0)
3455928750b6Schristos level = MSG_EXCESSIVE;
3456928750b6Schristos wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
3457928750b6Schristos
3458928750b6Schristos reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
3459928750b6Schristos reply, reply_size,
3460928750b6Schristos &from, fromlen);
3461928750b6Schristos
3462928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP
3463928750b6Schristos done:
3464928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
34659a53cbbeSchristos if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
34669a53cbbeSchristos fromlen) < 0) {
34679a53cbbeSchristos wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
34689a53cbbeSchristos strerror(errno));
34699a53cbbeSchristos }
34708dbcf02cSchristos os_free(reply);
34718dbcf02cSchristos }
34728dbcf02cSchristos
34738dbcf02cSchristos
3474928750b6Schristos #ifndef CONFIG_CTRL_IFACE_UDP
hostapd_ctrl_iface_path(struct hostapd_data * hapd)34758dbcf02cSchristos static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
34768dbcf02cSchristos {
34778dbcf02cSchristos char *buf;
34788dbcf02cSchristos size_t len;
34798dbcf02cSchristos
34808dbcf02cSchristos if (hapd->conf->ctrl_interface == NULL)
34818dbcf02cSchristos return NULL;
34828dbcf02cSchristos
34838dbcf02cSchristos len = os_strlen(hapd->conf->ctrl_interface) +
34848dbcf02cSchristos os_strlen(hapd->conf->iface) + 2;
34858dbcf02cSchristos buf = os_malloc(len);
34868dbcf02cSchristos if (buf == NULL)
34878dbcf02cSchristos return NULL;
34888dbcf02cSchristos
34898dbcf02cSchristos os_snprintf(buf, len, "%s/%s",
34908dbcf02cSchristos hapd->conf->ctrl_interface, hapd->conf->iface);
34918dbcf02cSchristos buf[len - 1] = '\0';
34928dbcf02cSchristos return buf;
34938dbcf02cSchristos }
3494928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
34958dbcf02cSchristos
34968dbcf02cSchristos
hostapd_ctrl_iface_msg_cb(void * ctx,int level,enum wpa_msg_type type,const char * txt,size_t len)3497928750b6Schristos static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
3498928750b6Schristos enum wpa_msg_type type,
34998dbcf02cSchristos const char *txt, size_t len)
35008dbcf02cSchristos {
35018dbcf02cSchristos struct hostapd_data *hapd = ctx;
35028dbcf02cSchristos if (hapd == NULL)
35038dbcf02cSchristos return;
3504928750b6Schristos hostapd_ctrl_iface_send(hapd, level, type, txt, len);
35058dbcf02cSchristos }
35068dbcf02cSchristos
35078dbcf02cSchristos
hostapd_ctrl_iface_init(struct hostapd_data * hapd)35088dbcf02cSchristos int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
35098dbcf02cSchristos {
3510928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP
3511928750b6Schristos int port = HOSTAPD_CTRL_IFACE_PORT;
3512928750b6Schristos char p[32] = { 0 };
3513928750b6Schristos char port_str[40], *tmp;
3514928750b6Schristos char *pos;
3515928750b6Schristos struct addrinfo hints = { 0 }, *res, *saveres;
3516928750b6Schristos int n;
3517928750b6Schristos
3518928750b6Schristos if (hapd->ctrl_sock > -1) {
3519928750b6Schristos wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
3520928750b6Schristos return 0;
3521928750b6Schristos }
3522928750b6Schristos
3523928750b6Schristos if (hapd->conf->ctrl_interface == NULL)
3524928750b6Schristos return 0;
3525928750b6Schristos
3526928750b6Schristos pos = os_strstr(hapd->conf->ctrl_interface, "udp:");
3527928750b6Schristos if (pos) {
3528928750b6Schristos pos += 4;
3529928750b6Schristos port = atoi(pos);
3530928750b6Schristos if (port <= 0) {
3531928750b6Schristos wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port");
3532928750b6Schristos goto fail;
3533928750b6Schristos }
3534928750b6Schristos }
3535928750b6Schristos
3536928750b6Schristos dl_list_init(&hapd->ctrl_dst);
3537928750b6Schristos hapd->ctrl_sock = -1;
3538928750b6Schristos os_get_random(cookie, COOKIE_LEN);
3539928750b6Schristos
3540928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3541928750b6Schristos hints.ai_flags = AI_PASSIVE;
3542928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3543928750b6Schristos
3544928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3545928750b6Schristos hints.ai_family = AF_INET6;
3546928750b6Schristos #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3547928750b6Schristos hints.ai_family = AF_INET;
3548928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3549928750b6Schristos hints.ai_socktype = SOCK_DGRAM;
3550928750b6Schristos
3551928750b6Schristos try_again:
3552928750b6Schristos os_snprintf(p, sizeof(p), "%d", port);
3553928750b6Schristos n = getaddrinfo(NULL, p, &hints, &res);
3554928750b6Schristos if (n) {
3555928750b6Schristos wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
3556928750b6Schristos goto fail;
3557928750b6Schristos }
3558928750b6Schristos
3559928750b6Schristos saveres = res;
3560928750b6Schristos hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
3561928750b6Schristos res->ai_protocol);
3562928750b6Schristos if (hapd->ctrl_sock < 0) {
3563928750b6Schristos wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
3564928750b6Schristos goto fail;
3565928750b6Schristos }
3566928750b6Schristos
3567928750b6Schristos if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
3568928750b6Schristos port--;
3569928750b6Schristos if ((HOSTAPD_CTRL_IFACE_PORT - port) <
3570928750b6Schristos HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos)
3571928750b6Schristos goto try_again;
3572928750b6Schristos wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
3573928750b6Schristos goto fail;
3574928750b6Schristos }
3575928750b6Schristos
3576928750b6Schristos freeaddrinfo(saveres);
3577928750b6Schristos
3578928750b6Schristos os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
3579928750b6Schristos tmp = os_strdup(port_str);
3580928750b6Schristos if (tmp) {
3581928750b6Schristos os_free(hapd->conf->ctrl_interface);
3582928750b6Schristos hapd->conf->ctrl_interface = tmp;
3583928750b6Schristos }
3584928750b6Schristos wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
3585928750b6Schristos
3586928750b6Schristos if (eloop_register_read_sock(hapd->ctrl_sock,
3587928750b6Schristos hostapd_ctrl_iface_receive, hapd, NULL) <
3588928750b6Schristos 0) {
3589928750b6Schristos hostapd_ctrl_iface_deinit(hapd);
3590928750b6Schristos return -1;
3591928750b6Schristos }
3592928750b6Schristos
3593928750b6Schristos hapd->msg_ctx = hapd;
3594928750b6Schristos wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
3595928750b6Schristos
3596928750b6Schristos return 0;
3597928750b6Schristos
3598928750b6Schristos fail:
3599928750b6Schristos if (hapd->ctrl_sock >= 0)
3600928750b6Schristos close(hapd->ctrl_sock);
3601928750b6Schristos return -1;
3602928750b6Schristos #else /* CONFIG_CTRL_IFACE_UDP */
36038dbcf02cSchristos struct sockaddr_un addr;
36048dbcf02cSchristos int s = -1;
36058dbcf02cSchristos char *fname = NULL;
36068dbcf02cSchristos
360762a52023Schristos if (hapd->ctrl_sock > -1) {
360862a52023Schristos wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
360962a52023Schristos return 0;
361062a52023Schristos }
36118dbcf02cSchristos
3612928750b6Schristos dl_list_init(&hapd->ctrl_dst);
3613928750b6Schristos
36148dbcf02cSchristos if (hapd->conf->ctrl_interface == NULL)
36158dbcf02cSchristos return 0;
36168dbcf02cSchristos
36178dbcf02cSchristos if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
36188dbcf02cSchristos if (errno == EEXIST) {
36198dbcf02cSchristos wpa_printf(MSG_DEBUG, "Using existing control "
36208dbcf02cSchristos "interface directory.");
36218dbcf02cSchristos } else {
36229a53cbbeSchristos wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
36239a53cbbeSchristos strerror(errno));
36248dbcf02cSchristos goto fail;
36258dbcf02cSchristos }
36268dbcf02cSchristos }
36278dbcf02cSchristos
36288dbcf02cSchristos if (hapd->conf->ctrl_interface_gid_set &&
3629*0d69f216Schristos lchown(hapd->conf->ctrl_interface, -1,
36308dbcf02cSchristos hapd->conf->ctrl_interface_gid) < 0) {
3631*0d69f216Schristos wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
36329a53cbbeSchristos strerror(errno));
36338dbcf02cSchristos return -1;
36348dbcf02cSchristos }
36358dbcf02cSchristos
363636d97821Schristos if (!hapd->conf->ctrl_interface_gid_set &&
363736d97821Schristos hapd->iface->interfaces->ctrl_iface_group &&
3638*0d69f216Schristos lchown(hapd->conf->ctrl_interface, -1,
363936d97821Schristos hapd->iface->interfaces->ctrl_iface_group) < 0) {
3640*0d69f216Schristos wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
36419a53cbbeSchristos strerror(errno));
364236d97821Schristos return -1;
364336d97821Schristos }
364436d97821Schristos
364562a52023Schristos #ifdef ANDROID
364662a52023Schristos /*
364762a52023Schristos * Android is using umask 0077 which would leave the control interface
364862a52023Schristos * directory without group access. This breaks things since Wi-Fi
364962a52023Schristos * framework assumes that this directory can be accessed by other
365062a52023Schristos * applications in the wifi group. Fix this by adding group access even
365162a52023Schristos * if umask value would prevent this.
365262a52023Schristos */
365362a52023Schristos if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
365462a52023Schristos wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
365562a52023Schristos strerror(errno));
365662a52023Schristos /* Try to continue anyway */
365762a52023Schristos }
365862a52023Schristos #endif /* ANDROID */
365962a52023Schristos
36608dbcf02cSchristos if (os_strlen(hapd->conf->ctrl_interface) + 1 +
36618dbcf02cSchristos os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
36628dbcf02cSchristos goto fail;
36638dbcf02cSchristos
36648dbcf02cSchristos s = socket(PF_UNIX, SOCK_DGRAM, 0);
36658dbcf02cSchristos if (s < 0) {
36669a53cbbeSchristos wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
36678dbcf02cSchristos goto fail;
36688dbcf02cSchristos }
36698dbcf02cSchristos
36708dbcf02cSchristos os_memset(&addr, 0, sizeof(addr));
36718dbcf02cSchristos #ifdef __FreeBSD__
36728dbcf02cSchristos addr.sun_len = sizeof(addr);
36738dbcf02cSchristos #endif /* __FreeBSD__ */
36748dbcf02cSchristos addr.sun_family = AF_UNIX;
36758dbcf02cSchristos fname = hostapd_ctrl_iface_path(hapd);
36768dbcf02cSchristos if (fname == NULL)
36778dbcf02cSchristos goto fail;
36788dbcf02cSchristos os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
36798dbcf02cSchristos if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
36808dbcf02cSchristos wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
36818dbcf02cSchristos strerror(errno));
36828dbcf02cSchristos if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
36838dbcf02cSchristos wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
36848dbcf02cSchristos " allow connections - assuming it was left"
36858dbcf02cSchristos "over from forced program termination");
36868dbcf02cSchristos if (unlink(fname) < 0) {
36879a53cbbeSchristos wpa_printf(MSG_ERROR,
36889a53cbbeSchristos "Could not unlink existing ctrl_iface socket '%s': %s",
36899a53cbbeSchristos fname, strerror(errno));
36908dbcf02cSchristos goto fail;
36918dbcf02cSchristos }
36928dbcf02cSchristos if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
36938dbcf02cSchristos 0) {
36949a53cbbeSchristos wpa_printf(MSG_ERROR,
36959a53cbbeSchristos "hostapd-ctrl-iface: bind(PF_UNIX): %s",
36969a53cbbeSchristos strerror(errno));
36978dbcf02cSchristos goto fail;
36988dbcf02cSchristos }
36998dbcf02cSchristos wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
37008dbcf02cSchristos "ctrl_iface socket '%s'", fname);
37018dbcf02cSchristos } else {
37028dbcf02cSchristos wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
37038dbcf02cSchristos "be in use - cannot override it");
37048dbcf02cSchristos wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
37058dbcf02cSchristos "not used anymore", fname);
37068dbcf02cSchristos os_free(fname);
37078dbcf02cSchristos fname = NULL;
37088dbcf02cSchristos goto fail;
37098dbcf02cSchristos }
37108dbcf02cSchristos }
37118dbcf02cSchristos
37128dbcf02cSchristos if (hapd->conf->ctrl_interface_gid_set &&
3713*0d69f216Schristos lchown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
3714*0d69f216Schristos wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
37159a53cbbeSchristos strerror(errno));
37168dbcf02cSchristos goto fail;
37178dbcf02cSchristos }
37188dbcf02cSchristos
371936d97821Schristos if (!hapd->conf->ctrl_interface_gid_set &&
372036d97821Schristos hapd->iface->interfaces->ctrl_iface_group &&
3721*0d69f216Schristos lchown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
3722*0d69f216Schristos wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
37239a53cbbeSchristos strerror(errno));
372436d97821Schristos goto fail;
372536d97821Schristos }
372636d97821Schristos
37278dbcf02cSchristos if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
37289a53cbbeSchristos wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
37299a53cbbeSchristos strerror(errno));
37308dbcf02cSchristos goto fail;
37318dbcf02cSchristos }
37328dbcf02cSchristos os_free(fname);
37338dbcf02cSchristos
37348dbcf02cSchristos hapd->ctrl_sock = s;
37359a53cbbeSchristos if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
37369a53cbbeSchristos NULL) < 0) {
37379a53cbbeSchristos hostapd_ctrl_iface_deinit(hapd);
37389a53cbbeSchristos return -1;
37399a53cbbeSchristos }
37408dbcf02cSchristos hapd->msg_ctx = hapd;
37418dbcf02cSchristos wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
37428dbcf02cSchristos
37438dbcf02cSchristos return 0;
37448dbcf02cSchristos
37458dbcf02cSchristos fail:
37468dbcf02cSchristos if (s >= 0)
37478dbcf02cSchristos close(s);
37488dbcf02cSchristos if (fname) {
37498dbcf02cSchristos unlink(fname);
37508dbcf02cSchristos os_free(fname);
37518dbcf02cSchristos }
37528dbcf02cSchristos return -1;
3753928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
37548dbcf02cSchristos }
37558dbcf02cSchristos
37568dbcf02cSchristos
hostapd_ctrl_iface_deinit(struct hostapd_data * hapd)37578dbcf02cSchristos void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
37588dbcf02cSchristos {
37598dbcf02cSchristos struct wpa_ctrl_dst *dst, *prev;
37608dbcf02cSchristos
37618dbcf02cSchristos if (hapd->ctrl_sock > -1) {
3762928750b6Schristos #ifndef CONFIG_CTRL_IFACE_UDP
37638dbcf02cSchristos char *fname;
3764928750b6Schristos #endif /* !CONFIG_CTRL_IFACE_UDP */
3765928750b6Schristos
37668dbcf02cSchristos eloop_unregister_read_sock(hapd->ctrl_sock);
37678dbcf02cSchristos close(hapd->ctrl_sock);
37688dbcf02cSchristos hapd->ctrl_sock = -1;
3769928750b6Schristos #ifndef CONFIG_CTRL_IFACE_UDP
37708dbcf02cSchristos fname = hostapd_ctrl_iface_path(hapd);
37718dbcf02cSchristos if (fname)
37728dbcf02cSchristos unlink(fname);
37738dbcf02cSchristos os_free(fname);
37748dbcf02cSchristos
37758dbcf02cSchristos if (hapd->conf->ctrl_interface &&
37768dbcf02cSchristos rmdir(hapd->conf->ctrl_interface) < 0) {
37778dbcf02cSchristos if (errno == ENOTEMPTY) {
37788dbcf02cSchristos wpa_printf(MSG_DEBUG, "Control interface "
37798dbcf02cSchristos "directory not empty - leaving it "
37808dbcf02cSchristos "behind");
37818dbcf02cSchristos } else {
378236d97821Schristos wpa_printf(MSG_ERROR,
378336d97821Schristos "rmdir[ctrl_interface=%s]: %s",
378436d97821Schristos hapd->conf->ctrl_interface,
378536d97821Schristos strerror(errno));
37868dbcf02cSchristos }
37878dbcf02cSchristos }
3788928750b6Schristos #endif /* !CONFIG_CTRL_IFACE_UDP */
37898dbcf02cSchristos }
37908dbcf02cSchristos
3791928750b6Schristos dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
3792928750b6Schristos list)
3793928750b6Schristos os_free(dst);
37949a53cbbeSchristos
37959a53cbbeSchristos #ifdef CONFIG_TESTING_OPTIONS
37969a53cbbeSchristos l2_packet_deinit(hapd->l2_test);
37979a53cbbeSchristos hapd->l2_test = NULL;
37989a53cbbeSchristos #endif /* CONFIG_TESTING_OPTIONS */
37998dbcf02cSchristos }
38008dbcf02cSchristos
38018dbcf02cSchristos
hostapd_ctrl_iface_add(struct hapd_interfaces * interfaces,char * buf)380262a52023Schristos static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
380362a52023Schristos char *buf)
380462a52023Schristos {
380562a52023Schristos if (hostapd_add_iface(interfaces, buf) < 0) {
380662a52023Schristos wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
380762a52023Schristos return -1;
380862a52023Schristos }
380962a52023Schristos return 0;
381062a52023Schristos }
381162a52023Schristos
381262a52023Schristos
hostapd_ctrl_iface_remove(struct hapd_interfaces * interfaces,char * buf)381362a52023Schristos static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
381462a52023Schristos char *buf)
381562a52023Schristos {
381662a52023Schristos if (hostapd_remove_iface(interfaces, buf) < 0) {
381762a52023Schristos wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
381862a52023Schristos return -1;
381962a52023Schristos }
382062a52023Schristos return 0;
382162a52023Schristos }
382262a52023Schristos
382362a52023Schristos
hostapd_global_ctrl_iface_attach(struct hapd_interfaces * interfaces,struct sockaddr_storage * from,socklen_t fromlen,char * input)3824928750b6Schristos static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
3825928750b6Schristos struct sockaddr_storage *from,
3826ebb5671cSchristos socklen_t fromlen, char *input)
3827928750b6Schristos {
3828ebb5671cSchristos return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen,
3829ebb5671cSchristos input);
3830928750b6Schristos }
3831928750b6Schristos
3832928750b6Schristos
hostapd_global_ctrl_iface_detach(struct hapd_interfaces * interfaces,struct sockaddr_storage * from,socklen_t fromlen)3833928750b6Schristos static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
3834928750b6Schristos struct sockaddr_storage *from,
3835928750b6Schristos socklen_t fromlen)
3836928750b6Schristos {
3837928750b6Schristos return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen);
3838928750b6Schristos }
3839928750b6Schristos
3840928750b6Schristos
hostapd_ctrl_iface_flush(struct hapd_interfaces * interfaces)384136d97821Schristos static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
384236d97821Schristos {
384336d97821Schristos #ifdef CONFIG_WPS_TESTING
384436d97821Schristos wps_version_number = 0x20;
384536d97821Schristos wps_testing_dummy_cred = 0;
384636d97821Schristos wps_corrupt_pkhash = 0;
384736d97821Schristos #endif /* CONFIG_WPS_TESTING */
3848ebb5671cSchristos
3849ebb5671cSchristos #ifdef CONFIG_TESTING_OPTIONS
3850ebb5671cSchristos #ifdef CONFIG_DPP
3851ebb5671cSchristos dpp_test = DPP_TEST_DISABLED;
3852ebb5671cSchristos #endif /* CONFIG_DPP */
3853ebb5671cSchristos #endif /* CONFIG_TESTING_OPTIONS */
3854ebb5671cSchristos
3855ebb5671cSchristos #ifdef CONFIG_DPP
3856*0d69f216Schristos dpp_global_clear(interfaces->dpp);
3857ebb5671cSchristos #endif /* CONFIG_DPP */
385836d97821Schristos }
385936d97821Schristos
386036d97821Schristos
3861928750b6Schristos #ifdef CONFIG_FST
3862928750b6Schristos
3863928750b6Schristos static int
hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces * interfaces,const char * cmd)3864928750b6Schristos hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces *interfaces,
3865928750b6Schristos const char *cmd)
3866928750b6Schristos {
3867928750b6Schristos char ifname[IFNAMSIZ + 1];
3868928750b6Schristos struct fst_iface_cfg cfg;
3869928750b6Schristos struct hostapd_data *hapd;
3870928750b6Schristos struct fst_wpa_obj iface_obj;
3871928750b6Schristos
3872928750b6Schristos if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
3873928750b6Schristos hapd = hostapd_get_iface(interfaces, ifname);
3874928750b6Schristos if (hapd) {
3875928750b6Schristos if (hapd->iface->fst) {
3876928750b6Schristos wpa_printf(MSG_INFO, "FST: Already attached");
3877928750b6Schristos return -1;
3878928750b6Schristos }
3879928750b6Schristos fst_hostapd_fill_iface_obj(hapd, &iface_obj);
3880928750b6Schristos hapd->iface->fst = fst_attach(ifname, hapd->own_addr,
3881928750b6Schristos &iface_obj, &cfg);
3882928750b6Schristos if (hapd->iface->fst)
3883928750b6Schristos return 0;
3884928750b6Schristos }
3885928750b6Schristos }
3886928750b6Schristos
3887928750b6Schristos return -EINVAL;
3888928750b6Schristos }
3889928750b6Schristos
3890928750b6Schristos
3891928750b6Schristos static int
hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces * interfaces,const char * cmd)3892928750b6Schristos hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces *interfaces,
3893928750b6Schristos const char *cmd)
3894928750b6Schristos {
3895928750b6Schristos char ifname[IFNAMSIZ + 1];
3896928750b6Schristos struct hostapd_data * hapd;
3897928750b6Schristos
3898928750b6Schristos if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
3899928750b6Schristos hapd = hostapd_get_iface(interfaces, ifname);
3900928750b6Schristos if (hapd) {
3901928750b6Schristos if (!fst_iface_detach(ifname)) {
3902928750b6Schristos hapd->iface->fst = NULL;
3903928750b6Schristos hapd->iface->fst_ies = NULL;
3904928750b6Schristos return 0;
3905928750b6Schristos }
3906928750b6Schristos }
3907928750b6Schristos }
3908928750b6Schristos
3909928750b6Schristos return -EINVAL;
3910928750b6Schristos }
3911928750b6Schristos
3912928750b6Schristos #endif /* CONFIG_FST */
3913928750b6Schristos
3914928750b6Schristos
3915928750b6Schristos static struct hostapd_data *
hostapd_interfaces_get_hapd(struct hapd_interfaces * interfaces,const char * ifname)3916928750b6Schristos hostapd_interfaces_get_hapd(struct hapd_interfaces *interfaces,
3917928750b6Schristos const char *ifname)
3918928750b6Schristos {
3919928750b6Schristos size_t i, j;
3920928750b6Schristos
3921928750b6Schristos for (i = 0; i < interfaces->count; i++) {
3922928750b6Schristos struct hostapd_iface *iface = interfaces->iface[i];
3923928750b6Schristos
3924928750b6Schristos for (j = 0; j < iface->num_bss; j++) {
3925928750b6Schristos struct hostapd_data *hapd;
3926928750b6Schristos
3927928750b6Schristos hapd = iface->bss[j];
3928928750b6Schristos if (os_strcmp(ifname, hapd->conf->iface) == 0)
3929928750b6Schristos return hapd;
3930928750b6Schristos }
3931928750b6Schristos }
3932928750b6Schristos
3933928750b6Schristos return NULL;
3934928750b6Schristos }
3935928750b6Schristos
3936928750b6Schristos
hostapd_ctrl_iface_dup_param(struct hostapd_data * src_hapd,struct hostapd_data * dst_hapd,const char * param)3937928750b6Schristos static int hostapd_ctrl_iface_dup_param(struct hostapd_data *src_hapd,
3938928750b6Schristos struct hostapd_data *dst_hapd,
3939928750b6Schristos const char *param)
3940928750b6Schristos {
3941928750b6Schristos int res;
3942928750b6Schristos char *value;
3943928750b6Schristos
3944928750b6Schristos value = os_zalloc(HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
3945928750b6Schristos if (!value) {
3946928750b6Schristos wpa_printf(MSG_ERROR,
3947928750b6Schristos "DUP: cannot allocate buffer to stringify %s",
3948928750b6Schristos param);
3949928750b6Schristos goto error_return;
3950928750b6Schristos }
3951928750b6Schristos
3952928750b6Schristos if (os_strcmp(param, "wpa") == 0) {
3953928750b6Schristos os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%d",
3954928750b6Schristos src_hapd->conf->wpa);
3955928750b6Schristos } else if (os_strcmp(param, "wpa_key_mgmt") == 0 &&
3956928750b6Schristos src_hapd->conf->wpa_key_mgmt) {
3957928750b6Schristos res = hostapd_ctrl_iface_get_key_mgmt(
3958928750b6Schristos src_hapd, value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
3959928750b6Schristos if (os_snprintf_error(HOSTAPD_CLI_DUP_VALUE_MAX_LEN, res))
3960928750b6Schristos goto error_stringify;
3961928750b6Schristos } else if (os_strcmp(param, "wpa_pairwise") == 0 &&
3962928750b6Schristos src_hapd->conf->wpa_pairwise) {
3963928750b6Schristos res = wpa_write_ciphers(value,
3964928750b6Schristos value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
3965928750b6Schristos src_hapd->conf->wpa_pairwise, " ");
3966928750b6Schristos if (res < 0)
3967928750b6Schristos goto error_stringify;
3968928750b6Schristos } else if (os_strcmp(param, "rsn_pairwise") == 0 &&
3969928750b6Schristos src_hapd->conf->rsn_pairwise) {
3970928750b6Schristos res = wpa_write_ciphers(value,
3971928750b6Schristos value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
3972928750b6Schristos src_hapd->conf->rsn_pairwise, " ");
3973928750b6Schristos if (res < 0)
3974928750b6Schristos goto error_stringify;
3975928750b6Schristos } else if (os_strcmp(param, "wpa_passphrase") == 0 &&
3976928750b6Schristos src_hapd->conf->ssid.wpa_passphrase) {
3977928750b6Schristos os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%s",
3978928750b6Schristos src_hapd->conf->ssid.wpa_passphrase);
3979928750b6Schristos } else if (os_strcmp(param, "wpa_psk") == 0 &&
3980928750b6Schristos src_hapd->conf->ssid.wpa_psk_set) {
3981928750b6Schristos wpa_snprintf_hex(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
3982928750b6Schristos src_hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
3983928750b6Schristos } else {
3984928750b6Schristos wpa_printf(MSG_WARNING, "DUP: %s cannot be duplicated", param);
3985928750b6Schristos goto error_return;
3986928750b6Schristos }
3987928750b6Schristos
3988928750b6Schristos res = hostapd_set_iface(dst_hapd->iconf, dst_hapd->conf, param, value);
3989928750b6Schristos os_free(value);
3990928750b6Schristos return res;
3991928750b6Schristos
3992928750b6Schristos error_stringify:
3993928750b6Schristos wpa_printf(MSG_ERROR, "DUP: cannot stringify %s", param);
3994928750b6Schristos error_return:
3995928750b6Schristos os_free(value);
3996928750b6Schristos return -1;
3997928750b6Schristos }
3998928750b6Schristos
3999928750b6Schristos
4000928750b6Schristos static int
hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces * interfaces,const char * input,char * reply,int reply_size)4001928750b6Schristos hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces,
4002928750b6Schristos const char *input,
4003928750b6Schristos char *reply, int reply_size)
4004928750b6Schristos {
4005928750b6Schristos size_t i, j;
4006928750b6Schristos int res;
4007928750b6Schristos char *pos, *end;
4008928750b6Schristos struct hostapd_iface *iface;
4009928750b6Schristos int show_ctrl = 0;
4010928750b6Schristos
4011928750b6Schristos if (input)
4012928750b6Schristos show_ctrl = !!os_strstr(input, "ctrl");
4013928750b6Schristos
4014928750b6Schristos pos = reply;
4015928750b6Schristos end = reply + reply_size;
4016928750b6Schristos
4017928750b6Schristos for (i = 0; i < interfaces->count; i++) {
4018928750b6Schristos iface = interfaces->iface[i];
4019928750b6Schristos
4020928750b6Schristos for (j = 0; j < iface->num_bss; j++) {
4021928750b6Schristos struct hostapd_bss_config *conf;
4022928750b6Schristos
4023928750b6Schristos conf = iface->conf->bss[j];
4024928750b6Schristos if (show_ctrl)
4025928750b6Schristos res = os_snprintf(pos, end - pos,
4026928750b6Schristos "%s ctrl_iface=%s\n",
4027928750b6Schristos conf->iface,
4028928750b6Schristos conf->ctrl_interface ?
4029928750b6Schristos conf->ctrl_interface : "N/A");
4030928750b6Schristos else
4031928750b6Schristos res = os_snprintf(pos, end - pos, "%s\n",
4032928750b6Schristos conf->iface);
4033928750b6Schristos if (os_snprintf_error(end - pos, res)) {
4034928750b6Schristos *pos = '\0';
4035928750b6Schristos return pos - reply;
4036928750b6Schristos }
4037928750b6Schristos pos += res;
4038928750b6Schristos }
4039928750b6Schristos }
4040928750b6Schristos
4041928750b6Schristos return pos - reply;
4042928750b6Schristos }
4043928750b6Schristos
4044928750b6Schristos
4045928750b6Schristos static int
hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces * interfaces,char * cmd)4046928750b6Schristos hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
4047928750b6Schristos char *cmd)
4048928750b6Schristos {
4049928750b6Schristos char *p_start = cmd, *p_end;
4050928750b6Schristos struct hostapd_data *src_hapd, *dst_hapd;
4051928750b6Schristos
4052928750b6Schristos /* cmd: "<src ifname> <dst ifname> <variable name> */
4053928750b6Schristos
4054928750b6Schristos p_end = os_strchr(p_start, ' ');
4055928750b6Schristos if (!p_end) {
4056928750b6Schristos wpa_printf(MSG_ERROR, "DUP: no src ifname found in cmd: '%s'",
4057928750b6Schristos cmd);
4058928750b6Schristos return -1;
4059928750b6Schristos }
4060928750b6Schristos
4061928750b6Schristos *p_end = '\0';
4062928750b6Schristos src_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
4063928750b6Schristos if (!src_hapd) {
4064928750b6Schristos wpa_printf(MSG_ERROR, "DUP: no src ifname found: '%s'",
4065928750b6Schristos p_start);
4066928750b6Schristos return -1;
4067928750b6Schristos }
4068928750b6Schristos
4069928750b6Schristos p_start = p_end + 1;
4070928750b6Schristos p_end = os_strchr(p_start, ' ');
4071928750b6Schristos if (!p_end) {
4072928750b6Schristos wpa_printf(MSG_ERROR, "DUP: no dst ifname found in cmd: '%s'",
4073928750b6Schristos cmd);
4074928750b6Schristos return -1;
4075928750b6Schristos }
4076928750b6Schristos
4077928750b6Schristos *p_end = '\0';
4078928750b6Schristos dst_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
4079928750b6Schristos if (!dst_hapd) {
4080928750b6Schristos wpa_printf(MSG_ERROR, "DUP: no dst ifname found: '%s'",
4081928750b6Schristos p_start);
4082928750b6Schristos return -1;
4083928750b6Schristos }
4084928750b6Schristos
4085928750b6Schristos p_start = p_end + 1;
4086928750b6Schristos return hostapd_ctrl_iface_dup_param(src_hapd, dst_hapd, p_start);
4087928750b6Schristos }
4088928750b6Schristos
4089928750b6Schristos
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)4090928750b6Schristos static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
4091928750b6Schristos const char *ifname,
4092928750b6Schristos char *buf, char *reply,
4093928750b6Schristos int reply_size,
4094928750b6Schristos struct sockaddr_storage *from,
4095928750b6Schristos socklen_t fromlen)
4096928750b6Schristos {
4097928750b6Schristos struct hostapd_data *hapd;
4098928750b6Schristos
4099928750b6Schristos hapd = hostapd_interfaces_get_hapd(interfaces, ifname);
4100928750b6Schristos if (hapd == NULL) {
4101928750b6Schristos int res;
4102928750b6Schristos
4103928750b6Schristos res = os_snprintf(reply, reply_size, "FAIL-NO-IFNAME-MATCH\n");
4104928750b6Schristos if (os_snprintf_error(reply_size, res))
4105928750b6Schristos return -1;
4106928750b6Schristos return res;
4107928750b6Schristos }
4108928750b6Schristos
4109928750b6Schristos return hostapd_ctrl_iface_receive_process(hapd, buf, reply,reply_size,
4110928750b6Schristos from, fromlen);
4111928750b6Schristos }
4112928750b6Schristos
4113928750b6Schristos
hostapd_global_ctrl_iface_receive(int sock,void * eloop_ctx,void * sock_ctx)411462a52023Schristos static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
411562a52023Schristos void *sock_ctx)
411662a52023Schristos {
411762a52023Schristos void *interfaces = eloop_ctx;
4118928750b6Schristos char buffer[256], *buf = buffer;
411962a52023Schristos int res;
4120928750b6Schristos struct sockaddr_storage from;
412162a52023Schristos socklen_t fromlen = sizeof(from);
4122928750b6Schristos char *reply;
412362a52023Schristos int reply_len;
4124928750b6Schristos const int reply_size = 4096;
4125928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP
4126928750b6Schristos unsigned char lcookie[COOKIE_LEN];
4127928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
412862a52023Schristos
4129928750b6Schristos res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
413062a52023Schristos (struct sockaddr *) &from, &fromlen);
413162a52023Schristos if (res < 0) {
41329a53cbbeSchristos wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
41339a53cbbeSchristos strerror(errno));
413462a52023Schristos return;
413562a52023Schristos }
413662a52023Schristos buf[res] = '\0';
413736d97821Schristos wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
413862a52023Schristos
4139928750b6Schristos reply = os_malloc(reply_size);
4140928750b6Schristos if (reply == NULL) {
4141928750b6Schristos if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
4142928750b6Schristos fromlen) < 0) {
4143928750b6Schristos wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
4144928750b6Schristos strerror(errno));
4145928750b6Schristos }
4146928750b6Schristos return;
4147928750b6Schristos }
4148928750b6Schristos
414962a52023Schristos os_memcpy(reply, "OK\n", 3);
415062a52023Schristos reply_len = 3;
415162a52023Schristos
4152928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP
4153928750b6Schristos if (os_strcmp(buf, "GET_COOKIE") == 0) {
4154928750b6Schristos os_memcpy(reply, "COOKIE=", 7);
4155928750b6Schristos wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
4156928750b6Schristos gcookie, COOKIE_LEN);
4157928750b6Schristos reply_len = 7 + 2 * COOKIE_LEN;
4158928750b6Schristos goto send_reply;
4159928750b6Schristos }
4160928750b6Schristos
4161928750b6Schristos if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
4162928750b6Schristos hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
4163928750b6Schristos wpa_printf(MSG_DEBUG,
4164928750b6Schristos "CTRL: No cookie in the request - drop request");
4165928750b6Schristos os_free(reply);
4166928750b6Schristos return;
4167928750b6Schristos }
4168928750b6Schristos
4169928750b6Schristos if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
4170928750b6Schristos wpa_printf(MSG_DEBUG,
4171928750b6Schristos "CTRL: Invalid cookie in the request - drop request");
4172928750b6Schristos os_free(reply);
4173928750b6Schristos return;
4174928750b6Schristos }
4175928750b6Schristos
4176928750b6Schristos buf += 7 + 2 * COOKIE_LEN;
4177928750b6Schristos while (*buf == ' ')
4178928750b6Schristos buf++;
4179928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
4180928750b6Schristos
4181928750b6Schristos if (os_strncmp(buf, "IFNAME=", 7) == 0) {
4182928750b6Schristos char *pos = os_strchr(buf + 7, ' ');
4183928750b6Schristos
4184928750b6Schristos if (pos) {
4185928750b6Schristos *pos++ = '\0';
4186928750b6Schristos reply_len = hostapd_global_ctrl_iface_ifname(
4187928750b6Schristos interfaces, buf + 7, pos, reply, reply_size,
4188928750b6Schristos &from, fromlen);
4189928750b6Schristos goto send_reply;
4190928750b6Schristos }
4191928750b6Schristos }
4192928750b6Schristos
419362a52023Schristos if (os_strcmp(buf, "PING") == 0) {
419462a52023Schristos os_memcpy(reply, "PONG\n", 5);
419562a52023Schristos reply_len = 5;
419636d97821Schristos } else if (os_strncmp(buf, "RELOG", 5) == 0) {
419736d97821Schristos if (wpa_debug_reopen_file() < 0)
419836d97821Schristos reply_len = -1;
419936d97821Schristos } else if (os_strcmp(buf, "FLUSH") == 0) {
420036d97821Schristos hostapd_ctrl_iface_flush(interfaces);
420162a52023Schristos } else if (os_strncmp(buf, "ADD ", 4) == 0) {
420262a52023Schristos if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
420362a52023Schristos reply_len = -1;
420462a52023Schristos } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
420562a52023Schristos if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
420662a52023Schristos reply_len = -1;
4207928750b6Schristos } else if (os_strcmp(buf, "ATTACH") == 0) {
4208928750b6Schristos if (hostapd_global_ctrl_iface_attach(interfaces, &from,
4209ebb5671cSchristos fromlen, NULL))
4210ebb5671cSchristos reply_len = -1;
4211ebb5671cSchristos } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
4212ebb5671cSchristos if (hostapd_global_ctrl_iface_attach(interfaces, &from,
4213ebb5671cSchristos fromlen, buf + 7))
4214928750b6Schristos reply_len = -1;
4215928750b6Schristos } else if (os_strcmp(buf, "DETACH") == 0) {
4216928750b6Schristos if (hostapd_global_ctrl_iface_detach(interfaces, &from,
4217928750b6Schristos fromlen))
4218928750b6Schristos reply_len = -1;
421936d97821Schristos #ifdef CONFIG_MODULE_TESTS
422036d97821Schristos } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
422136d97821Schristos if (hapd_module_tests() < 0)
422236d97821Schristos reply_len = -1;
422336d97821Schristos #endif /* CONFIG_MODULE_TESTS */
4224928750b6Schristos #ifdef CONFIG_FST
4225928750b6Schristos } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
4226928750b6Schristos if (!hostapd_global_ctrl_iface_fst_attach(interfaces, buf + 11))
4227928750b6Schristos reply_len = os_snprintf(reply, reply_size, "OK\n");
4228928750b6Schristos else
4229928750b6Schristos reply_len = -1;
4230928750b6Schristos } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
4231928750b6Schristos if (!hostapd_global_ctrl_iface_fst_detach(interfaces, buf + 11))
4232928750b6Schristos reply_len = os_snprintf(reply, reply_size, "OK\n");
4233928750b6Schristos else
4234928750b6Schristos reply_len = -1;
4235928750b6Schristos } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
4236928750b6Schristos reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
4237928750b6Schristos #endif /* CONFIG_FST */
4238928750b6Schristos } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
4239928750b6Schristos if (!hostapd_global_ctrl_iface_dup_network(interfaces,
4240928750b6Schristos buf + 12))
4241928750b6Schristos reply_len = os_snprintf(reply, reply_size, "OK\n");
4242928750b6Schristos else
4243928750b6Schristos reply_len = -1;
4244928750b6Schristos } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
4245928750b6Schristos reply_len = hostapd_global_ctrl_iface_interfaces(
4246928750b6Schristos interfaces, buf + 10, reply, sizeof(buffer));
4247928750b6Schristos } else if (os_strcmp(buf, "TERMINATE") == 0) {
4248928750b6Schristos eloop_terminate();
424962a52023Schristos } else {
425062a52023Schristos wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
425162a52023Schristos "ignored");
425262a52023Schristos reply_len = -1;
425362a52023Schristos }
425462a52023Schristos
4255928750b6Schristos send_reply:
425662a52023Schristos if (reply_len < 0) {
425762a52023Schristos os_memcpy(reply, "FAIL\n", 5);
425862a52023Schristos reply_len = 5;
425962a52023Schristos }
426062a52023Schristos
42619a53cbbeSchristos if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
42629a53cbbeSchristos fromlen) < 0) {
42639a53cbbeSchristos wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
42649a53cbbeSchristos strerror(errno));
42659a53cbbeSchristos }
4266928750b6Schristos os_free(reply);
426762a52023Schristos }
426862a52023Schristos
426962a52023Schristos
4270928750b6Schristos #ifndef CONFIG_CTRL_IFACE_UDP
hostapd_global_ctrl_iface_path(struct hapd_interfaces * interface)427162a52023Schristos static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
427262a52023Schristos {
427362a52023Schristos char *buf;
427462a52023Schristos size_t len;
427562a52023Schristos
427662a52023Schristos if (interface->global_iface_path == NULL)
427762a52023Schristos return NULL;
427862a52023Schristos
427962a52023Schristos len = os_strlen(interface->global_iface_path) +
428062a52023Schristos os_strlen(interface->global_iface_name) + 2;
428162a52023Schristos buf = os_malloc(len);
428262a52023Schristos if (buf == NULL)
428362a52023Schristos return NULL;
428462a52023Schristos
428562a52023Schristos os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
428662a52023Schristos interface->global_iface_name);
428762a52023Schristos buf[len - 1] = '\0';
428862a52023Schristos return buf;
428962a52023Schristos }
4290928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
429162a52023Schristos
429262a52023Schristos
hostapd_global_ctrl_iface_init(struct hapd_interfaces * interface)429362a52023Schristos int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
429462a52023Schristos {
4295928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP
4296928750b6Schristos int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
4297928750b6Schristos char p[32] = { 0 };
4298928750b6Schristos char *pos;
4299928750b6Schristos struct addrinfo hints = { 0 }, *res, *saveres;
4300928750b6Schristos int n;
4301928750b6Schristos
4302928750b6Schristos if (interface->global_ctrl_sock > -1) {
4303928750b6Schristos wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
4304928750b6Schristos return 0;
4305928750b6Schristos }
4306928750b6Schristos
4307928750b6Schristos if (interface->global_iface_path == NULL)
4308928750b6Schristos return 0;
4309928750b6Schristos
4310928750b6Schristos pos = os_strstr(interface->global_iface_path, "udp:");
4311928750b6Schristos if (pos) {
4312928750b6Schristos pos += 4;
4313928750b6Schristos port = atoi(pos);
4314928750b6Schristos if (port <= 0) {
4315928750b6Schristos wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port");
4316928750b6Schristos goto fail;
4317928750b6Schristos }
4318928750b6Schristos }
4319928750b6Schristos
4320928750b6Schristos os_get_random(gcookie, COOKIE_LEN);
4321928750b6Schristos
4322928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
4323928750b6Schristos hints.ai_flags = AI_PASSIVE;
4324928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
4325928750b6Schristos
4326928750b6Schristos #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
4327928750b6Schristos hints.ai_family = AF_INET6;
4328928750b6Schristos #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4329928750b6Schristos hints.ai_family = AF_INET;
4330928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4331928750b6Schristos hints.ai_socktype = SOCK_DGRAM;
4332928750b6Schristos
4333928750b6Schristos try_again:
4334928750b6Schristos os_snprintf(p, sizeof(p), "%d", port);
4335928750b6Schristos n = getaddrinfo(NULL, p, &hints, &res);
4336928750b6Schristos if (n) {
4337928750b6Schristos wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
4338928750b6Schristos goto fail;
4339928750b6Schristos }
4340928750b6Schristos
4341928750b6Schristos saveres = res;
4342928750b6Schristos interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
4343928750b6Schristos res->ai_protocol);
4344928750b6Schristos if (interface->global_ctrl_sock < 0) {
4345928750b6Schristos wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
4346928750b6Schristos goto fail;
4347928750b6Schristos }
4348928750b6Schristos
4349928750b6Schristos if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
4350928750b6Schristos 0) {
4351928750b6Schristos port++;
4352928750b6Schristos if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
4353928750b6Schristos HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
4354928750b6Schristos goto try_again;
4355928750b6Schristos wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
4356928750b6Schristos goto fail;
4357928750b6Schristos }
4358928750b6Schristos
4359928750b6Schristos freeaddrinfo(saveres);
4360928750b6Schristos
4361928750b6Schristos wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
4362928750b6Schristos
4363928750b6Schristos if (eloop_register_read_sock(interface->global_ctrl_sock,
4364928750b6Schristos hostapd_global_ctrl_iface_receive,
4365928750b6Schristos interface, NULL) < 0) {
4366928750b6Schristos hostapd_global_ctrl_iface_deinit(interface);
4367928750b6Schristos return -1;
4368928750b6Schristos }
4369928750b6Schristos
4370928750b6Schristos return 0;
4371928750b6Schristos
4372928750b6Schristos fail:
4373928750b6Schristos if (interface->global_ctrl_sock >= 0)
4374928750b6Schristos close(interface->global_ctrl_sock);
4375928750b6Schristos return -1;
4376928750b6Schristos #else /* CONFIG_CTRL_IFACE_UDP */
437762a52023Schristos struct sockaddr_un addr;
437862a52023Schristos int s = -1;
437962a52023Schristos char *fname = NULL;
438062a52023Schristos
438162a52023Schristos if (interface->global_iface_path == NULL) {
438262a52023Schristos wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
438362a52023Schristos return 0;
438462a52023Schristos }
438562a52023Schristos
438662a52023Schristos if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
438762a52023Schristos if (errno == EEXIST) {
438862a52023Schristos wpa_printf(MSG_DEBUG, "Using existing control "
438962a52023Schristos "interface directory.");
439062a52023Schristos } else {
43919a53cbbeSchristos wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
43929a53cbbeSchristos strerror(errno));
439362a52023Schristos goto fail;
439462a52023Schristos }
439536d97821Schristos } else if (interface->ctrl_iface_group &&
4396*0d69f216Schristos lchown(interface->global_iface_path, -1,
439736d97821Schristos interface->ctrl_iface_group) < 0) {
4398*0d69f216Schristos wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
43999a53cbbeSchristos strerror(errno));
440036d97821Schristos goto fail;
440162a52023Schristos }
440262a52023Schristos
440362a52023Schristos if (os_strlen(interface->global_iface_path) + 1 +
440462a52023Schristos os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
440562a52023Schristos goto fail;
440662a52023Schristos
440762a52023Schristos s = socket(PF_UNIX, SOCK_DGRAM, 0);
440862a52023Schristos if (s < 0) {
44099a53cbbeSchristos wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
441062a52023Schristos goto fail;
441162a52023Schristos }
441262a52023Schristos
441362a52023Schristos os_memset(&addr, 0, sizeof(addr));
441462a52023Schristos #ifdef __FreeBSD__
441562a52023Schristos addr.sun_len = sizeof(addr);
441662a52023Schristos #endif /* __FreeBSD__ */
441762a52023Schristos addr.sun_family = AF_UNIX;
441862a52023Schristos fname = hostapd_global_ctrl_iface_path(interface);
441962a52023Schristos if (fname == NULL)
442062a52023Schristos goto fail;
442162a52023Schristos os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
442262a52023Schristos if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
442362a52023Schristos wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
442462a52023Schristos strerror(errno));
442562a52023Schristos if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
442662a52023Schristos wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
442762a52023Schristos " allow connections - assuming it was left"
442862a52023Schristos "over from forced program termination");
442962a52023Schristos if (unlink(fname) < 0) {
44309a53cbbeSchristos wpa_printf(MSG_ERROR,
44319a53cbbeSchristos "Could not unlink existing ctrl_iface socket '%s': %s",
44329a53cbbeSchristos fname, strerror(errno));
443362a52023Schristos goto fail;
443462a52023Schristos }
443562a52023Schristos if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
443662a52023Schristos 0) {
44379a53cbbeSchristos wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
44389a53cbbeSchristos strerror(errno));
443962a52023Schristos goto fail;
444062a52023Schristos }
444162a52023Schristos wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
444262a52023Schristos "ctrl_iface socket '%s'", fname);
444362a52023Schristos } else {
444462a52023Schristos wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
444562a52023Schristos "be in use - cannot override it");
444662a52023Schristos wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
444762a52023Schristos "not used anymore", fname);
444862a52023Schristos os_free(fname);
444962a52023Schristos fname = NULL;
445062a52023Schristos goto fail;
445162a52023Schristos }
445262a52023Schristos }
445362a52023Schristos
445436d97821Schristos if (interface->ctrl_iface_group &&
4455*0d69f216Schristos lchown(fname, -1, interface->ctrl_iface_group) < 0) {
4456*0d69f216Schristos wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
44579a53cbbeSchristos strerror(errno));
445836d97821Schristos goto fail;
445936d97821Schristos }
446036d97821Schristos
446162a52023Schristos if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
44629a53cbbeSchristos wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
44639a53cbbeSchristos strerror(errno));
446462a52023Schristos goto fail;
446562a52023Schristos }
446662a52023Schristos os_free(fname);
446762a52023Schristos
446862a52023Schristos interface->global_ctrl_sock = s;
446962a52023Schristos eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
447062a52023Schristos interface, NULL);
447162a52023Schristos
447262a52023Schristos return 0;
447362a52023Schristos
447462a52023Schristos fail:
447562a52023Schristos if (s >= 0)
447662a52023Schristos close(s);
447762a52023Schristos if (fname) {
447862a52023Schristos unlink(fname);
447962a52023Schristos os_free(fname);
448062a52023Schristos }
448162a52023Schristos return -1;
4482928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
448362a52023Schristos }
448462a52023Schristos
448562a52023Schristos
hostapd_global_ctrl_iface_deinit(struct hapd_interfaces * interfaces)448662a52023Schristos void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
448762a52023Schristos {
4488928750b6Schristos #ifndef CONFIG_CTRL_IFACE_UDP
448962a52023Schristos char *fname = NULL;
4490928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
4491928750b6Schristos struct wpa_ctrl_dst *dst, *prev;
449262a52023Schristos
449362a52023Schristos if (interfaces->global_ctrl_sock > -1) {
449462a52023Schristos eloop_unregister_read_sock(interfaces->global_ctrl_sock);
449562a52023Schristos close(interfaces->global_ctrl_sock);
449662a52023Schristos interfaces->global_ctrl_sock = -1;
4497928750b6Schristos #ifndef CONFIG_CTRL_IFACE_UDP
449862a52023Schristos fname = hostapd_global_ctrl_iface_path(interfaces);
449962a52023Schristos if (fname) {
450062a52023Schristos unlink(fname);
450162a52023Schristos os_free(fname);
450262a52023Schristos }
450362a52023Schristos
450462a52023Schristos if (interfaces->global_iface_path &&
450562a52023Schristos rmdir(interfaces->global_iface_path) < 0) {
450662a52023Schristos if (errno == ENOTEMPTY) {
450762a52023Schristos wpa_printf(MSG_DEBUG, "Control interface "
450862a52023Schristos "directory not empty - leaving it "
450962a52023Schristos "behind");
451062a52023Schristos } else {
451136d97821Schristos wpa_printf(MSG_ERROR,
451236d97821Schristos "rmdir[ctrl_interface=%s]: %s",
451336d97821Schristos interfaces->global_iface_path,
451436d97821Schristos strerror(errno));
451562a52023Schristos }
451662a52023Schristos }
4517928750b6Schristos #endif /* CONFIG_CTRL_IFACE_UDP */
4518928750b6Schristos }
4519928750b6Schristos
452062a52023Schristos os_free(interfaces->global_iface_path);
452162a52023Schristos interfaces->global_iface_path = NULL;
4522928750b6Schristos
4523928750b6Schristos dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst,
4524928750b6Schristos struct wpa_ctrl_dst, list)
4525928750b6Schristos os_free(dst);
452662a52023Schristos }
452762a52023Schristos
452862a52023Schristos
hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst * dst,const char * buf)4529ebb5671cSchristos static int hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst *dst,
4530ebb5671cSchristos const char *buf)
4531ebb5671cSchristos {
4532ebb5671cSchristos /* Enable Probe Request events based on explicit request.
4533ebb5671cSchristos * Other events are enabled by default.
4534ebb5671cSchristos */
4535ebb5671cSchristos if (str_starts(buf, RX_PROBE_REQUEST))
4536ebb5671cSchristos return !!(dst->events & WPA_EVENT_RX_PROBE_REQUEST);
4537ebb5671cSchristos return 1;
4538ebb5671cSchristos }
4539ebb5671cSchristos
4540ebb5671cSchristos
hostapd_ctrl_iface_send(struct hostapd_data * hapd,int level,enum wpa_msg_type type,const char * buf,size_t len)45418dbcf02cSchristos static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
4542928750b6Schristos enum wpa_msg_type type,
45438dbcf02cSchristos const char *buf, size_t len)
45448dbcf02cSchristos {
45458dbcf02cSchristos struct wpa_ctrl_dst *dst, *next;
4546928750b6Schristos struct dl_list *ctrl_dst;
45478dbcf02cSchristos struct msghdr msg;
45488dbcf02cSchristos int idx;
45498dbcf02cSchristos struct iovec io[2];
45508dbcf02cSchristos char levelstr[10];
4551928750b6Schristos int s;
45528dbcf02cSchristos
4553928750b6Schristos if (type != WPA_MSG_ONLY_GLOBAL) {
4554928750b6Schristos s = hapd->ctrl_sock;
4555928750b6Schristos ctrl_dst = &hapd->ctrl_dst;
4556928750b6Schristos } else {
4557928750b6Schristos s = hapd->iface->interfaces->global_ctrl_sock;
4558928750b6Schristos ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst;
4559928750b6Schristos }
4560928750b6Schristos
4561928750b6Schristos if (s < 0 || dl_list_empty(ctrl_dst))
45628dbcf02cSchristos return;
45638dbcf02cSchristos
45648dbcf02cSchristos os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
45658dbcf02cSchristos io[0].iov_base = levelstr;
45668dbcf02cSchristos io[0].iov_len = os_strlen(levelstr);
45678dbcf02cSchristos io[1].iov_base = (char *) buf;
45688dbcf02cSchristos io[1].iov_len = len;
45698dbcf02cSchristos os_memset(&msg, 0, sizeof(msg));
45708dbcf02cSchristos msg.msg_iov = io;
45718dbcf02cSchristos msg.msg_iovlen = 2;
45728dbcf02cSchristos
45738dbcf02cSchristos idx = 0;
4574928750b6Schristos dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
4575ebb5671cSchristos if ((level >= dst->debug_level) &&
4576ebb5671cSchristos hostapd_ctrl_check_event_enabled(dst, buf)) {
4577928750b6Schristos sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
4578928750b6Schristos &dst->addr, dst->addrlen);
45798dbcf02cSchristos msg.msg_name = &dst->addr;
45808dbcf02cSchristos msg.msg_namelen = dst->addrlen;
4581928750b6Schristos if (sendmsg(s, &msg, 0) < 0) {
45828dbcf02cSchristos int _errno = errno;
45838dbcf02cSchristos wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
45848dbcf02cSchristos "%d - %s",
45858dbcf02cSchristos idx, errno, strerror(errno));
45868dbcf02cSchristos dst->errors++;
45878dbcf02cSchristos if (dst->errors > 10 || _errno == ENOENT) {
4588928750b6Schristos if (type != WPA_MSG_ONLY_GLOBAL)
45898dbcf02cSchristos hostapd_ctrl_iface_detach(
45908dbcf02cSchristos hapd, &dst->addr,
45918dbcf02cSchristos dst->addrlen);
4592928750b6Schristos else
4593928750b6Schristos hostapd_global_ctrl_iface_detach(
4594928750b6Schristos hapd->iface->interfaces,
4595928750b6Schristos &dst->addr,
4596928750b6Schristos dst->addrlen);
45978dbcf02cSchristos }
45988dbcf02cSchristos } else
45998dbcf02cSchristos dst->errors = 0;
46008dbcf02cSchristos }
46018dbcf02cSchristos idx++;
46028dbcf02cSchristos }
46038dbcf02cSchristos }
46048dbcf02cSchristos
46058dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */
4606