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