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