blob: e74b1c7ef621a2fd3989632eba325be5011a242e [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / UNIX domain socket -based control interface
Roshan Pius3a1667e2018-07-03 15:17:14 -07003 * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
10
11#ifndef CONFIG_NATIVE_WINDOWS
12
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080013#ifdef CONFIG_TESTING_OPTIONS
Hai Shalomfdcde762020-04-02 11:19:20 -070014#ifdef __NetBSD__
15#include <net/if_ether.h>
16#else
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080017#include <net/ethernet.h>
Hai Shalomfdcde762020-04-02 11:19:20 -070018#endif
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080019#include <netinet/ip.h>
20#endif /* CONFIG_TESTING_OPTIONS */
21
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022#include <sys/un.h>
23#include <sys/stat.h>
24#include <stddef.h>
25
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080026#ifdef CONFIG_CTRL_IFACE_UDP
27#include <netdb.h>
28#endif /* CONFIG_CTRL_IFACE_UDP */
29
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030#include "utils/common.h"
31#include "utils/eloop.h"
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -070032#include "utils/module_tests.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070033#include "common/version.h"
34#include "common/ieee802_11_defs.h"
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080035#include "common/ctrl_iface_common.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070036#ifdef CONFIG_DPP
37#include "common/dpp.h"
38#endif /* CONFIG_DPP */
39#include "common/wpa_ctrl.h"
Hai Shalom60840252021-02-19 19:02:11 -080040#include "common/ptksa_cache.h"
Sunil Ravi036cec52023-03-29 11:35:17 -070041#include "common/hw_features_common.h"
Sunil Ravib0ac25f2024-07-12 01:42:03 +000042#include "common/nan_de.h"
Dmitry Shmidtff787d52015-01-12 13:01:47 -080043#include "crypto/tls.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070044#include "drivers/driver.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080045#include "eapol_auth/eapol_auth_sm.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070046#include "radius/radius_client.h"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080047#include "radius/radius_server.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080048#include "l2_packet/l2_packet.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070049#include "ap/hostapd.h"
50#include "ap/ap_config.h"
51#include "ap/ieee802_1x.h"
52#include "ap/wpa_auth.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070053#include "ap/pmksa_cache_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070054#include "ap/ieee802_11.h"
55#include "ap/sta_info.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070056#include "ap/wps_hostapd.h"
57#include "ap/ctrl_iface_ap.h"
58#include "ap/ap_drv_ops.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080059#include "ap/hs20.h"
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -080060#include "ap/wnm_ap.h"
Dmitry Shmidtf7e0a992013-05-23 11:03:10 -070061#include "ap/wpa_auth.h"
Dmitry Shmidt7f656022015-02-25 14:36:37 -080062#include "ap/beacon.h"
Dmitry Shmidt849734c2016-05-27 09:59:01 -070063#include "ap/neighbor_db.h"
64#include "ap/rrm.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070065#include "ap/dpp_hostapd.h"
Hai Shalomfdcde762020-04-02 11:19:20 -070066#include "ap/dfs.h"
Sunil Ravib0ac25f2024-07-12 01:42:03 +000067#include "ap/nan_usd_ap.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070068#include "wps/wps_defs.h"
69#include "wps/wps.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080070#include "fst/fst_ctrl_iface.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070071#include "config_file.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070072#include "ctrl_iface.h"
73
74
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080075#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
76
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080077#ifdef CONFIG_CTRL_IFACE_UDP
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080078#define HOSTAPD_CTRL_IFACE_PORT 8877
79#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
80#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
81#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT 50
82#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070083
84static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
Anton Nayshtutf715e8d2014-11-16 16:52:49 +020085 enum wpa_msg_type type,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070086 const char *buf, size_t len);
87
88
89static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080090 struct sockaddr_storage *from,
Roshan Pius3a1667e2018-07-03 15:17:14 -070091 socklen_t fromlen, const char *input)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070092{
Roshan Pius3a1667e2018-07-03 15:17:14 -070093 return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen, input);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070094}
95
96
97static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -080098 struct sockaddr_storage *from,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070099 socklen_t fromlen)
100{
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800101 return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700102}
103
104
105static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800106 struct sockaddr_storage *from,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700107 socklen_t fromlen,
108 char *level)
109{
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -0800110 return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700111}
112
113
114static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
115 const char *txtaddr)
116{
117 u8 addr[ETH_ALEN];
118 struct sta_info *sta;
119
120 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
121
122 if (hwaddr_aton(txtaddr, addr))
123 return -1;
124
125 sta = ap_get_sta(hapd, addr);
126 if (sta)
127 return 0;
128
129 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
130 "notification", MAC2STR(addr));
131 sta = ap_sta_add(hapd, addr);
132 if (sta == NULL)
133 return -1;
134
135 hostapd_new_assoc_sta(hapd, sta, 0);
136 return 0;
137}
138
139
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700140#ifdef NEED_AP_MLME
141static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
142 const char *txtaddr)
143{
144 u8 addr[ETH_ALEN];
145 u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
146
147 wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
148
149 if (hwaddr_aton(txtaddr, addr) ||
150 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
151 return -1;
152
153 ieee802_11_send_sa_query_req(hapd, addr, trans_id);
154
155 return 0;
156}
157#endif /* NEED_AP_MLME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700158
159
160#ifdef CONFIG_WPS
161static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
162{
163 char *pin = os_strchr(txt, ' ');
164 char *timeout_txt;
165 int timeout;
166 u8 addr_buf[ETH_ALEN], *addr = NULL;
167 char *pos;
168
169 if (pin == NULL)
170 return -1;
171 *pin++ = '\0';
172
173 timeout_txt = os_strchr(pin, ' ');
174 if (timeout_txt) {
175 *timeout_txt++ = '\0';
176 timeout = atoi(timeout_txt);
177 pos = os_strchr(timeout_txt, ' ');
178 if (pos) {
179 *pos++ = '\0';
180 if (hwaddr_aton(pos, addr_buf) == 0)
181 addr = addr_buf;
182 }
183 } else
184 timeout = 0;
185
186 return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
187}
188
189
190static int hostapd_ctrl_iface_wps_check_pin(
191 struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
192{
193 char pin[9];
194 size_t len;
195 char *pos;
196 int ret;
197
198 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
199 (u8 *) cmd, os_strlen(cmd));
200 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
201 if (*pos < '0' || *pos > '9')
202 continue;
203 pin[len++] = *pos;
204 if (len == 9) {
205 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
206 return -1;
207 }
208 }
209 if (len != 4 && len != 8) {
210 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
211 return -1;
212 }
213 pin[len] = '\0';
214
215 if (len == 8) {
216 unsigned int pin_val;
217 pin_val = atoi(pin);
218 if (!wps_pin_valid(pin_val)) {
219 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
220 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800221 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700222 return -1;
223 return ret;
224 }
225 }
226
227 ret = os_snprintf(buf, buflen, "%s", pin);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800228 if (os_snprintf_error(buflen, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700229 return -1;
230
231 return ret;
232}
233
234
Dmitry Shmidt04949592012-07-19 12:16:46 -0700235#ifdef CONFIG_WPS_NFC
236static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
237 char *pos)
238{
239 size_t len;
240 struct wpabuf *buf;
241 int ret;
242
243 len = os_strlen(pos);
244 if (len & 0x01)
245 return -1;
246 len /= 2;
247
248 buf = wpabuf_alloc(len);
249 if (buf == NULL)
250 return -1;
251 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
252 wpabuf_free(buf);
253 return -1;
254 }
255
256 ret = hostapd_wps_nfc_tag_read(hapd, buf);
257 wpabuf_free(buf);
258
259 return ret;
260}
261
262
263static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
264 char *cmd, char *reply,
265 size_t max_len)
266{
267 int ndef;
268 struct wpabuf *buf;
269 int res;
270
271 if (os_strcmp(cmd, "WPS") == 0)
272 ndef = 0;
273 else if (os_strcmp(cmd, "NDEF") == 0)
274 ndef = 1;
275 else
276 return -1;
277
278 buf = hostapd_wps_nfc_config_token(hapd, ndef);
279 if (buf == NULL)
280 return -1;
281
282 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
283 wpabuf_len(buf));
284 reply[res++] = '\n';
285 reply[res] = '\0';
286
287 wpabuf_free(buf);
288
289 return res;
290}
291
292
293static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
294 char *reply, size_t max_len,
295 int ndef)
296{
297 struct wpabuf *buf;
298 int res;
299
300 buf = hostapd_wps_nfc_token_gen(hapd, ndef);
301 if (buf == NULL)
302 return -1;
303
304 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
305 wpabuf_len(buf));
306 reply[res++] = '\n';
307 reply[res] = '\0';
308
309 wpabuf_free(buf);
310
311 return res;
312}
313
314
315static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
316 char *cmd, char *reply,
317 size_t max_len)
318{
319 if (os_strcmp(cmd, "WPS") == 0)
320 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
321 max_len, 0);
322
323 if (os_strcmp(cmd, "NDEF") == 0)
324 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
325 max_len, 1);
326
327 if (os_strcmp(cmd, "enable") == 0)
328 return hostapd_wps_nfc_token_enable(hapd);
329
330 if (os_strcmp(cmd, "disable") == 0) {
331 hostapd_wps_nfc_token_disable(hapd);
332 return 0;
333 }
334
335 return -1;
336}
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800337
338
339static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
340 char *cmd, char *reply,
341 size_t max_len)
342{
343 struct wpabuf *buf;
344 int res;
345 char *pos;
346 int ndef;
347
348 pos = os_strchr(cmd, ' ');
349 if (pos == NULL)
350 return -1;
351 *pos++ = '\0';
352
353 if (os_strcmp(cmd, "WPS") == 0)
354 ndef = 0;
355 else if (os_strcmp(cmd, "NDEF") == 0)
356 ndef = 1;
357 else
358 return -1;
359
360 if (os_strcmp(pos, "WPS-CR") == 0)
361 buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
362 else
363 buf = NULL;
364 if (buf == NULL)
365 return -1;
366
367 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
368 wpabuf_len(buf));
369 reply[res++] = '\n';
370 reply[res] = '\0';
371
372 wpabuf_free(buf);
373
374 return res;
375}
376
377
378static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
379 char *cmd)
380{
Dmitry Shmidtcf32e602014-01-28 10:57:39 -0800381 size_t len;
382 struct wpabuf *req, *sel;
383 int ret;
384 char *pos, *role, *type, *pos2;
385
386 role = cmd;
387 pos = os_strchr(role, ' ');
388 if (pos == NULL)
389 return -1;
390 *pos++ = '\0';
391
392 type = pos;
393 pos = os_strchr(type, ' ');
394 if (pos == NULL)
395 return -1;
396 *pos++ = '\0';
397
398 pos2 = os_strchr(pos, ' ');
399 if (pos2 == NULL)
400 return -1;
401 *pos2++ = '\0';
402
403 len = os_strlen(pos);
404 if (len & 0x01)
405 return -1;
406 len /= 2;
407
408 req = wpabuf_alloc(len);
409 if (req == NULL)
410 return -1;
411 if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
412 wpabuf_free(req);
413 return -1;
414 }
415
416 len = os_strlen(pos2);
417 if (len & 0x01) {
418 wpabuf_free(req);
419 return -1;
420 }
421 len /= 2;
422
423 sel = wpabuf_alloc(len);
424 if (sel == NULL) {
425 wpabuf_free(req);
426 return -1;
427 }
428 if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
429 wpabuf_free(req);
430 wpabuf_free(sel);
431 return -1;
432 }
433
434 if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
435 ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
436 } else {
437 wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
438 "reported: role=%s type=%s", role, type);
439 ret = -1;
440 }
441 wpabuf_free(req);
442 wpabuf_free(sel);
443
444 return ret;
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800445}
446
Dmitry Shmidt04949592012-07-19 12:16:46 -0700447#endif /* CONFIG_WPS_NFC */
448
449
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700450static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
451 char *buf, size_t buflen)
452{
453 int timeout = 300;
454 char *pos;
455 const char *pin_txt;
456
457 pos = os_strchr(txt, ' ');
458 if (pos)
459 *pos++ = '\0';
460
461 if (os_strcmp(txt, "disable") == 0) {
462 hostapd_wps_ap_pin_disable(hapd);
463 return os_snprintf(buf, buflen, "OK\n");
464 }
465
466 if (os_strcmp(txt, "random") == 0) {
467 if (pos)
468 timeout = atoi(pos);
469 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
470 if (pin_txt == NULL)
471 return -1;
472 return os_snprintf(buf, buflen, "%s", pin_txt);
473 }
474
475 if (os_strcmp(txt, "get") == 0) {
476 pin_txt = hostapd_wps_ap_pin_get(hapd);
477 if (pin_txt == NULL)
478 return -1;
479 return os_snprintf(buf, buflen, "%s", pin_txt);
480 }
481
482 if (os_strcmp(txt, "set") == 0) {
483 char *pin;
484 if (pos == NULL)
485 return -1;
486 pin = pos;
487 pos = os_strchr(pos, ' ');
488 if (pos) {
489 *pos++ = '\0';
490 timeout = atoi(pos);
491 }
492 if (os_strlen(pin) > buflen)
493 return -1;
494 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
495 return -1;
496 return os_snprintf(buf, buflen, "%s", pin);
497 }
498
499 return -1;
500}
501
502
503static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
504{
505 char *pos;
506 char *ssid, *auth, *encr = NULL, *key = NULL;
507
508 ssid = txt;
509 pos = os_strchr(txt, ' ');
510 if (!pos)
511 return -1;
512 *pos++ = '\0';
513
514 auth = pos;
515 pos = os_strchr(pos, ' ');
516 if (pos) {
517 *pos++ = '\0';
518 encr = pos;
519 pos = os_strchr(pos, ' ');
520 if (pos) {
521 *pos++ = '\0';
522 key = pos;
523 }
524 }
525
526 return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
527}
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700528
529
530static const char * pbc_status_str(enum pbc_status status)
531{
532 switch (status) {
533 case WPS_PBC_STATUS_DISABLE:
534 return "Disabled";
535 case WPS_PBC_STATUS_ACTIVE:
536 return "Active";
537 case WPS_PBC_STATUS_TIMEOUT:
538 return "Timed-out";
539 case WPS_PBC_STATUS_OVERLAP:
540 return "Overlap";
541 default:
542 return "Unknown";
543 }
544}
545
546
547static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
548 char *buf, size_t buflen)
549{
550 int ret;
551 char *pos, *end;
552
553 pos = buf;
554 end = buf + buflen;
555
556 ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
557 pbc_status_str(hapd->wps_stats.pbc_status));
558
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800559 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700560 return pos - buf;
561 pos += ret;
562
563 ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
564 (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
565 "Success":
566 (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
567 "Failed" : "None")));
568
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800569 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700570 return pos - buf;
571 pos += ret;
572
573 /* If status == Failure - Add possible Reasons */
574 if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
575 hapd->wps_stats.failure_reason > 0) {
576 ret = os_snprintf(pos, end - pos,
577 "Failure Reason: %s\n",
578 wps_ei_str(hapd->wps_stats.failure_reason));
579
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800580 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700581 return pos - buf;
582 pos += ret;
583 }
584
585 if (hapd->wps_stats.status) {
586 ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
587 MAC2STR(hapd->wps_stats.peer_addr));
588
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800589 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -0700590 return pos - buf;
591 pos += ret;
592 }
593
594 return pos - buf;
595}
596
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700597#endif /* CONFIG_WPS */
598
Sunil Ravi876a49b2025-02-03 19:18:32 +0000599
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800600#ifdef CONFIG_HS20
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800601static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
602 const char *cmd)
603{
604 u8 addr[ETH_ALEN];
605 int code, reauth_delay, ret;
606 const char *pos;
607 size_t url_len;
608 struct wpabuf *req;
609
610 /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
611 if (hwaddr_aton(cmd, addr))
612 return -1;
613
614 pos = os_strchr(cmd, ' ');
615 if (pos == NULL)
616 return -1;
617 pos++;
618 code = atoi(pos);
619
620 pos = os_strchr(pos, ' ');
621 if (pos == NULL)
622 return -1;
623 pos++;
624 reauth_delay = atoi(pos);
625
626 url_len = 0;
627 pos = os_strchr(pos, ' ');
628 if (pos) {
629 pos++;
630 url_len = os_strlen(pos);
631 }
632
633 req = wpabuf_alloc(4 + url_len);
634 if (req == NULL)
635 return -1;
636 wpabuf_put_u8(req, code);
637 wpabuf_put_le16(req, reauth_delay);
638 wpabuf_put_u8(req, url_len);
639 if (pos)
640 wpabuf_put_data(req, pos, url_len);
641
642 wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
643 " to indicate imminent deauthentication (code=%d "
644 "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
645 ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
646 wpabuf_free(req);
647 return ret;
648}
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800649#endif /* CONFIG_HS20 */
650
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700651
Dmitry Shmidt051af732013-10-22 13:52:46 -0700652#ifdef CONFIG_INTERWORKING
653
654static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
655 const char *cmd)
656{
657 u8 qos_map_set[16 + 2 * 21], count = 0;
658 const char *pos = cmd;
659 int val, ret;
660
661 for (;;) {
662 if (count == sizeof(qos_map_set)) {
663 wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
664 return -1;
665 }
666
667 val = atoi(pos);
668 if (val < 0 || val > 255) {
669 wpa_printf(MSG_INFO, "Invalid QoS Map Set");
670 return -1;
671 }
672
673 qos_map_set[count++] = val;
674 pos = os_strchr(pos, ',');
675 if (!pos)
676 break;
677 pos++;
678 }
679
680 if (count < 16 || count & 1) {
681 wpa_printf(MSG_INFO, "Invalid QoS Map Set");
682 return -1;
683 }
684
685 ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
686 if (ret) {
687 wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
688 return -1;
689 }
690
691 os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
692 hapd->conf->qos_map_set_len = count;
693
694 return 0;
695}
696
697
698static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
699 const char *cmd)
700{
701 u8 addr[ETH_ALEN];
702 struct sta_info *sta;
703 struct wpabuf *buf;
704 u8 *qos_map_set = hapd->conf->qos_map_set;
705 u8 qos_map_set_len = hapd->conf->qos_map_set_len;
706 int ret;
707
708 if (!qos_map_set_len) {
709 wpa_printf(MSG_INFO, "QoS Map Set is not set");
710 return -1;
711 }
712
713 if (hwaddr_aton(cmd, addr))
714 return -1;
715
716 sta = ap_get_sta(hapd, addr);
717 if (sta == NULL) {
718 wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
719 "for QoS Map Configuration message",
720 MAC2STR(addr));
721 return -1;
722 }
723
724 if (!sta->qos_map_enabled) {
725 wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
726 "support for QoS Map", MAC2STR(addr));
727 return -1;
728 }
729
730 buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
731 if (buf == NULL)
732 return -1;
733
734 wpabuf_put_u8(buf, WLAN_ACTION_QOS);
735 wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
736
737 /* QoS Map Set Element */
738 wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
739 wpabuf_put_u8(buf, qos_map_set_len);
740 wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
741
742 ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
743 wpabuf_head(buf), wpabuf_len(buf));
744 wpabuf_free(buf);
745
746 return ret;
747}
748
749#endif /* CONFIG_INTERWORKING */
750
751
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700752#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800753
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800754static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
755 const char *cmd)
756{
757 u8 addr[ETH_ALEN];
758 struct sta_info *sta;
759 const char *pos;
760 unsigned int auto_report, timeout;
761
762 if (hwaddr_aton(cmd, addr)) {
763 wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
764 return -1;
765 }
766
767 sta = ap_get_sta(hapd, addr);
768 if (!sta) {
769 wpa_printf(MSG_DEBUG, "Station " MACSTR
770 " not found for Collocated Interference Request",
771 MAC2STR(addr));
772 return -1;
773 }
774
775 pos = cmd + 17;
776 if (*pos != ' ')
777 return -1;
778 pos++;
779 auto_report = atoi(pos);
780 pos = os_strchr(pos, ' ');
781 if (!pos)
782 return -1;
783 pos++;
784 timeout = atoi(pos);
785
786 return wnm_send_coloc_intf_req(hapd, sta, auto_report, timeout);
787}
788
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700789#endif /* CONFIG_WNM_AP */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800790
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800791
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800792static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
793 char *buf, size_t buflen)
794{
795 int ret = 0;
796 char *pos, *end;
797
798 pos = buf;
799 end = buf + buflen;
800
801 WPA_ASSERT(hapd->conf->wpa_key_mgmt);
802
803 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
804 ret = os_snprintf(pos, end - pos, "WPA-PSK ");
805 if (os_snprintf_error(end - pos, ret))
806 return pos - buf;
807 pos += ret;
808 }
809 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
810 ret = os_snprintf(pos, end - pos, "WPA-EAP ");
811 if (os_snprintf_error(end - pos, ret))
812 return pos - buf;
813 pos += ret;
814 }
Dmitry Shmidtabb90a32016-12-05 15:34:39 -0800815#ifdef CONFIG_IEEE80211R_AP
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800816 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
817 ret = os_snprintf(pos, end - pos, "FT-PSK ");
818 if (os_snprintf_error(end - pos, ret))
819 return pos - buf;
820 pos += ret;
821 }
822 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
823 ret = os_snprintf(pos, end - pos, "FT-EAP ");
824 if (os_snprintf_error(end - pos, ret))
825 return pos - buf;
826 pos += ret;
827 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700828#ifdef CONFIG_SHA384
829 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
830 ret = os_snprintf(pos, end - pos, "FT-EAP-SHA384 ");
831 if (os_snprintf_error(end - pos, ret))
832 return pos - buf;
833 pos += ret;
834 }
835#endif /* CONFIG_SHA384 */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800836#ifdef CONFIG_SAE
837 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
838 ret = os_snprintf(pos, end - pos, "FT-SAE ");
839 if (os_snprintf_error(end - pos, ret))
840 return pos - buf;
841 pos += ret;
842 }
Sunil Ravi89eba102022-09-13 21:04:37 -0700843 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
844 ret = os_snprintf(pos, end - pos, "FT-SAE-EXT-KEY ");
845 if (os_snprintf_error(end - pos, ret))
846 return pos - buf;
847 pos += ret;
848 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800849#endif /* CONFIG_SAE */
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800850#ifdef CONFIG_FILS
851 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
852 ret = os_snprintf(pos, end - pos, "FT-FILS-SHA256 ");
853 if (os_snprintf_error(end - pos, ret))
854 return pos - buf;
855 pos += ret;
856 }
857 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
858 ret = os_snprintf(pos, end - pos, "FT-FILS-SHA384 ");
859 if (os_snprintf_error(end - pos, ret))
860 return pos - buf;
861 pos += ret;
862 }
863#endif /* CONFIG_FILS */
Dmitry Shmidtabb90a32016-12-05 15:34:39 -0800864#endif /* CONFIG_IEEE80211R_AP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800865 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
866 ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
867 if (os_snprintf_error(end - pos, ret))
868 return pos - buf;
869 pos += ret;
870 }
871 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
872 ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
873 if (os_snprintf_error(end - pos, ret))
874 return pos - buf;
875 pos += ret;
876 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800877#ifdef CONFIG_SAE
878 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
879 ret = os_snprintf(pos, end - pos, "SAE ");
880 if (os_snprintf_error(end - pos, ret))
881 return pos - buf;
882 pos += ret;
883 }
Sunil Ravi89eba102022-09-13 21:04:37 -0700884 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
885 ret = os_snprintf(pos, end - pos, "SAE-EXT-KEY ");
886 if (os_snprintf_error(end - pos, ret))
887 return pos - buf;
888 pos += ret;
889 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800890#endif /* CONFIG_SAE */
891 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
892 ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
893 if (os_snprintf_error(end - pos, ret))
894 return pos - buf;
895 pos += ret;
896 }
897 if (hapd->conf->wpa_key_mgmt &
898 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
899 ret = os_snprintf(pos, end - pos,
900 "WPA-EAP-SUITE-B-192 ");
901 if (os_snprintf_error(end - pos, ret))
902 return pos - buf;
903 pos += ret;
904 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800905#ifdef CONFIG_FILS
906 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
907 ret = os_snprintf(pos, end - pos, "FILS-SHA256 ");
908 if (os_snprintf_error(end - pos, ret))
909 return pos - buf;
910 pos += ret;
911 }
912 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
913 ret = os_snprintf(pos, end - pos, "FILS-SHA384 ");
914 if (os_snprintf_error(end - pos, ret))
915 return pos - buf;
916 pos += ret;
917 }
918#endif /* CONFIG_FILS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800919
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700920#ifdef CONFIG_OWE
921 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
922 ret = os_snprintf(pos, end - pos, "OWE ");
923 if (os_snprintf_error(end - pos, ret))
924 return pos - buf;
925 pos += ret;
926 }
927#endif /* CONFIG_OWE */
928
929#ifdef CONFIG_DPP
930 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
931 ret = os_snprintf(pos, end - pos, "DPP ");
932 if (os_snprintf_error(end - pos, ret))
933 return pos - buf;
934 pos += ret;
935 }
936#endif /* CONFIG_DPP */
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000937#ifdef CONFIG_SHA384
938 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) {
939 ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA384 ");
940 if (os_snprintf_error(end - pos, ret))
941 return pos - buf;
942 pos += ret;
943 }
944#endif /* CONFIG_SHA384 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700945
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800946 if (pos > buf && *(pos - 1) == ' ') {
947 *(pos - 1) = '\0';
948 pos--;
949 }
950
951 return pos - buf;
952}
953
954
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700955static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
956 char *buf, size_t buflen)
957{
958 int ret;
959 char *pos, *end;
960
961 pos = buf;
962 end = buf + buflen;
963
964 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
965 "ssid=%s\n",
966 MAC2STR(hapd->own_addr),
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700967 wpa_ssid_txt(hapd->conf->ssid.ssid,
968 hapd->conf->ssid.ssid_len));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800969 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700970 return pos - buf;
971 pos += ret;
972
Sunil Ravi77d572f2023-01-17 23:58:31 +0000973 if ((hapd->conf->config_id)) {
974 ret = os_snprintf(pos, end - pos, "config_id=%s\n",
975 hapd->conf->config_id);
976 if (os_snprintf_error(end - pos, ret))
977 return pos - buf;
978 pos += ret;
979 }
980
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700981#ifdef CONFIG_WPS
982 ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
983 hapd->conf->wps_state == 0 ? "disabled" :
984 (hapd->conf->wps_state == 1 ? "not configured" :
985 "configured"));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800986 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700987 return pos - buf;
988 pos += ret;
989
990 if (hapd->conf->wps_state && hapd->conf->wpa &&
991 hapd->conf->ssid.wpa_passphrase) {
992 ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
993 hapd->conf->ssid.wpa_passphrase);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800994 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700995 return pos - buf;
996 pos += ret;
997 }
998
999 if (hapd->conf->wps_state && hapd->conf->wpa &&
1000 hapd->conf->ssid.wpa_psk &&
1001 hapd->conf->ssid.wpa_psk->group) {
1002 char hex[PMK_LEN * 2 + 1];
1003 wpa_snprintf_hex(hex, sizeof(hex),
1004 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
1005 ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001006 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001007 return pos - buf;
1008 pos += ret;
1009 }
Hai Shalom60840252021-02-19 19:02:11 -08001010
1011 if (hapd->conf->multi_ap) {
1012 struct hostapd_ssid *ssid = &hapd->conf->multi_ap_backhaul_ssid;
1013
1014 ret = os_snprintf(pos, end - pos, "multi_ap=%d\n",
1015 hapd->conf->multi_ap);
1016 if (os_snprintf_error(end - pos, ret))
1017 return pos - buf;
1018 pos += ret;
1019
1020 if (ssid->ssid_len) {
1021 ret = os_snprintf(pos, end - pos,
1022 "multi_ap_backhaul_ssid=%s\n",
1023 wpa_ssid_txt(ssid->ssid,
1024 ssid->ssid_len));
1025 if (os_snprintf_error(end - pos, ret))
1026 return pos - buf;
1027 pos += ret;
1028 }
1029
1030 if (hapd->conf->wps_state && hapd->conf->wpa &&
1031 ssid->wpa_passphrase) {
1032 ret = os_snprintf(pos, end - pos,
1033 "multi_ap_backhaul_wpa_passphrase=%s\n",
1034 ssid->wpa_passphrase);
1035 if (os_snprintf_error(end - pos, ret))
1036 return pos - buf;
1037 pos += ret;
1038 }
1039
1040 if (hapd->conf->wps_state && hapd->conf->wpa &&
1041 ssid->wpa_psk &&
1042 ssid->wpa_psk->group) {
1043 char hex[PMK_LEN * 2 + 1];
1044
1045 wpa_snprintf_hex(hex, sizeof(hex), ssid->wpa_psk->psk,
1046 PMK_LEN);
1047 ret = os_snprintf(pos, end - pos,
1048 "multi_ap_backhaul_wpa_psk=%s\n",
1049 hex);
1050 forced_memzero(hex, sizeof(hex));
1051 if (os_snprintf_error(end - pos, ret))
1052 return pos - buf;
1053 pos += ret;
1054 }
1055 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001056#endif /* CONFIG_WPS */
1057
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001058 if (hapd->conf->wpa) {
1059 ret = os_snprintf(pos, end - pos, "wpa=%d\n", hapd->conf->wpa);
1060 if (os_snprintf_error(end - pos, ret))
1061 return pos - buf;
1062 pos += ret;
1063 }
1064
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001065 if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
1066 ret = os_snprintf(pos, end - pos, "key_mgmt=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001067 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001068 return pos - buf;
1069 pos += ret;
1070
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001071 pos += hostapd_ctrl_iface_get_key_mgmt(hapd, pos, end - pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001072
1073 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001074 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001075 return pos - buf;
1076 pos += ret;
1077 }
1078
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001079 if (hapd->conf->wpa) {
1080 ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
1081 wpa_cipher_txt(hapd->conf->wpa_group));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001082 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001083 return pos - buf;
1084 pos += ret;
1085 }
1086
1087 if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
1088 ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001089 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001090 return pos - buf;
1091 pos += ret;
1092
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001093 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
1094 " ");
1095 if (ret < 0)
1096 return pos - buf;
1097 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001098
1099 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001100 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001101 return pos - buf;
1102 pos += ret;
1103 }
1104
1105 if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
1106 ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001107 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001108 return pos - buf;
1109 pos += ret;
1110
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001111 ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise,
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001112 " ");
1113 if (ret < 0)
1114 return pos - buf;
1115 pos += ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001116
1117 ret = os_snprintf(pos, end - pos, "\n");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001118 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001119 return pos - buf;
1120 pos += ret;
1121 }
1122
Hai Shalomfdcde762020-04-02 11:19:20 -07001123 if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
1124 ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
1125 hapd->conf->wpa_deny_ptk0_rekey);
1126 if (os_snprintf_error(end - pos, ret))
1127 return pos - buf;
1128 pos += ret;
1129 }
1130
1131 if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
1132 ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
1133 hapd->conf->extended_key_id);
1134 if (os_snprintf_error(end - pos, ret))
1135 return pos - buf;
1136 pos += ret;
1137 }
1138
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001139 return pos - buf;
1140}
1141
1142
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001143static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
Hai Shalom60840252021-02-19 19:02:11 -08001144 const char *bands)
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001145{
1146 union wpa_event_data event;
Hai Shalom60840252021-02-19 19:02:11 -08001147 u32 setband_mask = WPA_SETBAND_AUTO;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001148
Hai Shalom60840252021-02-19 19:02:11 -08001149 /*
1150 * For example:
1151 * SET setband 2G,6G
1152 * SET setband 5G
1153 * SET setband AUTO
1154 */
1155 if (!os_strstr(bands, "AUTO")) {
1156 if (os_strstr(bands, "5G"))
1157 setband_mask |= WPA_SETBAND_5G;
1158 if (os_strstr(bands, "6G"))
1159 setband_mask |= WPA_SETBAND_6G;
1160 if (os_strstr(bands, "2G"))
1161 setband_mask |= WPA_SETBAND_2G;
1162 if (setband_mask == WPA_SETBAND_AUTO)
1163 return -1;
1164 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001165
Hai Shalom60840252021-02-19 19:02:11 -08001166 if (hostapd_drv_set_band(hapd, setband_mask) == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001167 os_memset(&event, 0, sizeof(event));
1168 event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
1169 event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
1170 wpa_supplicant_event(hapd, EVENT_CHANNEL_LIST_CHANGED, &event);
1171 }
1172
1173 return 0;
1174}
1175
1176
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001177static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
1178{
1179 char *value;
1180 int ret = 0;
1181
1182 value = os_strchr(cmd, ' ');
1183 if (value == NULL)
1184 return -1;
1185 *value++ = '\0';
1186
1187 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
1188 if (0) {
1189#ifdef CONFIG_WPS_TESTING
1190 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
1191 long int val;
1192 val = strtol(value, NULL, 0);
1193 if (val < 0 || val > 0xff) {
1194 ret = -1;
1195 wpa_printf(MSG_DEBUG, "WPS: Invalid "
1196 "wps_version_number %ld", val);
1197 } else {
1198 wps_version_number = val;
1199 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
1200 "version %u.%u",
1201 (wps_version_number & 0xf0) >> 4,
1202 wps_version_number & 0x0f);
1203 hostapd_wps_update_ie(hapd);
1204 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001205 } else if (os_strcasecmp(cmd, "wps_testing_stub_cred") == 0) {
1206 wps_testing_stub_cred = atoi(value);
1207 wpa_printf(MSG_DEBUG, "WPS: Testing - stub_cred=%d",
1208 wps_testing_stub_cred);
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001209 } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
1210 wps_corrupt_pkhash = atoi(value);
1211 wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
1212 wps_corrupt_pkhash);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001213#endif /* CONFIG_WPS_TESTING */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001214#ifdef CONFIG_TESTING_OPTIONS
1215 } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
1216 hapd->ext_mgmt_frame_handling = atoi(value);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001217 } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
1218 hapd->ext_eapol_frame_io = atoi(value);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001219 } else if (os_strcasecmp(cmd, "force_backlog_bytes") == 0) {
1220 hapd->force_backlog_bytes = atoi(value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001221#ifdef CONFIG_DPP
1222 } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
1223 os_free(hapd->dpp_config_obj_override);
1224 hapd->dpp_config_obj_override = os_strdup(value);
1225 } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
1226 os_free(hapd->dpp_discovery_override);
1227 hapd->dpp_discovery_override = os_strdup(value);
1228 } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
1229 os_free(hapd->dpp_groups_override);
1230 hapd->dpp_groups_override = os_strdup(value);
1231 } else if (os_strcasecmp(cmd,
1232 "dpp_ignore_netaccesskey_mismatch") == 0) {
1233 hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001234 } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
1235 dpp_test = atoi(value);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001236 } else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
1237 dpp_version_override = atoi(value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001238#endif /* CONFIG_DPP */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001239#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001240#ifdef CONFIG_MBO
1241 } else if (os_strcasecmp(cmd, "mbo_assoc_disallow") == 0) {
1242 int val;
1243
1244 if (!hapd->conf->mbo_enabled)
1245 return -1;
1246
1247 val = atoi(value);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001248 if (val < 0 || val > MBO_ASSOC_DISALLOW_REASON_LOW_RSSI)
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001249 return -1;
1250
1251 hapd->mbo_assoc_disallow = val;
1252 ieee802_11_update_beacons(hapd->iface);
1253
1254 /*
1255 * TODO: Need to configure drivers that do AP MLME offload with
1256 * disallowing station logic.
1257 */
1258#endif /* CONFIG_MBO */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001259#ifdef CONFIG_DPP
1260 } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
1261 os_free(hapd->dpp_configurator_params);
1262 hapd->dpp_configurator_params = os_strdup(value);
Sunil Ravia04bd252022-05-02 22:54:18 -07001263#ifdef CONFIG_DPP2
1264 dpp_controller_set_params(hapd->iface->interfaces->dpp, value);
1265#endif /* CONFIG_DPP2 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08001266 } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
1267 hapd->dpp_init_max_tries = atoi(value);
1268 } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
1269 hapd->dpp_init_retry_time = atoi(value);
1270 } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
1271 hapd->dpp_resp_wait_time = atoi(value);
1272 } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
1273 hapd->dpp_resp_max_tries = atoi(value);
1274 } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
1275 hapd->dpp_resp_retry_time = atoi(value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001276#endif /* CONFIG_DPP */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001277 } else if (os_strcasecmp(cmd, "setband") == 0) {
1278 ret = hostapd_ctrl_iface_set_band(hapd, value);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001279 } else {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001280 ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001281 if (ret)
1282 return ret;
1283
1284 if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001285 hostapd_disassoc_deny_mac(hapd);
1286 } else if (os_strcasecmp(cmd, "accept_mac_file") == 0) {
1287 hostapd_disassoc_accept_mac(hapd);
Sunil Ravi99c035e2024-07-12 01:42:03 +00001288 } else if (os_strcasecmp(cmd, "ssid") == 0) {
1289 hostapd_neighbor_sync_own_report(hapd);
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001290 } else if (os_strncmp(cmd, "wme_ac_", 7) == 0 ||
1291 os_strncmp(cmd, "wmm_ac_", 7) == 0) {
1292 hapd->parameter_set_count++;
1293 if (ieee802_11_update_beacons(hapd->iface))
1294 wpa_printf(MSG_DEBUG,
1295 "Failed to update beacons with WMM parameters");
Hai Shalomc3565922019-10-28 11:58:20 -07001296 } else if (os_strcmp(cmd, "wpa_passphrase") == 0 ||
1297 os_strcmp(cmd, "sae_password") == 0 ||
1298 os_strcmp(cmd, "sae_pwe") == 0) {
1299 if (hapd->started)
1300 hostapd_setup_sae_pt(hapd->conf);
Hai Shalom899fcc72020-10-19 14:38:18 -07001301 } else if (os_strcasecmp(cmd, "transition_disable") == 0) {
1302 wpa_auth_set_transition_disable(hapd->wpa_auth,
1303 hapd->conf->transition_disable);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001304 }
Hai Shalomb755a2a2020-04-23 21:49:02 -07001305
1306#ifdef CONFIG_TESTING_OPTIONS
1307 if (os_strcmp(cmd, "ft_rsnxe_used") == 0)
1308 wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth,
1309 hapd->conf->ft_rsnxe_used);
Hai Shalom899fcc72020-10-19 14:38:18 -07001310 else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0)
1311 wpa_auth_set_ocv_override_freq(
1312 hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
1313 atoi(value));
1314 else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0)
1315 wpa_auth_set_ocv_override_freq(
1316 hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
1317 atoi(value));
1318 else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0)
1319 wpa_auth_set_ocv_override_freq(
1320 hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
1321 atoi(value));
1322 else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0)
1323 wpa_auth_set_ocv_override_freq(
1324 hapd->wpa_auth,
1325 WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value));
Kai Shie75b0652020-11-24 20:31:29 -08001326 else if (os_strcasecmp(cmd, "skip_send_eapol") == 0)
1327 wpa_auth_set_skip_send_eapol(hapd->wpa_auth, atoi(value));
1328 else if (os_strcasecmp(cmd, "enable_eapol_large_timeout") == 0)
1329 wpa_auth_set_enable_eapol_large_timeout(hapd->wpa_auth, atoi(value));
Hai Shalomb755a2a2020-04-23 21:49:02 -07001330#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001331 }
1332
1333 return ret;
1334}
1335
1336
1337static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
1338 char *buf, size_t buflen)
1339{
1340 int res;
1341
1342 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
1343
1344 if (os_strcmp(cmd, "version") == 0) {
1345 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001346 if (os_snprintf_error(buflen, res))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001347 return -1;
1348 return res;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001349 } else if (os_strcmp(cmd, "tls_library") == 0) {
1350 res = tls_get_library_version(buf, buflen);
1351 if (os_snprintf_error(buflen, res))
1352 return -1;
1353 return res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001354 }
1355
1356 return -1;
1357}
1358
1359
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001360static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
1361{
1362 if (hostapd_enable_iface(iface) < 0) {
1363 wpa_printf(MSG_ERROR, "Enabling of interface failed");
1364 return -1;
1365 }
1366 return 0;
1367}
1368
1369
1370static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
1371{
1372 if (hostapd_reload_iface(iface) < 0) {
1373 wpa_printf(MSG_ERROR, "Reloading of interface failed");
1374 return -1;
1375 }
1376 return 0;
1377}
1378
1379
Sunil Ravi77d572f2023-01-17 23:58:31 +00001380static int hostapd_ctrl_iface_reload_bss(struct hostapd_data *bss)
1381{
1382 if (hostapd_reload_bss_only(bss) < 0) {
1383 wpa_printf(MSG_ERROR, "Reloading of BSS failed");
1384 return -1;
1385 }
1386 return 0;
1387}
1388
1389
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001390static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
1391{
1392 if (hostapd_disable_iface(iface) < 0) {
1393 wpa_printf(MSG_ERROR, "Disabling of interface failed");
1394 return -1;
1395 }
1396 return 0;
1397}
1398
1399
Hai Shalom74f70d42019-02-11 14:42:39 -08001400static int
1401hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd,
1402 struct sta_info *sta, void *ctx)
1403{
1404 struct hostapd_wpa_psk *psk;
1405 const u8 *pmk;
1406 int pmk_len;
1407 int pmk_match;
1408 int sta_match;
1409 int bss_match;
1410 int reason;
1411
1412 pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
1413
1414 for (psk = hapd->conf->ssid.wpa_psk; pmk && psk; psk = psk->next) {
1415 pmk_match = PMK_LEN == pmk_len &&
1416 os_memcmp(psk->psk, pmk, pmk_len) == 0;
1417 sta_match = psk->group == 0 &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001418 ether_addr_equal(sta->addr, psk->addr);
Hai Shalom74f70d42019-02-11 14:42:39 -08001419 bss_match = psk->group == 1;
1420
1421 if (pmk_match && (sta_match || bss_match))
1422 return 0;
1423 }
1424
1425 wpa_printf(MSG_INFO, "STA " MACSTR
1426 " PSK/passphrase no longer valid - disconnect",
1427 MAC2STR(sta->addr));
1428 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
1429 hostapd_drv_sta_deauth(hapd, sta->addr, reason);
1430 ap_sta_deauthenticate(hapd, sta, reason);
1431
1432 return 0;
1433}
1434
1435
1436static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd)
1437{
1438 struct hostapd_bss_config *conf = hapd->conf;
1439 int err;
1440
1441 hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
1442
1443 err = hostapd_setup_wpa_psk(conf);
1444 if (err < 0) {
1445 wpa_printf(MSG_ERROR, "Reloading WPA-PSK passwords failed: %d",
1446 err);
1447 return -1;
1448 }
1449
1450 ap_for_each_sta(hapd, hostapd_ctrl_iface_kick_mismatch_psk_sta_iter,
1451 NULL);
1452
1453 return 0;
1454}
1455
1456
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001457#ifdef CONFIG_IEEE80211R_AP
1458
1459static int hostapd_ctrl_iface_get_rxkhs(struct hostapd_data *hapd,
1460 char *buf, size_t buflen)
1461{
1462 int ret, start_pos;
1463 char *pos, *end;
1464 struct ft_remote_r0kh *r0kh;
1465 struct ft_remote_r1kh *r1kh;
1466 struct hostapd_bss_config *conf = hapd->conf;
1467
1468 pos = buf;
1469 end = buf + buflen;
1470
1471 for (r0kh = conf->r0kh_list; r0kh; r0kh=r0kh->next) {
1472 start_pos = pos - buf;
1473 ret = os_snprintf(pos, end - pos, "r0kh=" MACSTR " ",
1474 MAC2STR(r0kh->addr));
1475 if (os_snprintf_error(end - pos, ret))
1476 return start_pos;
1477 pos += ret;
1478 if (r0kh->id_len + 1 >= (size_t) (end - pos))
1479 return start_pos;
1480 os_memcpy(pos, r0kh->id, r0kh->id_len);
1481 pos += r0kh->id_len;
1482 *pos++ = ' ';
1483 pos += wpa_snprintf_hex(pos, end - pos, r0kh->key,
1484 sizeof(r0kh->key));
1485 ret = os_snprintf(pos, end - pos, "\n");
1486 if (os_snprintf_error(end - pos, ret))
1487 return start_pos;
1488 pos += ret;
1489 }
1490
1491 for (r1kh = conf->r1kh_list; r1kh; r1kh=r1kh->next) {
1492 start_pos = pos - buf;
1493 ret = os_snprintf(pos, end - pos, "r1kh=" MACSTR " " MACSTR " ",
1494 MAC2STR(r1kh->addr), MAC2STR(r1kh->id));
1495 if (os_snprintf_error(end - pos, ret))
1496 return start_pos;
1497 pos += ret;
1498 pos += wpa_snprintf_hex(pos, end - pos, r1kh->key,
1499 sizeof(r1kh->key));
1500 ret = os_snprintf(pos, end - pos, "\n");
1501 if (os_snprintf_error(end - pos, ret))
1502 return start_pos;
1503 pos += ret;
1504 }
1505
1506 return pos - buf;
1507}
1508
1509
1510static int hostapd_ctrl_iface_reload_rxkhs(struct hostapd_data *hapd)
1511{
1512 struct hostapd_bss_config *conf = hapd->conf;
1513 int err;
1514
1515 hostapd_config_clear_rxkhs(conf);
1516
1517 err = hostapd_config_read_rxkh_file(conf, conf->rxkh_file);
1518 if (err < 0) {
1519 wpa_printf(MSG_ERROR, "Reloading RxKHs failed: %d",
1520 err);
1521 return -1;
1522 }
1523
1524 return 0;
1525}
1526
1527#endif /* CONFIG_IEEE80211R_AP */
1528
1529
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001530#ifdef CONFIG_TESTING_OPTIONS
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001531
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001532static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
1533{
1534 union wpa_event_data data;
1535 char *pos, *param;
1536 enum wpa_event_type event;
1537
1538 wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
1539
1540 os_memset(&data, 0, sizeof(data));
1541
1542 param = os_strchr(cmd, ' ');
1543 if (param == NULL)
1544 return -1;
1545 *param++ = '\0';
1546
1547 if (os_strcmp(cmd, "DETECTED") == 0)
1548 event = EVENT_DFS_RADAR_DETECTED;
1549 else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
1550 event = EVENT_DFS_CAC_FINISHED;
1551 else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
1552 event = EVENT_DFS_CAC_ABORTED;
1553 else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
1554 event = EVENT_DFS_NOP_FINISHED;
1555 else {
1556 wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
1557 cmd);
1558 return -1;
1559 }
1560
1561 pos = os_strstr(param, "freq=");
1562 if (pos)
1563 data.dfs_event.freq = atoi(pos + 5);
1564
1565 pos = os_strstr(param, "ht_enabled=1");
1566 if (pos)
1567 data.dfs_event.ht_enabled = 1;
1568
1569 pos = os_strstr(param, "chan_offset=");
1570 if (pos)
1571 data.dfs_event.chan_offset = atoi(pos + 12);
1572
1573 pos = os_strstr(param, "chan_width=");
1574 if (pos)
1575 data.dfs_event.chan_width = atoi(pos + 11);
1576
1577 pos = os_strstr(param, "cf1=");
1578 if (pos)
1579 data.dfs_event.cf1 = atoi(pos + 4);
1580
1581 pos = os_strstr(param, "cf2=");
1582 if (pos)
1583 data.dfs_event.cf2 = atoi(pos + 4);
1584
1585 wpa_supplicant_event(hapd, event, &data);
1586
1587 return 0;
1588}
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001589
1590
1591static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
1592{
1593 size_t len;
1594 u8 *buf;
1595 int res;
1596
1597 wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
1598
1599 len = os_strlen(cmd);
1600 if (len & 1)
1601 return -1;
1602 len /= 2;
1603
1604 buf = os_malloc(len);
1605 if (buf == NULL)
1606 return -1;
1607
1608 if (hexstr2bin(cmd, buf, len) < 0) {
1609 os_free(buf);
1610 return -1;
1611 }
1612
Hai Shalomfdcde762020-04-02 11:19:20 -07001613 res = hostapd_drv_send_mlme(hapd, buf, len, 0, NULL, 0, 0);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001614 os_free(buf);
1615 return res;
1616}
1617
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001618
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001619static int hostapd_ctrl_iface_mgmt_tx_status_process(struct hostapd_data *hapd,
1620 char *cmd)
1621{
1622 char *pos, *param;
1623 size_t len;
1624 u8 *buf;
1625 int stype = 0, ok = 0;
1626 union wpa_event_data event;
1627
1628 if (!hapd->ext_mgmt_frame_handling)
1629 return -1;
1630
1631 /* stype=<val> ok=<0/1> buf=<frame hexdump> */
1632
1633 wpa_printf(MSG_DEBUG, "External MGMT TX status process: %s", cmd);
1634
1635 pos = cmd;
1636 param = os_strstr(pos, "stype=");
1637 if (param) {
1638 param += 6;
1639 stype = atoi(param);
1640 }
1641
1642 param = os_strstr(pos, " ok=");
1643 if (param) {
1644 param += 4;
1645 ok = atoi(param);
1646 }
1647
1648 param = os_strstr(pos, " buf=");
1649 if (!param)
1650 return -1;
1651 param += 5;
1652
1653 len = os_strlen(param);
1654 if (len & 1)
1655 return -1;
1656 len /= 2;
1657
1658 buf = os_malloc(len);
1659 if (!buf || hexstr2bin(param, buf, len) < 0) {
1660 os_free(buf);
1661 return -1;
1662 }
1663
1664 os_memset(&event, 0, sizeof(event));
1665 event.tx_status.type = WLAN_FC_TYPE_MGMT;
1666 event.tx_status.data = buf;
1667 event.tx_status.data_len = len;
1668 event.tx_status.stype = stype;
1669 event.tx_status.ack = ok;
1670 hapd->ext_mgmt_frame_handling = 0;
1671 wpa_supplicant_event(hapd, EVENT_TX_STATUS, &event);
1672 hapd->ext_mgmt_frame_handling = 1;
1673
1674 os_free(buf);
1675
1676 return 0;
1677}
1678
1679
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08001680static int hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data *hapd,
1681 char *cmd)
1682{
1683 char *pos, *param;
1684 size_t len;
1685 u8 *buf;
1686 int freq = 0, datarate = 0, ssi_signal = 0;
1687 union wpa_event_data event;
1688
1689 if (!hapd->ext_mgmt_frame_handling)
1690 return -1;
1691
1692 /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
1693
1694 wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
1695
1696 pos = cmd;
1697 param = os_strstr(pos, "freq=");
1698 if (param) {
1699 param += 5;
1700 freq = atoi(param);
1701 }
1702
1703 param = os_strstr(pos, " datarate=");
1704 if (param) {
1705 param += 10;
1706 datarate = atoi(param);
1707 }
1708
1709 param = os_strstr(pos, " ssi_signal=");
1710 if (param) {
1711 param += 12;
1712 ssi_signal = atoi(param);
1713 }
1714
1715 param = os_strstr(pos, " frame=");
1716 if (param == NULL)
1717 return -1;
1718 param += 7;
1719
1720 len = os_strlen(param);
1721 if (len & 1)
1722 return -1;
1723 len /= 2;
1724
1725 buf = os_malloc(len);
1726 if (buf == NULL)
1727 return -1;
1728
1729 if (hexstr2bin(param, buf, len) < 0) {
1730 os_free(buf);
1731 return -1;
1732 }
1733
1734 os_memset(&event, 0, sizeof(event));
1735 event.rx_mgmt.freq = freq;
1736 event.rx_mgmt.frame = buf;
1737 event.rx_mgmt.frame_len = len;
1738 event.rx_mgmt.ssi_signal = ssi_signal;
1739 event.rx_mgmt.datarate = datarate;
1740 hapd->ext_mgmt_frame_handling = 0;
1741 wpa_supplicant_event(hapd, EVENT_RX_MGMT, &event);
1742 hapd->ext_mgmt_frame_handling = 1;
1743
1744 os_free(buf);
1745
1746 return 0;
1747}
1748
1749
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001750static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
1751{
1752 char *pos;
1753 u8 src[ETH_ALEN], *buf;
1754 int used;
1755 size_t len;
1756
1757 wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
1758
1759 pos = cmd;
1760 used = hwaddr_aton2(pos, src);
1761 if (used < 0)
1762 return -1;
1763 pos += used;
1764 while (*pos == ' ')
1765 pos++;
1766
1767 len = os_strlen(pos);
1768 if (len & 1)
1769 return -1;
1770 len /= 2;
1771
1772 buf = os_malloc(len);
1773 if (buf == NULL)
1774 return -1;
1775
1776 if (hexstr2bin(pos, buf, len) < 0) {
1777 os_free(buf);
1778 return -1;
1779 }
1780
Sunil8cd6f4d2022-06-28 18:40:46 +00001781 ieee802_1x_receive(hapd, src, buf, len, FRAME_ENCRYPTION_UNKNOWN);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001782 os_free(buf);
1783
1784 return 0;
1785}
1786
1787
Hai Shaloma20dcd72022-02-04 13:43:00 -08001788static int hostapd_ctrl_iface_eapol_tx(struct hostapd_data *hapd, char *cmd)
1789{
1790 char *pos, *pos2;
1791 u8 dst[ETH_ALEN], *buf;
1792 int used, ret;
1793 size_t len;
1794 unsigned int prev;
1795 int encrypt = 0;
1796
1797 wpa_printf(MSG_DEBUG, "External EAPOL TX: %s", cmd);
1798
1799 pos = cmd;
1800 used = hwaddr_aton2(pos, dst);
1801 if (used < 0)
1802 return -1;
1803 pos += used;
1804 while (*pos == ' ')
1805 pos++;
1806
1807 pos2 = os_strchr(pos, ' ');
1808 if (pos2) {
1809 len = pos2 - pos;
1810 encrypt = os_strstr(pos2, "encrypt=1") != NULL;
1811 } else {
1812 len = os_strlen(pos);
1813 }
1814 if (len & 1)
1815 return -1;
1816 len /= 2;
1817
1818 buf = os_malloc(len);
1819 if (!buf || hexstr2bin(pos, buf, len) < 0) {
1820 os_free(buf);
1821 return -1;
1822 }
1823
1824 prev = hapd->ext_eapol_frame_io;
1825 hapd->ext_eapol_frame_io = 0;
1826 ret = hostapd_wpa_auth_send_eapol(hapd, dst, buf, len, encrypt);
1827 hapd->ext_eapol_frame_io = prev;
1828 os_free(buf);
1829
1830 return ret;
1831}
1832
1833
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001834static u16 ipv4_hdr_checksum(const void *buf, size_t len)
1835{
1836 size_t i;
1837 u32 sum = 0;
1838 const u16 *pos = buf;
1839
1840 for (i = 0; i < len / 2; i++)
1841 sum += *pos++;
1842
1843 while (sum >> 16)
1844 sum = (sum & 0xffff) + (sum >> 16);
1845
1846 return sum ^ 0xffff;
1847}
1848
1849
1850#define HWSIM_PACKETLEN 1500
1851#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
1852
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07001853static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
1854 size_t len)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001855{
1856 struct hostapd_data *hapd = ctx;
1857 const struct ether_header *eth;
Hai Shalomfdcde762020-04-02 11:19:20 -07001858 struct ip ip;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001859 const u8 *pos;
1860 unsigned int i;
Hai Shalom81f62d82019-07-22 12:10:00 -07001861 char extra[30];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001862
Hai Shalom81f62d82019-07-22 12:10:00 -07001863 if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
1864 wpa_printf(MSG_DEBUG,
1865 "test data: RX - ignore unexpected length %d",
1866 (int) len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001867 return;
Hai Shalom81f62d82019-07-22 12:10:00 -07001868 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001869
1870 eth = (const struct ether_header *) buf;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001871 os_memcpy(&ip, eth + 1, sizeof(ip));
1872 pos = &buf[sizeof(*eth) + sizeof(ip)];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001873
Hai Shalomfdcde762020-04-02 11:19:20 -07001874 if (ip.ip_hl != 5 || ip.ip_v != 4 ||
1875 ntohs(ip.ip_len) > HWSIM_IP_LEN) {
Hai Shalom81f62d82019-07-22 12:10:00 -07001876 wpa_printf(MSG_DEBUG,
Hai Shalom899fcc72020-10-19 14:38:18 -07001877 "test data: RX - ignore unexpected IP header");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001878 return;
Hai Shalom81f62d82019-07-22 12:10:00 -07001879 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001880
Hai Shalomfdcde762020-04-02 11:19:20 -07001881 for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) {
Hai Shalom81f62d82019-07-22 12:10:00 -07001882 if (*pos != (u8) i) {
1883 wpa_printf(MSG_DEBUG,
1884 "test data: RX - ignore mismatching payload");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001885 return;
Hai Shalom81f62d82019-07-22 12:10:00 -07001886 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001887 pos++;
1888 }
1889
Hai Shalom81f62d82019-07-22 12:10:00 -07001890 extra[0] = '\0';
Hai Shalomfdcde762020-04-02 11:19:20 -07001891 if (ntohs(ip.ip_len) != HWSIM_IP_LEN)
1892 os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len));
Hai Shalom81f62d82019-07-22 12:10:00 -07001893 wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
1894 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001895}
1896
1897
1898static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
1899 char *cmd)
1900{
1901 int enabled = atoi(cmd);
1902 char *pos;
1903 const char *ifname;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001904 const u8 *addr = hapd->own_addr;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001905
1906 if (!enabled) {
1907 if (hapd->l2_test) {
1908 l2_packet_deinit(hapd->l2_test);
1909 hapd->l2_test = NULL;
1910 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1911 "test data: Disabled");
1912 }
1913 return 0;
1914 }
1915
1916 if (hapd->l2_test)
1917 return 0;
1918
1919 pos = os_strstr(cmd, " ifname=");
1920 if (pos)
1921 ifname = pos + 8;
1922 else
1923 ifname = hapd->conf->iface;
1924
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001925#ifdef CONFIG_IEEE80211BE
1926 if (hapd->conf->mld_ap)
Sunil Ravi99c035e2024-07-12 01:42:03 +00001927 addr = hapd->mld->mld_addr;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001928#endif /* CONFIG_IEEE80211BE */
1929 hapd->l2_test = l2_packet_init(ifname, addr,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001930 ETHERTYPE_IP, hostapd_data_test_rx,
1931 hapd, 1);
1932 if (hapd->l2_test == NULL)
1933 return -1;
1934
1935 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
1936
1937 return 0;
1938}
1939
1940
1941static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
1942{
1943 u8 dst[ETH_ALEN], src[ETH_ALEN];
Hai Shalom81f62d82019-07-22 12:10:00 -07001944 char *pos, *pos2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001945 int used;
1946 long int val;
1947 u8 tos;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001948 u8 buf[2 + HWSIM_PACKETLEN];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001949 struct ether_header *eth;
Hai Shalomfdcde762020-04-02 11:19:20 -07001950 struct ip *ip;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001951 u8 *dpos;
1952 unsigned int i;
Hai Shalom81f62d82019-07-22 12:10:00 -07001953 size_t send_len = HWSIM_IP_LEN;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001954
1955 if (hapd->l2_test == NULL)
1956 return -1;
1957
Hai Shalom81f62d82019-07-22 12:10:00 -07001958 /* format: <dst> <src> <tos> [len=<length>] */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001959
1960 pos = cmd;
1961 used = hwaddr_aton2(pos, dst);
1962 if (used < 0)
1963 return -1;
1964 pos += used;
1965 while (*pos == ' ')
1966 pos++;
1967 used = hwaddr_aton2(pos, src);
1968 if (used < 0)
1969 return -1;
1970 pos += used;
1971
Hai Shalom81f62d82019-07-22 12:10:00 -07001972 val = strtol(pos, &pos2, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001973 if (val < 0 || val > 0xff)
1974 return -1;
1975 tos = val;
1976
Hai Shalom81f62d82019-07-22 12:10:00 -07001977 pos = os_strstr(pos2, " len=");
1978 if (pos) {
1979 i = atoi(pos + 5);
1980 if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
1981 return -1;
1982 send_len = i;
1983 }
1984
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001985 eth = (struct ether_header *) &buf[2];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001986 os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
1987 os_memcpy(eth->ether_shost, src, ETH_ALEN);
1988 eth->ether_type = htons(ETHERTYPE_IP);
Hai Shalomfdcde762020-04-02 11:19:20 -07001989 ip = (struct ip *) (eth + 1);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001990 os_memset(ip, 0, sizeof(*ip));
Hai Shalomfdcde762020-04-02 11:19:20 -07001991 ip->ip_hl = 5;
1992 ip->ip_v = 4;
1993 ip->ip_ttl = 64;
1994 ip->ip_tos = tos;
1995 ip->ip_len = htons(send_len);
1996 ip->ip_p = 1;
1997 ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
1998 ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
1999 ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002000 dpos = (u8 *) (ip + 1);
Hai Shalom81f62d82019-07-22 12:10:00 -07002001 for (i = 0; i < send_len - sizeof(*ip); i++)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002002 *dpos++ = i;
2003
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002004 if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
Hai Shalom81f62d82019-07-22 12:10:00 -07002005 sizeof(struct ether_header) + send_len) < 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002006 return -1;
2007
2008 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
2009 " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
2010
2011 return 0;
2012}
2013
2014
2015static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
2016 char *cmd)
2017{
2018 u8 *buf;
2019 struct ether_header *eth;
2020 struct l2_packet_data *l2 = NULL;
2021 size_t len;
2022 u16 ethertype;
2023 int res = -1;
2024 const char *ifname = hapd->conf->iface;
2025
2026 if (os_strncmp(cmd, "ifname=", 7) == 0) {
2027 cmd += 7;
2028 ifname = cmd;
2029 cmd = os_strchr(cmd, ' ');
2030 if (cmd == NULL)
2031 return -1;
2032 *cmd++ = '\0';
2033 }
2034
2035 len = os_strlen(cmd);
2036 if (len & 1 || len < ETH_HLEN * 2)
2037 return -1;
2038 len /= 2;
2039
2040 buf = os_malloc(len);
2041 if (buf == NULL)
2042 return -1;
2043
2044 if (hexstr2bin(cmd, buf, len) < 0)
2045 goto done;
2046
2047 eth = (struct ether_header *) buf;
2048 ethertype = ntohs(eth->ether_type);
2049
2050 l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
2051 hostapd_data_test_rx, hapd, 1);
2052 if (l2 == NULL)
2053 goto done;
2054
2055 res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
2056 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
2057done:
2058 if (l2)
2059 l2_packet_deinit(l2);
2060 os_free(buf);
2061
2062 return res < 0 ? -1 : 0;
2063}
2064
Dmitry Shmidtff787d52015-01-12 13:01:47 -08002065
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002066static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
2067{
2068 struct sta_info *sta;
2069 u8 addr[ETH_ALEN];
2070 u8 zero[WPA_TK_MAX_LEN];
2071
2072 os_memset(zero, 0, sizeof(zero));
2073
2074 if (hwaddr_aton(cmd, addr))
2075 return -1;
2076
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002077 if (is_broadcast_ether_addr(addr) && os_strstr(cmd, " BIGTK")) {
2078 if (hapd->last_bigtk_alg == WPA_ALG_NONE)
2079 return -1;
2080
2081 wpa_printf(MSG_INFO, "TESTING: Reset BIPN for BIGTK");
2082
2083 /* First, use a zero key to avoid any possible duplicate key
2084 * avoidance in the driver. */
2085 if (hostapd_drv_set_key(hapd->conf->iface, hapd,
2086 hapd->last_bigtk_alg,
2087 broadcast_ether_addr,
2088 hapd->last_bigtk_key_idx, 0, 1, NULL, 0,
2089 zero, hapd->last_bigtk_len,
2090 KEY_FLAG_GROUP_TX_DEFAULT) < 0)
2091 return -1;
2092
2093 /* Set the previously configured key to reset its TSC */
2094 return hostapd_drv_set_key(hapd->conf->iface, hapd,
2095 hapd->last_bigtk_alg,
2096 broadcast_ether_addr,
2097 hapd->last_bigtk_key_idx, 0, 1, NULL,
2098 0, hapd->last_bigtk,
2099 hapd->last_bigtk_len,
2100 KEY_FLAG_GROUP_TX_DEFAULT);
2101 }
2102
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002103 if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
2104 if (hapd->last_igtk_alg == WPA_ALG_NONE)
2105 return -1;
2106
2107 wpa_printf(MSG_INFO, "TESTING: Reset IPN for IGTK");
2108
2109 /* First, use a zero key to avoid any possible duplicate key
2110 * avoidance in the driver. */
2111 if (hostapd_drv_set_key(hapd->conf->iface, hapd,
2112 hapd->last_igtk_alg,
2113 broadcast_ether_addr,
Hai Shalomfdcde762020-04-02 11:19:20 -07002114 hapd->last_igtk_key_idx, 0, 1, NULL, 0,
2115 zero, hapd->last_igtk_len,
2116 KEY_FLAG_GROUP_TX_DEFAULT) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002117 return -1;
2118
2119 /* Set the previously configured key to reset its TSC */
2120 return hostapd_drv_set_key(hapd->conf->iface, hapd,
2121 hapd->last_igtk_alg,
2122 broadcast_ether_addr,
Hai Shalomfdcde762020-04-02 11:19:20 -07002123 hapd->last_igtk_key_idx, 0, 1, NULL,
2124 0, hapd->last_igtk,
2125 hapd->last_igtk_len,
2126 KEY_FLAG_GROUP_TX_DEFAULT);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002127 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002128
2129 if (is_broadcast_ether_addr(addr)) {
2130 if (hapd->last_gtk_alg == WPA_ALG_NONE)
2131 return -1;
2132
2133 wpa_printf(MSG_INFO, "TESTING: Reset PN for GTK");
2134
2135 /* First, use a zero key to avoid any possible duplicate key
2136 * avoidance in the driver. */
2137 if (hostapd_drv_set_key(hapd->conf->iface, hapd,
2138 hapd->last_gtk_alg,
2139 broadcast_ether_addr,
Hai Shalomfdcde762020-04-02 11:19:20 -07002140 hapd->last_gtk_key_idx, 0, 1, NULL, 0,
2141 zero, hapd->last_gtk_len,
2142 KEY_FLAG_GROUP_TX_DEFAULT) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002143 return -1;
2144
2145 /* Set the previously configured key to reset its TSC */
2146 return hostapd_drv_set_key(hapd->conf->iface, hapd,
2147 hapd->last_gtk_alg,
2148 broadcast_ether_addr,
Hai Shalomfdcde762020-04-02 11:19:20 -07002149 hapd->last_gtk_key_idx, 0, 1, NULL,
2150 0, hapd->last_gtk,
2151 hapd->last_gtk_len,
2152 KEY_FLAG_GROUP_TX_DEFAULT);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002153 }
2154
2155 sta = ap_get_sta(hapd, addr);
2156 if (!sta)
2157 return -1;
2158
2159 if (sta->last_tk_alg == WPA_ALG_NONE)
2160 return -1;
2161
2162 wpa_printf(MSG_INFO, "TESTING: Reset PN for " MACSTR,
2163 MAC2STR(sta->addr));
2164
2165 /* First, use a zero key to avoid any possible duplicate key avoidance
2166 * in the driver. */
2167 if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
Hai Shalomfdcde762020-04-02 11:19:20 -07002168 sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
2169 zero, sta->last_tk_len,
2170 KEY_FLAG_PAIRWISE_RX_TX) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002171 return -1;
2172
2173 /* Set the previously configured key to reset its TSC/RSC */
2174 return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
Hai Shalomfdcde762020-04-02 11:19:20 -07002175 sta->addr, sta->last_tk_key_idx, 0, 1, NULL,
2176 0, sta->last_tk, sta->last_tk_len,
2177 KEY_FLAG_PAIRWISE_RX_TX);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002178}
2179
2180
2181static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
2182{
2183 u8 addr[ETH_ALEN];
2184 const char *pos = cmd;
2185 enum wpa_alg alg;
Hai Shalomfdcde762020-04-02 11:19:20 -07002186 enum key_flag key_flag;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002187 int idx, set_tx;
2188 u8 seq[6], key[WPA_TK_MAX_LEN];
2189 size_t key_len;
2190
Hai Shalomfdcde762020-04-02 11:19:20 -07002191 /* parameters: alg addr idx set_tx seq key key_flag */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002192
2193 alg = atoi(pos);
2194 pos = os_strchr(pos, ' ');
2195 if (!pos)
2196 return -1;
2197 pos++;
2198 if (hwaddr_aton(pos, addr))
2199 return -1;
2200 pos += 17;
2201 if (*pos != ' ')
2202 return -1;
2203 pos++;
2204 idx = atoi(pos);
2205 pos = os_strchr(pos, ' ');
2206 if (!pos)
2207 return -1;
2208 pos++;
2209 set_tx = atoi(pos);
2210 pos = os_strchr(pos, ' ');
2211 if (!pos)
2212 return -1;
2213 pos++;
Hai Shalom74f70d42019-02-11 14:42:39 -08002214 if (hexstr2bin(pos, seq, sizeof(seq)) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002215 return -1;
2216 pos += 2 * 6;
2217 if (*pos != ' ')
2218 return -1;
2219 pos++;
Hai Shalomfdcde762020-04-02 11:19:20 -07002220 if (!os_strchr(pos, ' '))
2221 return -1;
2222 key_len = (os_strchr(pos, ' ') - pos) / 2;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002223 if (hexstr2bin(pos, key, key_len) < 0)
2224 return -1;
Hai Shalomfdcde762020-04-02 11:19:20 -07002225 pos += 2 * key_len;
2226 if (*pos != ' ')
2227 return -1;
2228
2229 pos++;
2230 key_flag = atoi(pos);
2231 pos = os_strchr(pos, ' ');
2232 if (pos)
2233 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002234
2235 wpa_printf(MSG_INFO, "TESTING: Set key");
Hai Shalomfdcde762020-04-02 11:19:20 -07002236 return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx, 0,
2237 set_tx, seq, 6, key, key_len, key_flag);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002238}
2239
2240
2241static void restore_tk(void *ctx1, void *ctx2)
2242{
2243 struct hostapd_data *hapd = ctx1;
2244 struct sta_info *sta = ctx2;
2245
2246 wpa_printf(MSG_INFO, "TESTING: Restore TK for " MACSTR,
2247 MAC2STR(sta->addr));
2248 /* This does not really restore the TSC properly, so this will result
2249 * in replay protection issues for now since there is no clean way of
2250 * preventing encryption of a single EAPOL frame. */
2251 hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
Hai Shalomfdcde762020-04-02 11:19:20 -07002252 sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0,
2253 sta->last_tk, sta->last_tk_len,
2254 KEY_FLAG_PAIRWISE_RX_TX);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002255}
2256
2257
2258static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
2259{
2260 struct sta_info *sta;
2261 u8 addr[ETH_ALEN];
2262 int plain = os_strstr(cmd, "plaintext") != NULL;
2263
2264 if (hwaddr_aton(cmd, addr))
2265 return -1;
2266
2267 sta = ap_get_sta(hapd, addr);
2268 if (!sta || !sta->wpa_sm)
2269 return -1;
2270
2271 if (plain && sta->last_tk_alg == WPA_ALG_NONE)
2272 plain = 0; /* no need for special processing */
2273 if (plain) {
2274 wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
2275 MAC2STR(sta->addr));
2276 hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
Hai Shalomfdcde762020-04-02 11:19:20 -07002277 sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
2278 0, NULL, 0, KEY_FLAG_PAIRWISE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002279 }
2280
2281 wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
2282 return wpa_auth_resend_m1(sta->wpa_sm,
2283 os_strstr(cmd, "change-anonce") != NULL,
2284 plain ? restore_tk : NULL, hapd, sta);
2285}
2286
2287
2288static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
2289{
2290 struct sta_info *sta;
2291 u8 addr[ETH_ALEN];
2292 int plain = os_strstr(cmd, "plaintext") != NULL;
2293
2294 if (hwaddr_aton(cmd, addr))
2295 return -1;
2296
2297 sta = ap_get_sta(hapd, addr);
2298 if (!sta || !sta->wpa_sm)
2299 return -1;
2300
2301 if (plain && sta->last_tk_alg == WPA_ALG_NONE)
2302 plain = 0; /* no need for special processing */
2303 if (plain) {
2304 wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
2305 MAC2STR(sta->addr));
2306 hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
Hai Shalomfdcde762020-04-02 11:19:20 -07002307 sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
2308 0, NULL, 0, KEY_FLAG_PAIRWISE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002309 }
2310
2311 wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
2312 return wpa_auth_resend_m3(sta->wpa_sm,
2313 plain ? restore_tk : NULL, hapd, sta);
2314}
2315
2316
2317static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
2318 const char *cmd)
2319{
2320 struct sta_info *sta;
2321 u8 addr[ETH_ALEN];
2322 int plain = os_strstr(cmd, "plaintext") != NULL;
2323
2324 if (hwaddr_aton(cmd, addr))
2325 return -1;
2326
2327 sta = ap_get_sta(hapd, addr);
2328 if (!sta || !sta->wpa_sm)
2329 return -1;
2330
2331 if (plain && sta->last_tk_alg == WPA_ALG_NONE)
2332 plain = 0; /* no need for special processing */
2333 if (plain) {
2334 wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR,
2335 MAC2STR(sta->addr));
2336 hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
Hai Shalomfdcde762020-04-02 11:19:20 -07002337 sta->addr, sta->last_tk_key_idx, 0, 0, NULL,
2338 0, NULL, 0, KEY_FLAG_PAIRWISE);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002339 }
2340
2341 wpa_printf(MSG_INFO,
2342 "TESTING: Send group M1 for the same GTK and zero RSC to "
2343 MACSTR, MAC2STR(sta->addr));
2344 return wpa_auth_resend_group_m1(sta->wpa_sm,
2345 plain ? restore_tk : NULL, hapd, sta);
2346}
2347
Hai Shalomfdcde762020-04-02 11:19:20 -07002348
Hai Shaloma20dcd72022-02-04 13:43:00 -08002349static int hostapd_ctrl_rekey_ptk(struct hostapd_data *hapd, const char *cmd)
2350{
2351 struct sta_info *sta;
2352 u8 addr[ETH_ALEN];
2353
2354 if (hwaddr_aton(cmd, addr))
2355 return -1;
2356
2357 sta = ap_get_sta(hapd, addr);
2358 if (!sta || !sta->wpa_sm)
2359 return -1;
2360
2361 return wpa_auth_rekey_ptk(hapd->wpa_auth, sta->wpa_sm);
2362}
2363
2364
Hai Shalom899fcc72020-10-19 14:38:18 -07002365static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr,
2366 char *buf, size_t buflen)
2367{
2368 struct rsn_pmksa_cache_entry *pmksa;
2369
2370 pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, addr, NULL);
2371 if (!pmksa)
2372 return -1;
2373
2374 return wpa_snprintf_hex(buf, buflen, pmksa->pmk, pmksa->pmk_len);
2375}
2376
2377
Hai Shalomfdcde762020-04-02 11:19:20 -07002378static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
2379 char *buf, size_t buflen)
2380{
2381 struct sta_info *sta;
2382 u8 addr[ETH_ALEN];
2383 const u8 *pmk;
2384 int pmk_len;
2385
2386 if (hwaddr_aton(cmd, addr))
2387 return -1;
2388
2389 sta = ap_get_sta(hapd, addr);
2390 if (!sta || !sta->wpa_sm) {
2391 wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
2392 MAC2STR(addr));
Hai Shalom899fcc72020-10-19 14:38:18 -07002393 return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
Hai Shalomfdcde762020-04-02 11:19:20 -07002394 }
2395 pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07002396 if (!pmk || !pmk_len) {
Hai Shalomfdcde762020-04-02 11:19:20 -07002397 wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
2398 MAC2STR(addr));
Hai Shalom899fcc72020-10-19 14:38:18 -07002399 return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
Hai Shalomfdcde762020-04-02 11:19:20 -07002400 }
2401
2402 return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
2403}
2404
Hai Shaloma20dcd72022-02-04 13:43:00 -08002405
2406static int hostapd_ctrl_register_frame(struct hostapd_data *hapd,
2407 const char *cmd)
2408{
2409 u16 type;
2410 char *pos, *end;
2411 u8 match[10];
2412 size_t match_len;
2413 bool multicast = false;
2414
2415 type = strtol(cmd, &pos, 16);
2416 if (*pos != ' ')
2417 return -1;
2418 pos++;
2419 end = os_strchr(pos, ' ');
2420 if (end) {
2421 match_len = end - pos;
2422 multicast = os_strstr(end, "multicast") != NULL;
2423 } else {
2424 match_len = os_strlen(pos) / 2;
2425 }
2426 if (hexstr2bin(pos, match, match_len))
2427 return -1;
2428
2429 return hostapd_drv_register_frame(hapd, type, match, match_len,
2430 multicast);
2431}
2432
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002433#endif /* CONFIG_TESTING_OPTIONS */
2434
2435
Hai Shalomb755a2a2020-04-23 21:49:02 -07002436#ifdef NEED_AP_MLME
Sunil Ravic0f5d412024-09-11 22:12:49 +00002437
2438static bool
2439hostapd_ctrl_is_freq_in_cmode(struct hostapd_hw_modes *mode,
2440 struct hostapd_multi_hw_info *current_hw_info,
2441 int freq)
2442{
2443 struct hostapd_channel_data *chan;
2444 int i;
2445
2446 for (i = 0; i < mode->num_channels; i++) {
2447 chan = &mode->channels[i];
2448
2449 if (chan->flag & HOSTAPD_CHAN_DISABLED)
2450 continue;
2451
2452 if (!chan_in_current_hw_info(current_hw_info, chan))
2453 continue;
2454
2455 if (chan->freq == freq)
2456 return true;
2457 }
2458 return false;
2459}
2460
2461
Sunil Ravi036cec52023-03-29 11:35:17 -07002462static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
2463 u16 punct_bitmap)
Hai Shalomfdcde762020-04-02 11:19:20 -07002464{
Sunil Ravi036cec52023-03-29 11:35:17 -07002465 u32 start_freq;
2466
2467 if (is_6ghz_freq(params->freq)) {
2468 const int bw_idx[] = { 20, 40, 80, 160, 320 };
2469 int idx, bw;
2470
2471 /* The 6 GHz band requires HE to be enabled. */
2472 params->he_enabled = 1;
2473
2474 if (params->center_freq1) {
2475 if (params->freq == 5935)
2476 idx = (params->center_freq1 - 5925) / 5;
2477 else
2478 idx = (params->center_freq1 - 5950) / 5;
2479
2480 bw = center_idx_to_bw_6ghz(idx);
2481 if (bw < 0 || bw > (int) ARRAY_SIZE(bw_idx) ||
2482 bw_idx[bw] != params->bandwidth)
2483 return -1;
2484 }
Sunil Ravi7f769292024-07-23 22:21:32 +00002485 } else { /* Non-6 GHz channel */
2486 /* An EHT STA is also an HE STA as defined in
2487 * IEEE P802.11be/D5.0, 4.3.16a. */
2488 if (params->he_enabled || params->eht_enabled) {
2489 params->he_enabled = 1;
2490 /* An HE STA is also a VHT STA if operating in the 5 GHz
2491 * band and an HE STA is also an HT STA in the 2.4 GHz
2492 * band as defined in IEEE Std 802.11ax-2021, 4.3.15a.
2493 * A VHT STA is an HT STA as defined in IEEE
2494 * Std 802.11, 4.3.15. */
2495 if (IS_5GHZ(params->freq))
2496 params->vht_enabled = 1;
2497
2498 params->ht_enabled = 1;
2499 }
Sunil Ravi036cec52023-03-29 11:35:17 -07002500 }
2501
Hai Shalomfdcde762020-04-02 11:19:20 -07002502 switch (params->bandwidth) {
2503 case 0:
2504 /* bandwidth not specified: use 20 MHz by default */
2505 /* fall-through */
2506 case 20:
2507 if (params->center_freq1 &&
2508 params->center_freq1 != params->freq)
2509 return -1;
2510
2511 if (params->center_freq2 || params->sec_channel_offset)
2512 return -1;
Sunil Ravi036cec52023-03-29 11:35:17 -07002513
2514 if (punct_bitmap)
2515 return -1;
Hai Shalomfdcde762020-04-02 11:19:20 -07002516 break;
2517 case 40:
2518 if (params->center_freq2 || !params->sec_channel_offset)
2519 return -1;
2520
Sunil Ravi036cec52023-03-29 11:35:17 -07002521 if (punct_bitmap)
2522 return -1;
2523
Hai Shalomfdcde762020-04-02 11:19:20 -07002524 if (!params->center_freq1)
2525 break;
2526 switch (params->sec_channel_offset) {
2527 case 1:
2528 if (params->freq + 10 != params->center_freq1)
2529 return -1;
2530 break;
2531 case -1:
2532 if (params->freq - 10 != params->center_freq1)
2533 return -1;
2534 break;
2535 default:
2536 return -1;
2537 }
2538 break;
2539 case 80:
2540 if (!params->center_freq1 || !params->sec_channel_offset)
2541 return 1;
2542
2543 switch (params->sec_channel_offset) {
2544 case 1:
2545 if (params->freq - 10 != params->center_freq1 &&
2546 params->freq + 30 != params->center_freq1)
2547 return 1;
2548 break;
2549 case -1:
2550 if (params->freq + 10 != params->center_freq1 &&
2551 params->freq - 30 != params->center_freq1)
2552 return -1;
2553 break;
2554 default:
2555 return -1;
2556 }
2557
Sunil Ravi036cec52023-03-29 11:35:17 -07002558 if (params->center_freq2 && punct_bitmap)
2559 return -1;
2560
Hai Shalomfdcde762020-04-02 11:19:20 -07002561 /* Adjacent and overlapped are not allowed for 80+80 */
2562 if (params->center_freq2 &&
2563 params->center_freq1 - params->center_freq2 <= 80 &&
2564 params->center_freq2 - params->center_freq1 <= 80)
2565 return 1;
2566 break;
2567 case 160:
2568 if (!params->center_freq1 || params->center_freq2 ||
2569 !params->sec_channel_offset)
2570 return -1;
2571
2572 switch (params->sec_channel_offset) {
2573 case 1:
2574 if (params->freq + 70 != params->center_freq1 &&
2575 params->freq + 30 != params->center_freq1 &&
2576 params->freq - 10 != params->center_freq1 &&
2577 params->freq - 50 != params->center_freq1)
2578 return -1;
2579 break;
2580 case -1:
2581 if (params->freq + 50 != params->center_freq1 &&
2582 params->freq + 10 != params->center_freq1 &&
2583 params->freq - 30 != params->center_freq1 &&
2584 params->freq - 70 != params->center_freq1)
2585 return -1;
2586 break;
2587 default:
2588 return -1;
2589 }
2590 break;
Sunil Ravi640215c2023-06-28 23:08:09 +00002591 case 320:
2592 if (!params->center_freq1 || params->center_freq2 ||
2593 !params->sec_channel_offset)
2594 return -1;
2595
2596 switch (params->sec_channel_offset) {
2597 case 1:
2598 if (params->freq + 150 != params->center_freq1 &&
2599 params->freq + 110 != params->center_freq1 &&
2600 params->freq + 70 != params->center_freq1 &&
2601 params->freq + 30 != params->center_freq1 &&
2602 params->freq - 10 != params->center_freq1 &&
2603 params->freq - 50 != params->center_freq1 &&
2604 params->freq - 90 != params->center_freq1 &&
2605 params->freq - 130 != params->center_freq1)
2606 return -1;
2607 break;
2608 case -1:
2609 if (params->freq + 130 != params->center_freq1 &&
2610 params->freq + 90 != params->center_freq1 &&
2611 params->freq + 50 != params->center_freq1 &&
2612 params->freq + 10 != params->center_freq1 &&
2613 params->freq - 30 != params->center_freq1 &&
2614 params->freq - 70 != params->center_freq1 &&
2615 params->freq - 110 != params->center_freq1 &&
2616 params->freq - 150 != params->center_freq1)
2617 return -1;
2618 break;
2619 }
2620 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07002621 default:
2622 return -1;
2623 }
2624
Sunil Ravi036cec52023-03-29 11:35:17 -07002625 if (!punct_bitmap)
2626 return 0;
2627
2628 if (!params->eht_enabled) {
2629 wpa_printf(MSG_ERROR,
2630 "Preamble puncturing supported only in EHT");
2631 return -1;
2632 }
2633
2634 if (params->freq >= 2412 && params->freq <= 2484) {
2635 wpa_printf(MSG_ERROR,
2636 "Preamble puncturing is not supported in 2.4 GHz");
2637 return -1;
2638 }
2639
2640 start_freq = params->center_freq1 - (params->bandwidth / 2);
2641 if (!is_punct_bitmap_valid(params->bandwidth,
2642 (params->freq - start_freq) / 20,
2643 punct_bitmap)) {
2644 wpa_printf(MSG_ERROR, "Invalid preamble puncturing bitmap");
2645 return -1;
2646 }
2647
Hai Shalomfdcde762020-04-02 11:19:20 -07002648 return 0;
2649}
Hai Shalomb755a2a2020-04-23 21:49:02 -07002650#endif /* NEED_AP_MLME */
Hai Shalomfdcde762020-04-02 11:19:20 -07002651
2652
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002653static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
2654 char *pos)
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002655{
2656#ifdef NEED_AP_MLME
2657 struct csa_settings settings;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002658 int ret;
Hai Shalomfdcde762020-04-02 11:19:20 -07002659 int dfs_range = 0;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002660 unsigned int i;
Hai Shalomfdcde762020-04-02 11:19:20 -07002661 int bandwidth;
2662 u8 chan;
Sunil Ravi99c035e2024-07-12 01:42:03 +00002663 unsigned int num_err = 0;
2664 int err = 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002665
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002666 ret = hostapd_parse_csa_settings(pos, &settings);
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002667 if (ret)
2668 return ret;
2669
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002670 settings.link_id = -1;
2671#ifdef CONFIG_IEEE80211BE
2672 if (iface->num_bss && iface->bss[0]->conf->mld_ap)
2673 settings.link_id = iface->bss[0]->mld_link_id;
2674#endif /* CONFIG_IEEE80211BE */
2675
Sunil Ravic0f5d412024-09-11 22:12:49 +00002676 if (iface->num_hw_features > 1 &&
2677 !hostapd_ctrl_is_freq_in_cmode(iface->current_mode,
2678 iface->current_hw_info,
2679 settings.freq_params.freq)) {
2680 wpa_printf(MSG_INFO,
2681 "chanswitch: Invalid frequency settings provided for multi band phy");
2682 return -1;
2683 }
2684
Sunil Ravi036cec52023-03-29 11:35:17 -07002685 ret = hostapd_ctrl_check_freq_params(&settings.freq_params,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00002686 settings.freq_params.punct_bitmap);
Hai Shalomfdcde762020-04-02 11:19:20 -07002687 if (ret) {
2688 wpa_printf(MSG_INFO,
2689 "chanswitch: invalid frequency settings provided");
2690 return ret;
2691 }
2692
2693 switch (settings.freq_params.bandwidth) {
2694 case 40:
2695 bandwidth = CHAN_WIDTH_40;
2696 break;
2697 case 80:
2698 if (settings.freq_params.center_freq2)
2699 bandwidth = CHAN_WIDTH_80P80;
2700 else
2701 bandwidth = CHAN_WIDTH_80;
2702 break;
2703 case 160:
2704 bandwidth = CHAN_WIDTH_160;
2705 break;
Sunil8cd6f4d2022-06-28 18:40:46 +00002706 case 320:
2707 bandwidth = CHAN_WIDTH_320;
2708 break;
Hai Shalomfdcde762020-04-02 11:19:20 -07002709 default:
2710 bandwidth = CHAN_WIDTH_20;
2711 break;
2712 }
2713
2714 if (settings.freq_params.center_freq1)
2715 dfs_range += hostapd_is_dfs_overlap(
2716 iface, bandwidth, settings.freq_params.center_freq1);
2717 else
2718 dfs_range += hostapd_is_dfs_overlap(
2719 iface, bandwidth, settings.freq_params.freq);
2720
2721 if (settings.freq_params.center_freq2)
2722 dfs_range += hostapd_is_dfs_overlap(
2723 iface, bandwidth, settings.freq_params.center_freq2);
2724
2725 if (dfs_range) {
2726 ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
2727 if (ret == NUM_HOSTAPD_MODES) {
2728 wpa_printf(MSG_ERROR,
2729 "Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
2730 settings.freq_params.freq,
2731 settings.freq_params.sec_channel_offset,
2732 settings.freq_params.bandwidth);
2733 return -1;
2734 }
2735
2736 settings.freq_params.channel = chan;
2737
2738 wpa_printf(MSG_DEBUG,
2739 "DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
2740 settings.freq_params.channel,
2741 settings.freq_params.freq,
2742 settings.freq_params.sec_channel_offset,
2743 settings.freq_params.bandwidth,
2744 settings.freq_params.center_freq1);
2745
2746 /* Perform CAC and switch channel */
Sunil Ravi99c035e2024-07-12 01:42:03 +00002747 iface->is_ch_switch_dfs = true;
Hai Shalomfdcde762020-04-02 11:19:20 -07002748 hostapd_switch_channel_fallback(iface, &settings.freq_params);
2749 return 0;
2750 }
2751
Sunil Ravic0f5d412024-09-11 22:12:49 +00002752 if (iface->cac_started) {
2753 wpa_printf(MSG_DEBUG,
2754 "CAC is in progress - switching channel without CSA");
2755 return hostapd_force_channel_switch(iface, &settings);
2756 }
2757
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002758 for (i = 0; i < iface->num_bss; i++) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002759
Sunil Ravia04bd252022-05-02 22:54:18 -07002760 /* Save CHAN_SWITCH VHT, HE, and EHT config */
Hai Shalom60840252021-02-19 19:02:11 -08002761 hostapd_chan_switch_config(iface->bss[i],
2762 &settings.freq_params);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002763
Sunil Ravi99c035e2024-07-12 01:42:03 +00002764 err = hostapd_switch_channel(iface->bss[i], &settings);
2765 if (err) {
2766 ret = err;
2767 num_err++;
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07002768 }
2769 }
2770
Sunil Ravi99c035e2024-07-12 01:42:03 +00002771 return (iface->num_bss == num_err) ? ret : 0;
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08002772#else /* NEED_AP_MLME */
2773 return -1;
2774#endif /* NEED_AP_MLME */
2775}
2776
2777
Sunil Ravi7f769292024-07-23 22:21:32 +00002778#ifdef CONFIG_IEEE80211AX
2779static int hostapd_ctrl_iface_color_change(struct hostapd_iface *iface,
2780 const char *pos)
2781{
2782#ifdef NEED_AP_MLME
2783 struct cca_settings settings;
2784 struct hostapd_data *hapd = iface->bss[0];
2785 int ret, color;
2786 unsigned int i;
2787 char *end;
2788
2789 os_memset(&settings, 0, sizeof(settings));
2790
2791 color = strtol(pos, &end, 10);
2792 if (pos == end || color < 0 || color > 63) {
2793 wpa_printf(MSG_ERROR, "color_change: Invalid color provided");
2794 return -1;
2795 }
2796
2797 /* Color value is expected to be [1-63]. If 0 comes, assumption is this
2798 * is to disable the color. In this case no need to do CCA, just
2799 * changing Beacon frames is sufficient. */
2800 if (color == 0) {
2801 if (iface->conf->he_op.he_bss_color_disabled) {
2802 wpa_printf(MSG_ERROR,
2803 "color_change: Color is already disabled");
2804 return -1;
2805 }
2806
2807 iface->conf->he_op.he_bss_color_disabled = 1;
2808
2809 for (i = 0; i < iface->num_bss; i++)
2810 ieee802_11_set_beacon(iface->bss[i]);
2811
2812 return 0;
2813 }
2814
2815 if (color == iface->conf->he_op.he_bss_color) {
2816 if (!iface->conf->he_op.he_bss_color_disabled) {
2817 wpa_printf(MSG_ERROR,
2818 "color_change: Provided color is already set");
2819 return -1;
2820 }
2821
2822 iface->conf->he_op.he_bss_color_disabled = 0;
2823
2824 for (i = 0; i < iface->num_bss; i++)
2825 ieee802_11_set_beacon(iface->bss[i]);
2826
2827 return 0;
2828 }
2829
2830 if (hapd->cca_in_progress) {
2831 wpa_printf(MSG_ERROR,
2832 "color_change: CCA is already in progress");
2833 return -1;
2834 }
2835
2836 iface->conf->he_op.he_bss_color_disabled = 0;
2837
2838 for (i = 0; i < iface->num_bss; i++) {
2839 struct hostapd_data *bss = iface->bss[i];
2840
2841 hostapd_cleanup_cca_params(bss);
2842
2843 bss->cca_color = color;
2844 bss->cca_count = 10;
2845
2846 if (hostapd_fill_cca_settings(bss, &settings)) {
2847 wpa_printf(MSG_DEBUG,
2848 "color_change: Filling CCA settings failed for color: %d\n",
2849 color);
2850 hostapd_cleanup_cca_params(bss);
2851 continue;
2852 }
2853
2854 wpa_printf(MSG_DEBUG, "Setting user selected color: %d", color);
2855 ret = hostapd_drv_switch_color(bss, &settings);
2856 if (ret)
2857 hostapd_cleanup_cca_params(bss);
2858
2859 free_beacon_data(&settings.beacon_cca);
2860 free_beacon_data(&settings.beacon_after);
2861 }
2862
2863 return 0;
2864#else /* NEED_AP_MLME */
2865 return -1;
2866#endif /* NEED_AP_MLME */
2867}
2868#endif /* CONFIG_IEEE80211AX */
2869
2870
Sunil Ravi2a14cf12023-11-21 00:54:38 +00002871static u8 hostapd_maxnss(struct hostapd_data *hapd, struct sta_info *sta)
2872{
2873 u8 *mcs_set = NULL;
2874 u16 mcs_map;
2875 u8 ht_rx_nss = 0;
2876 u8 vht_rx_nss = 1;
2877 u8 mcs;
2878 bool ht_supported = false;
2879 bool vht_supported = false;
2880 int i;
2881
2882 if (sta->ht_capabilities && (sta->flags & WLAN_STA_HT)) {
2883 mcs_set = sta->ht_capabilities->supported_mcs_set;
2884 ht_supported = true;
2885 }
2886
2887 if (sta->vht_capabilities && (sta->flags & WLAN_STA_VHT)) {
2888 mcs_map = le_to_host16(
2889 sta->vht_capabilities->vht_supported_mcs_set.rx_map);
2890 vht_supported = true;
2891 }
2892
2893 if (ht_supported && mcs_set) {
2894 if (mcs_set[0])
2895 ht_rx_nss++;
2896 if (mcs_set[1])
2897 ht_rx_nss++;
2898 if (mcs_set[2])
2899 ht_rx_nss++;
2900 if (mcs_set[3])
2901 ht_rx_nss++;
2902 }
2903 if (vht_supported) {
2904 for (i = 7; i >= 0; i--) {
2905 mcs = (mcs_map >> (2 * i)) & 0x03;
2906 if (mcs != 0x03) {
2907 vht_rx_nss = i + 1;
2908 break;
2909 }
2910 }
2911 }
2912
2913 return ht_rx_nss > vht_rx_nss ? ht_rx_nss : vht_rx_nss;
2914}
2915
2916
2917static char hostapd_ctrl_iface_notify_cw_htaction(struct hostapd_data *hapd,
2918 const u8 *addr, u8 width)
2919{
2920 u8 buf[3];
2921 char ret;
2922
2923 width = width >= 1 ? 1 : 0;
2924
2925 buf[0] = WLAN_ACTION_HT;
2926 buf[1] = WLAN_HT_ACTION_NOTIFY_CHANWIDTH;
2927 buf[2] = width;
2928
2929 ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
2930 buf, sizeof(buf));
2931 if (ret)
2932 wpa_printf(MSG_DEBUG,
2933 "Failed to send Notify Channel Width frame to "
2934 MACSTR, MAC2STR(addr));
2935
2936 return ret;
2937}
2938
2939
2940static char hostapd_ctrl_iface_notify_cw_vhtaction(struct hostapd_data *hapd,
2941 const u8 *addr, u8 width)
2942{
2943 u8 buf[3];
2944 char ret;
2945
2946 buf[0] = WLAN_ACTION_VHT;
2947 buf[1] = WLAN_VHT_ACTION_OPMODE_NOTIF;
2948 buf[2] = width;
2949
2950 ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
2951 buf, sizeof(buf));
2952 if (ret)
2953 wpa_printf(MSG_DEBUG,
2954 "Failed to send Opeating Mode Notification frame to "
2955 MACSTR, MAC2STR(addr));
2956
2957 return ret;
2958}
2959
2960
2961static char hostapd_ctrl_iface_notify_cw_change(struct hostapd_data *hapd,
2962 const char *cmd)
2963{
2964 u8 cw, operating_mode = 0, nss;
2965 struct sta_info *sta;
2966 enum hostapd_hw_mode hw_mode;
2967
2968 if (is_6ghz_freq(hapd->iface->freq)) {
2969 wpa_printf(MSG_ERROR, "20/40 BSS coex not supported in 6 GHz");
2970 return -1;
2971 }
2972
2973 cw = atoi(cmd);
2974 hw_mode = hapd->iface->current_mode->mode;
2975 if ((hw_mode == HOSTAPD_MODE_IEEE80211G ||
2976 hw_mode == HOSTAPD_MODE_IEEE80211B) &&
2977 !(cw == 0 || cw == 1)) {
2978 wpa_printf(MSG_ERROR,
2979 "Channel width should be either 20 MHz or 40 MHz for 2.4 GHz band");
2980 return -1;
2981 }
2982
2983 switch (cw) {
2984 case 0:
2985 operating_mode = 0;
2986 break;
2987 case 1:
2988 operating_mode = VHT_OPMODE_CHANNEL_40MHZ;
2989 break;
2990 case 2:
2991 operating_mode = VHT_OPMODE_CHANNEL_80MHZ;
2992 break;
2993 case 3:
2994 operating_mode = VHT_OPMODE_CHANNEL_160MHZ;
2995 break;
2996 default:
2997 wpa_printf(MSG_ERROR, "Channel width should be between 0 to 3");
2998 return -1;
2999 }
3000
3001 for (sta = hapd->sta_list; sta; sta = sta->next) {
3002 if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
3003 nss = hostapd_maxnss(hapd, sta) - 1;
3004 hostapd_ctrl_iface_notify_cw_vhtaction(hapd, sta->addr,
3005 operating_mode |
3006 (u8) (nss << 4));
3007 continue;
3008 }
3009
3010 if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) ==
3011 WLAN_STA_HT && sta->ht_capabilities)
3012 hostapd_ctrl_iface_notify_cw_htaction(hapd, sta->addr,
3013 cw);
3014 }
3015
3016 return 0;
3017}
3018
3019
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003020static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
3021 int reply_size, const char *param)
3022{
3023#ifdef RADIUS_SERVER
3024 if (os_strcmp(param, "radius_server") == 0) {
3025 return radius_server_get_mib(hapd->radius_srv, reply,
3026 reply_size);
3027 }
3028#endif /* RADIUS_SERVER */
3029 return -1;
3030}
3031
3032
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003033static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
3034 char *buf, size_t buflen)
3035{
3036 int ret;
Hai Shalom60840252021-02-19 19:02:11 -08003037 char *pos, *temp = NULL;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003038 u8 *data = NULL;
3039 unsigned int vendor_id, subcmd;
Hai Shalom60840252021-02-19 19:02:11 -08003040 enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003041 struct wpabuf *reply;
3042 size_t data_len = 0;
3043
Hai Shalom60840252021-02-19 19:02:11 -08003044 /**
3045 * cmd: <vendor id> <subcommand id> [<hex formatted data>]
3046 * [nested=<0|1>]
3047 */
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003048 vendor_id = strtoul(cmd, &pos, 16);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003049 if (!isblank((unsigned char) *pos))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003050 return -EINVAL;
3051
3052 subcmd = strtoul(pos, &pos, 10);
3053
3054 if (*pos != '\0') {
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08003055 if (!isblank((unsigned char) *pos++))
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003056 return -EINVAL;
Hai Shalom60840252021-02-19 19:02:11 -08003057
3058 temp = os_strchr(pos, ' ');
3059 data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003060 }
3061
3062 if (data_len) {
3063 data_len /= 2;
3064 data = os_malloc(data_len);
3065 if (!data)
3066 return -ENOBUFS;
3067
3068 if (hexstr2bin(pos, data, data_len)) {
3069 wpa_printf(MSG_DEBUG,
3070 "Vendor command: wrong parameter format");
3071 os_free(data);
3072 return -EINVAL;
3073 }
3074 }
3075
Hai Shalom60840252021-02-19 19:02:11 -08003076 pos = os_strstr(cmd, "nested=");
3077 if (pos)
3078 nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED :
3079 NESTED_ATTR_NOT_USED;
3080
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003081 reply = wpabuf_alloc((buflen - 1) / 2);
3082 if (!reply) {
3083 os_free(data);
3084 return -ENOBUFS;
3085 }
3086
3087 ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
Hai Shalom60840252021-02-19 19:02:11 -08003088 nested_attr_flag, reply);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07003089
3090 if (ret == 0)
3091 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
3092 wpabuf_len(reply));
3093
3094 wpabuf_free(reply);
3095 os_free(data);
3096
3097 return ret;
3098}
3099
3100
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003101static int hostapd_ctrl_iface_eapol_reauth(struct hostapd_data *hapd,
3102 const char *cmd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003103{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003104 u8 addr[ETH_ALEN];
3105 struct sta_info *sta;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003106
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003107 if (hwaddr_aton(cmd, addr))
3108 return -1;
3109
3110 sta = ap_get_sta(hapd, addr);
3111 if (!sta || !sta->eapol_sm)
3112 return -1;
3113
3114 eapol_auth_reauthenticate(sta->eapol_sm);
3115 return 0;
3116}
3117
3118
3119static int hostapd_ctrl_iface_eapol_set(struct hostapd_data *hapd, char *cmd)
3120{
3121 u8 addr[ETH_ALEN];
3122 struct sta_info *sta;
3123 char *pos = cmd, *param;
3124
3125 if (hwaddr_aton(pos, addr) || pos[17] != ' ')
3126 return -1;
3127 pos += 18;
3128 param = pos;
3129 pos = os_strchr(pos, ' ');
3130 if (!pos)
3131 return -1;
3132 *pos++ = '\0';
3133
3134 sta = ap_get_sta(hapd, addr);
3135 if (!sta || !sta->eapol_sm)
3136 return -1;
3137
3138 return eapol_auth_set_conf(sta->eapol_sm, param, pos);
3139}
3140
3141
3142static int hostapd_ctrl_iface_log_level(struct hostapd_data *hapd, char *cmd,
3143 char *buf, size_t buflen)
3144{
3145 char *pos, *end, *stamp;
3146 int ret;
3147
3148 /* cmd: "LOG_LEVEL [<level>]" */
3149 if (*cmd == '\0') {
3150 pos = buf;
3151 end = buf + buflen;
3152 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
3153 "Timestamp: %d\n",
3154 debug_level_str(wpa_debug_level),
3155 wpa_debug_timestamp);
3156 if (os_snprintf_error(end - pos, ret))
3157 ret = 0;
3158
3159 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003160 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003161
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003162 while (*cmd == ' ')
3163 cmd++;
3164
3165 stamp = os_strchr(cmd, ' ');
3166 if (stamp) {
3167 *stamp++ = '\0';
3168 while (*stamp == ' ') {
3169 stamp++;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08003170 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003171 }
3172
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003173 if (os_strlen(cmd)) {
3174 int level = str_to_debug_level(cmd);
3175 if (level < 0)
3176 return -1;
3177 wpa_debug_level = level;
3178 }
3179
3180 if (stamp && os_strlen(stamp))
3181 wpa_debug_timestamp = atoi(stamp);
3182
3183 os_memcpy(buf, "OK\n", 3);
3184 return 3;
3185}
3186
3187
3188#ifdef NEED_AP_MLME
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003189
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003190static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
3191 char *buf, size_t buflen)
3192{
3193 struct hostapd_iface *iface = hapd->iface;
3194 char *pos, *end;
3195 struct hostapd_sta_info *info;
3196 struct os_reltime now;
3197
Dmitry Shmidt7d175302016-09-06 13:11:34 -07003198 if (!iface->num_sta_seen)
3199 return 0;
3200
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003201 sta_track_expire(iface, 0);
3202
3203 pos = buf;
3204 end = buf + buflen;
3205
3206 os_get_reltime(&now);
3207 dl_list_for_each_reverse(info, &iface->sta_seen,
3208 struct hostapd_sta_info, list) {
3209 struct os_reltime age;
3210 int ret;
3211
3212 os_reltime_sub(&now, &info->last_seen, &age);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003213 ret = os_snprintf(pos, end - pos, MACSTR " %u %d\n",
3214 MAC2STR(info->addr), (unsigned int) age.sec,
3215 info->ssi_signal);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003216 if (os_snprintf_error(end - pos, ret))
3217 break;
3218 pos += ret;
3219 }
3220
3221 return pos - buf;
3222}
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00003223
3224
3225static int hostapd_ctrl_iface_dump_beacon(struct hostapd_data *hapd,
3226 char *buf, size_t buflen)
3227{
3228 struct beacon_data beacon;
3229 char *pos, *end;
3230 int ret;
3231
3232 if (hostapd_build_beacon_data(hapd, &beacon) < 0)
3233 return -1;
3234
3235 if (2 * (beacon.head_len + beacon.tail_len) > buflen)
3236 return -1;
3237
3238 pos = buf;
3239 end = buf + buflen;
3240
3241 ret = wpa_snprintf_hex(pos, end - pos, beacon.head, beacon.head_len);
3242 pos += ret;
3243
3244 ret = wpa_snprintf_hex(pos, end - pos, beacon.tail, beacon.tail_len);
3245 pos += ret;
3246
3247 free_beacon_data(&beacon);
3248
3249 return pos - buf;
3250}
3251
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08003252#endif /* NEED_AP_MLME */
3253
3254
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003255static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
3256 const char *cmd)
3257{
3258 u8 addr[ETH_ALEN];
3259
3260 if (hwaddr_aton(cmd, addr)) {
3261 wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
3262 return -1;
3263 }
3264
3265 return hostapd_send_lci_req(hapd, addr);
3266}
3267
3268
Dmitry Shmidt4ae50e62016-06-27 13:48:39 -07003269static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003270{
3271 u8 addr[ETH_ALEN];
3272 char *token, *context = NULL;
3273 int random_interval, min_ap;
3274 u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
3275 unsigned int n_responders;
3276
3277 token = str_token(cmd, " ", &context);
3278 if (!token || hwaddr_aton(token, addr)) {
3279 wpa_printf(MSG_INFO,
3280 "CTRL: REQ_RANGE - Bad destination address");
3281 return -1;
3282 }
3283
3284 token = str_token(cmd, " ", &context);
3285 if (!token)
3286 return -1;
3287
3288 random_interval = atoi(token);
3289 if (random_interval < 0 || random_interval > 0xffff)
3290 return -1;
3291
3292 token = str_token(cmd, " ", &context);
3293 if (!token)
3294 return -1;
3295
3296 min_ap = atoi(token);
3297 if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
3298 return -1;
3299
3300 n_responders = 0;
3301 while ((token = str_token(cmd, " ", &context))) {
3302 if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
3303 wpa_printf(MSG_INFO,
3304 "CTRL: REQ_RANGE: Too many responders");
3305 return -1;
3306 }
3307
3308 if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
3309 wpa_printf(MSG_INFO,
3310 "CTRL: REQ_RANGE: Bad responder address");
3311 return -1;
3312 }
3313
3314 n_responders++;
3315 }
3316
3317 if (!n_responders) {
3318 wpa_printf(MSG_INFO,
3319 "CTRL: REQ_RANGE - No FTM responder address");
3320 return -1;
3321 }
3322
3323 return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
3324 responders, n_responders);
3325}
3326
3327
Dmitry Shmidt29333592017-01-09 12:27:11 -08003328static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd,
3329 const char *cmd, char *reply,
3330 size_t reply_size)
3331{
3332 u8 addr[ETH_ALEN];
3333 const char *pos;
3334 struct wpabuf *req;
3335 int ret;
3336 u8 req_mode = 0;
3337
3338 if (hwaddr_aton(cmd, addr))
3339 return -1;
3340 pos = os_strchr(cmd, ' ');
3341 if (!pos)
3342 return -1;
3343 pos++;
3344 if (os_strncmp(pos, "req_mode=", 9) == 0) {
3345 int val = hex2byte(pos + 9);
3346
3347 if (val < 0)
3348 return -1;
3349 req_mode = val;
3350 pos += 11;
3351 pos = os_strchr(pos, ' ');
3352 if (!pos)
3353 return -1;
3354 pos++;
3355 }
3356 req = wpabuf_parse_bin(pos);
3357 if (!req)
3358 return -1;
3359
3360 ret = hostapd_send_beacon_req(hapd, addr, req_mode, req);
3361 wpabuf_free(req);
3362 if (ret >= 0)
3363 ret = os_snprintf(reply, reply_size, "%d", ret);
3364 return ret;
3365}
3366
3367
Sunil Ravi99c035e2024-07-12 01:42:03 +00003368static int hostapd_ctrl_iface_req_link_measurement(struct hostapd_data *hapd,
3369 const char *cmd, char *reply,
3370 size_t reply_size)
3371{
3372 u8 addr[ETH_ALEN];
3373 int ret;
3374
3375 if (hwaddr_aton(cmd, addr)) {
3376 wpa_printf(MSG_ERROR,
3377 "CTRL: REQ_LINK_MEASUREMENT: Invalid MAC address");
3378 return -1;
3379 }
3380
3381 ret = hostapd_send_link_measurement_req(hapd, addr);
3382 if (ret >= 0)
3383 ret = os_snprintf(reply, reply_size, "%d", ret);
3384 return ret;
3385}
3386
3387
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003388static int hostapd_ctrl_iface_show_neighbor(struct hostapd_data *hapd,
3389 char *buf, size_t buflen)
3390{
3391 if (!(hapd->conf->radio_measurements[0] &
3392 WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
3393 wpa_printf(MSG_ERROR,
3394 "CTRL: SHOW_NEIGHBOR: Neighbor report is not enabled");
3395 return -1;
3396 }
3397
3398 return hostapd_neighbor_show(hapd, buf, buflen);
3399}
3400
3401
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003402static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
3403{
3404 struct wpa_ssid_value ssid;
3405 u8 bssid[ETH_ALEN];
3406 struct wpabuf *nr, *lci = NULL, *civic = NULL;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003407 int stationary = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003408 int bss_parameters = 0;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003409 char *tmp;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003410 int ret = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003411
3412 if (!(hapd->conf->radio_measurements[0] &
3413 WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
3414 wpa_printf(MSG_ERROR,
3415 "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
3416 return -1;
3417 }
3418
3419 if (hwaddr_aton(buf, bssid)) {
3420 wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
3421 return -1;
3422 }
3423
3424 tmp = os_strstr(buf, "ssid=");
3425 if (!tmp || ssid_parse(tmp + 5, &ssid)) {
3426 wpa_printf(MSG_ERROR,
3427 "CTRL: SET_NEIGHBOR: Bad or missing SSID");
3428 return -1;
3429 }
3430 buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
3431 if (!buf)
3432 return -1;
3433
3434 tmp = os_strstr(buf, "nr=");
3435 if (!tmp) {
3436 wpa_printf(MSG_ERROR,
3437 "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
3438 return -1;
3439 }
3440
3441 buf = os_strchr(tmp, ' ');
3442 if (buf)
3443 *buf++ = '\0';
3444
3445 nr = wpabuf_parse_bin(tmp + 3);
3446 if (!nr) {
3447 wpa_printf(MSG_ERROR,
3448 "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
3449 return -1;
3450 }
3451
3452 if (!buf)
3453 goto set;
3454
3455 tmp = os_strstr(buf, "lci=");
3456 if (tmp) {
3457 buf = os_strchr(tmp, ' ');
3458 if (buf)
3459 *buf++ = '\0';
3460 lci = wpabuf_parse_bin(tmp + 4);
3461 if (!lci) {
3462 wpa_printf(MSG_ERROR,
3463 "CTRL: SET_NEIGHBOR: Bad LCI subelement");
Hai Shaloma20dcd72022-02-04 13:43:00 -08003464 goto fail;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003465 }
3466 }
3467
3468 if (!buf)
3469 goto set;
3470
3471 tmp = os_strstr(buf, "civic=");
3472 if (tmp) {
3473 buf = os_strchr(tmp, ' ');
3474 if (buf)
3475 *buf++ = '\0';
3476 civic = wpabuf_parse_bin(tmp + 6);
3477 if (!civic) {
3478 wpa_printf(MSG_ERROR,
3479 "CTRL: SET_NEIGHBOR: Bad civic subelement");
Hai Shaloma20dcd72022-02-04 13:43:00 -08003480 goto fail;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003481 }
3482 }
3483
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003484 if (!buf)
3485 goto set;
3486
3487 if (os_strstr(buf, "stat"))
3488 stationary = 1;
3489
Hai Shaloma20dcd72022-02-04 13:43:00 -08003490 tmp = os_strstr(buf, "bss_parameter=");
3491 if (tmp) {
3492 bss_parameters = atoi(tmp + 14);
3493 if (bss_parameters < 0 || bss_parameters > 0xff) {
3494 wpa_printf(MSG_ERROR,
3495 "CTRL: SET_NEIGHBOR: Bad bss_parameters subelement");
3496 goto fail;
3497 }
3498 }
3499
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003500set:
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08003501 ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic,
Hai Shaloma20dcd72022-02-04 13:43:00 -08003502 stationary, bss_parameters);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003503
Hai Shaloma20dcd72022-02-04 13:43:00 -08003504fail:
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003505 wpabuf_free(nr);
3506 wpabuf_free(lci);
3507 wpabuf_free(civic);
3508
3509 return ret;
3510}
3511
3512
3513static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
3514 char *buf)
3515{
3516 struct wpa_ssid_value ssid;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003517 struct wpa_ssid_value *ssidp = NULL;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003518 u8 bssid[ETH_ALEN];
3519 char *tmp;
3520
3521 if (hwaddr_aton(buf, bssid)) {
3522 wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
3523 return -1;
3524 }
3525
3526 tmp = os_strstr(buf, "ssid=");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003527 if (tmp) {
3528 ssidp = &ssid;
3529 if (ssid_parse(tmp + 5, &ssid)) {
3530 wpa_printf(MSG_ERROR,
3531 "CTRL: REMOVE_NEIGHBOR: Bad SSID");
3532 return -1;
3533 }
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003534 }
3535
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003536 return hostapd_neighbor_remove(hapd, bssid, ssidp);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07003537}
3538
3539
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07003540static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
3541 size_t buflen)
3542{
3543 int ret, i;
3544 char *pos, *end;
3545
3546 ret = os_snprintf(buf, buflen, "%016llX:\n",
3547 (long long unsigned) iface->drv_flags);
3548 if (os_snprintf_error(buflen, ret))
3549 return -1;
3550
3551 pos = buf + ret;
3552 end = buf + buflen;
3553
3554 for (i = 0; i < 64; i++) {
3555 if (iface->drv_flags & (1LLU << i)) {
3556 ret = os_snprintf(pos, end - pos, "%s\n",
3557 driver_flag_to_string(1LLU << i));
3558 if (os_snprintf_error(end - pos, ret))
3559 return -1;
3560 pos += ret;
3561 }
3562 }
3563
3564 return pos - buf;
3565}
3566
3567
Hai Shalomb755a2a2020-04-23 21:49:02 -07003568static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf,
3569 size_t buflen)
3570{
3571 int ret, i;
3572 char *pos, *end;
3573
3574 ret = os_snprintf(buf, buflen, "%016llX:\n",
3575 (long long unsigned) iface->drv_flags2);
3576 if (os_snprintf_error(buflen, ret))
3577 return -1;
3578
3579 pos = buf + ret;
3580 end = buf + buflen;
3581
3582 for (i = 0; i < 64; i++) {
3583 if (iface->drv_flags2 & (1LLU << i)) {
3584 ret = os_snprintf(pos, end - pos, "%s\n",
3585 driver_flag2_to_string(1LLU << i));
3586 if (os_snprintf_error(end - pos, ret))
3587 return -1;
3588 pos += ret;
3589 }
3590 }
3591
3592 return pos - buf;
3593}
3594
3595
Hai Shalom021b0b52019-04-10 11:17:58 -07003596static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
3597 const char *field, char *buf,
3598 size_t buflen)
3599{
3600 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field);
3601
3602#ifdef CONFIG_DPP
3603 if (os_strcmp(field, "dpp") == 0) {
3604 int res;
3605
Hai Shaloma20dcd72022-02-04 13:43:00 -08003606#ifdef CONFIG_DPP3
3607 res = os_snprintf(buf, buflen, "DPP=3");
3608#elif defined(CONFIG_DPP2)
Hai Shalom021b0b52019-04-10 11:17:58 -07003609 res = os_snprintf(buf, buflen, "DPP=2");
3610#else /* CONFIG_DPP2 */
3611 res = os_snprintf(buf, buflen, "DPP=1");
3612#endif /* CONFIG_DPP2 */
3613 if (os_snprintf_error(buflen, res))
3614 return -1;
3615 return res;
3616 }
3617#endif /* CONFIG_DPP */
3618
3619 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
3620 field);
3621
3622 return -1;
3623}
3624
3625
Hai Shaloma20dcd72022-02-04 13:43:00 -08003626#ifdef ANDROID
3627static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd,
3628 char *buf, size_t buflen)
3629{
3630 int ret;
3631
3632 ret = hostapd_drv_driver_cmd(hapd, cmd, buf, buflen);
3633 if (ret == 0) {
3634 ret = os_snprintf(buf, buflen, "%s\n", "OK");
3635 if (os_snprintf_error(buflen, ret))
3636 ret = -1;
3637 }
3638 return ret;
3639}
3640#endif /* ANDROID */
3641
3642
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003643#ifdef CONFIG_IEEE80211BE
3644
3645static int hostapd_ctrl_iface_enable_mld(struct hostapd_iface *iface)
3646{
3647 unsigned int i;
3648
3649 if (!iface || !iface->bss[0]->conf->mld_ap) {
3650 wpa_printf(MSG_ERROR,
3651 "Trying to enable AP MLD on an interface that is not affiliated with an AP MLD");
3652 return -1;
3653 }
3654
3655 for (i = 0; i < iface->interfaces->count; ++i) {
3656 struct hostapd_iface *h_iface = iface->interfaces->iface[i];
3657 struct hostapd_data *h_hapd = h_iface->bss[0];
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003658
Sunil Ravi99c035e2024-07-12 01:42:03 +00003659 if (!hostapd_is_ml_partner(h_hapd, iface->bss[0]))
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003660 continue;
3661
3662 if (hostapd_enable_iface(h_iface)) {
3663 wpa_printf(MSG_ERROR, "Enabling of AP MLD failed");
3664 return -1;
3665 }
3666 }
3667 return 0;
3668}
3669
3670
3671static void hostapd_disable_iface_bss(struct hostapd_iface *iface)
3672{
3673 unsigned int i;
3674
3675 for (i = 0; i < iface->num_bss; i++)
3676 hostapd_bss_deinit_no_free(iface->bss[i]);
3677}
3678
3679
3680static int hostapd_ctrl_iface_disable_mld(struct hostapd_iface *iface)
3681{
3682 unsigned int i;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003683
3684 if (!iface || !iface->bss[0]->conf->mld_ap) {
3685 wpa_printf(MSG_ERROR,
3686 "Trying to disable AP MLD on an interface that is not affiliated with an AP MLD.");
3687 return -1;
3688 }
3689
3690 /* First, disable BSSs before stopping beaconing and doing driver
3691 * deinit so that the broadcast Deauthentication frames go out. */
3692
3693 for (i = 0; i < iface->interfaces->count; ++i) {
3694 struct hostapd_iface *h_iface = iface->interfaces->iface[i];
3695 struct hostapd_data *h_hapd = h_iface->bss[0];
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003696
Sunil Ravi99c035e2024-07-12 01:42:03 +00003697 if (!hostapd_is_ml_partner(h_hapd, iface->bss[0]))
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003698 continue;
3699
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003700 hostapd_disable_iface_bss(iface);
3701 }
3702
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003703 /* Then, fully disable interfaces */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003704 for (i = 0; i < iface->interfaces->count; ++i) {
3705 struct hostapd_iface *h_iface = iface->interfaces->iface[i];
3706 struct hostapd_data *h_hapd = h_iface->bss[0];
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003707
Sunil Ravi99c035e2024-07-12 01:42:03 +00003708 if (!hostapd_is_ml_partner(h_hapd, iface->bss[0]))
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003709 continue;
3710
3711 if (hostapd_disable_iface(h_iface)) {
3712 wpa_printf(MSG_ERROR, "Disabling AP MLD failed");
3713 return -1;
3714 }
3715 }
3716
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003717 return 0;
3718}
3719
3720
3721#ifdef CONFIG_TESTING_OPTIONS
3722static int hostapd_ctrl_iface_link_remove(struct hostapd_data *hapd, char *cmd,
3723 char *buf, size_t buflen)
3724{
3725 int ret;
3726 u32 count = atoi(cmd);
3727
3728 if (!count)
3729 count = 1;
3730
3731 ret = hostapd_link_remove(hapd, count);
3732 if (ret == 0) {
3733 ret = os_snprintf(buf, buflen, "%s\n", "OK");
3734 if (os_snprintf_error(buflen, ret))
3735 ret = -1;
3736 else
3737 ret = 0;
3738 }
3739
3740 return ret;
3741}
3742#endif /* CONFIG_TESTING_OPTIONS */
3743#endif /* CONFIG_IEEE80211BE */
3744
3745
3746#ifdef CONFIG_NAN_USD
3747
3748static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd,
3749 char *buf, size_t buflen)
3750{
3751 char *token, *context = NULL;
3752 int publish_id;
3753 struct nan_publish_params params;
3754 const char *service_name = NULL;
3755 struct wpabuf *ssi = NULL;
3756 int ret = -1;
3757 enum nan_service_protocol_type srv_proto_type = 0;
Sunil Ravic0f5d412024-09-11 22:12:49 +00003758 bool p2p = false;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003759
3760 os_memset(&params, 0, sizeof(params));
3761 /* USD shall use both solicited and unsolicited transmissions */
3762 params.unsolicited = true;
3763 params.solicited = true;
3764 /* USD shall require FSD without GAS */
3765 params.fsd = true;
3766
3767 while ((token = str_token(cmd, " ", &context))) {
3768 if (os_strncmp(token, "service_name=", 13) == 0) {
3769 service_name = token + 13;
3770 continue;
3771 }
3772
3773 if (os_strncmp(token, "ttl=", 4) == 0) {
3774 params.ttl = atoi(token + 4);
3775 continue;
3776 }
3777
3778 if (os_strncmp(token, "srv_proto_type=", 15) == 0) {
3779 srv_proto_type = atoi(token + 15);
3780 continue;
3781 }
3782
3783 if (os_strncmp(token, "ssi=", 4) == 0) {
3784 if (ssi)
3785 goto fail;
3786 ssi = wpabuf_parse_bin(token + 4);
3787 if (!ssi)
3788 goto fail;
3789 continue;
3790 }
3791
Sunil Ravic0f5d412024-09-11 22:12:49 +00003792 if (os_strcmp(token, "p2p=1") == 0) {
3793 p2p = true;
3794 continue;
3795 }
3796
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003797 if (os_strcmp(token, "solicited=0") == 0) {
3798 params.solicited = false;
3799 continue;
3800 }
3801
3802 if (os_strcmp(token, "unsolicited=0") == 0) {
3803 params.unsolicited = false;
3804 continue;
3805 }
3806
3807 if (os_strcmp(token, "fsd=0") == 0) {
3808 params.fsd = false;
3809 continue;
3810 }
3811
3812 wpa_printf(MSG_INFO, "CTRL: Invalid NAN_PUBLISH parameter: %s",
3813 token);
3814 goto fail;
3815 }
3816
3817 publish_id = hostapd_nan_usd_publish(hapd, service_name, srv_proto_type,
Sunil Ravic0f5d412024-09-11 22:12:49 +00003818 ssi, &params, p2p);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003819 if (publish_id > 0)
3820 ret = os_snprintf(buf, buflen, "%d", publish_id);
3821fail:
3822 wpabuf_free(ssi);
3823 return ret;
3824}
3825
3826
3827static int hostapd_ctrl_nan_cancel_publish(struct hostapd_data *hapd,
3828 char *cmd)
3829{
3830 char *token, *context = NULL;
3831 int publish_id = 0;
3832
3833 while ((token = str_token(cmd, " ", &context))) {
3834 if (sscanf(token, "publish_id=%i", &publish_id) == 1)
3835 continue;
3836 wpa_printf(MSG_INFO,
3837 "CTRL: Invalid NAN_CANCEL_PUBLISH parameter: %s",
3838 token);
3839 return -1;
3840 }
3841
3842 if (publish_id <= 0) {
3843 wpa_printf(MSG_INFO,
3844 "CTRL: Invalid or missing NAN_CANCEL_PUBLISH publish_id");
3845 return -1;
3846 }
3847
3848 hostapd_nan_usd_cancel_publish(hapd, publish_id);
3849 return 0;
3850}
3851
3852
3853static int hostapd_ctrl_nan_update_publish(struct hostapd_data *hapd,
3854 char *cmd)
3855{
3856 char *token, *context = NULL;
3857 int publish_id = 0;
3858 struct wpabuf *ssi = NULL;
3859 int ret = -1;
3860
3861 while ((token = str_token(cmd, " ", &context))) {
3862 if (sscanf(token, "publish_id=%i", &publish_id) == 1)
3863 continue;
3864 if (os_strncmp(token, "ssi=", 4) == 0) {
3865 if (ssi)
3866 goto fail;
3867 ssi = wpabuf_parse_bin(token + 4);
3868 if (!ssi)
3869 goto fail;
3870 continue;
3871 }
3872 wpa_printf(MSG_INFO,
3873 "CTRL: Invalid NAN_UPDATE_PUBLISH parameter: %s",
3874 token);
3875 goto fail;
3876 }
3877
3878 if (publish_id <= 0) {
3879 wpa_printf(MSG_INFO,
3880 "CTRL: Invalid or missing NAN_UPDATE_PUBLISH publish_id");
3881 goto fail;
3882 }
3883
3884 ret = hostapd_nan_usd_update_publish(hapd, publish_id, ssi);
3885fail:
3886 wpabuf_free(ssi);
3887 return ret;
3888}
3889
3890
3891static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd,
3892 char *buf, size_t buflen)
3893{
3894 char *token, *context = NULL;
3895 int subscribe_id;
3896 struct nan_subscribe_params params;
3897 const char *service_name = NULL;
3898 struct wpabuf *ssi = NULL;
3899 int ret = -1;
3900 enum nan_service_protocol_type srv_proto_type = 0;
Sunil Ravic0f5d412024-09-11 22:12:49 +00003901 bool p2p = false;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003902
3903 os_memset(&params, 0, sizeof(params));
3904
3905 while ((token = str_token(cmd, " ", &context))) {
3906 if (os_strncmp(token, "service_name=", 13) == 0) {
3907 service_name = token + 13;
3908 continue;
3909 }
3910
3911 if (os_strcmp(token, "active=1") == 0) {
3912 params.active = true;
3913 continue;
3914 }
3915
3916 if (os_strncmp(token, "ttl=", 4) == 0) {
3917 params.ttl = atoi(token + 4);
3918 continue;
3919 }
3920
3921 if (os_strncmp(token, "srv_proto_type=", 15) == 0) {
3922 srv_proto_type = atoi(token + 15);
3923 continue;
3924 }
3925
3926 if (os_strncmp(token, "ssi=", 4) == 0) {
3927 if (ssi)
3928 goto fail;
3929 ssi = wpabuf_parse_bin(token + 4);
3930 if (!ssi)
3931 goto fail;
3932 continue;
3933 }
3934
Sunil Ravic0f5d412024-09-11 22:12:49 +00003935 if (os_strcmp(token, "p2p=1") == 0) {
3936 p2p = true;
3937 continue;
3938 }
3939
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003940 wpa_printf(MSG_INFO,
3941 "CTRL: Invalid NAN_SUBSCRIBE parameter: %s",
3942 token);
3943 goto fail;
3944 }
3945
3946 subscribe_id = hostapd_nan_usd_subscribe(hapd, service_name,
3947 srv_proto_type, ssi,
Sunil Ravic0f5d412024-09-11 22:12:49 +00003948 &params, p2p);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00003949 if (subscribe_id > 0)
3950 ret = os_snprintf(buf, buflen, "%d", subscribe_id);
3951fail:
3952 wpabuf_free(ssi);
3953 return ret;
3954}
3955
3956
3957static int hostapd_ctrl_nan_cancel_subscribe(struct hostapd_data *hapd,
3958 char *cmd)
3959{
3960 char *token, *context = NULL;
3961 int subscribe_id = 0;
3962
3963 while ((token = str_token(cmd, " ", &context))) {
3964 if (sscanf(token, "subscribe_id=%i", &subscribe_id) == 1)
3965 continue;
3966 wpa_printf(MSG_INFO,
3967 "CTRL: Invalid NAN_CANCEL_SUBSCRIBE parameter: %s",
3968 token);
3969 return -1;
3970 }
3971
3972 if (subscribe_id <= 0) {
3973 wpa_printf(MSG_INFO,
3974 "CTRL: Invalid or missing NAN_CANCEL_SUBSCRIBE subscribe_id");
3975 return -1;
3976 }
3977
3978 hostapd_nan_usd_cancel_subscribe(hapd, subscribe_id);
3979 return 0;
3980}
3981
3982
3983static int hostapd_ctrl_nan_transmit(struct hostapd_data *hapd, char *cmd)
3984{
3985 char *token, *context = NULL;
3986 int handle = 0;
3987 int req_instance_id = 0;
3988 struct wpabuf *ssi = NULL;
3989 u8 peer_addr[ETH_ALEN];
3990 int ret = -1;
3991
3992 os_memset(peer_addr, 0, ETH_ALEN);
3993
3994 while ((token = str_token(cmd, " ", &context))) {
3995 if (sscanf(token, "handle=%i", &handle) == 1)
3996 continue;
3997
3998 if (sscanf(token, "req_instance_id=%i", &req_instance_id) == 1)
3999 continue;
4000
4001 if (os_strncmp(token, "address=", 8) == 0) {
4002 if (hwaddr_aton(token + 8, peer_addr) < 0)
4003 return -1;
4004 continue;
4005 }
4006
4007 if (os_strncmp(token, "ssi=", 4) == 0) {
4008 if (ssi)
4009 goto fail;
4010 ssi = wpabuf_parse_bin(token + 4);
4011 if (!ssi)
4012 goto fail;
4013 continue;
4014 }
4015
4016 wpa_printf(MSG_INFO,
4017 "CTRL: Invalid NAN_TRANSMIT parameter: %s",
4018 token);
4019 goto fail;
4020 }
4021
4022 if (handle <= 0) {
4023 wpa_printf(MSG_INFO,
4024 "CTRL: Invalid or missing NAN_TRANSMIT handle");
4025 goto fail;
4026 }
4027
4028 if (is_zero_ether_addr(peer_addr)) {
4029 wpa_printf(MSG_INFO,
4030 "CTRL: Invalid or missing NAN_TRANSMIT address");
4031 goto fail;
4032 }
4033
4034 ret = hostapd_nan_usd_transmit(hapd, handle, ssi, NULL, peer_addr,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004035 req_instance_id);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004036fail:
4037 wpabuf_free(ssi);
4038 return ret;
4039}
4040
4041#endif /* CONFIG_NAN_USD */
4042
4043
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004044static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
4045 char *buf, char *reply,
4046 int reply_size,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004047 struct sockaddr_storage *from,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004048 socklen_t fromlen)
4049{
4050 int reply_len, res;
4051
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004052 os_memcpy(reply, "OK\n", 3);
4053 reply_len = 3;
4054
4055 if (os_strcmp(buf, "PING") == 0) {
4056 os_memcpy(reply, "PONG\n", 5);
4057 reply_len = 5;
4058 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
4059 if (wpa_debug_reopen_file() < 0)
4060 reply_len = -1;
Sunil Ravi77d572f2023-01-17 23:58:31 +00004061 } else if (os_strcmp(buf, "CLOSE_LOG") == 0) {
4062 wpa_debug_stop_log();
Roshan Pius3a1667e2018-07-03 15:17:14 -07004063 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
4064 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004065 } else if (os_strcmp(buf, "STATUS") == 0) {
4066 reply_len = hostapd_ctrl_iface_status(hapd, reply,
4067 reply_size);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004068 } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
4069 reply_len = hostapd_drv_status(hapd, reply, reply_size);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004070 } else if (os_strcmp(buf, "MIB") == 0) {
4071 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
4072 if (reply_len >= 0) {
4073 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
4074 reply_size - reply_len);
4075 if (res < 0)
4076 reply_len = -1;
4077 else
4078 reply_len += res;
4079 }
4080 if (reply_len >= 0) {
4081 res = ieee802_1x_get_mib(hapd, reply + reply_len,
4082 reply_size - reply_len);
4083 if (res < 0)
4084 reply_len = -1;
4085 else
4086 reply_len += res;
4087 }
4088#ifndef CONFIG_NO_RADIUS
4089 if (reply_len >= 0) {
4090 res = radius_client_get_mib(hapd->radius,
4091 reply + reply_len,
4092 reply_size - reply_len);
4093 if (res < 0)
4094 reply_len = -1;
4095 else
4096 reply_len += res;
4097 }
4098#endif /* CONFIG_NO_RADIUS */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004099 } else if (os_strncmp(buf, "MIB ", 4) == 0) {
4100 reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
4101 buf + 4);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004102 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
4103 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
4104 reply_size);
4105 } else if (os_strncmp(buf, "STA ", 4) == 0) {
4106 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
4107 reply_size);
4108 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
4109 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
4110 reply_size);
4111 } else if (os_strcmp(buf, "ATTACH") == 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004112 if (hostapd_ctrl_iface_attach(hapd, from, fromlen, NULL))
4113 reply_len = -1;
4114 } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
4115 if (hostapd_ctrl_iface_attach(hapd, from, fromlen, buf + 7))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004116 reply_len = -1;
4117 } else if (os_strcmp(buf, "DETACH") == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004118 if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004119 reply_len = -1;
4120 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004121 if (hostapd_ctrl_iface_level(hapd, from, fromlen,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004122 buf + 6))
4123 reply_len = -1;
4124 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
4125 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
4126 reply_len = -1;
4127 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
4128 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
4129 reply_len = -1;
4130 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
4131 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
4132 reply_len = -1;
Dmitry Shmidtaca489e2016-09-28 15:44:14 -07004133#ifdef CONFIG_TAXONOMY
4134 } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) {
4135 reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10,
4136 reply, reply_size);
4137#endif /* CONFIG_TAXONOMY */
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004138 } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
4139 if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
4140 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004141 } else if (os_strcmp(buf, "STOP_AP") == 0) {
4142 if (hostapd_ctrl_iface_stop_ap(hapd))
4143 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004144#ifdef NEED_AP_MLME
4145 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
4146 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
4147 reply_len = -1;
4148#endif /* NEED_AP_MLME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004149#ifdef CONFIG_WPS
4150 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
4151 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
4152 reply_len = -1;
4153 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
4154 reply_len = hostapd_ctrl_iface_wps_check_pin(
4155 hapd, buf + 14, reply, reply_size);
4156 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
4157 if (hostapd_wps_button_pushed(hapd, NULL))
4158 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004159 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
4160 if (hostapd_wps_cancel(hapd))
4161 reply_len = -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004162 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
4163 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
4164 reply, reply_size);
4165 } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
4166 if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
4167 reply_len = -1;
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07004168 } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
4169 reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
4170 reply_size);
Dmitry Shmidt04949592012-07-19 12:16:46 -07004171#ifdef CONFIG_WPS_NFC
4172 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
4173 if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
4174 reply_len = -1;
4175 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
4176 reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
4177 hapd, buf + 21, reply, reply_size);
4178 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
4179 reply_len = hostapd_ctrl_iface_wps_nfc_token(
4180 hapd, buf + 14, reply, reply_size);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004181 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
4182 reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
4183 hapd, buf + 21, reply, reply_size);
4184 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
4185 if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
4186 reply_len = -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07004187#endif /* CONFIG_WPS_NFC */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004188#endif /* CONFIG_WPS */
Dmitry Shmidt051af732013-10-22 13:52:46 -07004189#ifdef CONFIG_INTERWORKING
4190 } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
4191 if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
4192 reply_len = -1;
4193 } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
4194 if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
4195 reply_len = -1;
4196#endif /* CONFIG_INTERWORKING */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004197#ifdef CONFIG_HS20
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08004198 } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
4199 if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
4200 reply_len = -1;
4201#endif /* CONFIG_HS20 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004202#ifdef CONFIG_WNM_AP
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08004203 } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
4204 if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
4205 reply_len = -1;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08004206 } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
4207 if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
4208 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004209 } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
4210 if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
4211 reply_len = -1;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08004212 } else if (os_strncmp(buf, "COLOC_INTF_REQ ", 15) == 0) {
4213 if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
4214 reply_len = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004215#endif /* CONFIG_WNM_AP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004216 } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
4217 reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
4218 reply_size);
4219 } else if (os_strncmp(buf, "SET ", 4) == 0) {
4220 if (hostapd_ctrl_iface_set(hapd, buf + 4))
4221 reply_len = -1;
4222 } else if (os_strncmp(buf, "GET ", 4) == 0) {
4223 reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
4224 reply_size);
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004225 } else if (os_strcmp(buf, "ENABLE") == 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004226 if (hostapd_ctrl_iface_enable(hapd->iface))
4227 reply_len = -1;
Hai Shalom74f70d42019-02-11 14:42:39 -08004228 } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) {
4229 if (hostapd_ctrl_iface_reload_wpa_psk(hapd))
4230 reply_len = -1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004231#ifdef CONFIG_IEEE80211R_AP
4232 } else if (os_strcmp(buf, "GET_RXKHS") == 0) {
4233 reply_len = hostapd_ctrl_iface_get_rxkhs(hapd, reply,
4234 reply_size);
4235 } else if (os_strcmp(buf, "RELOAD_RXKHS") == 0) {
4236 if (hostapd_ctrl_iface_reload_rxkhs(hapd))
4237 reply_len = -1;
4238#endif /* CONFIG_IEEE80211R_AP */
Sunil Ravi77d572f2023-01-17 23:58:31 +00004239 } else if (os_strcmp(buf, "RELOAD_BSS") == 0) {
4240 if (hostapd_ctrl_iface_reload_bss(hapd))
4241 reply_len = -1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004242 } else if (os_strcmp(buf, "RELOAD_CONFIG") == 0) {
4243 if (hostapd_reload_config(hapd->iface))
4244 reply_len = -1;
4245 } else if (os_strcmp(buf, "RELOAD") == 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004246 if (hostapd_ctrl_iface_reload(hapd->iface))
4247 reply_len = -1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004248 } else if (os_strcmp(buf, "DISABLE") == 0) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07004249 if (hostapd_ctrl_iface_disable(hapd->iface))
4250 reply_len = -1;
Dmitry Shmidt7f656022015-02-25 14:36:37 -08004251 } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
4252 if (ieee802_11_set_beacon(hapd))
4253 reply_len = -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004254#ifdef CONFIG_TESTING_OPTIONS
4255 } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
4256 if (hostapd_ctrl_iface_radar(hapd, buf + 6))
4257 reply_len = -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08004258 } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
4259 if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
4260 reply_len = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004261 } else if (os_strncmp(buf, "MGMT_TX_STATUS_PROCESS ", 23) == 0) {
4262 if (hostapd_ctrl_iface_mgmt_tx_status_process(hapd,
4263 buf + 23) < 0)
4264 reply_len = -1;
Dmitry Shmidtabb90a32016-12-05 15:34:39 -08004265 } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
4266 if (hostapd_ctrl_iface_mgmt_rx_process(hapd, buf + 16) < 0)
4267 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004268 } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
4269 if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
4270 reply_len = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004271 } else if (os_strncmp(buf, "EAPOL_TX ", 9) == 0) {
4272 if (hostapd_ctrl_iface_eapol_tx(hapd, buf + 9) < 0)
4273 reply_len = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004274 } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
4275 if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
4276 reply_len = -1;
4277 } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
4278 if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
4279 reply_len = -1;
4280 } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
4281 if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
4282 reply_len = -1;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004283 } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004284 if (testing_set_fail_pattern(true, buf + 16) < 0)
Dmitry Shmidtff787d52015-01-12 13:01:47 -08004285 reply_len = -1;
4286 } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004287 reply_len = testing_get_fail_pattern(true, reply, reply_size);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004288 } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004289 if (testing_set_fail_pattern(false, buf + 10) < 0)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004290 reply_len = -1;
4291 } else if (os_strcmp(buf, "GET_FAIL") == 0) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004292 reply_len = testing_get_fail_pattern(false, reply, reply_size);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004293 } else if (os_strncmp(buf, "RESET_PN ", 9) == 0) {
4294 if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 0)
4295 reply_len = -1;
4296 } else if (os_strncmp(buf, "SET_KEY ", 8) == 0) {
4297 if (hostapd_ctrl_set_key(hapd, buf + 8) < 0)
4298 reply_len = -1;
4299 } else if (os_strncmp(buf, "RESEND_M1 ", 10) == 0) {
4300 if (hostapd_ctrl_resend_m1(hapd, buf + 10) < 0)
4301 reply_len = -1;
4302 } else if (os_strncmp(buf, "RESEND_M3 ", 10) == 0) {
4303 if (hostapd_ctrl_resend_m3(hapd, buf + 10) < 0)
4304 reply_len = -1;
4305 } else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) {
4306 if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0)
4307 reply_len = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004308 } else if (os_strncmp(buf, "REKEY_PTK ", 10) == 0) {
4309 if (hostapd_ctrl_rekey_ptk(hapd, buf + 10) < 0)
4310 reply_len = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004311 } else if (os_strcmp(buf, "REKEY_GTK") == 0) {
4312 if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0)
4313 reply_len = -1;
Hai Shalomfdcde762020-04-02 11:19:20 -07004314 } else if (os_strncmp(buf, "GET_PMK ", 8) == 0) {
4315 reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply,
4316 reply_size);
Hai Shaloma20dcd72022-02-04 13:43:00 -08004317 } else if (os_strncmp(buf, "REGISTER_FRAME ", 15) == 0) {
4318 if (hostapd_ctrl_register_frame(hapd, buf + 16) < 0)
4319 reply_len = -1;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08004320#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004321 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
Dmitry Shmidtd30ac602014-06-30 09:54:22 -07004322 if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
Dmitry Shmidte0e48dc2013-11-18 12:00:06 -08004323 reply_len = -1;
Sunil Ravi7f769292024-07-23 22:21:32 +00004324#ifdef CONFIG_IEEE80211AX
4325 } else if (os_strncmp(buf, "COLOR_CHANGE ", 13) == 0) {
4326 if (hostapd_ctrl_iface_color_change(hapd->iface, buf + 13))
4327 reply_len = -1;
4328#endif /* CONFIG_IEEE80211AX */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00004329 } else if (os_strncmp(buf, "NOTIFY_CW_CHANGE ", 17) == 0) {
4330 if (hostapd_ctrl_iface_notify_cw_change(hapd, buf + 17))
4331 reply_len = -1;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07004332 } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
4333 reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
4334 reply_size);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004335 } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
4336 ieee802_1x_erp_flush(hapd);
4337#ifdef RADIUS_SERVER
4338 radius_server_erp_flush(hapd->radius_srv);
4339#endif /* RADIUS_SERVER */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004340 } else if (os_strncmp(buf, "EAPOL_REAUTH ", 13) == 0) {
4341 if (hostapd_ctrl_iface_eapol_reauth(hapd, buf + 13))
4342 reply_len = -1;
4343 } else if (os_strncmp(buf, "EAPOL_SET ", 10) == 0) {
4344 if (hostapd_ctrl_iface_eapol_set(hapd, buf + 10))
4345 reply_len = -1;
4346 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
4347 reply_len = hostapd_ctrl_iface_log_level(
4348 hapd, buf + 9, reply, reply_size);
4349#ifdef NEED_AP_MLME
4350 } else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
4351 reply_len = hostapd_ctrl_iface_track_sta_list(
4352 hapd, reply, reply_size);
Sunil Ravi79e6c4f2025-01-04 00:47:06 +00004353 } else if (os_strcmp(buf, "DUMP_BEACON") == 0) {
4354 reply_len = hostapd_ctrl_iface_dump_beacon(hapd, reply,
4355 reply_size);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004356#endif /* NEED_AP_MLME */
Dmitry Shmidte4663042016-04-04 10:07:49 -07004357 } else if (os_strcmp(buf, "PMKSA") == 0) {
4358 reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
4359 reply_size);
4360 } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
4361 hostapd_ctrl_iface_pmksa_flush(hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004362 } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
4363 if (hostapd_ctrl_iface_pmksa_add(hapd, buf + 10) < 0)
4364 reply_len = -1;
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004365 } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
4366 if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
4367 reply_len = -1;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004368 } else if (os_strcmp(buf, "SHOW_NEIGHBOR") == 0) {
4369 reply_len = hostapd_ctrl_iface_show_neighbor(hapd, reply,
4370 reply_size);
Dmitry Shmidt849734c2016-05-27 09:59:01 -07004371 } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
4372 if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
4373 reply_len = -1;
4374 } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
4375 if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
4376 reply_len = -1;
4377 } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
4378 if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
4379 reply_len = -1;
Dmitry Shmidt29333592017-01-09 12:27:11 -08004380 } else if (os_strncmp(buf, "REQ_BEACON ", 11) == 0) {
4381 reply_len = hostapd_ctrl_iface_req_beacon(hapd, buf + 11,
4382 reply, reply_size);
Sunil Ravi99c035e2024-07-12 01:42:03 +00004383 } else if (os_strncmp(buf, "REQ_LINK_MEASUREMENT ", 21) == 0) {
4384 reply_len = hostapd_ctrl_iface_req_link_measurement(
4385 hapd, buf + 21, reply, reply_size);
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07004386 } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
4387 reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
4388 reply_size);
Hai Shalomb755a2a2020-04-23 21:49:02 -07004389 } else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
4390 reply_len = hostapd_ctrl_driver_flags2(hapd->iface, reply,
4391 reply_size);
Dmitry Shmidt29333592017-01-09 12:27:11 -08004392 } else if (os_strcmp(buf, "TERMINATE") == 0) {
4393 eloop_terminate();
Roshan Pius3a1667e2018-07-03 15:17:14 -07004394 } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
4395 if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
Hai Shalom60840252021-02-19 19:02:11 -08004396 if (hostapd_ctrl_iface_acl_add_mac(
4397 &hapd->conf->accept_mac,
Sunil Ravia04bd252022-05-02 22:54:18 -07004398 &hapd->conf->num_accept_mac, buf + 19) ||
4399 hostapd_set_acl(hapd))
Hai Shalom60840252021-02-19 19:02:11 -08004400 reply_len = -1;
4401 } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
Sunil Ravia04bd252022-05-02 22:54:18 -07004402 if (hostapd_ctrl_iface_acl_del_mac(
Roshan Pius3a1667e2018-07-03 15:17:14 -07004403 &hapd->conf->accept_mac,
Sunil Ravia04bd252022-05-02 22:54:18 -07004404 &hapd->conf->num_accept_mac, buf + 19) ||
4405 hostapd_set_acl(hapd) ||
4406 hostapd_disassoc_accept_mac(hapd))
Roshan Pius3a1667e2018-07-03 15:17:14 -07004407 reply_len = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004408 } else if (os_strcmp(buf + 11, "SHOW") == 0) {
4409 reply_len = hostapd_ctrl_iface_acl_show_mac(
4410 hapd->conf->accept_mac,
4411 hapd->conf->num_accept_mac, reply, reply_size);
4412 } else if (os_strcmp(buf + 11, "CLEAR") == 0) {
4413 hostapd_ctrl_iface_acl_clear_list(
4414 &hapd->conf->accept_mac,
4415 &hapd->conf->num_accept_mac);
Sunil Ravia04bd252022-05-02 22:54:18 -07004416 if (hostapd_set_acl(hapd) ||
4417 hostapd_disassoc_accept_mac(hapd))
4418 reply_len = -1;
Sunil Ravi036cec52023-03-29 11:35:17 -07004419 } else {
4420 reply_len = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004421 }
4422 } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
4423 if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
Sunil Ravia04bd252022-05-02 22:54:18 -07004424 if (hostapd_ctrl_iface_acl_add_mac(
Roshan Pius3a1667e2018-07-03 15:17:14 -07004425 &hapd->conf->deny_mac,
Sunil Ravia04bd252022-05-02 22:54:18 -07004426 &hapd->conf->num_deny_mac, buf + 17) ||
4427 hostapd_set_acl(hapd) ||
4428 hostapd_disassoc_deny_mac(hapd))
Hai Shalom60840252021-02-19 19:02:11 -08004429 reply_len = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004430 } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
Hai Shalom60840252021-02-19 19:02:11 -08004431 if (hostapd_ctrl_iface_acl_del_mac(
4432 &hapd->conf->deny_mac,
Sunil Ravia04bd252022-05-02 22:54:18 -07004433 &hapd->conf->num_deny_mac, buf + 17) ||
4434 hostapd_set_acl(hapd))
Hai Shalom60840252021-02-19 19:02:11 -08004435 reply_len = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004436 } else if (os_strcmp(buf + 9, "SHOW") == 0) {
4437 reply_len = hostapd_ctrl_iface_acl_show_mac(
4438 hapd->conf->deny_mac,
4439 hapd->conf->num_deny_mac, reply, reply_size);
4440 } else if (os_strcmp(buf + 9, "CLEAR") == 0) {
4441 hostapd_ctrl_iface_acl_clear_list(
4442 &hapd->conf->deny_mac,
4443 &hapd->conf->num_deny_mac);
Sunil Ravia04bd252022-05-02 22:54:18 -07004444 if (hostapd_set_acl(hapd))
4445 reply_len = -1;
Sunil Ravi036cec52023-03-29 11:35:17 -07004446 } else {
4447 reply_len = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004448 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004449#ifdef CONFIG_DPP
4450 } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
4451 res = hostapd_dpp_qr_code(hapd, buf + 12);
4452 if (res < 0) {
4453 reply_len = -1;
4454 } else {
4455 reply_len = os_snprintf(reply, reply_size, "%d", res);
4456 if (os_snprintf_error(reply_size, reply_len))
4457 reply_len = -1;
4458 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004459 } else if (os_strncmp(buf, "DPP_NFC_URI ", 12) == 0) {
4460 res = hostapd_dpp_nfc_uri(hapd, buf + 12);
4461 if (res < 0) {
4462 reply_len = -1;
4463 } else {
4464 reply_len = os_snprintf(reply, reply_size, "%d", res);
4465 if (os_snprintf_error(reply_size, reply_len))
4466 reply_len = -1;
4467 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004468 } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) {
4469 res = hostapd_dpp_nfc_handover_req(hapd, buf + 20);
4470 if (res < 0) {
4471 reply_len = -1;
4472 } else {
4473 reply_len = os_snprintf(reply, reply_size, "%d", res);
4474 if (os_snprintf_error(reply_size, reply_len))
4475 reply_len = -1;
4476 }
4477 } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) {
4478 res = hostapd_dpp_nfc_handover_sel(hapd, buf + 20);
4479 if (res < 0) {
4480 reply_len = -1;
4481 } else {
4482 reply_len = os_snprintf(reply, reply_size, "%d", res);
4483 if (os_snprintf_error(reply_size, reply_len))
4484 reply_len = -1;
4485 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004486 } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004487 res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004488 if (res < 0) {
4489 reply_len = -1;
4490 } else {
4491 reply_len = os_snprintf(reply, reply_size, "%d", res);
4492 if (os_snprintf_error(reply_size, reply_len))
4493 reply_len = -1;
4494 }
4495 } else if (os_strncmp(buf, "DPP_BOOTSTRAP_REMOVE ", 21) == 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004496 if (dpp_bootstrap_remove(hapd->iface->interfaces->dpp,
4497 buf + 21) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004498 reply_len = -1;
4499 } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GET_URI ", 22) == 0) {
4500 const char *uri;
4501
Hai Shalom021b0b52019-04-10 11:17:58 -07004502 uri = dpp_bootstrap_get_uri(hapd->iface->interfaces->dpp,
4503 atoi(buf + 22));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004504 if (!uri) {
4505 reply_len = -1;
4506 } else {
4507 reply_len = os_snprintf(reply, reply_size, "%s", uri);
4508 if (os_snprintf_error(reply_size, reply_len))
4509 reply_len = -1;
4510 }
4511 } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004512 reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
4513 atoi(buf + 19),
4514 reply, reply_size);
Hai Shalomfdcde762020-04-02 11:19:20 -07004515 } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
4516 if (dpp_bootstrap_set(hapd->iface->interfaces->dpp,
4517 atoi(buf + 18),
4518 os_strchr(buf + 18, ' ')) < 0)
4519 reply_len = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004520 } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
4521 if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
4522 reply_len = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004523 } else if (os_strncmp(buf, "DPP_LISTEN ", 11) == 0) {
4524 if (hostapd_dpp_listen(hapd, buf + 11) < 0)
4525 reply_len = -1;
4526 } else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
4527 hostapd_dpp_stop(hapd);
4528 hostapd_dpp_listen_stop(hapd);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004529 } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004530 res = dpp_configurator_add(hapd->iface->interfaces->dpp,
4531 buf + 20);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004532 if (res < 0) {
4533 reply_len = -1;
4534 } else {
4535 reply_len = os_snprintf(reply, reply_size, "%d", res);
4536 if (os_snprintf_error(reply_size, reply_len))
4537 reply_len = -1;
4538 }
Sunil Ravia04bd252022-05-02 22:54:18 -07004539 } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) {
4540 if (dpp_configurator_set(hapd->iface->interfaces->dpp,
4541 buf + 20) < 0)
4542 reply_len = -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004543 } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004544 if (dpp_configurator_remove(hapd->iface->interfaces->dpp,
4545 buf + 24) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004546 reply_len = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004547 } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08004548 if (hostapd_dpp_configurator_sign(hapd, buf + 21) < 0)
Roshan Pius3a1667e2018-07-03 15:17:14 -07004549 reply_len = -1;
4550 } else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
Hai Shalom021b0b52019-04-10 11:17:58 -07004551 reply_len = dpp_configurator_get_key_id(
4552 hapd->iface->interfaces->dpp,
4553 atoi(buf + 25),
4554 reply, reply_size);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004555 } else if (os_strncmp(buf, "DPP_PKEX_ADD ", 13) == 0) {
4556 res = hostapd_dpp_pkex_add(hapd, buf + 12);
4557 if (res < 0) {
4558 reply_len = -1;
4559 } else {
4560 reply_len = os_snprintf(reply, reply_size, "%d", res);
4561 if (os_snprintf_error(reply_size, reply_len))
4562 reply_len = -1;
4563 }
4564 } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
4565 if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
4566 reply_len = -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004567#ifdef CONFIG_DPP2
Hai Shalom899fcc72020-10-19 14:38:18 -07004568 } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
4569 if (hostapd_dpp_controller_start(hapd, buf + 20) < 0)
4570 reply_len = -1;
4571 } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
4572 if (hostapd_dpp_controller_start(hapd, NULL) < 0)
4573 reply_len = -1;
4574 } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
4575 dpp_controller_stop(hapd->iface->interfaces->dpp);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004576 } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
4577 if (hostapd_dpp_chirp(hapd, buf + 9) < 0)
4578 reply_len = -1;
4579 } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
4580 hostapd_dpp_chirp_stop(hapd);
Sunil Ravi89eba102022-09-13 21:04:37 -07004581 } else if (os_strncmp(buf, "DPP_RELAY_ADD_CONTROLLER ", 25) == 0) {
4582 if (hostapd_dpp_add_controller(hapd, buf + 25) < 0)
4583 reply_len = -1;
4584 } else if (os_strncmp(buf, "DPP_RELAY_REMOVE_CONTROLLER ", 28) == 0) {
4585 hostapd_dpp_remove_controller(hapd, buf + 28);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004586#endif /* CONFIG_DPP2 */
Sunil Ravi89eba102022-09-13 21:04:37 -07004587#ifdef CONFIG_DPP3
4588 } else if (os_strcmp(buf, "DPP_PUSH_BUTTON") == 0) {
4589 if (hostapd_dpp_push_button(hapd, NULL) < 0)
4590 reply_len = -1;
4591 } else if (os_strncmp(buf, "DPP_PUSH_BUTTON ", 16) == 0) {
4592 if (hostapd_dpp_push_button(hapd, buf + 15) < 0)
4593 reply_len = -1;
4594#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004595#endif /* CONFIG_DPP */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004596#ifdef CONFIG_NAN_USD
4597 } else if (os_strncmp(buf, "NAN_PUBLISH ", 12) == 0) {
4598 reply_len = hostapd_ctrl_nan_publish(hapd, buf + 12, reply,
4599 reply_size);
4600 } else if (os_strncmp(buf, "NAN_CANCEL_PUBLISH ", 19) == 0) {
4601 if (hostapd_ctrl_nan_cancel_publish(hapd, buf + 19) < 0)
4602 reply_len = -1;
4603 } else if (os_strncmp(buf, "NAN_UPDATE_PUBLISH ", 19) == 0) {
4604 if (hostapd_ctrl_nan_update_publish(hapd, buf + 19) < 0)
4605 reply_len = -1;
4606 } else if (os_strncmp(buf, "NAN_SUBSCRIBE ", 14) == 0) {
4607 reply_len = hostapd_ctrl_nan_subscribe(hapd, buf + 14, reply,
4608 reply_size);
4609 } else if (os_strncmp(buf, "NAN_CANCEL_SUBSCRIBE ", 21) == 0) {
4610 if (hostapd_ctrl_nan_cancel_subscribe(hapd, buf + 21) < 0)
4611 reply_len = -1;
4612 } else if (os_strncmp(buf, "NAN_TRANSMIT ", 13) == 0) {
4613 if (hostapd_ctrl_nan_transmit(hapd, buf + 13) < 0)
4614 reply_len = -1;
4615#endif /* CONFIG_NAN_USD */
Roshan Pius3a1667e2018-07-03 15:17:14 -07004616#ifdef RADIUS_SERVER
4617 } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
4618 if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
4619 reply_len = -1;
4620#endif /* RADIUS_SERVER */
Hai Shalom021b0b52019-04-10 11:17:58 -07004621 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
4622 reply_len = hostapd_ctrl_iface_get_capability(
4623 hapd, buf + 15, reply, reply_size);
Hai Shalom60840252021-02-19 19:02:11 -08004624#ifdef CONFIG_PASN
4625 } else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) {
4626 reply_len = ptksa_cache_list(hapd->ptksa, reply, reply_size);
4627#endif /* CONFIG_PASN */
Hai Shaloma20dcd72022-02-04 13:43:00 -08004628#ifdef ANDROID
4629 } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
4630 reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply,
4631 reply_size);
4632#endif /* ANDROID */
Sunil Ravib0ac25f2024-07-12 01:42:03 +00004633#ifdef CONFIG_IEEE80211BE
4634 } else if (os_strcmp(buf, "ENABLE_MLD") == 0) {
4635 if (hostapd_ctrl_iface_enable_mld(hapd->iface))
4636 reply_len = -1;
4637 } else if (os_strcmp(buf, "DISABLE_MLD") == 0) {
4638 if (hostapd_ctrl_iface_disable_mld(hapd->iface))
4639 reply_len = -1;
4640#ifdef CONFIG_TESTING_OPTIONS
4641 } else if (os_strncmp(buf, "LINK_REMOVE ", 12) == 0) {
4642 if (hostapd_ctrl_iface_link_remove(hapd, buf + 12,
4643 reply, reply_size))
4644 reply_len = -1;
4645#endif /* CONFIG_TESTING_OPTIONS */
4646#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004647 } else {
4648 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
4649 reply_len = 16;
4650 }
4651
4652 if (reply_len < 0) {
4653 os_memcpy(reply, "FAIL\n", 5);
4654 reply_len = 5;
4655 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004656
4657 return reply_len;
4658}
4659
4660
4661static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
4662 void *sock_ctx)
4663{
4664 struct hostapd_data *hapd = eloop_ctx;
4665 char buf[4096];
4666 int res;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004667 struct sockaddr_storage from;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004668 socklen_t fromlen = sizeof(from);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004669 char *reply, *pos = buf;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004670 const int reply_size = 4096;
4671 int reply_len;
4672 int level = MSG_DEBUG;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004673#ifdef CONFIG_CTRL_IFACE_UDP
Hai Shalomfdcde762020-04-02 11:19:20 -07004674 unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004675#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004676
4677 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
4678 (struct sockaddr *) &from, &fromlen);
4679 if (res < 0) {
4680 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
4681 strerror(errno));
4682 return;
4683 }
4684 buf[res] = '\0';
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004685
4686 reply = os_malloc(reply_size);
4687 if (reply == NULL) {
4688 if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
4689 fromlen) < 0) {
4690 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
4691 strerror(errno));
4692 }
4693 return;
4694 }
4695
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004696#ifdef CONFIG_CTRL_IFACE_UDP
4697 if (os_strcmp(buf, "GET_COOKIE") == 0) {
4698 os_memcpy(reply, "COOKIE=", 7);
Hai Shalomfdcde762020-04-02 11:19:20 -07004699 wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
4700 hapd->ctrl_iface_cookie,
4701 CTRL_IFACE_COOKIE_LEN);
4702 reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004703 goto done;
4704 }
4705
4706 if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004707 hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004708 wpa_printf(MSG_DEBUG,
4709 "CTRL: No cookie in the request - drop request");
4710 os_free(reply);
4711 return;
4712 }
4713
Hai Shalomfdcde762020-04-02 11:19:20 -07004714 if (os_memcmp(hapd->ctrl_iface_cookie, lcookie,
4715 CTRL_IFACE_COOKIE_LEN) != 0) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004716 wpa_printf(MSG_DEBUG,
4717 "CTRL: Invalid cookie in the request - drop request");
4718 os_free(reply);
4719 return;
4720 }
4721
Hai Shalomfdcde762020-04-02 11:19:20 -07004722 pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004723 while (*pos == ' ')
4724 pos++;
4725#endif /* CONFIG_CTRL_IFACE_UDP */
4726
4727 if (os_strcmp(pos, "PING") == 0)
4728 level = MSG_EXCESSIVE;
4729 wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
4730
4731 reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08004732 reply, reply_size,
4733 &from, fromlen);
4734
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08004735#ifdef CONFIG_CTRL_IFACE_UDP
4736done:
4737#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08004738 if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
4739 fromlen) < 0) {
4740 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
4741 strerror(errno));
4742 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004743 os_free(reply);
4744}
4745
4746
Sunil Ravic0f5d412024-09-11 22:12:49 +00004747#ifdef CONFIG_IEEE80211BE
4748#ifndef CONFIG_CTRL_IFACE_UDP
4749
4750static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld,
4751 char *buf, char *reply,
4752 size_t reply_size,
4753 struct sockaddr_storage *from,
4754 socklen_t fromlen)
4755{
4756 struct hostapd_data *link_hapd, *link_itr;
4757 int reply_len = -1, link_id = -1;
4758 char *cmd;
4759 bool found = false;
4760
4761 os_memcpy(reply, "OK\n", 3);
4762 reply_len = 3;
4763
4764 cmd = buf;
4765
4766 /* Check whether the link ID is provided in the command */
4767 if (os_strncmp(cmd, "LINKID ", 7) == 0) {
4768 cmd += 7;
4769 link_id = atoi(cmd);
4770 if (link_id < 0 || link_id >= 15) {
4771 os_memcpy(reply, "INVALID LINK ID\n", 16);
4772 reply_len = 16;
4773 goto out;
4774 }
4775
4776 cmd = os_strchr(cmd, ' ');
4777 if (!cmd)
4778 goto out;
4779 cmd++;
4780 }
4781 if (link_id >= 0) {
4782 link_hapd = mld->fbss;
4783 if (!link_hapd) {
4784 os_memcpy(reply, "NO LINKS ACTIVE\n", 16);
4785 reply_len = 16;
4786 goto out;
4787 }
4788
4789 for_each_mld_link(link_itr, link_hapd) {
4790 if (link_itr->mld_link_id == link_id) {
4791 found = true;
4792 break;
4793 }
4794 }
4795
4796 if (!found)
4797 goto out;
4798
4799 link_hapd = link_itr;
4800 } else {
4801 link_hapd = mld->fbss;
4802 }
4803
4804 if (os_strcmp(cmd, "PING") == 0) {
4805 os_memcpy(reply, "PONG\n", 5);
4806 reply_len = 5;
4807 } else if (os_strcmp(cmd, "ATTACH") == 0) {
4808 if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, NULL))
4809 reply_len = -1;
4810 } else if (os_strncmp(cmd, "ATTACH ", 7) == 0) {
4811 if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, cmd + 7))
4812 reply_len = -1;
4813 } else if (os_strcmp(cmd, "DETACH") == 0) {
4814 if (ctrl_iface_detach(&mld->ctrl_dst, from, fromlen))
4815 reply_len = -1;
4816 } else {
4817 if (link_id == -1)
4818 wpa_printf(MSG_DEBUG,
4819 "Link ID not provided, using the first link BSS (if available)");
4820
4821 if (!link_hapd)
4822 reply_len = -1;
4823 else
4824 reply_len =
4825 hostapd_ctrl_iface_receive_process(
4826 link_hapd, cmd, reply, reply_size,
4827 from, fromlen);
4828 }
4829
4830out:
4831 if (reply_len < 0) {
4832 os_memcpy(reply, "FAIL\n", 5);
4833 reply_len = 5;
4834 }
4835
4836 return reply_len;
4837}
4838
4839
4840static void hostapd_mld_ctrl_iface_receive(int sock, void *eloop_ctx,
4841 void *sock_ctx)
4842{
4843 struct hostapd_mld *mld = eloop_ctx;
4844 char buf[4096];
4845 int res;
4846 struct sockaddr_storage from;
4847 socklen_t fromlen = sizeof(from);
4848 char *reply, *pos = buf;
4849 const size_t reply_size = 4096;
4850 int reply_len;
4851 int level = MSG_DEBUG;
4852
4853 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
4854 (struct sockaddr *) &from, &fromlen);
4855 if (res < 0) {
4856 wpa_printf(MSG_ERROR, "recvfrom(mld ctrl_iface): %s",
4857 strerror(errno));
4858 return;
4859 }
4860 buf[res] = '\0';
4861
4862 reply = os_malloc(reply_size);
4863 if (!reply) {
4864 if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
4865 fromlen) < 0) {
4866 wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s",
4867 strerror(errno));
4868 }
4869 return;
4870 }
4871
4872 if (os_strcmp(pos, "PING") == 0)
4873 level = MSG_EXCESSIVE;
4874
4875 wpa_hexdump_ascii(level, "RX MLD ctrl_iface", pos, res);
4876
4877 reply_len = hostapd_mld_ctrl_iface_receive_process(mld, pos,
4878 reply, reply_size,
4879 &from, fromlen);
4880
4881 if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
4882 fromlen) < 0) {
4883 wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s",
4884 strerror(errno));
4885 }
4886 os_free(reply);
4887}
4888
4889
4890static char * hostapd_mld_ctrl_iface_path(struct hostapd_mld *mld)
4891{
4892 size_t len;
4893 char *buf;
4894 int ret;
4895
4896 if (!mld->ctrl_interface)
4897 return NULL;
4898
4899 len = os_strlen(mld->ctrl_interface) + os_strlen(mld->name) + 2;
4900
4901 buf = os_malloc(len);
4902 if (!buf)
4903 return NULL;
4904
4905 ret = os_snprintf(buf, len, "%s/%s", mld->ctrl_interface, mld->name);
4906 if (os_snprintf_error(len, ret)) {
4907 os_free(buf);
4908 return NULL;
4909 }
4910
4911 return buf;
4912}
4913
4914#endif /* !CONFIG_CTRL_IFACE_UDP */
4915
4916
4917int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld)
4918{
4919#ifndef CONFIG_CTRL_IFACE_UDP
4920 struct sockaddr_un addr;
4921 int s = -1;
4922 char *fname = NULL;
4923
4924 if (!mld)
4925 return -1;
4926
4927 if (mld->ctrl_sock > -1) {
4928 wpa_printf(MSG_DEBUG, "MLD %s ctrl_iface already exists!",
4929 mld->name);
4930 return 0;
4931 }
4932
4933 dl_list_init(&mld->ctrl_dst);
4934
4935 if (!mld->ctrl_interface)
4936 return 0;
4937
4938 if (mkdir(mld->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
4939 if (errno == EEXIST) {
4940 wpa_printf(MSG_DEBUG,
4941 "Using existing control interface directory.");
4942 } else {
4943 wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
4944 strerror(errno));
4945 goto fail;
4946 }
4947 }
4948
4949 if (os_strlen(mld->ctrl_interface) + 1 + os_strlen(mld->name) >=
4950 sizeof(addr.sun_path))
4951 goto fail;
4952
4953 s = socket(PF_UNIX, SOCK_DGRAM, 0);
4954 if (s < 0) {
4955 wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
4956 goto fail;
4957 }
4958
4959 os_memset(&addr, 0, sizeof(addr));
4960#ifdef __FreeBSD__
4961 addr.sun_len = sizeof(addr);
4962#endif /* __FreeBSD__ */
4963 addr.sun_family = AF_UNIX;
4964
4965 fname = hostapd_mld_ctrl_iface_path(mld);
4966 if (!fname)
4967 goto fail;
4968
4969 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
4970
4971 wpa_printf(MSG_DEBUG, "Setting up MLD %s ctrl_iface", mld->name);
4972
4973 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
4974 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
4975 strerror(errno));
4976 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
4977 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not allow connections - assuming it was left over from forced program termination");
4978 if (unlink(fname) < 0) {
4979 wpa_printf(MSG_ERROR,
4980 "Could not unlink existing ctrl_iface socket '%s': %s",
4981 fname, strerror(errno));
4982 goto fail;
4983 }
4984 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
4985 0) {
4986 wpa_printf(MSG_ERROR,
4987 "hostapd-ctrl-iface: bind(PF_UNIX): %s",
4988 strerror(errno));
4989 goto fail;
4990 }
4991 wpa_printf(MSG_DEBUG,
4992 "Successfully replaced leftover ctrl_iface socket '%s'",
4993 fname);
4994 } else {
4995 wpa_printf(MSG_INFO,
4996 "ctrl_iface exists and seems to be in use - cannot override it");
4997 wpa_printf(MSG_INFO,
4998 "Delete '%s' manually if it is not used anymore", fname);
4999 os_free(fname);
5000 fname = NULL;
5001 goto fail;
5002 }
5003 }
5004
5005 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
5006 wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
5007 strerror(errno));
5008 goto fail;
5009 }
5010 os_free(fname);
5011
5012 mld->ctrl_sock = s;
5013
5014 if (eloop_register_read_sock(s, hostapd_mld_ctrl_iface_receive, mld,
5015 NULL) < 0)
5016 return -1;
5017
5018 return 0;
5019
5020fail:
5021 if (s >= 0)
5022 close(s);
5023 if (fname) {
5024 unlink(fname);
5025 os_free(fname);
5026 }
5027 return -1;
5028#endif /* !CONFIG_CTRL_IFACE_UDP */
5029 return 0;
5030}
5031
5032
5033void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld)
5034{
5035#ifndef CONFIG_CTRL_IFACE_UDP
5036 struct wpa_ctrl_dst *dst, *prev;
5037
5038 if (mld->ctrl_sock > -1) {
5039 char *fname;
5040
5041 eloop_unregister_read_sock(mld->ctrl_sock);
5042 close(mld->ctrl_sock);
5043 mld->ctrl_sock = -1;
5044
5045 fname = hostapd_mld_ctrl_iface_path(mld);
5046 if (fname) {
5047 unlink(fname);
5048 os_free(fname);
5049 }
5050
5051 if (mld->ctrl_interface &&
5052 rmdir(mld->ctrl_interface) < 0) {
5053 if (errno == ENOTEMPTY) {
5054 wpa_printf(MSG_DEBUG,
5055 "MLD control interface directory not empty - leaving it behind");
5056 } else {
5057 wpa_printf(MSG_ERROR,
5058 "rmdir[ctrl_interface=%s]: %s",
5059 mld->ctrl_interface,
5060 strerror(errno));
5061 }
5062 }
5063 }
5064
5065 dl_list_for_each_safe(dst, prev, &mld->ctrl_dst, struct wpa_ctrl_dst,
5066 list)
5067 os_free(dst);
5068#endif /* !CONFIG_CTRL_IFACE_UDP */
5069
5070 os_free(mld->ctrl_interface);
5071}
5072
5073#endif /* CONFIG_IEEE80211BE */
5074
5075
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005076#ifndef CONFIG_CTRL_IFACE_UDP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005077static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
5078{
5079 char *buf;
5080 size_t len;
Sunil Ravic0f5d412024-09-11 22:12:49 +00005081 const char *ctrl_sock_iface;
5082
5083#ifdef CONFIG_IEEE80211BE
5084 ctrl_sock_iface = hapd->ctrl_sock_iface;
5085#else /* CONFIG_IEEE80211BE */
5086 ctrl_sock_iface = hapd->conf->iface;
5087#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005088
5089 if (hapd->conf->ctrl_interface == NULL)
5090 return NULL;
5091
5092 len = os_strlen(hapd->conf->ctrl_interface) +
Sunil Ravic0f5d412024-09-11 22:12:49 +00005093 os_strlen(ctrl_sock_iface) + 2;
5094
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005095 buf = os_malloc(len);
5096 if (buf == NULL)
5097 return NULL;
5098
5099 os_snprintf(buf, len, "%s/%s",
Sunil Ravic0f5d412024-09-11 22:12:49 +00005100 hapd->conf->ctrl_interface, ctrl_sock_iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005101 buf[len - 1] = '\0';
5102 return buf;
5103}
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005104#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005105
5106
Dmitry Shmidt7a53dbb2015-06-11 13:13:53 -07005107static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
5108 enum wpa_msg_type type,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005109 const char *txt, size_t len)
5110{
5111 struct hostapd_data *hapd = ctx;
5112 if (hapd == NULL)
5113 return;
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005114 hostapd_ctrl_iface_send(hapd, level, type, txt, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005115}
5116
5117
5118int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
5119{
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005120#ifdef CONFIG_CTRL_IFACE_UDP
5121 int port = HOSTAPD_CTRL_IFACE_PORT;
5122 char p[32] = { 0 };
5123 char port_str[40], *tmp;
5124 char *pos;
5125 struct addrinfo hints = { 0 }, *res, *saveres;
5126 int n;
5127
5128 if (hapd->ctrl_sock > -1) {
5129 wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
5130 return 0;
5131 }
5132
5133 if (hapd->conf->ctrl_interface == NULL)
5134 return 0;
5135
5136 pos = os_strstr(hapd->conf->ctrl_interface, "udp:");
5137 if (pos) {
5138 pos += 4;
5139 port = atoi(pos);
5140 if (port <= 0) {
5141 wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port");
5142 goto fail;
5143 }
5144 }
5145
5146 dl_list_init(&hapd->ctrl_dst);
5147 hapd->ctrl_sock = -1;
Hai Shalomfdcde762020-04-02 11:19:20 -07005148 os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005149
5150#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
5151 hints.ai_flags = AI_PASSIVE;
5152#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
5153
5154#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
5155 hints.ai_family = AF_INET6;
5156#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
5157 hints.ai_family = AF_INET;
5158#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
5159 hints.ai_socktype = SOCK_DGRAM;
5160
5161try_again:
5162 os_snprintf(p, sizeof(p), "%d", port);
5163 n = getaddrinfo(NULL, p, &hints, &res);
5164 if (n) {
5165 wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
5166 goto fail;
5167 }
5168
5169 saveres = res;
5170 hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
5171 res->ai_protocol);
5172 if (hapd->ctrl_sock < 0) {
5173 wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
5174 goto fail;
5175 }
5176
5177 if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
5178 port--;
5179 if ((HOSTAPD_CTRL_IFACE_PORT - port) <
5180 HOSTAPD_CTRL_IFACE_PORT_LIMIT && !pos)
5181 goto try_again;
5182 wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
5183 goto fail;
5184 }
5185
5186 freeaddrinfo(saveres);
5187
5188 os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
5189 tmp = os_strdup(port_str);
5190 if (tmp) {
5191 os_free(hapd->conf->ctrl_interface);
5192 hapd->conf->ctrl_interface = tmp;
5193 }
5194 wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
5195
5196 if (eloop_register_read_sock(hapd->ctrl_sock,
5197 hostapd_ctrl_iface_receive, hapd, NULL) <
5198 0) {
5199 hostapd_ctrl_iface_deinit(hapd);
5200 return -1;
5201 }
5202
5203 hapd->msg_ctx = hapd;
5204 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
5205
5206 return 0;
5207
5208fail:
5209 if (hapd->ctrl_sock >= 0)
5210 close(hapd->ctrl_sock);
5211 return -1;
5212#else /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005213 struct sockaddr_un addr;
5214 int s = -1;
5215 char *fname = NULL;
Sunil Ravic0f5d412024-09-11 22:12:49 +00005216 size_t iflen;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005217
Dmitry Shmidt04949592012-07-19 12:16:46 -07005218 if (hapd->ctrl_sock > -1) {
5219 wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
5220 return 0;
5221 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005222
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005223 dl_list_init(&hapd->ctrl_dst);
5224
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005225 if (hapd->conf->ctrl_interface == NULL)
5226 return 0;
5227
5228 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
5229 if (errno == EEXIST) {
5230 wpa_printf(MSG_DEBUG, "Using existing control "
5231 "interface directory.");
5232 } else {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005233 wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
5234 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005235 goto fail;
5236 }
5237 }
5238
5239 if (hapd->conf->ctrl_interface_gid_set &&
Hai Shalom74f70d42019-02-11 14:42:39 -08005240 lchown(hapd->conf->ctrl_interface, -1,
5241 hapd->conf->ctrl_interface_gid) < 0) {
5242 wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005243 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005244 return -1;
5245 }
5246
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005247 if (!hapd->conf->ctrl_interface_gid_set &&
5248 hapd->iface->interfaces->ctrl_iface_group &&
Hai Shalom74f70d42019-02-11 14:42:39 -08005249 lchown(hapd->conf->ctrl_interface, -1,
5250 hapd->iface->interfaces->ctrl_iface_group) < 0) {
5251 wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005252 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005253 return -1;
5254 }
5255
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08005256#ifdef ANDROID
5257 /*
5258 * Android is using umask 0077 which would leave the control interface
5259 * directory without group access. This breaks things since Wi-Fi
5260 * framework assumes that this directory can be accessed by other
5261 * applications in the wifi group. Fix this by adding group access even
5262 * if umask value would prevent this.
5263 */
5264 if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
5265 wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
5266 strerror(errno));
5267 /* Try to continue anyway */
5268 }
5269#endif /* ANDROID */
5270
Sunil Ravic0f5d412024-09-11 22:12:49 +00005271#ifdef CONFIG_IEEE80211BE
5272 iflen = os_strlen(hapd->ctrl_sock_iface);
5273#else /* CONFIG_IEEE80211BE */
5274 iflen = os_strlen(hapd->conf->iface);
5275#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005276 if (os_strlen(hapd->conf->ctrl_interface) + 1 +
Sunil Ravic0f5d412024-09-11 22:12:49 +00005277 iflen >= sizeof(addr.sun_path))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005278 goto fail;
5279
5280 s = socket(PF_UNIX, SOCK_DGRAM, 0);
5281 if (s < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005282 wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005283 goto fail;
5284 }
5285
5286 os_memset(&addr, 0, sizeof(addr));
5287#ifdef __FreeBSD__
5288 addr.sun_len = sizeof(addr);
5289#endif /* __FreeBSD__ */
5290 addr.sun_family = AF_UNIX;
5291 fname = hostapd_ctrl_iface_path(hapd);
5292 if (fname == NULL)
5293 goto fail;
5294 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
5295 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
5296 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
5297 strerror(errno));
5298 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
5299 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
5300 " allow connections - assuming it was left"
5301 "over from forced program termination");
5302 if (unlink(fname) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005303 wpa_printf(MSG_ERROR,
5304 "Could not unlink existing ctrl_iface socket '%s': %s",
5305 fname, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005306 goto fail;
5307 }
5308 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
5309 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005310 wpa_printf(MSG_ERROR,
5311 "hostapd-ctrl-iface: bind(PF_UNIX): %s",
5312 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005313 goto fail;
5314 }
5315 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
5316 "ctrl_iface socket '%s'", fname);
5317 } else {
5318 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
5319 "be in use - cannot override it");
5320 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
5321 "not used anymore", fname);
5322 os_free(fname);
5323 fname = NULL;
5324 goto fail;
5325 }
5326 }
5327
5328 if (hapd->conf->ctrl_interface_gid_set &&
Hai Shalom74f70d42019-02-11 14:42:39 -08005329 lchown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
5330 wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005331 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005332 goto fail;
5333 }
5334
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005335 if (!hapd->conf->ctrl_interface_gid_set &&
5336 hapd->iface->interfaces->ctrl_iface_group &&
Hai Shalom74f70d42019-02-11 14:42:39 -08005337 lchown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
5338 wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005339 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07005340 goto fail;
5341 }
5342
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005343 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005344 wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
5345 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005346 goto fail;
5347 }
5348 os_free(fname);
5349
5350 hapd->ctrl_sock = s;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08005351 if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
5352 NULL) < 0) {
5353 hostapd_ctrl_iface_deinit(hapd);
5354 return -1;
5355 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005356 hapd->msg_ctx = hapd;
5357 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
5358
5359 return 0;
5360
5361fail:
5362 if (s >= 0)
5363 close(s);
5364 if (fname) {
5365 unlink(fname);
5366 os_free(fname);
5367 }
5368 return -1;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005369#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005370}
5371
5372
5373void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
5374{
5375 struct wpa_ctrl_dst *dst, *prev;
5376
5377 if (hapd->ctrl_sock > -1) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005378#ifndef CONFIG_CTRL_IFACE_UDP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005379 char *fname;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005380#endif /* !CONFIG_CTRL_IFACE_UDP */
5381
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005382 eloop_unregister_read_sock(hapd->ctrl_sock);
5383 close(hapd->ctrl_sock);
5384 hapd->ctrl_sock = -1;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005385#ifndef CONFIG_CTRL_IFACE_UDP
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005386 fname = hostapd_ctrl_iface_path(hapd);
5387 if (fname)
5388 unlink(fname);
5389 os_free(fname);
5390
5391 if (hapd->conf->ctrl_interface &&
5392 rmdir(hapd->conf->ctrl_interface) < 0) {
5393 if (errno == ENOTEMPTY) {
5394 wpa_printf(MSG_DEBUG, "Control interface "
5395 "directory not empty - leaving it "
5396 "behind");
5397 } else {
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07005398 wpa_printf(MSG_ERROR,
5399 "rmdir[ctrl_interface=%s]: %s",
5400 hapd->conf->ctrl_interface,
5401 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005402 }
5403 }
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005404#endif /* !CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005405 }
5406
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005407 dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
5408 list)
5409 os_free(dst);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005410
5411#ifdef CONFIG_TESTING_OPTIONS
5412 l2_packet_deinit(hapd->l2_test);
5413 hapd->l2_test = NULL;
5414#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07005415}
5416
5417
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005418static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
5419 char *buf)
5420{
5421 if (hostapd_add_iface(interfaces, buf) < 0) {
5422 wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
5423 return -1;
5424 }
5425 return 0;
5426}
5427
5428
5429static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
5430 char *buf)
5431{
5432 if (hostapd_remove_iface(interfaces, buf) < 0) {
5433 wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
5434 return -1;
5435 }
5436 return 0;
5437}
5438
5439
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005440static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005441 struct sockaddr_storage *from,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005442 socklen_t fromlen, char *input)
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005443{
Roshan Pius3a1667e2018-07-03 15:17:14 -07005444 return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen,
5445 input);
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005446}
5447
5448
5449static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005450 struct sockaddr_storage *from,
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005451 socklen_t fromlen)
5452{
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005453 return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen);
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005454}
5455
5456
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08005457static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
5458{
5459#ifdef CONFIG_WPS_TESTING
5460 wps_version_number = 0x20;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005461 wps_testing_stub_cred = 0;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08005462 wps_corrupt_pkhash = 0;
5463#endif /* CONFIG_WPS_TESTING */
Roshan Pius3a1667e2018-07-03 15:17:14 -07005464
5465#ifdef CONFIG_TESTING_OPTIONS
5466#ifdef CONFIG_DPP
5467 dpp_test = DPP_TEST_DISABLED;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005468#ifdef CONFIG_DPP3
5469 dpp_version_override = 3;
5470#elif defined(CONFIG_DPP2)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005471 dpp_version_override = 2;
5472#else /* CONFIG_DPP2 */
5473 dpp_version_override = 1;
5474#endif /* CONFIG_DPP2 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07005475#endif /* CONFIG_DPP */
5476#endif /* CONFIG_TESTING_OPTIONS */
5477
5478#ifdef CONFIG_DPP
Hai Shalom021b0b52019-04-10 11:17:58 -07005479 dpp_global_clear(interfaces->dpp);
Sunil Ravi89eba102022-09-13 21:04:37 -07005480#ifdef CONFIG_DPP3
Sunil Ravib0ac25f2024-07-12 01:42:03 +00005481 interfaces->dpp_pb_bi = NULL;
Sunil Ravi89eba102022-09-13 21:04:37 -07005482 {
5483 int i;
5484
5485 for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
5486 struct dpp_pb_info *info;
5487
5488 info = &interfaces->dpp_pb[i];
5489 info->rx_time.sec = 0;
5490 info->rx_time.usec = 0;
5491 }
5492 }
5493#endif /* CONFIG_DPP3 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07005494#endif /* CONFIG_DPP */
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08005495}
5496
5497
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005498#ifdef CONFIG_FST
5499
5500static int
5501hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces *interfaces,
5502 const char *cmd)
5503{
5504 char ifname[IFNAMSIZ + 1];
5505 struct fst_iface_cfg cfg;
5506 struct hostapd_data *hapd;
5507 struct fst_wpa_obj iface_obj;
5508
5509 if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
5510 hapd = hostapd_get_iface(interfaces, ifname);
5511 if (hapd) {
5512 if (hapd->iface->fst) {
5513 wpa_printf(MSG_INFO, "FST: Already attached");
5514 return -1;
5515 }
5516 fst_hostapd_fill_iface_obj(hapd, &iface_obj);
5517 hapd->iface->fst = fst_attach(ifname, hapd->own_addr,
5518 &iface_obj, &cfg);
5519 if (hapd->iface->fst)
5520 return 0;
5521 }
5522 }
5523
5524 return -EINVAL;
5525}
5526
5527
5528static int
5529hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces *interfaces,
5530 const char *cmd)
5531{
5532 char ifname[IFNAMSIZ + 1];
5533 struct hostapd_data * hapd;
5534
5535 if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
5536 hapd = hostapd_get_iface(interfaces, ifname);
5537 if (hapd) {
5538 if (!fst_iface_detach(ifname)) {
5539 hapd->iface->fst = NULL;
5540 hapd->iface->fst_ies = NULL;
5541 return 0;
5542 }
5543 }
5544 }
5545
5546 return -EINVAL;
5547}
5548
5549#endif /* CONFIG_FST */
5550
5551
5552static struct hostapd_data *
5553hostapd_interfaces_get_hapd(struct hapd_interfaces *interfaces,
5554 const char *ifname)
5555{
5556 size_t i, j;
5557
5558 for (i = 0; i < interfaces->count; i++) {
5559 struct hostapd_iface *iface = interfaces->iface[i];
5560
5561 for (j = 0; j < iface->num_bss; j++) {
5562 struct hostapd_data *hapd;
5563
5564 hapd = iface->bss[j];
5565 if (os_strcmp(ifname, hapd->conf->iface) == 0)
5566 return hapd;
5567 }
5568 }
5569
5570 return NULL;
5571}
5572
5573
5574static int hostapd_ctrl_iface_dup_param(struct hostapd_data *src_hapd,
5575 struct hostapd_data *dst_hapd,
5576 const char *param)
5577{
5578 int res;
5579 char *value;
5580
5581 value = os_zalloc(HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
5582 if (!value) {
5583 wpa_printf(MSG_ERROR,
5584 "DUP: cannot allocate buffer to stringify %s",
5585 param);
5586 goto error_return;
5587 }
5588
5589 if (os_strcmp(param, "wpa") == 0) {
5590 os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%d",
5591 src_hapd->conf->wpa);
5592 } else if (os_strcmp(param, "wpa_key_mgmt") == 0 &&
5593 src_hapd->conf->wpa_key_mgmt) {
5594 res = hostapd_ctrl_iface_get_key_mgmt(
5595 src_hapd, value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
5596 if (os_snprintf_error(HOSTAPD_CLI_DUP_VALUE_MAX_LEN, res))
5597 goto error_stringify;
5598 } else if (os_strcmp(param, "wpa_pairwise") == 0 &&
5599 src_hapd->conf->wpa_pairwise) {
5600 res = wpa_write_ciphers(value,
5601 value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
5602 src_hapd->conf->wpa_pairwise, " ");
5603 if (res < 0)
5604 goto error_stringify;
5605 } else if (os_strcmp(param, "rsn_pairwise") == 0 &&
5606 src_hapd->conf->rsn_pairwise) {
5607 res = wpa_write_ciphers(value,
5608 value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
5609 src_hapd->conf->rsn_pairwise, " ");
5610 if (res < 0)
5611 goto error_stringify;
5612 } else if (os_strcmp(param, "wpa_passphrase") == 0 &&
5613 src_hapd->conf->ssid.wpa_passphrase) {
5614 os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%s",
5615 src_hapd->conf->ssid.wpa_passphrase);
5616 } else if (os_strcmp(param, "wpa_psk") == 0 &&
5617 src_hapd->conf->ssid.wpa_psk_set) {
5618 wpa_snprintf_hex(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
5619 src_hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
5620 } else {
5621 wpa_printf(MSG_WARNING, "DUP: %s cannot be duplicated", param);
5622 goto error_return;
5623 }
5624
5625 res = hostapd_set_iface(dst_hapd->iconf, dst_hapd->conf, param, value);
5626 os_free(value);
5627 return res;
5628
5629error_stringify:
5630 wpa_printf(MSG_ERROR, "DUP: cannot stringify %s", param);
5631error_return:
5632 os_free(value);
5633 return -1;
5634}
5635
5636
5637static int
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005638hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces,
5639 const char *input,
5640 char *reply, int reply_size)
5641{
5642 size_t i, j;
5643 int res;
5644 char *pos, *end;
5645 struct hostapd_iface *iface;
5646 int show_ctrl = 0;
5647
5648 if (input)
5649 show_ctrl = !!os_strstr(input, "ctrl");
5650
5651 pos = reply;
5652 end = reply + reply_size;
5653
5654 for (i = 0; i < interfaces->count; i++) {
5655 iface = interfaces->iface[i];
5656
5657 for (j = 0; j < iface->num_bss; j++) {
5658 struct hostapd_bss_config *conf;
5659
5660 conf = iface->conf->bss[j];
5661 if (show_ctrl)
5662 res = os_snprintf(pos, end - pos,
5663 "%s ctrl_iface=%s\n",
5664 conf->iface,
5665 conf->ctrl_interface ?
5666 conf->ctrl_interface : "N/A");
5667 else
5668 res = os_snprintf(pos, end - pos, "%s\n",
5669 conf->iface);
5670 if (os_snprintf_error(end - pos, res)) {
5671 *pos = '\0';
5672 return pos - reply;
5673 }
5674 pos += res;
5675 }
5676 }
5677
5678 return pos - reply;
5679}
5680
5681
5682static int
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005683hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
5684 char *cmd)
5685{
5686 char *p_start = cmd, *p_end;
5687 struct hostapd_data *src_hapd, *dst_hapd;
5688
5689 /* cmd: "<src ifname> <dst ifname> <variable name> */
5690
5691 p_end = os_strchr(p_start, ' ');
5692 if (!p_end) {
5693 wpa_printf(MSG_ERROR, "DUP: no src ifname found in cmd: '%s'",
5694 cmd);
5695 return -1;
5696 }
5697
5698 *p_end = '\0';
5699 src_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
5700 if (!src_hapd) {
5701 wpa_printf(MSG_ERROR, "DUP: no src ifname found: '%s'",
5702 p_start);
5703 return -1;
5704 }
5705
5706 p_start = p_end + 1;
5707 p_end = os_strchr(p_start, ' ');
5708 if (!p_end) {
5709 wpa_printf(MSG_ERROR, "DUP: no dst ifname found in cmd: '%s'",
5710 cmd);
5711 return -1;
5712 }
5713
5714 *p_end = '\0';
5715 dst_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
5716 if (!dst_hapd) {
5717 wpa_printf(MSG_ERROR, "DUP: no dst ifname found: '%s'",
5718 p_start);
5719 return -1;
5720 }
5721
5722 p_start = p_end + 1;
5723 return hostapd_ctrl_iface_dup_param(src_hapd, dst_hapd, p_start);
5724}
5725
5726
5727static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
5728 const char *ifname,
5729 char *buf, char *reply,
5730 int reply_size,
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005731 struct sockaddr_storage *from,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005732 socklen_t fromlen)
5733{
5734 struct hostapd_data *hapd;
5735
5736 hapd = hostapd_interfaces_get_hapd(interfaces, ifname);
5737 if (hapd == NULL) {
5738 int res;
5739
5740 res = os_snprintf(reply, reply_size, "FAIL-NO-IFNAME-MATCH\n");
5741 if (os_snprintf_error(reply_size, res))
5742 return -1;
5743 return res;
5744 }
5745
5746 return hostapd_ctrl_iface_receive_process(hapd, buf, reply,reply_size,
5747 from, fromlen);
5748}
5749
5750
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005751static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
5752 void *sock_ctx)
5753{
Hai Shalomfdcde762020-04-02 11:19:20 -07005754 struct hapd_interfaces *interfaces = eloop_ctx;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005755 char buffer[256], *buf = buffer;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005756 int res;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005757 struct sockaddr_storage from;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005758 socklen_t fromlen = sizeof(from);
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005759 char *reply;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005760 int reply_len;
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005761 const int reply_size = 4096;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005762#ifdef CONFIG_CTRL_IFACE_UDP
Hai Shalomfdcde762020-04-02 11:19:20 -07005763 unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005764#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005765
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005766 res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005767 (struct sockaddr *) &from, &fromlen);
5768 if (res < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005769 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
5770 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005771 return;
5772 }
5773 buf[res] = '\0';
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005774 wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005775
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005776 reply = os_malloc(reply_size);
5777 if (reply == NULL) {
5778 if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
5779 fromlen) < 0) {
5780 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
5781 strerror(errno));
5782 }
5783 return;
5784 }
5785
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005786 os_memcpy(reply, "OK\n", 3);
5787 reply_len = 3;
5788
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005789#ifdef CONFIG_CTRL_IFACE_UDP
5790 if (os_strcmp(buf, "GET_COOKIE") == 0) {
5791 os_memcpy(reply, "COOKIE=", 7);
Hai Shalomfdcde762020-04-02 11:19:20 -07005792 wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
5793 interfaces->ctrl_iface_cookie,
5794 CTRL_IFACE_COOKIE_LEN);
5795 reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005796 goto send_reply;
5797 }
5798
5799 if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
Hai Shalomfdcde762020-04-02 11:19:20 -07005800 hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005801 wpa_printf(MSG_DEBUG,
5802 "CTRL: No cookie in the request - drop request");
5803 os_free(reply);
5804 return;
5805 }
5806
Hai Shalomfdcde762020-04-02 11:19:20 -07005807 if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie,
5808 CTRL_IFACE_COOKIE_LEN) != 0) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005809 wpa_printf(MSG_DEBUG,
5810 "CTRL: Invalid cookie in the request - drop request");
5811 os_free(reply);
5812 return;
5813 }
5814
Hai Shalomfdcde762020-04-02 11:19:20 -07005815 buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005816 while (*buf == ' ')
5817 buf++;
5818#endif /* CONFIG_CTRL_IFACE_UDP */
5819
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005820 if (os_strncmp(buf, "IFNAME=", 7) == 0) {
5821 char *pos = os_strchr(buf + 7, ' ');
5822
5823 if (pos) {
5824 *pos++ = '\0';
5825 reply_len = hostapd_global_ctrl_iface_ifname(
5826 interfaces, buf + 7, pos, reply, reply_size,
5827 &from, fromlen);
5828 goto send_reply;
5829 }
5830 }
5831
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005832 if (os_strcmp(buf, "PING") == 0) {
5833 os_memcpy(reply, "PONG\n", 5);
5834 reply_len = 5;
Dmitry Shmidtcce06662013-11-04 18:44:24 -08005835 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
5836 if (wpa_debug_reopen_file() < 0)
5837 reply_len = -1;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08005838 } else if (os_strcmp(buf, "FLUSH") == 0) {
5839 hostapd_ctrl_iface_flush(interfaces);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005840 } else if (os_strncmp(buf, "ADD ", 4) == 0) {
5841 if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
5842 reply_len = -1;
5843 } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
5844 if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
5845 reply_len = -1;
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005846 } else if (os_strcmp(buf, "ATTACH") == 0) {
5847 if (hostapd_global_ctrl_iface_attach(interfaces, &from,
Roshan Pius3a1667e2018-07-03 15:17:14 -07005848 fromlen, NULL))
5849 reply_len = -1;
5850 } else if (os_strncmp(buf, "ATTACH ", 7) == 0) {
5851 if (hostapd_global_ctrl_iface_attach(interfaces, &from,
5852 fromlen, buf + 7))
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005853 reply_len = -1;
5854 } else if (os_strcmp(buf, "DETACH") == 0) {
5855 if (hostapd_global_ctrl_iface_detach(interfaces, &from,
5856 fromlen))
5857 reply_len = -1;
Dmitry Shmidt7f93d6f2014-02-21 11:22:49 -08005858#ifdef CONFIG_MODULE_TESTS
5859 } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
Dmitry Shmidt7f93d6f2014-02-21 11:22:49 -08005860 if (hapd_module_tests() < 0)
5861 reply_len = -1;
5862#endif /* CONFIG_MODULE_TESTS */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005863#ifdef CONFIG_FST
5864 } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
5865 if (!hostapd_global_ctrl_iface_fst_attach(interfaces, buf + 11))
5866 reply_len = os_snprintf(reply, reply_size, "OK\n");
5867 else
5868 reply_len = -1;
5869 } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
5870 if (!hostapd_global_ctrl_iface_fst_detach(interfaces, buf + 11))
5871 reply_len = os_snprintf(reply, reply_size, "OK\n");
5872 else
5873 reply_len = -1;
5874 } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
5875 reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
5876#endif /* CONFIG_FST */
5877 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
5878 if (!hostapd_global_ctrl_iface_dup_network(interfaces,
5879 buf + 12))
5880 reply_len = os_snprintf(reply, reply_size, "OK\n");
5881 else
5882 reply_len = -1;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005883 } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
5884 reply_len = hostapd_global_ctrl_iface_interfaces(
Sunil Ravi99c035e2024-07-12 01:42:03 +00005885 interfaces, buf + 10, reply, reply_size);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005886 } else if (os_strcmp(buf, "TERMINATE") == 0) {
5887 eloop_terminate();
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005888 } else {
5889 wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
5890 "ignored");
5891 reply_len = -1;
5892 }
5893
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08005894send_reply:
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005895 if (reply_len < 0) {
5896 os_memcpy(reply, "FAIL\n", 5);
5897 reply_len = 5;
5898 }
5899
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08005900 if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
5901 fromlen) < 0) {
5902 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
5903 strerror(errno));
5904 }
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02005905 os_free(reply);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005906}
5907
5908
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005909#ifndef CONFIG_CTRL_IFACE_UDP
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005910static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
5911{
5912 char *buf;
5913 size_t len;
5914
5915 if (interface->global_iface_path == NULL)
5916 return NULL;
5917
5918 len = os_strlen(interface->global_iface_path) +
5919 os_strlen(interface->global_iface_name) + 2;
5920 buf = os_malloc(len);
5921 if (buf == NULL)
5922 return NULL;
5923
5924 os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
5925 interface->global_iface_name);
5926 buf[len - 1] = '\0';
5927 return buf;
5928}
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005929#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07005930
5931
5932int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
5933{
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005934#ifdef CONFIG_CTRL_IFACE_UDP
5935 int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
5936 char p[32] = { 0 };
5937 char *pos;
5938 struct addrinfo hints = { 0 }, *res, *saveres;
5939 int n;
5940
5941 if (interface->global_ctrl_sock > -1) {
5942 wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
5943 return 0;
5944 }
5945
5946 if (interface->global_iface_path == NULL)
5947 return 0;
5948
5949 pos = os_strstr(interface->global_iface_path, "udp:");
5950 if (pos) {
5951 pos += 4;
5952 port = atoi(pos);
5953 if (port <= 0) {
5954 wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port");
5955 goto fail;
5956 }
5957 }
5958
Hai Shalomfdcde762020-04-02 11:19:20 -07005959 os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08005960
5961#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
5962 hints.ai_flags = AI_PASSIVE;
5963#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
5964
5965#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
5966 hints.ai_family = AF_INET6;
5967#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
5968 hints.ai_family = AF_INET;
5969#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
5970 hints.ai_socktype = SOCK_DGRAM;
5971
5972try_again:
5973 os_snprintf(p, sizeof(p), "%d", port);
5974 n = getaddrinfo(NULL, p, &hints, &res);
5975 if (n) {
5976 wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
5977 goto fail;
5978 }
5979
5980 saveres = res;
5981 interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
5982 res->ai_protocol);
5983 if (interface->global_ctrl_sock < 0) {
5984 wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
5985 goto fail;
5986 }
5987
5988 if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
5989 0) {
5990 port++;
5991 if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
5992 HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
5993 goto try_again;
5994 wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
5995 goto fail;
5996 }
5997
5998 freeaddrinfo(saveres);
5999
6000 wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
6001
6002 if (eloop_register_read_sock(interface->global_ctrl_sock,
6003 hostapd_global_ctrl_iface_receive,
6004 interface, NULL) < 0) {
6005 hostapd_global_ctrl_iface_deinit(interface);
6006 return -1;
6007 }
6008
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006009 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
6010
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006011 return 0;
6012
6013fail:
6014 if (interface->global_ctrl_sock >= 0)
6015 close(interface->global_ctrl_sock);
6016 return -1;
6017#else /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006018 struct sockaddr_un addr;
6019 int s = -1;
6020 char *fname = NULL;
6021
6022 if (interface->global_iface_path == NULL) {
6023 wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
6024 return 0;
6025 }
6026
6027 if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
6028 if (errno == EEXIST) {
6029 wpa_printf(MSG_DEBUG, "Using existing control "
6030 "interface directory.");
6031 } else {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006032 wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
6033 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006034 goto fail;
6035 }
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07006036 } else if (interface->ctrl_iface_group &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006037 lchown(interface->global_iface_path, -1,
6038 interface->ctrl_iface_group) < 0) {
6039 wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006040 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07006041 goto fail;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006042 }
6043
6044 if (os_strlen(interface->global_iface_path) + 1 +
6045 os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
6046 goto fail;
6047
6048 s = socket(PF_UNIX, SOCK_DGRAM, 0);
6049 if (s < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006050 wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006051 goto fail;
6052 }
6053
6054 os_memset(&addr, 0, sizeof(addr));
6055#ifdef __FreeBSD__
6056 addr.sun_len = sizeof(addr);
6057#endif /* __FreeBSD__ */
6058 addr.sun_family = AF_UNIX;
6059 fname = hostapd_global_ctrl_iface_path(interface);
6060 if (fname == NULL)
6061 goto fail;
6062 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
6063 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
6064 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
6065 strerror(errno));
6066 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
6067 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
6068 " allow connections - assuming it was left"
6069 "over from forced program termination");
6070 if (unlink(fname) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006071 wpa_printf(MSG_ERROR,
6072 "Could not unlink existing ctrl_iface socket '%s': %s",
6073 fname, strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006074 goto fail;
6075 }
6076 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
6077 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006078 wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
6079 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006080 goto fail;
6081 }
6082 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
6083 "ctrl_iface socket '%s'", fname);
6084 } else {
6085 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
6086 "be in use - cannot override it");
6087 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
6088 "not used anymore", fname);
6089 os_free(fname);
6090 fname = NULL;
6091 goto fail;
6092 }
6093 }
6094
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07006095 if (interface->ctrl_iface_group &&
Hai Shalom74f70d42019-02-11 14:42:39 -08006096 lchown(fname, -1, interface->ctrl_iface_group) < 0) {
6097 wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006098 strerror(errno));
Dmitry Shmidt0ccb66e2013-03-29 16:41:28 -07006099 goto fail;
6100 }
6101
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006102 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08006103 wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
6104 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006105 goto fail;
6106 }
6107 os_free(fname);
6108
6109 interface->global_ctrl_sock = s;
6110 eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
6111 interface, NULL);
6112
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006113 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
6114
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006115 return 0;
6116
6117fail:
6118 if (s >= 0)
6119 close(s);
6120 if (fname) {
6121 unlink(fname);
6122 os_free(fname);
6123 }
6124 return -1;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006125#endif /* CONFIG_CTRL_IFACE_UDP */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006126}
6127
6128
6129void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
6130{
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006131#ifndef CONFIG_CTRL_IFACE_UDP
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006132 char *fname = NULL;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006133#endif /* CONFIG_CTRL_IFACE_UDP */
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02006134 struct wpa_ctrl_dst *dst, *prev;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006135
6136 if (interfaces->global_ctrl_sock > -1) {
6137 eloop_unregister_read_sock(interfaces->global_ctrl_sock);
6138 close(interfaces->global_ctrl_sock);
6139 interfaces->global_ctrl_sock = -1;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006140#ifndef CONFIG_CTRL_IFACE_UDP
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006141 fname = hostapd_global_ctrl_iface_path(interfaces);
6142 if (fname) {
6143 unlink(fname);
6144 os_free(fname);
6145 }
6146
6147 if (interfaces->global_iface_path &&
6148 rmdir(interfaces->global_iface_path) < 0) {
6149 if (errno == ENOTEMPTY) {
6150 wpa_printf(MSG_DEBUG, "Control interface "
6151 "directory not empty - leaving it "
6152 "behind");
6153 } else {
Dmitry Shmidtb7b4d0e2013-08-26 12:09:05 -07006154 wpa_printf(MSG_ERROR,
6155 "rmdir[ctrl_interface=%s]: %s",
6156 interfaces->global_iface_path,
6157 strerror(errno));
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006158 }
6159 }
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006160#endif /* CONFIG_CTRL_IFACE_UDP */
Anton Nayshtutf715e8d2014-11-16 16:52:49 +02006161 }
6162
6163 os_free(interfaces->global_iface_path);
6164 interfaces->global_iface_path = NULL;
6165
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006166 dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst,
6167 struct wpa_ctrl_dst, list)
6168 os_free(dst);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07006169}
6170
6171
Roshan Pius3a1667e2018-07-03 15:17:14 -07006172static int hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst *dst,
6173 const char *buf)
6174{
6175 /* Enable Probe Request events based on explicit request.
6176 * Other events are enabled by default.
6177 */
6178 if (str_starts(buf, RX_PROBE_REQUEST))
6179 return !!(dst->events & WPA_EVENT_RX_PROBE_REQUEST);
6180 return 1;
6181}
6182
6183
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006184static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst,
6185 const char *ifname, int level,
6186 const char *buf, size_t len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006187{
6188 struct wpa_ctrl_dst *dst, *next;
6189 struct msghdr msg;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006190 int idx, res;
6191 struct iovec io[5];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006192 char levelstr[10];
6193
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006194 if (sock < 0 || dl_list_empty(ctrl_dst))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006195 return;
6196
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006197 res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
6198 if (os_snprintf_error(sizeof(levelstr), res))
6199 return;
6200 idx = 0;
6201 if (ifname) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006202 io[idx].iov_base = "IFNAME=";
6203 io[idx].iov_len = 7;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006204 idx++;
6205 io[idx].iov_base = (char *) ifname;
6206 io[idx].iov_len = os_strlen(ifname);
6207 idx++;
6208 io[idx].iov_base = " ";
6209 io[idx].iov_len = 1;
6210 idx++;
6211 }
6212 io[idx].iov_base = levelstr;
6213 io[idx].iov_len = os_strlen(levelstr);
6214 idx++;
6215 io[idx].iov_base = (char *) buf;
6216 io[idx].iov_len = len;
6217 idx++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006218 os_memset(&msg, 0, sizeof(msg));
6219 msg.msg_iov = io;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006220 msg.msg_iovlen = idx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006221
6222 idx = 0;
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006223 dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07006224 if ((level >= dst->debug_level) &&
6225 hostapd_ctrl_check_event_enabled(dst, buf)) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08006226 sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send",
6227 &dst->addr, dst->addrlen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006228 msg.msg_name = &dst->addr;
6229 msg.msg_namelen = dst->addrlen;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006230 if (sendmsg(sock, &msg, 0) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006231 int _errno = errno;
6232 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
6233 "%d - %s",
6234 idx, errno, strerror(errno));
6235 dst->errors++;
6236 if (dst->errors > 10 || _errno == ENOENT) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006237 ctrl_iface_detach(ctrl_dst,
6238 &dst->addr,
6239 dst->addrlen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006240 }
6241 } else
6242 dst->errors = 0;
6243 }
6244 idx++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006245 }
6246}
6247
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08006248
6249static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
6250 enum wpa_msg_type type,
6251 const char *buf, size_t len)
6252{
6253 if (type != WPA_MSG_NO_GLOBAL) {
6254 hostapd_ctrl_iface_send_internal(
6255 hapd->iface->interfaces->global_ctrl_sock,
6256 &hapd->iface->interfaces->global_ctrl_dst,
6257 type != WPA_MSG_PER_INTERFACE ?
6258 NULL : hapd->conf->iface,
6259 level, buf, len);
6260 }
6261
6262 if (type != WPA_MSG_ONLY_GLOBAL) {
6263 hostapd_ctrl_iface_send_internal(
6264 hapd->ctrl_sock, &hapd->ctrl_dst,
6265 NULL, level, buf, len);
6266 }
6267}
6268
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07006269#endif /* CONFIG_NATIVE_WINDOWS */