1/*
2 * WPA Supplicant / Control interface (shared code for all backends)
3 * Copyright (c) 2004-2006, 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 "wpa_supplicant.h"
21#include "config.h"
22#include "eapol_sm.h"
23#include "wpa_supplicant_i.h"
24#include "ctrl_iface.h"
25#include "l2_packet.h"
26#include "preauth.h"
27#include "pmksa_cache.h"
28#include "wpa_ctrl.h"
29#include "eap.h"
30
31
32static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
33						  char *buf, int len);
34
35
36static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
37					 char *cmd)
38{
39	char *value;
40	int ret = 0;
41
42	value = os_strchr(cmd, ' ');
43	if (value == NULL)
44		return -1;
45	*value++ = '\0';
46
47	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
48	if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
49		eapol_sm_configure(wpa_s->eapol,
50				   atoi(value), -1, -1, -1);
51	} else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
52		eapol_sm_configure(wpa_s->eapol,
53				   -1, atoi(value), -1, -1);
54	} else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
55		eapol_sm_configure(wpa_s->eapol,
56				   -1, -1, atoi(value), -1);
57	} else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
58		eapol_sm_configure(wpa_s->eapol,
59				   -1, -1, -1, atoi(value));
60	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
61		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
62				     atoi(value)))
63			ret = -1;
64	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
65		   0) {
66		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
67				     atoi(value)))
68			ret = -1;
69	} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
70		if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
71			ret = -1;
72	} else
73		ret = -1;
74
75	return ret;
76}
77
78
79#ifdef IEEE8021X_EAPOL
80static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
81					     char *addr)
82{
83	u8 bssid[ETH_ALEN];
84
85	if (hwaddr_aton(addr, bssid)) {
86		wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
87			   "'%s'", addr);
88		return -1;
89	}
90
91	wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
92	rsn_preauth_deinit(wpa_s->wpa);
93	if (rsn_preauth_init(wpa_s->wpa, bssid, wpa_s->current_ssid))
94		return -1;
95
96	return 0;
97}
98#endif /* IEEE8021X_EAPOL */
99
100
101#ifdef CONFIG_PEERKEY
102/* MLME-STKSTART.request(peer) */
103static int wpa_supplicant_ctrl_iface_stkstart(
104	struct wpa_supplicant *wpa_s, char *addr)
105{
106	u8 peer[ETH_ALEN];
107
108	if (hwaddr_aton(addr, peer)) {
109		wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
110			   "address '%s'", peer);
111		return -1;
112	}
113
114	wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
115		   MAC2STR(peer));
116
117	return wpa_sm_stkstart(wpa_s->wpa, peer);
118}
119#endif /* CONFIG_PEERKEY */
120
121
122static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
123					      char *rsp)
124{
125#ifdef IEEE8021X_EAPOL
126	char *pos, *id_pos;
127	int id;
128	struct wpa_ssid *ssid;
129
130	pos = os_strchr(rsp, '-');
131	if (pos == NULL)
132		return -1;
133	*pos++ = '\0';
134	id_pos = pos;
135	pos = os_strchr(pos, ':');
136	if (pos == NULL)
137		return -1;
138	*pos++ = '\0';
139	id = atoi(id_pos);
140	wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
141	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
142			      (u8 *) pos, os_strlen(pos));
143
144	ssid = wpa_config_get_network(wpa_s->conf, id);
145	if (ssid == NULL) {
146		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
147			   "to update", id);
148		return -1;
149	}
150
151	if (os_strcmp(rsp, "IDENTITY") == 0) {
152		os_free(ssid->identity);
153		ssid->identity = (u8 *) os_strdup(pos);
154		ssid->identity_len = os_strlen(pos);
155		ssid->pending_req_identity = 0;
156		if (ssid == wpa_s->current_ssid)
157			wpa_s->reassociate = 1;
158	} else if (os_strcmp(rsp, "PASSWORD") == 0) {
159		os_free(ssid->password);
160		ssid->password = (u8 *) os_strdup(pos);
161		ssid->password_len = os_strlen(pos);
162		ssid->pending_req_password = 0;
163		if (ssid == wpa_s->current_ssid)
164			wpa_s->reassociate = 1;
165	} else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
166		os_free(ssid->new_password);
167		ssid->new_password = (u8 *) os_strdup(pos);
168		ssid->new_password_len = os_strlen(pos);
169		ssid->pending_req_new_password = 0;
170		if (ssid == wpa_s->current_ssid)
171			wpa_s->reassociate = 1;
172	} else if (os_strcmp(rsp, "PIN") == 0) {
173		os_free(ssid->pin);
174		ssid->pin = os_strdup(pos);
175		ssid->pending_req_pin = 0;
176		if (ssid == wpa_s->current_ssid)
177			wpa_s->reassociate = 1;
178	} else if (os_strcmp(rsp, "OTP") == 0) {
179		os_free(ssid->otp);
180		ssid->otp = (u8 *) os_strdup(pos);
181		ssid->otp_len = os_strlen(pos);
182		os_free(ssid->pending_req_otp);
183		ssid->pending_req_otp = NULL;
184		ssid->pending_req_otp_len = 0;
185	} else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
186		os_free(ssid->private_key_passwd);
187		ssid->private_key_passwd = (u8 *) os_strdup(pos);
188		ssid->pending_req_passphrase = 0;
189		if (ssid == wpa_s->current_ssid)
190			wpa_s->reassociate = 1;
191	} else {
192		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
193		return -1;
194	}
195
196	return 0;
197#else /* IEEE8021X_EAPOL */
198	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
199	return -1;
200#endif /* IEEE8021X_EAPOL */
201}
202
203
204static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
205					    const char *params,
206					    char *buf, size_t buflen)
207{
208	char *pos, *end, tmp[30];
209	int res, verbose, ret;
210
211	verbose = os_strcmp(params, "-VERBOSE") == 0;
212	pos = buf;
213	end = buf + buflen;
214	if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
215		struct wpa_ssid *ssid = wpa_s->current_ssid;
216		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
217				  MAC2STR(wpa_s->bssid));
218		if (ret < 0 || ret >= end - pos)
219			return pos - buf;
220		pos += ret;
221		if (ssid) {
222			u8 *_ssid = ssid->ssid;
223			size_t ssid_len = ssid->ssid_len;
224			u8 ssid_buf[MAX_SSID_LEN];
225			if (ssid_len == 0) {
226				int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
227				if (_res < 0)
228					ssid_len = 0;
229				else
230					ssid_len = _res;
231				_ssid = ssid_buf;
232			}
233			ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
234					  wpa_ssid_txt(_ssid, ssid_len),
235					  ssid->id);
236			if (ret < 0 || ret >= end - pos)
237				return pos - buf;
238			pos += ret;
239
240			if (ssid->id_str) {
241				ret = os_snprintf(pos, end - pos,
242						  "id_str=%s\n",
243						  ssid->id_str);
244				if (ret < 0 || ret >= end - pos)
245					return pos - buf;
246				pos += ret;
247			}
248		}
249
250		pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
251	}
252	ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
253			  wpa_supplicant_state_txt(wpa_s->wpa_state));
254	if (ret < 0 || ret >= end - pos)
255		return pos - buf;
256	pos += ret;
257
258	if (wpa_s->l2 &&
259	    l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
260		ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
261		if (ret < 0 || ret >= end - pos)
262			return pos - buf;
263		pos += ret;
264	}
265
266	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
267	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
268		res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
269					  verbose);
270		if (res >= 0)
271			pos += res;
272	}
273
274	res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
275	if (res >= 0)
276		pos += res;
277
278	return pos - buf;
279}
280
281
282static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
283					   char *cmd)
284{
285	char *pos;
286	int id;
287	struct wpa_ssid *ssid;
288	u8 bssid[ETH_ALEN];
289
290	/* cmd: "<network id> <BSSID>" */
291	pos = os_strchr(cmd, ' ');
292	if (pos == NULL)
293		return -1;
294	*pos++ = '\0';
295	id = atoi(cmd);
296	wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
297	if (hwaddr_aton(pos, bssid)) {
298		wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
299		return -1;
300	}
301
302	ssid = wpa_config_get_network(wpa_s->conf, id);
303	if (ssid == NULL) {
304		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
305			   "to update", id);
306		return -1;
307	}
308
309	os_memcpy(ssid->bssid, bssid, ETH_ALEN);
310	ssid->bssid_set =
311		os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0;
312
313
314	return 0;
315}
316
317#ifdef ANDROID
318static int wpa_supplicant_ctrl_iface_blacklist(
319		struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
320{
321	struct wpa_ssid *ssid;
322	u8 bssid[ETH_ALEN];
323	struct wpa_blacklist *e;
324	char *pos, *end;
325	int ret;
326
327	/* cmd: "BLACKLIST [<BSSID>]" */
328	if (*cmd == '\0') {
329		pos = buf;
330		end = buf + buflen;
331
332		e = wpa_s->blacklist;
333		while (e) {
334			ret = os_snprintf(pos, end-pos,
335					  "%02x:%02x:%02x:%02x:%02x:%02x\n",
336					  e->bssid[0],
337					  e->bssid[1],
338					  e->bssid[2],
339					  e->bssid[3],
340					  e->bssid[4],
341					  e->bssid[5]);
342			if (ret < 0 || ret >= end - pos)
343				return pos - buf;
344			pos += ret;
345			e = e->next;
346		}
347		return pos - buf;
348	}
349	wpa_printf(MSG_DEBUG, "CTRL_IFACE: bssid='%s'", cmd);
350
351	++cmd;
352	if (os_strncmp(cmd, "clear", 5) == 0) {
353		wpa_blacklist_clear(wpa_s);
354		return 0;
355	}
356
357	if (hwaddr_aton(cmd, bssid)) {
358		wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", cmd);
359		return -1;
360	}
361
362	/*
363	 * Add the BSSID twice, so its count will be 2, causing it to be
364	 * skipped when processing scan results.
365	 */
366	ret = wpa_blacklist_add(wpa_s, bssid);
367	if (ret != 0)
368		return ret;
369	return wpa_blacklist_add(wpa_s, bssid);
370}
371#endif
372
373static int wpa_supplicant_ctrl_iface_list_networks(
374	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
375{
376	char *pos, *end;
377	struct wpa_ssid *ssid;
378	int ret;
379
380	pos = buf;
381	end = buf + buflen;
382	ret = os_snprintf(pos, end - pos,
383			  "network id / ssid / bssid / flags\n");
384	if (ret < 0 || ret >= end - pos)
385		return pos - buf;
386	pos += ret;
387
388	ssid = wpa_s->conf->ssid;
389	while (ssid) {
390		ret = os_snprintf(pos, end - pos, "%d\t%s",
391				  ssid->id,
392				  wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
393		if (ret < 0 || ret >= end - pos)
394			return pos - buf;
395		pos += ret;
396		if (ssid->bssid_set) {
397			ret = os_snprintf(pos, end - pos, "\t" MACSTR,
398					  MAC2STR(ssid->bssid));
399		} else {
400			ret = os_snprintf(pos, end - pos, "\tany");
401		}
402		if (ret < 0 || ret >= end - pos)
403			return pos - buf;
404		pos += ret;
405		ret = os_snprintf(pos, end - pos, "\t%s%s",
406				  ssid == wpa_s->current_ssid ?
407				  "[CURRENT]" : "",
408				  ssid->disabled ? "[DISABLED]" : "");
409		if (ret < 0 || ret >= end - pos)
410			return pos - buf;
411		pos += ret;
412		ret = os_snprintf(pos, end - pos, "\n");
413		if (ret < 0 || ret >= end - pos)
414			return pos - buf;
415		pos += ret;
416
417		ssid = ssid->next;
418	}
419
420	return pos - buf;
421}
422
423
424static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
425{
426	int first = 1, ret;
427	ret = os_snprintf(pos, end - pos, "-");
428	if (ret < 0 || ret >= end - pos)
429		return pos;
430	pos += ret;
431	if (cipher & WPA_CIPHER_NONE) {
432		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
433		if (ret < 0 || ret >= end - pos)
434			return pos;
435		pos += ret;
436		first = 0;
437	}
438	if (cipher & WPA_CIPHER_WEP40) {
439		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
440		if (ret < 0 || ret >= end - pos)
441			return pos;
442		pos += ret;
443		first = 0;
444	}
445	if (cipher & WPA_CIPHER_WEP104) {
446		ret = os_snprintf(pos, end - pos, "%sWEP104",
447				  first ? "" : "+");
448		if (ret < 0 || ret >= end - pos)
449			return pos;
450		pos += ret;
451		first = 0;
452	}
453	if (cipher & WPA_CIPHER_TKIP) {
454		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
455		if (ret < 0 || ret >= end - pos)
456			return pos;
457		pos += ret;
458		first = 0;
459	}
460	if (cipher & WPA_CIPHER_CCMP) {
461		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
462		if (ret < 0 || ret >= end - pos)
463			return pos;
464		pos += ret;
465		first = 0;
466	}
467	return pos;
468}
469
470
471static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
472				    const u8 *ie, size_t ie_len)
473{
474	struct wpa_ie_data data;
475	int first, ret;
476
477	ret = os_snprintf(pos, end - pos, "[%s-", proto);
478	if (ret < 0 || ret >= end - pos)
479		return pos;
480	pos += ret;
481
482	if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
483		ret = os_snprintf(pos, end - pos, "?]");
484		if (ret < 0 || ret >= end - pos)
485			return pos;
486		pos += ret;
487		return pos;
488	}
489
490	first = 1;
491	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
492		ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
493		if (ret < 0 || ret >= end - pos)
494			return pos;
495		pos += ret;
496		first = 0;
497	}
498	if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
499		ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
500		if (ret < 0 || ret >= end - pos)
501			return pos;
502		pos += ret;
503		first = 0;
504	}
505	if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
506		ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
507		if (ret < 0 || ret >= end - pos)
508			return pos;
509		pos += ret;
510		first = 0;
511	}
512
513	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
514
515	if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
516		ret = os_snprintf(pos, end - pos, "-preauth");
517		if (ret < 0 || ret >= end - pos)
518			return pos;
519		pos += ret;
520	}
521
522	ret = os_snprintf(pos, end - pos, "]");
523	if (ret < 0 || ret >= end - pos)
524		return pos;
525	pos += ret;
526
527	return pos;
528}
529
530
531static int wpa_supplicant_ctrl_iface_scan_results(
532	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
533{
534	char *pos, *end, *retpos;
535	struct wpa_scan_result *res;
536	int i, ret;
537
538	if (wpa_s->scan_results == NULL &&
539	    wpa_supplicant_get_scan_results(wpa_s) < 0)
540		return 0;
541	if (wpa_s->scan_results == NULL)
542		return 0;
543
544	pos = buf;
545	end = buf + buflen;
546	ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
547			  "flags / ssid\n");
548	if (ret < 0 || ret >= end - pos)
549		return pos - buf;
550	pos += ret;
551
552	for (i = 0; i < wpa_s->num_scan_results; i++) {
553		retpos = pos;
554		res = &wpa_s->scan_results[i];
555		ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
556				  MAC2STR(res->bssid), res->freq, res->level);
557		if (ret < 0 || ret >= end - pos)
558			return retpos - buf;
559		pos += ret;
560		if (res->wpa_ie_len) {
561			pos = wpa_supplicant_ie_txt(pos, end, "WPA",
562						    res->wpa_ie,
563						    res->wpa_ie_len);
564		}
565		if (res->rsn_ie_len) {
566			pos = wpa_supplicant_ie_txt(pos, end, "WPA2",
567						    res->rsn_ie,
568						    res->rsn_ie_len);
569		}
570		if (!res->wpa_ie_len && !res->rsn_ie_len &&
571		    res->caps & IEEE80211_CAP_PRIVACY) {
572			ret = os_snprintf(pos, end - pos, "[WEP]");
573			if (ret < 0 || ret >= end - pos)
574				return retpos - buf;
575			pos += ret;
576		}
577		if (res->caps & IEEE80211_CAP_IBSS) {
578			ret = os_snprintf(pos, end - pos, "[IBSS]");
579			if (ret < 0 || ret >= end - pos)
580				return retpos - buf;
581			pos += ret;
582		}
583		if (!res->wpa_ie_len && !res->rsn_ie_len) {
584			ret = os_snprintf(pos, end - pos, "\t");
585			if (ret < 0 || ret >= end - pos)
586				return retpos - buf;
587			pos += ret;
588		}
589
590		ret = os_snprintf(pos, end - pos, "\t%s",
591				  wpa_ssid_txt(res->ssid, res->ssid_len));
592		if (ret < 0 || ret >= end - pos)
593			return retpos - buf;
594		pos += ret;
595
596		ret = os_snprintf(pos, end - pos, "\n");
597		if (ret < 0 || ret >= end - pos)
598			return retpos - buf;
599		pos += ret;
600	}
601
602	return pos - buf;
603}
604
605
606static int wpa_supplicant_ctrl_iface_select_network(
607	struct wpa_supplicant *wpa_s, char *cmd)
608{
609	int id;
610	struct wpa_ssid *ssid;
611
612	/* cmd: "<network id>" or "any" */
613	if (os_strcmp(cmd, "any") == 0) {
614		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
615		ssid = wpa_s->conf->ssid;
616		while (ssid) {
617			ssid->disabled = 0;
618			ssid = ssid->next;
619		}
620		wpa_s->reassociate = 1;
621		wpa_supplicant_req_scan(wpa_s, 0, 0);
622		return 0;
623	}
624
625	id = atoi(cmd);
626	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
627
628	ssid = wpa_config_get_network(wpa_s->conf, id);
629	if (ssid == NULL) {
630		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
631			   "id=%d", id);
632		return -1;
633	}
634
635	if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
636		wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
637
638	/* Mark all other networks disabled and trigger reassociation */
639	ssid = wpa_s->conf->ssid;
640	while (ssid) {
641		ssid->disabled = id != ssid->id;
642		ssid = ssid->next;
643	}
644	wpa_s->reassociate = 1;
645	wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
646	wpa_supplicant_req_scan(wpa_s, 0, 0);
647
648	return 0;
649}
650
651
652static int wpa_supplicant_ctrl_iface_enable_network(
653	struct wpa_supplicant *wpa_s, char *cmd)
654{
655	int id;
656	struct wpa_ssid *ssid;
657
658	/* cmd: "<network id>" */
659	id = atoi(cmd);
660	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
661
662	ssid = wpa_config_get_network(wpa_s->conf, id);
663	if (ssid == NULL) {
664		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
665			   "id=%d", id);
666		return -1;
667	}
668
669	if (wpa_s->current_ssid == NULL && ssid->disabled) {
670		/*
671		 * Try to reassociate since there is no current configuration
672		 * and a new network was made available. */
673		wpa_s->reassociate = 1;
674#ifdef ANDROID
675		wpa_supplicant_req_scan(wpa_s, 2, 0);
676#else
677		wpa_supplicant_req_scan(wpa_s, 0, 0);
678#endif
679	}
680	ssid->disabled = 0;
681
682	return 0;
683}
684
685
686static int wpa_supplicant_ctrl_iface_disable_network(
687	struct wpa_supplicant *wpa_s, char *cmd)
688{
689	int id;
690	struct wpa_ssid *ssid;
691
692	/* cmd: "<network id>" */
693	id = atoi(cmd);
694	wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
695
696	ssid = wpa_config_get_network(wpa_s->conf, id);
697	if (ssid == NULL) {
698		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
699			   "id=%d", id);
700		return -1;
701	}
702
703	if (ssid == wpa_s->current_ssid)
704		wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
705	ssid->disabled = 1;
706
707	return 0;
708}
709
710
711static int wpa_supplicant_ctrl_iface_add_network(
712	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
713{
714	struct wpa_ssid *ssid;
715	int ret;
716
717	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
718
719	ssid = wpa_config_add_network(wpa_s->conf);
720	if (ssid == NULL)
721		return -1;
722	ssid->disabled = 1;
723	wpa_config_set_network_defaults(ssid);
724
725	ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
726	if (ret < 0 || (size_t) ret >= buflen)
727		return -1;
728	return ret;
729}
730
731
732static int wpa_supplicant_ctrl_iface_remove_network(
733	struct wpa_supplicant *wpa_s, char *cmd)
734{
735	int id;
736	struct wpa_ssid *ssid;
737
738	/* cmd: "<network id>" */
739	id = atoi(cmd);
740	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
741
742	ssid = wpa_config_get_network(wpa_s->conf, id);
743	if (ssid == NULL ||
744	    wpa_config_remove_network(wpa_s->conf, id) < 0) {
745		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
746			   "id=%d", id);
747		return -1;
748	}
749
750	if (ssid == wpa_s->current_ssid) {
751		/*
752		 * Invalidate the EAP session cache if the current network is
753		 * removed.
754		 */
755		eapol_sm_invalidate_cached_session(wpa_s->eapol);
756
757		wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
758	}
759
760	return 0;
761}
762
763
764static int wpa_supplicant_ctrl_iface_set_network(
765	struct wpa_supplicant *wpa_s, char *cmd)
766{
767	int id;
768	struct wpa_ssid *ssid;
769	char *name, *value;
770
771	/* cmd: "<network id> <variable name> <value>" */
772	name = os_strchr(cmd, ' ');
773	if (name == NULL)
774		return -1;
775	*name++ = '\0';
776
777	value = os_strchr(name, ' ');
778	if (value == NULL)
779		return -1;
780	*value++ = '\0';
781
782	id = atoi(cmd);
783	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
784		   id, name);
785	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
786			      (u8 *) value, os_strlen(value));
787
788	ssid = wpa_config_get_network(wpa_s->conf, id);
789	if (ssid == NULL) {
790		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
791			   "id=%d", id);
792		return -1;
793	}
794
795	if (wpa_config_set(ssid, name, value, 0) < 0) {
796		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
797			   "variable '%s'", name);
798		return -1;
799	} else {
800		if (os_strcmp(name, "priority") == 0) {
801			wpa_config_update_prio_list(wpa_s->conf);
802		}
803	}
804
805	if (wpa_s->current_ssid == ssid) {
806		/*
807		 * Invalidate the EAP session cache if anything in the current
808		 * configuration changes.
809		 */
810		eapol_sm_invalidate_cached_session(wpa_s->eapol);
811	}
812
813	if ((os_strcmp(name, "psk") == 0 &&
814	     value[0] == '"' && ssid->ssid_len) ||
815	    (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
816		wpa_config_update_psk(ssid);
817
818	return 0;
819}
820
821
822static int wpa_supplicant_ctrl_iface_get_network(
823	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
824{
825	int id;
826	struct wpa_ssid *ssid;
827	char *name, *value;
828
829	/* cmd: "<network id> <variable name>" */
830	name = os_strchr(cmd, ' ');
831	if (name == NULL || buflen == 0)
832		return -1;
833	*name++ = '\0';
834
835	id = atoi(cmd);
836	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
837		   id, name);
838
839	ssid = wpa_config_get_network(wpa_s->conf, id);
840	if (ssid == NULL) {
841		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
842			   "id=%d", id);
843		return -1;
844	}
845
846	value = wpa_config_get_no_key(ssid, name);
847	if (value == NULL) {
848		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
849			   "variable '%s'", name);
850		return -1;
851	}
852
853	os_snprintf(buf, buflen, "%s", value);
854	buf[buflen - 1] = '\0';
855
856	os_free(value);
857
858	return os_strlen(buf);
859}
860
861
862static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
863{
864	int ret;
865
866	if (!wpa_s->conf->update_config) {
867		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
868			   "to update configuration (update_config=0)");
869		return -1;
870	}
871
872	ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
873	if (ret) {
874		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
875			   "update configuration");
876	} else {
877		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
878			   " updated");
879	}
880
881	return ret;
882}
883
884
885static int wpa_supplicant_ctrl_iface_get_capability(
886	struct wpa_supplicant *wpa_s, const char *_field, char *buf,
887	size_t buflen)
888{
889	struct wpa_driver_capa capa;
890	int res, first = 1, ret;
891	char *pos, *end, *strict;
892	char field[30];
893
894	/* Determine whether or not strict checking was requested */
895	os_snprintf(field, sizeof(field), "%s", _field);
896	field[sizeof(field) - 1] = '\0';
897	strict = os_strchr(field, ' ');
898	if (strict != NULL) {
899		*strict++ = '\0';
900		if (os_strcmp(strict, "strict") != 0)
901			return -1;
902	}
903
904	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
905		field, strict ? strict : "");
906
907	if (os_strcmp(field, "eap") == 0) {
908		return eap_get_names(buf, buflen);
909	}
910
911	res = wpa_drv_get_capa(wpa_s, &capa);
912
913	pos = buf;
914	end = pos + buflen;
915
916	if (os_strcmp(field, "pairwise") == 0) {
917		if (res < 0) {
918			if (strict)
919				return 0;
920			ret = os_snprintf(buf, buflen, "CCMP TKIP NONE");
921			if (ret < 0 || (size_t) ret >= buflen)
922				return -1;
923			return ret;
924		}
925
926		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
927			ret = os_snprintf(pos, end - pos, "%sCCMP",
928					  first ? "" : " ");
929			if (ret < 0 || ret >= end - pos)
930				return pos - buf;
931			pos += ret;
932			first = 0;
933		}
934
935		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
936			ret = os_snprintf(pos, end - pos, "%sTKIP",
937					  first ? "" : " ");
938			if (ret < 0 || ret >= end - pos)
939				return pos - buf;
940			pos += ret;
941			first = 0;
942		}
943
944		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
945			ret = os_snprintf(pos, end - pos, "%sNONE",
946					  first ? "" : " ");
947			if (ret < 0 || ret >= end - pos)
948				return pos - buf;
949			pos += ret;
950			first = 0;
951		}
952
953		return pos - buf;
954	}
955
956	if (os_strcmp(field, "group") == 0) {
957		if (res < 0) {
958			if (strict)
959				return 0;
960			ret = os_snprintf(buf, buflen,
961					  "CCMP TKIP WEP104 WEP40");
962			if (ret < 0 || (size_t) ret >= buflen)
963				return -1;
964			return ret;
965		}
966
967		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
968			ret = os_snprintf(pos, end - pos, "%sCCMP",
969					  first ? "" : " ");
970			if (ret < 0 || ret >= end - pos)
971				return pos - buf;
972			pos += ret;
973			first = 0;
974		}
975
976		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
977			ret = os_snprintf(pos, end - pos, "%sTKIP",
978					  first ? "" : " ");
979			if (ret < 0 || ret >= end - pos)
980				return pos - buf;
981			pos += ret;
982			first = 0;
983		}
984
985		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
986			ret = os_snprintf(pos, end - pos, "%sWEP104",
987					  first ? "" : " ");
988			if (ret < 0 || ret >= end - pos)
989				return pos - buf;
990			pos += ret;
991			first = 0;
992		}
993
994		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
995			ret = os_snprintf(pos, end - pos, "%sWEP40",
996					  first ? "" : " ");
997			if (ret < 0 || ret >= end - pos)
998				return pos - buf;
999			pos += ret;
1000			first = 0;
1001		}
1002
1003		return pos - buf;
1004	}
1005
1006	if (os_strcmp(field, "key_mgmt") == 0) {
1007		if (res < 0) {
1008			if (strict)
1009				return 0;
1010			ret = os_snprintf(buf, buflen, "WPA-PSK WPA-EAP "
1011					  "IEEE8021X WPA-NONE NONE");
1012			if (ret < 0 || (size_t) ret >= buflen)
1013				return -1;
1014			return ret;
1015		}
1016
1017		ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
1018		if (ret < 0 || ret >= end - pos)
1019			return pos - buf;
1020		pos += ret;
1021
1022		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1023				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
1024			ret = os_snprintf(pos, end - pos, " WPA-EAP");
1025			if (ret < 0 || ret >= end - pos)
1026				return pos - buf;
1027			pos += ret;
1028		}
1029
1030		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
1031				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1032			ret = os_snprintf(pos, end - pos, " WPA-PSK");
1033			if (ret < 0 || ret >= end - pos)
1034				return pos - buf;
1035			pos += ret;
1036		}
1037
1038		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1039			ret = os_snprintf(pos, end - pos, " WPA-NONE");
1040			if (ret < 0 || ret >= end - pos)
1041				return pos - buf;
1042			pos += ret;
1043		}
1044
1045		return pos - buf;
1046	}
1047
1048	if (os_strcmp(field, "proto") == 0) {
1049		if (res < 0) {
1050			if (strict)
1051				return 0;
1052			ret = os_snprintf(buf, buflen, "RSN WPA");
1053			if (ret < 0 || (size_t) ret >= buflen)
1054				return -1;
1055			return ret;
1056		}
1057
1058		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1059				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1060			ret = os_snprintf(pos, end - pos, "%sRSN",
1061					  first ? "" : " ");
1062			if (ret < 0 || ret >= end - pos)
1063				return pos - buf;
1064			pos += ret;
1065			first = 0;
1066		}
1067
1068		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1069				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
1070			ret = os_snprintf(pos, end - pos, "%sWPA",
1071					  first ? "" : " ");
1072			if (ret < 0 || ret >= end - pos)
1073				return pos - buf;
1074			pos += ret;
1075			first = 0;
1076		}
1077
1078		return pos - buf;
1079	}
1080
1081	if (os_strcmp(field, "auth_alg") == 0) {
1082		if (res < 0) {
1083			if (strict)
1084				return 0;
1085			ret = os_snprintf(buf, buflen, "OPEN SHARED LEAP");
1086			if (ret < 0 || (size_t) ret >= buflen)
1087				return -1;
1088			return ret;
1089		}
1090
1091		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
1092			ret = os_snprintf(pos, end - pos, "%sOPEN",
1093					  first ? "" : " ");
1094			if (ret < 0 || ret >= end - pos)
1095				return pos - buf;
1096			pos += ret;
1097			first = 0;
1098		}
1099
1100		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
1101			ret = os_snprintf(pos, end - pos, "%sSHARED",
1102					  first ? "" : " ");
1103			if (ret < 0 || ret >= end - pos)
1104				return pos - buf;
1105			pos += ret;
1106			first = 0;
1107		}
1108
1109		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
1110			ret = os_snprintf(pos, end - pos, "%sLEAP",
1111					  first ? "" : " ");
1112			if (ret < 0 || ret >= end - pos)
1113				return pos - buf;
1114			pos += ret;
1115			first = 0;
1116		}
1117
1118		return pos - buf;
1119	}
1120
1121	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
1122		   field);
1123
1124	return -1;
1125}
1126
1127
1128static int wpa_supplicant_ctrl_iface_ap_scan(
1129	struct wpa_supplicant *wpa_s, char *cmd)
1130{
1131	int ap_scan = atoi(cmd);
1132
1133	if (ap_scan < 0 || ap_scan > 2)
1134		return -1;
1135#ifdef ANDROID
1136	if ((ap_scan == 2) && (wpa_s->wpa_state != WPA_COMPLETED)) {
1137		return 0;
1138	}
1139#endif
1140	wpa_s->conf->ap_scan = ap_scan;
1141	return 0;
1142}
1143
1144static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s,
1145                                     char *cmd, char *buf, size_t buflen)
1146{
1147    int ret;
1148
1149    ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
1150    if( ret == 0 ) {
1151        ret = sprintf(buf, "%s\n", "OK");
1152    }
1153    return( ret );
1154}
1155
1156char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
1157					 char *buf, size_t *resp_len)
1158{
1159	char *reply;
1160	const int reply_size = 4096;
1161	int ctrl_rsp = 0;
1162	int reply_len;
1163
1164	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
1165	    os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1166		wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
1167				      (const u8 *) buf, os_strlen(buf));
1168	} else {
1169        if (os_strcmp(buf, "PING") != 0)
1170            wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface",
1171                              (const u8 *) buf, os_strlen(buf));
1172	}
1173
1174	reply = os_malloc(reply_size);
1175	if (reply == NULL) {
1176		*resp_len = 1;
1177		return NULL;
1178	}
1179
1180	os_memcpy(reply, "OK\n", 3);
1181	reply_len = 3;
1182
1183	if (os_strcmp(buf, "PING") == 0) {
1184		os_memcpy(reply, "PONG\n", 5);
1185		reply_len = 5;
1186	} else if (os_strcmp(buf, "MIB") == 0) {
1187		reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
1188		if (reply_len >= 0) {
1189			int res;
1190			res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
1191					       reply_size - reply_len);
1192			if (res < 0)
1193				reply_len = -1;
1194			else
1195				reply_len += res;
1196		}
1197	} else if (os_strncmp(buf, "STATUS", 6) == 0) {
1198		reply_len = wpa_supplicant_ctrl_iface_status(
1199			wpa_s, buf + 6, reply, reply_size);
1200	} else if (os_strcmp(buf, "PMKSA") == 0) {
1201		reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size);
1202	} else if (os_strncmp(buf, "SET ", 4) == 0) {
1203		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
1204			reply_len = -1;
1205	} else if (os_strcmp(buf, "LOGON") == 0) {
1206		eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
1207	} else if (os_strcmp(buf, "LOGOFF") == 0) {
1208		eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
1209	} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
1210		wpa_s->disconnected = 0;
1211		wpa_s->reassociate = 1;
1212		wpa_supplicant_req_scan(wpa_s, 0, 0);
1213	} else if (os_strcmp(buf, "RECONNECT") == 0) {
1214		if (wpa_s->disconnected) {
1215			wpa_s->disconnected = 0;
1216			wpa_s->reassociate = 1;
1217			wpa_supplicant_req_scan(wpa_s, 0, 0);
1218		}
1219#ifdef IEEE8021X_EAPOL
1220	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
1221		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
1222			reply_len = -1;
1223#endif /* IEEE8021X_EAPOL */
1224#ifdef CONFIG_PEERKEY
1225	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
1226		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
1227			reply_len = -1;
1228#endif /* CONFIG_PEERKEY */
1229	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
1230	{
1231		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
1232			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
1233			reply_len = -1;
1234		else
1235			ctrl_rsp = 1;
1236	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
1237		if (wpa_supplicant_reload_configuration(wpa_s))
1238			reply_len = -1;
1239	} else if (os_strcmp(buf, "TERMINATE") == 0) {
1240		eloop_terminate();
1241	} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
1242		if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
1243			reply_len = -1;
1244#ifdef ANDROID
1245	} else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
1246		reply_len = wpa_supplicant_ctrl_iface_blacklist(
1247				wpa_s, buf + 9, reply, reply_size);
1248		if (os_strlen(buf) > 10 && reply_len == 0) {
1249			struct wpa_blacklist *bl = wpa_s->blacklist;
1250			if (os_strncmp(buf+10, "clear", 5) == 0 ||
1251			    (bl != NULL && os_memcmp(bl->bssid, wpa_s->bssid, ETH_ALEN) == 0)) {
1252				wpa_s->disconnected = 0;
1253				wpa_s->reassociate = 1;
1254				wpa_supplicant_req_scan(wpa_s, 0, 0);
1255			}
1256		}
1257#endif
1258	} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
1259		reply_len = wpa_supplicant_ctrl_iface_list_networks(
1260			wpa_s, reply, reply_size);
1261	} else if (os_strcmp(buf, "DISCONNECT") == 0) {
1262		wpa_s->reassociate = 0;
1263		wpa_s->disconnected = 1;
1264		wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
1265	} else if (os_strcmp(buf, "SCAN") == 0) {
1266#ifdef ANDROID
1267		if (!wpa_s->scan_ongoing && ((wpa_s->wpa_state <= WPA_SCANNING) ||
1268			(wpa_s->wpa_state >= WPA_COMPLETED))) {
1269#endif
1270			wpa_s->scan_req = 2;
1271			wpa_supplicant_req_scan(wpa_s, 0, 0);
1272#ifdef ANDROID
1273		} else {
1274			wpa_printf(MSG_DEBUG, "Ongoing Scan action...");
1275		}
1276#endif
1277	} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
1278		reply_len = wpa_supplicant_ctrl_iface_scan_results(
1279			wpa_s, reply, reply_size);
1280	} else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
1281		if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
1282			reply_len = -1;
1283	} else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
1284		if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
1285			reply_len = -1;
1286	} else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
1287		if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
1288			reply_len = -1;
1289	} else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
1290		reply_len = wpa_supplicant_ctrl_iface_add_network(
1291			wpa_s, reply, reply_size);
1292	} else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
1293		if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
1294			reply_len = -1;
1295	} else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1296		if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
1297			reply_len = -1;
1298	} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
1299		reply_len = wpa_supplicant_ctrl_iface_get_network(
1300			wpa_s, buf + 12, reply, reply_size);
1301	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
1302		if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
1303			reply_len = -1;
1304	} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
1305		reply_len = wpa_supplicant_ctrl_iface_get_capability(
1306			wpa_s, buf + 15, reply, reply_size);
1307	} else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
1308		if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
1309			reply_len = -1;
1310	} else if (os_strcmp(buf, "INTERFACES") == 0) {
1311		reply_len = wpa_supplicant_global_iface_interfaces(
1312			wpa_s->global, reply, reply_size);
1313    } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
1314        reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, reply_size);
1315	} else {
1316		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1317		reply_len = 16;
1318	}
1319
1320	if (reply_len < 0) {
1321		os_memcpy(reply, "FAIL\n", 5);
1322		reply_len = 5;
1323	}
1324
1325	if (ctrl_rsp)
1326		eapol_sm_notify_ctrl_response(wpa_s->eapol);
1327
1328	*resp_len = reply_len;
1329	return reply;
1330}
1331
1332
1333static int wpa_supplicant_global_iface_add(struct wpa_global *global,
1334					   char *cmd)
1335{
1336	struct wpa_interface iface;
1337	char *pos;
1338
1339	/*
1340	 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
1341	 * TAB<bridge_ifname>
1342	 */
1343	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
1344
1345	os_memset(&iface, 0, sizeof(iface));
1346
1347	do {
1348		iface.ifname = pos = cmd;
1349		pos = os_strchr(pos, '\t');
1350		if (pos)
1351			*pos++ = '\0';
1352		if (iface.ifname[0] == '\0')
1353			return -1;
1354		if (pos == NULL)
1355			break;
1356
1357		iface.confname = pos;
1358		pos = os_strchr(pos, '\t');
1359		if (pos)
1360			*pos++ = '\0';
1361		if (iface.confname[0] == '\0')
1362			iface.confname = NULL;
1363		if (pos == NULL)
1364			break;
1365
1366		iface.driver = pos;
1367		pos = os_strchr(pos, '\t');
1368		if (pos)
1369			*pos++ = '\0';
1370		if (iface.driver[0] == '\0')
1371			iface.driver = NULL;
1372		if (pos == NULL)
1373			break;
1374
1375		iface.ctrl_interface = pos;
1376		pos = os_strchr(pos, '\t');
1377		if (pos)
1378			*pos++ = '\0';
1379		if (iface.ctrl_interface[0] == '\0')
1380			iface.ctrl_interface = NULL;
1381		if (pos == NULL)
1382			break;
1383
1384		iface.driver_param = pos;
1385		pos = os_strchr(pos, '\t');
1386		if (pos)
1387			*pos++ = '\0';
1388		if (iface.driver_param[0] == '\0')
1389			iface.driver_param = NULL;
1390		if (pos == NULL)
1391			break;
1392
1393		iface.bridge_ifname = pos;
1394		pos = os_strchr(pos, '\t');
1395		if (pos)
1396			*pos++ = '\0';
1397		if (iface.bridge_ifname[0] == '\0')
1398			iface.bridge_ifname = NULL;
1399		if (pos == NULL)
1400			break;
1401	} while (0);
1402
1403	if (wpa_supplicant_get_iface(global, iface.ifname))
1404		return -1;
1405
1406	return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
1407}
1408
1409
1410static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
1411					      char *cmd)
1412{
1413	struct wpa_supplicant *wpa_s;
1414
1415	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
1416
1417	wpa_s = wpa_supplicant_get_iface(global, cmd);
1418	if (wpa_s == NULL)
1419		return -1;
1420	return wpa_supplicant_remove_iface(global, wpa_s);
1421}
1422
1423
1424static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
1425						  char *buf, int len)
1426{
1427	int res;
1428	char *pos, *end;
1429	struct wpa_supplicant *wpa_s;
1430
1431	wpa_s = global->ifaces;
1432	pos = buf;
1433	end = buf + len;
1434
1435	while (wpa_s) {
1436		res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
1437		if (res < 0 || res >= end - pos) {
1438			*pos = '\0';
1439			break;
1440		}
1441		pos += res;
1442		wpa_s = wpa_s->next;
1443	}
1444	return pos - buf;
1445}
1446
1447
1448char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
1449						char *buf, size_t *resp_len)
1450{
1451	char *reply;
1452	const int reply_size = 4096;
1453	int reply_len;
1454
1455    if (os_strcmp(buf, "PING") != 0)
1456        wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
1457                          (const u8 *) buf, os_strlen(buf));
1458
1459	reply = os_malloc(reply_size);
1460	if (reply == NULL) {
1461		*resp_len = 1;
1462		return NULL;
1463	}
1464
1465	os_memcpy(reply, "OK\n", 3);
1466	reply_len = 3;
1467
1468	if (os_strcmp(buf, "PING") == 0) {
1469		os_memcpy(reply, "PONG\n", 5);
1470		reply_len = 5;
1471	} else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
1472		if (wpa_supplicant_global_iface_add(global, buf + 14))
1473			reply_len = -1;
1474	} else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
1475		if (wpa_supplicant_global_iface_remove(global, buf + 17))
1476			reply_len = -1;
1477	} else if (os_strcmp(buf, "INTERFACES") == 0) {
1478		reply_len = wpa_supplicant_global_iface_interfaces(
1479			global, reply, reply_size);
1480	} else if (os_strcmp(buf, "TERMINATE") == 0) {
1481		eloop_terminate();
1482	} else {
1483		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1484		reply_len = 16;
1485	}
1486
1487	if (reply_len < 0) {
1488		os_memcpy(reply, "FAIL\n", 5);
1489		reply_len = 5;
1490	}
1491
1492	*resp_len = reply_len;
1493	return reply;
1494}
1495