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