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