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