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