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