]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/ctrl_iface.c
tests: Fix MBO ANQP cellular data preference query
[thirdparty/hostap.git] / wpa_supplicant / ctrl_iface.c
CommitLineData
6fc6879b
JM
1/*
2 * WPA Supplicant / Control interface (shared code for all backends)
5e3b5197 3 * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 */
8
3a068632 9#include "utils/includes.h"
4a6cc862
JM
10#ifdef CONFIG_TESTING_OPTIONS
11#include <net/ethernet.h>
12#include <netinet/ip.h>
13#endif /* CONFIG_TESTING_OPTIONS */
6fc6879b 14
3a068632
JM
15#include "utils/common.h"
16#include "utils/eloop.h"
8aaafcee 17#include "utils/uuid.h"
50a17a76 18#include "utils/module_tests.h"
acec8d32 19#include "common/version.h"
3a068632 20#include "common/ieee802_11_defs.h"
337c781f 21#include "common/ieee802_11_common.h"
3a068632 22#include "common/wpa_ctrl.h"
a1651451 23#include "crypto/tls.h"
9d4ff04a 24#include "ap/hostapd.h"
3a068632
JM
25#include "eap_peer/eap.h"
26#include "eapol_supp/eapol_supp_sm.h"
3acb5005 27#include "rsn_supp/wpa.h"
3a068632
JM
28#include "rsn_supp/preauth.h"
29#include "rsn_supp/pmksa_cache.h"
30#include "l2_packet/l2_packet.h"
31#include "wps/wps.h"
df4cea89 32#include "fst/fst.h"
3794af2d 33#include "fst/fst_ctrl_iface.h"
6fc6879b 34#include "config.h"
6fc6879b 35#include "wpa_supplicant_i.h"
2d5b792d 36#include "driver_i.h"
fcc60db4 37#include "wps_supplicant.h"
11ef8d35 38#include "ibss_rsn.h"
3ec97afe 39#include "ap.h"
b563b388
JM
40#include "p2p_supplicant.h"
41#include "p2p/p2p.h"
a8918e86 42#include "hs20_supplicant.h"
9675ce35 43#include "wifi_display.h"
8bac466b 44#include "notify.h"
3a068632 45#include "bss.h"
9ba9fa07 46#include "scan.h"
3a068632 47#include "ctrl_iface.h"
afc064fe 48#include "interworking.h"
9aa10e2b 49#include "blacklist.h"
bc5d330a 50#include "autoscan.h"
e9199e31 51#include "wnm_sta.h"
60b893df 52#include "offchannel.h"
7a4a93b9 53#include "drivers/driver.h"
79070906 54#include "mesh.h"
6fc6879b 55
4b4a8ae5
JM
56static int wpa_supplicant_global_iface_list(struct wpa_global *global,
57 char *buf, int len);
6fc6879b 58static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
56e2fc2c 59 const char *input,
6fc6879b 60 char *buf, int len);
d3c9c35f
DS
61static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
62 char *val);
6fc6879b 63
d445a5cd
JM
64static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
65{
66 char *pos;
67 u8 addr[ETH_ALEN], *filter = NULL, *n;
68 size_t count = 0;
69
70 pos = val;
71 while (pos) {
72 if (*pos == '\0')
73 break;
1485ec07
JM
74 if (hwaddr_aton(pos, addr)) {
75 os_free(filter);
d445a5cd 76 return -1;
1485ec07 77 }
067ffa26 78 n = os_realloc_array(filter, count + 1, ETH_ALEN);
d445a5cd
JM
79 if (n == NULL) {
80 os_free(filter);
81 return -1;
82 }
83 filter = n;
84 os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
85 count++;
86
87 pos = os_strchr(pos, ' ');
88 if (pos)
89 pos++;
90 }
91
92 wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
93 os_free(wpa_s->bssid_filter);
94 wpa_s->bssid_filter = filter;
95 wpa_s->bssid_filter_count = count;
96
97 return 0;
98}
99
100
6407f413
JM
101static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
102{
103 char *pos;
104 u8 addr[ETH_ALEN], *bssid = NULL, *n;
105 struct wpa_ssid_value *ssid = NULL, *ns;
106 size_t count = 0, ssid_count = 0;
107 struct wpa_ssid *c;
108
109 /*
65015b2d 110 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
6407f413
JM
111 * SSID_SPEC ::= ssid <SSID_HEX>
112 * BSSID_SPEC ::= bssid <BSSID_HEX>
113 */
114
115 pos = val;
116 while (pos) {
117 if (*pos == '\0')
118 break;
119 if (os_strncmp(pos, "bssid ", 6) == 0) {
120 int res;
121 pos += 6;
122 res = hwaddr_aton2(pos, addr);
123 if (res < 0) {
124 os_free(ssid);
125 os_free(bssid);
126 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
127 "BSSID value '%s'", pos);
128 return -1;
129 }
130 pos += res;
131 n = os_realloc_array(bssid, count + 1, ETH_ALEN);
132 if (n == NULL) {
133 os_free(ssid);
134 os_free(bssid);
135 return -1;
136 }
137 bssid = n;
138 os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
139 count++;
140 } else if (os_strncmp(pos, "ssid ", 5) == 0) {
141 char *end;
142 pos += 5;
143
144 end = pos;
145 while (*end) {
146 if (*end == '\0' || *end == ' ')
147 break;
148 end++;
149 }
150
151 ns = os_realloc_array(ssid, ssid_count + 1,
152 sizeof(struct wpa_ssid_value));
153 if (ns == NULL) {
154 os_free(ssid);
155 os_free(bssid);
156 return -1;
157 }
158 ssid = ns;
159
d9d1b952
JM
160 if ((end - pos) & 0x01 ||
161 end - pos > 2 * SSID_MAX_LEN ||
6407f413
JM
162 hexstr2bin(pos, ssid[ssid_count].ssid,
163 (end - pos) / 2) < 0) {
164 os_free(ssid);
165 os_free(bssid);
166 wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
167 "SSID value '%s'", pos);
168 return -1;
169 }
170 ssid[ssid_count].ssid_len = (end - pos) / 2;
171 wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
172 ssid[ssid_count].ssid,
173 ssid[ssid_count].ssid_len);
174 ssid_count++;
175 pos = end;
176 } else {
177 wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
178 "'%s'", pos);
179 os_free(ssid);
180 os_free(bssid);
181 return -1;
182 }
183
184 pos = os_strchr(pos, ' ');
185 if (pos)
186 pos++;
187 }
188
189 wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
190 os_free(wpa_s->disallow_aps_bssid);
191 wpa_s->disallow_aps_bssid = bssid;
192 wpa_s->disallow_aps_bssid_count = count;
193
194 wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
195 os_free(wpa_s->disallow_aps_ssid);
196 wpa_s->disallow_aps_ssid = ssid;
197 wpa_s->disallow_aps_ssid_count = ssid_count;
198
199 if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
200 return 0;
201
202 c = wpa_s->current_ssid;
203 if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
204 return 0;
205
206 if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
207 !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
208 return 0;
209
210 wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
211 "because current AP was marked disallowed");
212
213#ifdef CONFIG_SME
214 wpa_s->sme.prev_bssid_set = 0;
215#endif /* CONFIG_SME */
216 wpa_s->reassociate = 1;
c2805909 217 wpa_s->own_disconnect_req = 1;
6407f413
JM
218 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
219 wpa_supplicant_req_scan(wpa_s, 0, 0);
220
221 return 0;
222}
223
224
1120e452
JM
225#ifndef CONFIG_NO_CONFIG_BLOBS
226static int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos)
227{
228 char *name = pos;
229 struct wpa_config_blob *blob;
230 size_t len;
231
232 pos = os_strchr(pos, ' ');
233 if (pos == NULL)
234 return -1;
235 *pos++ = '\0';
236 len = os_strlen(pos);
237 if (len & 1)
238 return -1;
239
240 wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name);
241 blob = os_zalloc(sizeof(*blob));
242 if (blob == NULL)
243 return -1;
244 blob->name = os_strdup(name);
245 blob->data = os_malloc(len / 2);
246 if (blob->name == NULL || blob->data == NULL) {
247 wpa_config_free_blob(blob);
248 return -1;
249 }
250
251 if (hexstr2bin(pos, blob->data, len / 2) < 0) {
252 wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data");
253 wpa_config_free_blob(blob);
254 return -1;
255 }
256 blob->len = len / 2;
257
258 wpa_config_set_blob(wpa_s->conf, blob);
259
260 return 0;
261}
262#endif /* CONFIG_NO_CONFIG_BLOBS */
263
d3c9c35f
DS
264
265static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
266{
267 char *params;
268 char *pos;
269 int *freqs = NULL;
270 int ret;
271
272 if (atoi(cmd)) {
273 params = os_strchr(cmd, ' ');
274 os_free(wpa_s->manual_sched_scan_freqs);
275 if (params) {
276 params++;
277 pos = os_strstr(params, "freq=");
278 if (pos)
279 freqs = freq_range_to_channel_list(wpa_s,
280 pos + 5);
281 }
282 wpa_s->manual_sched_scan_freqs = freqs;
283 ret = wpas_start_pno(wpa_s);
284 } else {
285 ret = wpas_stop_pno(wpa_s);
286 }
287 return ret;
288}
289
290
844dfeb8
SD
291static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
292{
293 union wpa_event_data event;
294
295 if (os_strcmp(band, "AUTO") == 0)
296 wpa_s->setband = WPA_SETBAND_AUTO;
297 else if (os_strcmp(band, "5G") == 0)
298 wpa_s->setband = WPA_SETBAND_5G;
299 else if (os_strcmp(band, "2G") == 0)
300 wpa_s->setband = WPA_SETBAND_2G;
301 else
302 return -1;
303
304 if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) {
305 os_memset(&event, 0, sizeof(event));
306 event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
307 event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
308 wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event);
309 }
310
311 return 0;
312}
313
314
4a742011
DS
315static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s,
316 const char *cmd)
317{
318 struct wpabuf *lci;
319
320 if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
321 wpabuf_free(wpa_s->lci);
322 wpa_s->lci = NULL;
323 return 0;
324 }
325
326 lci = wpabuf_parse_bin(cmd);
327 if (!lci)
328 return -1;
329
330 if (os_get_reltime(&wpa_s->lci_time)) {
331 wpabuf_free(lci);
332 return -1;
333 }
334
335 wpabuf_free(wpa_s->lci);
336 wpa_s->lci = lci;
337
338 return 0;
339}
340
341
57c3a605 342static int
343wpas_ctrl_set_relative_rssi(struct wpa_supplicant *wpa_s, const char *cmd)
344{
345 int relative_rssi;
346
347 if (os_strcmp(cmd, "disable") == 0) {
348 wpa_s->srp.relative_rssi_set = 0;
349 return 0;
350 }
351
352 relative_rssi = atoi(cmd);
353 if (relative_rssi < 0 || relative_rssi > 100)
354 return -1;
355 wpa_s->srp.relative_rssi = relative_rssi;
356 wpa_s->srp.relative_rssi_set = 1;
357 return 0;
358}
359
360
361static int wpas_ctrl_set_relative_band_adjust(struct wpa_supplicant *wpa_s,
362 const char *cmd)
363{
364 char *pos;
365 int adjust_rssi;
366
367 /* <band>:adjust_value */
368 pos = os_strchr(cmd, ':');
369 if (!pos)
370 return -1;
371 pos++;
372 adjust_rssi = atoi(pos);
373 if (adjust_rssi < -100 || adjust_rssi > 100)
374 return -1;
375
376 if (os_strncmp(cmd, "2G", 2) == 0)
377 wpa_s->srp.relative_adjust_band = WPA_SETBAND_2G;
378 else if (os_strncmp(cmd, "5G", 2) == 0)
379 wpa_s->srp.relative_adjust_band = WPA_SETBAND_5G;
380 else
381 return -1;
382
383 wpa_s->srp.relative_adjust_rssi = adjust_rssi;
384
385 return 0;
386}
387
388
c6c41f6e
JM
389static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s,
390 const char *cmd)
391{
392 struct wpabuf *ric_ies;
393
394 if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
395 wpabuf_free(wpa_s->ric_ies);
396 wpa_s->ric_ies = NULL;
397 return 0;
398 }
399
400 ric_ies = wpabuf_parse_bin(cmd);
401 if (!ric_ies)
402 return -1;
403
404 wpabuf_free(wpa_s->ric_ies);
405 wpa_s->ric_ies = ric_ies;
406
407 return 0;
408}
409
410
6fc6879b
JM
411static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
412 char *cmd)
413{
414 char *value;
415 int ret = 0;
416
417 value = os_strchr(cmd, ' ');
418 if (value == NULL)
419 return -1;
420 *value++ = '\0';
421
422 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
423 if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
424 eapol_sm_configure(wpa_s->eapol,
425 atoi(value), -1, -1, -1);
426 } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
427 eapol_sm_configure(wpa_s->eapol,
428 -1, atoi(value), -1, -1);
429 } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
430 eapol_sm_configure(wpa_s->eapol,
431 -1, -1, atoi(value), -1);
432 } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
433 eapol_sm_configure(wpa_s->eapol,
434 -1, -1, -1, atoi(value));
435 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
436 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
b4bdeadf 437 atoi(value))) {
6fc6879b 438 ret = -1;
b4bdeadf
JM
439 } else {
440 value[-1] = '=';
441 wpa_config_process_global(wpa_s->conf, cmd, -1);
442 }
6fc6879b
JM
443 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
444 0) {
445 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
b4bdeadf 446 atoi(value))) {
6fc6879b 447 ret = -1;
b4bdeadf
JM
448 } else {
449 value[-1] = '=';
450 wpa_config_process_global(wpa_s->conf, cmd, -1);
451 }
6fc6879b 452 } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
b4bdeadf
JM
453 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
454 atoi(value))) {
6fc6879b 455 ret = -1;
b4bdeadf
JM
456 } else {
457 value[-1] = '=';
458 wpa_config_process_global(wpa_s->conf, cmd, -1);
459 }
42f50264
JM
460 } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
461 wpa_s->wps_fragment_size = atoi(value);
b4e34f2f
JM
462#ifdef CONFIG_WPS_TESTING
463 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
464 long int val;
465 val = strtol(value, NULL, 0);
466 if (val < 0 || val > 0xff) {
467 ret = -1;
468 wpa_printf(MSG_DEBUG, "WPS: Invalid "
469 "wps_version_number %ld", val);
470 } else {
471 wps_version_number = val;
472 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
473 "version %u.%u",
474 (wps_version_number & 0xf0) >> 4,
475 wps_version_number & 0x0f);
476 }
477 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
478 wps_testing_dummy_cred = atoi(value);
479 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
480 wps_testing_dummy_cred);
91226e0d
JM
481 } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
482 wps_corrupt_pkhash = atoi(value);
483 wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
484 wps_corrupt_pkhash);
6e379c6c
JM
485 } else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) {
486 if (value[0] == '\0') {
487 wps_force_auth_types_in_use = 0;
488 } else {
489 wps_force_auth_types = strtol(value, NULL, 0);
490 wps_force_auth_types_in_use = 1;
491 }
492 } else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) {
493 if (value[0] == '\0') {
494 wps_force_encr_types_in_use = 0;
495 } else {
496 wps_force_encr_types = strtol(value, NULL, 0);
497 wps_force_encr_types_in_use = 1;
498 }
b4e34f2f 499#endif /* CONFIG_WPS_TESTING */
b6c79a99
JM
500 } else if (os_strcasecmp(cmd, "ampdu") == 0) {
501 if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
502 ret = -1;
9d2cb3ec 503#ifdef CONFIG_TDLS
5b0e6ece
JM
504#ifdef CONFIG_TDLS_TESTING
505 } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
5b0e6ece
JM
506 tdls_testing = strtol(value, NULL, 0);
507 wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
508#endif /* CONFIG_TDLS_TESTING */
b8f64582
JM
509 } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
510 int disabled = atoi(value);
511 wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
512 if (disabled) {
513 if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
514 ret = -1;
515 } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
516 ret = -1;
517 wpa_tdls_enable(wpa_s->wpa, !disabled);
518#endif /* CONFIG_TDLS */
b5c68312 519 } else if (os_strcasecmp(cmd, "pno") == 0) {
d3c9c35f 520 ret = wpas_ctrl_pno(wpa_s, value);
8b9d0bfa
JM
521 } else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
522 int disabled = atoi(value);
523 if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
524 ret = -1;
525 else if (disabled)
526 wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
aa074a64
JM
527 } else if (os_strcasecmp(cmd, "uapsd") == 0) {
528 if (os_strcmp(value, "disable") == 0)
529 wpa_s->set_sta_uapsd = 0;
530 else {
531 int be, bk, vi, vo;
532 char *pos;
533 /* format: BE,BK,VI,VO;max SP Length */
534 be = atoi(value);
535 pos = os_strchr(value, ',');
536 if (pos == NULL)
537 return -1;
538 pos++;
539 bk = atoi(pos);
540 pos = os_strchr(pos, ',');
541 if (pos == NULL)
542 return -1;
543 pos++;
544 vi = atoi(pos);
545 pos = os_strchr(pos, ',');
546 if (pos == NULL)
547 return -1;
548 pos++;
549 vo = atoi(pos);
550 /* ignore max SP Length for now */
551
552 wpa_s->set_sta_uapsd = 1;
553 wpa_s->sta_uapsd = 0;
554 if (be)
555 wpa_s->sta_uapsd |= BIT(0);
556 if (bk)
557 wpa_s->sta_uapsd |= BIT(1);
558 if (vi)
559 wpa_s->sta_uapsd |= BIT(2);
560 if (vo)
561 wpa_s->sta_uapsd |= BIT(3);
562 }
b2ff1681
JM
563 } else if (os_strcasecmp(cmd, "ps") == 0) {
564 ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
9675ce35
JM
565#ifdef CONFIG_WIFI_DISPLAY
566 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
bab6677a
JM
567 int enabled = !!atoi(value);
568 if (enabled && !wpa_s->global->p2p)
569 ret = -1;
570 else
571 wifi_display_enable(wpa_s->global, enabled);
9675ce35 572#endif /* CONFIG_WIFI_DISPLAY */
d445a5cd
JM
573 } else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
574 ret = set_bssid_filter(wpa_s, value);
6407f413
JM
575 } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
576 ret = set_disallow_aps(wpa_s, value);
2ec535fd
JM
577 } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
578 wpa_s->no_keep_alive = !!atoi(value);
60b893df
JM
579#ifdef CONFIG_TESTING_OPTIONS
580 } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
581 wpa_s->ext_mgmt_frame_handling = !!atoi(value);
9d4ff04a
JM
582 } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
583 wpa_s->ext_eapol_frame_io = !!atoi(value);
584#ifdef CONFIG_AP
585 if (wpa_s->ap_iface) {
586 wpa_s->ap_iface->bss[0]->ext_eapol_frame_io =
587 wpa_s->ext_eapol_frame_io;
588 }
589#endif /* CONFIG_AP */
1f94e4ee
JM
590 } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
591 wpa_s->extra_roc_dur = atoi(value);
911942ee
JM
592 } else if (os_strcasecmp(cmd, "test_failure") == 0) {
593 wpa_s->test_failure = atoi(value);
ed7820b4
IP
594 } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
595 wpa_s->p2p_go_csa_on_inv = !!atoi(value);
02adead5
MK
596 } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) {
597 wpa_s->ignore_auth_resp = !!atoi(value);
6ad37d73 598 } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
599 wpa_s->ignore_assoc_disallow = !!atoi(value);
a483c6f1 600 } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
601 wpa_s->reject_btm_req_reason = atoi(value);
c06fca04
JM
602 } else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) {
603 os_free(wpa_s->get_pref_freq_list_override);
604 if (!value[0])
605 wpa_s->get_pref_freq_list_override = NULL;
606 else
607 wpa_s->get_pref_freq_list_override = os_strdup(value);
60b893df 608#endif /* CONFIG_TESTING_OPTIONS */
1120e452
JM
609#ifndef CONFIG_NO_CONFIG_BLOBS
610 } else if (os_strcmp(cmd, "blob") == 0) {
611 ret = wpas_ctrl_set_blob(wpa_s, value);
612#endif /* CONFIG_NO_CONFIG_BLOBS */
209702d4 613 } else if (os_strcasecmp(cmd, "setband") == 0) {
844dfeb8 614 ret = wpas_ctrl_set_band(wpa_s, value);
92c6e2e3
DS
615#ifdef CONFIG_MBO
616 } else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
617 ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
e3394c0e
JM
618 if (ret == 0) {
619 value[-1] = '=';
620 wpa_config_process_global(wpa_s->conf, cmd, -1);
621 }
016082e9
AS
622 } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
623 wpas_mbo_update_cell_capa(wpa_s, atoi(value));
92c6e2e3 624#endif /* CONFIG_MBO */
4a742011
DS
625 } else if (os_strcasecmp(cmd, "lci") == 0) {
626 ret = wpas_ctrl_iface_set_lci(wpa_s, value);
2e4e4fb7
SD
627 } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) {
628 ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value));
57c3a605 629 } else if (os_strcasecmp(cmd, "relative_rssi") == 0) {
630 ret = wpas_ctrl_set_relative_rssi(wpa_s, value);
631 } else if (os_strcasecmp(cmd, "relative_band_adjust") == 0) {
632 ret = wpas_ctrl_set_relative_band_adjust(wpa_s, value);
c6c41f6e
JM
633 } else if (os_strcasecmp(cmd, "ric_ies") == 0) {
634 ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value);
611aea7d
JM
635 } else {
636 value[-1] = '=';
637 ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
638 if (ret == 0)
639 wpa_supplicant_update_config(wpa_s);
640 }
6fc6879b
JM
641
642 return ret;
643}
644
645
acec8d32
JM
646static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
647 char *cmd, char *buf, size_t buflen)
648{
6ce937b8 649 int res = -1;
acec8d32
JM
650
651 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
652
653 if (os_strcmp(cmd, "version") == 0) {
654 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
6ce937b8
DS
655 } else if (os_strcasecmp(cmd, "country") == 0) {
656 if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
657 res = os_snprintf(buf, buflen, "%c%c",
658 wpa_s->conf->country[0],
659 wpa_s->conf->country[1]);
9675ce35
JM
660#ifdef CONFIG_WIFI_DISPLAY
661 } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
bab6677a
JM
662 int enabled;
663 if (wpa_s->global->p2p == NULL ||
664 wpa_s->global->p2p_disabled)
665 enabled = 0;
666 else
667 enabled = wpa_s->global->wifi_display;
668 res = os_snprintf(buf, buflen, "%d", enabled);
9675ce35 669#endif /* CONFIG_WIFI_DISPLAY */
fa7ae950
JM
670#ifdef CONFIG_TESTING_GET_GTK
671 } else if (os_strcmp(cmd, "gtk") == 0) {
672 if (wpa_s->last_gtk_len == 0)
673 return -1;
674 res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
675 wpa_s->last_gtk_len);
676 return res;
677#endif /* CONFIG_TESTING_GET_GTK */
a1651451
JM
678 } else if (os_strcmp(cmd, "tls_library") == 0) {
679 res = tls_get_library_version(buf, buflen);
10263dc2
OO
680 } else {
681 res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
acec8d32
JM
682 }
683
1f102d3b 684 if (os_snprintf_error(buflen, res))
6ce937b8
DS
685 return -1;
686 return res;
acec8d32
JM
687}
688
689
ec717917 690#ifdef IEEE8021X_EAPOL
6fc6879b
JM
691static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
692 char *addr)
693{
694 u8 bssid[ETH_ALEN];
695 struct wpa_ssid *ssid = wpa_s->current_ssid;
696
697 if (hwaddr_aton(addr, bssid)) {
698 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
699 "'%s'", addr);
700 return -1;
701 }
702
703 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
704 rsn_preauth_deinit(wpa_s->wpa);
705 if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
706 return -1;
707
708 return 0;
709}
ec717917 710#endif /* IEEE8021X_EAPOL */
6fc6879b
JM
711
712
713#ifdef CONFIG_PEERKEY
714/* MLME-STKSTART.request(peer) */
715static int wpa_supplicant_ctrl_iface_stkstart(
716 struct wpa_supplicant *wpa_s, char *addr)
717{
718 u8 peer[ETH_ALEN];
719
720 if (hwaddr_aton(addr, peer)) {
721 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
a7b6c422 722 "address '%s'", addr);
6fc6879b
JM
723 return -1;
724 }
725
726 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
727 MAC2STR(peer));
728
729 return wpa_sm_stkstart(wpa_s->wpa, peer);
730}
731#endif /* CONFIG_PEERKEY */
732
733
281ff0aa
GP
734#ifdef CONFIG_TDLS
735
736static int wpa_supplicant_ctrl_iface_tdls_discover(
737 struct wpa_supplicant *wpa_s, char *addr)
738{
739 u8 peer[ETH_ALEN];
2d565a61 740 int ret;
281ff0aa
GP
741
742 if (hwaddr_aton(addr, peer)) {
743 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
744 "address '%s'", addr);
745 return -1;
746 }
747
748 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
749 MAC2STR(peer));
750
2d565a61
AN
751 if (wpa_tdls_is_external_setup(wpa_s->wpa))
752 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
753 else
754 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
755
756 return ret;
281ff0aa
GP
757}
758
759
760static int wpa_supplicant_ctrl_iface_tdls_setup(
761 struct wpa_supplicant *wpa_s, char *addr)
762{
763 u8 peer[ETH_ALEN];
94377fbc 764 int ret;
281ff0aa
GP
765
766 if (hwaddr_aton(addr, peer)) {
767 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
768 "address '%s'", addr);
769 return -1;
770 }
771
772 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
773 MAC2STR(peer));
774
800d5872
SD
775 if ((wpa_s->conf->tdls_external_control) &&
776 wpa_tdls_is_external_setup(wpa_s->wpa))
777 return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
778
3887878e
SD
779 wpa_tdls_remove(wpa_s->wpa, peer);
780
781 if (wpa_tdls_is_external_setup(wpa_s->wpa))
782 ret = wpa_tdls_start(wpa_s->wpa, peer);
783 else
784 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2d565a61 785
94377fbc 786 return ret;
281ff0aa
GP
787}
788
789
790static int wpa_supplicant_ctrl_iface_tdls_teardown(
791 struct wpa_supplicant *wpa_s, char *addr)
792{
793 u8 peer[ETH_ALEN];
4ed8d954 794 int ret;
281ff0aa 795
38ddccae
AN
796 if (os_strcmp(addr, "*") == 0) {
797 /* remove everyone */
798 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *");
799 wpa_tdls_teardown_peers(wpa_s->wpa);
800 return 0;
801 }
802
281ff0aa
GP
803 if (hwaddr_aton(addr, peer)) {
804 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
805 "address '%s'", addr);
806 return -1;
807 }
808
809 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
810 MAC2STR(peer));
811
800d5872
SD
812 if ((wpa_s->conf->tdls_external_control) &&
813 wpa_tdls_is_external_setup(wpa_s->wpa))
814 return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
815
4ed8d954
AS
816 if (wpa_tdls_is_external_setup(wpa_s->wpa))
817 ret = wpa_tdls_teardown_link(
818 wpa_s->wpa, peer,
819 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
820 else
821 ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
822
823 return ret;
281ff0aa
GP
824}
825
6e9375e4
DS
826
827static int ctrl_iface_get_capability_tdls(
828 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
829{
830 int ret;
831
832 ret = os_snprintf(buf, buflen, "%s\n",
833 wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ?
834 (wpa_s->drv_flags &
835 WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
836 "EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
7bdd8981 837 if (os_snprintf_error(buflen, ret))
6e9375e4
DS
838 return -1;
839 return ret;
840}
841
6b90deae
AN
842
843static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
844 struct wpa_supplicant *wpa_s, char *cmd)
845{
846 u8 peer[ETH_ALEN];
847 struct hostapd_freq_params freq_params;
848 u8 oper_class;
849 char *pos, *end;
850
851 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
852 wpa_printf(MSG_INFO,
853 "tdls_chanswitch: Only supported with external setup");
854 return -1;
855 }
856
857 os_memset(&freq_params, 0, sizeof(freq_params));
858
859 pos = os_strchr(cmd, ' ');
860 if (pos == NULL)
861 return -1;
862 *pos++ = '\0';
863
864 oper_class = strtol(pos, &end, 10);
865 if (pos == end) {
866 wpa_printf(MSG_INFO,
867 "tdls_chanswitch: Invalid op class provided");
868 return -1;
869 }
870
871 pos = end;
872 freq_params.freq = atoi(pos);
873 if (freq_params.freq == 0) {
874 wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
875 return -1;
876 }
877
878#define SET_FREQ_SETTING(str) \
879 do { \
880 const char *pos2 = os_strstr(pos, " " #str "="); \
881 if (pos2) { \
882 pos2 += sizeof(" " #str "=") - 1; \
883 freq_params.str = atoi(pos2); \
884 } \
885 } while (0)
886
887 SET_FREQ_SETTING(center_freq1);
888 SET_FREQ_SETTING(center_freq2);
889 SET_FREQ_SETTING(bandwidth);
890 SET_FREQ_SETTING(sec_channel_offset);
891#undef SET_FREQ_SETTING
892
893 freq_params.ht_enabled = !!os_strstr(pos, " ht");
894 freq_params.vht_enabled = !!os_strstr(pos, " vht");
895
896 if (hwaddr_aton(cmd, peer)) {
897 wpa_printf(MSG_DEBUG,
898 "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
899 cmd);
900 return -1;
901 }
902
903 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
904 " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
905 MAC2STR(peer), oper_class, freq_params.freq,
906 freq_params.center_freq1, freq_params.center_freq2,
907 freq_params.bandwidth, freq_params.sec_channel_offset,
908 freq_params.ht_enabled ? " HT" : "",
909 freq_params.vht_enabled ? " VHT" : "");
910
911 return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
912 &freq_params);
913}
914
915
916static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
917 struct wpa_supplicant *wpa_s, char *cmd)
918{
919 u8 peer[ETH_ALEN];
920
921 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
922 wpa_printf(MSG_INFO,
923 "tdls_chanswitch: Only supported with external setup");
924 return -1;
925 }
926
927 if (hwaddr_aton(cmd, peer)) {
928 wpa_printf(MSG_DEBUG,
929 "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
930 cmd);
931 return -1;
932 }
933
934 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
935 MAC2STR(peer));
936
937 return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
938}
939
4504621f
OG
940
941static int wpa_supplicant_ctrl_iface_tdls_link_status(
942 struct wpa_supplicant *wpa_s, const char *addr,
943 char *buf, size_t buflen)
944{
945 u8 peer[ETH_ALEN];
946 const char *tdls_status;
947 int ret;
948
949 if (hwaddr_aton(addr, peer)) {
950 wpa_printf(MSG_DEBUG,
951 "CTRL_IFACE TDLS_LINK_STATUS: Invalid address '%s'",
952 addr);
953 return -1;
954 }
955 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS " MACSTR,
956 MAC2STR(peer));
957
958 tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
959 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS: %s", tdls_status);
960 ret = os_snprintf(buf, buflen, "TDLS link status: %s\n", tdls_status);
961 if (os_snprintf_error(buflen, ret))
962 return -1;
963
964 return ret;
965}
966
281ff0aa
GP
967#endif /* CONFIG_TDLS */
968
969
eb2f2088
MB
970static int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd)
971{
972 char *token, *context = NULL;
973 struct wmm_ac_ts_setup_params params = {
974 .tsid = 0xff,
975 .direction = 0xff,
976 };
977
978 while ((token = str_token(cmd, " ", &context))) {
979 if (sscanf(token, "tsid=%i", &params.tsid) == 1 ||
980 sscanf(token, "up=%i", &params.user_priority) == 1 ||
981 sscanf(token, "nominal_msdu_size=%i",
982 &params.nominal_msdu_size) == 1 ||
983 sscanf(token, "mean_data_rate=%i",
984 &params.mean_data_rate) == 1 ||
985 sscanf(token, "min_phy_rate=%i",
986 &params.minimum_phy_rate) == 1 ||
987 sscanf(token, "sba=%i",
988 &params.surplus_bandwidth_allowance) == 1)
989 continue;
990
991 if (os_strcasecmp(token, "downlink") == 0) {
992 params.direction = WMM_TSPEC_DIRECTION_DOWNLINK;
993 } else if (os_strcasecmp(token, "uplink") == 0) {
994 params.direction = WMM_TSPEC_DIRECTION_UPLINK;
995 } else if (os_strcasecmp(token, "bidi") == 0) {
996 params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL;
997 } else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) {
998 params.fixed_nominal_msdu = 1;
999 } else {
1000 wpa_printf(MSG_DEBUG,
1001 "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'",
1002 token);
1003 return -1;
1004 }
1005
1006 }
1007
1008 return wpas_wmm_ac_addts(wpa_s, &params);
1009}
1010
1011
1012static int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd)
1013{
1014 u8 tsid = atoi(cmd);
1015
1016 return wpas_wmm_ac_delts(wpa_s, tsid);
1017}
1018
1019
6fc6879b
JM
1020#ifdef CONFIG_IEEE80211R
1021static int wpa_supplicant_ctrl_iface_ft_ds(
1022 struct wpa_supplicant *wpa_s, char *addr)
1023{
1024 u8 target_ap[ETH_ALEN];
76b7981d
JM
1025 struct wpa_bss *bss;
1026 const u8 *mdie;
6fc6879b
JM
1027
1028 if (hwaddr_aton(addr, target_ap)) {
1029 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
a7b6c422 1030 "address '%s'", addr);
6fc6879b
JM
1031 return -1;
1032 }
1033
1034 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
1035
76b7981d
JM
1036 bss = wpa_bss_get_bssid(wpa_s, target_ap);
1037 if (bss)
1038 mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
1039 else
1040 mdie = NULL;
1041
1042 return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
6fc6879b
JM
1043}
1044#endif /* CONFIG_IEEE80211R */
1045
1046
fcc60db4
JM
1047#ifdef CONFIG_WPS
1048static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
1049 char *cmd)
1050{
3ec97afe 1051 u8 bssid[ETH_ALEN], *_bssid = bssid;
ceb34f25 1052#ifdef CONFIG_P2P
634ce802 1053 u8 p2p_dev_addr[ETH_ALEN];
ceb34f25 1054#endif /* CONFIG_P2P */
634ce802
JM
1055#ifdef CONFIG_AP
1056 u8 *_p2p_dev_addr = NULL;
1057#endif /* CONFIG_AP */
fcc60db4 1058
d601247c 1059 if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
3ec97afe 1060 _bssid = NULL;
d601247c
JM
1061#ifdef CONFIG_P2P
1062 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
1063 if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
1064 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
1065 "P2P Device Address '%s'",
1066 cmd + 13);
1067 return -1;
1068 }
1069 _p2p_dev_addr = p2p_dev_addr;
1070#endif /* CONFIG_P2P */
1071 } else if (hwaddr_aton(cmd, bssid)) {
fcc60db4
JM
1072 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
1073 cmd);
1074 return -1;
1075 }
1076
3ec97afe
JM
1077#ifdef CONFIG_AP
1078 if (wpa_s->ap_iface)
d601247c 1079 return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
3ec97afe
JM
1080#endif /* CONFIG_AP */
1081
9fa243b2 1082 return wpas_wps_start_pbc(wpa_s, _bssid, 0);
fcc60db4
JM
1083}
1084
1085
1086static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
1087 char *cmd, char *buf,
1088 size_t buflen)
1089{
1090 u8 bssid[ETH_ALEN], *_bssid = bssid;
1091 char *pin;
1092 int ret;
1093
1094 pin = os_strchr(cmd, ' ');
1095 if (pin)
1096 *pin++ = '\0';
1097
1098 if (os_strcmp(cmd, "any") == 0)
1099 _bssid = NULL;
98aa7ca5 1100 else if (os_strcmp(cmd, "get") == 0) {
98a516ea
NL
1101 if (wps_generate_pin((unsigned int *) &ret) < 0)
1102 return -1;
98aa7ca5
JM
1103 goto done;
1104 } else if (hwaddr_aton(cmd, bssid)) {
3c1e2765 1105 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
fcc60db4
JM
1106 cmd);
1107 return -1;
1108 }
1109
3ec97afe 1110#ifdef CONFIG_AP
c423708f
JM
1111 if (wpa_s->ap_iface) {
1112 int timeout = 0;
1113 char *pos;
1114
1115 if (pin) {
1116 pos = os_strchr(pin, ' ');
1117 if (pos) {
1118 *pos++ = '\0';
1119 timeout = atoi(pos);
1120 }
1121 }
1122
3ec97afe 1123 return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
c423708f
JM
1124 buf, buflen, timeout);
1125 }
3ec97afe
JM
1126#endif /* CONFIG_AP */
1127
fcc60db4 1128 if (pin) {
3c5126a4
JM
1129 ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
1130 DEV_PW_DEFAULT);
fcc60db4
JM
1131 if (ret < 0)
1132 return -1;
1133 ret = os_snprintf(buf, buflen, "%s", pin);
d85e1fc8 1134 if (os_snprintf_error(buflen, ret))
fcc60db4
JM
1135 return -1;
1136 return ret;
1137 }
1138
3c5126a4 1139 ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
fcc60db4
JM
1140 if (ret < 0)
1141 return -1;
1142
98aa7ca5 1143done:
fcc60db4
JM
1144 /* Return the generated PIN */
1145 ret = os_snprintf(buf, buflen, "%08d", ret);
d85e1fc8 1146 if (os_snprintf_error(buflen, ret))
fcc60db4
JM
1147 return -1;
1148 return ret;
1149}
1150
1151
3981cb3c
JM
1152static int wpa_supplicant_ctrl_iface_wps_check_pin(
1153 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
1154{
1155 char pin[9];
1156 size_t len;
1157 char *pos;
1158 int ret;
1159
1160 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
1161 (u8 *) cmd, os_strlen(cmd));
1162 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
1163 if (*pos < '0' || *pos > '9')
1164 continue;
1165 pin[len++] = *pos;
1166 if (len == 9) {
1167 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
1168 return -1;
1169 }
1170 }
1171 if (len != 4 && len != 8) {
1172 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
1173 return -1;
1174 }
1175 pin[len] = '\0';
1176
1177 if (len == 8) {
1178 unsigned int pin_val;
1179 pin_val = atoi(pin);
1180 if (!wps_pin_valid(pin_val)) {
1181 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
1182 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
d85e1fc8 1183 if (os_snprintf_error(buflen, ret))
3981cb3c
JM
1184 return -1;
1185 return ret;
1186 }
1187 }
1188
1189 ret = os_snprintf(buf, buflen, "%s", pin);
d85e1fc8 1190 if (os_snprintf_error(buflen, ret))
3981cb3c
JM
1191 return -1;
1192
1193 return ret;
1194}
1195
1196
71892384 1197#ifdef CONFIG_WPS_NFC
3f2c8ba6
JM
1198
1199static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
1200 char *cmd)
1201{
1202 u8 bssid[ETH_ALEN], *_bssid = bssid;
1203
1204 if (cmd == NULL || cmd[0] == '\0')
1205 _bssid = NULL;
1206 else if (hwaddr_aton(cmd, bssid))
1207 return -1;
1208
23318bea 1209 return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
91a65018 1210 0, 0);
3f2c8ba6
JM
1211}
1212
1213
bbf41865
JM
1214static int wpa_supplicant_ctrl_iface_wps_nfc_config_token(
1215 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1216{
1217 int ndef;
1218 struct wpabuf *buf;
1219 int res;
88c8bf31 1220 char *pos;
bbf41865 1221
88c8bf31
JM
1222 pos = os_strchr(cmd, ' ');
1223 if (pos)
1224 *pos++ = '\0';
bbf41865
JM
1225 if (os_strcmp(cmd, "WPS") == 0)
1226 ndef = 0;
1227 else if (os_strcmp(cmd, "NDEF") == 0)
1228 ndef = 1;
1229 else
1230 return -1;
1231
88c8bf31 1232 buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
bbf41865
JM
1233 if (buf == NULL)
1234 return -1;
1235
1236 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1237 wpabuf_len(buf));
1238 reply[res++] = '\n';
1239 reply[res] = '\0';
1240
1241 wpabuf_free(buf);
1242
1243 return res;
1244}
1245
1246
3f2c8ba6
JM
1247static int wpa_supplicant_ctrl_iface_wps_nfc_token(
1248 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1249{
1250 int ndef;
1251 struct wpabuf *buf;
1252 int res;
1253
1254 if (os_strcmp(cmd, "WPS") == 0)
1255 ndef = 0;
1256 else if (os_strcmp(cmd, "NDEF") == 0)
1257 ndef = 1;
1258 else
1259 return -1;
1260
1261 buf = wpas_wps_nfc_token(wpa_s, ndef);
1262 if (buf == NULL)
1263 return -1;
1264
1265 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1266 wpabuf_len(buf));
1267 reply[res++] = '\n';
1268 reply[res] = '\0';
1269
1270 wpabuf_free(buf);
1271
1272 return res;
1273}
d7645d23
JM
1274
1275
1276static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
1277 struct wpa_supplicant *wpa_s, char *pos)
1278{
1279 size_t len;
1280 struct wpabuf *buf;
1281 int ret;
b56f6c88
JM
1282 char *freq;
1283 int forced_freq = 0;
1284
1285 freq = strstr(pos, " freq=");
1286 if (freq) {
1287 *freq = '\0';
1288 freq += 6;
1289 forced_freq = atoi(freq);
1290 }
d7645d23
JM
1291
1292 len = os_strlen(pos);
1293 if (len & 0x01)
1294 return -1;
1295 len /= 2;
1296
1297 buf = wpabuf_alloc(len);
1298 if (buf == NULL)
1299 return -1;
1300 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
1301 wpabuf_free(buf);
1302 return -1;
1303 }
1304
b56f6c88 1305 ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
d7645d23
JM
1306 wpabuf_free(buf);
1307
1308 return ret;
1309}
71892384 1310
e65552dd
JM
1311
1312static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
bbaaaee1 1313 char *reply, size_t max_len,
41f9ffb6 1314 int ndef)
e65552dd
JM
1315{
1316 struct wpabuf *buf;
1317 int res;
1318
41f9ffb6 1319 buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
e65552dd
JM
1320 if (buf == NULL)
1321 return -1;
1322
1323 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1324 wpabuf_len(buf));
1325 reply[res++] = '\n';
1326 reply[res] = '\0';
1327
1328 wpabuf_free(buf);
1329
1330 return res;
1331}
1332
1333
88853aed 1334#ifdef CONFIG_P2P
93588780
JM
1335static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
1336 char *reply, size_t max_len,
1337 int ndef)
1338{
1339 struct wpabuf *buf;
1340 int res;
1341
1342 buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
1343 if (buf == NULL) {
1344 wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
1345 return -1;
1346 }
1347
1348 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1349 wpabuf_len(buf));
1350 reply[res++] = '\n';
1351 reply[res] = '\0';
1352
1353 wpabuf_free(buf);
1354
1355 return res;
1356}
88853aed 1357#endif /* CONFIG_P2P */
93588780
JM
1358
1359
e65552dd
JM
1360static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
1361 char *cmd, char *reply,
1362 size_t max_len)
1363{
1364 char *pos;
41f9ffb6 1365 int ndef;
e65552dd
JM
1366
1367 pos = os_strchr(cmd, ' ');
1368 if (pos == NULL)
1369 return -1;
1370 *pos++ = '\0';
1371
41f9ffb6
JM
1372 if (os_strcmp(cmd, "WPS") == 0)
1373 ndef = 0;
1374 else if (os_strcmp(cmd, "NDEF") == 0)
1375 ndef = 1;
1376 else
e65552dd
JM
1377 return -1;
1378
bbaaaee1 1379 if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
41f9ffb6
JM
1380 if (!ndef)
1381 return -1;
bbaaaee1 1382 return wpas_ctrl_nfc_get_handover_req_wps(
41f9ffb6 1383 wpa_s, reply, max_len, ndef);
e65552dd
JM
1384 }
1385
88853aed 1386#ifdef CONFIG_P2P
93588780
JM
1387 if (os_strcmp(pos, "P2P-CR") == 0) {
1388 return wpas_ctrl_nfc_get_handover_req_p2p(
1389 wpa_s, reply, max_len, ndef);
1390 }
88853aed 1391#endif /* CONFIG_P2P */
93588780 1392
e65552dd
JM
1393 return -1;
1394}
1395
1396
1397static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
5ab9a6a5 1398 char *reply, size_t max_len,
f3f2ba2e 1399 int ndef, int cr, char *uuid)
e65552dd
JM
1400{
1401 struct wpabuf *buf;
1402 int res;
1403
f3f2ba2e 1404 buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid);
e65552dd
JM
1405 if (buf == NULL)
1406 return -1;
1407
1408 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1409 wpabuf_len(buf));
1410 reply[res++] = '\n';
1411 reply[res] = '\0';
1412
1413 wpabuf_free(buf);
1414
1415 return res;
1416}
1417
1418
88853aed 1419#ifdef CONFIG_P2P
93588780
JM
1420static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
1421 char *reply, size_t max_len,
1422 int ndef, int tag)
1423{
1424 struct wpabuf *buf;
1425 int res;
1426
1427 buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
1428 if (buf == NULL)
1429 return -1;
1430
1431 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1432 wpabuf_len(buf));
1433 reply[res++] = '\n';
1434 reply[res] = '\0';
1435
1436 wpabuf_free(buf);
1437
1438 return res;
1439}
88853aed 1440#endif /* CONFIG_P2P */
93588780
JM
1441
1442
e65552dd
JM
1443static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
1444 char *cmd, char *reply,
1445 size_t max_len)
1446{
f3f2ba2e 1447 char *pos, *pos2;
5ab9a6a5 1448 int ndef;
e65552dd
JM
1449
1450 pos = os_strchr(cmd, ' ');
1451 if (pos == NULL)
1452 return -1;
1453 *pos++ = '\0';
1454
5ab9a6a5
JM
1455 if (os_strcmp(cmd, "WPS") == 0)
1456 ndef = 0;
1457 else if (os_strcmp(cmd, "NDEF") == 0)
1458 ndef = 1;
1459 else
e65552dd
JM
1460 return -1;
1461
f3f2ba2e
JM
1462 pos2 = os_strchr(pos, ' ');
1463 if (pos2)
1464 *pos2++ = '\0';
5ab9a6a5 1465 if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
93588780
JM
1466 if (!ndef)
1467 return -1;
5ab9a6a5
JM
1468 return wpas_ctrl_nfc_get_handover_sel_wps(
1469 wpa_s, reply, max_len, ndef,
f3f2ba2e 1470 os_strcmp(pos, "WPS-CR") == 0, pos2);
e65552dd
JM
1471 }
1472
88853aed 1473#ifdef CONFIG_P2P
93588780
JM
1474 if (os_strcmp(pos, "P2P-CR") == 0) {
1475 return wpas_ctrl_nfc_get_handover_sel_p2p(
1476 wpa_s, reply, max_len, ndef, 0);
1477 }
1478
1479 if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
1480 return wpas_ctrl_nfc_get_handover_sel_p2p(
1481 wpa_s, reply, max_len, ndef, 1);
1482 }
88853aed 1483#endif /* CONFIG_P2P */
93588780 1484
e65552dd
JM
1485 return -1;
1486}
1487
1488
e4758827
JM
1489static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
1490 char *cmd)
1491{
1492 size_t len;
1493 struct wpabuf *req, *sel;
1494 int ret;
1495 char *pos, *role, *type, *pos2;
88853aed 1496#ifdef CONFIG_P2P
b56f6c88
JM
1497 char *freq;
1498 int forced_freq = 0;
1499
1500 freq = strstr(cmd, " freq=");
1501 if (freq) {
1502 *freq = '\0';
1503 freq += 6;
1504 forced_freq = atoi(freq);
1505 }
88853aed 1506#endif /* CONFIG_P2P */
e4758827
JM
1507
1508 role = cmd;
1509 pos = os_strchr(role, ' ');
73127764
JM
1510 if (pos == NULL) {
1511 wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
e4758827 1512 return -1;
73127764 1513 }
e4758827
JM
1514 *pos++ = '\0';
1515
1516 type = pos;
1517 pos = os_strchr(type, ' ');
73127764
JM
1518 if (pos == NULL) {
1519 wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
e4758827 1520 return -1;
73127764 1521 }
e4758827
JM
1522 *pos++ = '\0';
1523
1524 pos2 = os_strchr(pos, ' ');
73127764
JM
1525 if (pos2 == NULL) {
1526 wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
e4758827 1527 return -1;
73127764 1528 }
e4758827
JM
1529 *pos2++ = '\0';
1530
1531 len = os_strlen(pos);
73127764
JM
1532 if (len & 0x01) {
1533 wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
e4758827 1534 return -1;
73127764 1535 }
e4758827
JM
1536 len /= 2;
1537
1538 req = wpabuf_alloc(len);
73127764
JM
1539 if (req == NULL) {
1540 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
e4758827 1541 return -1;
73127764 1542 }
e4758827 1543 if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
73127764 1544 wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
e4758827
JM
1545 wpabuf_free(req);
1546 return -1;
1547 }
1548
1549 len = os_strlen(pos2);
1550 if (len & 0x01) {
73127764 1551 wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
e4758827
JM
1552 wpabuf_free(req);
1553 return -1;
1554 }
1555 len /= 2;
1556
1557 sel = wpabuf_alloc(len);
1558 if (sel == NULL) {
73127764 1559 wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
e4758827
JM
1560 wpabuf_free(req);
1561 return -1;
1562 }
1563 if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
73127764 1564 wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
e4758827
JM
1565 wpabuf_free(req);
1566 wpabuf_free(sel);
1567 return -1;
1568 }
1569
73127764
JM
1570 wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
1571 role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
1572
e4758827
JM
1573 if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
1574 ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
88853aed 1575#ifdef CONFIG_AP
d9507936
JM
1576 } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
1577 {
1578 ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
50d1f890
JM
1579 if (ret < 0)
1580 ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
88853aed
JM
1581#endif /* CONFIG_AP */
1582#ifdef CONFIG_P2P
db6ae69e
JM
1583 } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
1584 {
b56f6c88 1585 ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
db6ae69e
JM
1586 } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
1587 {
b56f6c88
JM
1588 ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
1589 forced_freq);
88853aed 1590#endif /* CONFIG_P2P */
e4758827
JM
1591 } else {
1592 wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
1593 "reported: role=%s type=%s", role, type);
1594 ret = -1;
1595 }
1596 wpabuf_free(req);
1597 wpabuf_free(sel);
1598
73127764
JM
1599 if (ret)
1600 wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
1601
e4758827
JM
1602 return ret;
1603}
1604
71892384 1605#endif /* CONFIG_WPS_NFC */
46bdb83a
MH
1606
1607
fcc60db4
JM
1608static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
1609 char *cmd)
1610{
129eb428 1611 u8 bssid[ETH_ALEN];
fcc60db4 1612 char *pin;
52eb293d
JM
1613 char *new_ssid;
1614 char *new_auth;
1615 char *new_encr;
1616 char *new_key;
1617 struct wps_new_ap_settings ap;
fcc60db4
JM
1618
1619 pin = os_strchr(cmd, ' ');
1620 if (pin == NULL)
1621 return -1;
1622 *pin++ = '\0';
1623
129eb428 1624 if (hwaddr_aton(cmd, bssid)) {
fcc60db4
JM
1625 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
1626 cmd);
1627 return -1;
1628 }
1629
52eb293d
JM
1630 new_ssid = os_strchr(pin, ' ');
1631 if (new_ssid == NULL)
129eb428 1632 return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
52eb293d
JM
1633 *new_ssid++ = '\0';
1634
1635 new_auth = os_strchr(new_ssid, ' ');
1636 if (new_auth == NULL)
1637 return -1;
1638 *new_auth++ = '\0';
1639
1640 new_encr = os_strchr(new_auth, ' ');
1641 if (new_encr == NULL)
1642 return -1;
1643 *new_encr++ = '\0';
1644
1645 new_key = os_strchr(new_encr, ' ');
1646 if (new_key == NULL)
1647 return -1;
1648 *new_key++ = '\0';
1649
1650 os_memset(&ap, 0, sizeof(ap));
1651 ap.ssid_hex = new_ssid;
1652 ap.auth = new_auth;
1653 ap.encr = new_encr;
1654 ap.key_hex = new_key;
129eb428 1655 return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
fcc60db4 1656}
72df2f5f
JM
1657
1658
70d84f11
JM
1659#ifdef CONFIG_AP
1660static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
1661 char *cmd, char *buf,
1662 size_t buflen)
1663{
1664 int timeout = 300;
1665 char *pos;
1666 const char *pin_txt;
1667
1668 if (!wpa_s->ap_iface)
1669 return -1;
1670
1671 pos = os_strchr(cmd, ' ');
1672 if (pos)
1673 *pos++ = '\0';
1674
1675 if (os_strcmp(cmd, "disable") == 0) {
1676 wpas_wps_ap_pin_disable(wpa_s);
1677 return os_snprintf(buf, buflen, "OK\n");
1678 }
1679
1680 if (os_strcmp(cmd, "random") == 0) {
1681 if (pos)
1682 timeout = atoi(pos);
1683 pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
1684 if (pin_txt == NULL)
1685 return -1;
1686 return os_snprintf(buf, buflen, "%s", pin_txt);
1687 }
1688
1689 if (os_strcmp(cmd, "get") == 0) {
1690 pin_txt = wpas_wps_ap_pin_get(wpa_s);
1691 if (pin_txt == NULL)
1692 return -1;
1693 return os_snprintf(buf, buflen, "%s", pin_txt);
1694 }
1695
1696 if (os_strcmp(cmd, "set") == 0) {
1697 char *pin;
1698 if (pos == NULL)
1699 return -1;
1700 pin = pos;
1701 pos = os_strchr(pos, ' ');
1702 if (pos) {
1703 *pos++ = '\0';
1704 timeout = atoi(pos);
1705 }
1706 if (os_strlen(pin) > buflen)
1707 return -1;
1708 if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
1709 return -1;
1710 return os_snprintf(buf, buflen, "%s", pin);
1711 }
1712
1713 return -1;
1714}
1715#endif /* CONFIG_AP */
1716
1717
72df2f5f
JM
1718#ifdef CONFIG_WPS_ER
1719static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
1720 char *cmd)
1721{
31fcea93
JM
1722 char *uuid = cmd, *pin, *pos;
1723 u8 addr_buf[ETH_ALEN], *addr = NULL;
72df2f5f
JM
1724 pin = os_strchr(uuid, ' ');
1725 if (pin == NULL)
1726 return -1;
1727 *pin++ = '\0';
31fcea93
JM
1728 pos = os_strchr(pin, ' ');
1729 if (pos) {
1730 *pos++ = '\0';
1731 if (hwaddr_aton(pos, addr_buf) == 0)
1732 addr = addr_buf;
1733 }
1734 return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
72df2f5f 1735}
e64dcfd5
JM
1736
1737
1738static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
1739 char *cmd)
1740{
1741 char *uuid = cmd, *pin;
1742 pin = os_strchr(uuid, ' ');
1743 if (pin == NULL)
1744 return -1;
1745 *pin++ = '\0';
1746 return wpas_wps_er_learn(wpa_s, uuid, pin);
1747}
7d6640a6
JM
1748
1749
ef10f473
JM
1750static int wpa_supplicant_ctrl_iface_wps_er_set_config(
1751 struct wpa_supplicant *wpa_s, char *cmd)
1752{
1753 char *uuid = cmd, *id;
1754 id = os_strchr(uuid, ' ');
1755 if (id == NULL)
1756 return -1;
1757 *id++ = '\0';
1758 return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
1759}
1760
1761
7d6640a6
JM
1762static int wpa_supplicant_ctrl_iface_wps_er_config(
1763 struct wpa_supplicant *wpa_s, char *cmd)
1764{
1765 char *pin;
1766 char *new_ssid;
1767 char *new_auth;
1768 char *new_encr;
1769 char *new_key;
1770 struct wps_new_ap_settings ap;
1771
1772 pin = os_strchr(cmd, ' ');
1773 if (pin == NULL)
1774 return -1;
1775 *pin++ = '\0';
1776
1777 new_ssid = os_strchr(pin, ' ');
1778 if (new_ssid == NULL)
1779 return -1;
1780 *new_ssid++ = '\0';
1781
1782 new_auth = os_strchr(new_ssid, ' ');
1783 if (new_auth == NULL)
1784 return -1;
1785 *new_auth++ = '\0';
1786
1787 new_encr = os_strchr(new_auth, ' ');
1788 if (new_encr == NULL)
1789 return -1;
1790 *new_encr++ = '\0';
1791
1792 new_key = os_strchr(new_encr, ' ');
1793 if (new_key == NULL)
1794 return -1;
1795 *new_key++ = '\0';
1796
1797 os_memset(&ap, 0, sizeof(ap));
1798 ap.ssid_hex = new_ssid;
1799 ap.auth = new_auth;
1800 ap.encr = new_encr;
1801 ap.key_hex = new_key;
1802 return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
1803}
1cea09a9
JM
1804
1805
1806#ifdef CONFIG_WPS_NFC
1807static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
1808 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1809{
1810 int ndef;
1811 struct wpabuf *buf;
1812 int res;
1813 char *uuid;
1814
1815 uuid = os_strchr(cmd, ' ');
1816 if (uuid == NULL)
1817 return -1;
1818 *uuid++ = '\0';
1819
1820 if (os_strcmp(cmd, "WPS") == 0)
1821 ndef = 0;
1822 else if (os_strcmp(cmd, "NDEF") == 0)
1823 ndef = 1;
1824 else
1825 return -1;
1826
1827 buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
1828 if (buf == NULL)
1829 return -1;
1830
1831 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1832 wpabuf_len(buf));
1833 reply[res++] = '\n';
1834 reply[res] = '\0';
1835
1836 wpabuf_free(buf);
1837
1838 return res;
1839}
1840#endif /* CONFIG_WPS_NFC */
72df2f5f
JM
1841#endif /* CONFIG_WPS_ER */
1842
fcc60db4
JM
1843#endif /* CONFIG_WPS */
1844
1845
11ef8d35
JM
1846#ifdef CONFIG_IBSS_RSN
1847static int wpa_supplicant_ctrl_iface_ibss_rsn(
1848 struct wpa_supplicant *wpa_s, char *addr)
1849{
1850 u8 peer[ETH_ALEN];
1851
1852 if (hwaddr_aton(addr, peer)) {
1853 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
a7b6c422 1854 "address '%s'", addr);
11ef8d35
JM
1855 return -1;
1856 }
1857
1858 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
1859 MAC2STR(peer));
1860
1861 return ibss_rsn_start(wpa_s->ibss_rsn, peer);
1862}
1863#endif /* CONFIG_IBSS_RSN */
1864
1865
7de5688d
DW
1866static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
1867 char *rsp)
1868{
1869#ifdef IEEE8021X_EAPOL
1870 char *pos, *id_pos;
1871 int id;
1872 struct wpa_ssid *ssid;
1873
1874 pos = os_strchr(rsp, '-');
1875 if (pos == NULL)
1876 return -1;
1877 *pos++ = '\0';
1878 id_pos = pos;
1879 pos = os_strchr(pos, ':');
1880 if (pos == NULL)
1881 return -1;
1882 *pos++ = '\0';
1883 id = atoi(id_pos);
1884 wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
1885 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1886 (u8 *) pos, os_strlen(pos));
1887
1888 ssid = wpa_config_get_network(wpa_s->conf, id);
1889 if (ssid == NULL) {
1890 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1891 "to update", id);
1892 return -1;
1893 }
1894
1895 return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
1896 pos);
6fc6879b
JM
1897#else /* IEEE8021X_EAPOL */
1898 wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1899 return -1;
1900#endif /* IEEE8021X_EAPOL */
1901}
1902
1903
1904static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
1905 const char *params,
1906 char *buf, size_t buflen)
1907{
1908 char *pos, *end, tmp[30];
0bc13468 1909 int res, verbose, wps, ret;
f9cd147d
JM
1910#ifdef CONFIG_HS20
1911 const u8 *hs20;
1912#endif /* CONFIG_HS20 */
993a8654
JM
1913 const u8 *sess_id;
1914 size_t sess_id_len;
6fc6879b 1915
a771c07d
JM
1916 if (os_strcmp(params, "-DRIVER") == 0)
1917 return wpa_drv_status(wpa_s, buf, buflen);
6fc6879b 1918 verbose = os_strcmp(params, "-VERBOSE") == 0;
0bc13468 1919 wps = os_strcmp(params, "-WPS") == 0;
6fc6879b
JM
1920 pos = buf;
1921 end = buf + buflen;
1922 if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1923 struct wpa_ssid *ssid = wpa_s->current_ssid;
1924 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
1925 MAC2STR(wpa_s->bssid));
d85e1fc8 1926 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
1927 return pos - buf;
1928 pos += ret;
b6ebdfbe
BP
1929 ret = os_snprintf(pos, end - pos, "freq=%u\n",
1930 wpa_s->assoc_freq);
d85e1fc8 1931 if (os_snprintf_error(end - pos, ret))
b6ebdfbe
BP
1932 return pos - buf;
1933 pos += ret;
6fc6879b
JM
1934 if (ssid) {
1935 u8 *_ssid = ssid->ssid;
1936 size_t ssid_len = ssid->ssid_len;
eaa8eefe 1937 u8 ssid_buf[SSID_MAX_LEN];
6fc6879b
JM
1938 if (ssid_len == 0) {
1939 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
1940 if (_res < 0)
1941 ssid_len = 0;
1942 else
1943 ssid_len = _res;
1944 _ssid = ssid_buf;
1945 }
1946 ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
1947 wpa_ssid_txt(_ssid, ssid_len),
1948 ssid->id);
d85e1fc8 1949 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
1950 return pos - buf;
1951 pos += ret;
1952
0bc13468
JM
1953 if (wps && ssid->passphrase &&
1954 wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
1955 (ssid->mode == WPAS_MODE_AP ||
1956 ssid->mode == WPAS_MODE_P2P_GO)) {
1957 ret = os_snprintf(pos, end - pos,
1958 "passphrase=%s\n",
1959 ssid->passphrase);
d85e1fc8 1960 if (os_snprintf_error(end - pos, ret))
0bc13468
JM
1961 return pos - buf;
1962 pos += ret;
1963 }
6fc6879b
JM
1964 if (ssid->id_str) {
1965 ret = os_snprintf(pos, end - pos,
1966 "id_str=%s\n",
1967 ssid->id_str);
d85e1fc8 1968 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
1969 return pos - buf;
1970 pos += ret;
1971 }
0e15e529
JM
1972
1973 switch (ssid->mode) {
d7dcba70 1974 case WPAS_MODE_INFRA:
0e15e529
JM
1975 ret = os_snprintf(pos, end - pos,
1976 "mode=station\n");
1977 break;
d7dcba70 1978 case WPAS_MODE_IBSS:
0e15e529
JM
1979 ret = os_snprintf(pos, end - pos,
1980 "mode=IBSS\n");
1981 break;
d7dcba70 1982 case WPAS_MODE_AP:
0e15e529
JM
1983 ret = os_snprintf(pos, end - pos,
1984 "mode=AP\n");
1985 break;
2c5d725c
JM
1986 case WPAS_MODE_P2P_GO:
1987 ret = os_snprintf(pos, end - pos,
1988 "mode=P2P GO\n");
1989 break;
1990 case WPAS_MODE_P2P_GROUP_FORMATION:
1991 ret = os_snprintf(pos, end - pos,
1992 "mode=P2P GO - group "
1993 "formation\n");
1994 break;
cee0be73
SB
1995 case WPAS_MODE_MESH:
1996 ret = os_snprintf(pos, end - pos,
1997 "mode=mesh\n");
1998 break;
0e15e529
JM
1999 default:
2000 ret = 0;
2001 break;
2002 }
1f102d3b 2003 if (os_snprintf_error(end - pos, ret))
0e15e529
JM
2004 return pos - buf;
2005 pos += ret;
6fc6879b
JM
2006 }
2007
43fb5297
JM
2008#ifdef CONFIG_AP
2009 if (wpa_s->ap_iface) {
2010 pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
2011 end - pos,
2012 verbose);
2013 } else
2014#endif /* CONFIG_AP */
6fc6879b
JM
2015 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
2016 }
afe73100 2017#ifdef CONFIG_SME
4954c859
JM
2018#ifdef CONFIG_SAE
2019 if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
e1ae5d74
JM
2020#ifdef CONFIG_AP
2021 !wpa_s->ap_iface &&
2022#endif /* CONFIG_AP */
2023 wpa_s->sme.sae.state == SAE_ACCEPTED) {
4954c859
JM
2024 ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
2025 wpa_s->sme.sae.group);
d85e1fc8 2026 if (os_snprintf_error(end - pos, ret))
4954c859
JM
2027 return pos - buf;
2028 pos += ret;
2029 }
2030#endif /* CONFIG_SAE */
afe73100 2031#endif /* CONFIG_SME */
6fc6879b
JM
2032 ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
2033 wpa_supplicant_state_txt(wpa_s->wpa_state));
d85e1fc8 2034 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2035 return pos - buf;
2036 pos += ret;
2037
2038 if (wpa_s->l2 &&
2039 l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
2040 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
d85e1fc8 2041 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2042 return pos - buf;
2043 pos += ret;
2044 }
2045
d23bd894
JM
2046#ifdef CONFIG_P2P
2047 if (wpa_s->global->p2p) {
2048 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
2049 "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
d85e1fc8 2050 if (os_snprintf_error(end - pos, ret))
d23bd894
JM
2051 return pos - buf;
2052 pos += ret;
2053 }
b21e2c84 2054#endif /* CONFIG_P2P */
6d4747a9
JM
2055
2056 ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
2057 MAC2STR(wpa_s->own_addr));
d85e1fc8 2058 if (os_snprintf_error(end - pos, ret))
6d4747a9
JM
2059 return pos - buf;
2060 pos += ret;
d23bd894 2061
64855b96
JM
2062#ifdef CONFIG_HS20
2063 if (wpa_s->current_bss &&
f9cd147d
JM
2064 (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss,
2065 HS20_IE_VENDOR_TYPE)) &&
4ed34f5a
JM
2066 wpa_s->wpa_proto == WPA_PROTO_RSN &&
2067 wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
f9cd147d
JM
2068 int release = 1;
2069 if (hs20[1] >= 5) {
2070 u8 rel_num = (hs20[6] & 0xf0) >> 4;
2071 release = rel_num + 1;
2072 }
2073 ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
d85e1fc8 2074 if (os_snprintf_error(end - pos, ret))
64855b96
JM
2075 return pos - buf;
2076 pos += ret;
2077 }
e99b4f3a
JM
2078
2079 if (wpa_s->current_ssid) {
2080 struct wpa_cred *cred;
2081 char *type;
2082
2083 for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
463c8ffb
JM
2084 size_t i;
2085
e99b4f3a
JM
2086 if (wpa_s->current_ssid->parent_cred != cred)
2087 continue;
e99b4f3a 2088
aa26ba68 2089 if (cred->provisioning_sp) {
463c8ffb 2090 ret = os_snprintf(pos, end - pos,
aa26ba68
JM
2091 "provisioning_sp=%s\n",
2092 cred->provisioning_sp);
d85e1fc8 2093 if (os_snprintf_error(end - pos, ret))
463c8ffb
JM
2094 return pos - buf;
2095 pos += ret;
2096 }
e99b4f3a 2097
aa26ba68
JM
2098 if (!cred->domain)
2099 goto no_domain;
2100
2101 i = 0;
2102 if (wpa_s->current_bss && wpa_s->current_bss->anqp) {
2103 struct wpabuf *names =
2104 wpa_s->current_bss->anqp->domain_name;
2105 for (i = 0; names && i < cred->num_domain; i++)
2106 {
2107 if (domain_name_list_contains(
2108 names, cred->domain[i], 1))
2109 break;
2110 }
2111 if (i == cred->num_domain)
2112 i = 0; /* show first entry by default */
2113 }
2114 ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
2115 cred->domain[i]);
d85e1fc8 2116 if (os_snprintf_error(end - pos, ret))
aa26ba68
JM
2117 return pos - buf;
2118 pos += ret;
2119
2120 no_domain:
e99b4f3a
JM
2121 if (wpa_s->current_bss == NULL ||
2122 wpa_s->current_bss->anqp == NULL)
2123 res = -1;
2124 else
2125 res = interworking_home_sp_cred(
2126 wpa_s, cred,
2127 wpa_s->current_bss->anqp->domain_name);
2128 if (res > 0)
2129 type = "home";
2130 else if (res == 0)
2131 type = "roaming";
2132 else
2133 type = "unknown";
2134
2135 ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
d85e1fc8 2136 if (os_snprintf_error(end - pos, ret))
e99b4f3a
JM
2137 return pos - buf;
2138 pos += ret;
2139
2140 break;
2141 }
2142 }
64855b96
JM
2143#endif /* CONFIG_HS20 */
2144
56586197
JM
2145 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
2146 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
6fc6879b
JM
2147 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
2148 verbose);
2149 if (res >= 0)
2150 pos += res;
2151 }
2152
7508c2ad
BA
2153#ifdef CONFIG_MACSEC
2154 res = ieee802_1x_kay_get_status(wpa_s->kay, pos, end - pos);
2155 if (res > 0)
2156 pos += res;
2157#endif /* CONFIG_MACSEC */
2158
993a8654
JM
2159 sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
2160 if (sess_id) {
2161 char *start = pos;
2162
2163 ret = os_snprintf(pos, end - pos, "eap_session_id=");
2164 if (os_snprintf_error(end - pos, ret))
2165 return start - buf;
2166 pos += ret;
2167 ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len);
2168 if (ret <= 0)
2169 return start - buf;
2170 pos += ret;
2171 ret = os_snprintf(pos, end - pos, "\n");
2172 if (os_snprintf_error(end - pos, ret))
2173 return start - buf;
2174 pos += ret;
2175 }
2176
6fc6879b
JM
2177 res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
2178 if (res >= 0)
2179 pos += res;
2180
8aaafcee
JM
2181#ifdef CONFIG_WPS
2182 {
2183 char uuid_str[100];
2184 uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
2185 ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
d85e1fc8 2186 if (os_snprintf_error(end - pos, ret))
8aaafcee
JM
2187 return pos - buf;
2188 pos += ret;
2189 }
2190#endif /* CONFIG_WPS */
2191
f6c2b8c3 2192#ifdef ANDROID
a6ab82d7 2193 /*
2194 * Allow using the STATUS command with default behavior, say for debug,
2195 * i.e., don't generate a "fake" CONNECTION and SUPPLICANT_STATE_CHANGE
2196 * events with STATUS-NO_EVENTS.
2197 */
2198 if (os_strcmp(params, "-NO_EVENTS")) {
2199 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
2200 "id=%d state=%d BSSID=" MACSTR " SSID=%s",
2201 wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
2202 wpa_s->wpa_state,
2203 MAC2STR(wpa_s->bssid),
2204 wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
2205 wpa_ssid_txt(wpa_s->current_ssid->ssid,
2206 wpa_s->current_ssid->ssid_len) : "");
2207 if (wpa_s->wpa_state == WPA_COMPLETED) {
2208 struct wpa_ssid *ssid = wpa_s->current_ssid;
2209 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
2210 "- connection to " MACSTR
2211 " completed %s [id=%d id_str=%s]",
2212 MAC2STR(wpa_s->bssid), "(auth)",
2213 ssid ? ssid->id : -1,
2214 ssid && ssid->id_str ? ssid->id_str : "");
2215 }
f6c2b8c3
DS
2216 }
2217#endif /* ANDROID */
2218
6fc6879b
JM
2219 return pos - buf;
2220}
2221
2222
2223static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
2224 char *cmd)
2225{
2226 char *pos;
2227 int id;
2228 struct wpa_ssid *ssid;
2229 u8 bssid[ETH_ALEN];
2230
2231 /* cmd: "<network id> <BSSID>" */
2232 pos = os_strchr(cmd, ' ');
2233 if (pos == NULL)
2234 return -1;
2235 *pos++ = '\0';
2236 id = atoi(cmd);
2237 wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
2238 if (hwaddr_aton(pos, bssid)) {
2239 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
2240 return -1;
2241 }
2242
2243 ssid = wpa_config_get_network(wpa_s->conf, id);
2244 if (ssid == NULL) {
2245 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
2246 "to update", id);
2247 return -1;
2248 }
2249
2250 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
a8e16edc 2251 ssid->bssid_set = !is_zero_ether_addr(bssid);
6fc6879b
JM
2252
2253 return 0;
2254}
2255
2256
9aa10e2b
DS
2257static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
2258 char *cmd, char *buf,
2259 size_t buflen)
2260{
2261 u8 bssid[ETH_ALEN];
2262 struct wpa_blacklist *e;
2263 char *pos, *end;
2264 int ret;
2265
2266 /* cmd: "BLACKLIST [<BSSID>]" */
2267 if (*cmd == '\0') {
2268 pos = buf;
2269 end = buf + buflen;
2270 e = wpa_s->blacklist;
2271 while (e) {
2272 ret = os_snprintf(pos, end - pos, MACSTR "\n",
2273 MAC2STR(e->bssid));
d85e1fc8 2274 if (os_snprintf_error(end - pos, ret))
9aa10e2b
DS
2275 return pos - buf;
2276 pos += ret;
2277 e = e->next;
2278 }
2279 return pos - buf;
2280 }
2281
2282 cmd++;
2283 if (os_strncmp(cmd, "clear", 5) == 0) {
2284 wpa_blacklist_clear(wpa_s);
2285 os_memcpy(buf, "OK\n", 3);
2286 return 3;
2287 }
2288
2289 wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
2290 if (hwaddr_aton(cmd, bssid)) {
2291 wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
2292 return -1;
2293 }
2294
2295 /*
2296 * Add the BSSID twice, so its count will be 2, causing it to be
2297 * skipped when processing scan results.
2298 */
2299 ret = wpa_blacklist_add(wpa_s, bssid);
bd8838a3 2300 if (ret < 0)
9aa10e2b
DS
2301 return -1;
2302 ret = wpa_blacklist_add(wpa_s, bssid);
bd8838a3 2303 if (ret < 0)
9aa10e2b
DS
2304 return -1;
2305 os_memcpy(buf, "OK\n", 3);
2306 return 3;
2307}
2308
2309
0597a5b5
DS
2310static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
2311 char *cmd, char *buf,
2312 size_t buflen)
2313{
2314 char *pos, *end, *stamp;
2315 int ret;
2316
0597a5b5
DS
2317 /* cmd: "LOG_LEVEL [<level>]" */
2318 if (*cmd == '\0') {
2319 pos = buf;
2320 end = buf + buflen;
2321 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
2322 "Timestamp: %d\n",
2323 debug_level_str(wpa_debug_level),
2324 wpa_debug_timestamp);
d85e1fc8 2325 if (os_snprintf_error(end - pos, ret))
0597a5b5
DS
2326 ret = 0;
2327
2328 return ret;
2329 }
2330
2331 while (*cmd == ' ')
2332 cmd++;
2333
2334 stamp = os_strchr(cmd, ' ');
2335 if (stamp) {
2336 *stamp++ = '\0';
2337 while (*stamp == ' ') {
2338 stamp++;
2339 }
2340 }
2341
137b2939 2342 if (os_strlen(cmd)) {
0597a5b5
DS
2343 int level = str_to_debug_level(cmd);
2344 if (level < 0)
2345 return -1;
2346 wpa_debug_level = level;
2347 }
2348
2349 if (stamp && os_strlen(stamp))
2350 wpa_debug_timestamp = atoi(stamp);
2351
2352 os_memcpy(buf, "OK\n", 3);
2353 return 3;
2354}
2355
2356
6fc6879b 2357static int wpa_supplicant_ctrl_iface_list_networks(
90903a77 2358 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
6fc6879b 2359{
f34891a3 2360 char *pos, *end, *prev;
6fc6879b
JM
2361 struct wpa_ssid *ssid;
2362 int ret;
2363
2364 pos = buf;
2365 end = buf + buflen;
2366 ret = os_snprintf(pos, end - pos,
2367 "network id / ssid / bssid / flags\n");
d85e1fc8 2368 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2369 return pos - buf;
2370 pos += ret;
2371
2372 ssid = wpa_s->conf->ssid;
90903a77
VD
2373
2374 /* skip over ssids until we find next one */
2375 if (cmd != NULL && os_strncmp(cmd, "LAST_ID=", 8) == 0) {
2376 int last_id = atoi(cmd + 8);
2377 if (last_id != -1) {
2378 while (ssid != NULL && ssid->id <= last_id) {
2379 ssid = ssid->next;
2380 }
2381 }
2382 }
2383
6fc6879b 2384 while (ssid) {
f34891a3 2385 prev = pos;
6fc6879b
JM
2386 ret = os_snprintf(pos, end - pos, "%d\t%s",
2387 ssid->id,
2388 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
d85e1fc8 2389 if (os_snprintf_error(end - pos, ret))
f34891a3 2390 return prev - buf;
6fc6879b
JM
2391 pos += ret;
2392 if (ssid->bssid_set) {
2393 ret = os_snprintf(pos, end - pos, "\t" MACSTR,
2394 MAC2STR(ssid->bssid));
2395 } else {
2396 ret = os_snprintf(pos, end - pos, "\tany");
2397 }
d85e1fc8 2398 if (os_snprintf_error(end - pos, ret))
f34891a3 2399 return prev - buf;
6fc6879b 2400 pos += ret;
00e5e3d5 2401 ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
6fc6879b
JM
2402 ssid == wpa_s->current_ssid ?
2403 "[CURRENT]" : "",
4dac0245 2404 ssid->disabled ? "[DISABLED]" : "",
00e5e3d5
JM
2405 ssid->disabled_until.sec ?
2406 "[TEMP-DISABLED]" : "",
4dac0245
JM
2407 ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
2408 "");
d85e1fc8 2409 if (os_snprintf_error(end - pos, ret))
f34891a3 2410 return prev - buf;
6fc6879b
JM
2411 pos += ret;
2412 ret = os_snprintf(pos, end - pos, "\n");
d85e1fc8 2413 if (os_snprintf_error(end - pos, ret))
f34891a3 2414 return prev - buf;
6fc6879b
JM
2415 pos += ret;
2416
2417 ssid = ssid->next;
2418 }
2419
2420 return pos - buf;
2421}
2422
2423
2424static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
2425{
0282a8c4 2426 int ret;
6fc6879b 2427 ret = os_snprintf(pos, end - pos, "-");
d85e1fc8 2428 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2429 return pos;
2430 pos += ret;
0282a8c4
JM
2431 ret = wpa_write_ciphers(pos, end, cipher, "+");
2432 if (ret < 0)
2433 return pos;
2434 pos += ret;
6fc6879b
JM
2435 return pos;
2436}
2437
2438
2439static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
2440 const u8 *ie, size_t ie_len)
2441{
2442 struct wpa_ie_data data;
ea3b8c1d
JM
2443 char *start;
2444 int ret;
6fc6879b
JM
2445
2446 ret = os_snprintf(pos, end - pos, "[%s-", proto);
d85e1fc8 2447 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2448 return pos;
2449 pos += ret;
2450
2451 if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
2452 ret = os_snprintf(pos, end - pos, "?]");
d85e1fc8 2453 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2454 return pos;
2455 pos += ret;
2456 return pos;
2457 }
2458
ea3b8c1d 2459 start = pos;
6fc6879b 2460 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
ea3b8c1d
JM
2461 ret = os_snprintf(pos, end - pos, "%sEAP",
2462 pos == start ? "" : "+");
d85e1fc8 2463 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2464 return pos;
2465 pos += ret;
6fc6879b
JM
2466 }
2467 if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
ea3b8c1d
JM
2468 ret = os_snprintf(pos, end - pos, "%sPSK",
2469 pos == start ? "" : "+");
d85e1fc8 2470 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2471 return pos;
2472 pos += ret;
6fc6879b
JM
2473 }
2474 if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
ea3b8c1d
JM
2475 ret = os_snprintf(pos, end - pos, "%sNone",
2476 pos == start ? "" : "+");
d85e1fc8 2477 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2478 return pos;
2479 pos += ret;
6fc6879b 2480 }
be6b29f6
JA
2481 if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
2482 ret = os_snprintf(pos, end - pos, "%sSAE",
2483 pos == start ? "" : "+");
d85e1fc8 2484 if (os_snprintf_error(end - pos, ret))
be6b29f6
JA
2485 return pos;
2486 pos += ret;
2487 }
6fc6879b
JM
2488#ifdef CONFIG_IEEE80211R
2489 if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
2490 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
ea3b8c1d 2491 pos == start ? "" : "+");
d85e1fc8 2492 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2493 return pos;
2494 pos += ret;
6fc6879b
JM
2495 }
2496 if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
2497 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
ea3b8c1d 2498 pos == start ? "" : "+");
d85e1fc8 2499 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2500 return pos;
2501 pos += ret;
6fc6879b 2502 }
be6b29f6
JA
2503 if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
2504 ret = os_snprintf(pos, end - pos, "%sFT/SAE",
2505 pos == start ? "" : "+");
d85e1fc8 2506 if (os_snprintf_error(end - pos, ret))
be6b29f6
JA
2507 return pos;
2508 pos += ret;
2509 }
6fc6879b 2510#endif /* CONFIG_IEEE80211R */
56586197
JM
2511#ifdef CONFIG_IEEE80211W
2512 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
2513 ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
ea3b8c1d 2514 pos == start ? "" : "+");
d85e1fc8 2515 if (os_snprintf_error(end - pos, ret))
56586197
JM
2516 return pos;
2517 pos += ret;
56586197
JM
2518 }
2519 if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
2520 ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
ea3b8c1d 2521 pos == start ? "" : "+");
d85e1fc8 2522 if (os_snprintf_error(end - pos, ret))
56586197
JM
2523 return pos;
2524 pos += ret;
56586197
JM
2525 }
2526#endif /* CONFIG_IEEE80211W */
6fc6879b 2527
5e3b5197 2528#ifdef CONFIG_SUITEB
666497c8
JM
2529 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
2530 ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
2531 pos == start ? "" : "+");
d85e1fc8 2532 if (os_snprintf_error(end - pos, ret))
666497c8
JM
2533 return pos;
2534 pos += ret;
2535 }
5e3b5197
JM
2536#endif /* CONFIG_SUITEB */
2537
2538#ifdef CONFIG_SUITEB192
2539 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
2540 ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
2541 pos == start ? "" : "+");
2542 if (os_snprintf_error(end - pos, ret))
2543 return pos;
2544 pos += ret;
2545 }
2546#endif /* CONFIG_SUITEB192 */
666497c8 2547
7147a834
JM
2548#ifdef CONFIG_FILS
2549 if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
2550 ret = os_snprintf(pos, end - pos, "%sFILS-SHA256",
2551 pos == start ? "" : "+");
2552 if (os_snprintf_error(end - pos, ret))
2553 return pos;
2554 pos += ret;
2555 }
2556 if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
2557 ret = os_snprintf(pos, end - pos, "%sFILS-SHA384",
2558 pos == start ? "" : "+");
2559 if (os_snprintf_error(end - pos, ret))
2560 return pos;
2561 pos += ret;
2562 }
2563#ifdef CONFIG_IEEE80211R
2564 if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
2565 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256",
2566 pos == start ? "" : "+");
2567 if (os_snprintf_error(end - pos, ret))
2568 return pos;
2569 pos += ret;
2570 }
2571 if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
2572 ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384",
2573 pos == start ? "" : "+");
2574 if (os_snprintf_error(end - pos, ret))
2575 return pos;
2576 pos += ret;
2577 }
2578#endif /* CONFIG_IEEE80211R */
2579#endif /* CONFIG_FILS */
2580
0f8385e6
BG
2581 if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
2582 ret = os_snprintf(pos, end - pos, "%sOSEN",
2583 pos == start ? "" : "+");
2584 if (os_snprintf_error(end - pos, ret))
2585 return pos;
2586 pos += ret;
2587 }
2588
6fc6879b
JM
2589 pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
2590
2591 if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
2592 ret = os_snprintf(pos, end - pos, "-preauth");
d85e1fc8 2593 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2594 return pos;
2595 pos += ret;
2596 }
2597
2598 ret = os_snprintf(pos, end - pos, "]");
d85e1fc8 2599 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2600 return pos;
2601 pos += ret;
2602
2603 return pos;
2604}
2605
3a068632 2606
eef7d7a1 2607#ifdef CONFIG_WPS
31fcea93
JM
2608static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
2609 char *pos, char *end,
3a068632
JM
2610 struct wpabuf *wps_ie)
2611{
eef7d7a1
JM
2612 int ret;
2613 const char *txt;
2614
eef7d7a1
JM
2615 if (wps_ie == NULL)
2616 return pos;
eef7d7a1
JM
2617 if (wps_is_selected_pbc_registrar(wps_ie))
2618 txt = "[WPS-PBC]";
31fcea93
JM
2619 else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
2620 txt = "[WPS-AUTH]";
eef7d7a1
JM
2621 else if (wps_is_selected_pin_registrar(wps_ie))
2622 txt = "[WPS-PIN]";
2623 else
2624 txt = "[WPS]";
2625
2626 ret = os_snprintf(pos, end - pos, "%s", txt);
a80ba67a 2627 if (!os_snprintf_error(end - pos, ret))
eef7d7a1
JM
2628 pos += ret;
2629 wpabuf_free(wps_ie);
3a068632
JM
2630 return pos;
2631}
2632#endif /* CONFIG_WPS */
2633
2634
31fcea93
JM
2635static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
2636 char *pos, char *end,
16b71ac2 2637 const struct wpa_bss *bss)
3a068632
JM
2638{
2639#ifdef CONFIG_WPS
2640 struct wpabuf *wps_ie;
2641 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
31fcea93 2642 return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
3a068632 2643#else /* CONFIG_WPS */
eef7d7a1 2644 return pos;
3a068632 2645#endif /* CONFIG_WPS */
eef7d7a1
JM
2646}
2647
6fc6879b
JM
2648
2649/* Format one result on one text line into a buffer. */
2650static int wpa_supplicant_ctrl_iface_scan_result(
31fcea93 2651 struct wpa_supplicant *wpa_s,
16b71ac2 2652 const struct wpa_bss *bss, char *buf, size_t buflen)
6fc6879b
JM
2653{
2654 char *pos, *end;
2655 int ret;
0f8385e6 2656 const u8 *ie, *ie2, *osen_ie, *p2p, *mesh;
0c6b310e 2657
638d9456 2658 mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
0c6b310e 2659 p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
bb50ae43
JM
2660 if (!p2p)
2661 p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
0c6b310e
JM
2662 if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
2663 os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
2664 0)
2665 return 0; /* Do not show P2P listen discovery results here */
6fc6879b
JM
2666
2667 pos = buf;
2668 end = buf + buflen;
2669
2670 ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
16b71ac2 2671 MAC2STR(bss->bssid), bss->freq, bss->level);
d85e1fc8 2672 if (os_snprintf_error(end - pos, ret))
fb0e5bd7 2673 return -1;
6fc6879b 2674 pos += ret;
16b71ac2 2675 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
6fc6879b
JM
2676 if (ie)
2677 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
16b71ac2 2678 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
638d9456
JA
2679 if (ie2) {
2680 pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
2681 ie2, 2 + ie2[1]);
2682 }
0f8385e6
BG
2683 osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
2684 if (osen_ie)
2685 pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
2686 osen_ie, 2 + osen_ie[1]);
31fcea93 2687 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
0f8385e6 2688 if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {
6fc6879b 2689 ret = os_snprintf(pos, end - pos, "[WEP]");
d85e1fc8 2690 if (os_snprintf_error(end - pos, ret))
fb0e5bd7 2691 return -1;
6fc6879b
JM
2692 pos += ret;
2693 }
638d9456
JA
2694 if (mesh) {
2695 ret = os_snprintf(pos, end - pos, "[MESH]");
d85e1fc8 2696 if (os_snprintf_error(end - pos, ret))
638d9456
JA
2697 return -1;
2698 pos += ret;
2699 }
e403ba85
BS
2700 if (bss_is_dmg(bss)) {
2701 const char *s;
2702 ret = os_snprintf(pos, end - pos, "[DMG]");
d85e1fc8 2703 if (os_snprintf_error(end - pos, ret))
fb0e5bd7 2704 return -1;
6fc6879b 2705 pos += ret;
e403ba85
BS
2706 switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
2707 case IEEE80211_CAP_DMG_IBSS:
2708 s = "[IBSS]";
2709 break;
2710 case IEEE80211_CAP_DMG_AP:
2711 s = "[ESS]";
2712 break;
2713 case IEEE80211_CAP_DMG_PBSS:
2714 s = "[PBSS]";
2715 break;
2716 default:
2717 s = "";
2718 break;
2719 }
2720 ret = os_snprintf(pos, end - pos, "%s", s);
d85e1fc8 2721 if (os_snprintf_error(end - pos, ret))
fb0e5bd7 2722 return -1;
bd1af96a 2723 pos += ret;
e403ba85
BS
2724 } else {
2725 if (bss->caps & IEEE80211_CAP_IBSS) {
2726 ret = os_snprintf(pos, end - pos, "[IBSS]");
d85e1fc8 2727 if (os_snprintf_error(end - pos, ret))
e403ba85
BS
2728 return -1;
2729 pos += ret;
2730 }
2731 if (bss->caps & IEEE80211_CAP_ESS) {
2732 ret = os_snprintf(pos, end - pos, "[ESS]");
d85e1fc8 2733 if (os_snprintf_error(end - pos, ret))
e403ba85
BS
2734 return -1;
2735 pos += ret;
2736 }
bd1af96a 2737 }
0c6b310e
JM
2738 if (p2p) {
2739 ret = os_snprintf(pos, end - pos, "[P2P]");
d85e1fc8 2740 if (os_snprintf_error(end - pos, ret))
fb0e5bd7 2741 return -1;
0c6b310e
JM
2742 pos += ret;
2743 }
64855b96 2744#ifdef CONFIG_HS20
4ed34f5a 2745 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
64855b96 2746 ret = os_snprintf(pos, end - pos, "[HS20]");
d85e1fc8 2747 if (os_snprintf_error(end - pos, ret))
64855b96
JM
2748 return -1;
2749 pos += ret;
2750 }
2751#endif /* CONFIG_HS20 */
7147a834
JM
2752#ifdef CONFIG_FILS
2753 if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
2754 ret = os_snprintf(pos, end - pos, "[FILS]");
2755 if (os_snprintf_error(end - pos, ret))
2756 return -1;
2757 pos += ret;
2758 }
2759#endif /* CONFIG_FILS */
55de4d4b
AN
2760#ifdef CONFIG_FST
2761 if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) {
2762 ret = os_snprintf(pos, end - pos, "[FST]");
2763 if (os_snprintf_error(end - pos, ret))
2764 return -1;
2765 pos += ret;
2766 }
2767#endif /* CONFIG_FST */
6fc6879b 2768
6fc6879b 2769 ret = os_snprintf(pos, end - pos, "\t%s",
16b71ac2 2770 wpa_ssid_txt(bss->ssid, bss->ssid_len));
d85e1fc8 2771 if (os_snprintf_error(end - pos, ret))
fb0e5bd7 2772 return -1;
6fc6879b
JM
2773 pos += ret;
2774
2775 ret = os_snprintf(pos, end - pos, "\n");
d85e1fc8 2776 if (os_snprintf_error(end - pos, ret))
fb0e5bd7 2777 return -1;
6fc6879b
JM
2778 pos += ret;
2779
2780 return pos - buf;
2781}
2782
2783
2784static int wpa_supplicant_ctrl_iface_scan_results(
2785 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2786{
2787 char *pos, *end;
16b71ac2 2788 struct wpa_bss *bss;
6fc6879b 2789 int ret;
6fc6879b
JM
2790
2791 pos = buf;
2792 end = buf + buflen;
2793 ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
2794 "flags / ssid\n");
d85e1fc8 2795 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
2796 return pos - buf;
2797 pos += ret;
2798
16b71ac2 2799 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
31fcea93 2800 ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
6fc6879b
JM
2801 end - pos);
2802 if (ret < 0 || ret >= end - pos)
2803 return pos - buf;
2804 pos += ret;
2805 }
2806
2807 return pos - buf;
2808}
2809
2810
603a3f34
JL
2811#ifdef CONFIG_MESH
2812
5b78493f
MH
2813static int wpa_supplicant_ctrl_iface_mesh_interface_add(
2814 struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
2815{
2816 char *pos, ifname[IFNAMSIZ + 1];
2817
2818 ifname[0] = '\0';
2819
2820 pos = os_strstr(cmd, "ifname=");
2821 if (pos) {
2822 pos += 7;
2823 os_strlcpy(ifname, pos, sizeof(ifname));
2824 }
2825
2826 if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
2827 return -1;
2828
2829 os_strlcpy(reply, ifname, max_len);
2830 return os_strlen(ifname);
2831}
2832
2833
603a3f34
JL
2834static int wpa_supplicant_ctrl_iface_mesh_group_add(
2835 struct wpa_supplicant *wpa_s, char *cmd)
2836{
2837 int id;
2838 struct wpa_ssid *ssid;
2839
2840 id = atoi(cmd);
2841 wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
2842
2843 ssid = wpa_config_get_network(wpa_s->conf, id);
2844 if (ssid == NULL) {
2845 wpa_printf(MSG_DEBUG,
2846 "CTRL_IFACE: Could not find network id=%d", id);
2847 return -1;
2848 }
2849 if (ssid->mode != WPAS_MODE_MESH) {
2850 wpa_printf(MSG_DEBUG,
2851 "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network");
2852 return -1;
2853 }
0c6099f3
MH
2854 if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
2855 ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
2856 wpa_printf(MSG_ERROR,
2857 "CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
2858 return -1;
2859 }
603a3f34
JL
2860
2861 /*
2862 * TODO: If necessary write our own group_add function,
2863 * for now we can reuse select_network
2864 */
2865 wpa_supplicant_select_network(wpa_s, ssid);
2866
2867 return 0;
2868}
2869
2870
2871static int wpa_supplicant_ctrl_iface_mesh_group_remove(
2872 struct wpa_supplicant *wpa_s, char *cmd)
2873{
5b78493f
MH
2874 struct wpa_supplicant *orig;
2875 struct wpa_global *global;
2876 int found = 0;
2877
2878 wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
2879
2880 global = wpa_s->global;
2881 orig = wpa_s;
2882
2883 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
2884 if (os_strcmp(wpa_s->ifname, cmd) == 0) {
2885 found = 1;
2886 break;
2887 }
2888 }
2889 if (!found) {
2890 wpa_printf(MSG_ERROR,
2891 "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
603a3f34
JL
2892 cmd);
2893 return -1;
2894 }
5b78493f
MH
2895 if (wpa_s->mesh_if_created && wpa_s == orig) {
2896 wpa_printf(MSG_ERROR,
2897 "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
2898 return -1;
2899 }
603a3f34
JL
2900
2901 wpa_s->reassociate = 0;
2902 wpa_s->disconnected = 1;
2903 wpa_supplicant_cancel_sched_scan(wpa_s);
2904 wpa_supplicant_cancel_scan(wpa_s);
2905
2906 /*
2907 * TODO: If necessary write our own group_remove function,
2908 * for now we can reuse deauthenticate
2909 */
2910 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
2911
5b78493f
MH
2912 if (wpa_s->mesh_if_created)
2913 wpa_supplicant_remove_iface(global, wpa_s, 0);
2914
603a3f34
JL
2915 return 0;
2916}
2917
e174ef34
MH
2918
2919static int wpa_supplicant_ctrl_iface_mesh_peer_remove(
2920 struct wpa_supplicant *wpa_s, char *cmd)
2921{
2922 u8 addr[ETH_ALEN];
2923
2924 if (hwaddr_aton(cmd, addr) < 0)
2925 return -1;
2926
2927 return wpas_mesh_peer_remove(wpa_s, addr);
2928}
2929
2604edbf
MH
2930
2931static int wpa_supplicant_ctrl_iface_mesh_peer_add(
2932 struct wpa_supplicant *wpa_s, char *cmd)
2933{
2934 u8 addr[ETH_ALEN];
9f2cf23e
MH
2935 int duration;
2936 char *pos;
2937
2938 pos = os_strstr(cmd, " duration=");
2939 if (pos) {
2940 *pos = '\0';
2941 duration = atoi(pos + 10);
2942 } else {
2943 duration = -1;
2944 }
2604edbf
MH
2945
2946 if (hwaddr_aton(cmd, addr))
2947 return -1;
2948
9f2cf23e 2949 return wpas_mesh_peer_add(wpa_s, addr, duration);
2604edbf
MH
2950}
2951
603a3f34
JL
2952#endif /* CONFIG_MESH */
2953
2954
6fc6879b
JM
2955static int wpa_supplicant_ctrl_iface_select_network(
2956 struct wpa_supplicant *wpa_s, char *cmd)
2957{
2958 int id;
2959 struct wpa_ssid *ssid;
204c9ac4 2960 char *pos;
6fc6879b
JM
2961
2962 /* cmd: "<network id>" or "any" */
204c9ac4 2963 if (os_strncmp(cmd, "any", 3) == 0) {
6fc6879b 2964 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
86b89452
WS
2965 ssid = NULL;
2966 } else {
2967 id = atoi(cmd);
2968 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
6fc6879b 2969
86b89452
WS
2970 ssid = wpa_config_get_network(wpa_s->conf, id);
2971 if (ssid == NULL) {
2972 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2973 "network id=%d", id);
2974 return -1;
2975 }
4dac0245
JM
2976 if (ssid->disabled == 2) {
2977 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2978 "SELECT_NETWORK with persistent P2P group");
2979 return -1;
2980 }
6fc6879b
JM
2981 }
2982
204c9ac4
DS
2983 pos = os_strstr(cmd, " freq=");
2984 if (pos) {
2985 int *freqs = freq_range_to_channel_list(wpa_s, pos + 6);
2986 if (freqs) {
88a44755
JM
2987 os_free(wpa_s->select_network_scan_freqs);
2988 wpa_s->select_network_scan_freqs = freqs;
204c9ac4
DS
2989 }
2990 }
2991
dfaf11d6
JM
2992 wpa_s->scan_min_time.sec = 0;
2993 wpa_s->scan_min_time.usec = 0;
86b89452 2994 wpa_supplicant_select_network(wpa_s, ssid);
6fc6879b
JM
2995
2996 return 0;
2997}
2998
2999
3000static int wpa_supplicant_ctrl_iface_enable_network(
3001 struct wpa_supplicant *wpa_s, char *cmd)
3002{
3003 int id;
3004 struct wpa_ssid *ssid;
3005
3006 /* cmd: "<network id>" or "all" */
3007 if (os_strcmp(cmd, "all") == 0) {
3008 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
86b89452
WS
3009 ssid = NULL;
3010 } else {
3011 id = atoi(cmd);
3012 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
6fc6879b 3013
86b89452
WS
3014 ssid = wpa_config_get_network(wpa_s->conf, id);
3015 if (ssid == NULL) {
3016 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3017 "network id=%d", id);
3018 return -1;
3019 }
4dac0245
JM
3020 if (ssid->disabled == 2) {
3021 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
3022 "ENABLE_NETWORK with persistent P2P group");
3023 return -1;
3024 }
84c78f95
JM
3025
3026 if (os_strstr(cmd, " no-connect")) {
3027 ssid->disabled = 0;
3028 return 0;
3029 }
6fc6879b 3030 }
dfaf11d6
JM
3031 wpa_s->scan_min_time.sec = 0;
3032 wpa_s->scan_min_time.usec = 0;
86b89452 3033 wpa_supplicant_enable_network(wpa_s, ssid);
6fc6879b
JM
3034
3035 return 0;
3036}
3037
3038
3039static int wpa_supplicant_ctrl_iface_disable_network(
3040 struct wpa_supplicant *wpa_s, char *cmd)
3041{
3042 int id;
3043 struct wpa_ssid *ssid;
3044
3045 /* cmd: "<network id>" or "all" */
3046 if (os_strcmp(cmd, "all") == 0) {
3047 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
86b89452
WS
3048 ssid = NULL;
3049 } else {
3050 id = atoi(cmd);
3051 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
6fc6879b 3052
86b89452
WS
3053 ssid = wpa_config_get_network(wpa_s->conf, id);
3054 if (ssid == NULL) {
3055 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3056 "network id=%d", id);
3057 return -1;
3058 }
4dac0245
JM
3059 if (ssid->disabled == 2) {
3060 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
3061 "DISABLE_NETWORK with persistent P2P "
3062 "group");
3063 return -1;
3064 }
6fc6879b 3065 }
86b89452 3066 wpa_supplicant_disable_network(wpa_s, ssid);
6fc6879b
JM
3067
3068 return 0;
3069}
3070
3071
3072static int wpa_supplicant_ctrl_iface_add_network(
3073 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
3074{
3075 struct wpa_ssid *ssid;
3076 int ret;
3077
3078 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
3079
d015bb05 3080 ssid = wpa_supplicant_add_network(wpa_s);
6fc6879b
JM
3081 if (ssid == NULL)
3082 return -1;
8bac466b 3083
6fc6879b 3084 ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
d85e1fc8 3085 if (os_snprintf_error(buflen, ret))
6fc6879b
JM
3086 return -1;
3087 return ret;
3088}
3089
3090
3091static int wpa_supplicant_ctrl_iface_remove_network(
3092 struct wpa_supplicant *wpa_s, char *cmd)
3093{
3094 int id;
3095 struct wpa_ssid *ssid;
d015bb05 3096 int result;
6fc6879b
JM
3097
3098 /* cmd: "<network id>" or "all" */
3099 if (os_strcmp(cmd, "all") == 0) {
3100 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
725fc39e
DS
3101 if (wpa_s->sched_scanning)
3102 wpa_supplicant_cancel_sched_scan(wpa_s);
3103
d8a790b9 3104 eapol_sm_invalidate_cached_session(wpa_s->eapol);
6fc6879b 3105 if (wpa_s->current_ssid) {
83df8149
JM
3106#ifdef CONFIG_SME
3107 wpa_s->sme.prev_bssid_set = 0;
3108#endif /* CONFIG_SME */
20a0b03d
JM
3109 wpa_sm_set_config(wpa_s->wpa, NULL);
3110 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
e66bcedd
JM
3111 if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3112 wpa_s->own_disconnect_req = 1;
07783eaa
JM
3113 wpa_supplicant_deauthenticate(
3114 wpa_s, WLAN_REASON_DEAUTH_LEAVING);
6fc6879b 3115 }
391f4925
JK
3116 ssid = wpa_s->conf->ssid;
3117 while (ssid) {
3118 struct wpa_ssid *remove_ssid = ssid;
3119 id = ssid->id;
3120 ssid = ssid->next;
c267753b
JM
3121 if (wpa_s->last_ssid == remove_ssid)
3122 wpa_s->last_ssid = NULL;
391f4925
JK
3123 wpas_notify_network_removed(wpa_s, remove_ssid);
3124 wpa_config_remove_network(wpa_s->conf, id);
3125 }
6fc6879b
JM
3126 return 0;
3127 }
3128
3129 id = atoi(cmd);
3130 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
3131
d015bb05
RP
3132 result = wpa_supplicant_remove_network(wpa_s, id);
3133 if (result == -1) {
6fc6879b
JM
3134 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
3135 "id=%d", id);
3136 return -1;
3137 }
d015bb05 3138 if (result == -2) {
59ff6653
DG
3139 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
3140 "network id=%d", id);
3141 return -1;
3142 }
6fc6879b
JM
3143 return 0;
3144}
3145
3146
1c330a2f
DS
3147static int wpa_supplicant_ctrl_iface_update_network(
3148 struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
3149 char *name, char *value)
3150{
5cd317d3
BKB
3151 int ret;
3152
3153 ret = wpa_config_set(ssid, name, value, 0);
3154 if (ret < 0) {
1c330a2f
DS
3155 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
3156 "variable '%s'", name);
3157 return -1;
3158 }
5cd317d3
BKB
3159 if (ret == 1)
3160 return 0; /* No change to the previously configured value */
1c330a2f
DS
3161
3162 if (os_strcmp(name, "bssid") != 0 &&
c3dc68e8 3163 os_strcmp(name, "priority") != 0) {
1c330a2f
DS
3164 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
3165
c3dc68e8
JM
3166 if (wpa_s->current_ssid == ssid ||
3167 wpa_s->current_ssid == NULL) {
3168 /*
3169 * Invalidate the EAP session cache if anything in the
3170 * current or previously used configuration changes.
3171 */
3172 eapol_sm_invalidate_cached_session(wpa_s->eapol);
3173 }
1c330a2f
DS
3174 }
3175
3176 if ((os_strcmp(name, "psk") == 0 &&
3177 value[0] == '"' && ssid->ssid_len) ||
3178 (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
3179 wpa_config_update_psk(ssid);
3180 else if (os_strcmp(name, "priority") == 0)
3181 wpa_config_update_prio_list(wpa_s->conf);
3182
3183 return 0;
3184}
3185
3186
6fc6879b
JM
3187static int wpa_supplicant_ctrl_iface_set_network(
3188 struct wpa_supplicant *wpa_s, char *cmd)
3189{
1e529832 3190 int id, ret, prev_bssid_set, prev_disabled;
6fc6879b
JM
3191 struct wpa_ssid *ssid;
3192 char *name, *value;
0ef023e4 3193 u8 prev_bssid[ETH_ALEN];
6fc6879b
JM
3194
3195 /* cmd: "<network id> <variable name> <value>" */
3196 name = os_strchr(cmd, ' ');
3197 if (name == NULL)
3198 return -1;
3199 *name++ = '\0';
3200
3201 value = os_strchr(name, ' ');
3202 if (value == NULL)
3203 return -1;
3204 *value++ = '\0';
3205
3206 id = atoi(cmd);
3207 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
3208 id, name);
3209 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
3210 (u8 *) value, os_strlen(value));
3211
3212 ssid = wpa_config_get_network(wpa_s->conf, id);
3213 if (ssid == NULL) {
3214 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
3215 "id=%d", id);
3216 return -1;
3217 }
3218
0ef023e4 3219 prev_bssid_set = ssid->bssid_set;
1e529832 3220 prev_disabled = ssid->disabled;
0ef023e4
JM
3221 os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
3222 ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
3223 value);
3224 if (ret == 0 &&
3225 (ssid->bssid_set != prev_bssid_set ||
3226 os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
3227 wpas_notify_network_bssid_set_changed(wpa_s, ssid);
1e529832
JM
3228
3229 if (prev_disabled != ssid->disabled &&
3230 (prev_disabled == 2 || ssid->disabled == 2))
3231 wpas_notify_network_type_changed(wpa_s, ssid);
3232
0ef023e4 3233 return ret;
6fc6879b
JM
3234}
3235
3236
3237static int wpa_supplicant_ctrl_iface_get_network(
3238 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
3239{
3240 int id;
3241 size_t res;
3242 struct wpa_ssid *ssid;
3243 char *name, *value;
3244
3245 /* cmd: "<network id> <variable name>" */
3246 name = os_strchr(cmd, ' ');
3247 if (name == NULL || buflen == 0)
3248 return -1;
3249 *name++ = '\0';
3250
3251 id = atoi(cmd);
8db9a79d 3252 wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
6fc6879b
JM
3253 id, name);
3254
3255 ssid = wpa_config_get_network(wpa_s->conf, id);
3256 if (ssid == NULL) {
8db9a79d 3257 wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Could not find network "
6fc6879b
JM
3258 "id=%d", id);
3259 return -1;
3260 }
3261
3262 value = wpa_config_get_no_key(ssid, name);
3263 if (value == NULL) {
8db9a79d 3264 wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Failed to get network "
6fc6879b
JM
3265 "variable '%s'", name);
3266 return -1;
3267 }
3268
3269 res = os_strlcpy(buf, value, buflen);
3270 if (res >= buflen) {
3271 os_free(value);
3272 return -1;
3273 }
3274
3275 os_free(value);
3276
3277 return res;
3278}
3279
3280
1c330a2f 3281static int wpa_supplicant_ctrl_iface_dup_network(
daae4995
AN
3282 struct wpa_supplicant *wpa_s, char *cmd,
3283 struct wpa_supplicant *dst_wpa_s)
1c330a2f
DS
3284{
3285 struct wpa_ssid *ssid_s, *ssid_d;
3286 char *name, *id, *value;
3287 int id_s, id_d, ret;
3288
3289 /* cmd: "<src network id> <dst network id> <variable name>" */
3290 id = os_strchr(cmd, ' ');
3291 if (id == NULL)
3292 return -1;
3293 *id++ = '\0';
3294
3295 name = os_strchr(id, ' ');
3296 if (name == NULL)
3297 return -1;
3298 *name++ = '\0';
3299
3300 id_s = atoi(cmd);
3301 id_d = atoi(id);
daae4995
AN
3302
3303 wpa_printf(MSG_DEBUG,
3304 "CTRL_IFACE: DUP_NETWORK ifname=%s->%s id=%d->%d name='%s'",
3305 wpa_s->ifname, dst_wpa_s->ifname, id_s, id_d, name);
1c330a2f
DS
3306
3307 ssid_s = wpa_config_get_network(wpa_s->conf, id_s);
3308 if (ssid_s == NULL) {
3309 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3310 "network id=%d", id_s);
3311 return -1;
3312 }
3313
daae4995 3314 ssid_d = wpa_config_get_network(dst_wpa_s->conf, id_d);
1c330a2f
DS
3315 if (ssid_d == NULL) {
3316 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
c0541906 3317 "network id=%d", id_d);
1c330a2f
DS
3318 return -1;
3319 }
3320
3321 value = wpa_config_get(ssid_s, name);
3322 if (value == NULL) {
3323 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
3324 "variable '%s'", name);
3325 return -1;
3326 }
3327
daae4995 3328 ret = wpa_supplicant_ctrl_iface_update_network(dst_wpa_s, ssid_d, name,
1c330a2f
DS
3329 value);
3330
3331 os_free(value);
3332
3333 return ret;
3334}
3335
3336
d94c9ee6
JM
3337static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
3338 char *buf, size_t buflen)
3339{
3340 char *pos, *end;
3341 struct wpa_cred *cred;
3342 int ret;
3343
3344 pos = buf;
3345 end = buf + buflen;
3346 ret = os_snprintf(pos, end - pos,
3347 "cred id / realm / username / domain / imsi\n");
d85e1fc8 3348 if (os_snprintf_error(end - pos, ret))
d94c9ee6
JM
3349 return pos - buf;
3350 pos += ret;
3351
3352 cred = wpa_s->conf->cred;
3353 while (cred) {
3354 ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
3355 cred->id, cred->realm ? cred->realm : "",
3356 cred->username ? cred->username : "",
463c8ffb 3357 cred->domain ? cred->domain[0] : "",
d94c9ee6 3358 cred->imsi ? cred->imsi : "");
d85e1fc8 3359 if (os_snprintf_error(end - pos, ret))
d94c9ee6
JM
3360 return pos - buf;
3361 pos += ret;
3362
3363 cred = cred->next;
3364 }
3365
3366 return pos - buf;
3367}
3368
3369
3370static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
3371 char *buf, size_t buflen)
3372{
3373 struct wpa_cred *cred;
3374 int ret;
3375
3376 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
3377
3378 cred = wpa_config_add_cred(wpa_s->conf);
3379 if (cred == NULL)
3380 return -1;
3381
1619e9d5
JM
3382 wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id);
3383
d94c9ee6 3384 ret = os_snprintf(buf, buflen, "%d\n", cred->id);
d85e1fc8 3385 if (os_snprintf_error(buflen, ret))
d94c9ee6
JM
3386 return -1;
3387 return ret;
3388}
3389
3390
736d4f2d
JM
3391static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
3392 struct wpa_cred *cred)
3393{
3394 struct wpa_ssid *ssid;
3395 char str[20];
1619e9d5 3396 int id;
736d4f2d 3397
1619e9d5 3398 if (cred == NULL) {
736d4f2d
JM
3399 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3400 return -1;
3401 }
3402
1619e9d5
JM
3403 id = cred->id;
3404 if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
3405 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3406 return -1;
3407 }
3408
3409 wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
3410
736d4f2d
JM
3411 /* Remove any network entry created based on the removed credential */
3412 ssid = wpa_s->conf->ssid;
3413 while (ssid) {
3414 if (ssid->parent_cred == cred) {
1d399771
JM
3415 int res;
3416
736d4f2d
JM
3417 wpa_printf(MSG_DEBUG, "Remove network id %d since it "
3418 "used the removed credential", ssid->id);
1d399771
JM
3419 res = os_snprintf(str, sizeof(str), "%d", ssid->id);
3420 if (os_snprintf_error(sizeof(str), res))
3421 str[sizeof(str) - 1] = '\0';
736d4f2d
JM
3422 ssid = ssid->next;
3423 wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
3424 } else
3425 ssid = ssid->next;
3426 }
3427
3428 return 0;
3429}
3430
3431
d94c9ee6
JM
3432static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
3433 char *cmd)
3434{
3435 int id;
736d4f2d 3436 struct wpa_cred *cred, *prev;
d94c9ee6 3437
aa26ba68
JM
3438 /* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or
3439 * "provisioning_sp=<FQDN> */
d94c9ee6
JM
3440 if (os_strcmp(cmd, "all") == 0) {
3441 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
3442 cred = wpa_s->conf->cred;
3443 while (cred) {
736d4f2d 3444 prev = cred;
d94c9ee6 3445 cred = cred->next;
736d4f2d 3446 wpas_ctrl_remove_cred(wpa_s, prev);
d94c9ee6
JM
3447 }
3448 return 0;
3449 }
3450
9afe52eb
JM
3451 if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
3452 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
3453 cmd + 8);
3454 cred = wpa_s->conf->cred;
3455 while (cred) {
3456 prev = cred;
3457 cred = cred->next;
463c8ffb
JM
3458 if (prev->domain) {
3459 size_t i;
3460 for (i = 0; i < prev->num_domain; i++) {
3461 if (os_strcmp(prev->domain[i], cmd + 8)
3462 != 0)
3463 continue;
3464 wpas_ctrl_remove_cred(wpa_s, prev);
3465 break;
3466 }
3467 }
9afe52eb
JM
3468 }
3469 return 0;
3470 }
3471
aa26ba68
JM
3472 if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) {
3473 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'",
3474 cmd + 16);
3475 cred = wpa_s->conf->cred;
3476 while (cred) {
3477 prev = cred;
3478 cred = cred->next;
3479 if (prev->provisioning_sp &&
3480 os_strcmp(prev->provisioning_sp, cmd + 16) == 0)
3481 wpas_ctrl_remove_cred(wpa_s, prev);
3482 }
3483 return 0;
3484 }
3485
d94c9ee6
JM
3486 id = atoi(cmd);
3487 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
3488
3489 cred = wpa_config_get_cred(wpa_s->conf, id);
736d4f2d 3490 return wpas_ctrl_remove_cred(wpa_s, cred);
d94c9ee6
JM
3491}
3492
3493
3494static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
3495 char *cmd)
3496{
3497 int id;
3498 struct wpa_cred *cred;
3499 char *name, *value;
3500
3501 /* cmd: "<cred id> <variable name> <value>" */
3502 name = os_strchr(cmd, ' ');
3503 if (name == NULL)
3504 return -1;
3505 *name++ = '\0';
3506
3507 value = os_strchr(name, ' ');
3508 if (value == NULL)
3509 return -1;
3510 *value++ = '\0';
3511
3512 id = atoi(cmd);
3513 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
3514 id, name);
3515 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
3516 (u8 *) value, os_strlen(value));
3517
3518 cred = wpa_config_get_cred(wpa_s->conf, id);
3519 if (cred == NULL) {
3520 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3521 id);
3522 return -1;
3523 }
3524
3525 if (wpa_config_set_cred(cred, name, value, 0) < 0) {
3526 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
3527 "variable '%s'", name);
3528 return -1;
3529 }
3530
1619e9d5
JM
3531 wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name);
3532
d94c9ee6
JM
3533 return 0;
3534}
3535
3536
c880ab87
JM
3537static int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s,
3538 char *cmd, char *buf,
3539 size_t buflen)
3540{
3541 int id;
3542 size_t res;
3543 struct wpa_cred *cred;
3544 char *name, *value;
3545
3546 /* cmd: "<cred id> <variable name>" */
3547 name = os_strchr(cmd, ' ');
3548 if (name == NULL)
3549 return -1;
3550 *name++ = '\0';
3551
3552 id = atoi(cmd);
3553 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'",
3554 id, name);
3555
3556 cred = wpa_config_get_cred(wpa_s->conf, id);
3557 if (cred == NULL) {
3558 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3559 id);
3560 return -1;
3561 }
3562
3563 value = wpa_config_get_cred_no_key(cred, name);
3564 if (value == NULL) {
3565 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'",
3566 name);
3567 return -1;
3568 }
3569
3570 res = os_strlcpy(buf, value, buflen);
3571 if (res >= buflen) {
3572 os_free(value);
3573 return -1;
3574 }
3575
3576 os_free(value);
3577
3578 return res;
3579}
3580
3581
6fc6879b
JM
3582#ifndef CONFIG_NO_CONFIG_WRITE
3583static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
3584{
3585 int ret;
3586
3587 if (!wpa_s->conf->update_config) {
3588 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
3589 "to update configuration (update_config=0)");
3590 return -1;
3591 }
3592
3593 ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
3594 if (ret) {
3595 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
3596 "update configuration");
3597 } else {
3598 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
3599 " updated");
3600 }
3601
3602 return ret;
3603}
3604#endif /* CONFIG_NO_CONFIG_WRITE */
3605
3606
4daa011b
JM
3607struct cipher_info {
3608 unsigned int capa;
3609 const char *name;
3610 int group_only;
3611};
3612
3613static const struct cipher_info ciphers[] = {
3614 { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
3615 { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
3616 { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
3617 { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
3618 { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
3619 { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
3620 { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
3621 { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
3622};
3623
b5f045de
JM
3624static const struct cipher_info ciphers_group_mgmt[] = {
3625 { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 },
3626 { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 },
3627 { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 },
3628 { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 },
3629};
3630
4daa011b 3631
6fc6879b
JM
3632static int ctrl_iface_get_capability_pairwise(int res, char *strict,
3633 struct wpa_driver_capa *capa,
3634 char *buf, size_t buflen)
3635{
ea3b8c1d 3636 int ret;
6fc6879b
JM
3637 char *pos, *end;
3638 size_t len;
4daa011b 3639 unsigned int i;
6fc6879b
JM
3640
3641 pos = buf;
3642 end = pos + buflen;
3643
3644 if (res < 0) {
3645 if (strict)
3646 return 0;
3647 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
3648 if (len >= buflen)
3649 return -1;
3650 return len;
3651 }
3652
4daa011b
JM
3653 for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3654 if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
3655 ret = os_snprintf(pos, end - pos, "%s%s",
ea3b8c1d
JM
3656 pos == buf ? "" : " ",
3657 ciphers[i].name);
d85e1fc8 3658 if (os_snprintf_error(end - pos, ret))
4daa011b
JM
3659 return pos - buf;
3660 pos += ret;
4daa011b 3661 }
6fc6879b
JM
3662 }
3663
3664 return pos - buf;
3665}
3666
3667
3668static int ctrl_iface_get_capability_group(int res, char *strict,
3669 struct wpa_driver_capa *capa,
3670 char *buf, size_t buflen)
3671{
ea3b8c1d 3672 int ret;
6fc6879b
JM
3673 char *pos, *end;
3674 size_t len;
4daa011b 3675 unsigned int i;
6fc6879b
JM
3676
3677 pos = buf;
3678 end = pos + buflen;
3679
3680 if (res < 0) {
3681 if (strict)
3682 return 0;
3683 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
3684 if (len >= buflen)
3685 return -1;
3686 return len;
3687 }
3688
4daa011b
JM
3689 for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3690 if (capa->enc & ciphers[i].capa) {
3691 ret = os_snprintf(pos, end - pos, "%s%s",
ea3b8c1d
JM
3692 pos == buf ? "" : " ",
3693 ciphers[i].name);
d85e1fc8 3694 if (os_snprintf_error(end - pos, ret))
4daa011b
JM
3695 return pos - buf;
3696 pos += ret;
4daa011b 3697 }
6fc6879b
JM
3698 }
3699
3700 return pos - buf;
3701}
3702
3703
b5f045de
JM
3704static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
3705 struct wpa_driver_capa *capa,
3706 char *buf, size_t buflen)
3707{
3708 int ret;
3709 char *pos, *end;
3710 unsigned int i;
3711
3712 pos = buf;
3713 end = pos + buflen;
3714
3715 if (res < 0)
3716 return 0;
3717
3718 for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) {
3719 if (capa->enc & ciphers_group_mgmt[i].capa) {
3720 ret = os_snprintf(pos, end - pos, "%s%s",
3721 pos == buf ? "" : " ",
3722 ciphers_group_mgmt[i].name);
3723 if (os_snprintf_error(end - pos, ret))
3724 return pos - buf;
3725 pos += ret;
3726 }
3727 }
3728
3729 return pos - buf;
3730}
3731
3732
6fc6879b
JM
3733static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
3734 struct wpa_driver_capa *capa,
3735 char *buf, size_t buflen)
3736{
3737 int ret;
3738 char *pos, *end;
3739 size_t len;
3740
3741 pos = buf;
3742 end = pos + buflen;
3743
3744 if (res < 0) {
3745 if (strict)
3746 return 0;
3747 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
3748 "NONE", buflen);
3749 if (len >= buflen)
3750 return -1;
3751 return len;
3752 }
3753
3754 ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
d85e1fc8 3755 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
3756 return pos - buf;
3757 pos += ret;
3758
3759 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3760 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
3761 ret = os_snprintf(pos, end - pos, " WPA-EAP");
d85e1fc8 3762 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
3763 return pos - buf;
3764 pos += ret;
3765 }
3766
3767 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
3768 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
3769 ret = os_snprintf(pos, end - pos, " WPA-PSK");
d85e1fc8 3770 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
3771 return pos - buf;
3772 pos += ret;
3773 }
3774
3775 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
3776 ret = os_snprintf(pos, end - pos, " WPA-NONE");
d85e1fc8 3777 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
3778 return pos - buf;
3779 pos += ret;
3780 }
3781
399e6135
JM
3782#ifdef CONFIG_SUITEB
3783 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
3784 ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
3785 if (os_snprintf_error(end - pos, ret))
3786 return pos - buf;
3787 pos += ret;
3788 }
3789#endif /* CONFIG_SUITEB */
3790#ifdef CONFIG_SUITEB192
3791 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
3792 ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
3793 if (os_snprintf_error(end - pos, ret))
3794 return pos - buf;
3795 pos += ret;
3796 }
3797#endif /* CONFIG_SUITEB192 */
3798
6fc6879b
JM
3799 return pos - buf;
3800}
3801
3802
3803static int ctrl_iface_get_capability_proto(int res, char *strict,
3804 struct wpa_driver_capa *capa,
3805 char *buf, size_t buflen)
3806{
ea3b8c1d 3807 int ret;
6fc6879b
JM
3808 char *pos, *end;
3809 size_t len;
3810
3811 pos = buf;
3812 end = pos + buflen;
3813
3814 if (res < 0) {
3815 if (strict)
3816 return 0;
3817 len = os_strlcpy(buf, "RSN WPA", buflen);
3818 if (len >= buflen)
3819 return -1;
3820 return len;
3821 }
3822
3823 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
3824 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
ea3b8c1d
JM
3825 ret = os_snprintf(pos, end - pos, "%sRSN",
3826 pos == buf ? "" : " ");
d85e1fc8 3827 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
3828 return pos - buf;
3829 pos += ret;
6fc6879b
JM
3830 }
3831
3832 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3833 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
ea3b8c1d
JM
3834 ret = os_snprintf(pos, end - pos, "%sWPA",
3835 pos == buf ? "" : " ");
d85e1fc8 3836 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
3837 return pos - buf;
3838 pos += ret;
6fc6879b
JM
3839 }
3840
3841 return pos - buf;
3842}
3843
3844
db5adfe7
JM
3845static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
3846 int res, char *strict,
6fc6879b
JM
3847 struct wpa_driver_capa *capa,
3848 char *buf, size_t buflen)
3849{
ea3b8c1d 3850 int ret;
6fc6879b
JM
3851 char *pos, *end;
3852 size_t len;
3853
3854 pos = buf;
3855 end = pos + buflen;
3856
3857 if (res < 0) {
3858 if (strict)
3859 return 0;
3860 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
3861 if (len >= buflen)
3862 return -1;
3863 return len;
3864 }
3865
3866 if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
ea3b8c1d
JM
3867 ret = os_snprintf(pos, end - pos, "%sOPEN",
3868 pos == buf ? "" : " ");
d85e1fc8 3869 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
3870 return pos - buf;
3871 pos += ret;
6fc6879b
JM
3872 }
3873
3874 if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
3875 ret = os_snprintf(pos, end - pos, "%sSHARED",
ea3b8c1d 3876 pos == buf ? "" : " ");
d85e1fc8 3877 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
3878 return pos - buf;
3879 pos += ret;
6fc6879b
JM
3880 }
3881
3882 if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
ea3b8c1d
JM
3883 ret = os_snprintf(pos, end - pos, "%sLEAP",
3884 pos == buf ? "" : " ");
d85e1fc8 3885 if (os_snprintf_error(end - pos, ret))
6fc6879b
JM
3886 return pos - buf;
3887 pos += ret;
6fc6879b
JM
3888 }
3889
db5adfe7
JM
3890#ifdef CONFIG_SAE
3891 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
3892 ret = os_snprintf(pos, end - pos, "%sSAE",
3893 pos == buf ? "" : " ");
3894 if (os_snprintf_error(end - pos, ret))
3895 return pos - buf;
3896 pos += ret;
3897 }
3898#endif /* CONFIG_SAE */
3899
6fc6879b
JM
3900 return pos - buf;
3901}
3902
3903
65d52fc1
BR
3904static int ctrl_iface_get_capability_modes(int res, char *strict,
3905 struct wpa_driver_capa *capa,
3906 char *buf, size_t buflen)
3907{
ea3b8c1d 3908 int ret;
65d52fc1
BR
3909 char *pos, *end;
3910 size_t len;
3911
3912 pos = buf;
3913 end = pos + buflen;
3914
3915 if (res < 0) {
3916 if (strict)
3917 return 0;
3918 len = os_strlcpy(buf, "IBSS AP", buflen);
3919 if (len >= buflen)
3920 return -1;
3921 return len;
3922 }
3923
3924 if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
ea3b8c1d
JM
3925 ret = os_snprintf(pos, end - pos, "%sIBSS",
3926 pos == buf ? "" : " ");
d85e1fc8 3927 if (os_snprintf_error(end - pos, ret))
65d52fc1
BR
3928 return pos - buf;
3929 pos += ret;
65d52fc1
BR
3930 }
3931
3932 if (capa->flags & WPA_DRIVER_FLAGS_AP) {
ea3b8c1d
JM
3933 ret = os_snprintf(pos, end - pos, "%sAP",
3934 pos == buf ? "" : " ");
d85e1fc8 3935 if (os_snprintf_error(end - pos, ret))
65d52fc1
BR
3936 return pos - buf;
3937 pos += ret;
65d52fc1
BR
3938 }
3939
cf08e9b1
JM
3940#ifdef CONFIG_MESH
3941 if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
3942 ret = os_snprintf(pos, end - pos, "%sMESH",
3943 pos == buf ? "" : " ");
3944 if (os_snprintf_error(end - pos, ret))
3945 return pos - buf;
3946 pos += ret;
3947 }
3948#endif /* CONFIG_MESH */
3949
65d52fc1
BR
3950 return pos - buf;
3951}
3952
3953
35aa088a
DS
3954static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
3955 char *buf, size_t buflen)
3956{
3957 struct hostapd_channel_data *chnl;
3958 int ret, i, j;
3959 char *pos, *end, *hmode;
3960
3961 pos = buf;
3962 end = pos + buflen;
3963
3964 for (j = 0; j < wpa_s->hw.num_modes; j++) {
3965 switch (wpa_s->hw.modes[j].mode) {
3966 case HOSTAPD_MODE_IEEE80211B:
3967 hmode = "B";
3968 break;
3969 case HOSTAPD_MODE_IEEE80211G:
3970 hmode = "G";
3971 break;
3972 case HOSTAPD_MODE_IEEE80211A:
3973 hmode = "A";
3974 break;
7829894c
VK
3975 case HOSTAPD_MODE_IEEE80211AD:
3976 hmode = "AD";
3977 break;
35aa088a
DS
3978 default:
3979 continue;
3980 }
3981 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
d85e1fc8 3982 if (os_snprintf_error(end - pos, ret))
35aa088a
DS
3983 return pos - buf;
3984 pos += ret;
3985 chnl = wpa_s->hw.modes[j].channels;
3986 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
3987 if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
3988 continue;
3989 ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
d85e1fc8 3990 if (os_snprintf_error(end - pos, ret))
35aa088a
DS
3991 return pos - buf;
3992 pos += ret;
3993 }
3994 ret = os_snprintf(pos, end - pos, "\n");
d85e1fc8 3995 if (os_snprintf_error(end - pos, ret))
35aa088a
DS
3996 return pos - buf;
3997 pos += ret;
3998 }
3999
4000 return pos - buf;
4001}
4002
4003
06060522
BR
4004static int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s,
4005 char *buf, size_t buflen)
4006{
4007 struct hostapd_channel_data *chnl;
4008 int ret, i, j;
4009 char *pos, *end, *hmode;
4010
4011 pos = buf;
4012 end = pos + buflen;
4013
4014 for (j = 0; j < wpa_s->hw.num_modes; j++) {
4015 switch (wpa_s->hw.modes[j].mode) {
4016 case HOSTAPD_MODE_IEEE80211B:
4017 hmode = "B";
4018 break;
4019 case HOSTAPD_MODE_IEEE80211G:
4020 hmode = "G";
4021 break;
4022 case HOSTAPD_MODE_IEEE80211A:
4023 hmode = "A";
4024 break;
4025 case HOSTAPD_MODE_IEEE80211AD:
4026 hmode = "AD";
4027 break;
4028 default:
4029 continue;
4030 }
4031 ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
4032 hmode);
d85e1fc8 4033 if (os_snprintf_error(end - pos, ret))
06060522
BR
4034 return pos - buf;
4035 pos += ret;
4036 chnl = wpa_s->hw.modes[j].channels;
4037 for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
4038 if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
4039 continue;
0547124d 4040 ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
06060522 4041 chnl[i].chan, chnl[i].freq,
0a443580
IP
4042 chnl[i].flag & HOSTAPD_CHAN_NO_IR ?
4043 " (NO_IR)" : "",
0547124d
DS
4044 chnl[i].flag & HOSTAPD_CHAN_RADAR ?
4045 " (DFS)" : "");
4046
d85e1fc8 4047 if (os_snprintf_error(end - pos, ret))
06060522
BR
4048 return pos - buf;
4049 pos += ret;
4050 }
4051 ret = os_snprintf(pos, end - pos, "\n");
d85e1fc8 4052 if (os_snprintf_error(end - pos, ret))
06060522
BR
4053 return pos - buf;
4054 pos += ret;
4055 }
4056
4057 return pos - buf;
4058}
4059
4060
6fc6879b
JM
4061static int wpa_supplicant_ctrl_iface_get_capability(
4062 struct wpa_supplicant *wpa_s, const char *_field, char *buf,
4063 size_t buflen)
4064{
4065 struct wpa_driver_capa capa;
4066 int res;
4067 char *strict;
4068 char field[30];
4069 size_t len;
4070
4071 /* Determine whether or not strict checking was requested */
4072 len = os_strlcpy(field, _field, sizeof(field));
4073 if (len >= sizeof(field))
4074 return -1;
4075 strict = os_strchr(field, ' ');
4076 if (strict != NULL) {
4077 *strict++ = '\0';
4078 if (os_strcmp(strict, "strict") != 0)
4079 return -1;
4080 }
4081
4082 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
4083 field, strict ? strict : "");
4084
4085 if (os_strcmp(field, "eap") == 0) {
4086 return eap_get_names(buf, buflen);
4087 }
4088
4089 res = wpa_drv_get_capa(wpa_s, &capa);
4090
4091 if (os_strcmp(field, "pairwise") == 0)
4092 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
4093 buf, buflen);
4094
4095 if (os_strcmp(field, "group") == 0)
4096 return ctrl_iface_get_capability_group(res, strict, &capa,
4097 buf, buflen);
4098
b5f045de
JM
4099 if (os_strcmp(field, "group_mgmt") == 0)
4100 return ctrl_iface_get_capability_group_mgmt(res, strict, &capa,
4101 buf, buflen);
4102
6fc6879b
JM
4103 if (os_strcmp(field, "key_mgmt") == 0)
4104 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
4105 buf, buflen);
4106
4107 if (os_strcmp(field, "proto") == 0)
4108 return ctrl_iface_get_capability_proto(res, strict, &capa,
4109 buf, buflen);
4110
4111 if (os_strcmp(field, "auth_alg") == 0)
db5adfe7
JM
4112 return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
4113 &capa, buf, buflen);
6fc6879b 4114
65d52fc1
BR
4115 if (os_strcmp(field, "modes") == 0)
4116 return ctrl_iface_get_capability_modes(res, strict, &capa,
4117 buf, buflen);
4118
35aa088a
DS
4119 if (os_strcmp(field, "channels") == 0)
4120 return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
4121
06060522
BR
4122 if (os_strcmp(field, "freq") == 0)
4123 return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
4124
6e9375e4
DS
4125#ifdef CONFIG_TDLS
4126 if (os_strcmp(field, "tdls") == 0)
4127 return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
4128#endif /* CONFIG_TDLS */
4129
02a8d45a
JM
4130#ifdef CONFIG_ERP
4131 if (os_strcmp(field, "erp") == 0) {
4132 res = os_snprintf(buf, buflen, "ERP");
d85e1fc8 4133 if (os_snprintf_error(buflen, res))
02a8d45a
JM
4134 return -1;
4135 return res;
4136 }
4137#endif /* CONFIG_EPR */
4138
1e4f7bf5
JM
4139#ifdef CONFIG_FIPS
4140 if (os_strcmp(field, "fips") == 0) {
4141 res = os_snprintf(buf, buflen, "FIPS");
4142 if (os_snprintf_error(buflen, res))
4143 return -1;
4144 return res;
4145 }
4146#endif /* CONFIG_FIPS */
4147
7d2f6743
JM
4148#ifdef CONFIG_ACS
4149 if (os_strcmp(field, "acs") == 0) {
4150 res = os_snprintf(buf, buflen, "ACS");
4151 if (os_snprintf_error(buflen, res))
4152 return -1;
4153 return res;
4154 }
4155#endif /* CONFIG_ACS */
4156
379e2b4d 4157#ifdef CONFIG_FILS
061dac1d
JM
4158 if (os_strcmp(field, "fils") == 0 &&
4159 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) {
379e2b4d
JM
4160 res = os_snprintf(buf, buflen, "FILS");
4161 if (os_snprintf_error(buflen, res))
4162 return -1;
4163 return res;
4164 }
4165#endif /* CONFIG_FILS */
4166
6fc6879b
JM
4167 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
4168 field);
4169
4170 return -1;
4171}
4172
4173
afc064fe
JM
4174#ifdef CONFIG_INTERWORKING
4175static char * anqp_add_hex(char *pos, char *end, const char *title,
4176 struct wpabuf *data)
4177{
4178 char *start = pos;
4179 size_t i;
4180 int ret;
4181 const u8 *d;
4182
4183 if (data == NULL)
4184 return start;
4185
4186 ret = os_snprintf(pos, end - pos, "%s=", title);
d85e1fc8 4187 if (os_snprintf_error(end - pos, ret))
afc064fe
JM
4188 return start;
4189 pos += ret;
4190
4191 d = wpabuf_head_u8(data);
4192 for (i = 0; i < wpabuf_len(data); i++) {
4193 ret = os_snprintf(pos, end - pos, "%02x", *d++);
d85e1fc8 4194 if (os_snprintf_error(end - pos, ret))
afc064fe
JM
4195 return start;
4196 pos += ret;
4197 }
4198
4199 ret = os_snprintf(pos, end - pos, "\n");
d85e1fc8 4200 if (os_snprintf_error(end - pos, ret))
afc064fe
JM
4201 return start;
4202 pos += ret;
4203
4204 return pos;
4205}
4206#endif /* CONFIG_INTERWORKING */
4207
4208
b54f4339
JM
4209#ifdef CONFIG_FILS
4210static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end)
4211{
4212 char *start = pos;
4213 const u8 *ie, *ie_end;
4214 u16 info, realms;
4215 int ret;
4216
4217 ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
4218 if (!ie)
4219 return 0;
4220 ie_end = ie + 2 + ie[1];
4221 ie += 2;
4222 if (ie_end - ie < 2)
4223 return -1;
4224
4225 info = WPA_GET_LE16(ie);
4226 ie += 2;
4227 ret = os_snprintf(pos, end - pos, "fils_info=%04x\n", info);
4228 if (os_snprintf_error(end - pos, ret))
4229 return 0;
4230 pos += ret;
4231
4232 if (info & BIT(7)) {
4233 /* Cache Identifier Included */
4234 if (ie_end - ie < 2)
4235 return -1;
4236 ret = os_snprintf(pos, end - pos, "fils_cache_id=%02x%02x\n",
4237 ie[0], ie[1]);
4238 if (os_snprintf_error(end - pos, ret))
4239 return 0;
4240 pos += ret;
4241 ie += 2;
4242 }
4243
4244 if (info & BIT(8)) {
4245 /* HESSID Included */
4246 if (ie_end - ie < ETH_ALEN)
4247 return -1;
4248 ret = os_snprintf(pos, end - pos, "fils_hessid=" MACSTR "\n",
4249 MAC2STR(ie));
4250 if (os_snprintf_error(end - pos, ret))
4251 return 0;
4252 pos += ret;
4253 ie += ETH_ALEN;
4254 }
4255
4256 realms = (info & (BIT(3) | BIT(4) | BIT(5))) >> 3;
4257 if (realms) {
4258 if (ie_end - ie < realms * 2)
4259 return -1;
4260 ret = os_snprintf(pos, end - pos, "fils_realms=");
4261 if (os_snprintf_error(end - pos, ret))
4262 return 0;
4263 pos += ret;
4264
4265 ret = wpa_snprintf_hex(pos, end - pos, ie, realms * 2);
4266 if (ret <= 0)
4267 return 0;
4268 pos += ret;
4269 ie += realms * 2;
4270 ret = os_snprintf(pos, end - pos, "\n");
4271 if (os_snprintf_error(end - pos, ret))
4272 return 0;
4273 pos += ret;
4274 }
4275
4276 return pos - start;
4277}
4278#endif /* CONFIG_FILS */
4279
4280
61ce9085 4281static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
5f97dd1c 4282 unsigned long mask, char *buf, size_t buflen)
6fc6879b 4283{
6fc6879b 4284 size_t i;
6fc6879b
JM
4285 int ret;
4286 char *pos, *end;
4a45dc19 4287 const u8 *ie, *ie2, *osen_ie, *mesh;
6fc6879b 4288
6fc6879b
JM
4289 pos = buf;
4290 end = buf + buflen;
6fc6879b 4291
5f97dd1c
DS
4292 if (mask & WPA_BSS_MASK_ID) {
4293 ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
d85e1fc8 4294 if (os_snprintf_error(end - pos, ret))
5f97dd1c 4295 return 0;
6fc6879b
JM
4296 pos += ret;
4297 }
4298
5f97dd1c
DS
4299 if (mask & WPA_BSS_MASK_BSSID) {
4300 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
4301 MAC2STR(bss->bssid));
d85e1fc8 4302 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4303 return 0;
4304 pos += ret;
4305 }
6fc6879b 4306
5f97dd1c
DS
4307 if (mask & WPA_BSS_MASK_FREQ) {
4308 ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
d85e1fc8 4309 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4310 return 0;
4311 pos += ret;
4312 }
6fc6879b 4313
5f97dd1c
DS
4314 if (mask & WPA_BSS_MASK_BEACON_INT) {
4315 ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
4316 bss->beacon_int);
d85e1fc8 4317 if (os_snprintf_error(end - pos, ret))
5f97dd1c 4318 return 0;
6fc6879b
JM
4319 pos += ret;
4320 }
5f97dd1c
DS
4321
4322 if (mask & WPA_BSS_MASK_CAPABILITIES) {
4323 ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
4324 bss->caps);
d85e1fc8 4325 if (os_snprintf_error(end - pos, ret))
5f97dd1c 4326 return 0;
6fc6879b
JM
4327 pos += ret;
4328 }
5f97dd1c
DS
4329
4330 if (mask & WPA_BSS_MASK_QUAL) {
4331 ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
d85e1fc8 4332 if (os_snprintf_error(end - pos, ret))
5f97dd1c 4333 return 0;
bd1af96a
JM
4334 pos += ret;
4335 }
5f97dd1c
DS
4336
4337 if (mask & WPA_BSS_MASK_NOISE) {
4338 ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
d85e1fc8 4339 if (os_snprintf_error(end - pos, ret))
5f97dd1c 4340 return 0;
cc81110d
JM
4341 pos += ret;
4342 }
6fc6879b 4343
5f97dd1c
DS
4344 if (mask & WPA_BSS_MASK_LEVEL) {
4345 ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
d85e1fc8 4346 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4347 return 0;
4348 pos += ret;
4349 }
6fc6879b 4350
5f97dd1c
DS
4351 if (mask & WPA_BSS_MASK_TSF) {
4352 ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
4353 (unsigned long long) bss->tsf);
d85e1fc8 4354 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4355 return 0;
4356 pos += ret;
4357 }
4358
4359 if (mask & WPA_BSS_MASK_AGE) {
acb69cec 4360 struct os_reltime now;
5f97dd1c 4361
acb69cec 4362 os_get_reltime(&now);
5f97dd1c
DS
4363 ret = os_snprintf(pos, end - pos, "age=%d\n",
4364 (int) (now.sec - bss->last_update.sec));
d85e1fc8 4365 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4366 return 0;
4367 pos += ret;
4368 }
4369
4370 if (mask & WPA_BSS_MASK_IE) {
4371 ret = os_snprintf(pos, end - pos, "ie=");
d85e1fc8 4372 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4373 return 0;
4374 pos += ret;
4375
4376 ie = (const u8 *) (bss + 1);
4377 for (i = 0; i < bss->ie_len; i++) {
4378 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
d85e1fc8 4379 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4380 return 0;
4381 pos += ret;
4382 }
4383
4384 ret = os_snprintf(pos, end - pos, "\n");
d85e1fc8 4385 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4386 return 0;
4387 pos += ret;
4388 }
4389
4390 if (mask & WPA_BSS_MASK_FLAGS) {
4391 ret = os_snprintf(pos, end - pos, "flags=");
d85e1fc8 4392 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4393 return 0;
4394 pos += ret;
4395
4a45dc19
SD
4396 mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
4397
5f97dd1c
DS
4398 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
4399 if (ie)
4400 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
4401 2 + ie[1]);
4402 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
4403 if (ie2)
4a45dc19
SD
4404 pos = wpa_supplicant_ie_txt(pos, end,
4405 mesh ? "RSN" : "WPA2", ie2,
5f97dd1c 4406 2 + ie2[1]);
0f8385e6
BG
4407 osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
4408 if (osen_ie)
4409 pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
4410 osen_ie, 2 + osen_ie[1]);
5f97dd1c 4411 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
0f8385e6
BG
4412 if (!ie && !ie2 && !osen_ie &&
4413 (bss->caps & IEEE80211_CAP_PRIVACY)) {
5f97dd1c 4414 ret = os_snprintf(pos, end - pos, "[WEP]");
d85e1fc8 4415 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4416 return 0;
4417 pos += ret;
4418 }
4a45dc19
SD
4419
4420 if (mesh) {
4421 ret = os_snprintf(pos, end - pos, "[MESH]");
4422 if (os_snprintf_error(end - pos, ret))
4423 return 0;
4424 pos += ret;
4425 }
4426
e403ba85
BS
4427 if (bss_is_dmg(bss)) {
4428 const char *s;
4429 ret = os_snprintf(pos, end - pos, "[DMG]");
d85e1fc8 4430 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4431 return 0;
4432 pos += ret;
e403ba85
BS
4433 switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
4434 case IEEE80211_CAP_DMG_IBSS:
4435 s = "[IBSS]";
4436 break;
4437 case IEEE80211_CAP_DMG_AP:
4438 s = "[ESS]";
4439 break;
4440 case IEEE80211_CAP_DMG_PBSS:
4441 s = "[PBSS]";
4442 break;
4443 default:
4444 s = "";
4445 break;
4446 }
4447 ret = os_snprintf(pos, end - pos, "%s", s);
d85e1fc8 4448 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4449 return 0;
4450 pos += ret;
e403ba85
BS
4451 } else {
4452 if (bss->caps & IEEE80211_CAP_IBSS) {
4453 ret = os_snprintf(pos, end - pos, "[IBSS]");
d85e1fc8 4454 if (os_snprintf_error(end - pos, ret))
e403ba85
BS
4455 return 0;
4456 pos += ret;
4457 }
4458 if (bss->caps & IEEE80211_CAP_ESS) {
4459 ret = os_snprintf(pos, end - pos, "[ESS]");
d85e1fc8 4460 if (os_snprintf_error(end - pos, ret))
e403ba85
BS
4461 return 0;
4462 pos += ret;
4463 }
5f97dd1c 4464 }
bb50ae43
JM
4465 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
4466 wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
5f97dd1c 4467 ret = os_snprintf(pos, end - pos, "[P2P]");
d85e1fc8 4468 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4469 return 0;
4470 pos += ret;
4471 }
64855b96
JM
4472#ifdef CONFIG_HS20
4473 if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
4474 ret = os_snprintf(pos, end - pos, "[HS20]");
d85e1fc8 4475 if (os_snprintf_error(end - pos, ret))
ff486913 4476 return 0;
64855b96
JM
4477 pos += ret;
4478 }
4479#endif /* CONFIG_HS20 */
7147a834
JM
4480#ifdef CONFIG_FILS
4481 if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
4482 ret = os_snprintf(pos, end - pos, "[FILS]");
4483 if (os_snprintf_error(end - pos, ret))
4484 return 0;
4485 pos += ret;
4486 }
4487#endif /* CONFIG_FILS */
5f97dd1c
DS
4488
4489 ret = os_snprintf(pos, end - pos, "\n");
d85e1fc8 4490 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4491 return 0;
4492 pos += ret;
4493 }
4494
4495 if (mask & WPA_BSS_MASK_SSID) {
4496 ret = os_snprintf(pos, end - pos, "ssid=%s\n",
4497 wpa_ssid_txt(bss->ssid, bss->ssid_len));
d85e1fc8 4498 if (os_snprintf_error(end - pos, ret))
5f97dd1c
DS
4499 return 0;
4500 pos += ret;
4501 }
6fc6879b 4502
611ed491 4503#ifdef CONFIG_WPS
5f97dd1c
DS
4504 if (mask & WPA_BSS_MASK_WPS_SCAN) {
4505 ie = (const u8 *) (bss + 1);
4506 ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
fc078be2 4507 if (ret >= end - pos)
5f97dd1c 4508 return 0;
fc078be2
JM
4509 if (ret > 0)
4510 pos += ret;
5f97dd1c 4511 }
611ed491
JM
4512#endif /* CONFIG_WPS */
4513
0c6b310e 4514#ifdef CONFIG_P2P
5f97dd1c
DS
4515 if (mask & WPA_BSS_MASK_P2P_SCAN) {
4516 ie = (const u8 *) (bss + 1);
4517 ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
3b208346 4518 if (ret >= end - pos)
5f97dd1c 4519 return 0;
3b208346
JA
4520 if (ret > 0)
4521 pos += ret;
5f97dd1c 4522 }
0c6b310e
JM
4523#endif /* CONFIG_P2P */
4524
337c781f
JM
4525#ifdef CONFIG_WIFI_DISPLAY
4526 if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
4527 struct wpabuf *wfd;
4528 ie = (const u8 *) (bss + 1);
4529 wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
4530 WFD_IE_VENDOR_TYPE);
4531 if (wfd) {
4532 ret = os_snprintf(pos, end - pos, "wfd_subelems=");
d85e1fc8 4533 if (os_snprintf_error(end - pos, ret)) {
5e6aa04b 4534 wpabuf_free(wfd);
ff486913 4535 return 0;
5e6aa04b 4536 }
337c781f
JM
4537 pos += ret;
4538
4539 pos += wpa_snprintf_hex(pos, end - pos,
4540 wpabuf_head(wfd),
4541 wpabuf_len(wfd));
4542 wpabuf_free(wfd);
4543
4544 ret = os_snprintf(pos, end - pos, "\n");
d85e1fc8 4545 if (os_snprintf_error(end - pos, ret))
ff486913 4546 return 0;
337c781f
JM
4547 pos += ret;
4548 }
4549 }
4550#endif /* CONFIG_WIFI_DISPLAY */
4551
afc064fe 4552#ifdef CONFIG_INTERWORKING
476aed35
JM
4553 if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
4554 struct wpa_bss_anqp *anqp = bss->anqp;
8c4a1026
JM
4555 struct wpa_bss_anqp_elem *elem;
4556
5ce6ac11
AN
4557 pos = anqp_add_hex(pos, end, "anqp_capability_list",
4558 anqp->capability_list);
5f97dd1c 4559 pos = anqp_add_hex(pos, end, "anqp_venue_name",
476aed35 4560 anqp->venue_name);
5f97dd1c 4561 pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
476aed35 4562 anqp->network_auth_type);
5f97dd1c 4563 pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
476aed35 4564 anqp->roaming_consortium);
5f97dd1c 4565 pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
476aed35 4566 anqp->ip_addr_type_availability);
5f97dd1c 4567 pos = anqp_add_hex(pos, end, "anqp_nai_realm",
476aed35
JM
4568 anqp->nai_realm);
4569 pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
5f97dd1c 4570 pos = anqp_add_hex(pos, end, "anqp_domain_name",
476aed35 4571 anqp->domain_name);
9cad6186
JM
4572 pos = anqp_add_hex(pos, end, "anqp_fils_realm_info",
4573 anqp->fils_realm_info);
25471fe3 4574#ifdef CONFIG_HS20
185ada47
AN
4575 pos = anqp_add_hex(pos, end, "hs20_capability_list",
4576 anqp->hs20_capability_list);
25471fe3 4577 pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
476aed35 4578 anqp->hs20_operator_friendly_name);
25471fe3 4579 pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
476aed35 4580 anqp->hs20_wan_metrics);
25471fe3 4581 pos = anqp_add_hex(pos, end, "hs20_connection_capability",
476aed35 4582 anqp->hs20_connection_capability);
1d2215fc
JM
4583 pos = anqp_add_hex(pos, end, "hs20_operating_class",
4584 anqp->hs20_operating_class);
4585 pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
4586 anqp->hs20_osu_providers_list);
25471fe3 4587#endif /* CONFIG_HS20 */
8c4a1026
JM
4588
4589 dl_list_for_each(elem, &anqp->anqp_elems,
4590 struct wpa_bss_anqp_elem, list) {
4591 char title[20];
4592
4593 os_snprintf(title, sizeof(title), "anqp[%u]",
4594 elem->infoid);
4595 pos = anqp_add_hex(pos, end, title, elem->payload);
4596 }
5f97dd1c 4597 }
afc064fe
JM
4598#endif /* CONFIG_INTERWORKING */
4599
79070906
MH
4600#ifdef CONFIG_MESH
4601 if (mask & WPA_BSS_MASK_MESH_SCAN) {
4602 ie = (const u8 *) (bss + 1);
4603 ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
3b208346 4604 if (ret >= end - pos)
79070906 4605 return 0;
3b208346
JA
4606 if (ret > 0)
4607 pos += ret;
79070906
MH
4608 }
4609#endif /* CONFIG_MESH */
4610
1d747e2a
JM
4611 if (mask & WPA_BSS_MASK_SNR) {
4612 ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr);
4613 if (os_snprintf_error(end - pos, ret))
4614 return 0;
4615 pos += ret;
4616 }
4617
4618 if (mask & WPA_BSS_MASK_EST_THROUGHPUT) {
4619 ret = os_snprintf(pos, end - pos, "est_throughput=%d\n",
4620 bss->est_throughput);
4621 if (os_snprintf_error(end - pos, ret))
4622 return 0;
4623 pos += ret;
4624 }
4625
3794af2d
AN
4626#ifdef CONFIG_FST
4627 if (mask & WPA_BSS_MASK_FST) {
4628 ret = fst_ctrl_iface_mb_info(bss->bssid, pos, end - pos);
4629 if (ret < 0 || ret >= end - pos)
4630 return 0;
4631 pos += ret;
4632 }
4633#endif /* CONFIG_FST */
4634
71ac9345
JM
4635 if (mask & WPA_BSS_MASK_UPDATE_IDX) {
4636 ret = os_snprintf(pos, end - pos, "update_idx=%u\n",
4637 bss->last_update_idx);
4638 if (os_snprintf_error(end - pos, ret))
4639 return 0;
4640 pos += ret;
4641 }
4642
19810d29
JM
4643 if ((mask & WPA_BSS_MASK_BEACON_IE) && bss->beacon_ie_len) {
4644 ret = os_snprintf(pos, end - pos, "beacon_ie=");
4645 if (os_snprintf_error(end - pos, ret))
4646 return 0;
4647 pos += ret;
4648
4649 ie = (const u8 *) (bss + 1);
4650 ie += bss->ie_len;
4651 for (i = 0; i < bss->beacon_ie_len; i++) {
4652 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
4653 if (os_snprintf_error(end - pos, ret))
4654 return 0;
4655 pos += ret;
4656 }
4657
4658 ret = os_snprintf(pos, end - pos, "\n");
4659 if (os_snprintf_error(end - pos, ret))
4660 return 0;
4661 pos += ret;
4662 }
4663
b54f4339
JM
4664#ifdef CONFIG_FILS
4665 if (mask & WPA_BSS_MASK_FILS_INDICATION) {
4666 ret = print_fils_indication(bss, pos, end);
4667 if (ret < 0)
4668 return 0;
4669 pos += ret;
4670 }
4671#endif /* CONFIG_FILS */
4672
c6673429
DS
4673 if (mask & WPA_BSS_MASK_DELIM) {
4674 ret = os_snprintf(pos, end - pos, "====\n");
d85e1fc8 4675 if (os_snprintf_error(end - pos, ret))
c6673429
DS
4676 return 0;
4677 pos += ret;
4678 }
4679
6fc6879b
JM
4680 return pos - buf;
4681}
4682
4683
61ce9085
DS
4684static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
4685 const char *cmd, char *buf,
4686 size_t buflen)
4687{
4688 u8 bssid[ETH_ALEN];
4689 size_t i;
4690 struct wpa_bss *bss;
eff1a95b
DS
4691 struct wpa_bss *bsslast = NULL;
4692 struct dl_list *next;
4693 int ret = 0;
4694 int len;
1d399771 4695 char *ctmp, *end = buf + buflen;
5f97dd1c 4696 unsigned long mask = WPA_BSS_MASK_ALL;
61ce9085 4697
eff1a95b
DS
4698 if (os_strncmp(cmd, "RANGE=", 6) == 0) {
4699 if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
4700 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
4701 list_id);
4702 bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
4703 list_id);
4704 } else { /* N1-N2 */
4705 unsigned int id1, id2;
4706
4707 if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
4708 wpa_printf(MSG_INFO, "Wrong BSS range "
4709 "format");
4710 return 0;
4711 }
4712
9f42d49c
AS
4713 if (*(cmd + 6) == '-')
4714 id1 = 0;
4715 else
4716 id1 = atoi(cmd + 6);
4717 ctmp++;
4718 if (*ctmp >= '0' && *ctmp <= '9')
4719 id2 = atoi(ctmp);
4720 else
4721 id2 = (unsigned int) -1;
4722 bss = wpa_bss_get_id_range(wpa_s, id1, id2);
4723 if (id2 == (unsigned int) -1)
eff1a95b
DS
4724 bsslast = dl_list_last(&wpa_s->bss_id,
4725 struct wpa_bss,
4726 list_id);
4727 else {
4728 bsslast = wpa_bss_get_id(wpa_s, id2);
4729 if (bsslast == NULL && bss && id2 > id1) {
4730 struct wpa_bss *tmp = bss;
4731 for (;;) {
4732 next = tmp->list_id.next;
4733 if (next == &wpa_s->bss_id)
4734 break;
4735 tmp = dl_list_entry(
4736 next, struct wpa_bss,
4737 list_id);
4738 if (tmp->id > id2)
4739 break;
4740 bsslast = tmp;
4741 }
4742 }
4743 }
4744 }
f330b4b4 4745 } else if (os_strncmp(cmd, "FIRST", 5) == 0)
51a0c3d4 4746 bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
cc03d0fe
AS
4747 else if (os_strncmp(cmd, "LAST", 4) == 0)
4748 bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
61ce9085
DS
4749 else if (os_strncmp(cmd, "ID-", 3) == 0) {
4750 i = atoi(cmd + 3);
4751 bss = wpa_bss_get_id(wpa_s, i);
4752 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
4753 i = atoi(cmd + 5);
4754 bss = wpa_bss_get_id(wpa_s, i);
4755 if (bss) {
eff1a95b 4756 next = bss->list_id.next;
61ce9085
DS
4757 if (next == &wpa_s->bss_id)
4758 bss = NULL;
4759 else
4760 bss = dl_list_entry(next, struct wpa_bss,
4761 list_id);
4762 }
9187b13a
JC
4763 } else if (os_strncmp(cmd, "CURRENT", 7) == 0) {
4764 bss = wpa_s->current_bss;
61ce9085
DS
4765#ifdef CONFIG_P2P
4766 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
4767 if (hwaddr_aton(cmd + 13, bssid) == 0)
4768 bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
4769 else
4770 bss = NULL;
4771#endif /* CONFIG_P2P */
4772 } else if (hwaddr_aton(cmd, bssid) == 0)
4773 bss = wpa_bss_get_bssid(wpa_s, bssid);
4774 else {
4775 struct wpa_bss *tmp;
4776 i = atoi(cmd);
4777 bss = NULL;
4778 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
4779 {
4780 if (i-- == 0) {
4781 bss = tmp;
4782 break;
4783 }
4784 }
4785 }
4786
5f97dd1c
DS
4787 if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
4788 mask = strtoul(ctmp + 5, NULL, 0x10);
4789 if (mask == 0)
4790 mask = WPA_BSS_MASK_ALL;
4791 }
4792
61ce9085
DS
4793 if (bss == NULL)
4794 return 0;
4795
eff1a95b
DS
4796 if (bsslast == NULL)
4797 bsslast = bss;
4798 do {
4799 len = print_bss_info(wpa_s, bss, mask, buf, buflen);
4800 ret += len;
4801 buf += len;
4802 buflen -= len;
cfd42c94
DS
4803 if (bss == bsslast) {
4804 if ((mask & WPA_BSS_MASK_DELIM) && len &&
4805 (bss == dl_list_last(&wpa_s->bss_id,
1d399771
JM
4806 struct wpa_bss, list_id))) {
4807 int res;
4808
4809 res = os_snprintf(buf - 5, end - buf + 5,
4810 "####\n");
4811 if (os_snprintf_error(end - buf + 5, res)) {
4812 wpa_printf(MSG_DEBUG,
4813 "Could not add end delim");
4814 }
4815 }
eff1a95b 4816 break;
cfd42c94 4817 }
eff1a95b
DS
4818 next = bss->list_id.next;
4819 if (next == &wpa_s->bss_id)
4820 break;
4821 bss = dl_list_entry(next, struct wpa_bss, list_id);
4822 } while (bss && len);
4823
4824 return ret;
61ce9085
DS
4825}
4826
4827
6fc6879b
JM
4828static int wpa_supplicant_ctrl_iface_ap_scan(
4829 struct wpa_supplicant *wpa_s, char *cmd)
4830{
4831 int ap_scan = atoi(cmd);
86b89452 4832 return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
6fc6879b
JM
4833}
4834
4835
67b9bd08
DS
4836static int wpa_supplicant_ctrl_iface_scan_interval(
4837 struct wpa_supplicant *wpa_s, char *cmd)
4838{
4839 int scan_int = atoi(cmd);
c6e86b63 4840 return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
67b9bd08
DS
4841}
4842
4843
78633c37
SL
4844static int wpa_supplicant_ctrl_iface_bss_expire_age(
4845 struct wpa_supplicant *wpa_s, char *cmd)
4846{
4847 int expire_age = atoi(cmd);
4848 return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
4849}
4850
4851
4852static int wpa_supplicant_ctrl_iface_bss_expire_count(
4853 struct wpa_supplicant *wpa_s, char *cmd)
4854{
4855 int expire_count = atoi(cmd);
4856 return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
4857}
4858
4859
a1144000 4860static void wpa_supplicant_ctrl_iface_bss_flush(
39ee845f
DS
4861 struct wpa_supplicant *wpa_s, char *cmd)
4862{
4863 int flush_age = atoi(cmd);
4864
4865 if (flush_age == 0)
4866 wpa_bss_flush(wpa_s);
4867 else
4868 wpa_bss_flush_by_age(wpa_s, flush_age);
39ee845f
DS
4869}
4870
4871
9ff4de6d 4872#ifdef CONFIG_TESTING_OPTIONS
32d5295f
JM
4873static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
4874{
32d5295f
JM
4875 wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
4876 /* MLME-DELETEKEYS.request */
0382097e
JM
4877 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
4878 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
4879 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
4880 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
32d5295f 4881#ifdef CONFIG_IEEE80211W
0382097e
JM
4882 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
4883 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
32d5295f
JM
4884#endif /* CONFIG_IEEE80211W */
4885
4886 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
4887 0);
4888 /* MLME-SETPROTECTION.request(None) */
4889 wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
4890 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
4891 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
4892 wpa_sm_drop_sa(wpa_s->wpa);
4893}
9ff4de6d 4894#endif /* CONFIG_TESTING_OPTIONS */
32d5295f
JM
4895
4896
86d4f806
JM
4897static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
4898 char *addr)
4899{
90b8fc8f
JM
4900#ifdef CONFIG_NO_SCAN_PROCESSING
4901 return -1;
4902#else /* CONFIG_NO_SCAN_PROCESSING */
86d4f806
JM
4903 u8 bssid[ETH_ALEN];
4904 struct wpa_bss *bss;
4905 struct wpa_ssid *ssid = wpa_s->current_ssid;
4906
4907 if (hwaddr_aton(addr, bssid)) {
4908 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
4909 "address '%s'", addr);
4910 return -1;
4911 }
4912
4913 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
4914
2f9b66d3
JM
4915 if (!ssid) {
4916 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
4917 "configuration known for the target AP");
4918 return -1;
4919 }
4920
4921 bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
86d4f806
JM
4922 if (!bss) {
4923 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
4924 "from BSS table");
4925 return -1;
4926 }
4927
4928 /*
4929 * TODO: Find best network configuration block from configuration to
4930 * allow roaming to other networks
4931 */
4932
86d4f806
JM
4933 wpa_s->reassociate = 1;
4934 wpa_supplicant_connect(wpa_s, bss, ssid);
4935
4936 return 0;
90b8fc8f 4937#endif /* CONFIG_NO_SCAN_PROCESSING */
86d4f806
JM
4938}
4939
4940
b563b388
JM
4941#ifdef CONFIG_P2P
4942static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
4943{
4944 unsigned int timeout = atoi(cmd);
4945 enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
6d92fa6e 4946 u8 dev_id[ETH_ALEN], *_dev_id = NULL;
2b384109 4947 u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
6d92fa6e 4948 char *pos;
05a77b3b 4949 unsigned int search_delay;
9542f21f 4950 const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
51775096 4951 u8 seek_count = 0;
fa9f381f 4952 int freq = 0;
b563b388 4953
e9eb648e
JM
4954 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
4955 wpa_dbg(wpa_s, MSG_INFO,
4956 "Reject P2P_FIND since interface is disabled");
4957 return -1;
4958 }
b563b388
JM
4959 if (os_strstr(cmd, "type=social"))
4960 type = P2P_FIND_ONLY_SOCIAL;
4961 else if (os_strstr(cmd, "type=progressive"))
4962 type = P2P_FIND_PROGRESSIVE;
4963
6d92fa6e
JM
4964 pos = os_strstr(cmd, "dev_id=");
4965 if (pos) {
4966 pos += 7;
4967 if (hwaddr_aton(pos, dev_id))
4968 return -1;
4969 _dev_id = dev_id;
4970 }
4971
2b384109
JM
4972 pos = os_strstr(cmd, "dev_type=");
4973 if (pos) {
4974 pos += 9;
4975 if (wps_dev_type_str2bin(pos, dev_type) < 0)
4976 return -1;
4977 _dev_type = dev_type;
4978 }
4979
37448ede
JM
4980 pos = os_strstr(cmd, "delay=");
4981 if (pos) {
4982 pos += 6;
4983 search_delay = atoi(pos);
05a77b3b
JM
4984 } else
4985 search_delay = wpas_p2p_search_delay(wpa_s);
37448ede 4986
a9ea609c
SM
4987 pos = os_strstr(cmd, "freq=");
4988 if (pos) {
4989 pos += 5;
4990 freq = atoi(pos);
4991 if (freq <= 0)
4992 return -1;
4993 }
4994
51775096
BG
4995 /* Must be searched for last, because it adds nul termination */
4996 pos = os_strstr(cmd, " seek=");
129b6216
JM
4997 if (pos)
4998 pos += 6;
51775096
BG
4999 while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
5000 char *term;
5001
129b6216 5002 _seek[seek_count++] = pos;
9542f21f 5003 seek = _seek;
129b6216
JM
5004 term = os_strchr(pos, ' ');
5005 if (!term)
5006 break;
5007 *term = '\0';
5008 pos = os_strstr(term + 1, "seek=");
5009 if (pos)
5010 pos += 5;
51775096 5011 }
9542f21f
JM
5012 if (seek_count > P2P_MAX_QUERY_HASH) {
5013 seek[0] = NULL;
5014 seek_count = 1;
5015 }
51775096 5016
2b384109 5017 return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
fa9f381f 5018 _dev_id, search_delay, seek_count, seek, freq);
b563b388
JM
5019}
5020
5021
e2b7fbf2
MS
5022static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt)
5023{
5024 const char *last = NULL;
5025 const char *token;
5026 long int token_len;
5027 unsigned int i;
5028
5029 /* Expected predefined CPT names delimited by ':' */
5030 for (i = 0; (token = cstr_token(pos, ": \t", &last)); i++) {
5031 if (i >= P2PS_FEATURE_CAPAB_CPT_MAX) {
5032 wpa_printf(MSG_ERROR,
5033 "P2PS: CPT name list is too long, expected up to %d names",
5034 P2PS_FEATURE_CAPAB_CPT_MAX);
5035 cpt[0] = 0;
5036 return -1;
5037 }
5038
5039 token_len = last - token;
5040
5041 if (token_len == 3 &&
5042 os_memcmp(token, "UDP", token_len) == 0) {
5043 cpt[i] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
5044 } else if (token_len == 3 &&
5045 os_memcmp(token, "MAC", token_len) == 0) {
5046 cpt[i] = P2PS_FEATURE_CAPAB_MAC_TRANSPORT;
5047 } else {
5048 wpa_printf(MSG_ERROR,
5049 "P2PS: Unsupported CPT name '%s'", token);
5050 cpt[0] = 0;
5051 return -1;
5052 }
5053
640b0b93 5054 if (isblank((unsigned char) *last)) {
e2b7fbf2
MS
5055 i++;
5056 break;
5057 }
5058 }
5059 cpt[i] = 0;
5060 return 0;
5061}
5062
5063
f309c18e
KV
5064static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
5065{
5066 struct p2ps_provision *p2ps_prov;
5067 char *pos;
5068 size_t info_len = 0;
5069 char *info = NULL;
5070 u8 role = P2PS_SETUP_NONE;
5071 long long unsigned val;
0670de74 5072 int i;
f309c18e
KV
5073
5074 pos = os_strstr(cmd, "info=");
5075 if (pos) {
5076 pos += 5;
5077 info_len = os_strlen(pos);
5078
5079 if (info_len) {
5080 info = os_malloc(info_len + 1);
5081 if (info) {
5082 info_len = utf8_unescape(pos, info_len,
5083 info, info_len + 1);
5084 } else
5085 info_len = 0;
5086 }
5087 }
5088
5089 p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1);
5090 if (p2ps_prov == NULL) {
5091 os_free(info);
5092 return NULL;
5093 }
5094
5095 if (info) {
5096 os_memcpy(p2ps_prov->info, info, info_len);
5097 p2ps_prov->info[info_len] = '\0';
5098 os_free(info);
5099 }
5100
5101 pos = os_strstr(cmd, "status=");
5102 if (pos)
5103 p2ps_prov->status = atoi(pos + 7);
5104 else
5105 p2ps_prov->status = -1;
5106
5107 pos = os_strstr(cmd, "adv_id=");
5108 if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL)
5109 goto invalid_args;
5110 p2ps_prov->adv_id = val;
5111
5112 pos = os_strstr(cmd, "method=");
5113 if (pos)
5114 p2ps_prov->method = strtol(pos + 7, NULL, 16);
5115 else
5116 p2ps_prov->method = 0;
5117
5118 pos = os_strstr(cmd, "session=");
5119 if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL)
5120 goto invalid_args;
5121 p2ps_prov->session_id = val;
5122
5123 pos = os_strstr(cmd, "adv_mac=");
5124 if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac))
5125 goto invalid_args;
5126
5127 pos = os_strstr(cmd, "session_mac=");
5128 if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))
5129 goto invalid_args;
5130
0670de74
MS
5131 pos = os_strstr(cmd, "cpt=");
5132 if (pos) {
5133 if (p2ps_ctrl_parse_cpt_priority(pos + 4,
5134 p2ps_prov->cpt_priority))
5135 goto invalid_args;
5136 } else {
5137 p2ps_prov->cpt_priority[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
5138 }
5139
5140 for (i = 0; p2ps_prov->cpt_priority[i]; i++)
5141 p2ps_prov->cpt_mask |= p2ps_prov->cpt_priority[i];
5142
f309c18e
KV
5143 /* force conncap with tstCap (no sanity checks) */
5144 pos = os_strstr(cmd, "tstCap=");
5145 if (pos) {
5146 role = strtol(pos + 7, NULL, 16);
5147 } else {
5148 pos = os_strstr(cmd, "role=");
5149 if (pos) {
5150 role = strtol(pos + 5, NULL, 16);
5151 if (role != P2PS_SETUP_CLIENT &&
5152 role != P2PS_SETUP_GROUP_OWNER)
5153 role = P2PS_SETUP_NONE;
5154 }
5155 }
5156 p2ps_prov->role = role;
5157
5158 return p2ps_prov;
5159
5160invalid_args:
5161 os_free(p2ps_prov);
5162 return NULL;
5163}
5164
5165
5166static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
5167{
5168 u8 addr[ETH_ALEN];
5169 struct p2ps_provision *p2ps_prov;
5170 char *pos;
5171
5172 /* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */
5173
5174 wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
5175
5176 if (hwaddr_aton(cmd, addr))
5177 return -1;
5178
5179 pos = cmd + 17;
5180 if (*pos != ' ')
5181 return -1;
5182
5183 p2ps_prov = p2p_parse_asp_provision_cmd(pos);
5184 if (!p2ps_prov)
5185 return -1;
5186
5187 if (p2ps_prov->status < 0) {
5188 os_free(p2ps_prov);
5189 return -1;
5190 }
5191
5192 return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
5193 p2ps_prov);
5194}
5195
5196
5197static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
5198{
5199 u8 addr[ETH_ALEN];
5200 struct p2ps_provision *p2ps_prov;
5201 char *pos;
5202
5203 /* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap>
5204 * session=<ses_id> mac=<ses_mac> [info=<infodata>]
5205 */
5206
5207 wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
5208 if (hwaddr_aton(cmd, addr))
5209 return -1;
5210
5211 pos = cmd + 17;
5212 if (*pos != ' ')
5213 return -1;
5214
5215 p2ps_prov = p2p_parse_asp_provision_cmd(pos);
5216 if (!p2ps_prov)
5217 return -1;
5218
93f22b45
MS
5219 p2ps_prov->pd_seeker = 1;
5220
f309c18e
KV
5221 return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
5222 p2ps_prov);
5223}
5224
5225
c27f4c90
AK
5226static int parse_freq(int chwidth, int freq2)
5227{
5228 if (freq2 < 0)
5229 return -1;
5230 if (freq2)
5231 return VHT_CHANWIDTH_80P80MHZ;
5232
5233 switch (chwidth) {
5234 case 0:
5235 case 20:
5236 case 40:
5237 return VHT_CHANWIDTH_USE_HT;
5238 case 80:
5239 return VHT_CHANWIDTH_80MHZ;
5240 case 160:
5241 return VHT_CHANWIDTH_160MHZ;
5242 default:
5243 wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
5244 chwidth);
5245 return -1;
5246 }
5247}
5248
5249
b563b388
JM
5250static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
5251 char *buf, size_t buflen)
5252{
5253 u8 addr[ETH_ALEN];
5254 char *pos, *pos2;
5255 char *pin = NULL;
5256 enum p2p_wps_method wps_method;
5257 int new_pin;
5258 int ret;
23c84252 5259 int persistent_group, persistent_id = -1;
b563b388
JM
5260 int join;
5261 int auth;
b31be3a0 5262 int automatic;
b563b388
JM
5263 int go_intent = -1;
5264 int freq = 0;
3bc462cb 5265 int pd;
c27f4c90 5266 int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
8edd9f10
JM
5267 u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
5268 size_t group_ssid_len = 0;
b563b388 5269
bdf0518b
JM
5270 if (!wpa_s->global->p2p_init_wpa_s)
5271 return -1;
5272 if (wpa_s->global->p2p_init_wpa_s != wpa_s) {
5273 wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s",
5274 wpa_s->global->p2p_init_wpa_s->ifname);
5275 wpa_s = wpa_s->global->p2p_init_wpa_s;
5276 }
5277
4f88fc04 5278 /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
23c84252 5279 * [persistent|persistent=<network id>]
e2308e4b 5280 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
8edd9f10 5281 * [ht40] [vht] [auto] [ssid=<hexdump>] */
b563b388
JM
5282
5283 if (hwaddr_aton(cmd, addr))
5284 return -1;
5285
5286 pos = cmd + 17;
5287 if (*pos != ' ')
5288 return -1;
5289 pos++;
5290
5291 persistent_group = os_strstr(pos, " persistent") != NULL;
23c84252
JM
5292 pos2 = os_strstr(pos, " persistent=");
5293 if (pos2) {
5294 struct wpa_ssid *ssid;
5295 persistent_id = atoi(pos2 + 12);
5296 ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
5297 if (ssid == NULL || ssid->disabled != 2 ||
5298 ssid->mode != WPAS_MODE_P2P_GO) {
5299 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
5300 "SSID id=%d for persistent P2P group (GO)",
5301 persistent_id);
5302 return -1;
5303 }
5304 }
b563b388
JM
5305 join = os_strstr(pos, " join") != NULL;
5306 auth = os_strstr(pos, " auth") != NULL;
b31be3a0 5307 automatic = os_strstr(pos, " auto") != NULL;
3bc462cb 5308 pd = os_strstr(pos, " provdisc") != NULL;
20ea1ca4
EP
5309 vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
5310 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
5311 vht;
b563b388
JM
5312
5313 pos2 = os_strstr(pos, " go_intent=");
5314 if (pos2) {
5315 pos2 += 11;
5316 go_intent = atoi(pos2);
5317 if (go_intent < 0 || go_intent > 15)
5318 return -1;
5319 }
5320
5321 pos2 = os_strstr(pos, " freq=");
5322 if (pos2) {
5323 pos2 += 6;
5324 freq = atoi(pos2);
5325 if (freq <= 0)
5326 return -1;
5327 }
5328
c27f4c90
AK
5329 pos2 = os_strstr(pos, " freq2=");
5330 if (pos2)
5331 freq2 = atoi(pos2 + 7);
5332
5333 pos2 = os_strstr(pos, " max_oper_chwidth=");
5334 if (pos2)
5335 chwidth = atoi(pos2 + 18);
5336
5337 max_oper_chwidth = parse_freq(chwidth, freq2);
5338 if (max_oper_chwidth < 0)
5339 return -1;
5340
8edd9f10
JM
5341 pos2 = os_strstr(pos, " ssid=");
5342 if (pos2) {
5343 char *end;
5344
5345 pos2 += 6;
5346 end = os_strchr(pos2, ' ');
5347 if (!end)
5348 group_ssid_len = os_strlen(pos2) / 2;
5349 else
5350 group_ssid_len = (end - pos2) / 2;
5351 if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN ||
5352 hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0)
5353 return -1;
5354 group_ssid = _group_ssid;
5355 }
5356
b563b388
JM
5357 if (os_strncmp(pos, "pin", 3) == 0) {
5358 /* Request random PIN (to be displayed) and enable the PIN */
5359 wps_method = WPS_PIN_DISPLAY;
5360 } else if (os_strncmp(pos, "pbc", 3) == 0) {
5361 wps_method = WPS_PBC;
31d7fb14
PK
5362 } else if (os_strstr(pos, "p2ps") != NULL) {
5363 wps_method = WPS_P2PS;
b563b388
JM
5364 } else {
5365 pin = pos;
5366 pos = os_strchr(pin, ' ');
5367 wps_method = WPS_PIN_KEYPAD;
5368 if (pos) {
5369 *pos++ = '\0';
07fecd39 5370 if (os_strncmp(pos, "display", 7) == 0)
b563b388
JM
5371 wps_method = WPS_PIN_DISPLAY;
5372 }
dcc33057 5373 if (!wps_pin_str_valid(pin)) {
36ebf7a1
MH
5374 os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
5375 return 17;
5376 }
b563b388
JM
5377 }
5378
5379 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
b31be3a0 5380 persistent_group, automatic, join,
c27f4c90 5381 auth, go_intent, freq, freq2, persistent_id,
8edd9f10
JM
5382 pd, ht40, vht, max_oper_chwidth,
5383 group_ssid, group_ssid_len);
d054a462
JM
5384 if (new_pin == -2) {
5385 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
5386 return 25;
5387 }
5388 if (new_pin == -3) {
5389 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
5390 return 25;
5391 }
b563b388
JM
5392 if (new_pin < 0)
5393 return -1;
5394 if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
5395 ret = os_snprintf(buf, buflen, "%08d", new_pin);
d85e1fc8 5396 if (os_snprintf_error(buflen, ret))
b563b388
JM
5397 return -1;
5398 return ret;
5399 }
5400
5401 os_memcpy(buf, "OK\n", 3);
5402 return 3;
5403}
5404
5405
5406static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
5407{
5408 unsigned int timeout = atoi(cmd);
e9eb648e
JM
5409 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
5410 wpa_dbg(wpa_s, MSG_INFO,
5411 "Reject P2P_LISTEN since interface is disabled");
5412 return -1;
5413 }
b563b388
JM
5414 return wpas_p2p_listen(wpa_s, timeout);
5415}
5416
5417
5418static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
5419{
5420 u8 addr[ETH_ALEN];
5421 char *pos;
0918c4bf 5422 enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
b563b388 5423
0918c4bf 5424 /* <addr> <config method> [join|auto] */
b563b388
JM
5425
5426 if (hwaddr_aton(cmd, addr))
5427 return -1;
5428
5429 pos = cmd + 17;
5430 if (*pos != ' ')
5431 return -1;
5432 pos++;
5433
0918c4bf
JM
5434 if (os_strstr(pos, " join") != NULL)
5435 use = WPAS_P2P_PD_FOR_JOIN;
5436 else if (os_strstr(pos, " auto") != NULL)
5437 use = WPAS_P2P_PD_AUTO;
5438
6d908514 5439 return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
b563b388
JM
5440}
5441
5442
5443static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
5444 size_t buflen)
5445{
5446 struct wpa_ssid *ssid = wpa_s->current_ssid;
5447
5448 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
5449 ssid->passphrase == NULL)
5450 return -1;
5451
5452 os_strlcpy(buf, ssid->passphrase, buflen);
5453 return os_strlen(buf);
5454}
5455
5456
5457static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
5458 char *buf, size_t buflen)
5459{
5460 u64 ref;
5461 int res;
5462 u8 dst_buf[ETH_ALEN], *dst;
5463 struct wpabuf *tlvs;
5464 char *pos;
5465 size_t len;
5466
5467 if (hwaddr_aton(cmd, dst_buf))
5468 return -1;
5469 dst = dst_buf;
5470 if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
5471 dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
5472 dst = NULL;
5473 pos = cmd + 17;
5474 if (*pos != ' ')
5475 return -1;
5476 pos++;
5477
5478 if (os_strncmp(pos, "upnp ", 5) == 0) {
5479 u8 version;
5480 pos += 5;
5481 if (hexstr2bin(pos, &version, 1) < 0)
5482 return -1;
5483 pos += 2;
5484 if (*pos != ' ')
5485 return -1;
5486 pos++;
7165c5dc 5487 ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
347d6a5b
JM
5488#ifdef CONFIG_WIFI_DISPLAY
5489 } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
5490 ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
5491#endif /* CONFIG_WIFI_DISPLAY */
5a4102ce
KV
5492 } else if (os_strncmp(pos, "asp ", 4) == 0) {
5493 char *svc_str;
5494 char *svc_info = NULL;
5495 u32 id;
5496
5497 pos += 4;
5498 if (sscanf(pos, "%x", &id) != 1 || id > 0xff)
5499 return -1;
5500
5501 pos = os_strchr(pos, ' ');
5502 if (pos == NULL || pos[1] == '\0' || pos[1] == ' ')
5503 return -1;
5504
5505 svc_str = pos + 1;
5506
5507 pos = os_strchr(svc_str, ' ');
5508
5509 if (pos)
5510 *pos++ = '\0';
5511
5512 /* All remaining data is the svc_info string */
5513 if (pos && pos[0] && pos[0] != ' ') {
5514 len = os_strlen(pos);
5515
5516 /* Unescape in place */
5517 len = utf8_unescape(pos, len, pos, len);
5518 if (len > 0xff)
5519 return -1;
5520
5521 svc_info = pos;
5522 }
5523
5524 ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id,
5525 svc_str, svc_info);
b563b388
JM
5526 } else {
5527 len = os_strlen(pos);
5528 if (len & 1)
5529 return -1;
5530 len /= 2;
5531 tlvs = wpabuf_alloc(len);
5532 if (tlvs == NULL)
5533 return -1;
5534 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
5535 wpabuf_free(tlvs);
5536 return -1;
5537 }
5538
7165c5dc 5539 ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
b563b388
JM
5540 wpabuf_free(tlvs);
5541 }
7165c5dc
JM
5542 if (ref == 0)
5543 return -1;
b563b388 5544 res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
d85e1fc8 5545 if (os_snprintf_error(buflen, res))
b563b388
JM
5546 return -1;
5547 return res;
5548}
5549
5550
5551static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
5552 char *cmd)
5553{
5554 long long unsigned val;
5555 u64 req;
5556 if (sscanf(cmd, "%llx", &val) != 1)
5557 return -1;
5558 req = val;
7165c5dc 5559 return wpas_p2p_sd_cancel_request(wpa_s, req);
b563b388
JM
5560}
5561
5562
5563static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
5564{
5565 int freq;
d25f7212 5566 u8 dst[ETH_ALEN];
b563b388
JM
5567 u8 dialog_token;
5568 struct wpabuf *resp_tlvs;
5569 char *pos, *pos2;
5570 size_t len;
5571
5572 pos = os_strchr(cmd, ' ');
5573 if (pos == NULL)
5574 return -1;
5575 *pos++ = '\0';
5576 freq = atoi(cmd);
5577 if (freq == 0)
5578 return -1;
5579
d25f7212 5580 if (hwaddr_aton(pos, dst))
b563b388 5581 return -1;
b563b388
JM
5582 pos += 17;
5583 if (*pos != ' ')
5584 return -1;
5585 pos++;
5586
5587 pos2 = os_strchr(pos, ' ');
5588 if (pos2 == NULL)
5589 return -1;
5590 *pos2++ = '\0';
5591 dialog_token = atoi(pos);
5592
5593 len = os_strlen(pos2);
5594 if (len & 1)
5595 return -1;
5596 len /= 2;
5597 resp_tlvs = wpabuf_alloc(len);
5598 if (resp_tlvs == NULL)
5599 return -1;
5600 if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
5601 wpabuf_free(resp_tlvs);
5602 return -1;
5603 }
5604
5605 wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
5606 wpabuf_free(resp_tlvs);
5607 return 0;
5608}
5609
5610
5611static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
5612 char *cmd)
5613{
28ef705d
GB
5614 if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
5615 return -1;
b563b388
JM
5616 wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
5617 return 0;
5618}
5619
5620
5621static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
5622 char *cmd)
5623{
5624 char *pos;
5625 size_t len;
5626 struct wpabuf *query, *resp;
5627
5628 pos = os_strchr(cmd, ' ');
5629 if (pos == NULL)
5630 return -1;
5631 *pos++ = '\0';
5632
5633 len = os_strlen(cmd);
5634 if (len & 1)
5635 return -1;
5636 len /= 2;
5637 query = wpabuf_alloc(len);
5638 if (query == NULL)
5639 return -1;
5640 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
5641 wpabuf_free(query);
5642 return -1;
5643 }
5644
5645 len = os_strlen(pos);
5646 if (len & 1) {
5647 wpabuf_free(query);
5648 return -1;
5649 }
5650 len /= 2;
5651 resp = wpabuf_alloc(len);
5652 if (resp == NULL) {
5653 wpabuf_free(query);
5654 return -1;
5655 }
5656 if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
5657 wpabuf_free(query);
5658 wpabuf_free(resp);
5659 return -1;
5660 }
5661
5662 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
5663 wpabuf_free(query);
5664 wpabuf_free(resp);
5665 return -1;
5666 }
5667 return 0;
5668}
5669
5670
5671static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
5672{
5673 char *pos;
5674 u8 version;
5675
5676 pos = os_strchr(cmd, ' ');
5677 if (pos == NULL)
5678 return -1;
5679 *pos++ = '\0';
5680
5681 if (hexstr2bin(cmd, &version, 1) < 0)
5682 return -1;
5683
5684 return wpas_p2p_service_add_upnp(wpa_s, version, pos);
5685}
5686
5687
ae9d45f3
KV
5688static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,
5689 u8 replace, char *cmd)
5690{
5691 char *pos;
5692 char *adv_str;
5693 u32 auto_accept, adv_id, svc_state, config_methods;
5694 char *svc_info = NULL;
e2b7fbf2
MS
5695 char *cpt_prio_str;
5696 u8 cpt_prio[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
ae9d45f3
KV
5697
5698 pos = os_strchr(cmd, ' ');
5699 if (pos == NULL)
5700 return -1;
5701 *pos++ = '\0';
5702
5703 /* Auto-Accept value is mandatory, and must be one of the
5704 * single values (0, 1, 2, 4) */
5705 auto_accept = atoi(cmd);
5706 switch (auto_accept) {
5707 case P2PS_SETUP_NONE: /* No auto-accept */
5708 case P2PS_SETUP_NEW:
5709 case P2PS_SETUP_CLIENT:
5710 case P2PS_SETUP_GROUP_OWNER:
5711 break;
5712 default:
5713 return -1;
5714 }
5715
5716 /* Advertisement ID is mandatory */
5717 cmd = pos;
5718 pos = os_strchr(cmd, ' ');
5719 if (pos == NULL)
5720 return -1;
5721 *pos++ = '\0';
5722
5723 /* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */
5724 if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0)
5725 return -1;
5726
5727 /* Only allow replacements if exist, and adds if not */
5728 if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) {
5729 if (!replace)
5730 return -1;
5731 } else {
5732 if (replace)
5733 return -1;
5734 }
5735
5736 /* svc_state between 0 - 0xff is mandatory */
5737 if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff)
5738 return -1;
5739
5740 pos = os_strchr(pos, ' ');
5741 if (pos == NULL)
5742 return -1;
5743
5744 /* config_methods is mandatory */
5745 pos++;
5746 if (sscanf(pos, "%x", &config_methods) != 1)
5747 return -1;
5748
5749 if (!(config_methods &
5750 (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS)))
5751 return -1;
5752
5753 pos = os_strchr(pos, ' ');
5754 if (pos == NULL)
5755 return -1;
5756
5757 pos++;
5758 adv_str = pos;
5759
5760 /* Advertisement string is mandatory */
5761 if (!pos[0] || pos[0] == ' ')
5762 return -1;
5763
5764 /* Terminate svc string */
5765 pos = os_strchr(pos, ' ');
5766 if (pos != NULL)
5767 *pos++ = '\0';
5768
e2b7fbf2
MS
5769 cpt_prio_str = (pos && pos[0]) ? os_strstr(pos, "cpt=") : NULL;
5770 if (cpt_prio_str) {
5771 pos = os_strchr(pos, ' ');
5772 if (pos != NULL)
5773 *pos++ = '\0';
5774
5775 if (p2ps_ctrl_parse_cpt_priority(cpt_prio_str + 4, cpt_prio))
5776 return -1;
5777 } else {
5778 cpt_prio[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
5779 cpt_prio[1] = 0;
5780 }
5781
ae9d45f3
KV
5782 /* Service and Response Information are optional */
5783 if (pos && pos[0]) {
5784 size_t len;
5785
5786 /* Note the bare ' included, which cannot exist legally
5787 * in unescaped string. */
5788 svc_info = os_strstr(pos, "svc_info='");
5789
5790 if (svc_info) {
5791 svc_info += 9;
5792 len = os_strlen(svc_info);
5793 utf8_unescape(svc_info, len, svc_info, len);
5794 }
5795 }
5796
5797 return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,
5798 (u8) svc_state, (u16) config_methods,
e2b7fbf2 5799 svc_info, cpt_prio);
ae9d45f3
KV
5800}
5801
5802
b563b388
JM
5803static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
5804{
5805 char *pos;
5806
5807 pos = os_strchr(cmd, ' ');
5808 if (pos == NULL)
5809 return -1;
5810 *pos++ = '\0';
5811
5812 if (os_strcmp(cmd, "bonjour") == 0)
5813 return p2p_ctrl_service_add_bonjour(wpa_s, pos);
5814 if (os_strcmp(cmd, "upnp") == 0)
5815 return p2p_ctrl_service_add_upnp(wpa_s, pos);
ae9d45f3
KV
5816 if (os_strcmp(cmd, "asp") == 0)
5817 return p2p_ctrl_service_add_asp(wpa_s, 0, pos);
b563b388
JM
5818 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5819 return -1;
5820}
5821
5822
5823static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
5824 char *cmd)
5825{
5826 size_t len;
5827 struct wpabuf *query;
5828 int ret;
5829
5830 len = os_strlen(cmd);
5831 if (len & 1)
5832 return -1;
5833 len /= 2;
5834 query = wpabuf_alloc(len);
5835 if (query == NULL)
5836 return -1;
5837 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
5838 wpabuf_free(query);
5839 return -1;
5840 }
5841
5842 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
5843 wpabuf_free(query);
5844 return ret;
5845}
5846
5847
5848static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
5849{
5850 char *pos;
5851 u8 version;
5852
5853 pos = os_strchr(cmd, ' ');
5854 if (pos == NULL)
5855 return -1;
5856 *pos++ = '\0';
5857
5858 if (hexstr2bin(cmd, &version, 1) < 0)
5859 return -1;
5860
5861 return wpas_p2p_service_del_upnp(wpa_s, version, pos);
5862}
5863
5864
ae9d45f3
KV
5865static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)
5866{
5867 u32 adv_id;
5868
e9d28050
MS
5869 if (os_strcmp(cmd, "all") == 0) {
5870 wpas_p2p_service_flush_asp(wpa_s);
5871 return 0;
5872 }
5873
ae9d45f3
KV
5874 if (sscanf(cmd, "%x", &adv_id) != 1)
5875 return -1;
5876
5877 return wpas_p2p_service_del_asp(wpa_s, adv_id);
5878}
5879
5880
b563b388
JM
5881static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
5882{
5883 char *pos;
5884
5885 pos = os_strchr(cmd, ' ');
5886 if (pos == NULL)
5887 return -1;
5888 *pos++ = '\0';
5889
5890 if (os_strcmp(cmd, "bonjour") == 0)
5891 return p2p_ctrl_service_del_bonjour(wpa_s, pos);
5892 if (os_strcmp(cmd, "upnp") == 0)
5893 return p2p_ctrl_service_del_upnp(wpa_s, pos);
ae9d45f3
KV
5894 if (os_strcmp(cmd, "asp") == 0)
5895 return p2p_ctrl_service_del_asp(wpa_s, pos);
5896 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5897 return -1;
5898}
5899
5900
5901static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd)
5902{
5903 char *pos;
5904
5905 pos = os_strchr(cmd, ' ');
5906 if (pos == NULL)
5907 return -1;
5908 *pos++ = '\0';
5909
5910 if (os_strcmp(cmd, "asp") == 0)
5911 return p2p_ctrl_service_add_asp(wpa_s, 1, pos);
5912
b563b388
JM
5913 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5914 return -1;
5915}
5916
5917
5918static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
5919{
5920 u8 addr[ETH_ALEN];
5921
5922 /* <addr> */
5923
5924 if (hwaddr_aton(cmd, addr))
5925 return -1;
5926
5927 return wpas_p2p_reject(wpa_s, addr);
5928}
5929
5930
5931static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
5932{
5933 char *pos;
5934 int id;
5935 struct wpa_ssid *ssid;
54c61e6e 5936 u8 *_peer = NULL, peer[ETH_ALEN];
f5877af0 5937 int freq = 0, pref_freq = 0;
c27f4c90 5938 int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
b563b388
JM
5939
5940 id = atoi(cmd);
5941 pos = os_strstr(cmd, " peer=");
5942 if (pos) {
5943 pos += 6;
5944 if (hwaddr_aton(pos, peer))
5945 return -1;
54c61e6e 5946 _peer = peer;
b563b388
JM
5947 }
5948 ssid = wpa_config_get_network(wpa_s->conf, id);
5949 if (ssid == NULL || ssid->disabled != 2) {
5950 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
5951 "for persistent P2P group",
5952 id);
5953 return -1;
5954 }
5955
4d32c0c4
JM
5956 pos = os_strstr(cmd, " freq=");
5957 if (pos) {
5958 pos += 6;
5959 freq = atoi(pos);
5960 if (freq <= 0)
5961 return -1;
5962 }
5963
f5877af0
JM
5964 pos = os_strstr(cmd, " pref=");
5965 if (pos) {
5966 pos += 6;
5967 pref_freq = atoi(pos);
5968 if (pref_freq <= 0)
5969 return -1;
5970 }
5971
20ea1ca4
EP
5972 vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
5973 ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
5974 vht;
4d32c0c4 5975
c27f4c90
AK
5976 pos = os_strstr(cmd, "freq2=");
5977 if (pos)
5978 freq2 = atoi(pos + 6);
5979
5980 pos = os_strstr(cmd, " max_oper_chwidth=");
5981 if (pos)
5982 chwidth = atoi(pos + 18);
5983
5984 max_oper_chwidth = parse_freq(chwidth, freq2);
5985 if (max_oper_chwidth < 0)
5986 return -1;
5987
5988 return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
5989 max_oper_chwidth, pref_freq);
b563b388
JM
5990}
5991
5992
5993static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
5994{
5995 char *pos;
5996 u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
5997
5998 pos = os_strstr(cmd, " peer=");
5999 if (!pos)
6000 return -1;
6001
6002 *pos = '\0';
6003 pos += 6;
6004 if (hwaddr_aton(pos, peer)) {
6005 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
6006 return -1;
6007 }
6008
6009 pos = os_strstr(pos, " go_dev_addr=");
6010 if (pos) {
6011 pos += 13;
6012 if (hwaddr_aton(pos, go_dev_addr)) {
6013 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
6014 pos);
6015 return -1;
6016 }
6017 go_dev = go_dev_addr;
6018 }
6019
6020 return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
6021}
6022
6023
6024static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
6025{
6026 if (os_strncmp(cmd, "persistent=", 11) == 0)
6027 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
6028 if (os_strncmp(cmd, "group=", 6) == 0)
6029 return p2p_ctrl_invite_group(wpa_s, cmd + 6);
6030
6031 return -1;
6032}
6033
6034
6035static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
c27f4c90
AK
6036 int id, int freq, int vht_center_freq2,
6037 int ht40, int vht, int vht_chwidth)
b563b388 6038{
b563b388
JM
6039 struct wpa_ssid *ssid;
6040
b563b388
JM
6041 ssid = wpa_config_get_network(wpa_s->conf, id);
6042 if (ssid == NULL || ssid->disabled != 2) {
6043 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
6044 "for persistent P2P group",
6045 id);
6046 return -1;
6047 }
6048
c27f4c90
AK
6049 return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
6050 vht_center_freq2, 0, ht40, vht,
6051 vht_chwidth, NULL, 0, 0);
b563b388
JM
6052}
6053
6054
6055static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
6056{
29292d53
EP
6057 int freq = 0, persistent = 0, group_id = -1;
6058 int vht = wpa_s->conf->p2p_go_vht;
6059 int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
c27f4c90 6060 int max_oper_chwidth, chwidth = 0, freq2 = 0;
29292d53 6061 char *token, *context = NULL;
e11776a5 6062
29292d53
EP
6063 while ((token = str_token(cmd, " ", &context))) {
6064 if (sscanf(token, "freq=%d", &freq) == 1 ||
c27f4c90
AK
6065 sscanf(token, "freq2=%d", &freq2) == 1 ||
6066 sscanf(token, "persistent=%d", &group_id) == 1 ||
6067 sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
29292d53
EP
6068 continue;
6069 } else if (os_strcmp(token, "ht40") == 0) {
6070 ht40 = 1;
6071 } else if (os_strcmp(token, "vht") == 0) {
6072 vht = 1;
6073 ht40 = 1;
6074 } else if (os_strcmp(token, "persistent") == 0) {
6075 persistent = 1;
6076 } else {
6077 wpa_printf(MSG_DEBUG,
6078 "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'",
6079 token);
6080 return -1;
6081 }
e11776a5
PK
6082 }
6083
c27f4c90
AK
6084 max_oper_chwidth = parse_freq(chwidth, freq2);
6085 if (max_oper_chwidth < 0)
6086 return -1;
6087
29292d53
EP
6088 if (group_id >= 0)
6089 return p2p_ctrl_group_add_persistent(wpa_s, group_id,
c27f4c90
AK
6090 freq, freq2, ht40, vht,
6091 max_oper_chwidth);
29292d53 6092
c27f4c90
AK
6093 return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
6094 max_oper_chwidth);
b563b388
JM
6095}
6096
6097
57b38882
PK
6098static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd,
6099 char *buf, size_t buflen)
6100{
6101 u8 dev_addr[ETH_ALEN];
6102 struct wpa_ssid *ssid;
6103 int res;
6104 const u8 *iaddr;
6105
6106 ssid = wpa_s->current_ssid;
6107 if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO ||
6108 hwaddr_aton(cmd, dev_addr))
6109 return -1;
6110
6111 iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr);
6112 if (!iaddr)
6113 return -1;
6114 res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr));
6115 if (os_snprintf_error(buflen, res))
6116 return -1;
6117 return res;
6118}
6119
6120
f47f9361
SD
6121static int wpas_find_p2p_dev_addr_bss(struct wpa_global *global,
6122 const u8 *p2p_dev_addr)
6123{
6124 struct wpa_supplicant *wpa_s;
6125
6126 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
6127 if (wpa_bss_get_p2p_dev_addr(wpa_s, p2p_dev_addr))
6128 return 1;
6129 }
6130
6131 return 0;
6132}
6133
6134
b563b388
JM
6135static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
6136 char *buf, size_t buflen)
6137{
f47f9361 6138 u8 addr[ETH_ALEN], *addr_ptr, group_capab;
b3ffc80b
JM
6139 int next, res;
6140 const struct p2p_peer_info *info;
6141 char *pos, *end;
6142 char devtype[WPS_DEV_TYPE_BUFSIZE];
87f841a1 6143 struct wpa_ssid *ssid;
f3989ced 6144 size_t i;
b563b388
JM
6145
6146 if (!wpa_s->global->p2p)
6147 return -1;
6148
6149 if (os_strcmp(cmd, "FIRST") == 0) {
6150 addr_ptr = NULL;
6151 next = 0;
6152 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
6153 if (hwaddr_aton(cmd + 5, addr) < 0)
6154 return -1;
6155 addr_ptr = addr;
6156 next = 1;
6157 } else {
6158 if (hwaddr_aton(cmd, addr) < 0)
6159 return -1;
6160 addr_ptr = addr;
6161 next = 0;
6162 }
6163
b3ffc80b
JM
6164 info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
6165 if (info == NULL)
6166 return -1;
f47f9361
SD
6167 group_capab = info->group_capab;
6168
6169 if (group_capab &&
6170 !wpas_find_p2p_dev_addr_bss(wpa_s->global, info->p2p_device_addr)) {
6171 wpa_printf(MSG_DEBUG,
6172 "P2P: Could not find any BSS with p2p_dev_addr "
6173 MACSTR ", hence override group_capab from 0x%x to 0",
6174 MAC2STR(info->p2p_device_addr), group_capab);
6175 group_capab = 0;
6176 }
b3ffc80b
JM
6177
6178 pos = buf;
6179 end = buf + buflen;
6180
6181 res = os_snprintf(pos, end - pos, MACSTR "\n"
6182 "pri_dev_type=%s\n"
6183 "device_name=%s\n"
6184 "manufacturer=%s\n"
6185 "model_name=%s\n"
6186 "model_number=%s\n"
6187 "serial_number=%s\n"
6188 "config_methods=0x%x\n"
6189 "dev_capab=0x%x\n"
6190 "group_capab=0x%x\n"
6191 "level=%d\n",
6192 MAC2STR(info->p2p_device_addr),
6193 wps_dev_type_bin2str(info->pri_dev_type,
6194 devtype, sizeof(devtype)),
6195 info->device_name,
6196 info->manufacturer,
6197 info->model_name,
6198 info->model_number,
6199 info->serial_number,
6200 info->config_methods,
6201 info->dev_capab,
f47f9361 6202 group_capab,
b3ffc80b 6203 info->level);
d85e1fc8 6204 if (os_snprintf_error(end - pos, res))
b3ffc80b
JM
6205 return pos - buf;
6206 pos += res;
6207
f3989ced
JM
6208 for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
6209 {
6210 const u8 *t;
6211 t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
6212 res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
6213 wps_dev_type_bin2str(t, devtype,
6214 sizeof(devtype)));
d85e1fc8 6215 if (os_snprintf_error(end - pos, res))
f3989ced
JM
6216 return pos - buf;
6217 pos += res;
6218 }
6219
c427ac92 6220 ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
87f841a1
JM
6221 if (ssid) {
6222 res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
d85e1fc8 6223 if (os_snprintf_error(end - pos, res))
87f841a1
JM
6224 return pos - buf;
6225 pos += res;
6226 }
6227
b3ffc80b
JM
6228 res = p2p_get_peer_info_txt(info, pos, end - pos);
6229 if (res < 0)
87f841a1 6230 return pos - buf;
b3ffc80b
JM
6231 pos += res;
6232
71a0e395
JM
6233 if (info->vendor_elems) {
6234 res = os_snprintf(pos, end - pos, "vendor_elems=");
d85e1fc8 6235 if (os_snprintf_error(end - pos, res))
71a0e395
JM
6236 return pos - buf;
6237 pos += res;
6238
6239 pos += wpa_snprintf_hex(pos, end - pos,
6240 wpabuf_head(info->vendor_elems),
6241 wpabuf_len(info->vendor_elems));
6242
6243 res = os_snprintf(pos, end - pos, "\n");
d85e1fc8 6244 if (os_snprintf_error(end - pos, res))
71a0e395
JM
6245 return pos - buf;
6246 pos += res;
6247 }
6248
b3ffc80b 6249 return pos - buf;
b563b388
JM
6250}
6251
6252
6f3bc72b
JM
6253static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
6254 const char *param)
6255{
af8a827b 6256 unsigned int i;
6f3bc72b
JM
6257
6258 if (wpa_s->global->p2p == NULL)
6259 return -1;
6260
af8a827b
JM
6261 if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
6262 return -1;
6f3bc72b 6263
af8a827b
JM
6264 for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
6265 struct wpa_freq_range *freq;
6266 freq = &wpa_s->global->p2p_disallow_freq.range[i];
6f3bc72b 6267 wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
af8a827b 6268 freq->min, freq->max);
6f3bc72b
JM
6269 }
6270
3a8f008a 6271 wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW);
6f3bc72b
JM
6272 return 0;
6273}
6274
6275
b563b388
JM
6276static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
6277{
6278 char *param;
6279
6280 if (wpa_s->global->p2p == NULL)
6281 return -1;
6282
6283 param = os_strchr(cmd, ' ');
6284 if (param == NULL)
6285 return -1;
6286 *param++ = '\0';
6287
6288 if (os_strcmp(cmd, "discoverability") == 0) {
6289 p2p_set_client_discoverability(wpa_s->global->p2p,
6290 atoi(param));
6291 return 0;
6292 }
6293
6294 if (os_strcmp(cmd, "managed") == 0) {
6295 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
6296 return 0;
6297 }
6298
6299 if (os_strcmp(cmd, "listen_channel") == 0) {
dfe0745c
LD
6300 char *pos;
6301 u8 channel, op_class;
6302
6303 channel = atoi(param);
6304 pos = os_strchr(param, ' ');
6305 op_class = pos ? atoi(pos) : 81;
6306
6307 return p2p_set_listen_channel(wpa_s->global->p2p, op_class,
6308 channel, 1);
b563b388
JM
6309 }
6310
6311 if (os_strcmp(cmd, "ssid_postfix") == 0) {
6312 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
6313 os_strlen(param));
6314 }
6315
6316 if (os_strcmp(cmd, "noa") == 0) {
6317 char *pos;
6318 int count, start, duration;
6319 /* GO NoA parameters: count,start_offset(ms),duration(ms) */
6320 count = atoi(param);
6321 pos = os_strchr(param, ',');
6322 if (pos == NULL)
6323 return -1;
6324 pos++;
6325 start = atoi(pos);
6326 pos = os_strchr(pos, ',');
6327 if (pos == NULL)
6328 return -1;
6329 pos++;
6330 duration = atoi(pos);
6331 if (count < 0 || count > 255 || start < 0 || duration < 0)
6332 return -1;
6333 if (count == 0 && duration > 0)
6334 return -1;
6335 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
6336 "start=%d duration=%d", count, start, duration);
aefb53bd 6337 return wpas_p2p_set_noa(wpa_s, count, start, duration);
b563b388
JM
6338 }
6339
c381508d
JM
6340 if (os_strcmp(cmd, "ps") == 0)
6341 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
6342
6343 if (os_strcmp(cmd, "oppps") == 0)
6344 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
6345
6346 if (os_strcmp(cmd, "ctwindow") == 0)
6347 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
6348
b563b388
JM
6349 if (os_strcmp(cmd, "disabled") == 0) {
6350 wpa_s->global->p2p_disabled = atoi(param);
6351 wpa_printf(MSG_DEBUG, "P2P functionality %s",
6352 wpa_s->global->p2p_disabled ?
6353 "disabled" : "enabled");
6354 if (wpa_s->global->p2p_disabled) {
6355 wpas_p2p_stop_find(wpa_s);
108def93 6356 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
b563b388
JM
6357 p2p_flush(wpa_s->global->p2p);
6358 }
6359 return 0;
6360 }
6361
b9cfc09a
JJ
6362 if (os_strcmp(cmd, "conc_pref") == 0) {
6363 if (os_strcmp(param, "sta") == 0)
6364 wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
6365 else if (os_strcmp(param, "p2p") == 0)
6366 wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
6367 else {
6368 wpa_printf(MSG_INFO, "Invalid conc_pref value");
6369 return -1;
6370 }
6371 wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
6372 "%s", param);
6373 return 0;
6374 }
6375
6e6963ea
JM
6376 if (os_strcmp(cmd, "force_long_sd") == 0) {
6377 wpa_s->force_long_sd = atoi(param);
6378 return 0;
6379 }
6380
80c9582a
JM
6381 if (os_strcmp(cmd, "peer_filter") == 0) {
6382 u8 addr[ETH_ALEN];
6383 if (hwaddr_aton(param, addr))
6384 return -1;
6385 p2p_set_peer_filter(wpa_s->global->p2p, addr);
6386 return 0;
6387 }
6388
72044390
JM
6389 if (os_strcmp(cmd, "cross_connect") == 0)
6390 return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
6391
eea2fd9e
JM
6392 if (os_strcmp(cmd, "go_apsd") == 0) {
6393 if (os_strcmp(param, "disable") == 0)
6394 wpa_s->set_ap_uapsd = 0;
6395 else {
6396 wpa_s->set_ap_uapsd = 1;
6397 wpa_s->ap_uapsd = atoi(param);
6398 }
6399 return 0;
6400 }
6401
6402 if (os_strcmp(cmd, "client_apsd") == 0) {
6403 if (os_strcmp(param, "disable") == 0)
6404 wpa_s->set_sta_uapsd = 0;
6405 else {
6406 int be, bk, vi, vo;
6407 char *pos;
6408 /* format: BE,BK,VI,VO;max SP Length */
6409 be = atoi(param);
6410 pos = os_strchr(param, ',');
6411 if (pos == NULL)
6412 return -1;
6413 pos++;
6414 bk = atoi(pos);
6415 pos = os_strchr(pos, ',');
6416 if (pos == NULL)
6417 return -1;
6418 pos++;
6419 vi = atoi(pos);
6420 pos = os_strchr(pos, ',');
6421 if (pos == NULL)
6422 return -1;
6423 pos++;
6424 vo = atoi(pos);
6425 /* ignore max SP Length for now */
6426
6427 wpa_s->set_sta_uapsd = 1;
6428 wpa_s->sta_uapsd = 0;
6429 if (be)
6430 wpa_s->sta_uapsd |= BIT(0);
6431 if (bk)
6432 wpa_s->sta_uapsd |= BIT(1);
6433 if (vi)
6434 wpa_s->sta_uapsd |= BIT(2);
6435 if (vo)
6436 wpa_s->sta_uapsd |= BIT(3);
6437 }
6438 return 0;
6439 }
6440
6f3bc72b
JM
6441 if (os_strcmp(cmd, "disallow_freq") == 0)
6442 return p2p_ctrl_disallow_freq(wpa_s, param);
6443
96beff11
JM
6444 if (os_strcmp(cmd, "disc_int") == 0) {
6445 int min_disc_int, max_disc_int, max_disc_tu;
6446 char *pos;
6447
6448 pos = param;
6449
6450 min_disc_int = atoi(pos);
6451 pos = os_strchr(pos, ' ');
6452 if (pos == NULL)
6453 return -1;
6454 *pos++ = '\0';
6455
6456 max_disc_int = atoi(pos);
6457 pos = os_strchr(pos, ' ');
6458 if (pos == NULL)
6459 return -1;
6460 *pos++ = '\0';
6461
6462 max_disc_tu = atoi(pos);
6463
6464 return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
6465 max_disc_int, max_disc_tu);
6466 }
6467
05766ed8
JM
6468 if (os_strcmp(cmd, "per_sta_psk") == 0) {
6469 wpa_s->global->p2p_per_sta_psk = !!atoi(param);
6470 return 0;
6471 }
6472
c4f87a70
JM
6473#ifdef CONFIG_WPS_NFC
6474 if (os_strcmp(cmd, "nfc_tag") == 0)
6475 return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
6476#endif /* CONFIG_WPS_NFC */
6477
201b0f5f
JM
6478 if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
6479 wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
6480 return 0;
6481 }
6482
3a7819f0
JM
6483 if (os_strcmp(cmd, "override_pref_op_chan") == 0) {
6484 int op_class, chan;
6485
6486 op_class = atoi(param);
6487 param = os_strchr(param, ':');
6488 if (!param)
6489 return -1;
6490 param++;
6491 chan = atoi(param);
6492 p2p_set_override_pref_op_chan(wpa_s->global->p2p, op_class,
6493 chan);
6494 return 0;
6495 }
6496
b563b388
JM
6497 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
6498 cmd);
6499
6500 return -1;
6501}
6502
6503
acb54643
JM
6504static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
6505{
6506 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
6507 wpa_s->force_long_sd = 0;
477b082c 6508 wpas_p2p_stop_find(wpa_s);
b9da88d6 6509 wpa_s->parent->p2ps_method_config_any = 0;
acb54643
JM
6510 if (wpa_s->global->p2p)
6511 p2p_flush(wpa_s->global->p2p);
6512}
6513
6514
b563b388
JM
6515static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
6516{
6517 char *pos, *pos2;
6518 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
6519
6520 if (cmd[0]) {
6521 pos = os_strchr(cmd, ' ');
6522 if (pos == NULL)
6523 return -1;
6524 *pos++ = '\0';
6525 dur1 = atoi(cmd);
6526
6527 pos2 = os_strchr(pos, ' ');
6528 if (pos2)
6529 *pos2++ = '\0';
6530 int1 = atoi(pos);
6531 } else
6532 pos2 = NULL;
6533
6534 if (pos2) {
6535 pos = os_strchr(pos2, ' ');
6536 if (pos == NULL)
6537 return -1;
6538 *pos++ = '\0';
6539 dur2 = atoi(pos2);
6540 int2 = atoi(pos);
6541 }
6542
6543 return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
6544}
6545
6546
6547static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
6548{
6549 char *pos;
6550 unsigned int period = 0, interval = 0;
6551
6552 if (cmd[0]) {
6553 pos = os_strchr(cmd, ' ');
6554 if (pos == NULL)
6555 return -1;
6556 *pos++ = '\0';
6557 period = atoi(cmd);
6558 interval = atoi(pos);
6559 }
6560
6561 return wpas_p2p_ext_listen(wpa_s, period, interval);
6562}
6563
f2c56602
JM
6564
6565static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
6566{
6567 const char *pos;
6568 u8 peer[ETH_ALEN];
6569 int iface_addr = 0;
6570
6571 pos = cmd;
6572 if (os_strncmp(pos, "iface=", 6) == 0) {
6573 iface_addr = 1;
6574 pos += 6;
6575 }
6576 if (hwaddr_aton(pos, peer))
6577 return -1;
6578
6579 wpas_p2p_remove_client(wpa_s, peer, iface_addr);
6580 return 0;
6581}
6582
a6f5b193
PX
6583
6584static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
6585{
6586 int freq = 0, period = 0, interval = 0, count = 0;
6587
6588 if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
6589 {
6590 wpa_printf(MSG_DEBUG,
6591 "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
6592 return -1;
6593 }
6594
6595 return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
6596}
6597
b563b388
JM
6598#endif /* CONFIG_P2P */
6599
6600
356d1488
JM
6601static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
6602{
6603 struct wpa_freq_range_list ranges;
6604 int *freqs = NULL;
6605 struct hostapd_hw_modes *mode;
6606 u16 i;
6607
6608 if (wpa_s->hw.modes == NULL)
6609 return NULL;
6610
6611 os_memset(&ranges, 0, sizeof(ranges));
6612 if (freq_range_list_parse(&ranges, val) < 0)
6613 return NULL;
6614
6615 for (i = 0; i < wpa_s->hw.num_modes; i++) {
6616 int j;
6617
6618 mode = &wpa_s->hw.modes[i];
6619 for (j = 0; j < mode->num_channels; j++) {
6620 unsigned int freq;
6621
6622 if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
6623 continue;
6624
6625 freq = mode->channels[j].freq;
6626 if (!freq_range_list_includes(&ranges, freq))
6627 continue;
6628
6629 int_array_add_unique(&freqs, freq);
6630 }
6631 }
6632
6633 os_free(ranges.range);
6634 return freqs;
6635}
6636
6637
afc064fe 6638#ifdef CONFIG_INTERWORKING
356d1488
JM
6639
6640static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
6641{
6642 int auto_sel = 0;
6643 int *freqs = NULL;
6644
6645 if (param) {
6646 char *pos;
6647
6648 auto_sel = os_strstr(param, "auto") != NULL;
6649
6650 pos = os_strstr(param, "freq=");
6651 if (pos) {
6652 freqs = freq_range_to_channel_list(wpa_s, pos + 5);
6653 if (freqs == NULL)
6654 return -1;
6655 }
6656
6657 }
6658
6659 return interworking_select(wpa_s, auto_sel, freqs);
6660}
6661
6662
f91a512f
JM
6663static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
6664 int only_add)
b02fe7ff
JM
6665{
6666 u8 bssid[ETH_ALEN];
6667 struct wpa_bss *bss;
6668
6669 if (hwaddr_aton(dst, bssid)) {
6670 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
6671 return -1;
6672 }
6673
6674 bss = wpa_bss_get_bssid(wpa_s, bssid);
6675 if (bss == NULL) {
6676 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
6677 MAC2STR(bssid));
6678 return -1;
6679 }
6680
783b2a97
JM
6681 if (bss->ssid_len == 0) {
6682 int found = 0;
6683
6684 wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
6685 " does not have SSID information", MAC2STR(bssid));
6686
6687 dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
6688 list) {
6689 if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
6690 bss->ssid_len > 0) {
6691 found = 1;
6692 break;
6693 }
6694 }
6695
6696 if (!found)
6697 return -1;
6698 wpa_printf(MSG_DEBUG,
6699 "Found another matching BSS entry with SSID");
6700 }
6701
f91a512f 6702 return interworking_connect(wpa_s, bss, only_add);
b02fe7ff
JM
6703}
6704
6705
afc064fe
JM
6706static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
6707{
6708 u8 dst_addr[ETH_ALEN];
6709 int used;
6710 char *pos;
6711#define MAX_ANQP_INFO_ID 100
6712 u16 id[MAX_ANQP_INFO_ID];
6713 size_t num_id = 0;
cf28c66b 6714 u32 subtypes = 0;
2316cb35 6715 u32 mbo_subtypes = 0;
afc064fe
JM
6716
6717 used = hwaddr_aton2(dst, dst_addr);
6718 if (used < 0)
6719 return -1;
6720 pos = dst + used;
b68d602d
JM
6721 if (*pos == ' ')
6722 pos++;
afc064fe 6723 while (num_id < MAX_ANQP_INFO_ID) {
cf28c66b
DS
6724 if (os_strncmp(pos, "hs20:", 5) == 0) {
6725#ifdef CONFIG_HS20
6726 int num = atoi(pos + 5);
6727 if (num <= 0 || num > 31)
6728 return -1;
6729 subtypes |= BIT(num);
6730#else /* CONFIG_HS20 */
6731 return -1;
6732#endif /* CONFIG_HS20 */
8f479174 6733 } else if (os_strncmp(pos, "mbo:", 4) == 0) {
6734#ifdef CONFIG_MBO
6735 int num = atoi(pos + 4);
2316cb35
AS
6736
6737 if (num <= 0 || num > MAX_MBO_ANQP_SUBTYPE)
8f479174 6738 return -1;
2316cb35 6739 mbo_subtypes |= BIT(num);
8f479174 6740#else /* CONFIG_MBO */
6741 return -1;
6742#endif /* CONFIG_MBO */
cf28c66b
DS
6743 } else {
6744 id[num_id] = atoi(pos);
6745 if (id[num_id])
6746 num_id++;
6747 }
afc064fe
JM
6748 pos = os_strchr(pos + 1, ',');
6749 if (pos == NULL)
6750 break;
6751 pos++;
6752 }
6753
6754 if (num_id == 0)
6755 return -1;
6756
8f479174 6757 return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
2316cb35 6758 mbo_subtypes);
afc064fe 6759}
b1f12296
JM
6760
6761
6762static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
6763{
6764 u8 dst_addr[ETH_ALEN];
6765 struct wpabuf *advproto, *query = NULL;
6766 int used, ret = -1;
6767 char *pos, *end;
6768 size_t len;
6769
6770 used = hwaddr_aton2(cmd, dst_addr);
6771 if (used < 0)
6772 return -1;
6773
6774 pos = cmd + used;
6775 while (*pos == ' ')
6776 pos++;
6777
6778 /* Advertisement Protocol ID */
6779 end = os_strchr(pos, ' ');
6780 if (end)
6781 len = end - pos;
6782 else
6783 len = os_strlen(pos);
6784 if (len & 0x01)
6785 return -1;
6786 len /= 2;
6787 if (len == 0)
6788 return -1;
6789 advproto = wpabuf_alloc(len);
6790 if (advproto == NULL)
6791 return -1;
6792 if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
6793 goto fail;
6794
6795 if (end) {
6796 /* Optional Query Request */
6797 pos = end + 1;
6798 while (*pos == ' ')
6799 pos++;
6800
6801 len = os_strlen(pos);
6802 if (len) {
6803 if (len & 0x01)
6804 goto fail;
6805 len /= 2;
6806 if (len == 0)
6807 goto fail;
6808 query = wpabuf_alloc(len);
6809 if (query == NULL)
6810 goto fail;
6811 if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
6812 goto fail;
6813 }
6814 }
6815
6816 ret = gas_send_request(wpa_s, dst_addr, advproto, query);
6817
6818fail:
6819 wpabuf_free(advproto);
6820 wpabuf_free(query);
6821
6822 return ret;
6823}
6824
6825
6826static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
6827 size_t buflen)
6828{
6829 u8 addr[ETH_ALEN];
6830 int dialog_token;
6831 int used;
6832 char *pos;
6833 size_t resp_len, start, requested_len;
b6a9590b
JM
6834 struct wpabuf *resp;
6835 int ret;
b1f12296
JM
6836
6837 used = hwaddr_aton2(cmd, addr);
6838 if (used < 0)
6839 return -1;
6840
6841 pos = cmd + used;
6842 while (*pos == ' ')
6843 pos++;
6844 dialog_token = atoi(pos);
6845
b6a9590b
JM
6846 if (wpa_s->last_gas_resp &&
6847 os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
6848 dialog_token == wpa_s->last_gas_dialog_token)
6849 resp = wpa_s->last_gas_resp;
6850 else if (wpa_s->prev_gas_resp &&
6851 os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
6852 dialog_token == wpa_s->prev_gas_dialog_token)
6853 resp = wpa_s->prev_gas_resp;
6854 else
b1f12296
JM
6855 return -1;
6856
b6a9590b 6857 resp_len = wpabuf_len(resp);
b1f12296
JM
6858 start = 0;
6859 requested_len = resp_len;
6860
6861 pos = os_strchr(pos, ' ');
6862 if (pos) {
6863 start = atoi(pos);
6864 if (start > resp_len)
6865 return os_snprintf(buf, buflen, "FAIL-Invalid range");
6866 pos = os_strchr(pos, ',');
6867 if (pos == NULL)
6868 return -1;
6869 pos++;
6870 requested_len = atoi(pos);
6871 if (start + requested_len > resp_len)
6872 return os_snprintf(buf, buflen, "FAIL-Invalid range");
6873 }
6874
6875 if (requested_len * 2 + 1 > buflen)
6876 return os_snprintf(buf, buflen, "FAIL-Too long response");
6877
b6a9590b
JM
6878 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
6879 requested_len);
6880
6881 if (start + requested_len == resp_len) {
6882 /*
6883 * Free memory by dropping the response after it has been
6884 * fetched.
6885 */
6886 if (resp == wpa_s->prev_gas_resp) {
6887 wpabuf_free(wpa_s->prev_gas_resp);
6888 wpa_s->prev_gas_resp = NULL;
6889 } else {
6890 wpabuf_free(wpa_s->last_gas_resp);
6891 wpa_s->last_gas_resp = NULL;
6892 }
6893 }
6894
6895 return ret;
b1f12296 6896}
afc064fe
JM
6897#endif /* CONFIG_INTERWORKING */
6898
6899
a8918e86
JK
6900#ifdef CONFIG_HS20
6901
6902static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
6903{
6904 u8 dst_addr[ETH_ALEN];
6905 int used;
6906 char *pos;
6907 u32 subtypes = 0;
6908
6909 used = hwaddr_aton2(dst, dst_addr);
6910 if (used < 0)
6911 return -1;
6912 pos = dst + used;
b68d602d
JM
6913 if (*pos == ' ')
6914 pos++;
a8918e86
JK
6915 for (;;) {
6916 int num = atoi(pos);
6917 if (num <= 0 || num > 31)
6918 return -1;
6919 subtypes |= BIT(num);
6920 pos = os_strchr(pos + 1, ',');
6921 if (pos == NULL)
6922 break;
6923 pos++;
6924 }
6925
6926 if (subtypes == 0)
6927 return -1;
6928
8dd5c1b4 6929 return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0);
a8918e86
JK
6930}
6931
6932
6933static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
6934 const u8 *addr, const char *realm)
6935{
6936 u8 *buf;
6937 size_t rlen, len;
6938 int ret;
6939
6940 rlen = os_strlen(realm);
6941 len = 3 + rlen;
6942 buf = os_malloc(len);
6943 if (buf == NULL)
6944 return -1;
6945 buf[0] = 1; /* NAI Home Realm Count */
6946 buf[1] = 0; /* Formatted in accordance with RFC 4282 */
6947 buf[2] = rlen;
6948 os_memcpy(buf + 3, realm, rlen);
6949
6950 ret = hs20_anqp_send_req(wpa_s, addr,
6951 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
8dd5c1b4 6952 buf, len, 0);
a8918e86
JK
6953
6954 os_free(buf);
6955
6956 return ret;
6957}
6958
6959
6960static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
6961 char *dst)
6962{
6963 struct wpa_cred *cred = wpa_s->conf->cred;
6964 u8 dst_addr[ETH_ALEN];
6965 int used;
6966 u8 *buf;
6967 size_t len;
6968 int ret;
6969
6970 used = hwaddr_aton2(dst, dst_addr);
6971 if (used < 0)
6972 return -1;
6973
6974 while (dst[used] == ' ')
6975 used++;
6976 if (os_strncmp(dst + used, "realm=", 6) == 0)
6977 return hs20_nai_home_realm_list(wpa_s, dst_addr,
6978 dst + used + 6);
6979
6980 len = os_strlen(dst + used);
6981
6982 if (len == 0 && cred && cred->realm)
6983 return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
6984
0e87e798 6985 if (len & 1)
a8918e86
JK
6986 return -1;
6987 len /= 2;
6988 buf = os_malloc(len);
6989 if (buf == NULL)
6990 return -1;
6991 if (hexstr2bin(dst + used, buf, len) < 0) {
6992 os_free(buf);
6993 return -1;
6994 }
6995
6996 ret = hs20_anqp_send_req(wpa_s, dst_addr,
6997 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
8dd5c1b4 6998 buf, len, 0);
a8918e86
JK
6999 os_free(buf);
7000
7001 return ret;
7002}
7003
184e110c 7004
8dd5c1b4
JN
7005static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply,
7006 int buflen)
7007{
7008 u8 dst_addr[ETH_ALEN];
7009 int used;
7010 char *ctx = NULL, *icon, *poffset, *psize;
7011
7012 used = hwaddr_aton2(cmd, dst_addr);
7013 if (used < 0)
7014 return -1;
7015 cmd += used;
7016
7017 icon = str_token(cmd, " ", &ctx);
7018 poffset = str_token(cmd, " ", &ctx);
7019 psize = str_token(cmd, " ", &ctx);
7020 if (!icon || !poffset || !psize)
7021 return -1;
7022
7023 wpa_s->fetch_osu_icon_in_progress = 0;
7024 return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize),
7025 reply, buflen);
7026}
7027
7028
7029static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd)
7030{
7031 u8 dst_addr[ETH_ALEN];
7032 int used;
7033 char *icon;
7034
7035 if (!cmd[0])
7036 return hs20_del_icon(wpa_s, NULL, NULL);
7037
7038 used = hwaddr_aton2(cmd, dst_addr);
7039 if (used < 0)
7040 return -1;
7041
7042 while (cmd[used] == ' ')
7043 used++;
7044 icon = cmd[used] ? &cmd[used] : NULL;
7045
7046 return hs20_del_icon(wpa_s, dst_addr, icon);
7047}
7048
7049
7050static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem)
184e110c
JM
7051{
7052 u8 dst_addr[ETH_ALEN];
7053 int used;
7054 char *icon;
7055
7056 used = hwaddr_aton2(cmd, dst_addr);
7057 if (used < 0)
7058 return -1;
7059
7060 while (cmd[used] == ' ')
7061 used++;
7062 icon = &cmd[used];
7063
b572df86 7064 wpa_s->fetch_osu_icon_in_progress = 0;
184e110c 7065 return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
8dd5c1b4 7066 (u8 *) icon, os_strlen(icon), inmem);
184e110c
JM
7067}
7068
a8918e86
JK
7069#endif /* CONFIG_HS20 */
7070
7071
bc5d330a
TB
7072#ifdef CONFIG_AUTOSCAN
7073
7074static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
7075 char *cmd)
7076{
7077 enum wpa_states state = wpa_s->wpa_state;
7078 char *new_params = NULL;
7079
7080 if (os_strlen(cmd) > 0) {
7081 new_params = os_strdup(cmd);
7082 if (new_params == NULL)
7083 return -1;
7084 }
7085
7086 os_free(wpa_s->conf->autoscan);
7087 wpa_s->conf->autoscan = new_params;
7088
7089 if (wpa_s->conf->autoscan == NULL)
7090 autoscan_deinit(wpa_s);
7091 else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
99218999 7092 autoscan_init(wpa_s, 1);
99f00324
JM
7093 else if (state == WPA_SCANNING)
7094 wpa_supplicant_reinit_autoscan(wpa_s);
9d3f4a74
JM
7095 else
7096 wpa_printf(MSG_DEBUG, "No autoscan update in state %s",
7097 wpa_supplicant_state_txt(state));
bc5d330a
TB
7098
7099 return 0;
7100}
7101
7102#endif /* CONFIG_AUTOSCAN */
7103
7104
e9199e31
JM
7105#ifdef CONFIG_WNM
7106
7107static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
7108{
7109 int enter;
7110 int intval = 0;
7111 char *pos;
cd0ef657
JM
7112 int ret;
7113 struct wpabuf *tfs_req = NULL;
e9199e31
JM
7114
7115 if (os_strncmp(cmd, "enter", 5) == 0)
7116 enter = 1;
7117 else if (os_strncmp(cmd, "exit", 4) == 0)
7118 enter = 0;
7119 else
7120 return -1;
7121
7122 pos = os_strstr(cmd, " interval=");
7123 if (pos)
7124 intval = atoi(pos + 10);
7125
cd0ef657
JM
7126 pos = os_strstr(cmd, " tfs_req=");
7127 if (pos) {
7128 char *end;
7129 size_t len;
7130 pos += 9;
7131 end = os_strchr(pos, ' ');
7132 if (end)
7133 len = end - pos;
7134 else
7135 len = os_strlen(pos);
7136 if (len & 1)
7137 return -1;
7138 len /= 2;
7139 tfs_req = wpabuf_alloc(len);
7140 if (tfs_req == NULL)
7141 return -1;
7142 if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
7143 wpabuf_free(tfs_req);
7144 return -1;
7145 }
7146 }
7147
df80a0cc
JM
7148 ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
7149 WNM_SLEEP_MODE_EXIT, intval,
cd0ef657
JM
7150 tfs_req);
7151 wpabuf_free(tfs_req);
7152
7153 return ret;
e9199e31
JM
7154}
7155
65bcd0a9
VK
7156
7157static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
7158{
9a493fab 7159 int query_reason, list = 0;
65bcd0a9
VK
7160
7161 query_reason = atoi(cmd);
7162
9a493fab
AS
7163 cmd = os_strchr(cmd, ' ');
7164 if (cmd) {
7165 cmd++;
7166 if (os_strncmp(cmd, "list", 4) == 0) {
7167 list = 1;
7168 } else {
7169 wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s",
7170 cmd);
7171 return -1;
7172 }
7173 }
7174
7175 wpa_printf(MSG_DEBUG,
7176 "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s",
7177 query_reason, list ? " candidate list" : "");
65bcd0a9 7178
9a493fab 7179 return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, list);
65bcd0a9
VK
7180}
7181
e9199e31
JM
7182#endif /* CONFIG_WNM */
7183
7184
60b24b0d
DS
7185static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
7186 size_t buflen)
7187{
7188 struct wpa_signal_info si;
7189 int ret;
2cc8d8f4 7190 char *pos, *end;
60b24b0d
DS
7191
7192 ret = wpa_drv_signal_poll(wpa_s, &si);
7193 if (ret)
7194 return -1;
7195
2cc8d8f4
AO
7196 pos = buf;
7197 end = buf + buflen;
7198
7199 ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
60b24b0d
DS
7200 "NOISE=%d\nFREQUENCY=%u\n",
7201 si.current_signal, si.current_txrate / 1000,
7202 si.current_noise, si.frequency);
7bdd8981 7203 if (os_snprintf_error(end - pos, ret))
60b24b0d 7204 return -1;
2cc8d8f4
AO
7205 pos += ret;
7206
7207 if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
7208 ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
7a4a93b9 7209 channel_width_to_string(si.chanwidth));
7bdd8981 7210 if (os_snprintf_error(end - pos, ret))
2cc8d8f4
AO
7211 return -1;
7212 pos += ret;
7213 }
7214
7215 if (si.center_frq1 > 0 && si.center_frq2 > 0) {
7216 ret = os_snprintf(pos, end - pos,
7217 "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
7218 si.center_frq1, si.center_frq2);
7bdd8981 7219 if (os_snprintf_error(end - pos, ret))
2cc8d8f4
AO
7220 return -1;
7221 pos += ret;
7222 }
7223
95783298
AO
7224 if (si.avg_signal) {
7225 ret = os_snprintf(pos, end - pos,
7226 "AVG_RSSI=%d\n", si.avg_signal);
d85e1fc8 7227 if (os_snprintf_error(end - pos, ret))
95783298
AO
7228 return -1;
7229 pos += ret;
7230 }
7231
74fa78b2
JM
7232 if (si.avg_beacon_signal) {
7233 ret = os_snprintf(pos, end - pos,
7234 "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal);
7235 if (os_snprintf_error(end - pos, ret))
7236 return -1;
7237 pos += ret;
7238 }
7239
2cc8d8f4 7240 return pos - buf;
60b24b0d
DS
7241}
7242
7243
96e8d831
DS
7244static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s,
7245 const char *cmd)
7246{
7247 const char *pos;
7248 int threshold = 0;
7249 int hysteresis = 0;
7250
7251 if (wpa_s->bgscan && wpa_s->bgscan_priv) {
7252 wpa_printf(MSG_DEBUG,
7253 "Reject SIGNAL_MONITOR command - bgscan is active");
7254 return -1;
7255 }
7256 pos = os_strstr(cmd, "THRESHOLD=");
7257 if (pos)
7258 threshold = atoi(pos + 10);
7259 pos = os_strstr(cmd, "HYSTERESIS=");
7260 if (pos)
7261 hysteresis = atoi(pos + 11);
7262 return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis);
7263}
7264
7265
c06fca04
JM
7266#ifdef CONFIG_TESTING_OPTIONS
7267int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
7268 enum wpa_driver_if_type if_type,
7269 unsigned int *num,
7270 unsigned int *freq_list)
7271{
7272 char *pos = wpa_s->get_pref_freq_list_override;
7273 char *end;
7274 unsigned int count = 0;
7275
7276 /* Override string format:
7277 * <if_type1>:<freq1>,<freq2>,... <if_type2>:... */
7278
7279 while (pos) {
7280 if (atoi(pos) == (int) if_type)
7281 break;
7282 pos = os_strchr(pos, ' ');
7283 if (pos)
7284 pos++;
7285 }
7286 if (!pos)
7287 return -1;
7288 pos = os_strchr(pos, ':');
7289 if (!pos)
7290 return -1;
7291 pos++;
7292 end = os_strchr(pos, ' ');
7293 while (pos && (!end || pos < end) && count < *num) {
7294 freq_list[count++] = atoi(pos);
7295 pos = os_strchr(pos, ',');
7296 if (pos)
7297 pos++;
7298 }
7299
7300 *num = count;
7301 return 0;
7302}
7303#endif /* CONFIG_TESTING_OPTIONS */
7304
7305
98342208
AK
7306static int wpas_ctrl_iface_get_pref_freq_list(
7307 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
7308{
7309 unsigned int freq_list[100], num = 100, i;
7310 int ret;
7311 enum wpa_driver_if_type iface_type;
7312 char *pos, *end;
7313
7314 pos = buf;
7315 end = buf + buflen;
7316
7317 /* buf: "<interface_type>" */
7318 if (os_strcmp(cmd, "STATION") == 0)
7319 iface_type = WPA_IF_STATION;
7320 else if (os_strcmp(cmd, "AP") == 0)
7321 iface_type = WPA_IF_AP_BSS;
7322 else if (os_strcmp(cmd, "P2P_GO") == 0)
7323 iface_type = WPA_IF_P2P_GO;
7324 else if (os_strcmp(cmd, "P2P_CLIENT") == 0)
7325 iface_type = WPA_IF_P2P_CLIENT;
7326 else if (os_strcmp(cmd, "IBSS") == 0)
7327 iface_type = WPA_IF_IBSS;
7328 else if (os_strcmp(cmd, "TDLS") == 0)
7329 iface_type = WPA_IF_TDLS;
7330 else
7331 return -1;
7332
7333 wpa_printf(MSG_DEBUG,
7334 "CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)",
7335 iface_type, buf);
7336
7337 ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list);
7338 if (ret)
7339 return -1;
7340
7341 for (i = 0; i < num; i++) {
7342 ret = os_snprintf(pos, end - pos, "%s%u",
7343 i > 0 ? "," : "", freq_list[i]);
7344 if (os_snprintf_error(end - pos, ret))
7345 return -1;
7346 pos += ret;
7347 }
7348
7349 return pos - buf;
7350}
7351
7352
4d7aab78
EL
7353static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
7354 char *buf, size_t buflen)
7355{
7356 int ret, i;
7357 char *pos, *end;
7358
7359 ret = os_snprintf(buf, buflen, "%016llX:\n",
7360 (long long unsigned) wpa_s->drv_flags);
7361 if (os_snprintf_error(buflen, ret))
7362 return -1;
7363
7364 pos = buf + ret;
7365 end = buf + buflen;
7366
7367 for (i = 0; i < 64; i++) {
7368 if (wpa_s->drv_flags & (1LLU << i)) {
7369 ret = os_snprintf(pos, end - pos, "%s\n",
7370 driver_flag_to_string(1LLU << i));
7371 if (os_snprintf_error(end - pos, ret))
7372 return -1;
7373 pos += ret;
7374 }
7375 }
7376
7377 return pos - buf;
7378}
7379
7380
dc7785f8
YZ
7381static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
7382 size_t buflen)
7383{
7384 struct hostap_sta_driver_data sta;
7385 int ret;
7386
7387 ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
7388 if (ret)
7389 return -1;
7390
7391 ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
7392 sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
7bdd8981 7393 if (os_snprintf_error(buflen, ret))
dc7785f8
YZ
7394 return -1;
7395 return ret;
7396}
7397
7398
5e2c3490
JM
7399#ifdef ANDROID
7400static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
7401 char *buf, size_t buflen)
7402{
7403 int ret;
7404
7405 ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
a94737ea
DS
7406 if (ret == 0) {
7407 if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
7408 struct p2p_data *p2p = wpa_s->global->p2p;
7409 if (p2p) {
7410 char country[3];
7411 country[0] = cmd[8];
7412 country[1] = cmd[9];
7413 country[2] = 0x04;
7414 p2p_set_country(p2p, country);
7415 }
7416 }
5e2c3490 7417 ret = os_snprintf(buf, buflen, "%s\n", "OK");
aaadd727
JM
7418 if (os_snprintf_error(buflen, ret))
7419 ret = -1;
a94737ea 7420 }
5e2c3490
JM
7421 return ret;
7422}
7423#endif /* ANDROID */
7424
7425
adef8948
BL
7426static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
7427 char *buf, size_t buflen)
7428{
7429 int ret;
7430 char *pos;
7431 u8 *data = NULL;
7432 unsigned int vendor_id, subcmd;
7433 struct wpabuf *reply;
7434 size_t data_len = 0;
7435
7436 /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
7437 vendor_id = strtoul(cmd, &pos, 16);
640b0b93 7438 if (!isblank((unsigned char) *pos))
adef8948
BL
7439 return -EINVAL;
7440
7441 subcmd = strtoul(pos, &pos, 10);
7442
7443 if (*pos != '\0') {
640b0b93 7444 if (!isblank((unsigned char) *pos++))
adef8948
BL
7445 return -EINVAL;
7446 data_len = os_strlen(pos);
7447 }
7448
7449 if (data_len) {
7450 data_len /= 2;
7451 data = os_malloc(data_len);
7452 if (!data)
2cebdee6 7453 return -1;
adef8948
BL
7454
7455 if (hexstr2bin(pos, data, data_len)) {
7456 wpa_printf(MSG_DEBUG,
7457 "Vendor command: wrong parameter format");
7458 os_free(data);
7459 return -EINVAL;
7460 }
7461 }
7462
7463 reply = wpabuf_alloc((buflen - 1) / 2);
7464 if (!reply) {
7465 os_free(data);
2cebdee6 7466 return -1;
adef8948
BL
7467 }
7468
7469 ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
7470 reply);
7471
7472 if (ret == 0)
7473 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
7474 wpabuf_len(reply));
7475
7476 wpabuf_free(reply);
7477 os_free(data);
7478
7479 return ret;
7480}
7481
7482
acb54643
JM
7483static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
7484{
7e608d1d
IP
7485#ifdef CONFIG_P2P
7486 struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
7487 wpa_s->global->p2p_init_wpa_s : wpa_s;
7488#endif /* CONFIG_P2P */
7489
acb54643
JM
7490 wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
7491
6e374bd4
JM
7492 if (wpas_abort_ongoing_scan(wpa_s) == 0)
7493 wpa_s->ignore_post_flush_scan_res = 1;
53401e91 7494
e9ccfc38
JM
7495 if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
7496 /*
7497 * Avoid possible auto connect re-connection on getting
7498 * disconnected due to state flush.
7499 */
7500 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
7501 }
7502
acb54643 7503#ifdef CONFIG_P2P
1d20c66e 7504 wpas_p2p_group_remove(p2p_wpa_s, "*");
7e608d1d
IP
7505 wpas_p2p_cancel(p2p_wpa_s);
7506 p2p_ctrl_flush(p2p_wpa_s);
7e608d1d
IP
7507 wpas_p2p_service_flush(p2p_wpa_s);
7508 p2p_wpa_s->global->p2p_disabled = 0;
7509 p2p_wpa_s->global->p2p_per_sta_psk = 0;
7510 p2p_wpa_s->conf->num_sec_device_types = 0;
7511 p2p_wpa_s->p2p_disable_ip_addr_req = 0;
7512 os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
7513 p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
85e152b6 7514 p2p_wpa_s->global->p2p_go_avoid_freq.num = 0;
9a58e521 7515 p2p_wpa_s->global->pending_p2ps_group = 0;
8bb8e6ed 7516 p2p_wpa_s->global->pending_p2ps_group_freq = 0;
acb54643
JM
7517#endif /* CONFIG_P2P */
7518
7519#ifdef CONFIG_WPS_TESTING
7520 wps_version_number = 0x20;
7521 wps_testing_dummy_cred = 0;
91226e0d 7522 wps_corrupt_pkhash = 0;
6e379c6c
JM
7523 wps_force_auth_types_in_use = 0;
7524 wps_force_encr_types_in_use = 0;
acb54643
JM
7525#endif /* CONFIG_WPS_TESTING */
7526#ifdef CONFIG_WPS
7b02375a 7527 wpa_s->wps_fragment_size = 0;
acb54643 7528 wpas_wps_cancel(wpa_s);
422ba11e 7529 wps_registrar_flush(wpa_s->wps->registrar);
acb54643 7530#endif /* CONFIG_WPS */
7255983b 7531 wpa_s->after_wps = 0;
4d9fb08d 7532 wpa_s->known_wps_freq = 0;
acb54643 7533
9d2cb3ec 7534#ifdef CONFIG_TDLS
acb54643 7535#ifdef CONFIG_TDLS_TESTING
acb54643
JM
7536 tdls_testing = 0;
7537#endif /* CONFIG_TDLS_TESTING */
acb54643
JM
7538 wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
7539 wpa_tdls_enable(wpa_s->wpa, 1);
7540#endif /* CONFIG_TDLS */
7541
e78aaca0
JM
7542 eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
7543 wpa_supplicant_stop_countermeasures(wpa_s, NULL);
7544
acb54643 7545 wpa_s->no_keep_alive = 0;
c2805909 7546 wpa_s->own_disconnect_req = 0;
acb54643
JM
7547
7548 os_free(wpa_s->disallow_aps_bssid);
7549 wpa_s->disallow_aps_bssid = NULL;
7550 wpa_s->disallow_aps_bssid_count = 0;
7551 os_free(wpa_s->disallow_aps_ssid);
7552 wpa_s->disallow_aps_ssid = NULL;
7553 wpa_s->disallow_aps_ssid_count = 0;
7554
7555 wpa_s->set_sta_uapsd = 0;
7556 wpa_s->sta_uapsd = 0;
7557
7558 wpa_drv_radio_disable(wpa_s, 0);
acb54643 7559 wpa_blacklist_clear(wpa_s);
a8a7890d 7560 wpa_s->extra_blacklist_count = 0;
acb54643
JM
7561 wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
7562 wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
d9bb2821 7563 wpa_config_flush_blobs(wpa_s->conf);
ea6e040c
JM
7564 wpa_s->conf->auto_interworking = 0;
7565 wpa_s->conf->okc = 0;
04f7ecc6 7566
b925506a
JM
7567 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
7568 rsn_preauth_deinit(wpa_s->wpa);
7569
04f7ecc6
JM
7570 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
7571 wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
7572 wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
0d79b50a 7573 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
b1ae396f 7574
b3253ebb 7575 radio_remove_works(wpa_s, NULL, 1);
e3745228 7576 wpa_s->ext_work_in_progress = 0;
3d910ef4
JM
7577
7578 wpa_s->next_ssid = NULL;
b572df86
JM
7579
7580#ifdef CONFIG_INTERWORKING
876e74aa 7581#ifdef CONFIG_HS20
b572df86 7582 hs20_cancel_fetch_osu(wpa_s);
8dd5c1b4 7583 hs20_del_icon(wpa_s, NULL, NULL);
876e74aa 7584#endif /* CONFIG_HS20 */
b572df86 7585#endif /* CONFIG_INTERWORKING */
60b893df
JM
7586
7587 wpa_s->ext_mgmt_frame_handling = 0;
9d4ff04a 7588 wpa_s->ext_eapol_frame_io = 0;
1f94e4ee
JM
7589#ifdef CONFIG_TESTING_OPTIONS
7590 wpa_s->extra_roc_dur = 0;
911942ee 7591 wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
ed7820b4 7592 wpa_s->p2p_go_csa_on_inv = 0;
02adead5 7593 wpa_s->ignore_auth_resp = 0;
6ad37d73 7594 wpa_s->ignore_assoc_disallow = 0;
a483c6f1 7595 wpa_s->reject_btm_req_reason = 0;
651c6a84 7596 wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
c06fca04
JM
7597 os_free(wpa_s->get_pref_freq_list_override);
7598 wpa_s->get_pref_freq_list_override = NULL;
1f94e4ee 7599#endif /* CONFIG_TESTING_OPTIONS */
97cfe110
JM
7600
7601 wpa_s->disconnected = 0;
b8db1dfc
JM
7602 os_free(wpa_s->next_scan_freqs);
7603 wpa_s->next_scan_freqs = NULL;
88a44755
JM
7604 os_free(wpa_s->select_network_scan_freqs);
7605 wpa_s->select_network_scan_freqs = NULL;
6c699913
JM
7606
7607 wpa_bss_flush(wpa_s);
7608 if (!dl_list_empty(&wpa_s->bss)) {
7609 wpa_printf(MSG_DEBUG,
7610 "BSS table not empty after flush: %u entries, current_bss=%p bssid="
7611 MACSTR " pending_bssid=" MACSTR,
7612 dl_list_len(&wpa_s->bss), wpa_s->current_bss,
7613 MAC2STR(wpa_s->bssid),
7614 MAC2STR(wpa_s->pending_bssid));
7615 }
9bd566a3
AS
7616
7617 eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
03ed0a52 7618 wpa_s->wnmsleep_used = 0;
ab6ab07a
JM
7619
7620#ifdef CONFIG_SME
7621 wpa_s->sme.last_unprot_disconnect.sec = 0;
7622#endif /* CONFIG_SME */
c6c41f6e
JM
7623
7624 wpabuf_free(wpa_s->ric_ies);
7625 wpa_s->ric_ies = NULL;
acb54643
JM
7626}
7627
7628
1f965e62
JM
7629static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
7630 char *buf, size_t buflen)
7631{
7632 struct wpa_radio_work *work;
7633 char *pos, *end;
7634 struct os_reltime now, diff;
7635
7636 pos = buf;
7637 end = buf + buflen;
7638
7639 os_get_reltime(&now);
7640
7641 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
7642 {
7643 int ret;
7644
7645 os_reltime_sub(&now, &work->time, &diff);
7646 ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
7647 work->type, work->wpa_s->ifname, work->freq,
7648 work->started, diff.sec, diff.usec);
d85e1fc8 7649 if (os_snprintf_error(end - pos, ret))
1f965e62
JM
7650 break;
7651 pos += ret;
7652 }
7653
7654 return pos - buf;
7655}
7656
7657
7658static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
7659{
7660 struct wpa_radio_work *work = eloop_ctx;
7661 struct wpa_external_work *ework = work->ctx;
7662
7663 wpa_dbg(work->wpa_s, MSG_DEBUG,
7664 "Timing out external radio work %u (%s)",
7665 ework->id, work->type);
7666 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
e3745228 7667 work->wpa_s->ext_work_in_progress = 0;
1f965e62 7668 radio_work_done(work);
df48efc5 7669 os_free(ework);
1f965e62
JM
7670}
7671
7672
7673static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
7674{
7675 struct wpa_external_work *ework = work->ctx;
7676
7677 if (deinit) {
b3253ebb
AO
7678 if (work->started)
7679 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
7680 work, NULL);
7681
7d1007a6
JM
7682 /*
7683 * work->type points to a buffer in ework, so need to replace
7684 * that here with a fixed string to avoid use of freed memory
7685 * in debug prints.
7686 */
7687 work->type = "freed-ext-work";
7688 work->ctx = NULL;
1f965e62
JM
7689 os_free(ework);
7690 return;
7691 }
7692
7693 wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
7694 ework->id, ework->type);
7695 wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
e3745228 7696 work->wpa_s->ext_work_in_progress = 1;
1f965e62
JM
7697 if (!ework->timeout)
7698 ework->timeout = 10;
7699 eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
7700 work, NULL);
7701}
7702
7703
7704static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
7705 char *buf, size_t buflen)
7706{
7707 struct wpa_external_work *ework;
7708 char *pos, *pos2;
7709 size_t type_len;
7710 int ret;
7711 unsigned int freq = 0;
7712
7713 /* format: <name> [freq=<MHz>] [timeout=<seconds>] */
7714
7715 ework = os_zalloc(sizeof(*ework));
7716 if (ework == NULL)
7717 return -1;
7718
7719 pos = os_strchr(cmd, ' ');
7720 if (pos) {
7721 type_len = pos - cmd;
7722 pos++;
7723
7724 pos2 = os_strstr(pos, "freq=");
7725 if (pos2)
7726 freq = atoi(pos2 + 5);
7727
7728 pos2 = os_strstr(pos, "timeout=");
7729 if (pos2)
7730 ework->timeout = atoi(pos2 + 8);
7731 } else {
7732 type_len = os_strlen(cmd);
7733 }
7734 if (4 + type_len >= sizeof(ework->type))
7735 type_len = sizeof(ework->type) - 4 - 1;
7736 os_strlcpy(ework->type, "ext:", sizeof(ework->type));
7737 os_memcpy(ework->type + 4, cmd, type_len);
7738 ework->type[4 + type_len] = '\0';
7739
7740 wpa_s->ext_work_id++;
7741 if (wpa_s->ext_work_id == 0)
7742 wpa_s->ext_work_id++;
7743 ework->id = wpa_s->ext_work_id;
7744
7745 if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
7746 ework) < 0) {
7747 os_free(ework);
7748 return -1;
7749 }
7750
7751 ret = os_snprintf(buf, buflen, "%u", ework->id);
d85e1fc8 7752 if (os_snprintf_error(buflen, ret))
1f965e62
JM
7753 return -1;
7754 return ret;
7755}
7756
7757
7758static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
7759{
7760 struct wpa_radio_work *work;
7761 unsigned int id = atoi(cmd);
7762
7763 dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
7764 {
7765 struct wpa_external_work *ework;
7766
7767 if (os_strncmp(work->type, "ext:", 4) != 0)
7768 continue;
7769 ework = work->ctx;
7770 if (id && ework->id != id)
7771 continue;
7772 wpa_dbg(wpa_s, MSG_DEBUG,
7773 "Completed external radio work %u (%s)",
7774 ework->id, ework->type);
7775 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
e3745228 7776 wpa_s->ext_work_in_progress = 0;
1f965e62 7777 radio_work_done(work);
6829da39 7778 os_free(ework);
1f965e62
JM
7779 return 3; /* "OK\n" */
7780 }
7781
7782 return -1;
7783}
7784
7785
7786static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
7787 char *buf, size_t buflen)
7788{
7789 if (os_strcmp(cmd, "show") == 0)
7790 return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
7791 if (os_strncmp(cmd, "add ", 4) == 0)
7792 return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
7793 if (os_strncmp(cmd, "done ", 5) == 0)
7794 return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
7795 return -1;
7796}
7797
7798
7799void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
7800{
7801 struct wpa_radio_work *work, *tmp;
7802
a6cff8bf
MS
7803 if (!wpa_s || !wpa_s->radio)
7804 return;
7805
1f965e62
JM
7806 dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
7807 struct wpa_radio_work, list) {
7808 struct wpa_external_work *ework;
7809
7810 if (os_strncmp(work->type, "ext:", 4) != 0)
7811 continue;
7812 ework = work->ctx;
7813 wpa_dbg(wpa_s, MSG_DEBUG,
023b466d 7814 "Flushing%s external radio work %u (%s)",
1f965e62
JM
7815 work->started ? " started" : "", ework->id,
7816 ework->type);
7817 if (work->started)
7818 eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
7819 work, NULL);
1f965e62 7820 radio_work_done(work);
df48efc5 7821 os_free(ework);
1f965e62
JM
7822 }
7823}
7824
7825
bceb8431
JM
7826static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
7827{
7828 struct wpa_supplicant *wpa_s = eloop_ctx;
7829 eapol_sm_notify_ctrl_response(wpa_s->eapol);
7830}
7831
7832
43a66ecb
JM
7833static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value,
7834 unsigned int *scan_id_count, int scan_id[])
6891f0e6
LJ
7835{
7836 const char *pos = value;
7837
7838 while (pos) {
7839 if (*pos == ' ' || *pos == '\0')
7840 break;
43a66ecb 7841 if (*scan_id_count == MAX_SCAN_ID)
6891f0e6 7842 return -1;
43a66ecb 7843 scan_id[(*scan_id_count)++] = atoi(pos);
6891f0e6
LJ
7844 pos = os_strchr(pos, ',');
7845 if (pos)
7846 pos++;
7847 }
7848
7849 return 0;
7850}
7851
7852
fee52342
JM
7853static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
7854 char *reply, int reply_size, int *reply_len)
7855{
7856 char *pos;
43a66ecb
JM
7857 unsigned int manual_scan_passive = 0;
7858 unsigned int manual_scan_use_id = 0;
7859 unsigned int manual_scan_only_new = 0;
7860 unsigned int scan_only = 0;
7861 unsigned int scan_id_count = 0;
7862 int scan_id[MAX_SCAN_ID];
7863 void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
7864 struct wpa_scan_results *scan_res);
7865 int *manual_scan_freqs = NULL;
a80651d0
KV
7866 struct wpa_ssid_value *ssid = NULL, *ns;
7867 unsigned int ssid_count = 0;
fee52342
JM
7868
7869 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
7870 *reply_len = -1;
7871 return;
7872 }
7873
e69ae5ff
JM
7874 if (radio_work_pending(wpa_s, "scan")) {
7875 wpa_printf(MSG_DEBUG,
7876 "Pending scan scheduled - reject new request");
7877 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
7878 return;
7879 }
7880
9772af66
NM
7881#ifdef CONFIG_INTERWORKING
7882 if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
7883 wpa_printf(MSG_DEBUG,
7884 "Interworking select in progress - reject new scan");
7885 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
7886 return;
7887 }
7888#endif /* CONFIG_INTERWORKING */
7889
fee52342
JM
7890 if (params) {
7891 if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
43a66ecb 7892 scan_only = 1;
fee52342
JM
7893
7894 pos = os_strstr(params, "freq=");
43a66ecb
JM
7895 if (pos) {
7896 manual_scan_freqs = freq_range_to_channel_list(wpa_s,
7897 pos + 5);
7898 if (manual_scan_freqs == NULL) {
7899 *reply_len = -1;
7900 goto done;
7901 }
fee52342 7902 }
88c2d488
JM
7903
7904 pos = os_strstr(params, "passive=");
7905 if (pos)
43a66ecb 7906 manual_scan_passive = !!atoi(pos + 8);
d81c73be
JM
7907
7908 pos = os_strstr(params, "use_id=");
7909 if (pos)
43a66ecb 7910 manual_scan_use_id = atoi(pos + 7);
949938aa
JM
7911
7912 pos = os_strstr(params, "only_new=1");
7913 if (pos)
43a66ecb 7914 manual_scan_only_new = 1;
6891f0e6
LJ
7915
7916 pos = os_strstr(params, "scan_id=");
43a66ecb
JM
7917 if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count,
7918 scan_id) < 0) {
6891f0e6 7919 *reply_len = -1;
43a66ecb 7920 goto done;
6891f0e6 7921 }
a80651d0
KV
7922
7923 pos = params;
7924 while (pos && *pos != '\0') {
7925 if (os_strncmp(pos, "ssid ", 5) == 0) {
7926 char *end;
7927
7928 pos += 5;
7929 end = pos;
7930 while (*end) {
7931 if (*end == '\0' || *end == ' ')
7932 break;
7933 end++;
7934 }
7935
7936 ns = os_realloc_array(
7937 ssid, ssid_count + 1,
7938 sizeof(struct wpa_ssid_value));
7939 if (ns == NULL) {
7940 *reply_len = -1;
7941 goto done;
7942 }
7943 ssid = ns;
7944
7945 if ((end - pos) & 0x01 ||
7946 end - pos > 2 * SSID_MAX_LEN ||
7947 hexstr2bin(pos, ssid[ssid_count].ssid,
7948 (end - pos) / 2) < 0) {
7949 wpa_printf(MSG_DEBUG,
7950 "Invalid SSID value '%s'",
7951 pos);
7952 *reply_len = -1;
7953 goto done;
7954 }
7955 ssid[ssid_count].ssid_len = (end - pos) / 2;
7956 wpa_hexdump_ascii(MSG_DEBUG, "scan SSID",
7957 ssid[ssid_count].ssid,
7958 ssid[ssid_count].ssid_len);
7959 ssid_count++;
7960 pos = end;
7961 }
7962
7963 pos = os_strchr(pos, ' ');
7964 if (pos)
7965 pos++;
7966 }
7967 }
7968
7969 wpa_s->num_ssids_from_scan_req = ssid_count;
7970 os_free(wpa_s->ssids_from_scan_req);
7971 if (ssid_count) {
7972 wpa_s->ssids_from_scan_req = ssid;
7973 ssid = NULL;
7974 } else {
7975 wpa_s->ssids_from_scan_req = NULL;
fee52342
JM
7976 }
7977
43a66ecb
JM
7978 if (scan_only)
7979 scan_res_handler = scan_only_handler;
7980 else if (wpa_s->scan_res_handler == scan_only_handler)
7981 scan_res_handler = NULL;
7982 else
7983 scan_res_handler = wpa_s->scan_res_handler;
7984
fee52342
JM
7985 if (!wpa_s->sched_scanning && !wpa_s->scanning &&
7986 ((wpa_s->wpa_state <= WPA_SCANNING) ||
7987 (wpa_s->wpa_state == WPA_COMPLETED))) {
43a66ecb
JM
7988 wpa_s->manual_scan_passive = manual_scan_passive;
7989 wpa_s->manual_scan_use_id = manual_scan_use_id;
7990 wpa_s->manual_scan_only_new = manual_scan_only_new;
7991 wpa_s->scan_id_count = scan_id_count;
7992 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
7993 wpa_s->scan_res_handler = scan_res_handler;
7994 os_free(wpa_s->manual_scan_freqs);
7995 wpa_s->manual_scan_freqs = manual_scan_freqs;
7996 manual_scan_freqs = NULL;
7997
fee52342
JM
7998 wpa_s->normal_scans = 0;
7999 wpa_s->scan_req = MANUAL_SCAN_REQ;
8000 wpa_s->after_wps = 0;
8001 wpa_s->known_wps_freq = 0;
8002 wpa_supplicant_req_scan(wpa_s, 0, 0);
d81c73be
JM
8003 if (wpa_s->manual_scan_use_id) {
8004 wpa_s->manual_scan_id++;
8005 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
8006 wpa_s->manual_scan_id);
8007 *reply_len = os_snprintf(reply, reply_size, "%u\n",
8008 wpa_s->manual_scan_id);
8009 }
fee52342 8010 } else if (wpa_s->sched_scanning) {
43a66ecb
JM
8011 wpa_s->manual_scan_passive = manual_scan_passive;
8012 wpa_s->manual_scan_use_id = manual_scan_use_id;
8013 wpa_s->manual_scan_only_new = manual_scan_only_new;
8014 wpa_s->scan_id_count = scan_id_count;
8015 os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
8016 wpa_s->scan_res_handler = scan_res_handler;
8017 os_free(wpa_s->manual_scan_freqs);
8018 wpa_s->manual_scan_freqs = manual_scan_freqs;
8019 manual_scan_freqs = NULL;
8020
fee52342
JM
8021 wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
8022 wpa_supplicant_cancel_sched_scan(wpa_s);
8023 wpa_s->scan_req = MANUAL_SCAN_REQ;
8024 wpa_supplicant_req_scan(wpa_s, 0, 0);
d81c73be
JM
8025 if (wpa_s->manual_scan_use_id) {
8026 wpa_s->manual_scan_id++;
8027 *reply_len = os_snprintf(reply, reply_size, "%u\n",
8028 wpa_s->manual_scan_id);
8029 wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
8030 wpa_s->manual_scan_id);
8031 }
fee52342
JM
8032 } else {
8033 wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
8034 *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
8035 }
43a66ecb
JM
8036
8037done:
8038 os_free(manual_scan_freqs);
a80651d0 8039 os_free(ssid);
fee52342
JM
8040}
8041
8042
60b893df
JM
8043#ifdef CONFIG_TESTING_OPTIONS
8044
8045static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s,
8046 unsigned int freq, const u8 *dst,
8047 const u8 *src, const u8 *bssid,
8048 const u8 *data, size_t data_len,
8049 enum offchannel_send_action_result
8050 result)
8051{
8052 wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR
8053 " src=" MACSTR " bssid=" MACSTR " result=%s",
8054 freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
8055 result == OFFCHANNEL_SEND_ACTION_SUCCESS ?
8056 "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ?
8057 "NO_ACK" : "FAILED"));
8058}
8059
8060
8061static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd)
8062{
8063 char *pos, *param;
8064 size_t len;
8065 u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN];
8066 int res, used;
8067 int freq = 0, no_cck = 0, wait_time = 0;
8068
8069 /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
8070 * <action=Action frame payload> */
8071
8072 wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
8073
8074 pos = cmd;
8075 used = hwaddr_aton2(pos, da);
8076 if (used < 0)
8077 return -1;
8078 pos += used;
8079 while (*pos == ' ')
8080 pos++;
8081 used = hwaddr_aton2(pos, bssid);
8082 if (used < 0)
8083 return -1;
8084 pos += used;
8085
8086 param = os_strstr(pos, " freq=");
8087 if (param) {
8088 param += 6;
8089 freq = atoi(param);
8090 }
8091
8092 param = os_strstr(pos, " no_cck=");
8093 if (param) {
8094 param += 8;
8095 no_cck = atoi(param);
8096 }
8097
8098 param = os_strstr(pos, " wait_time=");
8099 if (param) {
8100 param += 11;
8101 wait_time = atoi(param);
8102 }
8103
8104 param = os_strstr(pos, " action=");
8105 if (param == NULL)
8106 return -1;
8107 param += 8;
8108
8109 len = os_strlen(param);
8110 if (len & 1)
8111 return -1;
8112 len /= 2;
8113
8114 buf = os_malloc(len);
8115 if (buf == NULL)
8116 return -1;
8117
8118 if (hexstr2bin(param, buf, len) < 0) {
8119 os_free(buf);
8120 return -1;
8121 }
8122
8123 res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid,
8124 buf, len, wait_time,
8125 wpas_ctrl_iface_mgmt_tx_cb, no_cck);
8126 os_free(buf);
8127 return res;
8128}
8129
8130
8131static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
8132{
8133 wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting");
8134 offchannel_send_action_done(wpa_s);
8135}
8136
ad12f2f4 8137
4de70e23
JM
8138static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s,
8139 char *cmd)
8140{
8141 char *pos, *param;
8142 size_t len;
8143 u8 *buf;
8144 int freq = 0, datarate = 0, ssi_signal = 0;
8145 union wpa_event_data event;
8146
8147 if (!wpa_s->ext_mgmt_frame_handling)
8148 return -1;
8149
8150 /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
8151
8152 wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
8153
8154 pos = cmd;
8155 param = os_strstr(pos, "freq=");
8156 if (param) {
8157 param += 5;
8158 freq = atoi(param);
8159 }
8160
8161 param = os_strstr(pos, " datarate=");
8162 if (param) {
8163 param += 10;
8164 datarate = atoi(param);
8165 }
8166
8167 param = os_strstr(pos, " ssi_signal=");
8168 if (param) {
8169 param += 12;
8170 ssi_signal = atoi(param);
8171 }
8172
8173 param = os_strstr(pos, " frame=");
8174 if (param == NULL)
8175 return -1;
8176 param += 7;
8177
8178 len = os_strlen(param);
8179 if (len & 1)
8180 return -1;
8181 len /= 2;
8182
8183 buf = os_malloc(len);
8184 if (buf == NULL)
8185 return -1;
8186
8187 if (hexstr2bin(param, buf, len) < 0) {
8188 os_free(buf);
8189 return -1;
8190 }
8191
8192 os_memset(&event, 0, sizeof(event));
8193 event.rx_mgmt.freq = freq;
8194 event.rx_mgmt.frame = buf;
8195 event.rx_mgmt.frame_len = len;
8196 event.rx_mgmt.ssi_signal = ssi_signal;
8197 event.rx_mgmt.datarate = datarate;
8198 wpa_s->ext_mgmt_frame_handling = 0;
8199 wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event);
8200 wpa_s->ext_mgmt_frame_handling = 1;
8201
8202 os_free(buf);
8203
8204 return 0;
8205}
8206
8207
e4a3e1d0
JM
8208static int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s,
8209 char *param)
8210{
8211 struct wpa_scan_res *res;
8212 struct os_reltime now;
8213 char *pos, *end;
1fb4437c 8214 int ret = -1;
e4a3e1d0
JM
8215
8216 if (!param)
8217 return -1;
8218
8219 if (os_strcmp(param, "START") == 0) {
8220 wpa_bss_update_start(wpa_s);
8221 return 0;
8222 }
8223
8224 if (os_strcmp(param, "END") == 0) {
8225 wpa_bss_update_end(wpa_s, NULL, 1);
8226 return 0;
8227 }
8228
8229 if (os_strncmp(param, "BSS ", 4) != 0)
8230 return -1;
8231 param += 3;
8232
8233 res = os_zalloc(sizeof(*res) + os_strlen(param) / 2);
8234 if (!res)
8235 return -1;
8236
8237 pos = os_strstr(param, " flags=");
8238 if (pos)
8239 res->flags = strtol(pos + 7, NULL, 16);
8240
8241 pos = os_strstr(param, " bssid=");
1fb4437c
JM
8242 if (pos && hwaddr_aton(pos + 7, res->bssid))
8243 goto fail;
e4a3e1d0
JM
8244
8245 pos = os_strstr(param, " freq=");
8246 if (pos)
8247 res->freq = atoi(pos + 6);
8248
8249 pos = os_strstr(param, " beacon_int=");
8250 if (pos)
8251 res->beacon_int = atoi(pos + 12);
8252
8253 pos = os_strstr(param, " caps=");
8254 if (pos)
8255 res->caps = strtol(pos + 6, NULL, 16);
8256
8257 pos = os_strstr(param, " qual=");
8258 if (pos)
8259 res->qual = atoi(pos + 6);
8260
8261 pos = os_strstr(param, " noise=");
8262 if (pos)
8263 res->noise = atoi(pos + 7);
8264
8265 pos = os_strstr(param, " level=");
8266 if (pos)
8267 res->level = atoi(pos + 7);
8268
8269 pos = os_strstr(param, " tsf=");
8270 if (pos)
8271 res->tsf = strtoll(pos + 5, NULL, 16);
8272
8273 pos = os_strstr(param, " age=");
8274 if (pos)
8275 res->age = atoi(pos + 5);
8276
8277 pos = os_strstr(param, " est_throughput=");
8278 if (pos)
8279 res->est_throughput = atoi(pos + 16);
8280
8281 pos = os_strstr(param, " snr=");
8282 if (pos)
8283 res->snr = atoi(pos + 5);
8284
8285 pos = os_strstr(param, " parent_tsf=");
8286 if (pos)
8287 res->parent_tsf = strtoll(pos + 7, NULL, 16);
8288
8289 pos = os_strstr(param, " tsf_bssid=");
1fb4437c
JM
8290 if (pos && hwaddr_aton(pos + 11, res->tsf_bssid))
8291 goto fail;
e4a3e1d0
JM
8292
8293 pos = os_strstr(param, " ie=");
8294 if (pos) {
8295 pos += 4;
8296 end = os_strchr(pos, ' ');
8297 if (!end)
8298 end = pos + os_strlen(pos);
8299 res->ie_len = (end - pos) / 2;
1fb4437c
JM
8300 if (hexstr2bin(pos, (u8 *) (res + 1), res->ie_len))
8301 goto fail;
e4a3e1d0
JM
8302 }
8303
8304 pos = os_strstr(param, " beacon_ie=");
8305 if (pos) {
8306 pos += 11;
8307 end = os_strchr(pos, ' ');
8308 if (!end)
8309 end = pos + os_strlen(pos);
8310 res->beacon_ie_len = (end - pos) / 2;
1fb4437c
JM
8311 if (hexstr2bin(pos, ((u8 *) (res + 1)) + res->ie_len,
8312 res->beacon_ie_len))
8313 goto fail;
e4a3e1d0
JM
8314 }
8315
8316 os_get_reltime(&now);
8317 wpa_bss_update_scan_res(wpa_s, res, &now);
1fb4437c
JM
8318 ret = 0;
8319fail:
e4a3e1d0
JM
8320 os_free(res);
8321
1fb4437c 8322 return ret;
e4a3e1d0
JM
8323}
8324
8325
ad12f2f4
JM
8326static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
8327{
8328 char *pos, *param;
8329 union wpa_event_data event;
8330 enum wpa_event_type ev;
8331
8332 /* <event name> [parameters..] */
8333
8334 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd);
8335
8336 pos = cmd;
8337 param = os_strchr(pos, ' ');
8338 if (param)
8339 *param++ = '\0';
8340
8341 os_memset(&event, 0, sizeof(event));
8342
8343 if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) {
8344 ev = EVENT_INTERFACE_ENABLED;
8345 } else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) {
8346 ev = EVENT_INTERFACE_DISABLED;
7bb70909
JM
8347 } else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) {
8348 ev = EVENT_AVOID_FREQUENCIES;
8349 if (param == NULL)
8350 param = "";
8351 if (freq_range_list_parse(&event.freq_range, param) < 0)
8352 return -1;
8353 wpa_supplicant_event(wpa_s, ev, &event);
8354 os_free(event.freq_range.range);
8355 return 0;
e4a3e1d0
JM
8356 } else if (os_strcmp(cmd, "SCAN_RES") == 0) {
8357 return wpas_ctrl_iface_driver_scan_res(wpa_s, param);
ad12f2f4
JM
8358 } else {
8359 wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
8360 cmd);
8361 return -1;
8362 }
8363
8364 wpa_supplicant_event(wpa_s, ev, &event);
8365
8366 return 0;
8367}
8368
9d4ff04a
JM
8369
8370static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
8371{
8372 char *pos;
8373 u8 src[ETH_ALEN], *buf;
8374 int used;
8375 size_t len;
8376
8377 wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
8378
8379 pos = cmd;
8380 used = hwaddr_aton2(pos, src);
8381 if (used < 0)
8382 return -1;
8383 pos += used;
8384 while (*pos == ' ')
8385 pos++;
8386
8387 len = os_strlen(pos);
8388 if (len & 1)
8389 return -1;
8390 len /= 2;
8391
8392 buf = os_malloc(len);
8393 if (buf == NULL)
8394 return -1;
8395
8396 if (hexstr2bin(pos, buf, len) < 0) {
8397 os_free(buf);
8398 return -1;
8399 }
8400
8401 wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
8402 os_free(buf);
8403
8404 return 0;
8405}
8406
4a6cc862
JM
8407
8408static u16 ipv4_hdr_checksum(const void *buf, size_t len)
8409{
8410 size_t i;
8411 u32 sum = 0;
8412 const u16 *pos = buf;
8413
8414 for (i = 0; i < len / 2; i++)
8415 sum += *pos++;
8416
8417 while (sum >> 16)
8418 sum = (sum & 0xffff) + (sum >> 16);
8419
8420 return sum ^ 0xffff;
8421}
8422
8423
8424#define HWSIM_PACKETLEN 1500
8425#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
8426
0dbe22be
JM
8427static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
8428 size_t len)
4a6cc862
JM
8429{
8430 struct wpa_supplicant *wpa_s = ctx;
8431 const struct ether_header *eth;
75352270 8432 struct iphdr ip;
4a6cc862
JM
8433 const u8 *pos;
8434 unsigned int i;
8435
8436 if (len != HWSIM_PACKETLEN)
8437 return;
8438
8439 eth = (const struct ether_header *) buf;
75352270
JM
8440 os_memcpy(&ip, eth + 1, sizeof(ip));
8441 pos = &buf[sizeof(*eth) + sizeof(ip)];
4a6cc862 8442
75352270
JM
8443 if (ip.ihl != 5 || ip.version != 4 ||
8444 ntohs(ip.tot_len) != HWSIM_IP_LEN)
4a6cc862
JM
8445 return;
8446
75352270 8447 for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
4a6cc862
JM
8448 if (*pos != (u8) i)
8449 return;
8450 pos++;
8451 }
8452
8453 wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
8454 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
8455}
8456
8457
8458static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
8459 char *cmd)
8460{
8461 int enabled = atoi(cmd);
ba91e920
MB
8462 char *pos;
8463 const char *ifname;
4a6cc862
JM
8464
8465 if (!enabled) {
8466 if (wpa_s->l2_test) {
8467 l2_packet_deinit(wpa_s->l2_test);
8468 wpa_s->l2_test = NULL;
8469 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled");
8470 }
8471 return 0;
8472 }
8473
8474 if (wpa_s->l2_test)
8475 return 0;
8476
ba91e920
MB
8477 pos = os_strstr(cmd, " ifname=");
8478 if (pos)
8479 ifname = pos + 8;
8480 else
8481 ifname = wpa_s->ifname;
8482
8483 wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr,
4a6cc862
JM
8484 ETHERTYPE_IP, wpas_data_test_rx,
8485 wpa_s, 1);
8486 if (wpa_s->l2_test == NULL)
8487 return -1;
8488
8489 wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled");
8490
8491 return 0;
8492}
8493
8494
8495static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
8496{
8497 u8 dst[ETH_ALEN], src[ETH_ALEN];
8498 char *pos;
8499 int used;
8500 long int val;
8501 u8 tos;
75352270 8502 u8 buf[2 + HWSIM_PACKETLEN];
4a6cc862
JM
8503 struct ether_header *eth;
8504 struct iphdr *ip;
8505 u8 *dpos;
8506 unsigned int i;
8507
8508 if (wpa_s->l2_test == NULL)
8509 return -1;
8510
8511 /* format: <dst> <src> <tos> */
8512
8513 pos = cmd;
8514 used = hwaddr_aton2(pos, dst);
8515 if (used < 0)
8516 return -1;
8517 pos += used;
8518 while (*pos == ' ')
8519 pos++;
8520 used = hwaddr_aton2(pos, src);
8521 if (used < 0)
8522 return -1;
8523 pos += used;
8524
8525 val = strtol(pos, NULL, 0);
8526 if (val < 0 || val > 0xff)
8527 return -1;
8528 tos = val;
8529
75352270 8530 eth = (struct ether_header *) &buf[2];
4a6cc862
JM
8531 os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
8532 os_memcpy(eth->ether_shost, src, ETH_ALEN);
8533 eth->ether_type = htons(ETHERTYPE_IP);
8534 ip = (struct iphdr *) (eth + 1);
8535 os_memset(ip, 0, sizeof(*ip));
8536 ip->ihl = 5;
8537 ip->version = 4;
8538 ip->ttl = 64;
8539 ip->tos = tos;
8540 ip->tot_len = htons(HWSIM_IP_LEN);
8541 ip->protocol = 1;
66f1e078
JM
8542 ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
8543 ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
4a6cc862
JM
8544 ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
8545 dpos = (u8 *) (ip + 1);
8546 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
8547 *dpos++ = i;
8548
75352270 8549 if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],
4a6cc862
JM
8550 HWSIM_PACKETLEN) < 0)
8551 return -1;
8552
8553 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
8554 " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
8555
8556 return 0;
8557}
8558
fc0ef7c0
JM
8559
8560static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s,
8561 char *cmd)
8562{
8563 u8 *buf;
8564 struct ether_header *eth;
8565 struct l2_packet_data *l2 = NULL;
8566 size_t len;
8567 u16 ethertype;
8568 int res = -1;
8569
8570 len = os_strlen(cmd);
8571 if (len & 1 || len < ETH_HLEN * 2)
8572 return -1;
8573 len /= 2;
8574
8575 buf = os_malloc(len);
8576 if (buf == NULL)
8577 return -1;
8578
8579 if (hexstr2bin(cmd, buf, len) < 0)
8580 goto done;
8581
8582 eth = (struct ether_header *) buf;
8583 ethertype = ntohs(eth->ether_type);
8584
8585 l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype,
8586 wpas_data_test_rx, wpa_s, 1);
8587 if (l2 == NULL)
8588 goto done;
8589
8590 res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
8591 wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res);
8592done:
8593 if (l2)
8594 l2_packet_deinit(l2);
8595 os_free(buf);
8596
8597 return res < 0 ? -1 : 0;
8598}
8599
a156ffda
JM
8600
8601static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
8602{
8603#ifdef WPA_TRACE_BFD
a156ffda
JM
8604 char *pos;
8605
8606 wpa_trace_fail_after = atoi(cmd);
8607 pos = os_strchr(cmd, ':');
8608 if (pos) {
8609 pos++;
8610 os_strlcpy(wpa_trace_fail_func, pos,
8611 sizeof(wpa_trace_fail_func));
8612 } else {
8613 wpa_trace_fail_after = 0;
8614 }
8615 return 0;
8616#else /* WPA_TRACE_BFD */
8617 return -1;
8618#endif /* WPA_TRACE_BFD */
8619}
8620
8621
8622static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
8623 char *buf, size_t buflen)
8624{
8625#ifdef WPA_TRACE_BFD
a156ffda
JM
8626 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
8627 wpa_trace_fail_func);
8628#else /* WPA_TRACE_BFD */
8629 return -1;
8630#endif /* WPA_TRACE_BFD */
8631}
8632
2da52565
JM
8633
8634static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
8635{
8636#ifdef WPA_TRACE_BFD
2da52565
JM
8637 char *pos;
8638
8639 wpa_trace_test_fail_after = atoi(cmd);
8640 pos = os_strchr(cmd, ':');
8641 if (pos) {
8642 pos++;
8643 os_strlcpy(wpa_trace_test_fail_func, pos,
8644 sizeof(wpa_trace_test_fail_func));
8645 } else {
8646 wpa_trace_test_fail_after = 0;
8647 }
8648 return 0;
8649#else /* WPA_TRACE_BFD */
8650 return -1;
8651#endif /* WPA_TRACE_BFD */
8652}
8653
8654
8655static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
8656 char *buf, size_t buflen)
8657{
8658#ifdef WPA_TRACE_BFD
2da52565
JM
8659 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
8660 wpa_trace_test_fail_func);
8661#else /* WPA_TRACE_BFD */
8662 return -1;
8663#endif /* WPA_TRACE_BFD */
8664}
8665
a530fe77
JM
8666
8667static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx)
8668{
8669 struct wpa_supplicant *wpa_s = eloop_ctx;
8670 int i, count = (intptr_t) timeout_ctx;
8671
8672 wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages",
8673 count);
8674 for (i = 0; i < count; i++) {
8675 wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d",
8676 i + 1, count);
8677 }
8678}
8679
8680
8681static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
8682{
8683 int count;
8684
8685 count = atoi(cmd);
8686 if (count <= 0)
8687 return -1;
8688
8689 return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s,
8690 (void *) (intptr_t) count);
8691}
8692
651c6a84
JM
8693
8694static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
8695 const char *cmd)
8696{
8697 struct wpabuf *buf;
8698 size_t len;
8699
8700 len = os_strlen(cmd);
8701 if (len & 1)
8702 return -1;
8703 len /= 2;
8704
8705 if (len == 0) {
8706 buf = NULL;
8707 } else {
8708 buf = wpabuf_alloc(len);
8709 if (buf == NULL)
8710 return -1;
8711
8712 if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
8713 wpabuf_free(buf);
8714 return -1;
8715 }
8716 }
8717
8718 wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
8719 return 0;
8720}
8721
60b893df
JM
8722#endif /* CONFIG_TESTING_OPTIONS */
8723
8724
86bd36f0
JM
8725static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
8726{
8727 char *pos = cmd;
8728 int frame;
8729 size_t len;
8730 struct wpabuf *buf;
8731 struct ieee802_11_elems elems;
8732
8733 frame = atoi(pos);
8734 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
8735 return -1;
af041f99 8736 wpa_s = wpas_vendor_elem(wpa_s, frame);
86bd36f0
JM
8737
8738 pos = os_strchr(pos, ' ');
8739 if (pos == NULL)
8740 return -1;
8741 pos++;
8742
8743 len = os_strlen(pos);
8744 if (len == 0)
8745 return 0;
8746 if (len & 1)
8747 return -1;
8748 len /= 2;
8749
8750 buf = wpabuf_alloc(len);
8751 if (buf == NULL)
8752 return -1;
8753
8754 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
8755 wpabuf_free(buf);
8756 return -1;
8757 }
8758
8759 if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) ==
8760 ParseFailed) {
8761 wpabuf_free(buf);
8762 return -1;
8763 }
8764
8765 if (wpa_s->vendor_elem[frame] == NULL) {
8766 wpa_s->vendor_elem[frame] = buf;
af041f99 8767 wpas_vendor_elem_update(wpa_s);
86bd36f0
JM
8768 return 0;
8769 }
8770
8771 if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
8772 wpabuf_free(buf);
8773 return -1;
8774 }
8775
8776 wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
8777 wpabuf_free(buf);
af041f99 8778 wpas_vendor_elem_update(wpa_s);
86bd36f0
JM
8779
8780 return 0;
8781}
8782
8783
8784static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
8785 char *buf, size_t buflen)
8786{
8787 int frame = atoi(cmd);
8788
8789 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
8790 return -1;
af041f99 8791 wpa_s = wpas_vendor_elem(wpa_s, frame);
86bd36f0
JM
8792
8793 if (wpa_s->vendor_elem[frame] == NULL)
8794 return 0;
8795
8796 return wpa_snprintf_hex(buf, buflen,
8797 wpabuf_head_u8(wpa_s->vendor_elem[frame]),
8798 wpabuf_len(wpa_s->vendor_elem[frame]));
8799}
8800
8801
8802static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
8803{
8804 char *pos = cmd;
8805 int frame;
8806 size_t len;
8807 u8 *buf;
8808 struct ieee802_11_elems elems;
af041f99 8809 int res;
86bd36f0
JM
8810
8811 frame = atoi(pos);
8812 if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
8813 return -1;
af041f99 8814 wpa_s = wpas_vendor_elem(wpa_s, frame);
86bd36f0
JM
8815
8816 pos = os_strchr(pos, ' ');
8817 if (pos == NULL)
8818 return -1;
8819 pos++;
8820
8821 if (*pos == '*') {
8822 wpabuf_free(wpa_s->vendor_elem[frame]);
8823 wpa_s->vendor_elem[frame] = NULL;
af041f99 8824 wpas_vendor_elem_update(wpa_s);
86bd36f0
JM
8825 return 0;
8826 }
8827
8828 if (wpa_s->vendor_elem[frame] == NULL)
8829 return -1;
8830
8831 len = os_strlen(pos);
8832 if (len == 0)
8833 return 0;
8834 if (len & 1)
8835 return -1;
8836 len /= 2;
8837
8838 buf = os_malloc(len);
8839 if (buf == NULL)
8840 return -1;
8841
8842 if (hexstr2bin(pos, buf, len) < 0) {
8843 os_free(buf);
8844 return -1;
8845 }
8846
8847 if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) {
8848 os_free(buf);
8849 return -1;
8850 }
8851
af041f99 8852 res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
86bd36f0 8853 os_free(buf);
af041f99 8854 return res;
86bd36f0
JM
8855}
8856
8857
f4b8bfae
AK
8858static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
8859{
8860 struct wpa_supplicant *wpa_s = ctx;
cf667c66
IP
8861 size_t len;
8862 const u8 *data;
f4b8bfae 8863
cf667c66
IP
8864 /*
8865 * Neighbor Report element (IEEE P802.11-REVmc/D5.0)
8866 * BSSID[6]
8867 * BSSID Information[4]
8868 * Operating Class[1]
8869 * Channel Number[1]
8870 * PHY Type[1]
8871 * Optional Subelements[variable]
8872 */
8873#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
8874
8875 if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) {
f4b8bfae 8876 wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
cf667c66
IP
8877 goto out;
8878 }
8879
8880 data = wpabuf_head_u8(neighbor_rep);
8881 len = wpabuf_len(neighbor_rep);
8882
8883 while (len >= 2 + NR_IE_MIN_LEN) {
8884 const u8 *nr;
8885 char lci[256 * 2 + 1];
8886 char civic[256 * 2 + 1];
8887 u8 nr_len = data[1];
8888 const u8 *pos = data, *end;
8889
8890 if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
8891 nr_len < NR_IE_MIN_LEN) {
8892 wpa_printf(MSG_DEBUG,
8893 "CTRL: Invalid Neighbor Report element: id=%u len=%u",
8894 data[0], nr_len);
8895 goto out;
8896 }
8897
8898 if (2U + nr_len > len) {
8899 wpa_printf(MSG_DEBUG,
8900 "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
8901 data[0], len, nr_len);
8902 goto out;
8903 }
8904 pos += 2;
8905 end = pos + nr_len;
8906
8907 nr = pos;
8908 pos += NR_IE_MIN_LEN;
8909
8910 lci[0] = '\0';
8911 civic[0] = '\0';
8912 while (end - pos > 2) {
8913 u8 s_id, s_len;
8914
8915 s_id = *pos++;
8916 s_len = *pos++;
8917 if (s_len > end - pos)
8918 goto out;
8919 if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
8920 /* Measurement Token[1] */
8921 /* Measurement Report Mode[1] */
8922 /* Measurement Type[1] */
8923 /* Measurement Report[variable] */
8924 switch (pos[2]) {
8925 case MEASURE_TYPE_LCI:
8926 if (lci[0])
8927 break;
8928 wpa_snprintf_hex(lci, sizeof(lci),
8929 pos, s_len);
8930 break;
8931 case MEASURE_TYPE_LOCATION_CIVIC:
8932 if (civic[0])
8933 break;
8934 wpa_snprintf_hex(civic, sizeof(civic),
8935 pos, s_len);
8936 break;
8937 }
8938 }
8939
8940 pos += s_len;
8941 }
8942
8943 wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
8944 "bssid=" MACSTR
8945 " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
8946 MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
8947 nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
8948 nr[ETH_ALEN + 6],
8949 lci[0] ? " lci=" : "", lci,
8950 civic[0] ? " civic=" : "", civic);
8951
8952 data = end;
8953 len -= 2 + nr_len;
f4b8bfae 8954 }
cf667c66
IP
8955
8956out:
8957 wpabuf_free(neighbor_rep);
f4b8bfae
AK
8958}
8959
8960
6a4f0ed7
JM
8961static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
8962 char *cmd)
f4b8bfae 8963{
d41a5352
DS
8964 struct wpa_ssid_value ssid, *ssid_p = NULL;
8965 int ret, lci = 0, civic = 0;
8966 char *ssid_s;
4c4b2305 8967
d41a5352
DS
8968 ssid_s = os_strstr(cmd, "ssid=");
8969 if (ssid_s) {
8970 if (ssid_parse(ssid_s + 5, &ssid)) {
8971 wpa_printf(MSG_ERROR,
8972 "CTRL: Send Neighbor Report: bad SSID");
4c4b2305 8973 return -1;
d41a5352
DS
8974 }
8975
4c4b2305 8976 ssid_p = &ssid;
d41a5352
DS
8977
8978 /*
8979 * Move cmd after the SSID text that may include "lci" or
8980 * "civic".
8981 */
8982 cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' ');
8983 if (cmd)
8984 cmd++;
8985
4c4b2305
AK
8986 }
8987
d41a5352
DS
8988 if (cmd && os_strstr(cmd, "lci"))
8989 lci = 1;
8990
8991 if (cmd && os_strstr(cmd, "civic"))
8992 civic = 1;
8993
8994 ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic,
4c4b2305
AK
8995 wpas_ctrl_neighbor_rep_cb,
8996 wpa_s);
8997
8998 return ret;
f4b8bfae
AK
8999}
9000
9001
65d9a5e2
JM
9002static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
9003{
9004 eapol_sm_erp_flush(wpa_s->eapol);
9005 return 0;
9006}
9007
9008
fb375883
IP
9009static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
9010 char *cmd)
9011{
9012 char *token, *context = NULL;
9013 unsigned int enable = ~0, type = 0;
9014 u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
9015 u8 *addr = NULL, *mask = NULL;
9016
9017 while ((token = str_token(cmd, " ", &context))) {
9018 if (os_strcasecmp(token, "scan") == 0) {
9019 type |= MAC_ADDR_RAND_SCAN;
9020 } else if (os_strcasecmp(token, "sched") == 0) {
9021 type |= MAC_ADDR_RAND_SCHED_SCAN;
9022 } else if (os_strcasecmp(token, "pno") == 0) {
9023 type |= MAC_ADDR_RAND_PNO;
9024 } else if (os_strcasecmp(token, "all") == 0) {
9025 type = wpa_s->mac_addr_rand_supported;
9026 } else if (os_strncasecmp(token, "enable=", 7) == 0) {
9027 enable = atoi(token + 7);
9028 } else if (os_strncasecmp(token, "addr=", 5) == 0) {
9029 addr = _addr;
9030 if (hwaddr_aton(token + 5, addr)) {
9031 wpa_printf(MSG_INFO,
9032 "CTRL: Invalid MAC address: %s",
9033 token);
9034 return -1;
9035 }
9036 } else if (os_strncasecmp(token, "mask=", 5) == 0) {
9037 mask = _mask;
9038 if (hwaddr_aton(token + 5, mask)) {
9039 wpa_printf(MSG_INFO,
9040 "CTRL: Invalid MAC address mask: %s",
9041 token);
9042 return -1;
9043 }
9044 } else {
9045 wpa_printf(MSG_INFO,
9046 "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
9047 token);
9048 return -1;
9049 }
9050 }
9051
9052 if (!type) {
9053 wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
9054 return -1;
9055 }
9056
9057 if ((wpa_s->mac_addr_rand_supported & type) != type) {
9058 wpa_printf(MSG_INFO,
9059 "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
9060 type, wpa_s->mac_addr_rand_supported);
9061 return -1;
9062 }
9063
9064 if (enable > 1) {
9065 wpa_printf(MSG_INFO,
9066 "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
9067 return -1;
9068 }
9069
9070 if (!enable) {
9071 wpas_mac_addr_rand_scan_clear(wpa_s, type);
9072 if (wpa_s->pno) {
9073 if (type & MAC_ADDR_RAND_PNO) {
9074 wpas_stop_pno(wpa_s);
9075 wpas_start_pno(wpa_s);
9076 }
9077 } else if (wpa_s->sched_scanning &&
9078 (type & MAC_ADDR_RAND_SCHED_SCAN)) {
5bb7327a 9079 wpas_scan_restart_sched_scan(wpa_s);
fb375883
IP
9080 }
9081 return 0;
9082 }
9083
9084 if ((addr && !mask) || (!addr && mask)) {
9085 wpa_printf(MSG_INFO,
9086 "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
9087 return -1;
9088 }
9089
9090 if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
9091 wpa_printf(MSG_INFO,
9092 "CTRL: MAC_RAND_SCAN cannot allow multicast address");
9093 return -1;
9094 }
9095
9096 if (type & MAC_ADDR_RAND_SCAN) {
9097 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
9098 addr, mask);
9099 }
9100
9101 if (type & MAC_ADDR_RAND_SCHED_SCAN) {
9102 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
9103 addr, mask);
9104
5bb7327a
JM
9105 if (wpa_s->sched_scanning && !wpa_s->pno)
9106 wpas_scan_restart_sched_scan(wpa_s);
fb375883
IP
9107 }
9108
9109 if (type & MAC_ADDR_RAND_PNO) {
9110 wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
9111 addr, mask);
9112 if (wpa_s->pno) {
9113 wpas_stop_pno(wpa_s);
9114 wpas_start_pno(wpa_s);
9115 }
9116 }
9117
9118 return 0;
9119}
9120
9121
b8daac18
MH
9122static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
9123 char *buf, size_t buflen)
9124{
9125 size_t reply_len;
9126
9127 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
9128#ifdef CONFIG_AP
9129 reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
9130 buflen - reply_len);
9131#endif /* CONFIG_AP */
9132 return reply_len;
9133}
9134
9135
4c522c77
MH
9136static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
9137{
9138 wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
9139#ifdef CONFIG_AP
9140 wpas_ap_pmksa_cache_flush(wpa_s);
9141#endif /* CONFIG_AP */
9142}
9143
9144
3459381d
JM
9145#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
9146
9147static int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s,
9148 const char *cmd, char *buf, size_t buflen)
9149{
9150 struct rsn_pmksa_cache_entry *entry;
9151 struct wpa_ssid *ssid;
9152 char *pos, *pos2, *end;
9153 int ret;
9154 struct os_reltime now;
9155
9156 ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
9157 if (!ssid)
9158 return -1;
9159
9160 pos = buf;
9161 end = buf + buflen;
9162
9163 os_get_reltime(&now);
9164
9165 /*
9166 * Entry format:
9167 * <BSSID> <PMKID> <PMK> <reauth_time in seconds>
9168 * <expiration in seconds> <akmp> <opportunistic>
b7286c1b 9169 * [FILS Cache Identifier]
3459381d
JM
9170 */
9171
9172 for (entry = wpa_sm_pmksa_cache_head(wpa_s->wpa); entry;
9173 entry = entry->next) {
9174 if (entry->network_ctx != ssid)
9175 continue;
9176
9177 pos2 = pos;
9178 ret = os_snprintf(pos2, end - pos2, MACSTR " ",
9179 MAC2STR(entry->aa));
9180 if (os_snprintf_error(end - pos2, ret))
9181 break;
9182 pos2 += ret;
9183
9184 pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmkid,
9185 PMKID_LEN);
9186
9187 ret = os_snprintf(pos2, end - pos2, " ");
9188 if (os_snprintf_error(end - pos2, ret))
9189 break;
9190 pos2 += ret;
9191
9192 pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmk,
9193 entry->pmk_len);
9194
9195 ret = os_snprintf(pos2, end - pos2, " %d %d %d %d",
9196 (int) (entry->reauth_time - now.sec),
9197 (int) (entry->expiration - now.sec),
9198 entry->akmp,
9199 entry->opportunistic);
9200 if (os_snprintf_error(end - pos2, ret))
9201 break;
9202 pos2 += ret;
9203
b7286c1b
JM
9204 if (entry->fils_cache_id_set) {
9205 ret = os_snprintf(pos2, end - pos2, " %02x%02x",
9206 entry->fils_cache_id[0],
9207 entry->fils_cache_id[1]);
9208 if (os_snprintf_error(end - pos2, ret))
9209 break;
9210 pos2 += ret;
9211 }
9212
3459381d
JM
9213 ret = os_snprintf(pos2, end - pos2, "\n");
9214 if (os_snprintf_error(end - pos2, ret))
9215 break;
9216 pos2 += ret;
9217
9218 pos = pos2;
9219 }
9220
9221 return pos - buf;
9222}
9223
9224
9225static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
9226 char *cmd)
9227{
9228 struct rsn_pmksa_cache_entry *entry;
9229 struct wpa_ssid *ssid;
9230 char *pos, *pos2;
9231 int ret = -1;
9232 struct os_reltime now;
b7286c1b 9233 int reauth_time = 0, expiration = 0, i;
3459381d
JM
9234
9235 /*
9236 * Entry format:
9237 * <network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds>
9238 * <expiration in seconds> <akmp> <opportunistic>
b7286c1b 9239 * [FILS Cache Identifier]
3459381d
JM
9240 */
9241
9242 ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
9243 if (!ssid)
9244 return -1;
9245
9246 pos = os_strchr(cmd, ' ');
9247 if (!pos)
9248 return -1;
9249 pos++;
9250
9251 entry = os_zalloc(sizeof(*entry));
9252 if (!entry)
9253 return -1;
9254
9255 if (hwaddr_aton(pos, entry->aa))
9256 goto fail;
9257
9258 pos = os_strchr(pos, ' ');
9259 if (!pos)
9260 goto fail;
9261 pos++;
9262
9263 if (hexstr2bin(pos, entry->pmkid, PMKID_LEN) < 0)
9264 goto fail;
9265
9266 pos = os_strchr(pos, ' ');
9267 if (!pos)
9268 goto fail;
9269 pos++;
9270
9271 pos2 = os_strchr(pos, ' ');
9272 if (!pos2)
9273 goto fail;
9274 entry->pmk_len = (pos2 - pos) / 2;
9275 if (entry->pmk_len < PMK_LEN || entry->pmk_len > PMK_LEN_MAX ||
9276 hexstr2bin(pos, entry->pmk, entry->pmk_len) < 0)
9277 goto fail;
9278
9279 pos = os_strchr(pos, ' ');
9280 if (!pos)
9281 goto fail;
9282 pos++;
9283
9284 if (sscanf(pos, "%d %d %d %d", &reauth_time, &expiration,
9285 &entry->akmp, &entry->opportunistic) != 4)
9286 goto fail;
b7286c1b
JM
9287 for (i = 0; i < 4; i++) {
9288 pos = os_strchr(pos, ' ');
9289 if (!pos) {
9290 if (i < 3)
9291 goto fail;
9292 break;
9293 }
9294 pos++;
9295 }
9296 if (pos) {
9297 if (hexstr2bin(pos, entry->fils_cache_id,
9298 FILS_CACHE_ID_LEN) < 0)
9299 goto fail;
9300 entry->fils_cache_id_set = 1;
9301 }
3459381d
JM
9302 os_get_reltime(&now);
9303 entry->expiration = now.sec + expiration;
9304 entry->reauth_time = now.sec + reauth_time;
9305
9306 entry->network_ctx = ssid;
9307
9308 wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
9309 entry = NULL;
9310 ret = 0;
9311fail:
9312 os_free(entry);
9313 return ret;
9314}
9315
4d77d80e
MH
9316
9317#ifdef CONFIG_MESH
9318
9319static int wpas_ctrl_iface_mesh_pmksa_get(struct wpa_supplicant *wpa_s,
9320 const char *cmd, char *buf,
9321 size_t buflen)
9322{
9323 u8 spa[ETH_ALEN];
9324
9325 if (!wpa_s->ifmsh)
9326 return -1;
9327
9328 if (os_strcasecmp(cmd, "any") == 0)
9329 return wpas_ap_pmksa_cache_list_mesh(wpa_s, NULL, buf, buflen);
9330
9331 if (hwaddr_aton(cmd, spa))
9332 return -1;
9333
9334 return wpas_ap_pmksa_cache_list_mesh(wpa_s, spa, buf, buflen);
9335}
9336
9337
9338static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s,
9339 char *cmd)
9340{
9341 /*
9342 * We do not check mesh interface existance because PMKSA should be
9343 * stored before wpa_s->ifmsh creation to suppress commit message
9344 * creation.
9345 */
9346 return wpas_ap_pmksa_cache_add_external(wpa_s, cmd);
9347}
9348
9349#endif /* CONFIG_MESH */
3459381d
JM
9350#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
9351
9352
5732b770
JM
9353#ifdef CONFIG_FILS
9354static int wpas_ctrl_iface_fils_hlp_req_add(struct wpa_supplicant *wpa_s,
9355 const char *cmd)
9356{
9357 struct fils_hlp_req *req;
9358 const char *pos;
9359
9360 /* format: <dst> <packet starting from ethertype> */
9361
9362 req = os_zalloc(sizeof(*req));
9363 if (!req)
9364 return -1;
9365
9366 if (hwaddr_aton(cmd, req->dst))
9367 goto fail;
9368
9369 pos = os_strchr(cmd, ' ');
9370 if (!pos)
9371 goto fail;
9372 pos++;
9373 req->pkt = wpabuf_parse_bin(pos);
9374 if (!req->pkt)
9375 goto fail;
9376
9377 dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list);
9378 return 0;
9379fail:
9380 wpabuf_free(req->pkt);
9381 os_free(req);
9382 return -1;
9383}
9384#endif /* CONFIG_FILS */
9385
9386
8db9a79d
JM
9387static int wpas_ctrl_cmd_debug_level(const char *cmd)
9388{
9389 if (os_strcmp(cmd, "PING") == 0 ||
9390 os_strncmp(cmd, "BSS ", 4) == 0 ||
9391 os_strncmp(cmd, "GET_NETWORK ", 12) == 0 ||
9392 os_strncmp(cmd, "STATUS", 6) == 0 ||
9393 os_strncmp(cmd, "STA ", 4) == 0 ||
9394 os_strncmp(cmd, "STA-", 4) == 0)
9395 return MSG_EXCESSIVE;
9396 return MSG_DEBUG;
9397}
9398
9399
6fc6879b
JM
9400char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
9401 char *buf, size_t *resp_len)
9402{
9403 char *reply;
b563b388 9404 const int reply_size = 4096;
6fc6879b
JM
9405 int reply_len;
9406
9407 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
d31b5ac7
JM
9408 os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
9409 if (wpa_debug_show_keys)
9410 wpa_dbg(wpa_s, MSG_DEBUG,
9411 "Control interface command '%s'", buf);
9412 else
9413 wpa_dbg(wpa_s, MSG_DEBUG,
9414 "Control interface command '%s [REMOVED]'",
9415 os_strncmp(buf, WPA_CTRL_RSP,
9416 os_strlen(WPA_CTRL_RSP)) == 0 ?
9417 WPA_CTRL_RSP : "SET_NETWORK");
9418 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
679f2e7c 9419 os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) {
6fc6879b
JM
9420 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
9421 (const u8 *) buf, os_strlen(buf));
9422 } else {
8db9a79d 9423 int level = wpas_ctrl_cmd_debug_level(buf);
b470b2bf 9424 wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
6fc6879b
JM
9425 }
9426
9427 reply = os_malloc(reply_size);
9428 if (reply == NULL) {
9429 *resp_len = 1;
9430 return NULL;
9431 }
9432
9433 os_memcpy(reply, "OK\n", 3);
9434 reply_len = 3;
9435
9436 if (os_strcmp(buf, "PING") == 0) {
9437 os_memcpy(reply, "PONG\n", 5);
9438 reply_len = 5;
0eed2a8d
JD
9439 } else if (os_strcmp(buf, "IFNAME") == 0) {
9440 reply_len = os_strlen(wpa_s->ifname);
9441 os_memcpy(reply, wpa_s->ifname, reply_len);
ac6912b5
BG
9442 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
9443 if (wpa_debug_reopen_file() < 0)
9444 reply_len = -1;
77895cd9
JM
9445 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
9446 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
6fc6879b
JM
9447 } else if (os_strcmp(buf, "MIB") == 0) {
9448 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
9449 if (reply_len >= 0) {
5ac73acf
JM
9450 reply_len += eapol_sm_get_mib(wpa_s->eapol,
9451 reply + reply_len,
9452 reply_size - reply_len);
6fc6879b
JM
9453 }
9454 } else if (os_strncmp(buf, "STATUS", 6) == 0) {
9455 reply_len = wpa_supplicant_ctrl_iface_status(
9456 wpa_s, buf + 6, reply, reply_size);
9457 } else if (os_strcmp(buf, "PMKSA") == 0) {
b8daac18 9458 reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
79e2b1cc 9459 } else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
4c522c77 9460 wpas_ctrl_iface_pmksa_flush(wpa_s);
3459381d
JM
9461#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
9462 } else if (os_strncmp(buf, "PMKSA_GET ", 10) == 0) {
9463 reply_len = wpas_ctrl_iface_pmksa_get(wpa_s, buf + 10,
9464 reply, reply_size);
9465 } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
9466 if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0)
9467 reply_len = -1;
4d77d80e
MH
9468#ifdef CONFIG_MESH
9469 } else if (os_strncmp(buf, "MESH_PMKSA_GET ", 15) == 0) {
9470 reply_len = wpas_ctrl_iface_mesh_pmksa_get(wpa_s, buf + 15,
9471 reply, reply_size);
9472 } else if (os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) {
9473 if (wpas_ctrl_iface_mesh_pmksa_add(wpa_s, buf + 15) < 0)
9474 reply_len = -1;
9475#endif /* CONFIG_MESH */
3459381d 9476#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
6fc6879b
JM
9477 } else if (os_strncmp(buf, "SET ", 4) == 0) {
9478 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
9479 reply_len = -1;
10263dc2
OO
9480 } else if (os_strncmp(buf, "DUMP", 4) == 0) {
9481 reply_len = wpa_config_dump_values(wpa_s->conf,
9482 reply, reply_size);
acec8d32
JM
9483 } else if (os_strncmp(buf, "GET ", 4) == 0) {
9484 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
9485 reply, reply_size);
6fc6879b
JM
9486 } else if (os_strcmp(buf, "LOGON") == 0) {
9487 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
9488 } else if (os_strcmp(buf, "LOGOFF") == 0) {
9489 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
9490 } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
8401a6b0
JM
9491 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
9492 reply_len = -1;
9796a86c
JM
9493 else
9494 wpas_request_connection(wpa_s);
0f44ec8e
PQ
9495 } else if (os_strcmp(buf, "REATTACH") == 0) {
9496 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED ||
9497 !wpa_s->current_ssid)
9498 reply_len = -1;
9499 else {
9500 wpa_s->reattach = 1;
9501 wpas_request_connection(wpa_s);
9502 }
6fc6879b 9503 } else if (os_strcmp(buf, "RECONNECT") == 0) {
8401a6b0
JM
9504 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
9505 reply_len = -1;
9796a86c
JM
9506 else if (wpa_s->disconnected)
9507 wpas_request_connection(wpa_s);
ec717917 9508#ifdef IEEE8021X_EAPOL
6fc6879b
JM
9509 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
9510 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
9511 reply_len = -1;
ec717917 9512#endif /* IEEE8021X_EAPOL */
6fc6879b
JM
9513#ifdef CONFIG_PEERKEY
9514 } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
9515 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
9516 reply_len = -1;
9517#endif /* CONFIG_PEERKEY */
9518#ifdef CONFIG_IEEE80211R
9519 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
9520 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
9521 reply_len = -1;
9522#endif /* CONFIG_IEEE80211R */
fcc60db4
JM
9523#ifdef CONFIG_WPS
9524 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
3152ff42
CWY
9525 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
9526 if (res == -2) {
9527 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
9528 reply_len = 17;
9529 } else if (res)
fcc60db4
JM
9530 reply_len = -1;
9531 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
3152ff42
CWY
9532 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
9533 if (res == -2) {
9534 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
9535 reply_len = 17;
9536 } else if (res)
fcc60db4
JM
9537 reply_len = -1;
9538 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
9539 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
9540 reply,
9541 reply_size);
3981cb3c
JM
9542 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
9543 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
9544 wpa_s, buf + 14, reply, reply_size);
2f9929ff
AC
9545 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
9546 if (wpas_wps_cancel(wpa_s))
9547 reply_len = -1;
71892384 9548#ifdef CONFIG_WPS_NFC
3f2c8ba6
JM
9549 } else if (os_strcmp(buf, "WPS_NFC") == 0) {
9550 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
9551 reply_len = -1;
9552 } else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
9553 if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
9554 reply_len = -1;
bbf41865
JM
9555 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
9556 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
9557 wpa_s, buf + 21, reply, reply_size);
3f2c8ba6
JM
9558 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
9559 reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
9560 wpa_s, buf + 14, reply, reply_size);
d7645d23
JM
9561 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
9562 if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
9563 buf + 17))
9564 reply_len = -1;
e65552dd
JM
9565 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
9566 reply_len = wpas_ctrl_nfc_get_handover_req(
9567 wpa_s, buf + 21, reply, reply_size);
9568 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
9569 reply_len = wpas_ctrl_nfc_get_handover_sel(
9570 wpa_s, buf + 21, reply, reply_size);
e4758827
JM
9571 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
9572 if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
9573 reply_len = -1;
71892384 9574#endif /* CONFIG_WPS_NFC */
fcc60db4
JM
9575 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
9576 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
9577 reply_len = -1;
70d84f11
JM
9578#ifdef CONFIG_AP
9579 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
9580 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
9581 wpa_s, buf + 11, reply, reply_size);
9582#endif /* CONFIG_AP */
72df2f5f 9583#ifdef CONFIG_WPS_ER
e9bcfebf 9584 } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
08486685
JM
9585 if (wpas_wps_er_start(wpa_s, NULL))
9586 reply_len = -1;
9587 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
9588 if (wpas_wps_er_start(wpa_s, buf + 13))
e9bcfebf
JM
9589 reply_len = -1;
9590 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
f77cedc1 9591 wpas_wps_er_stop(wpa_s);
72df2f5f
JM
9592 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
9593 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
9594 reply_len = -1;
564cd7fa 9595 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
ed159ad4
JM
9596 int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
9597 if (ret == -2) {
9598 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
9599 reply_len = 17;
9600 } else if (ret == -3) {
9601 os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
9602 reply_len = 18;
9603 } else if (ret == -4) {
9604 os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
9605 reply_len = 20;
9606 } else if (ret)
564cd7fa 9607 reply_len = -1;
e64dcfd5
JM
9608 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
9609 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
9610 reply_len = -1;
ef10f473
JM
9611 } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
9612 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
9613 buf + 18))
9614 reply_len = -1;
7d6640a6
JM
9615 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
9616 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
9617 reply_len = -1;
1cea09a9
JM
9618#ifdef CONFIG_WPS_NFC
9619 } else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
9620 reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
9621 wpa_s, buf + 24, reply, reply_size);
9622#endif /* CONFIG_WPS_NFC */
72df2f5f 9623#endif /* CONFIG_WPS_ER */
fcc60db4 9624#endif /* CONFIG_WPS */
11ef8d35
JM
9625#ifdef CONFIG_IBSS_RSN
9626 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
9627 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
9628 reply_len = -1;
9629#endif /* CONFIG_IBSS_RSN */
603a3f34 9630#ifdef CONFIG_MESH
5b78493f
MH
9631 } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
9632 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
9633 wpa_s, buf + 19, reply, reply_size);
9634 } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
9635 reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
9636 wpa_s, "", reply, reply_size);
603a3f34
JL
9637 } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
9638 if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
9639 reply_len = -1;
9640 } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
9641 if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
9642 buf + 18))
9643 reply_len = -1;
e174ef34
MH
9644 } else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
9645 if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
9646 reply_len = -1;
2604edbf
MH
9647 } else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
9648 if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
9649 reply_len = -1;
603a3f34 9650#endif /* CONFIG_MESH */
b563b388
JM
9651#ifdef CONFIG_P2P
9652 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
51775096 9653 if (p2p_ctrl_find(wpa_s, buf + 8))
b563b388
JM
9654 reply_len = -1;
9655 } else if (os_strcmp(buf, "P2P_FIND") == 0) {
9656 if (p2p_ctrl_find(wpa_s, ""))
9657 reply_len = -1;
9658 } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
9659 wpas_p2p_stop_find(wpa_s);
f309c18e
KV
9660 } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) {
9661 if (p2p_ctrl_asp_provision(wpa_s, buf + 18))
9662 reply_len = -1;
9663 } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) {
9664 if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23))
9665 reply_len = -1;
b563b388
JM
9666 } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
9667 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
9668 reply_size);
9669 } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
9670 if (p2p_ctrl_listen(wpa_s, buf + 11))
9671 reply_len = -1;
9672 } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
9673 if (p2p_ctrl_listen(wpa_s, ""))
9674 reply_len = -1;
9675 } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
9676 if (wpas_p2p_group_remove(wpa_s, buf + 17))
9677 reply_len = -1;
9678 } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
38dcc86c 9679 if (p2p_ctrl_group_add(wpa_s, ""))
b563b388
JM
9680 reply_len = -1;
9681 } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
9682 if (p2p_ctrl_group_add(wpa_s, buf + 14))
9683 reply_len = -1;
57b38882
PK
9684 } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) {
9685 reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply,
9686 reply_size);
b563b388
JM
9687 } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
9688 if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
9689 reply_len = -1;
9690 } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
9691 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
9692 } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
9693 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
9694 reply_size);
9695 } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
9696 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
9697 reply_len = -1;
9698 } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
9699 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
9700 reply_len = -1;
9701 } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
9702 wpas_p2p_sd_service_update(wpa_s);
9703 } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
9704 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
9705 reply_len = -1;
9706 } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
9707 wpas_p2p_service_flush(wpa_s);
9708 } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
9709 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
9710 reply_len = -1;
9711 } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
9712 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
9713 reply_len = -1;
ae9d45f3
KV
9714 } else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) {
9715 if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0)
9716 reply_len = -1;
b563b388
JM
9717 } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
9718 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
9719 reply_len = -1;
9720 } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
9721 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
9722 reply_len = -1;
9723 } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
9724 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
9725 reply_size);
9726 } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
9727 if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
9728 reply_len = -1;
9729 } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
acb54643 9730 p2p_ctrl_flush(wpa_s);
9d562b79
SS
9731 } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
9732 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
9733 reply_len = -1;
59eba7a2
JM
9734 } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
9735 if (wpas_p2p_cancel(wpa_s))
9736 reply_len = -1;
b563b388
JM
9737 } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
9738 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
9739 reply_len = -1;
9740 } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
9741 if (p2p_ctrl_presence_req(wpa_s, "") < 0)
9742 reply_len = -1;
9743 } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
9744 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
9745 reply_len = -1;
9746 } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
9747 if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
9748 reply_len = -1;
f2c56602
JM
9749 } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
9750 if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
9751 reply_len = -1;
a6f5b193
PX
9752 } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
9753 if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
9754 reply_len = -1;
9755 } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
9756 if (wpas_p2p_lo_stop(wpa_s))
9757 reply_len = -1;
b563b388 9758#endif /* CONFIG_P2P */
9675ce35
JM
9759#ifdef CONFIG_WIFI_DISPLAY
9760 } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
9761 if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
9762 reply_len = -1;
9763 } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
9764 reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
9765 reply, reply_size);
9766#endif /* CONFIG_WIFI_DISPLAY */
afc064fe
JM
9767#ifdef CONFIG_INTERWORKING
9768 } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
9769 if (interworking_fetch_anqp(wpa_s) < 0)
9770 reply_len = -1;
9771 } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
9772 interworking_stop_fetch_anqp(wpa_s);
356d1488
JM
9773 } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
9774 if (ctrl_interworking_select(wpa_s, NULL) < 0)
9775 reply_len = -1;
9776 } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
9777 if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
b02fe7ff
JM
9778 reply_len = -1;
9779 } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
f91a512f 9780 if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0)
b02fe7ff 9781 reply_len = -1;
f91a512f
JM
9782 } else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) {
9783 int id;
9784
9785 id = ctrl_interworking_connect(wpa_s, buf + 25, 1);
9786 if (id < 0)
9787 reply_len = -1;
9788 else {
9789 reply_len = os_snprintf(reply, reply_size, "%d\n", id);
9790 if (os_snprintf_error(reply_size, reply_len))
9791 reply_len = -1;
9792 }
afc064fe
JM
9793 } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
9794 if (get_anqp(wpa_s, buf + 9) < 0)
9795 reply_len = -1;
b1f12296
JM
9796 } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
9797 if (gas_request(wpa_s, buf + 12) < 0)
9798 reply_len = -1;
9799 } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
9800 reply_len = gas_response_get(wpa_s, buf + 17, reply,
9801 reply_size);
afc064fe 9802#endif /* CONFIG_INTERWORKING */
a8918e86
JK
9803#ifdef CONFIG_HS20
9804 } else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
9805 if (get_hs20_anqp(wpa_s, buf + 14) < 0)
9806 reply_len = -1;
9807 } else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
9808 if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
9809 reply_len = -1;
184e110c 9810 } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
8dd5c1b4
JN
9811 if (hs20_icon_request(wpa_s, buf + 18, 0) < 0)
9812 reply_len = -1;
9813 } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) {
9814 if (hs20_icon_request(wpa_s, buf + 14, 1) < 0)
9815 reply_len = -1;
9816 } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) {
9817 reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size);
9818 } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) {
9819 if (del_hs20_icon(wpa_s, buf + 14) < 0)
184e110c 9820 reply_len = -1;
b572df86 9821 } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
dd20eabd
JM
9822 if (hs20_fetch_osu(wpa_s, 0) < 0)
9823 reply_len = -1;
9824 } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
9825 if (hs20_fetch_osu(wpa_s, 1) < 0)
b572df86
JM
9826 reply_len = -1;
9827 } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
9828 hs20_cancel_fetch_osu(wpa_s);
a8918e86 9829#endif /* CONFIG_HS20 */
6fc6879b
JM
9830 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
9831 {
9832 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
9833 wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
9834 reply_len = -1;
bceb8431
JM
9835 else {
9836 /*
9837 * Notify response from timeout to allow the control
9838 * interface response to be sent first.
9839 */
9840 eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
9841 wpa_s, NULL);
9842 }
6fc6879b
JM
9843 } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
9844 if (wpa_supplicant_reload_configuration(wpa_s))
9845 reply_len = -1;
9846 } else if (os_strcmp(buf, "TERMINATE") == 0) {
1a1bf008 9847 wpa_supplicant_terminate_proc(wpa_s->global);
6fc6879b
JM
9848 } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
9849 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
9850 reply_len = -1;
9aa10e2b
DS
9851 } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
9852 reply_len = wpa_supplicant_ctrl_iface_blacklist(
9853 wpa_s, buf + 9, reply, reply_size);
0597a5b5
DS
9854 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
9855 reply_len = wpa_supplicant_ctrl_iface_log_level(
9856 wpa_s, buf + 9, reply, reply_size);
90903a77
VD
9857 } else if (os_strncmp(buf, "LIST_NETWORKS ", 14) == 0) {
9858 reply_len = wpa_supplicant_ctrl_iface_list_networks(
9859 wpa_s, buf + 14, reply, reply_size);
6fc6879b
JM
9860 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
9861 reply_len = wpa_supplicant_ctrl_iface_list_networks(
90903a77 9862 wpa_s, NULL, reply, reply_size);
6fc6879b 9863 } else if (os_strcmp(buf, "DISCONNECT") == 0) {
5f040be4 9864 wpas_request_disconnection(wpa_s);
fee52342
JM
9865 } else if (os_strcmp(buf, "SCAN") == 0) {
9866 wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
9867 } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
9868 wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
6fc6879b
JM
9869 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
9870 reply_len = wpa_supplicant_ctrl_iface_scan_results(
9871 wpa_s, reply, reply_size);
2ea2166d
JM
9872 } else if (os_strcmp(buf, "ABORT_SCAN") == 0) {
9873 if (wpas_abort_ongoing_scan(wpa_s) < 0)
9874 reply_len = -1;
6fc6879b
JM
9875 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
9876 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
9877 reply_len = -1;
9878 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
9879 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
9880 reply_len = -1;
9881 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
9882 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
9883 reply_len = -1;
9884 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
9885 reply_len = wpa_supplicant_ctrl_iface_add_network(
9886 wpa_s, reply, reply_size);
9887 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
9888 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
9889 reply_len = -1;
9890 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
9891 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
9892 reply_len = -1;
9893 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
9894 reply_len = wpa_supplicant_ctrl_iface_get_network(
9895 wpa_s, buf + 12, reply, reply_size);
1c330a2f 9896 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
daae4995
AN
9897 if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12,
9898 wpa_s))
1c330a2f 9899 reply_len = -1;
d94c9ee6
JM
9900 } else if (os_strcmp(buf, "LIST_CREDS") == 0) {
9901 reply_len = wpa_supplicant_ctrl_iface_list_creds(
9902 wpa_s, reply, reply_size);
9903 } else if (os_strcmp(buf, "ADD_CRED") == 0) {
9904 reply_len = wpa_supplicant_ctrl_iface_add_cred(
9905 wpa_s, reply, reply_size);
9906 } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
9907 if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
9908 reply_len = -1;
9909 } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
9910 if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
9911 reply_len = -1;
c880ab87
JM
9912 } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) {
9913 reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9,
9914 reply,
9915 reply_size);
6fc6879b
JM
9916#ifndef CONFIG_NO_CONFIG_WRITE
9917 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
9918 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
9919 reply_len = -1;
9920#endif /* CONFIG_NO_CONFIG_WRITE */
9921 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
9922 reply_len = wpa_supplicant_ctrl_iface_get_capability(
9923 wpa_s, buf + 15, reply, reply_size);
9924 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
9925 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
9926 reply_len = -1;
67b9bd08
DS
9927 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
9928 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
9929 reply_len = -1;
4b4a8ae5
JM
9930 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
9931 reply_len = wpa_supplicant_global_iface_list(
9932 wpa_s->global, reply, reply_size);
56e2fc2c 9933 } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
6fc6879b 9934 reply_len = wpa_supplicant_global_iface_interfaces(
56e2fc2c 9935 wpa_s->global, buf + 10, reply, reply_size);
6fc6879b
JM
9936 } else if (os_strncmp(buf, "BSS ", 4) == 0) {
9937 reply_len = wpa_supplicant_ctrl_iface_bss(
9938 wpa_s, buf + 4, reply, reply_size);
e653b622
JM
9939#ifdef CONFIG_AP
9940 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
9941 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
9942 } else if (os_strncmp(buf, "STA ", 4) == 0) {
9943 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
9944 reply_size);
9945 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
9946 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
9947 reply_size);
e60b2951
JJ
9948 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
9949 if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
9950 reply_len = -1;
9951 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
9952 if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
9953 reply_len = -1;
334bf36a
AO
9954 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
9955 if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
9956 reply_len = -1;
99650cad
JM
9957 } else if (os_strcmp(buf, "STOP_AP") == 0) {
9958 if (wpas_ap_stop_ap(wpa_s))
9959 reply_len = -1;
e653b622 9960#endif /* CONFIG_AP */
207ef3fb
JM
9961 } else if (os_strcmp(buf, "SUSPEND") == 0) {
9962 wpas_notify_suspend(wpa_s->global);
9963 } else if (os_strcmp(buf, "RESUME") == 0) {
9964 wpas_notify_resume(wpa_s->global);
9ff4de6d 9965#ifdef CONFIG_TESTING_OPTIONS
32d5295f
JM
9966 } else if (os_strcmp(buf, "DROP_SA") == 0) {
9967 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
9ff4de6d 9968#endif /* CONFIG_TESTING_OPTIONS */
86d4f806
JM
9969 } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
9970 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
9971 reply_len = -1;
0d0a8ca1 9972 } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
5407c69d 9973 wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0;
78633c37
SL
9974 } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
9975 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
9976 reply_len = -1;
9977 } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
9978 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
9979 buf + 17))
9980 reply_len = -1;
39ee845f 9981 } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
a1144000 9982 wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10);
281ff0aa
GP
9983#ifdef CONFIG_TDLS
9984 } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
9985 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
9986 reply_len = -1;
9987 } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
9988 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
9989 reply_len = -1;
9990 } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
9991 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
9992 reply_len = -1;
6b90deae
AN
9993 } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
9994 if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
9995 buf + 17))
9996 reply_len = -1;
9997 } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
9998 if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
9999 buf + 24))
10000 reply_len = -1;
4504621f
OG
10001 } else if (os_strncmp(buf, "TDLS_LINK_STATUS ", 17) == 0) {
10002 reply_len = wpa_supplicant_ctrl_iface_tdls_link_status(
10003 wpa_s, buf + 17, reply, reply_size);
281ff0aa 10004#endif /* CONFIG_TDLS */
8506ea6f
MB
10005 } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
10006 reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
eb2f2088
MB
10007 } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) {
10008 if (wmm_ac_ctrl_addts(wpa_s, buf + 13))
10009 reply_len = -1;
10010 } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) {
10011 if (wmm_ac_ctrl_delts(wpa_s, buf + 13))
10012 reply_len = -1;
60b24b0d
DS
10013 } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
10014 reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
10015 reply_size);
96e8d831
DS
10016 } else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) {
10017 if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14))
10018 reply_len = -1;
dc7785f8
YZ
10019 } else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
10020 reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
10021 reply_size);
bc5d330a
TB
10022#ifdef CONFIG_AUTOSCAN
10023 } else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
10024 if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
10025 reply_len = -1;
10026#endif /* CONFIG_AUTOSCAN */
4d7aab78
EL
10027 } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
10028 reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
10029 reply_size);
5e2c3490
JM
10030#ifdef ANDROID
10031 } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
10032 reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
10033 reply_size);
10034#endif /* ANDROID */
adef8948
BL
10035 } else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
10036 reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply,
10037 reply_size);
9482426e 10038 } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
f5f37d3a 10039 pmksa_cache_clear_current(wpa_s->wpa);
9482426e 10040 eapol_sm_request_reauth(wpa_s->eapol);
e9199e31
JM
10041#ifdef CONFIG_WNM
10042 } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
10043 if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
10044 reply_len = -1;
07565ab0
MG
10045 } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
10046 if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
65bcd0a9 10047 reply_len = -1;
e9199e31 10048#endif /* CONFIG_WNM */
acb54643
JM
10049 } else if (os_strcmp(buf, "FLUSH") == 0) {
10050 wpa_supplicant_ctrl_iface_flush(wpa_s);
1f965e62
JM
10051 } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
10052 reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
10053 reply_size);
60b893df
JM
10054#ifdef CONFIG_TESTING_OPTIONS
10055 } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
10056 if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0)
10057 reply_len = -1;
10058 } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
10059 wpas_ctrl_iface_mgmt_tx_done(wpa_s);
4de70e23
JM
10060 } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
10061 if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0)
10062 reply_len = -1;
ad12f2f4
JM
10063 } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
10064 if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
10065 reply_len = -1;
9d4ff04a
JM
10066 } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
10067 if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
10068 reply_len = -1;
4a6cc862
JM
10069 } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
10070 if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
10071 reply_len = -1;
10072 } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
10073 if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0)
10074 reply_len = -1;
fc0ef7c0
JM
10075 } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
10076 if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
10077 reply_len = -1;
a156ffda
JM
10078 } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
10079 if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
10080 reply_len = -1;
10081 } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
10082 reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
2da52565
JM
10083 } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
10084 if (wpas_ctrl_test_fail(wpa_s, buf + 10) < 0)
10085 reply_len = -1;
10086 } else if (os_strcmp(buf, "GET_FAIL") == 0) {
10087 reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);
a530fe77
JM
10088 } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
10089 if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
10090 reply_len = -1;
651c6a84
JM
10091 } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
10092 if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
10093 reply_len = -1;
60b893df 10094#endif /* CONFIG_TESTING_OPTIONS */
86bd36f0
JM
10095 } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
10096 if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
10097 reply_len = -1;
10098 } else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) {
10099 reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply,
10100 reply_size);
10101 } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) {
10102 if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
10103 reply_len = -1;
f4b8bfae 10104 } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
6a4f0ed7 10105 if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
f4b8bfae 10106 reply_len = -1;
65d9a5e2
JM
10107 } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
10108 wpas_ctrl_iface_erp_flush(wpa_s);
fb375883
IP
10109 } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
10110 if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
10111 reply_len = -1;
98342208
AK
10112 } else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) {
10113 reply_len = wpas_ctrl_iface_get_pref_freq_list(
10114 wpa_s, buf + 19, reply, reply_size);
5732b770
JM
10115#ifdef CONFIG_FILS
10116 } else if (os_strncmp(buf, "FILS_HLP_REQ_ADD ", 17) == 0) {
10117 if (wpas_ctrl_iface_fils_hlp_req_add(wpa_s, buf + 17))
10118 reply_len = -1;
10119 } else if (os_strcmp(buf, "FILS_HLP_REQ_FLUSH") == 0) {
10120 wpas_flush_fils_hlp_req(wpa_s);
10121#endif /* CONFIG_FILS */
6fc6879b
JM
10122 } else {
10123 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
10124 reply_len = 16;
10125 }
10126
10127 if (reply_len < 0) {
10128 os_memcpy(reply, "FAIL\n", 5);
10129 reply_len = 5;
10130 }
10131
6fc6879b
JM
10132 *resp_len = reply_len;
10133 return reply;
10134}
10135
10136
10137static int wpa_supplicant_global_iface_add(struct wpa_global *global,
10138 char *cmd)
10139{
10140 struct wpa_interface iface;
efa232f9
JJ
10141 char *pos, *extra;
10142 struct wpa_supplicant *wpa_s;
10143 unsigned int create_iface = 0;
10144 u8 mac_addr[ETH_ALEN];
0f039e34 10145 enum wpa_driver_if_type type = WPA_IF_STATION;
6fc6879b
JM
10146
10147 /*
10148 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
0f039e34 10149 * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]]
6fc6879b
JM
10150 */
10151 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
10152
10153 os_memset(&iface, 0, sizeof(iface));
10154
10155 do {
10156 iface.ifname = pos = cmd;
10157 pos = os_strchr(pos, '\t');
10158 if (pos)
10159 *pos++ = '\0';
10160 if (iface.ifname[0] == '\0')
10161 return -1;
10162 if (pos == NULL)
10163 break;
10164
10165 iface.confname = pos;
10166 pos = os_strchr(pos, '\t');
10167 if (pos)
10168 *pos++ = '\0';
10169 if (iface.confname[0] == '\0')
10170 iface.confname = NULL;
10171 if (pos == NULL)
10172 break;
10173
10174 iface.driver = pos;
10175 pos = os_strchr(pos, '\t');
10176 if (pos)
10177 *pos++ = '\0';
10178 if (iface.driver[0] == '\0')
10179 iface.driver = NULL;
10180 if (pos == NULL)
10181 break;
10182
10183 iface.ctrl_interface = pos;
10184 pos = os_strchr(pos, '\t');
10185 if (pos)
10186 *pos++ = '\0';
10187 if (iface.ctrl_interface[0] == '\0')
10188 iface.ctrl_interface = NULL;
10189 if (pos == NULL)
10190 break;
10191
10192 iface.driver_param = pos;
10193 pos = os_strchr(pos, '\t');
10194 if (pos)
10195 *pos++ = '\0';
10196 if (iface.driver_param[0] == '\0')
10197 iface.driver_param = NULL;
10198 if (pos == NULL)
10199 break;
10200
10201 iface.bridge_ifname = pos;
10202 pos = os_strchr(pos, '\t');
10203 if (pos)
10204 *pos++ = '\0';
10205 if (iface.bridge_ifname[0] == '\0')
10206 iface.bridge_ifname = NULL;
10207 if (pos == NULL)
10208 break;
efa232f9
JJ
10209
10210 extra = pos;
10211 pos = os_strchr(pos, '\t');
10212 if (pos)
10213 *pos++ = '\0';
da3db681
BG
10214 if (!extra[0])
10215 break;
10216
0f039e34 10217 if (os_strcmp(extra, "create") == 0) {
efa232f9 10218 create_iface = 1;
0f039e34
AS
10219 if (!pos)
10220 break;
10221
10222 if (os_strcmp(pos, "sta") == 0) {
10223 type = WPA_IF_STATION;
10224 } else if (os_strcmp(pos, "ap") == 0) {
10225 type = WPA_IF_AP_BSS;
10226 } else {
10227 wpa_printf(MSG_DEBUG,
10228 "INTERFACE_ADD unsupported interface type: '%s'",
10229 pos);
10230 return -1;
10231 }
10232 } else {
da3db681
BG
10233 wpa_printf(MSG_DEBUG,
10234 "INTERFACE_ADD unsupported extra parameter: '%s'",
10235 extra);
efa232f9 10236 return -1;
da3db681 10237 }
6fc6879b
JM
10238 } while (0);
10239
efa232f9
JJ
10240 if (create_iface) {
10241 wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'",
10242 iface.ifname);
10243 if (!global->ifaces)
10244 return -1;
0f039e34 10245 if (wpa_drv_if_add(global->ifaces, type, iface.ifname,
efa232f9
JJ
10246 NULL, NULL, NULL, mac_addr, NULL) < 0) {
10247 wpa_printf(MSG_ERROR,
10248 "CTRL_IFACE interface creation failed");
10249 return -1;
10250 }
10251
10252 wpa_printf(MSG_DEBUG,
10253 "CTRL_IFACE interface '%s' created with MAC addr: "
10254 MACSTR, iface.ifname, MAC2STR(mac_addr));
10255 }
10256
6fc6879b 10257 if (wpa_supplicant_get_iface(global, iface.ifname))
efa232f9
JJ
10258 goto fail;
10259
10260 wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
10261 if (!wpa_s)
10262 goto fail;
10263 wpa_s->added_vif = create_iface;
10264 return 0;
6fc6879b 10265
efa232f9
JJ
10266fail:
10267 if (create_iface)
10268 wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname);
10269 return -1;
6fc6879b
JM
10270}
10271
10272
10273static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
10274 char *cmd)
10275{
10276 struct wpa_supplicant *wpa_s;
efa232f9
JJ
10277 int ret;
10278 unsigned int delete_iface;
6fc6879b
JM
10279
10280 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
10281
10282 wpa_s = wpa_supplicant_get_iface(global, cmd);
10283 if (wpa_s == NULL)
10284 return -1;
efa232f9
JJ
10285 delete_iface = wpa_s->added_vif;
10286 ret = wpa_supplicant_remove_iface(global, wpa_s, 0);
10287 if (!ret && delete_iface) {
10288 wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'",
10289 cmd);
10290 ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd);
10291 }
10292 return ret;
6fc6879b
JM
10293}
10294
10295
4b4a8ae5
JM
10296static void wpa_free_iface_info(struct wpa_interface_info *iface)
10297{
10298 struct wpa_interface_info *prev;
10299
10300 while (iface) {
10301 prev = iface;
10302 iface = iface->next;
10303
10304 os_free(prev->ifname);
10305 os_free(prev->desc);
10306 os_free(prev);
10307 }
10308}
10309
10310
10311static int wpa_supplicant_global_iface_list(struct wpa_global *global,
10312 char *buf, int len)
10313{
10314 int i, res;
10315 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
10316 char *pos, *end;
10317
c5121837 10318 for (i = 0; wpa_drivers[i]; i++) {
8b423edb 10319 const struct wpa_driver_ops *drv = wpa_drivers[i];
4b4a8ae5
JM
10320 if (drv->get_interfaces == NULL)
10321 continue;
5fbc1f27 10322 tmp = drv->get_interfaces(global->drv_priv[i]);
4b4a8ae5
JM
10323 if (tmp == NULL)
10324 continue;
10325
10326 if (last == NULL)
10327 iface = last = tmp;
10328 else
10329 last->next = tmp;
10330 while (last->next)
10331 last = last->next;
10332 }
10333
10334 pos = buf;
10335 end = buf + len;
10336 for (tmp = iface; tmp; tmp = tmp->next) {
10337 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
10338 tmp->drv_name, tmp->ifname,
10339 tmp->desc ? tmp->desc : "");
d85e1fc8 10340 if (os_snprintf_error(end - pos, res)) {
4b4a8ae5
JM
10341 *pos = '\0';
10342 break;
10343 }
10344 pos += res;
10345 }
10346
10347 wpa_free_iface_info(iface);
10348
10349 return pos - buf;
10350}
10351
10352
6fc6879b 10353static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
56e2fc2c 10354 const char *input,
6fc6879b
JM
10355 char *buf, int len)
10356{
10357 int res;
10358 char *pos, *end;
10359 struct wpa_supplicant *wpa_s;
56e2fc2c
JD
10360 int show_ctrl = 0;
10361
10362 if (input)
10363 show_ctrl = !!os_strstr(input, "ctrl");
6fc6879b
JM
10364
10365 wpa_s = global->ifaces;
10366 pos = buf;
10367 end = buf + len;
10368
10369 while (wpa_s) {
56e2fc2c
JD
10370 if (show_ctrl)
10371 res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n",
10372 wpa_s->ifname,
10373 wpa_s->conf->ctrl_interface ?
10374 wpa_s->conf->ctrl_interface : "N/A");
10375 else
10376 res = os_snprintf(pos, end - pos, "%s\n",
10377 wpa_s->ifname);
10378
d85e1fc8 10379 if (os_snprintf_error(end - pos, res)) {
6fc6879b
JM
10380 *pos = '\0';
10381 break;
10382 }
10383 pos += res;
10384 wpa_s = wpa_s->next;
10385 }
10386 return pos - buf;
10387}
10388
10389
cf3bebf2
JM
10390static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
10391 const char *ifname,
10392 char *cmd, size_t *resp_len)
10393{
10394 struct wpa_supplicant *wpa_s;
10395
10396 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
10397 if (os_strcmp(ifname, wpa_s->ifname) == 0)
10398 break;
10399 }
10400
10401 if (wpa_s == NULL) {
10402 char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
10403 if (resp)
10404 *resp_len = os_strlen(resp);
10405 else
10406 *resp_len = 1;
10407 return resp;
10408 }
10409
10410 return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
10411}
10412
10413
576bce9c
JM
10414static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
10415 char *buf, size_t *resp_len)
10416{
10417#ifdef CONFIG_P2P
10418 static const char * cmd[] = {
443427e4 10419 "LIST_NETWORKS",
576bce9c
JM
10420 "P2P_FIND",
10421 "P2P_STOP_FIND",
10422 "P2P_LISTEN",
10423 "P2P_GROUP_ADD",
10424 "P2P_GET_PASSPHRASE",
10425 "P2P_SERVICE_UPDATE",
10426 "P2P_SERVICE_FLUSH",
10427 "P2P_FLUSH",
10428 "P2P_CANCEL",
10429 "P2P_PRESENCE_REQ",
10430 "P2P_EXT_LISTEN",
f2bc3448
DS
10431#ifdef CONFIG_AP
10432 "STA-FIRST",
10433#endif /* CONFIG_AP */
576bce9c
JM
10434 NULL
10435 };
10436 static const char * prefix[] = {
443427e4
DS
10437#ifdef ANDROID
10438 "DRIVER ",
10439#endif /* ANDROID */
10440 "GET_NETWORK ",
10441 "REMOVE_NETWORK ",
576bce9c
JM
10442 "P2P_FIND ",
10443 "P2P_CONNECT ",
10444 "P2P_LISTEN ",
10445 "P2P_GROUP_REMOVE ",
10446 "P2P_GROUP_ADD ",
57b38882 10447 "P2P_GROUP_MEMBER ",
576bce9c
JM
10448 "P2P_PROV_DISC ",
10449 "P2P_SERV_DISC_REQ ",
10450 "P2P_SERV_DISC_CANCEL_REQ ",
10451 "P2P_SERV_DISC_RESP ",
10452 "P2P_SERV_DISC_EXTERNAL ",
10453 "P2P_SERVICE_ADD ",
10454 "P2P_SERVICE_DEL ",
87d5ef5a 10455 "P2P_SERVICE_REP ",
576bce9c
JM
10456 "P2P_REJECT ",
10457 "P2P_INVITE ",
10458 "P2P_PEER ",
10459 "P2P_SET ",
10460 "P2P_UNAUTHORIZE ",
10461 "P2P_PRESENCE_REQ ",
10462 "P2P_EXT_LISTEN ",
f2c56602 10463 "P2P_REMOVE_CLIENT ",
8ad8bc5c
DS
10464 "WPS_NFC_TOKEN ",
10465 "WPS_NFC_TAG_READ ",
f3ff9487
AM
10466 "NFC_GET_HANDOVER_SEL ",
10467 "NFC_GET_HANDOVER_REQ ",
10468 "NFC_REPORT_HANDOVER ",
87d5ef5a
KV
10469 "P2P_ASP_PROVISION ",
10470 "P2P_ASP_PROVISION_RESP ",
f2bc3448
DS
10471#ifdef CONFIG_AP
10472 "STA ",
10473 "STA-NEXT ",
10474#endif /* CONFIG_AP */
576bce9c
JM
10475 NULL
10476 };
10477 int found = 0;
10478 int i;
10479
10480 if (global->p2p_init_wpa_s == NULL)
10481 return NULL;
10482
10483 for (i = 0; !found && cmd[i]; i++) {
10484 if (os_strcmp(buf, cmd[i]) == 0)
10485 found = 1;
10486 }
10487
10488 for (i = 0; !found && prefix[i]; i++) {
10489 if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
10490 found = 1;
10491 }
10492
10493 if (found)
10494 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
10495 buf, resp_len);
10496#endif /* CONFIG_P2P */
10497 return NULL;
10498}
10499
10500
10501static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
10502 char *buf, size_t *resp_len)
10503{
10504#ifdef CONFIG_WIFI_DISPLAY
10505 if (global->p2p_init_wpa_s == NULL)
10506 return NULL;
10507 if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
10508 os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
10509 return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
10510 buf, resp_len);
10511#endif /* CONFIG_WIFI_DISPLAY */
10512 return NULL;
10513}
10514
10515
10516static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
10517 char *buf, size_t *resp_len)
10518{
10519 char *ret;
10520
10521 ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
10522 if (ret)
10523 return ret;
10524
10525 ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
10526 if (ret)
10527 return ret;
10528
10529 return NULL;
10530}
10531
10532
1b9b31c1
JM
10533static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
10534{
10535 char *value;
10536
10537 value = os_strchr(cmd, ' ');
10538 if (value == NULL)
10539 return -1;
10540 *value++ = '\0';
10541
10542 wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
10543
10544#ifdef CONFIG_WIFI_DISPLAY
10545 if (os_strcasecmp(cmd, "wifi_display") == 0) {
10546 wifi_display_enable(global, !!atoi(value));
10547 return 0;
10548 }
10549#endif /* CONFIG_WIFI_DISPLAY */
10550
a7ca6dac
JM
10551 /* Restore cmd to its original value to allow redirection */
10552 value[-1] = ' ';
10553
1b9b31c1
JM
10554 return -1;
10555}
10556
10557
daae4995
AN
10558static int wpas_global_ctrl_iface_dup_network(struct wpa_global *global,
10559 char *cmd)
10560{
10561 struct wpa_supplicant *wpa_s[2]; /* src, dst */
10562 char *p;
10563 unsigned int i;
10564
10565 /* cmd: "<src ifname> <dst ifname> <src network id> <dst network id>
10566 * <variable name> */
10567
10568 for (i = 0; i < ARRAY_SIZE(wpa_s) ; i++) {
10569 p = os_strchr(cmd, ' ');
10570 if (p == NULL)
10571 return -1;
10572 *p = '\0';
10573
10574 wpa_s[i] = global->ifaces;
10575 for (; wpa_s[i]; wpa_s[i] = wpa_s[i]->next) {
10576 if (os_strcmp(cmd, wpa_s[i]->ifname) == 0)
10577 break;
10578 }
10579
10580 if (!wpa_s[i]) {
10581 wpa_printf(MSG_DEBUG,
10582 "CTRL_IFACE: Could not find iface=%s", cmd);
10583 return -1;
10584 }
10585
10586 cmd = p + 1;
10587 }
10588
10589 return wpa_supplicant_ctrl_iface_dup_network(wpa_s[0], cmd, wpa_s[1]);
10590}
10591
10592
42868f14
JM
10593#ifndef CONFIG_NO_CONFIG_WRITE
10594static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
10595{
d6b818ef 10596 int ret = 0, saved = 0;
42868f14
JM
10597 struct wpa_supplicant *wpa_s;
10598
10599 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
10600 if (!wpa_s->conf->update_config) {
10601 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
10602 continue;
10603 }
10604
10605 if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
10606 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
10607 ret = 1;
10608 } else {
10609 wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
d6b818ef 10610 saved++;
42868f14
JM
10611 }
10612 }
10613
d6b818ef
JM
10614 if (!saved && !ret) {
10615 wpa_dbg(wpa_s, MSG_DEBUG,
10616 "CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated");
10617 ret = 1;
10618 }
10619
42868f14
JM
10620 return ret;
10621}
10622#endif /* CONFIG_NO_CONFIG_WRITE */
10623
10624
ae8c27f7
JM
10625static int wpas_global_ctrl_iface_status(struct wpa_global *global,
10626 char *buf, size_t buflen)
10627{
10628 char *pos, *end;
10629 int ret;
10630 struct wpa_supplicant *wpa_s;
10631
10632 pos = buf;
10633 end = buf + buflen;
10634
10635#ifdef CONFIG_P2P
4c559019 10636 if (global->p2p && !global->p2p_disabled) {
ae8c27f7 10637 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
4c559019
JM
10638 "\n"
10639 "p2p_state=%s\n",
10640 MAC2STR(global->p2p_dev_addr),
10641 p2p_get_state_txt(global->p2p));
d85e1fc8 10642 if (os_snprintf_error(end - pos, ret))
4c559019
JM
10643 return pos - buf;
10644 pos += ret;
10645 } else if (global->p2p) {
10646 ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
d85e1fc8 10647 if (os_snprintf_error(end - pos, ret))
ae8c27f7
JM
10648 return pos - buf;
10649 pos += ret;
10650 }
10651#endif /* CONFIG_P2P */
10652
10653#ifdef CONFIG_WIFI_DISPLAY
10654 ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
10655 !!global->wifi_display);
d85e1fc8 10656 if (os_snprintf_error(end - pos, ret))
ae8c27f7
JM
10657 return pos - buf;
10658 pos += ret;
10659#endif /* CONFIG_WIFI_DISPLAY */
10660
10661 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
10662 ret = os_snprintf(pos, end - pos, "ifname=%s\n"
10663 "address=" MACSTR "\n",
10664 wpa_s->ifname, MAC2STR(wpa_s->own_addr));
d85e1fc8 10665 if (os_snprintf_error(end - pos, ret))
ae8c27f7
JM
10666 return pos - buf;
10667 pos += ret;
10668 }
10669
10670 return pos - buf;
10671}
10672
10673
3794af2d
AN
10674#ifdef CONFIG_FST
10675
10676static int wpas_global_ctrl_iface_fst_attach(struct wpa_global *global,
10677 char *cmd, char *buf,
10678 size_t reply_size)
10679{
10680 char ifname[IFNAMSIZ + 1];
10681 struct fst_iface_cfg cfg;
10682 struct wpa_supplicant *wpa_s;
10683 struct fst_wpa_obj iface_obj;
10684
10685 if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
10686 wpa_s = wpa_supplicant_get_iface(global, ifname);
10687 if (wpa_s) {
5dbd3bf9
JM
10688 if (wpa_s->fst) {
10689 wpa_printf(MSG_INFO, "FST: Already attached");
10690 return -1;
10691 }
3794af2d
AN
10692 fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
10693 wpa_s->fst = fst_attach(ifname, wpa_s->own_addr,
10694 &iface_obj, &cfg);
10695 if (wpa_s->fst)
10696 return os_snprintf(buf, reply_size, "OK\n");
10697 }
10698 }
10699
10700 return -1;
10701}
10702
10703
10704static int wpas_global_ctrl_iface_fst_detach(struct wpa_global *global,
10705 char *cmd, char *buf,
10706 size_t reply_size)
10707{
10708 char ifname[IFNAMSIZ + 1];
10709 struct wpa_supplicant *wpa_s;
10710
10711 if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
10712 wpa_s = wpa_supplicant_get_iface(global, ifname);
10713 if (wpa_s) {
10714 if (!fst_iface_detach(ifname)) {
10715 wpa_s->fst = NULL;
10716 return os_snprintf(buf, reply_size, "OK\n");
10717 }
10718 }
10719 }
10720
10721 return -1;
10722}
10723
10724#endif /* CONFIG_FST */
10725
10726
6fc6879b
JM
10727char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
10728 char *buf, size_t *resp_len)
10729{
10730 char *reply;
10731 const int reply_size = 2048;
10732 int reply_len;
f4a0a82c 10733 int level = MSG_DEBUG;
6fc6879b 10734
cf3bebf2
JM
10735 if (os_strncmp(buf, "IFNAME=", 7) == 0) {
10736 char *pos = os_strchr(buf + 7, ' ');
10737 if (pos) {
10738 *pos++ = '\0';
10739 return wpas_global_ctrl_iface_ifname(global,
10740 buf + 7, pos,
10741 resp_len);
10742 }
10743 }
10744
576bce9c
JM
10745 reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
10746 if (reply)
10747 return reply;
10748
f4a0a82c
JM
10749 if (os_strcmp(buf, "PING") == 0)
10750 level = MSG_EXCESSIVE;
10751 wpa_hexdump_ascii(level, "RX global ctrl_iface",
6fc6879b
JM
10752 (const u8 *) buf, os_strlen(buf));
10753
10754 reply = os_malloc(reply_size);
10755 if (reply == NULL) {
10756 *resp_len = 1;
10757 return NULL;
10758 }
10759
10760 os_memcpy(reply, "OK\n", 3);
10761 reply_len = 3;
10762
10763 if (os_strcmp(buf, "PING") == 0) {
10764 os_memcpy(reply, "PONG\n", 5);
10765 reply_len = 5;
10766 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
10767 if (wpa_supplicant_global_iface_add(global, buf + 14))
10768 reply_len = -1;
10769 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
10770 if (wpa_supplicant_global_iface_remove(global, buf + 17))
10771 reply_len = -1;
4b4a8ae5
JM
10772 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
10773 reply_len = wpa_supplicant_global_iface_list(
10774 global, reply, reply_size);
56e2fc2c 10775 } else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
6fc6879b 10776 reply_len = wpa_supplicant_global_iface_interfaces(
56e2fc2c 10777 global, buf + 10, reply, reply_size);
3794af2d
AN
10778#ifdef CONFIG_FST
10779 } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
10780 reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11,
10781 reply,
10782 reply_size);
10783 } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
10784 reply_len = wpas_global_ctrl_iface_fst_detach(global, buf + 11,
10785 reply,
10786 reply_size);
10787 } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
10788 reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
10789#endif /* CONFIG_FST */
6fc6879b 10790 } else if (os_strcmp(buf, "TERMINATE") == 0) {
1a1bf008 10791 wpa_supplicant_terminate_proc(global);
207ef3fb
JM
10792 } else if (os_strcmp(buf, "SUSPEND") == 0) {
10793 wpas_notify_suspend(global);
10794 } else if (os_strcmp(buf, "RESUME") == 0) {
10795 wpas_notify_resume(global);
1b9b31c1 10796 } else if (os_strncmp(buf, "SET ", 4) == 0) {
a7ca6dac
JM
10797 if (wpas_global_ctrl_iface_set(global, buf + 4)) {
10798#ifdef CONFIG_P2P
10799 if (global->p2p_init_wpa_s) {
10800 os_free(reply);
10801 /* Check if P2P redirection would work for this
10802 * command. */
10803 return wpa_supplicant_ctrl_iface_process(
10804 global->p2p_init_wpa_s,
10805 buf, resp_len);
10806 }
10807#endif /* CONFIG_P2P */
1b9b31c1 10808 reply_len = -1;
a7ca6dac 10809 }
daae4995
AN
10810 } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
10811 if (wpas_global_ctrl_iface_dup_network(global, buf + 12))
10812 reply_len = -1;
42868f14
JM
10813#ifndef CONFIG_NO_CONFIG_WRITE
10814 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
10815 if (wpas_global_ctrl_iface_save_config(global))
10816 reply_len = -1;
10817#endif /* CONFIG_NO_CONFIG_WRITE */
ae8c27f7
JM
10818 } else if (os_strcmp(buf, "STATUS") == 0) {
10819 reply_len = wpas_global_ctrl_iface_status(global, reply,
10820 reply_size);
ea449b5b
JM
10821#ifdef CONFIG_MODULE_TESTS
10822 } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
ea449b5b
JM
10823 if (wpas_module_tests() < 0)
10824 reply_len = -1;
10825#endif /* CONFIG_MODULE_TESTS */
5f797376
JM
10826 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
10827 if (wpa_debug_reopen_file() < 0)
10828 reply_len = -1;
6fc6879b
JM
10829 } else {
10830 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
10831 reply_len = 16;
10832 }
10833
10834 if (reply_len < 0) {
10835 os_memcpy(reply, "FAIL\n", 5);
10836 reply_len = 5;
10837 }
10838
10839 *resp_len = reply_len;
10840 return reply;
10841}