]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/ctrl_iface.c
P2P: Optimize scan timeouts for group formation
[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"
8bac466b 34#include "notify.h"
3a068632 35#include "bss.h"
9ba9fa07 36#include "scan.h"
3a068632 37#include "ctrl_iface.h"
6fc6879b 38
c5121837 39extern struct wpa_driver_ops *wpa_drivers[];
2d5b792d 40
4b4a8ae5
JM
41static int wpa_supplicant_global_iface_list(struct wpa_global *global,
42 char *buf, int len);
6fc6879b
JM
43static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
44 char *buf, int len);
45
46
47static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
48 char *cmd)
49{
50 char *value;
51 int ret = 0;
52
53 value = os_strchr(cmd, ' ');
54 if (value == NULL)
55 return -1;
56 *value++ = '\0';
57
58 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
59 if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
60 eapol_sm_configure(wpa_s->eapol,
61 atoi(value), -1, -1, -1);
62 } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
63 eapol_sm_configure(wpa_s->eapol,
64 -1, atoi(value), -1, -1);
65 } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
66 eapol_sm_configure(wpa_s->eapol,
67 -1, -1, atoi(value), -1);
68 } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
69 eapol_sm_configure(wpa_s->eapol,
70 -1, -1, -1, atoi(value));
71 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
72 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
73 atoi(value)))
74 ret = -1;
75 } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
76 0) {
77 if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
78 atoi(value)))
79 ret = -1;
80 } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
81 if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
82 ret = -1;
42f50264
JM
83 } else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
84 wpa_s->wps_fragment_size = atoi(value);
611aea7d
JM
85 } else {
86 value[-1] = '=';
87 ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
88 if (ret == 0)
89 wpa_supplicant_update_config(wpa_s);
90 }
6fc6879b
JM
91
92 return ret;
93}
94
95
ec717917 96#ifdef IEEE8021X_EAPOL
6fc6879b
JM
97static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
98 char *addr)
99{
100 u8 bssid[ETH_ALEN];
101 struct wpa_ssid *ssid = wpa_s->current_ssid;
102
103 if (hwaddr_aton(addr, bssid)) {
104 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
105 "'%s'", addr);
106 return -1;
107 }
108
109 wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
110 rsn_preauth_deinit(wpa_s->wpa);
111 if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
112 return -1;
113
114 return 0;
115}
ec717917 116#endif /* IEEE8021X_EAPOL */
6fc6879b
JM
117
118
119#ifdef CONFIG_PEERKEY
120/* MLME-STKSTART.request(peer) */
121static int wpa_supplicant_ctrl_iface_stkstart(
122 struct wpa_supplicant *wpa_s, char *addr)
123{
124 u8 peer[ETH_ALEN];
125
126 if (hwaddr_aton(addr, peer)) {
127 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
a7b6c422 128 "address '%s'", addr);
6fc6879b
JM
129 return -1;
130 }
131
132 wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
133 MAC2STR(peer));
134
135 return wpa_sm_stkstart(wpa_s->wpa, peer);
136}
137#endif /* CONFIG_PEERKEY */
138
139
140#ifdef CONFIG_IEEE80211R
141static int wpa_supplicant_ctrl_iface_ft_ds(
142 struct wpa_supplicant *wpa_s, char *addr)
143{
144 u8 target_ap[ETH_ALEN];
76b7981d
JM
145 struct wpa_bss *bss;
146 const u8 *mdie;
6fc6879b
JM
147
148 if (hwaddr_aton(addr, target_ap)) {
149 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
a7b6c422 150 "address '%s'", addr);
6fc6879b
JM
151 return -1;
152 }
153
154 wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
155
76b7981d
JM
156 bss = wpa_bss_get_bssid(wpa_s, target_ap);
157 if (bss)
158 mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
159 else
160 mdie = NULL;
161
162 return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
6fc6879b
JM
163}
164#endif /* CONFIG_IEEE80211R */
165
166
fcc60db4
JM
167#ifdef CONFIG_WPS
168static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
169 char *cmd)
170{
3ec97afe 171 u8 bssid[ETH_ALEN], *_bssid = bssid;
fcc60db4
JM
172
173 if (cmd == NULL || os_strcmp(cmd, "any") == 0)
3ec97afe
JM
174 _bssid = NULL;
175 else if (hwaddr_aton(cmd, bssid)) {
fcc60db4
JM
176 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
177 cmd);
178 return -1;
179 }
180
3ec97afe
JM
181#ifdef CONFIG_AP
182 if (wpa_s->ap_iface)
183 return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid);
184#endif /* CONFIG_AP */
185
9fa243b2 186 return wpas_wps_start_pbc(wpa_s, _bssid, 0);
fcc60db4
JM
187}
188
189
190static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
191 char *cmd, char *buf,
192 size_t buflen)
193{
194 u8 bssid[ETH_ALEN], *_bssid = bssid;
195 char *pin;
196 int ret;
197
198 pin = os_strchr(cmd, ' ');
199 if (pin)
200 *pin++ = '\0';
201
202 if (os_strcmp(cmd, "any") == 0)
203 _bssid = NULL;
204 else if (hwaddr_aton(cmd, bssid)) {
3c1e2765 205 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
fcc60db4
JM
206 cmd);
207 return -1;
208 }
209
3ec97afe
JM
210#ifdef CONFIG_AP
211 if (wpa_s->ap_iface)
212 return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
213 buf, buflen);
214#endif /* CONFIG_AP */
215
fcc60db4 216 if (pin) {
9fa243b2 217 ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0);
fcc60db4
JM
218 if (ret < 0)
219 return -1;
220 ret = os_snprintf(buf, buflen, "%s", pin);
221 if (ret < 0 || (size_t) ret >= buflen)
222 return -1;
223 return ret;
224 }
225
9fa243b2 226 ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0);
fcc60db4
JM
227 if (ret < 0)
228 return -1;
229
230 /* Return the generated PIN */
231 ret = os_snprintf(buf, buflen, "%08d", ret);
232 if (ret < 0 || (size_t) ret >= buflen)
233 return -1;
234 return ret;
235}
236
237
116f7bb0 238#ifdef CONFIG_WPS_OOB
46bdb83a
MH
239static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
240 char *cmd)
241{
e1ee6b60 242 char *path, *method, *name;
46bdb83a
MH
243
244 path = os_strchr(cmd, ' ');
245 if (path == NULL)
246 return -1;
247 *path++ = '\0';
248
249 method = os_strchr(path, ' ');
250 if (method == NULL)
251 return -1;
252 *method++ = '\0';
253
e1ee6b60
MH
254 name = os_strchr(method, ' ');
255 if (name != NULL)
256 *name++ = '\0';
257
258 return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
46bdb83a 259}
116f7bb0 260#endif /* CONFIG_WPS_OOB */
46bdb83a
MH
261
262
fcc60db4
JM
263static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
264 char *cmd)
265{
266 u8 bssid[ETH_ALEN], *_bssid = bssid;
267 char *pin;
52eb293d
JM
268 char *new_ssid;
269 char *new_auth;
270 char *new_encr;
271 char *new_key;
272 struct wps_new_ap_settings ap;
fcc60db4
JM
273
274 pin = os_strchr(cmd, ' ');
275 if (pin == NULL)
276 return -1;
277 *pin++ = '\0';
278
279 if (os_strcmp(cmd, "any") == 0)
280 _bssid = NULL;
281 else if (hwaddr_aton(cmd, bssid)) {
282 wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
283 cmd);
284 return -1;
285 }
286
52eb293d
JM
287 new_ssid = os_strchr(pin, ' ');
288 if (new_ssid == NULL)
289 return wpas_wps_start_reg(wpa_s, _bssid, pin, NULL);
290 *new_ssid++ = '\0';
291
292 new_auth = os_strchr(new_ssid, ' ');
293 if (new_auth == NULL)
294 return -1;
295 *new_auth++ = '\0';
296
297 new_encr = os_strchr(new_auth, ' ');
298 if (new_encr == NULL)
299 return -1;
300 *new_encr++ = '\0';
301
302 new_key = os_strchr(new_encr, ' ');
303 if (new_key == NULL)
304 return -1;
305 *new_key++ = '\0';
306
307 os_memset(&ap, 0, sizeof(ap));
308 ap.ssid_hex = new_ssid;
309 ap.auth = new_auth;
310 ap.encr = new_encr;
311 ap.key_hex = new_key;
312 return wpas_wps_start_reg(wpa_s, _bssid, pin, &ap);
fcc60db4 313}
72df2f5f
JM
314
315
316#ifdef CONFIG_WPS_ER
317static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
318 char *cmd)
319{
31fcea93
JM
320 char *uuid = cmd, *pin, *pos;
321 u8 addr_buf[ETH_ALEN], *addr = NULL;
72df2f5f
JM
322 pin = os_strchr(uuid, ' ');
323 if (pin == NULL)
324 return -1;
325 *pin++ = '\0';
31fcea93
JM
326 pos = os_strchr(pin, ' ');
327 if (pos) {
328 *pos++ = '\0';
329 if (hwaddr_aton(pos, addr_buf) == 0)
330 addr = addr_buf;
331 }
332 return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
72df2f5f 333}
e64dcfd5
JM
334
335
336static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
337 char *cmd)
338{
339 char *uuid = cmd, *pin;
340 pin = os_strchr(uuid, ' ');
341 if (pin == NULL)
342 return -1;
343 *pin++ = '\0';
344 return wpas_wps_er_learn(wpa_s, uuid, pin);
345}
7d6640a6
JM
346
347
348static int wpa_supplicant_ctrl_iface_wps_er_config(
349 struct wpa_supplicant *wpa_s, char *cmd)
350{
351 char *pin;
352 char *new_ssid;
353 char *new_auth;
354 char *new_encr;
355 char *new_key;
356 struct wps_new_ap_settings ap;
357
358 pin = os_strchr(cmd, ' ');
359 if (pin == NULL)
360 return -1;
361 *pin++ = '\0';
362
363 new_ssid = os_strchr(pin, ' ');
364 if (new_ssid == NULL)
365 return -1;
366 *new_ssid++ = '\0';
367
368 new_auth = os_strchr(new_ssid, ' ');
369 if (new_auth == NULL)
370 return -1;
371 *new_auth++ = '\0';
372
373 new_encr = os_strchr(new_auth, ' ');
374 if (new_encr == NULL)
375 return -1;
376 *new_encr++ = '\0';
377
378 new_key = os_strchr(new_encr, ' ');
379 if (new_key == NULL)
380 return -1;
381 *new_key++ = '\0';
382
383 os_memset(&ap, 0, sizeof(ap));
384 ap.ssid_hex = new_ssid;
385 ap.auth = new_auth;
386 ap.encr = new_encr;
387 ap.key_hex = new_key;
388 return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
389}
72df2f5f
JM
390#endif /* CONFIG_WPS_ER */
391
fcc60db4
JM
392#endif /* CONFIG_WPS */
393
394
11ef8d35
JM
395#ifdef CONFIG_IBSS_RSN
396static int wpa_supplicant_ctrl_iface_ibss_rsn(
397 struct wpa_supplicant *wpa_s, char *addr)
398{
399 u8 peer[ETH_ALEN];
400
401 if (hwaddr_aton(addr, peer)) {
402 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
a7b6c422 403 "address '%s'", addr);
11ef8d35
JM
404 return -1;
405 }
406
407 wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
408 MAC2STR(peer));
409
410 return ibss_rsn_start(wpa_s->ibss_rsn, peer);
411}
412#endif /* CONFIG_IBSS_RSN */
413
414
6fc6879b
JM
415static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
416 char *rsp)
417{
418#ifdef IEEE8021X_EAPOL
419 char *pos, *id_pos;
420 int id;
421 struct wpa_ssid *ssid;
422 struct eap_peer_config *eap;
423
424 pos = os_strchr(rsp, '-');
425 if (pos == NULL)
426 return -1;
427 *pos++ = '\0';
428 id_pos = pos;
429 pos = os_strchr(pos, ':');
430 if (pos == NULL)
431 return -1;
432 *pos++ = '\0';
433 id = atoi(id_pos);
434 wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
435 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
436 (u8 *) pos, os_strlen(pos));
437
438 ssid = wpa_config_get_network(wpa_s->conf, id);
439 if (ssid == NULL) {
440 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
441 "to update", id);
442 return -1;
443 }
444 eap = &ssid->eap;
445
446 if (os_strcmp(rsp, "IDENTITY") == 0) {
447 os_free(eap->identity);
448 eap->identity = (u8 *) os_strdup(pos);
449 eap->identity_len = os_strlen(pos);
450 eap->pending_req_identity = 0;
451 if (ssid == wpa_s->current_ssid)
452 wpa_s->reassociate = 1;
453 } else if (os_strcmp(rsp, "PASSWORD") == 0) {
454 os_free(eap->password);
455 eap->password = (u8 *) os_strdup(pos);
456 eap->password_len = os_strlen(pos);
457 eap->pending_req_password = 0;
458 if (ssid == wpa_s->current_ssid)
459 wpa_s->reassociate = 1;
460 } else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
461 os_free(eap->new_password);
462 eap->new_password = (u8 *) os_strdup(pos);
463 eap->new_password_len = os_strlen(pos);
464 eap->pending_req_new_password = 0;
465 if (ssid == wpa_s->current_ssid)
466 wpa_s->reassociate = 1;
467 } else if (os_strcmp(rsp, "PIN") == 0) {
468 os_free(eap->pin);
469 eap->pin = os_strdup(pos);
470 eap->pending_req_pin = 0;
471 if (ssid == wpa_s->current_ssid)
472 wpa_s->reassociate = 1;
473 } else if (os_strcmp(rsp, "OTP") == 0) {
474 os_free(eap->otp);
475 eap->otp = (u8 *) os_strdup(pos);
476 eap->otp_len = os_strlen(pos);
477 os_free(eap->pending_req_otp);
478 eap->pending_req_otp = NULL;
479 eap->pending_req_otp_len = 0;
480 } else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
481 os_free(eap->private_key_passwd);
482 eap->private_key_passwd = (u8 *) os_strdup(pos);
483 eap->pending_req_passphrase = 0;
484 if (ssid == wpa_s->current_ssid)
485 wpa_s->reassociate = 1;
486 } else {
487 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
488 return -1;
489 }
490
491 return 0;
492#else /* IEEE8021X_EAPOL */
493 wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
494 return -1;
495#endif /* IEEE8021X_EAPOL */
496}
497
498
499static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
500 const char *params,
501 char *buf, size_t buflen)
502{
503 char *pos, *end, tmp[30];
504 int res, verbose, ret;
505
506 verbose = os_strcmp(params, "-VERBOSE") == 0;
507 pos = buf;
508 end = buf + buflen;
509 if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
510 struct wpa_ssid *ssid = wpa_s->current_ssid;
511 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
512 MAC2STR(wpa_s->bssid));
513 if (ret < 0 || ret >= end - pos)
514 return pos - buf;
515 pos += ret;
516 if (ssid) {
517 u8 *_ssid = ssid->ssid;
518 size_t ssid_len = ssid->ssid_len;
519 u8 ssid_buf[MAX_SSID_LEN];
520 if (ssid_len == 0) {
521 int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
522 if (_res < 0)
523 ssid_len = 0;
524 else
525 ssid_len = _res;
526 _ssid = ssid_buf;
527 }
528 ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
529 wpa_ssid_txt(_ssid, ssid_len),
530 ssid->id);
531 if (ret < 0 || ret >= end - pos)
532 return pos - buf;
533 pos += ret;
534
535 if (ssid->id_str) {
536 ret = os_snprintf(pos, end - pos,
537 "id_str=%s\n",
538 ssid->id_str);
539 if (ret < 0 || ret >= end - pos)
540 return pos - buf;
541 pos += ret;
542 }
0e15e529
JM
543
544 switch (ssid->mode) {
d7dcba70 545 case WPAS_MODE_INFRA:
0e15e529
JM
546 ret = os_snprintf(pos, end - pos,
547 "mode=station\n");
548 break;
d7dcba70 549 case WPAS_MODE_IBSS:
0e15e529
JM
550 ret = os_snprintf(pos, end - pos,
551 "mode=IBSS\n");
552 break;
d7dcba70 553 case WPAS_MODE_AP:
0e15e529
JM
554 ret = os_snprintf(pos, end - pos,
555 "mode=AP\n");
556 break;
2c5d725c
JM
557 case WPAS_MODE_P2P_GO:
558 ret = os_snprintf(pos, end - pos,
559 "mode=P2P GO\n");
560 break;
561 case WPAS_MODE_P2P_GROUP_FORMATION:
562 ret = os_snprintf(pos, end - pos,
563 "mode=P2P GO - group "
564 "formation\n");
565 break;
0e15e529
JM
566 default:
567 ret = 0;
568 break;
569 }
570 if (ret < 0 || ret >= end - pos)
571 return pos - buf;
572 pos += ret;
6fc6879b
JM
573 }
574
43fb5297
JM
575#ifdef CONFIG_AP
576 if (wpa_s->ap_iface) {
577 pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
578 end - pos,
579 verbose);
580 } else
581#endif /* CONFIG_AP */
6fc6879b
JM
582 pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
583 }
584 ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
585 wpa_supplicant_state_txt(wpa_s->wpa_state));
586 if (ret < 0 || ret >= end - pos)
587 return pos - buf;
588 pos += ret;
589
590 if (wpa_s->l2 &&
591 l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
592 ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
593 if (ret < 0 || ret >= end - pos)
594 return pos - buf;
595 pos += ret;
596 }
597
56586197
JM
598 if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
599 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
6fc6879b
JM
600 res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
601 verbose);
602 if (res >= 0)
603 pos += res;
604 }
605
606 res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
607 if (res >= 0)
608 pos += res;
609
610 return pos - buf;
611}
612
613
614static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
615 char *cmd)
616{
617 char *pos;
618 int id;
619 struct wpa_ssid *ssid;
620 u8 bssid[ETH_ALEN];
621
622 /* cmd: "<network id> <BSSID>" */
623 pos = os_strchr(cmd, ' ');
624 if (pos == NULL)
625 return -1;
626 *pos++ = '\0';
627 id = atoi(cmd);
628 wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
629 if (hwaddr_aton(pos, bssid)) {
630 wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
631 return -1;
632 }
633
634 ssid = wpa_config_get_network(wpa_s->conf, id);
635 if (ssid == NULL) {
636 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
637 "to update", id);
638 return -1;
639 }
640
641 os_memcpy(ssid->bssid, bssid, ETH_ALEN);
a8e16edc 642 ssid->bssid_set = !is_zero_ether_addr(bssid);
6fc6879b
JM
643
644 return 0;
645}
646
647
648static int wpa_supplicant_ctrl_iface_list_networks(
649 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
650{
651 char *pos, *end;
652 struct wpa_ssid *ssid;
653 int ret;
654
655 pos = buf;
656 end = buf + buflen;
657 ret = os_snprintf(pos, end - pos,
658 "network id / ssid / bssid / flags\n");
659 if (ret < 0 || ret >= end - pos)
660 return pos - buf;
661 pos += ret;
662
663 ssid = wpa_s->conf->ssid;
664 while (ssid) {
665 ret = os_snprintf(pos, end - pos, "%d\t%s",
666 ssid->id,
667 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
668 if (ret < 0 || ret >= end - pos)
669 return pos - buf;
670 pos += ret;
671 if (ssid->bssid_set) {
672 ret = os_snprintf(pos, end - pos, "\t" MACSTR,
673 MAC2STR(ssid->bssid));
674 } else {
675 ret = os_snprintf(pos, end - pos, "\tany");
676 }
677 if (ret < 0 || ret >= end - pos)
678 return pos - buf;
679 pos += ret;
4dac0245 680 ret = os_snprintf(pos, end - pos, "\t%s%s%s",
6fc6879b
JM
681 ssid == wpa_s->current_ssid ?
682 "[CURRENT]" : "",
4dac0245
JM
683 ssid->disabled ? "[DISABLED]" : "",
684 ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
685 "");
6fc6879b
JM
686 if (ret < 0 || ret >= end - pos)
687 return pos - buf;
688 pos += ret;
689 ret = os_snprintf(pos, end - pos, "\n");
690 if (ret < 0 || ret >= end - pos)
691 return pos - buf;
692 pos += ret;
693
694 ssid = ssid->next;
695 }
696
697 return pos - buf;
698}
699
700
701static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
702{
703 int first = 1, ret;
704 ret = os_snprintf(pos, end - pos, "-");
705 if (ret < 0 || ret >= end - pos)
706 return pos;
707 pos += ret;
708 if (cipher & WPA_CIPHER_NONE) {
709 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
710 if (ret < 0 || ret >= end - pos)
711 return pos;
712 pos += ret;
713 first = 0;
714 }
715 if (cipher & WPA_CIPHER_WEP40) {
716 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
717 if (ret < 0 || ret >= end - pos)
718 return pos;
719 pos += ret;
720 first = 0;
721 }
722 if (cipher & WPA_CIPHER_WEP104) {
723 ret = os_snprintf(pos, end - pos, "%sWEP104",
724 first ? "" : "+");
725 if (ret < 0 || ret >= end - pos)
726 return pos;
727 pos += ret;
728 first = 0;
729 }
730 if (cipher & WPA_CIPHER_TKIP) {
731 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
732 if (ret < 0 || ret >= end - pos)
733 return pos;
734 pos += ret;
735 first = 0;
736 }
737 if (cipher & WPA_CIPHER_CCMP) {
738 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
739 if (ret < 0 || ret >= end - pos)
740 return pos;
741 pos += ret;
742 first = 0;
743 }
744 return pos;
745}
746
747
748static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
749 const u8 *ie, size_t ie_len)
750{
751 struct wpa_ie_data data;
752 int first, ret;
753
754 ret = os_snprintf(pos, end - pos, "[%s-", proto);
755 if (ret < 0 || ret >= end - pos)
756 return pos;
757 pos += ret;
758
759 if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
760 ret = os_snprintf(pos, end - pos, "?]");
761 if (ret < 0 || ret >= end - pos)
762 return pos;
763 pos += ret;
764 return pos;
765 }
766
767 first = 1;
768 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
769 ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
770 if (ret < 0 || ret >= end - pos)
771 return pos;
772 pos += ret;
773 first = 0;
774 }
775 if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
776 ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
777 if (ret < 0 || ret >= end - pos)
778 return pos;
779 pos += ret;
780 first = 0;
781 }
782 if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
783 ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
784 if (ret < 0 || ret >= end - pos)
785 return pos;
786 pos += ret;
787 first = 0;
788 }
789#ifdef CONFIG_IEEE80211R
790 if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
791 ret = os_snprintf(pos, end - pos, "%sFT/EAP",
792 first ? "" : "+");
793 if (ret < 0 || ret >= end - pos)
794 return pos;
795 pos += ret;
796 first = 0;
797 }
798 if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
799 ret = os_snprintf(pos, end - pos, "%sFT/PSK",
800 first ? "" : "+");
801 if (ret < 0 || ret >= end - pos)
802 return pos;
803 pos += ret;
804 first = 0;
805 }
806#endif /* CONFIG_IEEE80211R */
56586197
JM
807#ifdef CONFIG_IEEE80211W
808 if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
809 ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
810 first ? "" : "+");
811 if (ret < 0 || ret >= end - pos)
812 return pos;
813 pos += ret;
814 first = 0;
815 }
816 if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
817 ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
818 first ? "" : "+");
819 if (ret < 0 || ret >= end - pos)
820 return pos;
821 pos += ret;
822 first = 0;
823 }
824#endif /* CONFIG_IEEE80211W */
6fc6879b
JM
825
826 pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
827
828 if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
829 ret = os_snprintf(pos, end - pos, "-preauth");
830 if (ret < 0 || ret >= end - pos)
831 return pos;
832 pos += ret;
833 }
834
835 ret = os_snprintf(pos, end - pos, "]");
836 if (ret < 0 || ret >= end - pos)
837 return pos;
838 pos += ret;
839
840 return pos;
841}
842
3a068632 843
eef7d7a1 844#ifdef CONFIG_WPS
31fcea93
JM
845static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
846 char *pos, char *end,
3a068632
JM
847 struct wpabuf *wps_ie)
848{
eef7d7a1
JM
849 int ret;
850 const char *txt;
851
eef7d7a1
JM
852 if (wps_ie == NULL)
853 return pos;
eef7d7a1
JM
854 if (wps_is_selected_pbc_registrar(wps_ie))
855 txt = "[WPS-PBC]";
53587ec1 856#ifdef CONFIG_WPS2
31fcea93
JM
857 else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
858 txt = "[WPS-AUTH]";
53587ec1 859#endif /* CONFIG_WPS2 */
eef7d7a1
JM
860 else if (wps_is_selected_pin_registrar(wps_ie))
861 txt = "[WPS-PIN]";
862 else
863 txt = "[WPS]";
864
865 ret = os_snprintf(pos, end - pos, "%s", txt);
866 if (ret >= 0 && ret < end - pos)
867 pos += ret;
868 wpabuf_free(wps_ie);
3a068632
JM
869 return pos;
870}
871#endif /* CONFIG_WPS */
872
873
31fcea93
JM
874static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
875 char *pos, char *end,
16b71ac2 876 const struct wpa_bss *bss)
3a068632
JM
877{
878#ifdef CONFIG_WPS
879 struct wpabuf *wps_ie;
880 wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
31fcea93 881 return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
3a068632 882#else /* CONFIG_WPS */
eef7d7a1 883 return pos;
3a068632 884#endif /* CONFIG_WPS */
eef7d7a1
JM
885}
886
6fc6879b
JM
887
888/* Format one result on one text line into a buffer. */
889static int wpa_supplicant_ctrl_iface_scan_result(
31fcea93 890 struct wpa_supplicant *wpa_s,
16b71ac2 891 const struct wpa_bss *bss, char *buf, size_t buflen)
6fc6879b
JM
892{
893 char *pos, *end;
894 int ret;
895 const u8 *ie, *ie2;
896
897 pos = buf;
898 end = buf + buflen;
899
900 ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
16b71ac2 901 MAC2STR(bss->bssid), bss->freq, bss->level);
6fc6879b
JM
902 if (ret < 0 || ret >= end - pos)
903 return pos - buf;
904 pos += ret;
16b71ac2 905 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
6fc6879b
JM
906 if (ie)
907 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
16b71ac2 908 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
6fc6879b
JM
909 if (ie2)
910 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
31fcea93 911 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
16b71ac2 912 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
6fc6879b
JM
913 ret = os_snprintf(pos, end - pos, "[WEP]");
914 if (ret < 0 || ret >= end - pos)
915 return pos - buf;
916 pos += ret;
917 }
16b71ac2 918 if (bss->caps & IEEE80211_CAP_IBSS) {
6fc6879b
JM
919 ret = os_snprintf(pos, end - pos, "[IBSS]");
920 if (ret < 0 || ret >= end - pos)
921 return pos - buf;
922 pos += ret;
923 }
16b71ac2 924 if (bss->caps & IEEE80211_CAP_ESS) {
bd1af96a
JM
925 ret = os_snprintf(pos, end - pos, "[ESS]");
926 if (ret < 0 || ret >= end - pos)
927 return pos - buf;
928 pos += ret;
929 }
6fc6879b 930
6fc6879b 931 ret = os_snprintf(pos, end - pos, "\t%s",
16b71ac2 932 wpa_ssid_txt(bss->ssid, bss->ssid_len));
6fc6879b
JM
933 if (ret < 0 || ret >= end - pos)
934 return pos - buf;
935 pos += ret;
936
937 ret = os_snprintf(pos, end - pos, "\n");
938 if (ret < 0 || ret >= end - pos)
939 return pos - buf;
940 pos += ret;
941
942 return pos - buf;
943}
944
945
946static int wpa_supplicant_ctrl_iface_scan_results(
947 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
948{
949 char *pos, *end;
16b71ac2 950 struct wpa_bss *bss;
6fc6879b 951 int ret;
6fc6879b
JM
952
953 pos = buf;
954 end = buf + buflen;
955 ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
956 "flags / ssid\n");
957 if (ret < 0 || ret >= end - pos)
958 return pos - buf;
959 pos += ret;
960
16b71ac2 961 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
31fcea93 962 ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
6fc6879b
JM
963 end - pos);
964 if (ret < 0 || ret >= end - pos)
965 return pos - buf;
966 pos += ret;
967 }
968
969 return pos - buf;
970}
971
972
973static int wpa_supplicant_ctrl_iface_select_network(
974 struct wpa_supplicant *wpa_s, char *cmd)
975{
976 int id;
977 struct wpa_ssid *ssid;
978
979 /* cmd: "<network id>" or "any" */
980 if (os_strcmp(cmd, "any") == 0) {
981 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
86b89452
WS
982 ssid = NULL;
983 } else {
984 id = atoi(cmd);
985 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
6fc6879b 986
86b89452
WS
987 ssid = wpa_config_get_network(wpa_s->conf, id);
988 if (ssid == NULL) {
989 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
990 "network id=%d", id);
991 return -1;
992 }
4dac0245
JM
993 if (ssid->disabled == 2) {
994 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
995 "SELECT_NETWORK with persistent P2P group");
996 return -1;
997 }
6fc6879b
JM
998 }
999
86b89452 1000 wpa_supplicant_select_network(wpa_s, ssid);
6fc6879b
JM
1001
1002 return 0;
1003}
1004
1005
1006static int wpa_supplicant_ctrl_iface_enable_network(
1007 struct wpa_supplicant *wpa_s, char *cmd)
1008{
1009 int id;
1010 struct wpa_ssid *ssid;
1011
1012 /* cmd: "<network id>" or "all" */
1013 if (os_strcmp(cmd, "all") == 0) {
1014 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
86b89452
WS
1015 ssid = NULL;
1016 } else {
1017 id = atoi(cmd);
1018 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
6fc6879b 1019
86b89452
WS
1020 ssid = wpa_config_get_network(wpa_s->conf, id);
1021 if (ssid == NULL) {
1022 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
1023 "network id=%d", id);
1024 return -1;
1025 }
4dac0245
JM
1026 if (ssid->disabled == 2) {
1027 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
1028 "ENABLE_NETWORK with persistent P2P group");
1029 return -1;
1030 }
6fc6879b 1031 }
86b89452 1032 wpa_supplicant_enable_network(wpa_s, ssid);
6fc6879b
JM
1033
1034 return 0;
1035}
1036
1037
1038static int wpa_supplicant_ctrl_iface_disable_network(
1039 struct wpa_supplicant *wpa_s, char *cmd)
1040{
1041 int id;
1042 struct wpa_ssid *ssid;
1043
1044 /* cmd: "<network id>" or "all" */
1045 if (os_strcmp(cmd, "all") == 0) {
1046 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
86b89452
WS
1047 ssid = NULL;
1048 } else {
1049 id = atoi(cmd);
1050 wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
6fc6879b 1051
86b89452
WS
1052 ssid = wpa_config_get_network(wpa_s->conf, id);
1053 if (ssid == NULL) {
1054 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
1055 "network id=%d", id);
1056 return -1;
1057 }
4dac0245
JM
1058 if (ssid->disabled == 2) {
1059 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
1060 "DISABLE_NETWORK with persistent P2P "
1061 "group");
1062 return -1;
1063 }
6fc6879b 1064 }
86b89452 1065 wpa_supplicant_disable_network(wpa_s, ssid);
6fc6879b
JM
1066
1067 return 0;
1068}
1069
1070
1071static int wpa_supplicant_ctrl_iface_add_network(
1072 struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1073{
1074 struct wpa_ssid *ssid;
1075 int ret;
1076
1077 wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
1078
1079 ssid = wpa_config_add_network(wpa_s->conf);
1080 if (ssid == NULL)
1081 return -1;
8bac466b
JM
1082
1083 wpas_notify_network_added(wpa_s, ssid);
1084
6fc6879b
JM
1085 ssid->disabled = 1;
1086 wpa_config_set_network_defaults(ssid);
1087
1088 ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
1089 if (ret < 0 || (size_t) ret >= buflen)
1090 return -1;
1091 return ret;
1092}
1093
1094
1095static int wpa_supplicant_ctrl_iface_remove_network(
1096 struct wpa_supplicant *wpa_s, char *cmd)
1097{
1098 int id;
1099 struct wpa_ssid *ssid;
1100
1101 /* cmd: "<network id>" or "all" */
1102 if (os_strcmp(cmd, "all") == 0) {
1103 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
1104 ssid = wpa_s->conf->ssid;
1105 while (ssid) {
8bac466b 1106 struct wpa_ssid *remove_ssid = ssid;
6fc6879b
JM
1107 id = ssid->id;
1108 ssid = ssid->next;
8bac466b 1109 wpas_notify_network_removed(wpa_s, remove_ssid);
6fc6879b
JM
1110 wpa_config_remove_network(wpa_s->conf, id);
1111 }
1112 if (wpa_s->current_ssid) {
1113 eapol_sm_invalidate_cached_session(wpa_s->eapol);
1114 wpa_supplicant_disassociate(wpa_s,
1115 WLAN_REASON_DEAUTH_LEAVING);
1116 }
1117 return 0;
1118 }
1119
1120 id = atoi(cmd);
1121 wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
1122
1123 ssid = wpa_config_get_network(wpa_s->conf, id);
1124 if (ssid == NULL ||
1125 wpa_config_remove_network(wpa_s->conf, id) < 0) {
1126 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1127 "id=%d", id);
1128 return -1;
1129 }
1130
1131 if (ssid == wpa_s->current_ssid) {
1132 /*
1133 * Invalidate the EAP session cache if the current network is
1134 * removed.
1135 */
1136 eapol_sm_invalidate_cached_session(wpa_s->eapol);
1137
1138 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1139 }
1140
1141 return 0;
1142}
1143
1144
1145static int wpa_supplicant_ctrl_iface_set_network(
1146 struct wpa_supplicant *wpa_s, char *cmd)
1147{
1148 int id;
1149 struct wpa_ssid *ssid;
1150 char *name, *value;
1151
1152 /* cmd: "<network id> <variable name> <value>" */
1153 name = os_strchr(cmd, ' ');
1154 if (name == NULL)
1155 return -1;
1156 *name++ = '\0';
1157
1158 value = os_strchr(name, ' ');
1159 if (value == NULL)
1160 return -1;
1161 *value++ = '\0';
1162
1163 id = atoi(cmd);
1164 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
1165 id, name);
1166 wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1167 (u8 *) value, os_strlen(value));
1168
1169 ssid = wpa_config_get_network(wpa_s->conf, id);
1170 if (ssid == NULL) {
1171 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1172 "id=%d", id);
1173 return -1;
1174 }
1175
1176 if (wpa_config_set(ssid, name, value, 0) < 0) {
1177 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
1178 "variable '%s'", name);
1179 return -1;
1180 }
1181
1182 if (wpa_s->current_ssid == ssid) {
1183 /*
1184 * Invalidate the EAP session cache if anything in the current
1185 * configuration changes.
1186 */
1187 eapol_sm_invalidate_cached_session(wpa_s->eapol);
1188 }
1189
1190 if ((os_strcmp(name, "psk") == 0 &&
1191 value[0] == '"' && ssid->ssid_len) ||
1192 (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
1193 wpa_config_update_psk(ssid);
aa53509f
DS
1194 else if (os_strcmp(name, "priority") == 0)
1195 wpa_config_update_prio_list(wpa_s->conf);
6fc6879b
JM
1196
1197 return 0;
1198}
1199
1200
1201static int wpa_supplicant_ctrl_iface_get_network(
1202 struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
1203{
1204 int id;
1205 size_t res;
1206 struct wpa_ssid *ssid;
1207 char *name, *value;
1208
1209 /* cmd: "<network id> <variable name>" */
1210 name = os_strchr(cmd, ' ');
1211 if (name == NULL || buflen == 0)
1212 return -1;
1213 *name++ = '\0';
1214
1215 id = atoi(cmd);
1216 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
1217 id, name);
1218
1219 ssid = wpa_config_get_network(wpa_s->conf, id);
1220 if (ssid == NULL) {
1221 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1222 "id=%d", id);
1223 return -1;
1224 }
1225
1226 value = wpa_config_get_no_key(ssid, name);
1227 if (value == NULL) {
1228 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
1229 "variable '%s'", name);
1230 return -1;
1231 }
1232
1233 res = os_strlcpy(buf, value, buflen);
1234 if (res >= buflen) {
1235 os_free(value);
1236 return -1;
1237 }
1238
1239 os_free(value);
1240
1241 return res;
1242}
1243
1244
1245#ifndef CONFIG_NO_CONFIG_WRITE
1246static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
1247{
1248 int ret;
1249
1250 if (!wpa_s->conf->update_config) {
1251 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
1252 "to update configuration (update_config=0)");
1253 return -1;
1254 }
1255
1256 ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
1257 if (ret) {
1258 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
1259 "update configuration");
1260 } else {
1261 wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
1262 " updated");
1263 }
1264
1265 return ret;
1266}
1267#endif /* CONFIG_NO_CONFIG_WRITE */
1268
1269
1270static int ctrl_iface_get_capability_pairwise(int res, char *strict,
1271 struct wpa_driver_capa *capa,
1272 char *buf, size_t buflen)
1273{
1274 int ret, first = 1;
1275 char *pos, *end;
1276 size_t len;
1277
1278 pos = buf;
1279 end = pos + buflen;
1280
1281 if (res < 0) {
1282 if (strict)
1283 return 0;
1284 len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
1285 if (len >= buflen)
1286 return -1;
1287 return len;
1288 }
1289
1290 if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
1291 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
1292 if (ret < 0 || ret >= end - pos)
1293 return pos - buf;
1294 pos += ret;
1295 first = 0;
1296 }
1297
1298 if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
1299 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
1300 if (ret < 0 || ret >= end - pos)
1301 return pos - buf;
1302 pos += ret;
1303 first = 0;
1304 }
1305
1306 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1307 ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
1308 if (ret < 0 || ret >= end - pos)
1309 return pos - buf;
1310 pos += ret;
1311 first = 0;
1312 }
1313
1314 return pos - buf;
1315}
1316
1317
1318static int ctrl_iface_get_capability_group(int res, char *strict,
1319 struct wpa_driver_capa *capa,
1320 char *buf, size_t buflen)
1321{
1322 int ret, first = 1;
1323 char *pos, *end;
1324 size_t len;
1325
1326 pos = buf;
1327 end = pos + buflen;
1328
1329 if (res < 0) {
1330 if (strict)
1331 return 0;
1332 len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
1333 if (len >= buflen)
1334 return -1;
1335 return len;
1336 }
1337
1338 if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
1339 ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
1340 if (ret < 0 || ret >= end - pos)
1341 return pos - buf;
1342 pos += ret;
1343 first = 0;
1344 }
1345
1346 if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
1347 ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
1348 if (ret < 0 || ret >= end - pos)
1349 return pos - buf;
1350 pos += ret;
1351 first = 0;
1352 }
1353
1354 if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
1355 ret = os_snprintf(pos, end - pos, "%sWEP104",
1356 first ? "" : " ");
1357 if (ret < 0 || ret >= end - pos)
1358 return pos - buf;
1359 pos += ret;
1360 first = 0;
1361 }
1362
1363 if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
1364 ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
1365 if (ret < 0 || ret >= end - pos)
1366 return pos - buf;
1367 pos += ret;
1368 first = 0;
1369 }
1370
1371 return pos - buf;
1372}
1373
1374
1375static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
1376 struct wpa_driver_capa *capa,
1377 char *buf, size_t buflen)
1378{
1379 int ret;
1380 char *pos, *end;
1381 size_t len;
1382
1383 pos = buf;
1384 end = pos + buflen;
1385
1386 if (res < 0) {
1387 if (strict)
1388 return 0;
1389 len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
1390 "NONE", buflen);
1391 if (len >= buflen)
1392 return -1;
1393 return len;
1394 }
1395
1396 ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
1397 if (ret < 0 || ret >= end - pos)
1398 return pos - buf;
1399 pos += ret;
1400
1401 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1402 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
1403 ret = os_snprintf(pos, end - pos, " WPA-EAP");
1404 if (ret < 0 || ret >= end - pos)
1405 return pos - buf;
1406 pos += ret;
1407 }
1408
1409 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
1410 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1411 ret = os_snprintf(pos, end - pos, " WPA-PSK");
1412 if (ret < 0 || ret >= end - pos)
1413 return pos - buf;
1414 pos += ret;
1415 }
1416
1417 if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1418 ret = os_snprintf(pos, end - pos, " WPA-NONE");
1419 if (ret < 0 || ret >= end - pos)
1420 return pos - buf;
1421 pos += ret;
1422 }
1423
1424 return pos - buf;
1425}
1426
1427
1428static int ctrl_iface_get_capability_proto(int res, char *strict,
1429 struct wpa_driver_capa *capa,
1430 char *buf, size_t buflen)
1431{
1432 int ret, first = 1;
1433 char *pos, *end;
1434 size_t len;
1435
1436 pos = buf;
1437 end = pos + buflen;
1438
1439 if (res < 0) {
1440 if (strict)
1441 return 0;
1442 len = os_strlcpy(buf, "RSN WPA", buflen);
1443 if (len >= buflen)
1444 return -1;
1445 return len;
1446 }
1447
1448 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1449 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1450 ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
1451 if (ret < 0 || ret >= end - pos)
1452 return pos - buf;
1453 pos += ret;
1454 first = 0;
1455 }
1456
1457 if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1458 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
1459 ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
1460 if (ret < 0 || ret >= end - pos)
1461 return pos - buf;
1462 pos += ret;
1463 first = 0;
1464 }
1465
1466 return pos - buf;
1467}
1468
1469
1470static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
1471 struct wpa_driver_capa *capa,
1472 char *buf, size_t buflen)
1473{
1474 int ret, first = 1;
1475 char *pos, *end;
1476 size_t len;
1477
1478 pos = buf;
1479 end = pos + buflen;
1480
1481 if (res < 0) {
1482 if (strict)
1483 return 0;
1484 len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
1485 if (len >= buflen)
1486 return -1;
1487 return len;
1488 }
1489
1490 if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
1491 ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
1492 if (ret < 0 || ret >= end - pos)
1493 return pos - buf;
1494 pos += ret;
1495 first = 0;
1496 }
1497
1498 if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
1499 ret = os_snprintf(pos, end - pos, "%sSHARED",
1500 first ? "" : " ");
1501 if (ret < 0 || ret >= end - pos)
1502 return pos - buf;
1503 pos += ret;
1504 first = 0;
1505 }
1506
1507 if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
1508 ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
1509 if (ret < 0 || ret >= end - pos)
1510 return pos - buf;
1511 pos += ret;
1512 first = 0;
1513 }
1514
1515 return pos - buf;
1516}
1517
1518
1519static int wpa_supplicant_ctrl_iface_get_capability(
1520 struct wpa_supplicant *wpa_s, const char *_field, char *buf,
1521 size_t buflen)
1522{
1523 struct wpa_driver_capa capa;
1524 int res;
1525 char *strict;
1526 char field[30];
1527 size_t len;
1528
1529 /* Determine whether or not strict checking was requested */
1530 len = os_strlcpy(field, _field, sizeof(field));
1531 if (len >= sizeof(field))
1532 return -1;
1533 strict = os_strchr(field, ' ');
1534 if (strict != NULL) {
1535 *strict++ = '\0';
1536 if (os_strcmp(strict, "strict") != 0)
1537 return -1;
1538 }
1539
1540 wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
1541 field, strict ? strict : "");
1542
1543 if (os_strcmp(field, "eap") == 0) {
1544 return eap_get_names(buf, buflen);
1545 }
1546
1547 res = wpa_drv_get_capa(wpa_s, &capa);
1548
1549 if (os_strcmp(field, "pairwise") == 0)
1550 return ctrl_iface_get_capability_pairwise(res, strict, &capa,
1551 buf, buflen);
1552
1553 if (os_strcmp(field, "group") == 0)
1554 return ctrl_iface_get_capability_group(res, strict, &capa,
1555 buf, buflen);
1556
1557 if (os_strcmp(field, "key_mgmt") == 0)
1558 return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
1559 buf, buflen);
1560
1561 if (os_strcmp(field, "proto") == 0)
1562 return ctrl_iface_get_capability_proto(res, strict, &capa,
1563 buf, buflen);
1564
1565 if (os_strcmp(field, "auth_alg") == 0)
1566 return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
1567 buf, buflen);
1568
1569 wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
1570 field);
1571
1572 return -1;
1573}
1574
1575
1576static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
1577 const char *cmd, char *buf,
1578 size_t buflen)
1579{
1580 u8 bssid[ETH_ALEN];
1581 size_t i;
3a068632 1582 struct wpa_bss *bss;
6fc6879b
JM
1583 int ret;
1584 char *pos, *end;
1585 const u8 *ie, *ie2;
1586
3a068632
JM
1587 if (os_strcmp(cmd, "FIRST") == 0)
1588 bss = dl_list_first(&wpa_s->bss, struct wpa_bss, list);
1589 else if (os_strncmp(cmd, "ID-", 3) == 0) {
1590 i = atoi(cmd + 3);
1591 bss = wpa_bss_get_id(wpa_s, i);
1592 } else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
1593 i = atoi(cmd + 5);
1594 bss = wpa_bss_get_id(wpa_s, i);
1595 if (bss) {
1596 struct dl_list *next = bss->list_id.next;
1597 if (next == &wpa_s->bss_id)
1598 bss = NULL;
1599 else
1600 bss = dl_list_entry(next, struct wpa_bss,
1601 list_id);
6fc6879b 1602 }
3a068632
JM
1603 } else if (hwaddr_aton(cmd, bssid) == 0)
1604 bss = wpa_bss_get_bssid(wpa_s, bssid);
1605 else {
1606 struct wpa_bss *tmp;
6fc6879b 1607 i = atoi(cmd);
3a068632
JM
1608 bss = NULL;
1609 dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
1610 {
1611 if (i-- == 0) {
1612 bss = tmp;
1613 break;
1614 }
1615 }
1616 }
6fc6879b 1617
3a068632
JM
1618 if (bss == NULL)
1619 return 0;
6fc6879b 1620
6fc6879b
JM
1621 pos = buf;
1622 end = buf + buflen;
3fd0b8f1 1623 ret = os_snprintf(pos, end - pos,
3a068632 1624 "id=%u\n"
3fd0b8f1
JM
1625 "bssid=" MACSTR "\n"
1626 "freq=%d\n"
1627 "beacon_int=%d\n"
1628 "capabilities=0x%04x\n"
1629 "qual=%d\n"
1630 "noise=%d\n"
1631 "level=%d\n"
1632 "tsf=%016llu\n"
1633 "ie=",
3a068632 1634 bss->id,
3fd0b8f1
JM
1635 MAC2STR(bss->bssid), bss->freq, bss->beacon_int,
1636 bss->caps, bss->qual, bss->noise, bss->level,
1637 (unsigned long long) bss->tsf);
6fc6879b
JM
1638 if (ret < 0 || ret >= end - pos)
1639 return pos - buf;
1640 pos += ret;
1641
1642 ie = (const u8 *) (bss + 1);
1643 for (i = 0; i < bss->ie_len; i++) {
3fd0b8f1 1644 ret = os_snprintf(pos, end - pos, "%02x", *ie++);
6fc6879b
JM
1645 if (ret < 0 || ret >= end - pos)
1646 return pos - buf;
1647 pos += ret;
1648 }
1649
3fd0b8f1 1650 ret = os_snprintf(pos, end - pos, "\n");
6fc6879b
JM
1651 if (ret < 0 || ret >= end - pos)
1652 return pos - buf;
1653 pos += ret;
1654
1655 ret = os_snprintf(pos, end - pos, "flags=");
1656 if (ret < 0 || ret >= end - pos)
1657 return pos - buf;
1658 pos += ret;
1659
3a068632 1660 ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
6fc6879b
JM
1661 if (ie)
1662 pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
3a068632 1663 ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
6fc6879b
JM
1664 if (ie2)
1665 pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
31fcea93 1666 pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
6fc6879b
JM
1667 if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
1668 ret = os_snprintf(pos, end - pos, "[WEP]");
1669 if (ret < 0 || ret >= end - pos)
1670 return pos - buf;
1671 pos += ret;
1672 }
1673 if (bss->caps & IEEE80211_CAP_IBSS) {
1674 ret = os_snprintf(pos, end - pos, "[IBSS]");
1675 if (ret < 0 || ret >= end - pos)
1676 return pos - buf;
1677 pos += ret;
1678 }
bd1af96a
JM
1679 if (bss->caps & IEEE80211_CAP_ESS) {
1680 ret = os_snprintf(pos, end - pos, "[ESS]");
1681 if (ret < 0 || ret >= end - pos)
1682 return pos - buf;
1683 pos += ret;
1684 }
6fc6879b 1685
3fd0b8f1 1686 ret = os_snprintf(pos, end - pos, "\n");
6fc6879b
JM
1687 if (ret < 0 || ret >= end - pos)
1688 return pos - buf;
1689 pos += ret;
1690
6fc6879b 1691 ret = os_snprintf(pos, end - pos, "ssid=%s\n",
3a068632 1692 wpa_ssid_txt(bss->ssid, bss->ssid_len));
6fc6879b
JM
1693 if (ret < 0 || ret >= end - pos)
1694 return pos - buf;
1695 pos += ret;
1696
611ed491
JM
1697#ifdef CONFIG_WPS
1698 ie = (const u8 *) (bss + 1);
1699 ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
1700 if (ret < 0 || ret >= end - pos)
1701 return pos - buf;
1702 pos += ret;
1703#endif /* CONFIG_WPS */
1704
6fc6879b
JM
1705 return pos - buf;
1706}
1707
1708
1709static int wpa_supplicant_ctrl_iface_ap_scan(
1710 struct wpa_supplicant *wpa_s, char *cmd)
1711{
1712 int ap_scan = atoi(cmd);
86b89452 1713 return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
6fc6879b
JM
1714}
1715
1716
32d5295f
JM
1717static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
1718{
1719 u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
1720
1721 wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
1722 /* MLME-DELETEKEYS.request */
1723 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0);
1724 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
1725 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
1726 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
1727#ifdef CONFIG_IEEE80211W
1728 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
1729 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
1730#endif /* CONFIG_IEEE80211W */
1731
1732 wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
1733 0);
1734 /* MLME-SETPROTECTION.request(None) */
1735 wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
1736 MLME_SETPROTECTION_PROTECT_TYPE_NONE,
1737 MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
1738 wpa_sm_drop_sa(wpa_s->wpa);
1739}
1740
1741
86d4f806
JM
1742static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
1743 char *addr)
1744{
1745 u8 bssid[ETH_ALEN];
1746 struct wpa_bss *bss;
1747 struct wpa_ssid *ssid = wpa_s->current_ssid;
1748
1749 if (hwaddr_aton(addr, bssid)) {
1750 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
1751 "address '%s'", addr);
1752 return -1;
1753 }
1754
1755 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
1756
1757 bss = wpa_bss_get_bssid(wpa_s, bssid);
1758 if (!bss) {
1759 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
1760 "from BSS table");
1761 return -1;
1762 }
1763
1764 /*
1765 * TODO: Find best network configuration block from configuration to
1766 * allow roaming to other networks
1767 */
1768
1769 if (!ssid) {
1770 wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
1771 "configuration known for the target AP");
1772 return -1;
1773 }
1774
1775 wpa_s->reassociate = 1;
1776 wpa_supplicant_connect(wpa_s, bss, ssid);
1777
1778 return 0;
1779}
1780
1781
6fc6879b
JM
1782char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
1783 char *buf, size_t *resp_len)
1784{
1785 char *reply;
1786 const int reply_size = 2048;
1787 int ctrl_rsp = 0;
1788 int reply_len;
1789
1790 if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
1791 os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1792 wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
1793 (const u8 *) buf, os_strlen(buf));
1794 } else {
1795 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface",
1796 (const u8 *) buf, os_strlen(buf));
1797 }
1798
1799 reply = os_malloc(reply_size);
1800 if (reply == NULL) {
1801 *resp_len = 1;
1802 return NULL;
1803 }
1804
1805 os_memcpy(reply, "OK\n", 3);
1806 reply_len = 3;
1807
1808 if (os_strcmp(buf, "PING") == 0) {
1809 os_memcpy(reply, "PONG\n", 5);
1810 reply_len = 5;
77895cd9
JM
1811 } else if (os_strncmp(buf, "NOTE ", 5) == 0) {
1812 wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
6fc6879b
JM
1813 } else if (os_strcmp(buf, "MIB") == 0) {
1814 reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
1815 if (reply_len >= 0) {
1816 int res;
1817 res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
1818 reply_size - reply_len);
1819 if (res < 0)
1820 reply_len = -1;
1821 else
1822 reply_len += res;
1823 }
1824 } else if (os_strncmp(buf, "STATUS", 6) == 0) {
1825 reply_len = wpa_supplicant_ctrl_iface_status(
1826 wpa_s, buf + 6, reply, reply_size);
1827 } else if (os_strcmp(buf, "PMKSA") == 0) {
540264a7
JM
1828 reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
1829 reply_size);
6fc6879b
JM
1830 } else if (os_strncmp(buf, "SET ", 4) == 0) {
1831 if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
1832 reply_len = -1;
1833 } else if (os_strcmp(buf, "LOGON") == 0) {
1834 eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
1835 } else if (os_strcmp(buf, "LOGOFF") == 0) {
1836 eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
1837 } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
8401a6b0
JM
1838 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
1839 reply_len = -1;
1840 else {
1841 wpa_s->disconnected = 0;
1842 wpa_s->reassociate = 1;
1843 wpa_supplicant_req_scan(wpa_s, 0, 0);
1844 }
6fc6879b 1845 } else if (os_strcmp(buf, "RECONNECT") == 0) {
8401a6b0
JM
1846 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
1847 reply_len = -1;
1848 else if (wpa_s->disconnected) {
6fc6879b
JM
1849 wpa_s->disconnected = 0;
1850 wpa_s->reassociate = 1;
1851 wpa_supplicant_req_scan(wpa_s, 0, 0);
1852 }
ec717917 1853#ifdef IEEE8021X_EAPOL
6fc6879b
JM
1854 } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
1855 if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
1856 reply_len = -1;
ec717917 1857#endif /* IEEE8021X_EAPOL */
6fc6879b
JM
1858#ifdef CONFIG_PEERKEY
1859 } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
1860 if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
1861 reply_len = -1;
1862#endif /* CONFIG_PEERKEY */
1863#ifdef CONFIG_IEEE80211R
1864 } else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
1865 if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
1866 reply_len = -1;
1867#endif /* CONFIG_IEEE80211R */
fcc60db4
JM
1868#ifdef CONFIG_WPS
1869 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
1870 if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL))
1871 reply_len = -1;
1872 } else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
1873 if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8))
1874 reply_len = -1;
1875 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
1876 reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
1877 reply,
1878 reply_size);
116f7bb0 1879#ifdef CONFIG_WPS_OOB
46bdb83a
MH
1880 } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
1881 if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
1882 reply_len = -1;
116f7bb0 1883#endif /* CONFIG_WPS_OOB */
fcc60db4
JM
1884 } else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
1885 if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
1886 reply_len = -1;
72df2f5f 1887#ifdef CONFIG_WPS_ER
e9bcfebf 1888 } else if (os_strcmp(buf, "WPS_ER_START") == 0) {
08486685
JM
1889 if (wpas_wps_er_start(wpa_s, NULL))
1890 reply_len = -1;
1891 } else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
1892 if (wpas_wps_er_start(wpa_s, buf + 13))
e9bcfebf
JM
1893 reply_len = -1;
1894 } else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
1895 if (wpas_wps_er_stop(wpa_s))
1896 reply_len = -1;
72df2f5f
JM
1897 } else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
1898 if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
1899 reply_len = -1;
564cd7fa
JM
1900 } else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
1901 if (wpas_wps_er_pbc(wpa_s, buf + 11))
1902 reply_len = -1;
e64dcfd5
JM
1903 } else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
1904 if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
1905 reply_len = -1;
7d6640a6
JM
1906 } else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
1907 if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
1908 reply_len = -1;
72df2f5f 1909#endif /* CONFIG_WPS_ER */
fcc60db4 1910#endif /* CONFIG_WPS */
11ef8d35
JM
1911#ifdef CONFIG_IBSS_RSN
1912 } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
1913 if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
1914 reply_len = -1;
1915#endif /* CONFIG_IBSS_RSN */
6fc6879b
JM
1916 } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
1917 {
1918 if (wpa_supplicant_ctrl_iface_ctrl_rsp(
1919 wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
1920 reply_len = -1;
1921 else
1922 ctrl_rsp = 1;
1923 } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
1924 if (wpa_supplicant_reload_configuration(wpa_s))
1925 reply_len = -1;
1926 } else if (os_strcmp(buf, "TERMINATE") == 0) {
1a1bf008 1927 wpa_supplicant_terminate_proc(wpa_s->global);
6fc6879b
JM
1928 } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
1929 if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
1930 reply_len = -1;
1931 } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
1932 reply_len = wpa_supplicant_ctrl_iface_list_networks(
1933 wpa_s, reply, reply_size);
1934 } else if (os_strcmp(buf, "DISCONNECT") == 0) {
1935 wpa_s->reassociate = 0;
1936 wpa_s->disconnected = 1;
cf4783e3
JM
1937 wpa_supplicant_deauthenticate(wpa_s,
1938 WLAN_REASON_DEAUTH_LEAVING);
6fc6879b 1939 } else if (os_strcmp(buf, "SCAN") == 0) {
8401a6b0
JM
1940 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
1941 reply_len = -1;
1942 else {
1943 wpa_s->scan_req = 2;
1944 wpa_supplicant_req_scan(wpa_s, 0, 0);
1945 }
6fc6879b
JM
1946 } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
1947 reply_len = wpa_supplicant_ctrl_iface_scan_results(
1948 wpa_s, reply, reply_size);
1949 } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
1950 if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
1951 reply_len = -1;
1952 } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
1953 if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
1954 reply_len = -1;
1955 } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
1956 if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
1957 reply_len = -1;
1958 } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
1959 reply_len = wpa_supplicant_ctrl_iface_add_network(
1960 wpa_s, reply, reply_size);
1961 } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
1962 if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
1963 reply_len = -1;
1964 } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1965 if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
1966 reply_len = -1;
1967 } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
1968 reply_len = wpa_supplicant_ctrl_iface_get_network(
1969 wpa_s, buf + 12, reply, reply_size);
1970#ifndef CONFIG_NO_CONFIG_WRITE
1971 } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
1972 if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
1973 reply_len = -1;
1974#endif /* CONFIG_NO_CONFIG_WRITE */
1975 } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
1976 reply_len = wpa_supplicant_ctrl_iface_get_capability(
1977 wpa_s, buf + 15, reply, reply_size);
1978 } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
1979 if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
1980 reply_len = -1;
4b4a8ae5
JM
1981 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
1982 reply_len = wpa_supplicant_global_iface_list(
1983 wpa_s->global, reply, reply_size);
6fc6879b
JM
1984 } else if (os_strcmp(buf, "INTERFACES") == 0) {
1985 reply_len = wpa_supplicant_global_iface_interfaces(
1986 wpa_s->global, reply, reply_size);
1987 } else if (os_strncmp(buf, "BSS ", 4) == 0) {
1988 reply_len = wpa_supplicant_ctrl_iface_bss(
1989 wpa_s, buf + 4, reply, reply_size);
e653b622
JM
1990#ifdef CONFIG_AP
1991 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
1992 reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
1993 } else if (os_strncmp(buf, "STA ", 4) == 0) {
1994 reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
1995 reply_size);
1996 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
1997 reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
1998 reply_size);
1999#endif /* CONFIG_AP */
207ef3fb
JM
2000 } else if (os_strcmp(buf, "SUSPEND") == 0) {
2001 wpas_notify_suspend(wpa_s->global);
2002 } else if (os_strcmp(buf, "RESUME") == 0) {
2003 wpas_notify_resume(wpa_s->global);
32d5295f
JM
2004 } else if (os_strcmp(buf, "DROP_SA") == 0) {
2005 wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
86d4f806
JM
2006 } else if (os_strncmp(buf, "ROAM ", 5) == 0) {
2007 if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
2008 reply_len = -1;
6fc6879b
JM
2009 } else {
2010 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
2011 reply_len = 16;
2012 }
2013
2014 if (reply_len < 0) {
2015 os_memcpy(reply, "FAIL\n", 5);
2016 reply_len = 5;
2017 }
2018
2019 if (ctrl_rsp)
2020 eapol_sm_notify_ctrl_response(wpa_s->eapol);
2021
2022 *resp_len = reply_len;
2023 return reply;
2024}
2025
2026
2027static int wpa_supplicant_global_iface_add(struct wpa_global *global,
2028 char *cmd)
2029{
2030 struct wpa_interface iface;
2031 char *pos;
2032
2033 /*
2034 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
2035 * TAB<bridge_ifname>
2036 */
2037 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
2038
2039 os_memset(&iface, 0, sizeof(iface));
2040
2041 do {
2042 iface.ifname = pos = cmd;
2043 pos = os_strchr(pos, '\t');
2044 if (pos)
2045 *pos++ = '\0';
2046 if (iface.ifname[0] == '\0')
2047 return -1;
2048 if (pos == NULL)
2049 break;
2050
2051 iface.confname = pos;
2052 pos = os_strchr(pos, '\t');
2053 if (pos)
2054 *pos++ = '\0';
2055 if (iface.confname[0] == '\0')
2056 iface.confname = NULL;
2057 if (pos == NULL)
2058 break;
2059
2060 iface.driver = pos;
2061 pos = os_strchr(pos, '\t');
2062 if (pos)
2063 *pos++ = '\0';
2064 if (iface.driver[0] == '\0')
2065 iface.driver = NULL;
2066 if (pos == NULL)
2067 break;
2068
2069 iface.ctrl_interface = pos;
2070 pos = os_strchr(pos, '\t');
2071 if (pos)
2072 *pos++ = '\0';
2073 if (iface.ctrl_interface[0] == '\0')
2074 iface.ctrl_interface = NULL;
2075 if (pos == NULL)
2076 break;
2077
2078 iface.driver_param = pos;
2079 pos = os_strchr(pos, '\t');
2080 if (pos)
2081 *pos++ = '\0';
2082 if (iface.driver_param[0] == '\0')
2083 iface.driver_param = NULL;
2084 if (pos == NULL)
2085 break;
2086
2087 iface.bridge_ifname = pos;
2088 pos = os_strchr(pos, '\t');
2089 if (pos)
2090 *pos++ = '\0';
2091 if (iface.bridge_ifname[0] == '\0')
2092 iface.bridge_ifname = NULL;
2093 if (pos == NULL)
2094 break;
2095 } while (0);
2096
2097 if (wpa_supplicant_get_iface(global, iface.ifname))
2098 return -1;
2099
2100 return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
2101}
2102
2103
2104static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
2105 char *cmd)
2106{
2107 struct wpa_supplicant *wpa_s;
2108
2109 wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
2110
2111 wpa_s = wpa_supplicant_get_iface(global, cmd);
2112 if (wpa_s == NULL)
2113 return -1;
2114 return wpa_supplicant_remove_iface(global, wpa_s);
2115}
2116
2117
4b4a8ae5
JM
2118static void wpa_free_iface_info(struct wpa_interface_info *iface)
2119{
2120 struct wpa_interface_info *prev;
2121
2122 while (iface) {
2123 prev = iface;
2124 iface = iface->next;
2125
2126 os_free(prev->ifname);
2127 os_free(prev->desc);
2128 os_free(prev);
2129 }
2130}
2131
2132
2133static int wpa_supplicant_global_iface_list(struct wpa_global *global,
2134 char *buf, int len)
2135{
2136 int i, res;
2137 struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
2138 char *pos, *end;
2139
c5121837
JM
2140 for (i = 0; wpa_drivers[i]; i++) {
2141 struct wpa_driver_ops *drv = wpa_drivers[i];
4b4a8ae5
JM
2142 if (drv->get_interfaces == NULL)
2143 continue;
5fbc1f27 2144 tmp = drv->get_interfaces(global->drv_priv[i]);
4b4a8ae5
JM
2145 if (tmp == NULL)
2146 continue;
2147
2148 if (last == NULL)
2149 iface = last = tmp;
2150 else
2151 last->next = tmp;
2152 while (last->next)
2153 last = last->next;
2154 }
2155
2156 pos = buf;
2157 end = buf + len;
2158 for (tmp = iface; tmp; tmp = tmp->next) {
2159 res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
2160 tmp->drv_name, tmp->ifname,
2161 tmp->desc ? tmp->desc : "");
2162 if (res < 0 || res >= end - pos) {
2163 *pos = '\0';
2164 break;
2165 }
2166 pos += res;
2167 }
2168
2169 wpa_free_iface_info(iface);
2170
2171 return pos - buf;
2172}
2173
2174
6fc6879b
JM
2175static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
2176 char *buf, int len)
2177{
2178 int res;
2179 char *pos, *end;
2180 struct wpa_supplicant *wpa_s;
2181
2182 wpa_s = global->ifaces;
2183 pos = buf;
2184 end = buf + len;
2185
2186 while (wpa_s) {
2187 res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
2188 if (res < 0 || res >= end - pos) {
2189 *pos = '\0';
2190 break;
2191 }
2192 pos += res;
2193 wpa_s = wpa_s->next;
2194 }
2195 return pos - buf;
2196}
2197
2198
2199char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
2200 char *buf, size_t *resp_len)
2201{
2202 char *reply;
2203 const int reply_size = 2048;
2204 int reply_len;
2205
2206 wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
2207 (const u8 *) buf, os_strlen(buf));
2208
2209 reply = os_malloc(reply_size);
2210 if (reply == NULL) {
2211 *resp_len = 1;
2212 return NULL;
2213 }
2214
2215 os_memcpy(reply, "OK\n", 3);
2216 reply_len = 3;
2217
2218 if (os_strcmp(buf, "PING") == 0) {
2219 os_memcpy(reply, "PONG\n", 5);
2220 reply_len = 5;
2221 } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
2222 if (wpa_supplicant_global_iface_add(global, buf + 14))
2223 reply_len = -1;
2224 } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
2225 if (wpa_supplicant_global_iface_remove(global, buf + 17))
2226 reply_len = -1;
4b4a8ae5
JM
2227 } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
2228 reply_len = wpa_supplicant_global_iface_list(
2229 global, reply, reply_size);
6fc6879b
JM
2230 } else if (os_strcmp(buf, "INTERFACES") == 0) {
2231 reply_len = wpa_supplicant_global_iface_interfaces(
2232 global, reply, reply_size);
2233 } else if (os_strcmp(buf, "TERMINATE") == 0) {
1a1bf008 2234 wpa_supplicant_terminate_proc(global);
207ef3fb
JM
2235 } else if (os_strcmp(buf, "SUSPEND") == 0) {
2236 wpas_notify_suspend(global);
2237 } else if (os_strcmp(buf, "RESUME") == 0) {
2238 wpas_notify_resume(global);
6fc6879b
JM
2239 } else {
2240 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
2241 reply_len = 16;
2242 }
2243
2244 if (reply_len < 0) {
2245 os_memcpy(reply, "FAIL\n", 5);
2246 reply_len = 5;
2247 }
2248
2249 *resp_len = reply_len;
2250 return reply;
2251}