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