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