]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/ctrl_iface.c
Use normal scan before sched_scan if that can speed up connection
[thirdparty/hostap.git] / wpa_supplicant / ctrl_iface.c
CommitLineData
6fc6879b
JM
1/*
2 * WPA Supplicant / Control interface (shared code for all backends)
207ef3fb 3 * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
6fc6879b
JM
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
3a068632 15#include "utils/includes.h"
6fc6879b 16
3a068632
JM
17#include "utils/common.h"
18#include "utils/eloop.h"
acec8d32 19#include "common/version.h"
3a068632
JM
20#include "common/ieee802_11_defs.h"
21#include "common/wpa_ctrl.h"
22#include "eap_peer/eap.h"
23#include "eapol_supp/eapol_supp_sm.h"
3acb5005 24#include "rsn_supp/wpa.h"
3a068632
JM
25#include "rsn_supp/preauth.h"
26#include "rsn_supp/pmksa_cache.h"
27#include "l2_packet/l2_packet.h"
28#include "wps/wps.h"
6fc6879b 29#include "config.h"
6fc6879b 30#include "wpa_supplicant_i.h"
2d5b792d 31#include "driver_i.h"
fcc60db4 32#include "wps_supplicant.h"
11ef8d35 33#include "ibss_rsn.h"
3ec97afe 34#include "ap.h"
b563b388
JM
35#include "p2p_supplicant.h"
36#include "p2p/p2p.h"
8bac466b 37#include "notify.h"
3a068632 38#include "bss.h"
9ba9fa07 39#include "scan.h"
3a068632 40#include "ctrl_iface.h"
afc064fe 41#include "interworking.h"
9aa10e2b 42#include "blacklist.h"
7de5688d 43#include "wpas_glue.h"
6fc6879b 44
c5121837 45extern struct wpa_driver_ops *wpa_drivers[];
2d5b792d 46
4b4a8ae5
JM
47static int wpa_supplicant_global_iface_list(struct wpa_global *global,
48 char *buf, int len);
6fc6879b
JM
49static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
50 char *buf, int len);
51
52
b5c68312
JM
53static int pno_start(struct wpa_supplicant *wpa_s)
54{
55 int ret;
56 size_t i, num_ssid;
57 struct wpa_ssid *ssid;
58 struct wpa_driver_scan_params params;
59
60 if (wpa_s->pno)
61 return 0;
62
63 os_memset(&params, 0, sizeof(params));
64
65 num_ssid = 0;
66 ssid = wpa_s->conf->ssid;
67 while (ssid) {
68 if (!ssid->disabled)
69 num_ssid++;
70 ssid = ssid->next;
71 }
72 if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
73 wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
74 "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
75 num_ssid = WPAS_MAX_SCAN_SSIDS;
76 }
77
78 if (num_ssid == 0) {
79 wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
80 return -1;
81 }
82
83 params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
84 num_ssid);
85 if (params.filter_ssids == NULL)
86 return -1;
87 i = 0;
88 while (ssid) {
89 if (!ssid->disabled) {
90 params.ssids[i].ssid = ssid->ssid;
91 params.ssids[i].ssid_len = ssid->ssid_len;
92 params.num_ssids++;
93 os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
94 ssid->ssid_len);
95 params.filter_ssids[i].ssid_len = ssid->ssid_len;
96 params.num_filter_ssids++;
97 i++;
98 if (i == num_ssid)
99 break;
100 }
101 ssid = ssid->next;
102 }
103
104 ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
105 os_free(params.filter_ssids);
106 if (ret == 0)
107 wpa_s->pno = 1;
108 return ret;
109}
110
111
112static int pno_stop(struct wpa_supplicant *wpa_s)
113{
114 if (wpa_s->pno) {
115 wpa_s->pno = 0;
116 return wpa_drv_stop_sched_scan(wpa_s);
117 }
118 return 0;
119}
120
121
6fc6879b
JM
122static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
123 char *cmd)
124{
125 char *value;
126 int ret = 0;
127
128 value = os_strchr(cmd, ' ');
129 if (value == NULL)
130 return -1;
131 *value++ = '\0';
132
133 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
134 if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
135 eapol_sm_configure(wpa_s->eapol,
136 atoi(value), -1, -1, -1);
137 } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
138 eapol_sm_configure(wpa_s->eapol,
139 -1, atoi(value), -1, -1);
140 } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
141 eapol_sm_configure(wpa_s->eapol,
142 -1, -1, atoi(value), -1);
143 } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
144 eapol_sm_configure(wpa_s->eapol,
145 -1, -1, -1, atoi(value));
146 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
147 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
148 atoi(value)))
149 ret = -1;
150 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
151 0) {
152 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
153 atoi(value)))
154 ret = -1;
155 } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
156 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
157 ret = -1;
42f50264
JM
158 } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
159 wpa_s->wps_fragment_size = atoi(value);
b4e34f2f
JM
160#ifdef CONFIG_WPS_TESTING
161 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
162 long int val;
163 val = strtol(value, NULL, 0);
164 if (val < 0 || val > 0xff) {
165 ret = -1;
166 wpa_printf(MSG_DEBUG, "WPS: Invalid "
167 "wps_version_number %ld", val);
168 } else {
169 wps_version_number = val;
170 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
171 "version %u.%u",
172 (wps_version_number & 0xf0) >> 4,
173 wps_version_number & 0x0f);
174 }
175 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
176 wps_testing_dummy_cred = atoi(value);
177 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
178 wps_testing_dummy_cred);
179#endif /* CONFIG_WPS_TESTING */
b6c79a99
JM
180 } else if (os_strcasecmp(cmd, "ampdu") == 0) {
181 if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
182 ret = -1;
5b0e6ece
JM
183#ifdef CONFIG_TDLS_TESTING
184 } else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
185 extern unsigned int tdls_testing;
186 tdls_testing = strtol(value, NULL, 0);
187 wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
188#endif /* CONFIG_TDLS_TESTING */
b8f64582
JM
189#ifdef CONFIG_TDLS
190 } else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
191 int disabled = atoi(value);
192 wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
193 if (disabled) {
194 if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
195 ret = -1;
196 } else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
197 ret = -1;
198 wpa_tdls_enable(wpa_s->wpa, !disabled);
199#endif /* CONFIG_TDLS */
b5c68312
JM
200 } else if (os_strcasecmp(cmd, "pno") == 0) {
201 if (atoi(value))
202 ret = pno_start(wpa_s);
203 else
204 ret = pno_stop(wpa_s);
611aea7d
JM
205 } else {
206 value[-1] = '=';
207 ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
208 if (ret == 0)
209 wpa_supplicant_update_config(wpa_s);
210 }
6fc6879b
JM
211
212 return ret;
213}
214
215
acec8d32
JM
216static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
217 char *cmd, char *buf, size_t buflen)
218{
6ce937b8 219 int res = -1;
acec8d32
JM
220
221 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
222
223 if (os_strcmp(cmd, "version") == 0) {
224 res = os_snprintf(buf, buflen, "%s", VERSION_STR);
6ce937b8
DS
225 } else if (os_strcasecmp(cmd, "country") == 0) {
226 if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
227 res = os_snprintf(buf, buflen, "%c%c",
228 wpa_s->conf->country[0],
229 wpa_s->conf->country[1]);
acec8d32
JM
230 }
231
6ce937b8
DS
232 if (res < 0 || (unsigned int) res >= buflen)
233 return -1;
234 return res;
acec8d32
JM
235}
236
237
ec717917 238#ifdef IEEE8021X_EAPOL
6fc6879b
JM
239static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
240 char *addr)
241{
242 u8 bssid[ETH_ALEN];
243 struct wpa_ssid *ssid = wpa_s->current_ssid;
244
245 if (hwaddr_aton(addr, bssid)) {
246 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
247 "'%s'", addr);
248 return -1;
249 }
250
251 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
252 rsn_preauth_deinit(wpa_s->wpa);
253 if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
254 return -1;
255
256 return 0;
257}
ec717917 258#endif /* IEEE8021X_EAPOL */
6fc6879b
JM
259
260
261#ifdef CONFIG_PEERKEY
262/* MLME-STKSTART.request(peer) */
263static int wpa_supplicant_ctrl_iface_stkstart(
264 struct wpa_supplicant *wpa_s, char *addr)
265{
266 u8 peer[ETH_ALEN];
267
268 if (hwaddr_aton(addr, peer)) {
269 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
a7b6c422 270 "address '%s'", addr);
6fc6879b
JM
271 return -1;
272 }
273
274 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
275 MAC2STR(peer));
276
277 return wpa_sm_stkstart(wpa_s->wpa, peer);
278}
279#endif /* CONFIG_PEERKEY */
280
281
281ff0aa
GP
282#ifdef CONFIG_TDLS
283
284static int wpa_supplicant_ctrl_iface_tdls_discover(
285 struct wpa_supplicant *wpa_s, char *addr)
286{
287 u8 peer[ETH_ALEN];
2d565a61 288 int ret;
281ff0aa
GP
289
290 if (hwaddr_aton(addr, peer)) {
291 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
292 "address '%s'", addr);
293 return -1;
294 }
295
296 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
297 MAC2STR(peer));
298
2d565a61
AN
299 if (wpa_tdls_is_external_setup(wpa_s->wpa))
300 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
301 else
302 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
303
304 return ret;
281ff0aa
GP
305}
306
307
308static int wpa_supplicant_ctrl_iface_tdls_setup(
309 struct wpa_supplicant *wpa_s, char *addr)
310{
311 u8 peer[ETH_ALEN];
94377fbc 312 int ret;
281ff0aa
GP
313
314 if (hwaddr_aton(addr, peer)) {
315 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
316 "address '%s'", addr);
317 return -1;
318 }
319
320 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
321 MAC2STR(peer));
322
94377fbc 323 ret = wpa_tdls_reneg(wpa_s->wpa, peer);
2d565a61
AN
324 if (ret) {
325 if (wpa_tdls_is_external_setup(wpa_s->wpa))
326 ret = wpa_tdls_start(wpa_s->wpa, peer);
327 else
328 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
329 }
330
94377fbc 331 return ret;
281ff0aa
GP
332}
333
334
335static int wpa_supplicant_ctrl_iface_tdls_teardown(
336 struct wpa_supplicant *wpa_s, char *addr)
337{
338 u8 peer[ETH_ALEN];
339
340 if (hwaddr_aton(addr, peer)) {
341 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
342 "address '%s'", addr);
343 return -1;
344 }
345
346 wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
347 MAC2STR(peer));
348
2d565a61
AN
349 return wpa_tdls_teardown_link(wpa_s->wpa, peer,
350 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
281ff0aa
GP
351}
352
353#endif /* CONFIG_TDLS */
354
355
6fc6879b
JM
356#ifdef CONFIG_IEEE80211R
357static int wpa_supplicant_ctrl_iface_ft_ds(
358 struct wpa_supplicant *wpa_s, char *addr)
359{
360 u8 target_ap[ETH_ALEN];
76b7981d
JM
361 struct wpa_bss *bss;
362 const u8 *mdie;
6fc6879b
JM
363
364 if (hwaddr_aton(addr, target_ap)) {
365 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
a7b6c422 366 "address '%s'", addr);
6fc6879b
JM
367 return -1;
368 }
369
370 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
371
76b7981d
JM
372 bss = wpa_bss_get_bssid(wpa_s, target_ap);
373 if (bss)
374 mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
375 else
376 mdie = NULL;
377
378 return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
6fc6879b
JM
379}
380#endif /* CONFIG_IEEE80211R */
381
382
fcc60db4
JM
383#ifdef CONFIG_WPS
384static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
385 char *cmd)
386{
3ec97afe 387 u8 bssid[ETH_ALEN], *_bssid = bssid;
ceb34f25 388#ifdef CONFIG_P2P
634ce802 389 u8 p2p_dev_addr[ETH_ALEN];
ceb34f25 390#endif /* CONFIG_P2P */
634ce802
JM
391#ifdef CONFIG_AP
392 u8 *_p2p_dev_addr = NULL;
393#endif /* CONFIG_AP */
fcc60db4 394
d601247c 395 if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
3ec97afe 396 _bssid = NULL;
d601247c
JM
397#ifdef CONFIG_P2P
398 } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
399 if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
400 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
401 "P2P Device Address '%s'",
402 cmd + 13);
403 return -1;
404 }
405 _p2p_dev_addr = p2p_dev_addr;
406#endif /* CONFIG_P2P */
407 } else if (hwaddr_aton(cmd, bssid)) {
fcc60db4
JM
408 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
409 cmd);
410 return -1;
411 }
412
3ec97afe
JM
413#ifdef CONFIG_AP
414 if (wpa_s->ap_iface)
d601247c 415 return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
3ec97afe
JM
416#endif /* CONFIG_AP */
417
9fa243b2 418 return wpas_wps_start_pbc(wpa_s, _bssid, 0);
fcc60db4
JM
419}
420
421
422static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
423 char *cmd, char *buf,
424 size_t buflen)
425{
426 u8 bssid[ETH_ALEN], *_bssid = bssid;
427 char *pin;
428 int ret;
429
430 pin = os_strchr(cmd, ' ');
431 if (pin)
432 *pin++ = '\0';
433
434 if (os_strcmp(cmd, "any") == 0)
435 _bssid = NULL;
98aa7ca5
JM
436 else if (os_strcmp(cmd, "get") == 0) {
437 ret = wps_generate_pin();
438 goto done;
439 } else if (hwaddr_aton(cmd, bssid)) {
3c1e2765 440 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
fcc60db4
JM
441 cmd);
442 return -1;
443 }
444
3ec97afe
JM
445#ifdef CONFIG_AP
446 if (wpa_s->ap_iface)
447 return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
448 buf, buflen);
449#endif /* CONFIG_AP */
450
fcc60db4 451 if (pin) {
3c5126a4
JM
452 ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
453 DEV_PW_DEFAULT);
fcc60db4
JM
454 if (ret < 0)
455 return -1;
456 ret = os_snprintf(buf, buflen, "%s", pin);
457 if (ret < 0 || (size_t) ret >= buflen)
458 return -1;
459 return ret;
460 }
461
3c5126a4 462 ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
fcc60db4
JM
463 if (ret < 0)
464 return -1;
465
98aa7ca5 466done:
fcc60db4
JM
467 /* Return the generated PIN */
468 ret = os_snprintf(buf, buflen, "%08d", ret);
469 if (ret < 0 || (size_t) ret >= buflen)
470 return -1;
471 return ret;
472}
473
474
3981cb3c
JM
475static int wpa_supplicant_ctrl_iface_wps_check_pin(
476 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
477{
478 char pin[9];
479 size_t len;
480 char *pos;
481 int ret;
482
483 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
484 (u8 *) cmd, os_strlen(cmd));
485 for (pos = cmd, len = 0; *pos != '\0'; pos++) {
486 if (*pos < '0' || *pos > '9')
487 continue;
488 pin[len++] = *pos;
489 if (len == 9) {
490 wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
491 return -1;
492 }
493 }
494 if (len != 4 && len != 8) {
495 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
496 return -1;
497 }
498 pin[len] = '\0';
499
500 if (len == 8) {
501 unsigned int pin_val;
502 pin_val = atoi(pin);
503 if (!wps_pin_valid(pin_val)) {
504 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
505 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
506 if (ret < 0 || (size_t) ret >= buflen)
507 return -1;
508 return ret;
509 }
510 }
511
512 ret = os_snprintf(buf, buflen, "%s", pin);
513 if (ret < 0 || (size_t) ret >= buflen)
514 return -1;
515
516 return ret;
517}
518
519
116f7bb0 520#ifdef CONFIG_WPS_OOB
46bdb83a
MH
521static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
522 char *cmd)
523{
e1ee6b60 524 char *path, *method, *name;
46bdb83a
MH
525
526 path = os_strchr(cmd, ' ');
527 if (path == NULL)
528 return -1;
529 *path++ = '\0';
530
531 method = os_strchr(path, ' ');
532 if (method == NULL)
533 return -1;
534 *method++ = '\0';
535
e1ee6b60
MH
536 name = os_strchr(method, ' ');
537 if (name != NULL)
538 *name++ = '\0';
539
540 return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
46bdb83a 541}
116f7bb0 542#endif /* CONFIG_WPS_OOB */
46bdb83a
MH
543
544
fcc60db4
JM
545static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
546 char *cmd)
547{
129eb428 548 u8 bssid[ETH_ALEN];
fcc60db4 549 char *pin;
52eb293d
JM
550 char *new_ssid;
551 char *new_auth;
552 char *new_encr;
553 char *new_key;
554 struct wps_new_ap_settings ap;
fcc60db4
JM
555
556 pin = os_strchr(cmd, ' ');
557 if (pin == NULL)
558 return -1;
559 *pin++ = '\0';
560
129eb428 561 if (hwaddr_aton(cmd, bssid)) {
fcc60db4
JM
562 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
563 cmd);
564 return -1;
565 }
566
52eb293d
JM
567 new_ssid = os_strchr(pin, ' ');
568 if (new_ssid == NULL)
129eb428 569 return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
52eb293d
JM
570 *new_ssid++ = '\0';
571
572 new_auth = os_strchr(new_ssid, ' ');
573 if (new_auth == NULL)
574 return -1;
575 *new_auth++ = '\0';
576
577 new_encr = os_strchr(new_auth, ' ');
578 if (new_encr == NULL)
579 return -1;
580 *new_encr++ = '\0';
581
582 new_key = os_strchr(new_encr, ' ');
583 if (new_key == NULL)
584 return -1;
585 *new_key++ = '\0';
586
587 os_memset(&ap, 0, sizeof(ap));
588 ap.ssid_hex = new_ssid;
589 ap.auth = new_auth;
590 ap.encr = new_encr;
591 ap.key_hex = new_key;
129eb428 592 return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
fcc60db4 593}
72df2f5f
JM
594
595
70d84f11
JM
596#ifdef CONFIG_AP
597static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
598 char *cmd, char *buf,
599 size_t buflen)
600{
601 int timeout = 300;
602 char *pos;
603 const char *pin_txt;
604
605 if (!wpa_s->ap_iface)
606 return -1;
607
608 pos = os_strchr(cmd, ' ');
609 if (pos)
610 *pos++ = '\0';
611
612 if (os_strcmp(cmd, "disable") == 0) {
613 wpas_wps_ap_pin_disable(wpa_s);
614 return os_snprintf(buf, buflen, "OK\n");
615 }
616
617 if (os_strcmp(cmd, "random") == 0) {
618 if (pos)
619 timeout = atoi(pos);
620 pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
621 if (pin_txt == NULL)
622 return -1;
623 return os_snprintf(buf, buflen, "%s", pin_txt);
624 }
625
626 if (os_strcmp(cmd, "get") == 0) {
627 pin_txt = wpas_wps_ap_pin_get(wpa_s);
628 if (pin_txt == NULL)
629 return -1;
630 return os_snprintf(buf, buflen, "%s", pin_txt);
631 }
632
633 if (os_strcmp(cmd, "set") == 0) {
634 char *pin;
635 if (pos == NULL)
636 return -1;
637 pin = pos;
638 pos = os_strchr(pos, ' ');
639 if (pos) {
640 *pos++ = '\0';
641 timeout = atoi(pos);
642 }
643 if (os_strlen(pin) > buflen)
644 return -1;
645 if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
646 return -1;
647 return os_snprintf(buf, buflen, "%s", pin);
648 }
649
650 return -1;
651}
652#endif /* CONFIG_AP */
653
654
72df2f5f
JM
655#ifdef CONFIG_WPS_ER
656static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
657 char *cmd)
658{
31fcea93
JM
659 char *uuid = cmd, *pin, *pos;
660 u8 addr_buf[ETH_ALEN], *addr = NULL;
72df2f5f
JM
661 pin = os_strchr(uuid, ' ');
662 if (pin == NULL)
663 return -1;
664 *pin++ = '\0';
31fcea93
JM
665 pos = os_strchr(pin, ' ');
666 if (pos) {
667 *pos++ = '\0';
668 if (hwaddr_aton(pos, addr_buf) == 0)
669 addr = addr_buf;
670 }
671 return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
72df2f5f 672}
e64dcfd5
JM
673
674
675static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
676 char *cmd)
677{
678 char *uuid = cmd, *pin;
679 pin = os_strchr(uuid, ' ');
680 if (pin == NULL)
681 return -1;
682 *pin++ = '\0';
683 return wpas_wps_er_learn(wpa_s, uuid, pin);
684}
7d6640a6
JM
685
686
ef10f473
JM
687static int wpa_supplicant_ctrl_iface_wps_er_set_config(
688 struct wpa_supplicant *wpa_s, char *cmd)
689{
690 char *uuid = cmd, *id;
691 id = os_strchr(uuid, ' ');
692 if (id == NULL)
693 return -1;
694 *id++ = '\0';
695 return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
696}
697
698
7d6640a6
JM
699static int wpa_supplicant_ctrl_iface_wps_er_config(
700 struct wpa_supplicant *wpa_s, char *cmd)
701{
702 char *pin;
703 char *new_ssid;
704 char *new_auth;
705 char *new_encr;
706 char *new_key;
707 struct wps_new_ap_settings ap;
708
709 pin = os_strchr(cmd, ' ');
710 if (pin == NULL)
711 return -1;
712 *pin++ = '\0';
713
714 new_ssid = os_strchr(pin, ' ');
715 if (new_ssid == NULL)
716 return -1;
717 *new_ssid++ = '\0';
718
719 new_auth = os_strchr(new_ssid, ' ');
720 if (new_auth == NULL)
721 return -1;
722 *new_auth++ = '\0';
723
724 new_encr = os_strchr(new_auth, ' ');
725 if (new_encr == NULL)
726 return -1;
727 *new_encr++ = '\0';
728
729 new_key = os_strchr(new_encr, ' ');
730 if (new_key == NULL)
731 return -1;
732 *new_key++ = '\0';
733
734 os_memset(&ap, 0, sizeof(ap));
735 ap.ssid_hex = new_ssid;
736 ap.auth = new_auth;
737 ap.encr = new_encr;
738 ap.key_hex = new_key;
739 return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
740}
72df2f5f
JM
741#endif /* CONFIG_WPS_ER */
742
fcc60db4
JM
743#endif /* CONFIG_WPS */
744
745
11ef8d35
JM
746#ifdef CONFIG_IBSS_RSN
747static int wpa_supplicant_ctrl_iface_ibss_rsn(
748 struct wpa_supplicant *wpa_s, char *addr)
749{
750 u8 peer[ETH_ALEN];
751
752 if (hwaddr_aton(addr, peer)) {
753 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
a7b6c422 754 "address '%s'", addr);
11ef8d35
JM
755 return -1;
756 }
757
758 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
759 MAC2STR(peer));
760
761 return ibss_rsn_start(wpa_s->ibss_rsn, peer);
762}
763#endif /* CONFIG_IBSS_RSN */
764
765
7de5688d
DW
766int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
767 struct wpa_ssid *ssid,
768 const char *field,
769 const char *value)
6fc6879b 770{
7de5688d 771 struct eap_peer_config *eap = &ssid->eap;
6fc6879b 772
7de5688d
DW
773 wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
774 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
775 (const u8 *) value, os_strlen(value));
6fc6879b 776
7de5688d
DW
777 switch (wpa_supplicant_ctrl_req_from_string(field)) {
778 case WPA_CTRL_REQ_EAP_IDENTITY:
6fc6879b 779 os_free(eap->identity);
7de5688d
DW
780 eap->identity = (u8 *) os_strdup(value);
781 eap->identity_len = os_strlen(value);
6fc6879b
JM
782 eap->pending_req_identity = 0;
783 if (ssid == wpa_s->current_ssid)
784 wpa_s->reassociate = 1;
7de5688d
DW
785 break;
786 case WPA_CTRL_REQ_EAP_PASSWORD:
6fc6879b 787 os_free(eap->password);
7de5688d
DW
788 eap->password = (u8 *) os_strdup(value);
789 eap->password_len = os_strlen(value);
6fc6879b
JM
790 eap->pending_req_password = 0;
791 if (ssid == wpa_s->current_ssid)
792 wpa_s->reassociate = 1;
7de5688d
DW
793 break;
794 case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
6fc6879b 795 os_free(eap->new_password);
7de5688d
DW
796 eap->new_password = (u8 *) os_strdup(value);
797 eap->new_password_len = os_strlen(value);
6fc6879b
JM
798 eap->pending_req_new_password = 0;
799 if (ssid == wpa_s->current_ssid)
800 wpa_s->reassociate = 1;
7de5688d
DW
801 break;
802 case WPA_CTRL_REQ_EAP_PIN:
6fc6879b 803 os_free(eap->pin);
7de5688d 804 eap->pin = os_strdup(value);
6fc6879b
JM
805 eap->pending_req_pin = 0;
806 if (ssid == wpa_s->current_ssid)
807 wpa_s->reassociate = 1;
7de5688d
DW
808 break;
809 case WPA_CTRL_REQ_EAP_OTP:
6fc6879b 810 os_free(eap->otp);
7de5688d
DW
811 eap->otp = (u8 *) os_strdup(value);
812 eap->otp_len = os_strlen(value);
6fc6879b
JM
813 os_free(eap->pending_req_otp);
814 eap->pending_req_otp = NULL;
815 eap->pending_req_otp_len = 0;
7de5688d
DW
816 break;
817 case WPA_CTRL_REQ_EAP_PASSPHRASE:
6fc6879b 818 os_free(eap->private_key_passwd);
7de5688d 819 eap->private_key_passwd = (u8 *) os_strdup(value);
6fc6879b
JM
820 eap->pending_req_passphrase = 0;
821 if (ssid == wpa_s->current_ssid)
822 wpa_s->reassociate = 1;
7de5688d
DW
823 break;
824 default:
825 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
6fc6879b
JM
826 return -1;
827 }
828
829 return 0;
7de5688d
DW
830}
831
832
833static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
834 char *rsp)
835{
836#ifdef IEEE8021X_EAPOL
837 char *pos, *id_pos;
838 int id;
839 struct wpa_ssid *ssid;
840
841 pos = os_strchr(rsp, '-');
842 if (pos == NULL)
843 return -1;
844 *pos++ = '\0';
845 id_pos = pos;
846 pos = os_strchr(pos, ':');
847 if (pos == NULL)
848 return -1;
849 *pos++ = '\0';
850 id = atoi(id_pos);
851 wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
852 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
853 (u8 *) pos, os_strlen(pos));
854
855 ssid = wpa_config_get_network(wpa_s->conf, id);
856 if (ssid == NULL) {
857 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
858 "to update", id);
859 return -1;
860 }
861
862 return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
863 pos);
6fc6879b
JM
864#else /* IEEE8021X_EAPOL */
865 wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
866 return -1;
867#endif /* IEEE8021X_EAPOL */
868}
869
870
871static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
872 const char *params,
873 char *buf, size_t buflen)
874{
875 char *pos, *end, tmp[30];
876 int res, verbose, ret;
877
878 verbose = os_strcmp(params, "-VERBOSE") == 0;
879 pos = buf;
880 end = buf + buflen;
881 if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
882 struct wpa_ssid *ssid = wpa_s->current_ssid;
883 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
884 MAC2STR(wpa_s->bssid));
885 if (ret < 0 || ret >= end - pos)
886 return pos - buf;
887 pos += ret;
888 if (ssid) {
889 u8 *_ssid = ssid->ssid;
890 size_t ssid_len = ssid->ssid_len;
891 u8 ssid_buf[MAX_SSID_LEN];
892 if (ssid_len == 0) {
893 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
894 if (_res < 0)
895 ssid_len = 0;
896 else
897 ssid_len = _res;
898 _ssid = ssid_buf;
899 }
900 ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
901 wpa_ssid_txt(_ssid, ssid_len),
902 ssid->id);
903 if (ret < 0 || ret >= end - pos)
904 return pos - buf;
905 pos += ret;
906
907 if (ssid->id_str) {
908 ret = os_snprintf(pos, end - pos,
909 "id_str=%s\n",
910 ssid->id_str);
911 if (ret < 0 || ret >= end - pos)
912 return pos - buf;
913 pos += ret;
914 }
0e15e529
JM
915
916 switch (ssid->mode) {
d7dcba70 917 case WPAS_MODE_INFRA:
0e15e529
JM
918 ret = os_snprintf(pos, end - pos,
919 "mode=station\n");
920 break;
d7dcba70 921 case WPAS_MODE_IBSS:
0e15e529
JM
922 ret = os_snprintf(pos, end - pos,
923 "mode=IBSS\n");
924 break;
d7dcba70 925 case WPAS_MODE_AP:
0e15e529
JM
926 ret = os_snprintf(pos, end - pos,
927 "mode=AP\n");
928 break;
2c5d725c
JM
929 case WPAS_MODE_P2P_GO:
930 ret = os_snprintf(pos, end - pos,
931 "mode=P2P GO\n");
932 break;
933 case WPAS_MODE_P2P_GROUP_FORMATION:
934 ret = os_snprintf(pos, end - pos,
935 "mode=P2P GO - group "
936 "formation\n");
937 break;
0e15e529
JM
938 default:
939 ret = 0;
940 break;
941 }
942 if (ret < 0 || ret >= end - pos)
943 return pos - buf;
944 pos += ret;
6fc6879b
JM
945 }
946
43fb5297
JM
947#ifdef CONFIG_AP
948 if (wpa_s->ap_iface) {
949 pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
950 end - pos,
951 verbose);
952 } else
953#endif /* CONFIG_AP */
6fc6879b
JM
954 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
955 }
956 ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
957 wpa_supplicant_state_txt(wpa_s->wpa_state));
958 if (ret < 0 || ret >= end - pos)
959 return pos - buf;
960 pos += ret;
961
962 if (wpa_s->l2 &&
963 l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
964 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
965 if (ret < 0 || ret >= end - pos)
966 return pos - buf;
967 pos += ret;
968 }
969
d23bd894
JM
970#ifdef CONFIG_P2P
971 if (wpa_s->global->p2p) {
972 ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
973 "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
974 if (ret < 0 || ret >= end - pos)
975 return pos - buf;
976 pos += ret;
977 }
b21e2c84 978#endif /* CONFIG_P2P */
6d4747a9
JM
979
980 ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
981 MAC2STR(wpa_s->own_addr));
982 if (ret < 0 || ret >= end - pos)
983 return pos - buf;
984 pos += ret;
d23bd894 985
56586197
JM
986 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
987 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
6fc6879b
JM
988 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
989 verbose);
990 if (res >= 0)
991 pos += res;
992 }
993
994 res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
995 if (res >= 0)
996 pos += res;
997
998 return pos - buf;
999}
1000
1001
1002static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
1003 char *cmd)
1004{
1005 char *pos;
1006 int id;
1007 struct wpa_ssid *ssid;
1008 u8 bssid[ETH_ALEN];
1009
1010 /* cmd: "<network id> <BSSID>" */
1011 pos = os_strchr(cmd, ' ');
1012 if (pos == NULL)
1013 return -1;
1014 *pos++ = '\0';
1015 id = atoi(cmd);
1016 wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
1017 if (hwaddr_aton(pos, bssid)) {
1018 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
1019 return -1;
1020 }
1021
1022 ssid = wpa_config_get_network(wpa_s->conf, id);
1023 if (ssid == NULL) {
1024 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1025 "to update", id);
1026 return -1;
1027 }
1028
1029 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
a8e16edc 1030 ssid->bssid_set = !is_zero_ether_addr(bssid);
6fc6879b
JM
1031
1032 return 0;
1033}
1034
1035
9aa10e2b
DS
1036static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
1037 char *cmd, char *buf,
1038 size_t buflen)
1039{
1040 u8 bssid[ETH_ALEN];
1041 struct wpa_blacklist *e;
1042 char *pos, *end;
1043 int ret;
1044
1045 /* cmd: "BLACKLIST [<BSSID>]" */
1046 if (*cmd == '\0') {
1047 pos = buf;
1048 end = buf + buflen;
1049 e = wpa_s->blacklist;
1050 while (e) {
1051 ret = os_snprintf(pos, end - pos, MACSTR "\n",
1052 MAC2STR(e->bssid));
1053 if (ret < 0 || ret >= end - pos)
1054 return pos - buf;
1055 pos += ret;
1056 e = e->next;
1057 }
1058 return pos - buf;
1059 }
1060
1061 cmd++;
1062 if (os_strncmp(cmd, "clear", 5) == 0) {
1063 wpa_blacklist_clear(wpa_s);
1064 os_memcpy(buf, "OK\n", 3);
1065 return 3;
1066 }
1067
1068 wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
1069 if (hwaddr_aton(cmd, bssid)) {
1070 wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
1071 return -1;
1072 }
1073
1074 /*
1075 * Add the BSSID twice, so its count will be 2, causing it to be
1076 * skipped when processing scan results.
1077 */
1078 ret = wpa_blacklist_add(wpa_s, bssid);
1079 if (ret != 0)
1080 return -1;
1081 ret = wpa_blacklist_add(wpa_s, bssid);
1082 if (ret != 0)
1083 return -1;
1084 os_memcpy(buf, "OK\n", 3);
1085 return 3;
1086}
1087
1088
0597a5b5
DS
1089extern int wpa_debug_level;
1090extern int wpa_debug_timestamp;
1091
1092static const char * debug_level_str(int level)
1093{
1094 switch (level) {
1095 case MSG_EXCESSIVE:
1096 return "EXCESSIVE";
1097 case MSG_MSGDUMP:
1098 return "MSGDUMP";
1099 case MSG_DEBUG:
1100 return "DEBUG";
1101 case MSG_INFO:
1102 return "INFO";
1103 case MSG_WARNING:
1104 return "WARNING";
1105 case MSG_ERROR:
1106 return "ERROR";
1107 default:
1108 return "?";
1109 }
1110}
1111
1112
1113static int str_to_debug_level(const char *s)
1114{
1115 if (os_strcasecmp(s, "EXCESSIVE") == 0)
1116 return MSG_EXCESSIVE;
1117 if (os_strcasecmp(s, "MSGDUMP") == 0)
1118 return MSG_MSGDUMP;
1119 if (os_strcasecmp(s, "DEBUG") == 0)
1120 return MSG_DEBUG;
1121 if (os_strcasecmp(s, "INFO") == 0)
1122 return MSG_INFO;
1123 if (os_strcasecmp(s, "WARNING") == 0)
1124 return MSG_WARNING;
1125 if (os_strcasecmp(s, "ERROR") == 0)
1126 return MSG_ERROR;
1127 return -1;
1128}
1129
1130
1131static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
1132 char *cmd, char *buf,
1133 size_t buflen)
1134{
1135 char *pos, *end, *stamp;
1136 int ret;
1137
1138 if (cmd == NULL) {
1139 return -1;
1140 }
1141
1142 /* cmd: "LOG_LEVEL [<level>]" */
1143 if (*cmd == '\0') {
1144 pos = buf;
1145 end = buf + buflen;
1146 ret = os_snprintf(pos, end - pos, "Current level: %s\n"
1147 "Timestamp: %d\n",
1148 debug_level_str(wpa_debug_level),
1149 wpa_debug_timestamp);
1150 if (ret < 0 || ret >= end - pos)
1151 ret = 0;
1152
1153 return ret;
1154 }
1155
1156 while (*cmd == ' ')
1157 cmd++;
1158
1159 stamp = os_strchr(cmd, ' ');
1160 if (stamp) {
1161 *stamp++ = '\0';
1162 while (*stamp == ' ') {
1163 stamp++;
1164 }
1165 }
1166
1167 if (cmd && os_strlen(cmd)) {
1168 int level = str_to_debug_level(cmd);
1169 if (level < 0)
1170 return -1;
1171 wpa_debug_level = level;
1172 }
1173
1174 if (stamp && os_strlen(stamp))
1175 wpa_debug_timestamp = atoi(stamp);
1176
1177 os_memcpy(buf, "OK\n", 3);
1178 return 3;
1179}
1180
1181
6fc6879b
JM
1182static int wpa_supplicant_ctrl_iface_list_networks(
1183 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1184{
1185 char *pos, *end;
1186 struct wpa_ssid *ssid;
1187 int ret;
1188
1189 pos = buf;
1190 end = buf + buflen;
1191 ret = os_snprintf(pos, end - pos,
1192 "network id / ssid / bssid / flags\n");
1193 if (ret < 0 || ret >= end - pos)
1194 return pos - buf;
1195 pos += ret;
1196
1197 ssid = wpa_s->conf->ssid;
1198 while (ssid) {
1199 ret = os_snprintf(pos, end - pos, "%d\t%s",
1200 ssid->id,
1201 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
1202 if (ret < 0 || ret >= end - pos)
1203 return pos - buf;
1204 pos += ret;
1205 if (ssid->bssid_set) {
1206 ret = os_snprintf(pos, end - pos, "\t" MACSTR,
1207 MAC2STR(ssid->bssid));
1208 } else {
1209 ret = os_snprintf(pos, end - pos, "\tany");
1210 }
1211 if (ret < 0 || ret >= end - pos)
1212 return pos - buf;
1213 pos += ret;
4dac0245 1214 ret = os_snprintf(pos, end - pos, "\t%s%s%s",
6fc6879b
JM
1215 ssid == wpa_s->current_ssid ?
1216 "[CURRENT]" : "",
4dac0245
JM
1217 ssid->disabled ? "[DISABLED]" : "",
1218 ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
1219 "");
6fc6879b
JM
1220 if (ret < 0 || ret >= end - pos)
1221 return pos - buf;
1222 pos += ret;
1223 ret = os_snprintf(pos, end - pos, "\n");
1224 if (ret < 0 || ret >= end - pos)
1225 return pos - buf;
1226 pos += ret;
1227
1228 ssid = ssid->next;
1229 }
1230
1231 return pos - buf;
1232}
1233
1234
1235static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
1236{
1237 int first = 1, ret;
1238 ret = os_snprintf(pos, end - pos, "-");
1239 if (ret < 0 || ret >= end - pos)
1240 return pos;
1241 pos += ret;
1242 if (cipher & WPA_CIPHER_NONE) {
1243 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
1244 if (ret < 0 || ret >= end - pos)
1245 return pos;
1246 pos += ret;
1247 first = 0;
1248 }
1249 if (cipher & WPA_CIPHER_WEP40) {
1250 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
1251 if (ret < 0 || ret >= end - pos)
1252 return pos;
1253 pos += ret;
1254 first = 0;
1255 }
1256 if (cipher & WPA_CIPHER_WEP104) {
1257 ret = os_snprintf(pos, end - pos, "%sWEP104",
1258 first ? "" : "+");
1259 if (ret < 0 || ret >= end - pos)
1260 return pos;
1261 pos += ret;
1262 first = 0;
1263 }
1264 if (cipher & WPA_CIPHER_TKIP) {
1265 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
1266 if (ret < 0 || ret >= end - pos)
1267 return pos;
1268 pos += ret;
1269 first = 0;
1270 }
1271 if (cipher & WPA_CIPHER_CCMP) {
1272 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
1273 if (ret < 0 || ret >= end - pos)
1274 return pos;
1275 pos += ret;
1276 first = 0;
1277 }
1278 return pos;
1279}
1280
1281
1282static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
1283 const u8 *ie, size_t ie_len)
1284{
1285 struct wpa_ie_data data;
1286 int first, ret;
1287
1288 ret = os_snprintf(pos, end - pos, "[%s-", proto);
1289 if (ret < 0 || ret >= end - pos)
1290 return pos;
1291 pos += ret;
1292
1293 if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
1294 ret = os_snprintf(pos, end - pos, "?]");
1295 if (ret < 0 || ret >= end - pos)
1296 return pos;
1297 pos += ret;
1298 return pos;
1299 }
1300
1301 first = 1;
1302 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
1303 ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
1304 if (ret < 0 || ret >= end - pos)
1305 return pos;
1306 pos += ret;
1307 first = 0;
1308 }
1309 if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
1310 ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
1311 if (ret < 0 || ret >= end - pos)
1312 return pos;
1313 pos += ret;
1314 first = 0;
1315 }
1316 if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
1317 ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
1318 if (ret < 0 || ret >= end - pos)
1319 return pos;
1320 pos += ret;
1321 first = 0;
1322 }
1323#ifdef CONFIG_IEEE80211R
1324 if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
1325 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
1326 first ? "" : "+");
1327 if (ret < 0 || ret >= end - pos)
1328 return pos;
1329 pos += ret;
1330 first = 0;
1331 }
1332 if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
1333 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
1334 first ? "" : "+");
1335 if (ret < 0 || ret >= end - pos)
1336 return pos;
1337 pos += ret;
1338 first = 0;
1339 }
1340#endif /* CONFIG_IEEE80211R */
56586197
JM
1341#ifdef CONFIG_IEEE80211W
1342 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
1343 ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
1344 first ? "" : "+");
1345 if (ret < 0 || ret >= end - pos)
1346 return pos;
1347 pos += ret;
1348 first = 0;
1349 }
1350 if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
1351 ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
1352 first ? "" : "+");
1353 if (ret < 0 || ret >= end - pos)
1354 return pos;
1355 pos += ret;
1356 first = 0;
1357 }
1358#endif /* CONFIG_IEEE80211W */
6fc6879b
JM
1359
1360 pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
1361
1362 if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
1363 ret = os_snprintf(pos, end - pos, "-preauth");
1364 if (ret < 0 || ret >= end - pos)
1365 return pos;
1366 pos += ret;
1367 }
1368
1369 ret = os_snprintf(pos, end - pos, "]");
1370 if (ret < 0 || ret >= end - pos)
1371 return pos;
1372 pos += ret;
1373
1374 return pos;
1375}
1376
3a068632 1377
eef7d7a1 1378#ifdef CONFIG_WPS
31fcea93
JM
1379static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
1380 char *pos, char *end,
3a068632
JM
1381 struct wpabuf *wps_ie)
1382{
eef7d7a1
JM
1383 int ret;
1384 const char *txt;
1385
eef7d7a1
JM
1386 if (wps_ie == NULL)
1387 return pos;
eef7d7a1
JM
1388 if (wps_is_selected_pbc_registrar(wps_ie))
1389 txt = "[WPS-PBC]";
53587ec1 1390#ifdef CONFIG_WPS2
31fcea93
JM
1391 else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
1392 txt = "[WPS-AUTH]";
53587ec1 1393#endif /* CONFIG_WPS2 */
eef7d7a1
JM
1394 else if (wps_is_selected_pin_registrar(wps_ie))
1395 txt = "[WPS-PIN]";
1396 else
1397 txt = "[WPS]";
1398
1399 ret = os_snprintf(pos, end - pos, "%s", txt);
1400 if (ret >= 0 && ret < end - pos)
1401 pos += ret;
1402 wpabuf_free(wps_ie);
3a068632
JM
1403 return pos;
1404}
1405#endif /* CONFIG_WPS */
1406
1407
31fcea93
JM
1408static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
1409 char *pos, char *end,
16b71ac2 1410 const struct wpa_bss *bss)
3a068632
JM
1411{
1412#ifdef CONFIG_WPS
1413 struct wpabuf *wps_ie;
1414 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
31fcea93 1415 return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
3a068632 1416#else /* CONFIG_WPS */
eef7d7a1 1417 return pos;
3a068632 1418#endif /* CONFIG_WPS */
eef7d7a1
JM
1419}
1420
6fc6879b
JM
1421
1422/* Format one result on one text line into a buffer. */
1423static int wpa_supplicant_ctrl_iface_scan_result(
31fcea93 1424 struct wpa_supplicant *wpa_s,
16b71ac2 1425 const struct wpa_bss *bss, char *buf, size_t buflen)
6fc6879b
JM
1426{
1427 char *pos, *end;
1428 int ret;
0c6b310e
JM
1429 const u8 *ie, *ie2, *p2p;
1430
1431 p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
1432 if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
1433 os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
1434 0)
1435 return 0; /* Do not show P2P listen discovery results here */
6fc6879b
JM
1436
1437 pos = buf;
1438 end = buf + buflen;
1439
1440 ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
16b71ac2 1441 MAC2STR(bss->bssid), bss->freq, bss->level);
6fc6879b 1442 if (ret < 0 || ret >= end - pos)
fb0e5bd7 1443 return -1;
6fc6879b 1444 pos += ret;
16b71ac2 1445 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
6fc6879b
JM
1446 if (ie)
1447 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
16b71ac2 1448 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
6fc6879b
JM
1449 if (ie2)
1450 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
31fcea93 1451 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
16b71ac2 1452 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
6fc6879b
JM
1453 ret = os_snprintf(pos, end - pos, "[WEP]");
1454 if (ret < 0 || ret >= end - pos)
fb0e5bd7 1455 return -1;
6fc6879b
JM
1456 pos += ret;
1457 }
16b71ac2 1458 if (bss->caps & IEEE80211_CAP_IBSS) {
6fc6879b
JM
1459 ret = os_snprintf(pos, end - pos, "[IBSS]");
1460 if (ret < 0 || ret >= end - pos)
fb0e5bd7 1461 return -1;
6fc6879b
JM
1462 pos += ret;
1463 }
16b71ac2 1464 if (bss->caps & IEEE80211_CAP_ESS) {
bd1af96a
JM
1465 ret = os_snprintf(pos, end - pos, "[ESS]");
1466 if (ret < 0 || ret >= end - pos)
fb0e5bd7 1467 return -1;
bd1af96a
JM
1468 pos += ret;
1469 }
0c6b310e
JM
1470 if (p2p) {
1471 ret = os_snprintf(pos, end - pos, "[P2P]");
1472 if (ret < 0 || ret >= end - pos)
fb0e5bd7 1473 return -1;
0c6b310e
JM
1474 pos += ret;
1475 }
6fc6879b 1476
6fc6879b 1477 ret = os_snprintf(pos, end - pos, "\t%s",
16b71ac2 1478 wpa_ssid_txt(bss->ssid, bss->ssid_len));
6fc6879b 1479 if (ret < 0 || ret >= end - pos)
fb0e5bd7 1480 return -1;
6fc6879b
JM
1481 pos += ret;
1482
1483 ret = os_snprintf(pos, end - pos, "\n");
1484 if (ret < 0 || ret >= end - pos)
fb0e5bd7 1485 return -1;
6fc6879b
JM
1486 pos += ret;
1487
1488 return pos - buf;
1489}
1490
1491
1492static int wpa_supplicant_ctrl_iface_scan_results(
1493 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1494{
1495 char *pos, *end;
16b71ac2 1496 struct wpa_bss *bss;
6fc6879b 1497 int ret;
6fc6879b
JM
1498
1499 pos = buf;
1500 end = buf + buflen;
1501 ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
1502 "flags / ssid\n");
1503 if (ret < 0 || ret >= end - pos)
1504 return pos - buf;
1505 pos += ret;
1506
16b71ac2 1507 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
31fcea93 1508 ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
6fc6879b
JM
1509 end - pos);
1510 if (ret < 0 || ret >= end - pos)
1511 return pos - buf;
1512 pos += ret;
1513 }
1514
1515 return pos - buf;
1516}
1517
1518
1519static int wpa_supplicant_ctrl_iface_select_network(
1520 struct wpa_supplicant *wpa_s, char *cmd)
1521{
1522 int id;
1523 struct wpa_ssid *ssid;
1524
1525 /* cmd: "<network id>" or "any" */
1526 if (os_strcmp(cmd, "any") == 0) {
1527 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
86b89452
WS
1528 ssid = NULL;
1529 } else {
1530 id = atoi(cmd);
1531 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
6fc6879b 1532
86b89452
WS
1533 ssid = wpa_config_get_network(wpa_s->conf, id);
1534 if (ssid == NULL) {
1535 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
1536 "network id=%d", id);
1537 return -1;
1538 }
4dac0245
JM
1539 if (ssid->disabled == 2) {
1540 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
1541 "SELECT_NETWORK with persistent P2P group");
1542 return -1;
1543 }
6fc6879b
JM
1544 }
1545
86b89452 1546 wpa_supplicant_select_network(wpa_s, ssid);
6fc6879b
JM
1547
1548 return 0;
1549}
1550
1551
1552static int wpa_supplicant_ctrl_iface_enable_network(
1553 struct wpa_supplicant *wpa_s, char *cmd)
1554{
1555 int id;
1556 struct wpa_ssid *ssid;
1557
1558 /* cmd: "<network id>" or "all" */
1559 if (os_strcmp(cmd, "all") == 0) {
1560 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
86b89452
WS
1561 ssid = NULL;
1562 } else {
1563 id = atoi(cmd);
1564 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
6fc6879b 1565
86b89452
WS
1566 ssid = wpa_config_get_network(wpa_s->conf, id);
1567 if (ssid == NULL) {
1568 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
1569 "network id=%d", id);
1570 return -1;
1571 }
4dac0245
JM
1572 if (ssid->disabled == 2) {
1573 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
1574 "ENABLE_NETWORK with persistent P2P group");
1575 return -1;
1576 }
6fc6879b 1577 }
86b89452 1578 wpa_supplicant_enable_network(wpa_s, ssid);
6fc6879b
JM
1579
1580 return 0;
1581}
1582
1583
1584static int wpa_supplicant_ctrl_iface_disable_network(
1585 struct wpa_supplicant *wpa_s, char *cmd)
1586{
1587 int id;
1588 struct wpa_ssid *ssid;
1589
1590 /* cmd: "<network id>" or "all" */
1591 if (os_strcmp(cmd, "all") == 0) {
1592 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
86b89452
WS
1593 ssid = NULL;
1594 } else {
1595 id = atoi(cmd);
1596 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
6fc6879b 1597
86b89452
WS
1598 ssid = wpa_config_get_network(wpa_s->conf, id);
1599 if (ssid == NULL) {
1600 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
1601 "network id=%d", id);
1602 return -1;
1603 }
4dac0245
JM
1604 if (ssid->disabled == 2) {
1605 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
1606 "DISABLE_NETWORK with persistent P2P "
1607 "group");
1608 return -1;
1609 }
6fc6879b 1610 }
86b89452 1611 wpa_supplicant_disable_network(wpa_s, ssid);
6fc6879b
JM
1612
1613 return 0;
1614}
1615
1616
1617static int wpa_supplicant_ctrl_iface_add_network(
1618 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1619{
1620 struct wpa_ssid *ssid;
1621 int ret;
1622
1623 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
1624
1625 ssid = wpa_config_add_network(wpa_s->conf);
1626 if (ssid == NULL)
1627 return -1;
8bac466b
JM
1628
1629 wpas_notify_network_added(wpa_s, ssid);
1630
6fc6879b
JM
1631 ssid->disabled = 1;
1632 wpa_config_set_network_defaults(ssid);
1633
1634 ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
1635 if (ret < 0 || (size_t) ret >= buflen)
1636 return -1;
1637 return ret;
1638}
1639
1640
1641static int wpa_supplicant_ctrl_iface_remove_network(
1642 struct wpa_supplicant *wpa_s, char *cmd)
1643{
1644 int id;
1645 struct wpa_ssid *ssid;
1646
1647 /* cmd: "<network id>" or "all" */
1648 if (os_strcmp(cmd, "all") == 0) {
1649 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
1650 ssid = wpa_s->conf->ssid;
1651 while (ssid) {
8bac466b 1652 struct wpa_ssid *remove_ssid = ssid;
6fc6879b
JM
1653 id = ssid->id;
1654 ssid = ssid->next;
8bac466b 1655 wpas_notify_network_removed(wpa_s, remove_ssid);
6fc6879b
JM
1656 wpa_config_remove_network(wpa_s->conf, id);
1657 }
d8a790b9 1658 eapol_sm_invalidate_cached_session(wpa_s->eapol);
6fc6879b 1659 if (wpa_s->current_ssid) {
20a0b03d
JM
1660 wpa_sm_set_config(wpa_s->wpa, NULL);
1661 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
6fc6879b
JM
1662 wpa_supplicant_disassociate(wpa_s,
1663 WLAN_REASON_DEAUTH_LEAVING);
1664 }
1665 return 0;
1666 }
1667
1668 id = atoi(cmd);
1669 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
1670
1671 ssid = wpa_config_get_network(wpa_s->conf, id);
f3857c2e
JM
1672 if (ssid)
1673 wpas_notify_network_removed(wpa_s, ssid);
6fc6879b
JM
1674 if (ssid == NULL ||
1675 wpa_config_remove_network(wpa_s->conf, id) < 0) {
1676 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1677 "id=%d", id);
1678 return -1;
1679 }
1680
d8a790b9 1681 if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
6fc6879b 1682 /*
d8a790b9
JM
1683 * Invalidate the EAP session cache if the current or
1684 * previously used network is removed.
6fc6879b
JM
1685 */
1686 eapol_sm_invalidate_cached_session(wpa_s->eapol);
d8a790b9
JM
1687 }
1688
1689 if (ssid == wpa_s->current_ssid) {
20a0b03d
JM
1690 wpa_sm_set_config(wpa_s->wpa, NULL);
1691 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
6fc6879b
JM
1692
1693 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1694 }
1695
1696 return 0;
1697}
1698
1699
1700static int wpa_supplicant_ctrl_iface_set_network(
1701 struct wpa_supplicant *wpa_s, char *cmd)
1702{
1703 int id;
1704 struct wpa_ssid *ssid;
1705 char *name, *value;
1706
1707 /* cmd: "<network id> <variable name> <value>" */
1708 name = os_strchr(cmd, ' ');
1709 if (name == NULL)
1710 return -1;
1711 *name++ = '\0';
1712
1713 value = os_strchr(name, ' ');
1714 if (value == NULL)
1715 return -1;
1716 *value++ = '\0';
1717
1718 id = atoi(cmd);
1719 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
1720 id, name);
1721 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1722 (u8 *) value, os_strlen(value));
1723
1724 ssid = wpa_config_get_network(wpa_s->conf, id);
1725 if (ssid == NULL) {
1726 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1727 "id=%d", id);
1728 return -1;
1729 }
1730
1731 if (wpa_config_set(ssid, name, value, 0) < 0) {
1732 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
1733 "variable '%s'", name);
1734 return -1;
1735 }
1736
d8a790b9
JM
1737 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
1738
1739 if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
6fc6879b
JM
1740 /*
1741 * Invalidate the EAP session cache if anything in the current
d8a790b9 1742 * or previously used configuration changes.
6fc6879b
JM
1743 */
1744 eapol_sm_invalidate_cached_session(wpa_s->eapol);
1745 }
1746
1747 if ((os_strcmp(name, "psk") == 0 &&
1748 value[0] == '"' && ssid->ssid_len) ||
1749 (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
1750 wpa_config_update_psk(ssid);
aa53509f
DS
1751 else if (os_strcmp(name, "priority") == 0)
1752 wpa_config_update_prio_list(wpa_s->conf);
6fc6879b
JM
1753
1754 return 0;
1755}
1756
1757
1758static int wpa_supplicant_ctrl_iface_get_network(
1759 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
1760{
1761 int id;
1762 size_t res;
1763 struct wpa_ssid *ssid;
1764 char *name, *value;
1765
1766 /* cmd: "<network id> <variable name>" */
1767 name = os_strchr(cmd, ' ');
1768 if (name == NULL || buflen == 0)
1769 return -1;
1770 *name++ = '\0';
1771
1772 id = atoi(cmd);
1773 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
1774 id, name);
1775
1776 ssid = wpa_config_get_network(wpa_s->conf, id);
1777 if (ssid == NULL) {
1778 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1779 "id=%d", id);
1780 return -1;
1781 }
1782
1783 value = wpa_config_get_no_key(ssid, name);
1784 if (value == NULL) {
1785 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
1786 "variable '%s'", name);
1787 return -1;
1788 }
1789
1790 res = os_strlcpy(buf, value, buflen);
1791 if (res >= buflen) {
1792 os_free(value);
1793 return -1;
1794 }
1795
1796 os_free(value);
1797
1798 return res;
1799}
1800
1801
1802#ifndef CONFIG_NO_CONFIG_WRITE
1803static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
1804{
1805 int ret;
1806
1807 if (!wpa_s->conf->update_config) {
1808 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
1809 "to update configuration (update_config=0)");
1810 return -1;
1811 }
1812
1813 ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
1814 if (ret) {
1815 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
1816 "update configuration");
1817 } else {
1818 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
1819 " updated");
1820 }
1821
1822 return ret;
1823}
1824#endif /* CONFIG_NO_CONFIG_WRITE */
1825
1826
1827static int ctrl_iface_get_capability_pairwise(int res, char *strict,
1828 struct wpa_driver_capa *capa,
1829 char *buf, size_t buflen)
1830{
1831 int ret, first = 1;
1832 char *pos, *end;
1833 size_t len;
1834
1835 pos = buf;
1836 end = pos + buflen;
1837
1838 if (res < 0) {
1839 if (strict)
1840 return 0;
1841 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
1842 if (len >= buflen)
1843 return -1;
1844 return len;
1845 }
1846
1847 if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
1848 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
1849 if (ret < 0 || ret >= end - pos)
1850 return pos - buf;
1851 pos += ret;
1852 first = 0;
1853 }
1854
1855 if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
1856 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
1857 if (ret < 0 || ret >= end - pos)
1858 return pos - buf;
1859 pos += ret;
1860 first = 0;
1861 }
1862
1863 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1864 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
1865 if (ret < 0 || ret >= end - pos)
1866 return pos - buf;
1867 pos += ret;
1868 first = 0;
1869 }
1870
1871 return pos - buf;
1872}
1873
1874
1875static int ctrl_iface_get_capability_group(int res, char *strict,
1876 struct wpa_driver_capa *capa,
1877 char *buf, size_t buflen)
1878{
1879 int ret, first = 1;
1880 char *pos, *end;
1881 size_t len;
1882
1883 pos = buf;
1884 end = pos + buflen;
1885
1886 if (res < 0) {
1887 if (strict)
1888 return 0;
1889 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
1890 if (len >= buflen)
1891 return -1;
1892 return len;
1893 }
1894
1895 if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
1896 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
1897 if (ret < 0 || ret >= end - pos)
1898 return pos - buf;
1899 pos += ret;
1900 first = 0;
1901 }
1902
1903 if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
1904 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
1905 if (ret < 0 || ret >= end - pos)
1906 return pos - buf;
1907 pos += ret;
1908 first = 0;
1909 }
1910
1911 if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
1912 ret = os_snprintf(pos, end - pos, "%sWEP104",
1913 first ? "" : " ");
1914 if (ret < 0 || ret >= end - pos)
1915 return pos - buf;
1916 pos += ret;
1917 first = 0;
1918 }
1919
1920 if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
1921 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
1922 if (ret < 0 || ret >= end - pos)
1923 return pos - buf;
1924 pos += ret;
1925 first = 0;
1926 }
1927
1928 return pos - buf;
1929}
1930
1931
1932static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
1933 struct wpa_driver_capa *capa,
1934 char *buf, size_t buflen)
1935{
1936 int ret;
1937 char *pos, *end;
1938 size_t len;
1939
1940 pos = buf;
1941 end = pos + buflen;
1942
1943 if (res < 0) {
1944 if (strict)
1945 return 0;
1946 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
1947 "NONE", buflen);
1948 if (len >= buflen)
1949 return -1;
1950 return len;
1951 }
1952
1953 ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
1954 if (ret < 0 || ret >= end - pos)
1955 return pos - buf;
1956 pos += ret;
1957
1958 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1959 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
1960 ret = os_snprintf(pos, end - pos, " WPA-EAP");
1961 if (ret < 0 || ret >= end - pos)
1962 return pos - buf;
1963 pos += ret;
1964 }
1965
1966 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
1967 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1968 ret = os_snprintf(pos, end - pos, " WPA-PSK");
1969 if (ret < 0 || ret >= end - pos)
1970 return pos - buf;
1971 pos += ret;
1972 }
1973
1974 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1975 ret = os_snprintf(pos, end - pos, " WPA-NONE");
1976 if (ret < 0 || ret >= end - pos)
1977 return pos - buf;
1978 pos += ret;
1979 }
1980
1981 return pos - buf;
1982}
1983
1984
1985static int ctrl_iface_get_capability_proto(int res, char *strict,
1986 struct wpa_driver_capa *capa,
1987 char *buf, size_t buflen)
1988{
1989 int ret, first = 1;
1990 char *pos, *end;
1991 size_t len;
1992
1993 pos = buf;
1994 end = pos + buflen;
1995
1996 if (res < 0) {
1997 if (strict)
1998 return 0;
1999 len = os_strlcpy(buf, "RSN WPA", buflen);
2000 if (len >= buflen)
2001 return -1;
2002 return len;
2003 }
2004
2005 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2006 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2007 ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
2008 if (ret < 0 || ret >= end - pos)
2009 return pos - buf;
2010 pos += ret;
2011 first = 0;
2012 }
2013
2014 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2015 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
2016 ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
2017 if (ret < 0 || ret >= end - pos)
2018 return pos - buf;
2019 pos += ret;
2020 first = 0;
2021 }
2022
2023 return pos - buf;
2024}
2025
2026
2027static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
2028 struct wpa_driver_capa *capa,
2029 char *buf, size_t buflen)
2030{
2031 int ret, first = 1;
2032 char *pos, *end;
2033 size_t len;
2034
2035 pos = buf;
2036 end = pos + buflen;
2037
2038 if (res < 0) {
2039 if (strict)
2040 return 0;
2041 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
2042 if (len >= buflen)
2043 return -1;
2044 return len;
2045 }
2046
2047 if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
2048 ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
2049 if (ret < 0 || ret >= end - pos)
2050 return pos - buf;
2051 pos += ret;
2052 first = 0;
2053 }
2054
2055 if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
2056 ret = os_snprintf(pos, end - pos, "%sSHARED",
2057 first ? "" : " ");
2058 if (ret < 0 || ret >= end - pos)
2059 return pos - buf;
2060 pos += ret;
2061 first = 0;
2062 }
2063
2064 if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
2065 ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
2066 if (ret < 0 || ret >= end - pos)
2067 return pos - buf;
2068 pos += ret;
2069 first = 0;
2070 }
2071
2072 return pos - buf;
2073}
2074
2075
2076static int wpa_supplicant_ctrl_iface_get_capability(
2077 struct wpa_supplicant *wpa_s, const char *_field, char *buf,
2078 size_t buflen)
2079{
2080 struct wpa_driver_capa capa;
2081 int res;
2082 char *strict;
2083 char field[30];
2084 size_t len;
2085
2086 /* Determine whether or not strict checking was requested */
2087 len = os_strlcpy(field, _field, sizeof(field));
2088 if (len >= sizeof(field))
2089 return -1;
2090 strict = os_strchr(field, ' ');
2091 if (strict != NULL) {
2092 *strict++ = '\0';
2093 if (os_strcmp(strict, "strict") != 0)
2094 return -1;
2095 }
2096
2097 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
2098 field, strict ? strict : "");
2099
2100 if (os_strcmp(field, "eap") == 0) {
2101 return eap_get_names(buf, buflen);
2102 }
2103
2104 res = wpa_drv_get_capa(wpa_s, &capa);
2105
2106 if (os_strcmp(field, "pairwise") == 0)
2107 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
2108 buf, buflen);
2109
2110 if (os_strcmp(field, "group") == 0)
2111 return ctrl_iface_get_capability_group(res, strict, &capa,
2112 buf, buflen);
2113
2114 if (os_strcmp(field, "key_mgmt") == 0)
2115 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
2116 buf, buflen);
2117
2118 if (os_strcmp(field, "proto") == 0)
2119 return ctrl_iface_get_capability_proto(res, strict, &capa,
2120 buf, buflen);
2121
2122 if (os_strcmp(field, "auth_alg") == 0)
2123 return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
2124 buf, buflen);
2125
2126 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
2127 field);
2128
2129 return -1;
2130}
2131
2132
afc064fe
JM
2133#ifdef CONFIG_INTERWORKING
2134static char * anqp_add_hex(char *pos, char *end, const char *title,
2135 struct wpabuf *data)
2136{
2137 char *start = pos;
2138 size_t i;
2139 int ret;
2140 const u8 *d;
2141
2142 if (data == NULL)
2143 return start;
2144
2145 ret = os_snprintf(pos, end - pos, "%s=", title);
2146 if (ret < 0 || ret >= end - pos)
2147 return start;
2148 pos += ret;
2149
2150 d = wpabuf_head_u8(data);
2151 for (i = 0; i < wpabuf_len(data); i++) {
2152 ret = os_snprintf(pos, end - pos, "%02x", *d++);
2153 if (ret < 0 || ret >= end - pos)
2154 return start;
2155 pos += ret;
2156 }
2157
2158 ret = os_snprintf(pos, end - pos, "\n");
2159 if (ret < 0 || ret >= end - pos)
2160 return start;
2161 pos += ret;
2162
2163 return pos;
2164}
2165#endif /* CONFIG_INTERWORKING */
2166
2167
6fc6879b
JM
2168static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
2169 const char *cmd, char *buf,
2170 size_t buflen)
2171{
2172 u8 bssid[ETH_ALEN];
2173 size_t i;
3a068632 2174 struct wpa_bss *bss;
6fc6879b
JM
2175 int ret;
2176 char *pos, *end;
2177 const u8 *ie, *ie2;
2178
3a068632
JM
2179 if (os_strcmp(cmd, "FIRST") == 0)
2180 bss = dl_list_first(&wpa_s->bss, struct wpa_bss, list);
2181 else if (os_strncmp(cmd, "ID-", 3) == 0) {
2182 i = atoi(cmd + 3);
2183 bss = wpa_bss_get_id(wpa_s, i);
2184 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
2185 i = atoi(cmd + 5);
2186 bss = wpa_bss_get_id(wpa_s, i);
2187 if (bss) {
2188 struct dl_list *next = bss->list_id.next;
2189 if (next == &wpa_s->bss_id)
2190 bss = NULL;
2191 else
2192 bss = dl_list_entry(next, struct wpa_bss,
2193 list_id);
6fc6879b 2194 }
3a068632
JM
2195 } else if (hwaddr_aton(cmd, bssid) == 0)
2196 bss = wpa_bss_get_bssid(wpa_s, bssid);
2197 else {
2198 struct wpa_bss *tmp;
6fc6879b 2199 i = atoi(cmd);
3a068632
JM
2200 bss = NULL;
2201 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
2202 {
2203 if (i-- == 0) {
2204 bss = tmp;
2205 break;
2206 }
2207 }
2208 }
6fc6879b 2209
3a068632
JM
2210 if (bss == NULL)
2211 return 0;
6fc6879b 2212
6fc6879b
JM
2213 pos = buf;
2214 end = buf + buflen;
3fd0b8f1 2215 ret = os_snprintf(pos, end - pos,
3a068632 2216 "id=%u\n"
3fd0b8f1
JM
2217 "bssid=" MACSTR "\n"
2218 "freq=%d\n"
2219 "beacon_int=%d\n"
2220 "capabilities=0x%04x\n"
2221 "qual=%d\n"
2222 "noise=%d\n"
2223 "level=%d\n"
2224 "tsf=%016llu\n"
2225 "ie=",
3a068632 2226 bss->id,
3fd0b8f1
JM
2227 MAC2STR(bss->bssid), bss->freq, bss->beacon_int,
2228 bss->caps, bss->qual, bss->noise, bss->level,
2229 (unsigned long long) bss->tsf);
6fc6879b
JM
2230 if (ret < 0 || ret >= end - pos)
2231 return pos - buf;
2232 pos += ret;
2233
2234 ie = (const u8 *) (bss + 1);
2235 for (i = 0; i < bss->ie_len; i++) {
3fd0b8f1 2236 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
6fc6879b
JM
2237 if (ret < 0 || ret >= end - pos)
2238 return pos - buf;
2239 pos += ret;
2240 }
2241
3fd0b8f1 2242 ret = os_snprintf(pos, end - pos, "\n");
6fc6879b
JM
2243 if (ret < 0 || ret >= end - pos)
2244 return pos - buf;
2245 pos += ret;
2246
2247 ret = os_snprintf(pos, end - pos, "flags=");
2248 if (ret < 0 || ret >= end - pos)
2249 return pos - buf;
2250 pos += ret;
2251
3a068632 2252 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
6fc6879b
JM
2253 if (ie)
2254 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
3a068632 2255 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
6fc6879b
JM
2256 if (ie2)
2257 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
31fcea93 2258 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
6fc6879b
JM
2259 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
2260 ret = os_snprintf(pos, end - pos, "[WEP]");
2261 if (ret < 0 || ret >= end - pos)
2262 return pos - buf;
2263 pos += ret;
2264 }
2265 if (bss->caps & IEEE80211_CAP_IBSS) {
2266 ret = os_snprintf(pos, end - pos, "[IBSS]");
2267 if (ret < 0 || ret >= end - pos)
2268 return pos - buf;
2269 pos += ret;
2270 }
bd1af96a
JM
2271 if (bss->caps & IEEE80211_CAP_ESS) {
2272 ret = os_snprintf(pos, end - pos, "[ESS]");
2273 if (ret < 0 || ret >= end - pos)
2274 return pos - buf;
2275 pos += ret;
2276 }
cc81110d
JM
2277 if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
2278 ret = os_snprintf(pos, end - pos, "[P2P]");
2279 if (ret < 0 || ret >= end - pos)
2280 return pos - buf;
2281 pos += ret;
2282 }
6fc6879b 2283
3fd0b8f1 2284 ret = os_snprintf(pos, end - pos, "\n");
6fc6879b
JM
2285 if (ret < 0 || ret >= end - pos)
2286 return pos - buf;
2287 pos += ret;
2288
6fc6879b 2289 ret = os_snprintf(pos, end - pos, "ssid=%s\n",
3a068632 2290 wpa_ssid_txt(bss->ssid, bss->ssid_len));
6fc6879b
JM
2291 if (ret < 0 || ret >= end - pos)
2292 return pos - buf;
2293 pos += ret;
2294
611ed491
JM
2295#ifdef CONFIG_WPS
2296 ie = (const u8 *) (bss + 1);
2297 ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
2298 if (ret < 0 || ret >= end - pos)
2299 return pos - buf;
2300 pos += ret;
2301#endif /* CONFIG_WPS */
2302
0c6b310e
JM
2303#ifdef CONFIG_P2P
2304 ie = (const u8 *) (bss + 1);
2305 ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
2306 if (ret < 0 || ret >= end - pos)
2307 return pos - buf;
2308 pos += ret;
2309#endif /* CONFIG_P2P */
2310
afc064fe
JM
2311#ifdef CONFIG_INTERWORKING
2312 pos = anqp_add_hex(pos, end, "anqp_venue_name", bss->anqp_venue_name);
2313 pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
2314 bss->anqp_network_auth_type);
2315 pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
2316 bss->anqp_roaming_consortium);
2317 pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
2318 bss->anqp_ip_addr_type_availability);
2319 pos = anqp_add_hex(pos, end, "anqp_nai_realm", bss->anqp_nai_realm);
2320 pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
2321 pos = anqp_add_hex(pos, end, "anqp_domain_name",
2322 bss->anqp_domain_name);
2323#endif /* CONFIG_INTERWORKING */
2324
6fc6879b
JM
2325 return pos - buf;
2326}
2327
2328
2329static int wpa_supplicant_ctrl_iface_ap_scan(
2330 struct wpa_supplicant *wpa_s, char *cmd)
2331{
2332 int ap_scan = atoi(cmd);
86b89452 2333 return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
6fc6879b
JM
2334}
2335
2336
67b9bd08
DS
2337static int wpa_supplicant_ctrl_iface_scan_interval(
2338 struct wpa_supplicant *wpa_s, char *cmd)
2339{
2340 int scan_int = atoi(cmd);
2341 if (scan_int < 0)
2342 return -1;
2343 wpa_s->scan_interval = scan_int;
2344 return 0;
2345}
2346
2347
78633c37
SL
2348static int wpa_supplicant_ctrl_iface_bss_expire_age(
2349 struct wpa_supplicant *wpa_s, char *cmd)
2350{
2351 int expire_age = atoi(cmd);
2352 return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
2353}
2354
2355
2356static int wpa_supplicant_ctrl_iface_bss_expire_count(
2357 struct wpa_supplicant *wpa_s, char *cmd)
2358{
2359 int expire_count = atoi(cmd);
2360 return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
2361}
2362
2363
32d5295f
JM
2364static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
2365{
32d5295f
JM
2366 wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
2367 /* MLME-DELETEKEYS.request */
0382097e
JM
2368 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
2369 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
2370 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
2371 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
32d5295f 2372#ifdef CONFIG_IEEE80211W
0382097e
JM
2373 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
2374 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
32d5295f
JM
2375#endif /* CONFIG_IEEE80211W */
2376
2377 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
2378 0);
2379 /* MLME-SETPROTECTION.request(None) */
2380 wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
2381 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
2382 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
2383 wpa_sm_drop_sa(wpa_s->wpa);
2384}
2385
2386
86d4f806
JM
2387static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
2388 char *addr)
2389{
2390 u8 bssid[ETH_ALEN];
2391 struct wpa_bss *bss;
2392 struct wpa_ssid *ssid = wpa_s->current_ssid;
2393
2394 if (hwaddr_aton(addr, bssid)) {
2395 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
2396 "address '%s'", addr);
2397 return -1;
2398 }
2399
2400 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
2401
2402 bss = wpa_bss_get_bssid(wpa_s, bssid);
2403 if (!bss) {
2404 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
2405 "from BSS table");
2406 return -1;
2407 }
2408
2409 /*
2410 * TODO: Find best network configuration block from configuration to
2411 * allow roaming to other networks
2412 */
2413
2414 if (!ssid) {
2415 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
2416 "configuration known for the target AP");
2417 return -1;
2418 }
2419
2420 wpa_s->reassociate = 1;
2421 wpa_supplicant_connect(wpa_s, bss, ssid);
2422
2423 return 0;
2424}
2425
2426
b563b388
JM
2427#ifdef CONFIG_P2P
2428static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
2429{
2430 unsigned int timeout = atoi(cmd);
2431 enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
2432
2433 if (os_strstr(cmd, "type=social"))
2434 type = P2P_FIND_ONLY_SOCIAL;
2435 else if (os_strstr(cmd, "type=progressive"))
2436 type = P2P_FIND_PROGRESSIVE;
2437
046ef4aa 2438 return wpas_p2p_find(wpa_s, timeout, type, 0, NULL);
b563b388
JM
2439}
2440
2441
2442static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
2443 char *buf, size_t buflen)
2444{
2445 u8 addr[ETH_ALEN];
2446 char *pos, *pos2;
2447 char *pin = NULL;
2448 enum p2p_wps_method wps_method;
2449 int new_pin;
2450 int ret;
2451 int persistent_group;
2452 int join;
2453 int auth;
2454 int go_intent = -1;
2455 int freq = 0;
2456
2457 /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad] [persistent]
108def93 2458 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] */
b563b388
JM
2459
2460 if (hwaddr_aton(cmd, addr))
2461 return -1;
2462
2463 pos = cmd + 17;
2464 if (*pos != ' ')
2465 return -1;
2466 pos++;
2467
2468 persistent_group = os_strstr(pos, " persistent") != NULL;
2469 join = os_strstr(pos, " join") != NULL;
2470 auth = os_strstr(pos, " auth") != NULL;
2471
2472 pos2 = os_strstr(pos, " go_intent=");
2473 if (pos2) {
2474 pos2 += 11;
2475 go_intent = atoi(pos2);
2476 if (go_intent < 0 || go_intent > 15)
2477 return -1;
2478 }
2479
2480 pos2 = os_strstr(pos, " freq=");
2481 if (pos2) {
2482 pos2 += 6;
2483 freq = atoi(pos2);
2484 if (freq <= 0)
2485 return -1;
2486 }
2487
2488 if (os_strncmp(pos, "pin", 3) == 0) {
2489 /* Request random PIN (to be displayed) and enable the PIN */
2490 wps_method = WPS_PIN_DISPLAY;
2491 } else if (os_strncmp(pos, "pbc", 3) == 0) {
2492 wps_method = WPS_PBC;
2493 } else {
2494 pin = pos;
2495 pos = os_strchr(pin, ' ');
2496 wps_method = WPS_PIN_KEYPAD;
2497 if (pos) {
2498 *pos++ = '\0';
07fecd39 2499 if (os_strncmp(pos, "display", 7) == 0)
b563b388
JM
2500 wps_method = WPS_PIN_DISPLAY;
2501 }
2502 }
2503
2504 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
2505 persistent_group, join, auth, go_intent,
2506 freq);
d054a462
JM
2507 if (new_pin == -2) {
2508 os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
2509 return 25;
2510 }
2511 if (new_pin == -3) {
2512 os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
2513 return 25;
2514 }
b563b388
JM
2515 if (new_pin < 0)
2516 return -1;
2517 if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
2518 ret = os_snprintf(buf, buflen, "%08d", new_pin);
2519 if (ret < 0 || (size_t) ret >= buflen)
2520 return -1;
2521 return ret;
2522 }
2523
2524 os_memcpy(buf, "OK\n", 3);
2525 return 3;
2526}
2527
2528
2529static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
2530{
2531 unsigned int timeout = atoi(cmd);
2532 return wpas_p2p_listen(wpa_s, timeout);
2533}
2534
2535
2536static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
2537{
2538 u8 addr[ETH_ALEN];
2539 char *pos;
2540
2541 /* <addr> <config method> */
2542
2543 if (hwaddr_aton(cmd, addr))
2544 return -1;
2545
2546 pos = cmd + 17;
2547 if (*pos != ' ')
2548 return -1;
2549 pos++;
2550
2551 return wpas_p2p_prov_disc(wpa_s, addr, pos);
2552}
2553
2554
2555static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
2556 size_t buflen)
2557{
2558 struct wpa_ssid *ssid = wpa_s->current_ssid;
2559
2560 if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
2561 ssid->passphrase == NULL)
2562 return -1;
2563
2564 os_strlcpy(buf, ssid->passphrase, buflen);
2565 return os_strlen(buf);
2566}
2567
2568
2569static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
2570 char *buf, size_t buflen)
2571{
2572 u64 ref;
2573 int res;
2574 u8 dst_buf[ETH_ALEN], *dst;
2575 struct wpabuf *tlvs;
2576 char *pos;
2577 size_t len;
2578
2579 if (hwaddr_aton(cmd, dst_buf))
2580 return -1;
2581 dst = dst_buf;
2582 if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
2583 dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
2584 dst = NULL;
2585 pos = cmd + 17;
2586 if (*pos != ' ')
2587 return -1;
2588 pos++;
2589
2590 if (os_strncmp(pos, "upnp ", 5) == 0) {
2591 u8 version;
2592 pos += 5;
2593 if (hexstr2bin(pos, &version, 1) < 0)
2594 return -1;
2595 pos += 2;
2596 if (*pos != ' ')
2597 return -1;
2598 pos++;
0423d090
JB
2599 ref = (unsigned long) wpas_p2p_sd_request_upnp(wpa_s, dst,
2600 version, pos);
b563b388
JM
2601 } else {
2602 len = os_strlen(pos);
2603 if (len & 1)
2604 return -1;
2605 len /= 2;
2606 tlvs = wpabuf_alloc(len);
2607 if (tlvs == NULL)
2608 return -1;
2609 if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
2610 wpabuf_free(tlvs);
2611 return -1;
2612 }
2613
0423d090 2614 ref = (unsigned long) wpas_p2p_sd_request(wpa_s, dst, tlvs);
b563b388
JM
2615 wpabuf_free(tlvs);
2616 }
2617 res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
2618 if (res < 0 || (unsigned) res >= buflen)
2619 return -1;
2620 return res;
2621}
2622
2623
2624static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
2625 char *cmd)
2626{
2627 long long unsigned val;
2628 u64 req;
2629 if (sscanf(cmd, "%llx", &val) != 1)
2630 return -1;
2631 req = val;
0423d090 2632 return wpas_p2p_sd_cancel_request(wpa_s, (void *) (unsigned long) req);
b563b388
JM
2633}
2634
2635
2636static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
2637{
2638 int freq;
d25f7212 2639 u8 dst[ETH_ALEN];
b563b388
JM
2640 u8 dialog_token;
2641 struct wpabuf *resp_tlvs;
2642 char *pos, *pos2;
2643 size_t len;
2644
2645 pos = os_strchr(cmd, ' ');
2646 if (pos == NULL)
2647 return -1;
2648 *pos++ = '\0';
2649 freq = atoi(cmd);
2650 if (freq == 0)
2651 return -1;
2652
d25f7212 2653 if (hwaddr_aton(pos, dst))
b563b388 2654 return -1;
b563b388
JM
2655 pos += 17;
2656 if (*pos != ' ')
2657 return -1;
2658 pos++;
2659
2660 pos2 = os_strchr(pos, ' ');
2661 if (pos2 == NULL)
2662 return -1;
2663 *pos2++ = '\0';
2664 dialog_token = atoi(pos);
2665
2666 len = os_strlen(pos2);
2667 if (len & 1)
2668 return -1;
2669 len /= 2;
2670 resp_tlvs = wpabuf_alloc(len);
2671 if (resp_tlvs == NULL)
2672 return -1;
2673 if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
2674 wpabuf_free(resp_tlvs);
2675 return -1;
2676 }
2677
2678 wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
2679 wpabuf_free(resp_tlvs);
2680 return 0;
2681}
2682
2683
2684static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
2685 char *cmd)
2686{
2687 wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
2688 return 0;
2689}
2690
2691
2692static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
2693 char *cmd)
2694{
2695 char *pos;
2696 size_t len;
2697 struct wpabuf *query, *resp;
2698
2699 pos = os_strchr(cmd, ' ');
2700 if (pos == NULL)
2701 return -1;
2702 *pos++ = '\0';
2703
2704 len = os_strlen(cmd);
2705 if (len & 1)
2706 return -1;
2707 len /= 2;
2708 query = wpabuf_alloc(len);
2709 if (query == NULL)
2710 return -1;
2711 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
2712 wpabuf_free(query);
2713 return -1;
2714 }
2715
2716 len = os_strlen(pos);
2717 if (len & 1) {
2718 wpabuf_free(query);
2719 return -1;
2720 }
2721 len /= 2;
2722 resp = wpabuf_alloc(len);
2723 if (resp == NULL) {
2724 wpabuf_free(query);
2725 return -1;
2726 }
2727 if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
2728 wpabuf_free(query);
2729 wpabuf_free(resp);
2730 return -1;
2731 }
2732
2733 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
2734 wpabuf_free(query);
2735 wpabuf_free(resp);
2736 return -1;
2737 }
2738 return 0;
2739}
2740
2741
2742static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
2743{
2744 char *pos;
2745 u8 version;
2746
2747 pos = os_strchr(cmd, ' ');
2748 if (pos == NULL)
2749 return -1;
2750 *pos++ = '\0';
2751
2752 if (hexstr2bin(cmd, &version, 1) < 0)
2753 return -1;
2754
2755 return wpas_p2p_service_add_upnp(wpa_s, version, pos);
2756}
2757
2758
2759static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
2760{
2761 char *pos;
2762
2763 pos = os_strchr(cmd, ' ');
2764 if (pos == NULL)
2765 return -1;
2766 *pos++ = '\0';
2767
2768 if (os_strcmp(cmd, "bonjour") == 0)
2769 return p2p_ctrl_service_add_bonjour(wpa_s, pos);
2770 if (os_strcmp(cmd, "upnp") == 0)
2771 return p2p_ctrl_service_add_upnp(wpa_s, pos);
2772 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
2773 return -1;
2774}
2775
2776
2777static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
2778 char *cmd)
2779{
2780 size_t len;
2781 struct wpabuf *query;
2782 int ret;
2783
2784 len = os_strlen(cmd);
2785 if (len & 1)
2786 return -1;
2787 len /= 2;
2788 query = wpabuf_alloc(len);
2789 if (query == NULL)
2790 return -1;
2791 if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
2792 wpabuf_free(query);
2793 return -1;
2794 }
2795
2796 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
2797 wpabuf_free(query);
2798 return ret;
2799}
2800
2801
2802static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
2803{
2804 char *pos;
2805 u8 version;
2806
2807 pos = os_strchr(cmd, ' ');
2808 if (pos == NULL)
2809 return -1;
2810 *pos++ = '\0';
2811
2812 if (hexstr2bin(cmd, &version, 1) < 0)
2813 return -1;
2814
2815 return wpas_p2p_service_del_upnp(wpa_s, version, pos);
2816}
2817
2818
2819static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
2820{
2821 char *pos;
2822
2823 pos = os_strchr(cmd, ' ');
2824 if (pos == NULL)
2825 return -1;
2826 *pos++ = '\0';
2827
2828 if (os_strcmp(cmd, "bonjour") == 0)
2829 return p2p_ctrl_service_del_bonjour(wpa_s, pos);
2830 if (os_strcmp(cmd, "upnp") == 0)
2831 return p2p_ctrl_service_del_upnp(wpa_s, pos);
2832 wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
2833 return -1;
2834}
2835
2836
2837static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
2838{
2839 u8 addr[ETH_ALEN];
2840
2841 /* <addr> */
2842
2843 if (hwaddr_aton(cmd, addr))
2844 return -1;
2845
2846 return wpas_p2p_reject(wpa_s, addr);
2847}
2848
2849
2850static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
2851{
2852 char *pos;
2853 int id;
2854 struct wpa_ssid *ssid;
2855 u8 peer[ETH_ALEN];
2856
2857 id = atoi(cmd);
2858 pos = os_strstr(cmd, " peer=");
2859 if (pos) {
2860 pos += 6;
2861 if (hwaddr_aton(pos, peer))
2862 return -1;
2863 }
2864 ssid = wpa_config_get_network(wpa_s->conf, id);
2865 if (ssid == NULL || ssid->disabled != 2) {
2866 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
2867 "for persistent P2P group",
2868 id);
2869 return -1;
2870 }
2871
2872 return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL);
2873}
2874
2875
2876static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
2877{
2878 char *pos;
2879 u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
2880
2881 pos = os_strstr(cmd, " peer=");
2882 if (!pos)
2883 return -1;
2884
2885 *pos = '\0';
2886 pos += 6;
2887 if (hwaddr_aton(pos, peer)) {
2888 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
2889 return -1;
2890 }
2891
2892 pos = os_strstr(pos, " go_dev_addr=");
2893 if (pos) {
2894 pos += 13;
2895 if (hwaddr_aton(pos, go_dev_addr)) {
2896 wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
2897 pos);
2898 return -1;
2899 }
2900 go_dev = go_dev_addr;
2901 }
2902
2903 return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
2904}
2905
2906
2907static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
2908{
2909 if (os_strncmp(cmd, "persistent=", 11) == 0)
2910 return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
2911 if (os_strncmp(cmd, "group=", 6) == 0)
2912 return p2p_ctrl_invite_group(wpa_s, cmd + 6);
2913
2914 return -1;
2915}
2916
2917
2918static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
2919 char *cmd, int freq)
2920{
2921 int id;
2922 struct wpa_ssid *ssid;
2923
2924 id = atoi(cmd);
2925 ssid = wpa_config_get_network(wpa_s->conf, id);
2926 if (ssid == NULL || ssid->disabled != 2) {
2927 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
2928 "for persistent P2P group",
2929 id);
2930 return -1;
2931 }
2932
2933 return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq);
2934}
2935
2936
2937static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
2938{
2939 int freq = 0;
2940 char *pos;
2941
2942 pos = os_strstr(cmd, "freq=");
2943 if (pos)
2944 freq = atoi(pos + 5);
2945
2946 if (os_strncmp(cmd, "persistent=", 11) == 0)
2947 return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
2948 if (os_strcmp(cmd, "persistent") == 0 ||
2949 os_strncmp(cmd, "persistent ", 11) == 0)
2950 return wpas_p2p_group_add(wpa_s, 1, freq);
2951 if (os_strncmp(cmd, "freq=", 5) == 0)
2952 return wpas_p2p_group_add(wpa_s, 0, freq);
2953
2954 wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
2955 cmd);
2956 return -1;
2957}
2958
2959
2960static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
2961 char *buf, size_t buflen)
2962{
2963 u8 addr[ETH_ALEN], *addr_ptr;
2964 int next;
2965
2966 if (!wpa_s->global->p2p)
2967 return -1;
2968
2969 if (os_strcmp(cmd, "FIRST") == 0) {
2970 addr_ptr = NULL;
2971 next = 0;
2972 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
2973 if (hwaddr_aton(cmd + 5, addr) < 0)
2974 return -1;
2975 addr_ptr = addr;
2976 next = 1;
2977 } else {
2978 if (hwaddr_aton(cmd, addr) < 0)
2979 return -1;
2980 addr_ptr = addr;
2981 next = 0;
2982 }
2983
2984 return p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next,
2985 buf, buflen);
2986}
2987
2988
2989static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
2990{
2991 char *param;
2992
2993 if (wpa_s->global->p2p == NULL)
2994 return -1;
2995
2996 param = os_strchr(cmd, ' ');
2997 if (param == NULL)
2998 return -1;
2999 *param++ = '\0';
3000
3001 if (os_strcmp(cmd, "discoverability") == 0) {
3002 p2p_set_client_discoverability(wpa_s->global->p2p,
3003 atoi(param));
3004 return 0;
3005 }
3006
3007 if (os_strcmp(cmd, "managed") == 0) {
3008 p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
3009 return 0;
3010 }
3011
3012 if (os_strcmp(cmd, "listen_channel") == 0) {
3013 return p2p_set_listen_channel(wpa_s->global->p2p, 81,
3014 atoi(param));
3015 }
3016
3017 if (os_strcmp(cmd, "ssid_postfix") == 0) {
3018 return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
3019 os_strlen(param));
3020 }
3021
3022 if (os_strcmp(cmd, "noa") == 0) {
3023 char *pos;
3024 int count, start, duration;
3025 /* GO NoA parameters: count,start_offset(ms),duration(ms) */
3026 count = atoi(param);
3027 pos = os_strchr(param, ',');
3028 if (pos == NULL)
3029 return -1;
3030 pos++;
3031 start = atoi(pos);
3032 pos = os_strchr(pos, ',');
3033 if (pos == NULL)
3034 return -1;
3035 pos++;
3036 duration = atoi(pos);
3037 if (count < 0 || count > 255 || start < 0 || duration < 0)
3038 return -1;
3039 if (count == 0 && duration > 0)
3040 return -1;
3041 wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
3042 "start=%d duration=%d", count, start, duration);
aefb53bd 3043 return wpas_p2p_set_noa(wpa_s, count, start, duration);
b563b388
JM
3044 }
3045
c381508d
JM
3046 if (os_strcmp(cmd, "ps") == 0)
3047 return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
3048
3049 if (os_strcmp(cmd, "oppps") == 0)
3050 return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
3051
3052 if (os_strcmp(cmd, "ctwindow") == 0)
3053 return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
3054
b563b388
JM
3055 if (os_strcmp(cmd, "disabled") == 0) {
3056 wpa_s->global->p2p_disabled = atoi(param);
3057 wpa_printf(MSG_DEBUG, "P2P functionality %s",
3058 wpa_s->global->p2p_disabled ?
3059 "disabled" : "enabled");
3060 if (wpa_s->global->p2p_disabled) {
3061 wpas_p2p_stop_find(wpa_s);
108def93 3062 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
b563b388
JM
3063 p2p_flush(wpa_s->global->p2p);
3064 }
3065 return 0;
3066 }
3067
6e6963ea
JM
3068 if (os_strcmp(cmd, "force_long_sd") == 0) {
3069 wpa_s->force_long_sd = atoi(param);
3070 return 0;
3071 }
3072
80c9582a
JM
3073 if (os_strcmp(cmd, "peer_filter") == 0) {
3074 u8 addr[ETH_ALEN];
3075 if (hwaddr_aton(param, addr))
3076 return -1;
3077 p2p_set_peer_filter(wpa_s->global->p2p, addr);
3078 return 0;
3079 }
3080
72044390
JM
3081 if (os_strcmp(cmd, "cross_connect") == 0)
3082 return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
3083
eea2fd9e
JM
3084 if (os_strcmp(cmd, "go_apsd") == 0) {
3085 if (os_strcmp(param, "disable") == 0)
3086 wpa_s->set_ap_uapsd = 0;
3087 else {
3088 wpa_s->set_ap_uapsd = 1;
3089 wpa_s->ap_uapsd = atoi(param);
3090 }
3091 return 0;
3092 }
3093
3094 if (os_strcmp(cmd, "client_apsd") == 0) {
3095 if (os_strcmp(param, "disable") == 0)
3096 wpa_s->set_sta_uapsd = 0;
3097 else {
3098 int be, bk, vi, vo;
3099 char *pos;
3100 /* format: BE,BK,VI,VO;max SP Length */
3101 be = atoi(param);
3102 pos = os_strchr(param, ',');
3103 if (pos == NULL)
3104 return -1;
3105 pos++;
3106 bk = atoi(pos);
3107 pos = os_strchr(pos, ',');
3108 if (pos == NULL)
3109 return -1;
3110 pos++;
3111 vi = atoi(pos);
3112 pos = os_strchr(pos, ',');
3113 if (pos == NULL)
3114 return -1;
3115 pos++;
3116 vo = atoi(pos);
3117 /* ignore max SP Length for now */
3118
3119 wpa_s->set_sta_uapsd = 1;
3120 wpa_s->sta_uapsd = 0;
3121 if (be)
3122 wpa_s->sta_uapsd |= BIT(0);
3123 if (bk)
3124 wpa_s->sta_uapsd |= BIT(1);
3125 if (vi)
3126 wpa_s->sta_uapsd |= BIT(2);
3127 if (vo)
3128 wpa_s->sta_uapsd |= BIT(3);
3129 }
3130 return 0;
3131 }
3132
b563b388
JM
3133 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
3134 cmd);
3135
3136 return -1;
3137}
3138
3139
3140static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
3141{
3142 char *pos, *pos2;
3143 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
3144
3145 if (cmd[0]) {
3146 pos = os_strchr(cmd, ' ');
3147 if (pos == NULL)
3148 return -1;
3149 *pos++ = '\0';
3150 dur1 = atoi(cmd);
3151
3152 pos2 = os_strchr(pos, ' ');
3153 if (pos2)
3154 *pos2++ = '\0';
3155 int1 = atoi(pos);
3156 } else
3157 pos2 = NULL;
3158
3159 if (pos2) {
3160 pos = os_strchr(pos2, ' ');
3161 if (pos == NULL)
3162 return -1;
3163 *pos++ = '\0';
3164 dur2 = atoi(pos2);
3165 int2 = atoi(pos);
3166 }
3167
3168 return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
3169}
3170
3171
3172static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
3173{
3174 char *pos;
3175 unsigned int period = 0, interval = 0;
3176
3177 if (cmd[0]) {
3178 pos = os_strchr(cmd, ' ');
3179 if (pos == NULL)
3180 return -1;
3181 *pos++ = '\0';
3182 period = atoi(cmd);
3183 interval = atoi(pos);
3184 }
3185
3186 return wpas_p2p_ext_listen(wpa_s, period, interval);
3187}
3188
3189#endif /* CONFIG_P2P */
3190
3191
afc064fe 3192#ifdef CONFIG_INTERWORKING
b02fe7ff
JM
3193static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
3194{
3195 u8 bssid[ETH_ALEN];
3196 struct wpa_bss *bss;
3197
3198 if (hwaddr_aton(dst, bssid)) {
3199 wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
3200 return -1;
3201 }
3202
3203 bss = wpa_bss_get_bssid(wpa_s, bssid);
3204 if (bss == NULL) {
3205 wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
3206 MAC2STR(bssid));
3207 return -1;
3208 }
3209
3210 return interworking_connect(wpa_s, bss);
3211}
3212
3213
afc064fe
JM
3214static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
3215{
3216 u8 dst_addr[ETH_ALEN];
3217 int used;
3218 char *pos;
3219#define MAX_ANQP_INFO_ID 100
3220 u16 id[MAX_ANQP_INFO_ID];
3221 size_t num_id = 0;
3222
3223 used = hwaddr_aton2(dst, dst_addr);
3224 if (used < 0)
3225 return -1;
3226 pos = dst + used;
3227 while (num_id < MAX_ANQP_INFO_ID) {
3228 id[num_id] = atoi(pos);
3229 if (id[num_id])
3230 num_id++;
3231 pos = os_strchr(pos + 1, ',');
3232 if (pos == NULL)
3233 break;
3234 pos++;
3235 }
3236
3237 if (num_id == 0)
3238 return -1;
3239
3240 return anqp_send_req(wpa_s, dst_addr, id, num_id);
3241}
3242#endif /* CONFIG_INTERWORKING */
3243
3244
0d0a8ca1
AC
3245static int wpa_supplicant_ctrl_iface_sta_autoconnect(
3246 struct wpa_supplicant *wpa_s, char *cmd)
3247{
3248 wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
3249 return 0;
3250}
3251
3252
60b24b0d
DS
3253static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
3254 size_t buflen)
3255{
3256 struct wpa_signal_info si;
3257 int ret;
3258
3259 ret = wpa_drv_signal_poll(wpa_s, &si);
3260 if (ret)
3261 return -1;
3262
3263 ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
3264 "NOISE=%d\nFREQUENCY=%u\n",
3265 si.current_signal, si.current_txrate / 1000,
3266 si.current_noise, si.frequency);
3267 if (ret < 0 || (unsigned int) ret > buflen)
3268 return -1;
3269 return ret;
3270}
3271
3272
6fc6879b
JM
3273char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
3274 char *buf, size_t *resp_len)
3275{
3276 char *reply;
b563b388 3277 const int reply_size = 4096;
6fc6879b
JM
3278 int ctrl_rsp = 0;
3279 int reply_len;
3280
3281 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
3282 os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
3283 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
3284 (const u8 *) buf, os_strlen(buf));
3285 } else {
235f69fc
JM
3286 int level = MSG_DEBUG;
3287 if (os_strcmp(buf, "PING") == 0)
3288 level = MSG_EXCESSIVE;
3289 wpa_hexdump_ascii(level, "RX ctrl_iface",
6fc6879b
JM
3290 (const u8 *) buf, os_strlen(buf));
3291 }
3292
3293 reply = os_malloc(reply_size);
3294 if (reply == NULL) {
3295 *resp_len = 1;
3296 return NULL;
3297 }
3298
3299 os_memcpy(reply, "OK\n", 3);
3300 reply_len = 3;
3301
3302 if (os_strcmp(buf, "PING") == 0) {
3303 os_memcpy(reply, "PONG\n", 5);
3304 reply_len = 5;
ac6912b5
BG
3305 } else if (os_strncmp(buf, "RELOG", 5) == 0) {
3306 if (wpa_debug_reopen_file() < 0)
3307 reply_len = -1;
77895cd9
JM
3308 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
3309 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
6fc6879b
JM
3310 } else if (os_strcmp(buf, "MIB") == 0) {
3311 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
3312 if (reply_len >= 0) {
3313 int res;
3314 res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
3315 reply_size - reply_len);
3316 if (res < 0)
3317 reply_len = -1;
3318 else
3319 reply_len += res;
3320 }
3321 } else if (os_strncmp(buf, "STATUS", 6) == 0) {
3322 reply_len = wpa_supplicant_ctrl_iface_status(
3323 wpa_s, buf + 6, reply, reply_size);
3324 } else if (os_strcmp(buf, "PMKSA") == 0) {
540264a7
JM
3325 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
3326 reply_size);
6fc6879b
JM
3327 } else if (os_strncmp(buf, "SET ", 4) == 0) {
3328 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
3329 reply_len = -1;
acec8d32
JM
3330 } else if (os_strncmp(buf, "GET ", 4) == 0) {
3331 reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
3332 reply, reply_size);
6fc6879b
JM
3333 } else if (os_strcmp(buf, "LOGON") == 0) {
3334 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
3335 } else if (os_strcmp(buf, "LOGOFF") == 0) {
3336 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
3337 } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
0b7a25c0 3338 wpa_s->normal_scans = 0;
8401a6b0
JM
3339 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
3340 reply_len = -1;
3341 else {
3342 wpa_s->disconnected = 0;
3343 wpa_s->reassociate = 1;
3344 wpa_supplicant_req_scan(wpa_s, 0, 0);
3345 }
6fc6879b 3346 } else if (os_strcmp(buf, "RECONNECT") == 0) {
0b7a25c0 3347 wpa_s->normal_scans = 0;
8401a6b0
JM
3348 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
3349 reply_len = -1;
3350 else if (wpa_s->disconnected) {
6fc6879b
JM
3351 wpa_s->disconnected = 0;
3352 wpa_s->reassociate = 1;
3353 wpa_supplicant_req_scan(wpa_s, 0, 0);
3354 }
ec717917 3355#ifdef IEEE8021X_EAPOL
6fc6879b
JM
3356 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
3357 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
3358 reply_len = -1;
ec717917 3359#endif /* IEEE8021X_EAPOL */
6fc6879b
JM
3360#ifdef CONFIG_PEERKEY
3361 } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
3362 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
3363 reply_len = -1;
3364#endif /* CONFIG_PEERKEY */
3365#ifdef CONFIG_IEEE80211R
3366 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
3367 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
3368 reply_len = -1;
3369#endif /* CONFIG_IEEE80211R */
fcc60db4
JM
3370#ifdef CONFIG_WPS
3371 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
3152ff42
CWY
3372 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
3373 if (res == -2) {
3374 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
3375 reply_len = 17;
3376 } else if (res)
fcc60db4
JM
3377 reply_len = -1;
3378 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
3152ff42
CWY
3379 int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
3380 if (res == -2) {
3381 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
3382 reply_len = 17;
3383 } else if (res)
fcc60db4
JM
3384 reply_len = -1;
3385 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
3386 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
3387 reply,
3388 reply_size);
3981cb3c
JM
3389 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
3390 reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
3391 wpa_s, buf + 14, reply, reply_size);
2f9929ff
AC
3392 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
3393 if (wpas_wps_cancel(wpa_s))
3394 reply_len = -1;
116f7bb0 3395#ifdef CONFIG_WPS_OOB
46bdb83a
MH
3396 } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
3397 if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
3398 reply_len = -1;
116f7bb0 3399#endif /* CONFIG_WPS_OOB */
fcc60db4
JM
3400 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
3401 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
3402 reply_len = -1;
70d84f11
JM
3403#ifdef CONFIG_AP
3404 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
3405 reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
3406 wpa_s, buf + 11, reply, reply_size);
3407#endif /* CONFIG_AP */
72df2f5f 3408#ifdef CONFIG_WPS_ER
e9bcfebf 3409 } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
08486685
JM
3410 if (wpas_wps_er_start(wpa_s, NULL))
3411 reply_len = -1;
3412 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
3413 if (wpas_wps_er_start(wpa_s, buf + 13))
e9bcfebf
JM
3414 reply_len = -1;
3415 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
3416 if (wpas_wps_er_stop(wpa_s))
3417 reply_len = -1;
72df2f5f
JM
3418 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
3419 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
3420 reply_len = -1;
564cd7fa 3421 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
ed159ad4
JM
3422 int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
3423 if (ret == -2) {
3424 os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
3425 reply_len = 17;
3426 } else if (ret == -3) {
3427 os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
3428 reply_len = 18;
3429 } else if (ret == -4) {
3430 os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
3431 reply_len = 20;
3432 } else if (ret)
564cd7fa 3433 reply_len = -1;
e64dcfd5
JM
3434 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
3435 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
3436 reply_len = -1;
ef10f473
JM
3437 } else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
3438 if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
3439 buf + 18))
3440 reply_len = -1;
7d6640a6
JM
3441 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
3442 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
3443 reply_len = -1;
72df2f5f 3444#endif /* CONFIG_WPS_ER */
fcc60db4 3445#endif /* CONFIG_WPS */
11ef8d35
JM
3446#ifdef CONFIG_IBSS_RSN
3447 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
3448 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
3449 reply_len = -1;
3450#endif /* CONFIG_IBSS_RSN */
b563b388
JM
3451#ifdef CONFIG_P2P
3452 } else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
3453 if (p2p_ctrl_find(wpa_s, buf + 9))
3454 reply_len = -1;
3455 } else if (os_strcmp(buf, "P2P_FIND") == 0) {
3456 if (p2p_ctrl_find(wpa_s, ""))
3457 reply_len = -1;
3458 } else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
3459 wpas_p2p_stop_find(wpa_s);
3460 } else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
3461 reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
3462 reply_size);
3463 } else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
3464 if (p2p_ctrl_listen(wpa_s, buf + 11))
3465 reply_len = -1;
3466 } else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
3467 if (p2p_ctrl_listen(wpa_s, ""))
3468 reply_len = -1;
3469 } else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
3470 if (wpas_p2p_group_remove(wpa_s, buf + 17))
3471 reply_len = -1;
3472 } else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
3473 if (wpas_p2p_group_add(wpa_s, 0, 0))
3474 reply_len = -1;
3475 } else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
3476 if (p2p_ctrl_group_add(wpa_s, buf + 14))
3477 reply_len = -1;
3478 } else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
3479 if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
3480 reply_len = -1;
3481 } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
3482 reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
3483 } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
3484 reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
3485 reply_size);
3486 } else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
3487 if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
3488 reply_len = -1;
3489 } else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
3490 if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
3491 reply_len = -1;
3492 } else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
3493 wpas_p2p_sd_service_update(wpa_s);
3494 } else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
3495 if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
3496 reply_len = -1;
3497 } else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
3498 wpas_p2p_service_flush(wpa_s);
3499 } else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
3500 if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
3501 reply_len = -1;
3502 } else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
3503 if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
3504 reply_len = -1;
3505 } else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
3506 if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
3507 reply_len = -1;
3508 } else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
3509 if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
3510 reply_len = -1;
3511 } else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
3512 reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
3513 reply_size);
3514 } else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
3515 if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
3516 reply_len = -1;
3517 } else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
108def93 3518 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
6e6963ea 3519 wpa_s->force_long_sd = 0;
9526fd29
JM
3520 if (wpa_s->global->p2p)
3521 p2p_flush(wpa_s->global->p2p);
9d562b79
SS
3522 } else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
3523 if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
3524 reply_len = -1;
59eba7a2
JM
3525 } else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
3526 if (wpas_p2p_cancel(wpa_s))
3527 reply_len = -1;
b563b388
JM
3528 } else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
3529 if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
3530 reply_len = -1;
3531 } else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
3532 if (p2p_ctrl_presence_req(wpa_s, "") < 0)
3533 reply_len = -1;
3534 } else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
3535 if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
3536 reply_len = -1;
3537 } else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
3538 if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
3539 reply_len = -1;
3540#endif /* CONFIG_P2P */
afc064fe
JM
3541#ifdef CONFIG_INTERWORKING
3542 } else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
3543 if (interworking_fetch_anqp(wpa_s) < 0)
3544 reply_len = -1;
3545 } else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
3546 interworking_stop_fetch_anqp(wpa_s);
b02fe7ff
JM
3547 } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
3548 if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
3549 NULL) < 0)
3550 reply_len = -1;
3551 } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
3552 if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
3553 reply_len = -1;
afc064fe
JM
3554 } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
3555 if (get_anqp(wpa_s, buf + 9) < 0)
3556 reply_len = -1;
3557#endif /* CONFIG_INTERWORKING */
6fc6879b
JM
3558 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
3559 {
3560 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
3561 wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
3562 reply_len = -1;
3563 else
3564 ctrl_rsp = 1;
3565 } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
3566 if (wpa_supplicant_reload_configuration(wpa_s))
3567 reply_len = -1;
3568 } else if (os_strcmp(buf, "TERMINATE") == 0) {
1a1bf008 3569 wpa_supplicant_terminate_proc(wpa_s->global);
6fc6879b
JM
3570 } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
3571 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
3572 reply_len = -1;
9aa10e2b
DS
3573 } else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
3574 reply_len = wpa_supplicant_ctrl_iface_blacklist(
3575 wpa_s, buf + 9, reply, reply_size);
0597a5b5
DS
3576 } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
3577 reply_len = wpa_supplicant_ctrl_iface_log_level(
3578 wpa_s, buf + 9, reply, reply_size);
6fc6879b
JM
3579 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
3580 reply_len = wpa_supplicant_ctrl_iface_list_networks(
3581 wpa_s, reply, reply_size);
3582 } else if (os_strcmp(buf, "DISCONNECT") == 0) {
3583 wpa_s->reassociate = 0;
3584 wpa_s->disconnected = 1;
6ad9c911 3585 wpa_supplicant_cancel_sched_scan(wpa_s);
cf4783e3
JM
3586 wpa_supplicant_deauthenticate(wpa_s,
3587 WLAN_REASON_DEAUTH_LEAVING);
6fc6879b 3588 } else if (os_strcmp(buf, "SCAN") == 0) {
0b7a25c0 3589 wpa_s->normal_scans = 0;
8401a6b0
JM
3590 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
3591 reply_len = -1;
3592 else {
746bba1a
DS
3593 if (!wpa_s->scanning &&
3594 ((wpa_s->wpa_state <= WPA_SCANNING) ||
3595 (wpa_s->wpa_state == WPA_COMPLETED))) {
3596 wpa_s->scan_req = 2;
3597 wpa_supplicant_req_scan(wpa_s, 0, 0);
3598 } else {
3599 wpa_printf(MSG_DEBUG, "Ongoing scan action - "
3600 "reject new request");
3601 reply_len = os_snprintf(reply, reply_size,
3602 "FAIL-BUSY\n");
3603 }
8401a6b0 3604 }
6fc6879b
JM
3605 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
3606 reply_len = wpa_supplicant_ctrl_iface_scan_results(
3607 wpa_s, reply, reply_size);
3608 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
3609 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
3610 reply_len = -1;
3611 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
3612 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
3613 reply_len = -1;
3614 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
3615 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
3616 reply_len = -1;
3617 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
3618 reply_len = wpa_supplicant_ctrl_iface_add_network(
3619 wpa_s, reply, reply_size);
3620 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
3621 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
3622 reply_len = -1;
3623 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
3624 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
3625 reply_len = -1;
3626 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
3627 reply_len = wpa_supplicant_ctrl_iface_get_network(
3628 wpa_s, buf + 12, reply, reply_size);
3629#ifndef CONFIG_NO_CONFIG_WRITE
3630 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
3631 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
3632 reply_len = -1;
3633#endif /* CONFIG_NO_CONFIG_WRITE */
3634 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
3635 reply_len = wpa_supplicant_ctrl_iface_get_capability(
3636 wpa_s, buf + 15, reply, reply_size);
3637 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
3638 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
3639 reply_len = -1;
67b9bd08
DS
3640 } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
3641 if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
3642 reply_len = -1;
4b4a8ae5
JM
3643 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
3644 reply_len = wpa_supplicant_global_iface_list(
3645 wpa_s->global, reply, reply_size);
6fc6879b
JM
3646 } else if (os_strcmp(buf, "INTERFACES") == 0) {
3647 reply_len = wpa_supplicant_global_iface_interfaces(
3648 wpa_s->global, reply, reply_size);
3649 } else if (os_strncmp(buf, "BSS ", 4) == 0) {
3650 reply_len = wpa_supplicant_ctrl_iface_bss(
3651 wpa_s, buf + 4, reply, reply_size);
e653b622
JM
3652#ifdef CONFIG_AP
3653 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
3654 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
3655 } else if (os_strncmp(buf, "STA ", 4) == 0) {
3656 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
3657 reply_size);
3658 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
3659 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
3660 reply_size);
3661#endif /* CONFIG_AP */
207ef3fb
JM
3662 } else if (os_strcmp(buf, "SUSPEND") == 0) {
3663 wpas_notify_suspend(wpa_s->global);
3664 } else if (os_strcmp(buf, "RESUME") == 0) {
3665 wpas_notify_resume(wpa_s->global);
32d5295f
JM
3666 } else if (os_strcmp(buf, "DROP_SA") == 0) {
3667 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
86d4f806
JM
3668 } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
3669 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
3670 reply_len = -1;
0d0a8ca1
AC
3671 } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
3672 if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
3673 reply_len = -1;
78633c37
SL
3674 } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
3675 if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
3676 reply_len = -1;
3677 } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
3678 if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
3679 buf + 17))
3680 reply_len = -1;
281ff0aa
GP
3681#ifdef CONFIG_TDLS
3682 } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
3683 if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
3684 reply_len = -1;
3685 } else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
3686 if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
3687 reply_len = -1;
3688 } else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
3689 if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
3690 reply_len = -1;
3691#endif /* CONFIG_TDLS */
60b24b0d
DS
3692 } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
3693 reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
3694 reply_size);
9482426e
JM
3695 } else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
3696 eapol_sm_request_reauth(wpa_s->eapol);
6fc6879b
JM
3697 } else {
3698 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
3699 reply_len = 16;
3700 }
3701
3702 if (reply_len < 0) {
3703 os_memcpy(reply, "FAIL\n", 5);
3704 reply_len = 5;
3705 }
3706
3707 if (ctrl_rsp)
3708 eapol_sm_notify_ctrl_response(wpa_s->eapol);
3709
3710 *resp_len = reply_len;
3711 return reply;
3712}
3713
3714
3715static int wpa_supplicant_global_iface_add(struct wpa_global *global,
3716 char *cmd)
3717{
3718 struct wpa_interface iface;
3719 char *pos;
3720
3721 /*
3722 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
3723 * TAB<bridge_ifname>
3724 */
3725 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
3726
3727 os_memset(&iface, 0, sizeof(iface));
3728
3729 do {
3730 iface.ifname = pos = cmd;
3731 pos = os_strchr(pos, '\t');
3732 if (pos)
3733 *pos++ = '\0';
3734 if (iface.ifname[0] == '\0')
3735 return -1;
3736 if (pos == NULL)
3737 break;
3738
3739 iface.confname = pos;
3740 pos = os_strchr(pos, '\t');
3741 if (pos)
3742 *pos++ = '\0';
3743 if (iface.confname[0] == '\0')
3744 iface.confname = NULL;
3745 if (pos == NULL)
3746 break;
3747
3748 iface.driver = pos;
3749 pos = os_strchr(pos, '\t');
3750 if (pos)
3751 *pos++ = '\0';
3752 if (iface.driver[0] == '\0')
3753 iface.driver = NULL;
3754 if (pos == NULL)
3755 break;
3756
3757 iface.ctrl_interface = pos;
3758 pos = os_strchr(pos, '\t');
3759 if (pos)
3760 *pos++ = '\0';
3761 if (iface.ctrl_interface[0] == '\0')
3762 iface.ctrl_interface = NULL;
3763 if (pos == NULL)
3764 break;
3765
3766 iface.driver_param = pos;
3767 pos = os_strchr(pos, '\t');
3768 if (pos)
3769 *pos++ = '\0';
3770 if (iface.driver_param[0] == '\0')
3771 iface.driver_param = NULL;
3772 if (pos == NULL)
3773 break;
3774
3775 iface.bridge_ifname = pos;
3776 pos = os_strchr(pos, '\t');
3777 if (pos)
3778 *pos++ = '\0';
3779 if (iface.bridge_ifname[0] == '\0')
3780 iface.bridge_ifname = NULL;
3781 if (pos == NULL)
3782 break;
3783 } while (0);
3784
3785 if (wpa_supplicant_get_iface(global, iface.ifname))
3786 return -1;
3787
3788 return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
3789}
3790
3791
3792static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
3793 char *cmd)
3794{
3795 struct wpa_supplicant *wpa_s;
3796
3797 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
3798
3799 wpa_s = wpa_supplicant_get_iface(global, cmd);
3800 if (wpa_s == NULL)
3801 return -1;
3802 return wpa_supplicant_remove_iface(global, wpa_s);
3803}
3804
3805
4b4a8ae5
JM
3806static void wpa_free_iface_info(struct wpa_interface_info *iface)
3807{
3808 struct wpa_interface_info *prev;
3809
3810 while (iface) {
3811 prev = iface;
3812 iface = iface->next;
3813
3814 os_free(prev->ifname);
3815 os_free(prev->desc);
3816 os_free(prev);
3817 }
3818}
3819
3820
3821static int wpa_supplicant_global_iface_list(struct wpa_global *global,
3822 char *buf, int len)
3823{
3824 int i, res;
3825 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
3826 char *pos, *end;
3827
c5121837
JM
3828 for (i = 0; wpa_drivers[i]; i++) {
3829 struct wpa_driver_ops *drv = wpa_drivers[i];
4b4a8ae5
JM
3830 if (drv->get_interfaces == NULL)
3831 continue;
5fbc1f27 3832 tmp = drv->get_interfaces(global->drv_priv[i]);
4b4a8ae5
JM
3833 if (tmp == NULL)
3834 continue;
3835
3836 if (last == NULL)
3837 iface = last = tmp;
3838 else
3839 last->next = tmp;
3840 while (last->next)
3841 last = last->next;
3842 }
3843
3844 pos = buf;
3845 end = buf + len;
3846 for (tmp = iface; tmp; tmp = tmp->next) {
3847 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
3848 tmp->drv_name, tmp->ifname,
3849 tmp->desc ? tmp->desc : "");
3850 if (res < 0 || res >= end - pos) {
3851 *pos = '\0';
3852 break;
3853 }
3854 pos += res;
3855 }
3856
3857 wpa_free_iface_info(iface);
3858
3859 return pos - buf;
3860}
3861
3862
6fc6879b
JM
3863static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
3864 char *buf, int len)
3865{
3866 int res;
3867 char *pos, *end;
3868 struct wpa_supplicant *wpa_s;
3869
3870 wpa_s = global->ifaces;
3871 pos = buf;
3872 end = buf + len;
3873
3874 while (wpa_s) {
3875 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
3876 if (res < 0 || res >= end - pos) {
3877 *pos = '\0';
3878 break;
3879 }
3880 pos += res;
3881 wpa_s = wpa_s->next;
3882 }
3883 return pos - buf;
3884}
3885
3886
3887char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
3888 char *buf, size_t *resp_len)
3889{
3890 char *reply;
3891 const int reply_size = 2048;
3892 int reply_len;
f4a0a82c 3893 int level = MSG_DEBUG;
6fc6879b 3894
f4a0a82c
JM
3895 if (os_strcmp(buf, "PING") == 0)
3896 level = MSG_EXCESSIVE;
3897 wpa_hexdump_ascii(level, "RX global ctrl_iface",
6fc6879b
JM
3898 (const u8 *) buf, os_strlen(buf));
3899
3900 reply = os_malloc(reply_size);
3901 if (reply == NULL) {
3902 *resp_len = 1;
3903 return NULL;
3904 }
3905
3906 os_memcpy(reply, "OK\n", 3);
3907 reply_len = 3;
3908
3909 if (os_strcmp(buf, "PING") == 0) {
3910 os_memcpy(reply, "PONG\n", 5);
3911 reply_len = 5;
3912 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
3913 if (wpa_supplicant_global_iface_add(global, buf + 14))
3914 reply_len = -1;
3915 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
3916 if (wpa_supplicant_global_iface_remove(global, buf + 17))
3917 reply_len = -1;
4b4a8ae5
JM
3918 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
3919 reply_len = wpa_supplicant_global_iface_list(
3920 global, reply, reply_size);
6fc6879b
JM
3921 } else if (os_strcmp(buf, "INTERFACES") == 0) {
3922 reply_len = wpa_supplicant_global_iface_interfaces(
3923 global, reply, reply_size);
3924 } else if (os_strcmp(buf, "TERMINATE") == 0) {
1a1bf008 3925 wpa_supplicant_terminate_proc(global);
207ef3fb
JM
3926 } else if (os_strcmp(buf, "SUSPEND") == 0) {
3927 wpas_notify_suspend(global);
3928 } else if (os_strcmp(buf, "RESUME") == 0) {
3929 wpas_notify_resume(global);
6fc6879b
JM
3930 } else {
3931 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
3932 reply_len = 16;
3933 }
3934
3935 if (reply_len < 0) {
3936 os_memcpy(reply, "FAIL\n", 5);
3937 reply_len = 5;
3938 }
3939
3940 *resp_len = reply_len;
3941 return reply;
3942}