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