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