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