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