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