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