ctrl_iface.c revision 189251
190731Sjhay/*
2158124Smarcel * WPA Supplicant / Control interface (shared code for all backends)
3158124Smarcel * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
490731Sjhay *
590731Sjhay * This program is free software; you can redistribute it and/or modify
690731Sjhay * it under the terms of the GNU General Public License version 2 as
790731Sjhay * published by the Free Software Foundation.
890731Sjhay *
990731Sjhay * Alternatively, this software may be distributed under the terms of BSD
1090731Sjhay * license.
1190731Sjhay *
1290731Sjhay * See README and COPYING for more details.
1390731Sjhay */
1490731Sjhay
1590731Sjhay#include "includes.h"
1690731Sjhay
1790731Sjhay#include "common.h"
1890731Sjhay#include "eloop.h"
1990731Sjhay#include "wpa.h"
2090731Sjhay#include "config.h"
2190731Sjhay#include "eapol_supp/eapol_supp_sm.h"
2290731Sjhay#include "wpa_supplicant_i.h"
2390731Sjhay#include "ctrl_iface.h"
2490731Sjhay#include "l2_packet/l2_packet.h"
2590731Sjhay#include "preauth.h"
2690731Sjhay#include "pmksa_cache.h"
2790731Sjhay#include "wpa_ctrl.h"
2890731Sjhay#include "eap_peer/eap.h"
2990731Sjhay#include "ieee802_11_defs.h"
3090731Sjhay#include "wps_supplicant.h"
3190731Sjhay#include "wps/wps.h"
3290731Sjhay
3390731Sjhaystatic int wpa_supplicant_global_iface_list(struct wpa_global *global,
3490731Sjhay					    char *buf, int len);
3590731Sjhaystatic int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
36158124Smarcel						  char *buf, int len);
37263109Srstone
3890731Sjhay
3990731Sjhaystatic int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
4090731Sjhay					 char *cmd)
4190731Sjhay{
4290731Sjhay	char *value;
4390731Sjhay	int ret = 0;
4490731Sjhay
45102714Sphk	value = os_strchr(cmd, ' ');
46158124Smarcel	if (value == NULL)
47158124Smarcel		return -1;
48160030Sobrien	*value++ = '\0';
4990731Sjhay
50158124Smarcel	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
5190731Sjhay	if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
52158124Smarcel		eapol_sm_configure(wpa_s->eapol,
53158124Smarcel				   atoi(value), -1, -1, -1);
54158124Smarcel	} else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
55158124Smarcel		eapol_sm_configure(wpa_s->eapol,
56158124Smarcel				   -1, atoi(value), -1, -1);
57158124Smarcel	} else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
58158124Smarcel		eapol_sm_configure(wpa_s->eapol,
59158124Smarcel				   -1, -1, atoi(value), -1);
6090731Sjhay	} else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
61158124Smarcel		eapol_sm_configure(wpa_s->eapol,
6290731Sjhay				   -1, -1, -1, atoi(value));
63158124Smarcel	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
64158124Smarcel		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
65158124Smarcel				     atoi(value)))
66158124Smarcel			ret = -1;
67158124Smarcel	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
68158124Smarcel		   0) {
69102893Sphk		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
70158124Smarcel				     atoi(value)))
71102893Sphk			ret = -1;
72227293Sed	} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
73158124Smarcel		if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
74263109Srstone			ret = -1;
75263109Srstone	} else
76158124Smarcel		ret = -1;
77158124Smarcel
78102734Sphk	return ret;
79158124Smarcel}
80158124Smarcel
81294883Sjhibbits
82158124Smarcel#ifdef IEEE8021X_EAPOL
83102734Sphkstatic int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
84158124Smarcel					     char *addr)
85158124Smarcel{
86158124Smarcel	u8 bssid[ETH_ALEN];
87158124Smarcel	struct wpa_ssid *ssid = wpa_s->current_ssid;
88158124Smarcel
89158124Smarcel	if (hwaddr_aton(addr, bssid)) {
90158124Smarcel		wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
91158124Smarcel			   "'%s'", addr);
92158124Smarcel		return -1;
93158124Smarcel	}
94158124Smarcel
95158124Smarcel	wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
96158124Smarcel	rsn_preauth_deinit(wpa_s->wpa);
97158124Smarcel	if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
98158124Smarcel		return -1;
99158124Smarcel
100158124Smarcel	return 0;
101158124Smarcel}
102158124Smarcel#endif /* IEEE8021X_EAPOL */
103158124Smarcel
104158124Smarcel
105158124Smarcel#ifdef CONFIG_PEERKEY
106158124Smarcel/* MLME-STKSTART.request(peer) */
107158124Smarcelstatic int wpa_supplicant_ctrl_iface_stkstart(
108158124Smarcel	struct wpa_supplicant *wpa_s, char *addr)
109158124Smarcel{
110158124Smarcel	u8 peer[ETH_ALEN];
111158124Smarcel
112102734Sphk	if (hwaddr_aton(addr, peer)) {
113158124Smarcel		wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
114158124Smarcel			   "address '%s'", peer);
115158124Smarcel		return -1;
116158124Smarcel	}
117158124Smarcel
118158124Smarcel	wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
119158124Smarcel		   MAC2STR(peer));
120158124Smarcel
121158124Smarcel	return wpa_sm_stkstart(wpa_s->wpa, peer);
122158124Smarcel}
123158124Smarcel#endif /* CONFIG_PEERKEY */
124158124Smarcel
125142502Ssam
126158124Smarcel#ifdef CONFIG_IEEE80211R
127158124Smarcelstatic int wpa_supplicant_ctrl_iface_ft_ds(
128102734Sphk	struct wpa_supplicant *wpa_s, char *addr)
129102734Sphk{
130166901Spiso	u8 target_ap[ETH_ALEN];
131158124Smarcel
132112270Ssobomax	if (hwaddr_aton(addr, target_ap)) {
133158124Smarcel		wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
134158124Smarcel			   "address '%s'", target_ap);
135200397Smarcel		return -1;
136200397Smarcel	}
137158124Smarcel
138112270Ssobomax	wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
139200397Smarcel
140200397Smarcel	return wpa_ft_start_over_ds(wpa_s->wpa, target_ap);
141200397Smarcel}
142200397Smarcel#endif /* CONFIG_IEEE80211R */
143200397Smarcel
144200397Smarcel
145200397Smarcel#ifdef CONFIG_WPS
146200397Smarcelstatic int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
147200397Smarcel					     char *cmd)
148200397Smarcel{
149200397Smarcel	u8 bssid[ETH_ALEN];
150200397Smarcel
151200397Smarcel	if (cmd == NULL || os_strcmp(cmd, "any") == 0)
152200397Smarcel		return wpas_wps_start_pbc(wpa_s, NULL);
153200397Smarcel
154200397Smarcel	if (hwaddr_aton(cmd, bssid)) {
155200397Smarcel		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
156200397Smarcel			   cmd);
157200397Smarcel		return -1;
158200397Smarcel	}
159200397Smarcel
160200397Smarcel	return wpas_wps_start_pbc(wpa_s, bssid);
161200397Smarcel}
162112270Ssobomax
163200397Smarcel
164200397Smarcelstatic int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
165200397Smarcel					     char *cmd, char *buf,
166158124Smarcel					     size_t buflen)
167200397Smarcel{
168200397Smarcel	u8 bssid[ETH_ALEN], *_bssid = bssid;
169158124Smarcel	char *pin;
170200397Smarcel	int ret;
171158124Smarcel
172200397Smarcel	pin = os_strchr(cmd, ' ');
173200397Smarcel	if (pin)
174200397Smarcel		*pin++ = '\0';
175158124Smarcel
176200397Smarcel	if (os_strcmp(cmd, "any") == 0)
177158124Smarcel		_bssid = NULL;
178200397Smarcel	else if (hwaddr_aton(cmd, bssid)) {
179200397Smarcel		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
180158124Smarcel			   cmd);
181200397Smarcel		return -1;
182200397Smarcel	}
183200397Smarcel
184200397Smarcel	if (pin) {
185200397Smarcel		ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
186200397Smarcel		if (ret < 0)
187200397Smarcel			return -1;
188200397Smarcel		ret = os_snprintf(buf, buflen, "%s", pin);
189200397Smarcel		if (ret < 0 || (size_t) ret >= buflen)
190200397Smarcel			return -1;
191200397Smarcel		return ret;
192200397Smarcel	}
193200397Smarcel
194200397Smarcel	ret = wpas_wps_start_pin(wpa_s, _bssid, NULL);
195200397Smarcel	if (ret < 0)
196200397Smarcel		return -1;
197200397Smarcel
198200397Smarcel	/* Return the generated PIN */
199200397Smarcel	ret = os_snprintf(buf, buflen, "%08d", ret);
200200397Smarcel	if (ret < 0 || (size_t) ret >= buflen)
201200397Smarcel		return -1;
202200397Smarcel	return ret;
203200397Smarcel}
204158124Smarcel
205200397Smarcel
206200397Smarcelstatic int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
207112270Ssobomax					     char *cmd)
208112270Ssobomax{
209102714Sphk	u8 bssid[ETH_ALEN], *_bssid = bssid;
210158124Smarcel	char *pin;
21190731Sjhay
212158124Smarcel	pin = os_strchr(cmd, ' ');
213158124Smarcel	if (pin == NULL)
214158124Smarcel		return -1;
21590731Sjhay	*pin++ = '\0';
216158124Smarcel
217158124Smarcel	if (os_strcmp(cmd, "any") == 0)
218158124Smarcel		_bssid = NULL;
219158124Smarcel	else if (hwaddr_aton(cmd, bssid)) {
220158124Smarcel		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
221158124Smarcel			   cmd);
222158124Smarcel		return -1;
22390731Sjhay	}
224158124Smarcel
225119814Smarcel	return wpas_wps_start_reg(wpa_s, _bssid, pin);
226158124Smarcel}
227158124Smarcel#endif /* CONFIG_WPS */
22890731Sjhay
229158124Smarcel
230158124Smarcelstatic int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
231158124Smarcel					      char *rsp)
232158124Smarcel{
233158124Smarcel#ifdef IEEE8021X_EAPOL
234158124Smarcel	char *pos, *id_pos;
235158124Smarcel	int id;
236158124Smarcel	struct wpa_ssid *ssid;
237158124Smarcel	struct eap_peer_config *eap;
238158124Smarcel
239158124Smarcel	pos = os_strchr(rsp, '-');
240158124Smarcel	if (pos == NULL)
241158124Smarcel		return -1;
242158124Smarcel	*pos++ = '\0';
243158124Smarcel	id_pos = pos;
244158124Smarcel	pos = os_strchr(pos, ':');
245158124Smarcel	if (pos == NULL)
24690731Sjhay		return -1;
247158124Smarcel	*pos++ = '\0';
248158124Smarcel	id = atoi(id_pos);
249158124Smarcel	wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
250158124Smarcel	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
251158124Smarcel			      (u8 *) pos, os_strlen(pos));
252158124Smarcel
253158124Smarcel	ssid = wpa_config_get_network(wpa_s->conf, id);
254158124Smarcel	if (ssid == NULL) {
255158124Smarcel		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
25690731Sjhay			   "to update", id);
257158124Smarcel		return -1;
258158124Smarcel	}
259158124Smarcel	eap = &ssid->eap;
260158124Smarcel
261158124Smarcel	if (os_strcmp(rsp, "IDENTITY") == 0) {
26290731Sjhay		os_free(eap->identity);
263158124Smarcel		eap->identity = (u8 *) os_strdup(pos);
264158124Smarcel		eap->identity_len = os_strlen(pos);
265158124Smarcel		eap->pending_req_identity = 0;
26690731Sjhay		if (ssid == wpa_s->current_ssid)
267158124Smarcel			wpa_s->reassociate = 1;
268158124Smarcel	} else if (os_strcmp(rsp, "PASSWORD") == 0) {
269158124Smarcel		os_free(eap->password);
270109458Smarcel		eap->password = (u8 *) os_strdup(pos);
271158124Smarcel		eap->password_len = os_strlen(pos);
272158124Smarcel		eap->pending_req_password = 0;
273158124Smarcel		if (ssid == wpa_s->current_ssid)
274158124Smarcel			wpa_s->reassociate = 1;
275158124Smarcel	} else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
276158124Smarcel		os_free(eap->new_password);
277158124Smarcel		eap->new_password = (u8 *) os_strdup(pos);
278158124Smarcel		eap->new_password_len = os_strlen(pos);
279158124Smarcel		eap->pending_req_new_password = 0;
280158124Smarcel		if (ssid == wpa_s->current_ssid)
281158124Smarcel			wpa_s->reassociate = 1;
282158124Smarcel	} else if (os_strcmp(rsp, "PIN") == 0) {
283158124Smarcel		os_free(eap->pin);
284158124Smarcel		eap->pin = os_strdup(pos);
285119814Smarcel		eap->pending_req_pin = 0;
286158124Smarcel		if (ssid == wpa_s->current_ssid)
287158124Smarcel			wpa_s->reassociate = 1;
288158124Smarcel	} else if (os_strcmp(rsp, "OTP") == 0) {
289158124Smarcel		os_free(eap->otp);
290158124Smarcel		eap->otp = (u8 *) os_strdup(pos);
291158124Smarcel		eap->otp_len = os_strlen(pos);
292158124Smarcel		os_free(eap->pending_req_otp);
293158124Smarcel		eap->pending_req_otp = NULL;
294158124Smarcel		eap->pending_req_otp_len = 0;
295158124Smarcel	} else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
296158124Smarcel		os_free(eap->private_key_passwd);
297158124Smarcel		eap->private_key_passwd = (u8 *) os_strdup(pos);
298158124Smarcel		eap->pending_req_passphrase = 0;
299158124Smarcel		if (ssid == wpa_s->current_ssid)
300158124Smarcel			wpa_s->reassociate = 1;
301158124Smarcel	} else {
302158124Smarcel		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
303158124Smarcel		return -1;
304158124Smarcel	}
305158124Smarcel
30690731Sjhay	return 0;
307158124Smarcel#else /* IEEE8021X_EAPOL */
308158124Smarcel	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
309158124Smarcel	return -1;
310158124Smarcel#endif /* IEEE8021X_EAPOL */
311158124Smarcel}
312112270Ssobomax
313158124Smarcel
314158124Smarcelstatic int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
315158124Smarcel					    const char *params,
316158124Smarcel					    char *buf, size_t buflen)
31790731Sjhay{
318158124Smarcel	char *pos, *end, tmp[30];
319158124Smarcel	int res, verbose, ret;
320158124Smarcel
321102734Sphk	verbose = os_strcmp(params, "-VERBOSE") == 0;
32290731Sjhay	pos = buf;
323158124Smarcel	end = buf + buflen;
324158124Smarcel	if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
325158124Smarcel		struct wpa_ssid *ssid = wpa_s->current_ssid;
326158124Smarcel		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
327158124Smarcel				  MAC2STR(wpa_s->bssid));
328158124Smarcel		if (ret < 0 || ret >= end - pos)
32990731Sjhay			return pos - buf;
330158124Smarcel		pos += ret;
331158124Smarcel		if (ssid) {
332158124Smarcel			u8 *_ssid = ssid->ssid;
333158124Smarcel			size_t ssid_len = ssid->ssid_len;
334166901Spiso			u8 ssid_buf[MAX_SSID_LEN];
335158124Smarcel			if (ssid_len == 0) {
336158124Smarcel				int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
337166901Spiso				if (_res < 0)
338166901Spiso					ssid_len = 0;
339158124Smarcel				else
340158124Smarcel					ssid_len = _res;
34190731Sjhay				_ssid = ssid_buf;
342158124Smarcel			}
343158124Smarcel			ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
344158124Smarcel					  wpa_ssid_txt(_ssid, ssid_len),
345158124Smarcel					  ssid->id);
346158124Smarcel			if (ret < 0 || ret >= end - pos)
34790731Sjhay				return pos - buf;
348158124Smarcel			pos += ret;
349158124Smarcel
350158124Smarcel			if (ssid->id_str) {
351158124Smarcel				ret = os_snprintf(pos, end - pos,
352158124Smarcel						  "id_str=%s\n",
35390731Sjhay						  ssid->id_str);
354158124Smarcel				if (ret < 0 || ret >= end - pos)
355158124Smarcel					return pos - buf;
356158124Smarcel				pos += ret;
357158124Smarcel			}
35890731Sjhay		}
359158124Smarcel
360158124Smarcel		pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
361158124Smarcel	}
362158124Smarcel	ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
36390925Snyan			  wpa_supplicant_state_txt(wpa_s->wpa_state));
36490731Sjhay	if (ret < 0 || ret >= end - pos)
36590731Sjhay		return pos - buf;
366158124Smarcel	pos += ret;
367158124Smarcel
368158124Smarcel	if (wpa_s->l2 &&
369158124Smarcel	    l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
370158124Smarcel		ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
371158124Smarcel		if (ret < 0 || ret >= end - pos)
372158124Smarcel			return pos - buf;
37390731Sjhay		pos += ret;
374158124Smarcel	}
375158124Smarcel
376158124Smarcel	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
377158124Smarcel	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
378158124Smarcel		res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
379158124Smarcel					  verbose);
380158124Smarcel		if (res >= 0)
381158124Smarcel			pos += res;
382158124Smarcel	}
383158124Smarcel
384158124Smarcel	res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
385158124Smarcel	if (res >= 0)
386158124Smarcel		pos += res;
387158124Smarcel
388158124Smarcel	return pos - buf;
389158124Smarcel}
390158124Smarcel
391158124Smarcel
392158124Smarcelstatic int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
393158124Smarcel					   char *cmd)
394158124Smarcel{
395158124Smarcel	char *pos;
396158124Smarcel	int id;
397158124Smarcel	struct wpa_ssid *ssid;
398158124Smarcel	u8 bssid[ETH_ALEN];
39990731Sjhay
40090731Sjhay	/* cmd: "<network id> <BSSID>" */
401158124Smarcel	pos = os_strchr(cmd, ' ');
402158124Smarcel	if (pos == NULL)
403112270Ssobomax		return -1;
404158124Smarcel	*pos++ = '\0';
405158124Smarcel	id = atoi(cmd);
406158124Smarcel	wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
407158124Smarcel	if (hwaddr_aton(pos, bssid)) {
408112270Ssobomax		wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
409158124Smarcel		return -1;
410112270Ssobomax	}
411158124Smarcel
412158124Smarcel	ssid = wpa_config_get_network(wpa_s->conf, id);
413158124Smarcel	if (ssid == NULL) {
414158124Smarcel		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
415158124Smarcel			   "to update", id);
416158124Smarcel		return -1;
417158124Smarcel	}
418158124Smarcel
419158124Smarcel	os_memcpy(ssid->bssid, bssid, ETH_ALEN);
420158124Smarcel	ssid->bssid_set = !is_zero_ether_addr(bssid);
421158124Smarcel
422158124Smarcel	return 0;
423158124Smarcel}
424158124Smarcel
425112270Ssobomax
426158124Smarcelstatic int wpa_supplicant_ctrl_iface_list_networks(
427158124Smarcel	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
428112270Ssobomax{
429158124Smarcel	char *pos, *end;
430158124Smarcel	struct wpa_ssid *ssid;
431158124Smarcel	int ret;
43290731Sjhay
433158124Smarcel	pos = buf;
434158124Smarcel	end = buf + buflen;
435158124Smarcel	ret = os_snprintf(pos, end - pos,
436158124Smarcel			  "network id / ssid / bssid / flags\n");
437158124Smarcel	if (ret < 0 || ret >= end - pos)
438158124Smarcel		return pos - buf;
439158124Smarcel	pos += ret;
440158124Smarcel
441158124Smarcel	ssid = wpa_s->conf->ssid;
442158124Smarcel	while (ssid) {
443158124Smarcel		ret = os_snprintf(pos, end - pos, "%d\t%s",
444158124Smarcel				  ssid->id,
445158124Smarcel				  wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
446158124Smarcel		if (ret < 0 || ret >= end - pos)
447158124Smarcel			return pos - buf;
44890731Sjhay		pos += ret;
44990731Sjhay		if (ssid->bssid_set) {
450158124Smarcel			ret = os_snprintf(pos, end - pos, "\t" MACSTR,
451158124Smarcel					  MAC2STR(ssid->bssid));
45290731Sjhay		} else {
453158124Smarcel			ret = os_snprintf(pos, end - pos, "\tany");
454158124Smarcel		}
455158124Smarcel		if (ret < 0 || ret >= end - pos)
45690731Sjhay			return pos - buf;
457158124Smarcel		pos += ret;
458158124Smarcel		ret = os_snprintf(pos, end - pos, "\t%s%s",
459158124Smarcel				  ssid == wpa_s->current_ssid ?
46090731Sjhay				  "[CURRENT]" : "",
461158124Smarcel				  ssid->disabled ? "[DISABLED]" : "");
462158124Smarcel		if (ret < 0 || ret >= end - pos)
463158124Smarcel			return pos - buf;
464158124Smarcel		pos += ret;
465158124Smarcel		ret = os_snprintf(pos, end - pos, "\n");
466158124Smarcel		if (ret < 0 || ret >= end - pos)
467158124Smarcel			return pos - buf;
468158124Smarcel		pos += ret;
469158124Smarcel
470158124Smarcel		ssid = ssid->next;
471158124Smarcel	}
472158124Smarcel
47390731Sjhay	return pos - buf;
47490731Sjhay}
475102714Sphk
476158124Smarcel
477294883Sjhibbitsstatic char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
47890731Sjhay{
479158124Smarcel	int first = 1, ret;
480158124Smarcel	ret = os_snprintf(pos, end - pos, "-");
481158124Smarcel	if (ret < 0 || ret >= end - pos)
482158124Smarcel		return pos;
48390731Sjhay	pos += ret;
484158124Smarcel	if (cipher & WPA_CIPHER_NONE) {
485158124Smarcel		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
486158124Smarcel		if (ret < 0 || ret >= end - pos)
487158124Smarcel			return pos;
488158124Smarcel		pos += ret;
489158124Smarcel		first = 0;
490118292Sambrisko	}
491158124Smarcel	if (cipher & WPA_CIPHER_WEP40) {
492158124Smarcel		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
49390731Sjhay		if (ret < 0 || ret >= end - pos)
494158124Smarcel			return pos;
495158124Smarcel		pos += ret;
496158124Smarcel		first = 0;
497158124Smarcel	}
498296298Sjhibbits	if (cipher & WPA_CIPHER_WEP104) {
499158124Smarcel		ret = os_snprintf(pos, end - pos, "%sWEP104",
500158124Smarcel				  first ? "" : "+");
501158124Smarcel		if (ret < 0 || ret >= end - pos)
502158124Smarcel			return pos;
503158124Smarcel		pos += ret;
504158124Smarcel		first = 0;
505118292Sambrisko	}
506158124Smarcel	if (cipher & WPA_CIPHER_TKIP) {
50790731Sjhay		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
508158124Smarcel		if (ret < 0 || ret >= end - pos)
509158124Smarcel			return pos;
510158124Smarcel		pos += ret;
511158124Smarcel		first = 0;
512158124Smarcel	}
513158124Smarcel	if (cipher & WPA_CIPHER_CCMP) {
514158124Smarcel		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
515158124Smarcel		if (ret < 0 || ret >= end - pos)
516158124Smarcel			return pos;
517158124Smarcel		pos += ret;
518158124Smarcel		first = 0;
519158124Smarcel	}
520158124Smarcel	return pos;
521158124Smarcel}
522158124Smarcel
523158124Smarcel
524158124Smarcelstatic char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
525158124Smarcel				    const u8 *ie, size_t ie_len)
526158124Smarcel{
52790731Sjhay	struct wpa_ie_data data;
52890731Sjhay	int first, ret;
529102714Sphk
530158124Smarcel	ret = os_snprintf(pos, end - pos, "[%s-", proto);
53190731Sjhay	if (ret < 0 || ret >= end - pos)
53290731Sjhay		return pos;
533158124Smarcel	pos += ret;
534158124Smarcel
535158124Smarcel	if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
536158124Smarcel		ret = os_snprintf(pos, end - pos, "?]");
537158124Smarcel		if (ret < 0 || ret >= end - pos)
538158124Smarcel			return pos;
539158124Smarcel		pos += ret;
540158124Smarcel		return pos;
541158124Smarcel	}
542158124Smarcel
543158124Smarcel	first = 1;
544158124Smarcel	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
545158124Smarcel		ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
546158124Smarcel		if (ret < 0 || ret >= end - pos)
547158124Smarcel			return pos;
548158124Smarcel		pos += ret;
549158124Smarcel		first = 0;
550158124Smarcel	}
551158124Smarcel	if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
552158124Smarcel		ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
553158124Smarcel		if (ret < 0 || ret >= end - pos)
554158124Smarcel			return pos;
555158124Smarcel		pos += ret;
556158124Smarcel		first = 0;
557158124Smarcel	}
558158124Smarcel	if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
559158124Smarcel		ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
560158124Smarcel		if (ret < 0 || ret >= end - pos)
561158124Smarcel			return pos;
562158124Smarcel		pos += ret;
563158124Smarcel		first = 0;
564158124Smarcel	}
56590731Sjhay#ifdef CONFIG_IEEE80211R
56690731Sjhay	if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
56790731Sjhay		ret = os_snprintf(pos, end - pos, "%sFT/EAP",
568102714Sphk				  first ? "" : "+");
569158124Smarcel		if (ret < 0 || ret >= end - pos)
570294883Sjhibbits			return pos;
57190731Sjhay		pos += ret;
572158124Smarcel		first = 0;
573158124Smarcel	}
574294883Sjhibbits	if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
57590731Sjhay		ret = os_snprintf(pos, end - pos, "%sFT/PSK",
576158124Smarcel				  first ? "" : "+");
577158124Smarcel		if (ret < 0 || ret >= end - pos)
578158124Smarcel			return pos;
579158124Smarcel		pos += ret;
580158124Smarcel		first = 0;
58190731Sjhay	}
582158124Smarcel#endif /* CONFIG_IEEE80211R */
583158124Smarcel#ifdef CONFIG_IEEE80211W
584158124Smarcel	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
585158124Smarcel		ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
586158124Smarcel				  first ? "" : "+");
587158124Smarcel		if (ret < 0 || ret >= end - pos)
588158124Smarcel			return pos;
589158124Smarcel		pos += ret;
590158124Smarcel		first = 0;
591158124Smarcel	}
592158124Smarcel	if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
593158124Smarcel		ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
594158124Smarcel				  first ? "" : "+");
595158124Smarcel		if (ret < 0 || ret >= end - pos)
596158124Smarcel			return pos;
597158124Smarcel		pos += ret;
598158124Smarcel		first = 0;
599158124Smarcel	}
600158124Smarcel#endif /* CONFIG_IEEE80211W */
60190731Sjhay
60290731Sjhay	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
603102714Sphk
604158124Smarcel	if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
605166901Spiso		ret = os_snprintf(pos, end - pos, "-preauth");
60690731Sjhay		if (ret < 0 || ret >= end - pos)
607158124Smarcel			return pos;
60890731Sjhay		pos += ret;
609158124Smarcel	}
610158124Smarcel
61190731Sjhay	ret = os_snprintf(pos, end - pos, "]");
612158124Smarcel	if (ret < 0 || ret >= end - pos)
613158124Smarcel		return pos;
614158124Smarcel	pos += ret;
615158124Smarcel
616158124Smarcel	return pos;
617158124Smarcel}
618158124Smarcel
619158124Smarcelstatic char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
620158124Smarcel					const struct wpa_scan_res *res)
621158124Smarcel{
622158124Smarcel#ifdef CONFIG_WPS
623158124Smarcel	struct wpabuf *wps_ie;
624170386Spiso	int ret;
625158124Smarcel	const char *txt;
626170386Spiso
627245471Sjhb	wps_ie = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
628170386Spiso	if (wps_ie == NULL)
629158124Smarcel		return pos;
630102895Sphk
631158124Smarcel	if (wps_is_selected_pbc_registrar(wps_ie))
632158124Smarcel		txt = "[WPS-PBC]";
633158124Smarcel	else if (wps_is_selected_pin_registrar(wps_ie))
634158124Smarcel		txt = "[WPS-PIN]";
635158124Smarcel	else
636158124Smarcel		txt = "[WPS]";
637158124Smarcel
638158124Smarcel	ret = os_snprintf(pos, end - pos, "%s", txt);
639158124Smarcel	if (ret >= 0 && ret < end - pos)
640158124Smarcel		pos += ret;
641158124Smarcel	wpabuf_free(wps_ie);
642158124Smarcel#endif /* CONFIG_WPS */
643158124Smarcel
644158124Smarcel	return pos;
64590731Sjhay}
64690731Sjhay
647158124Smarcel
648158124Smarcel/* Format one result on one text line into a buffer. */
649166901Spisostatic int wpa_supplicant_ctrl_iface_scan_result(
650158124Smarcel	const struct wpa_scan_res *res, char *buf, size_t buflen)
651158124Smarcel{
652158124Smarcel	char *pos, *end;
653158124Smarcel	int ret;
654158124Smarcel	const u8 *ie, *ie2;
655158124Smarcel
656158124Smarcel	pos = buf;
657158124Smarcel	end = buf + buflen;
65890731Sjhay
65990731Sjhay	ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
660102714Sphk			  MAC2STR(res->bssid), res->freq, res->level);
661158124Smarcel	if (ret < 0 || ret >= end - pos)
662158124Smarcel		return pos - buf;
66390731Sjhay	pos += ret;
664158124Smarcel	ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
665158124Smarcel	if (ie)
666158124Smarcel		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
66790731Sjhay	ie2 = wpa_scan_get_ie(res, WLAN_EID_RSN);
66890731Sjhay	if (ie2)
669158124Smarcel		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
670158124Smarcel	pos = wpa_supplicant_wps_ie_txt(pos, end, res);
671158124Smarcel	if (!ie && !ie2 && res->caps & IEEE80211_CAP_PRIVACY) {
672158124Smarcel		ret = os_snprintf(pos, end - pos, "[WEP]");
673158124Smarcel		if (ret < 0 || ret >= end - pos)
674158124Smarcel			return pos - buf;
675158124Smarcel		pos += ret;
676158124Smarcel	}
677158124Smarcel	if (res->caps & IEEE80211_CAP_IBSS) {
678158124Smarcel		ret = os_snprintf(pos, end - pos, "[IBSS]");
679158124Smarcel		if (ret < 0 || ret >= end - pos)
680158124Smarcel			return pos - buf;
681158124Smarcel		pos += ret;
682158124Smarcel	}
683158124Smarcel
684158124Smarcel	ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
685158124Smarcel	ret = os_snprintf(pos, end - pos, "\t%s",
686158124Smarcel			  ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
687158124Smarcel	if (ret < 0 || ret >= end - pos)
688158124Smarcel		return pos - buf;
689158124Smarcel	pos += ret;
690158124Smarcel
691158124Smarcel	ret = os_snprintf(pos, end - pos, "\n");
692158124Smarcel	if (ret < 0 || ret >= end - pos)
693158124Smarcel		return pos - buf;
694158124Smarcel	pos += ret;
695158124Smarcel
696158124Smarcel	return pos - buf;
697158124Smarcel}
698158124Smarcel
699158124Smarcel
70090731Sjhaystatic int wpa_supplicant_ctrl_iface_scan_results(
70190731Sjhay	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
702102714Sphk{
703158124Smarcel	char *pos, *end;
70490731Sjhay	struct wpa_scan_res *res;
705158124Smarcel	int ret;
70690731Sjhay	size_t i;
707158124Smarcel
708158124Smarcel	if (wpa_s->scan_res == NULL &&
709158124Smarcel	    wpa_supplicant_get_scan_results(wpa_s) < 0)
710158124Smarcel		return 0;
711158124Smarcel
71290731Sjhay	pos = buf;
713158124Smarcel	end = buf + buflen;
714158124Smarcel	ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
715158124Smarcel			  "flags / ssid\n");
716158124Smarcel	if (ret < 0 || ret >= end - pos)
717158124Smarcel		return pos - buf;
718158124Smarcel	pos += ret;
71990731Sjhay
720158124Smarcel	for (i = 0; i < wpa_s->scan_res->num; i++) {
721158124Smarcel		res = wpa_s->scan_res->res[i];
72290731Sjhay		ret = wpa_supplicant_ctrl_iface_scan_result(res, pos,
723158124Smarcel							    end - pos);
724158124Smarcel		if (ret < 0 || ret >= end - pos)
725119814Smarcel			return pos - buf;
72690731Sjhay		pos += ret;
72790731Sjhay	}
72890731Sjhay
72990731Sjhay	return pos - buf;
73090731Sjhay}
731223091Sjhb
732223091Sjhb
733223091Sjhbstatic int wpa_supplicant_ctrl_iface_select_network(
734223091Sjhb	struct wpa_supplicant *wpa_s, char *cmd)
735223091Sjhb{
736223091Sjhb	int id;
737223091Sjhb	struct wpa_ssid *ssid;
738223091Sjhb
739223091Sjhb	/* cmd: "<network id>" or "any" */
740223091Sjhb	if (os_strcmp(cmd, "any") == 0) {
741223091Sjhb		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
742223091Sjhb		ssid = wpa_s->conf->ssid;
743223091Sjhb		while (ssid) {
744223091Sjhb			ssid->disabled = 0;
745223091Sjhb			ssid = ssid->next;
746223091Sjhb		}
747223091Sjhb		wpa_s->reassociate = 1;
748223091Sjhb		wpa_supplicant_req_scan(wpa_s, 0, 0);
749223091Sjhb		return 0;
750223091Sjhb	}
751223091Sjhb
752223091Sjhb	id = atoi(cmd);
753223091Sjhb	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
754223091Sjhb
755223091Sjhb	ssid = wpa_config_get_network(wpa_s->conf, id);
756223091Sjhb	if (ssid == NULL) {
757223091Sjhb		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
758223091Sjhb			   "id=%d", id);
759223091Sjhb		return -1;
760223091Sjhb	}
761223091Sjhb
762223091Sjhb	if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
763223091Sjhb		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
764223091Sjhb
765223091Sjhb	/* Mark all other networks disabled and trigger reassociation */
766223091Sjhb	ssid = wpa_s->conf->ssid;
767223091Sjhb	while (ssid) {
768223091Sjhb		ssid->disabled = id != ssid->id;
769		ssid = ssid->next;
770	}
771	wpa_s->reassociate = 1;
772	wpa_supplicant_req_scan(wpa_s, 0, 0);
773
774	return 0;
775}
776
777
778static int wpa_supplicant_ctrl_iface_enable_network(
779	struct wpa_supplicant *wpa_s, char *cmd)
780{
781	int id;
782	struct wpa_ssid *ssid;
783
784	/* cmd: "<network id>" or "all" */
785	if (os_strcmp(cmd, "all") == 0) {
786		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
787		ssid = wpa_s->conf->ssid;
788		while (ssid) {
789			if (ssid == wpa_s->current_ssid && ssid->disabled)
790				wpa_s->reassociate = 1;
791			ssid->disabled = 0;
792			ssid = ssid->next;
793		}
794		if (wpa_s->reassociate)
795			wpa_supplicant_req_scan(wpa_s, 0, 0);
796		return 0;
797	}
798
799	id = atoi(cmd);
800	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
801
802	ssid = wpa_config_get_network(wpa_s->conf, id);
803	if (ssid == NULL) {
804		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
805			   "id=%d", id);
806		return -1;
807	}
808
809	if (wpa_s->current_ssid == NULL && ssid->disabled) {
810		/*
811		 * Try to reassociate since there is no current configuration
812		 * and a new network was made available. */
813		wpa_s->reassociate = 1;
814		wpa_supplicant_req_scan(wpa_s, 0, 0);
815	}
816	ssid->disabled = 0;
817
818	return 0;
819}
820
821
822static int wpa_supplicant_ctrl_iface_disable_network(
823	struct wpa_supplicant *wpa_s, char *cmd)
824{
825	int id;
826	struct wpa_ssid *ssid;
827
828	/* cmd: "<network id>" or "all" */
829	if (os_strcmp(cmd, "all") == 0) {
830		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
831		ssid = wpa_s->conf->ssid;
832		while (ssid) {
833			ssid->disabled = 1;
834			ssid = ssid->next;
835		}
836		if (wpa_s->current_ssid)
837			wpa_supplicant_disassociate(wpa_s,
838				                    WLAN_REASON_DEAUTH_LEAVING);
839		return 0;
840	}
841
842	id = atoi(cmd);
843	wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
844
845	ssid = wpa_config_get_network(wpa_s->conf, id);
846	if (ssid == NULL) {
847		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
848			   "id=%d", id);
849		return -1;
850	}
851
852	if (ssid == wpa_s->current_ssid)
853		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
854	ssid->disabled = 1;
855
856	return 0;
857}
858
859
860static int wpa_supplicant_ctrl_iface_add_network(
861	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
862{
863	struct wpa_ssid *ssid;
864	int ret;
865
866	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
867
868	ssid = wpa_config_add_network(wpa_s->conf);
869	if (ssid == NULL)
870		return -1;
871	ssid->disabled = 1;
872	wpa_config_set_network_defaults(ssid);
873
874	ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
875	if (ret < 0 || (size_t) ret >= buflen)
876		return -1;
877	return ret;
878}
879
880
881static int wpa_supplicant_ctrl_iface_remove_network(
882	struct wpa_supplicant *wpa_s, char *cmd)
883{
884	int id;
885	struct wpa_ssid *ssid;
886
887	/* cmd: "<network id>" or "all" */
888	if (os_strcmp(cmd, "all") == 0) {
889		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
890		ssid = wpa_s->conf->ssid;
891		while (ssid) {
892			id = ssid->id;
893			ssid = ssid->next;
894			wpa_config_remove_network(wpa_s->conf, id);
895		}
896		if (wpa_s->current_ssid) {
897			eapol_sm_invalidate_cached_session(wpa_s->eapol);
898			wpa_supplicant_disassociate(wpa_s,
899				                    WLAN_REASON_DEAUTH_LEAVING);
900		}
901		return 0;
902	}
903
904	id = atoi(cmd);
905	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
906
907	ssid = wpa_config_get_network(wpa_s->conf, id);
908	if (ssid == NULL ||
909	    wpa_config_remove_network(wpa_s->conf, id) < 0) {
910		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
911			   "id=%d", id);
912		return -1;
913	}
914
915	if (ssid == wpa_s->current_ssid) {
916		/*
917		 * Invalidate the EAP session cache if the current network is
918		 * removed.
919		 */
920		eapol_sm_invalidate_cached_session(wpa_s->eapol);
921
922		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
923	}
924
925	return 0;
926}
927
928
929static int wpa_supplicant_ctrl_iface_set_network(
930	struct wpa_supplicant *wpa_s, char *cmd)
931{
932	int id;
933	struct wpa_ssid *ssid;
934	char *name, *value;
935
936	/* cmd: "<network id> <variable name> <value>" */
937	name = os_strchr(cmd, ' ');
938	if (name == NULL)
939		return -1;
940	*name++ = '\0';
941
942	value = os_strchr(name, ' ');
943	if (value == NULL)
944		return -1;
945	*value++ = '\0';
946
947	id = atoi(cmd);
948	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
949		   id, name);
950	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
951			      (u8 *) value, os_strlen(value));
952
953	ssid = wpa_config_get_network(wpa_s->conf, id);
954	if (ssid == NULL) {
955		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
956			   "id=%d", id);
957		return -1;
958	}
959
960	if (wpa_config_set(ssid, name, value, 0) < 0) {
961		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
962			   "variable '%s'", name);
963		return -1;
964	}
965
966	if (wpa_s->current_ssid == ssid) {
967		/*
968		 * Invalidate the EAP session cache if anything in the current
969		 * configuration changes.
970		 */
971		eapol_sm_invalidate_cached_session(wpa_s->eapol);
972	}
973
974	if ((os_strcmp(name, "psk") == 0 &&
975	     value[0] == '"' && ssid->ssid_len) ||
976	    (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
977		wpa_config_update_psk(ssid);
978
979	return 0;
980}
981
982
983static int wpa_supplicant_ctrl_iface_get_network(
984	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
985{
986	int id;
987	size_t res;
988	struct wpa_ssid *ssid;
989	char *name, *value;
990
991	/* cmd: "<network id> <variable name>" */
992	name = os_strchr(cmd, ' ');
993	if (name == NULL || buflen == 0)
994		return -1;
995	*name++ = '\0';
996
997	id = atoi(cmd);
998	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
999		   id, name);
1000
1001	ssid = wpa_config_get_network(wpa_s->conf, id);
1002	if (ssid == NULL) {
1003		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
1004			   "id=%d", id);
1005		return -1;
1006	}
1007
1008	value = wpa_config_get_no_key(ssid, name);
1009	if (value == NULL) {
1010		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
1011			   "variable '%s'", name);
1012		return -1;
1013	}
1014
1015	res = os_strlcpy(buf, value, buflen);
1016	if (res >= buflen) {
1017		os_free(value);
1018		return -1;
1019	}
1020
1021	os_free(value);
1022
1023	return res;
1024}
1025
1026
1027#ifndef CONFIG_NO_CONFIG_WRITE
1028static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
1029{
1030	int ret;
1031
1032	if (!wpa_s->conf->update_config) {
1033		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
1034			   "to update configuration (update_config=0)");
1035		return -1;
1036	}
1037
1038	ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
1039	if (ret) {
1040		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
1041			   "update configuration");
1042	} else {
1043		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
1044			   " updated");
1045	}
1046
1047	return ret;
1048}
1049#endif /* CONFIG_NO_CONFIG_WRITE */
1050
1051
1052static int ctrl_iface_get_capability_pairwise(int res, char *strict,
1053					      struct wpa_driver_capa *capa,
1054					      char *buf, size_t buflen)
1055{
1056	int ret, first = 1;
1057	char *pos, *end;
1058	size_t len;
1059
1060	pos = buf;
1061	end = pos + buflen;
1062
1063	if (res < 0) {
1064		if (strict)
1065			return 0;
1066		len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
1067		if (len >= buflen)
1068			return -1;
1069		return len;
1070	}
1071
1072	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
1073		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
1074		if (ret < 0 || ret >= end - pos)
1075			return pos - buf;
1076		pos += ret;
1077		first = 0;
1078	}
1079
1080	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
1081		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
1082		if (ret < 0 || ret >= end - pos)
1083			return pos - buf;
1084		pos += ret;
1085		first = 0;
1086	}
1087
1088	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1089		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
1090		if (ret < 0 || ret >= end - pos)
1091			return pos - buf;
1092		pos += ret;
1093		first = 0;
1094	}
1095
1096	return pos - buf;
1097}
1098
1099
1100static int ctrl_iface_get_capability_group(int res, char *strict,
1101					   struct wpa_driver_capa *capa,
1102					   char *buf, size_t buflen)
1103{
1104	int ret, first = 1;
1105	char *pos, *end;
1106	size_t len;
1107
1108	pos = buf;
1109	end = pos + buflen;
1110
1111	if (res < 0) {
1112		if (strict)
1113			return 0;
1114		len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
1115		if (len >= buflen)
1116			return -1;
1117		return len;
1118	}
1119
1120	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
1121		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
1122		if (ret < 0 || ret >= end - pos)
1123			return pos - buf;
1124		pos += ret;
1125		first = 0;
1126	}
1127
1128	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
1129		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
1130		if (ret < 0 || ret >= end - pos)
1131			return pos - buf;
1132		pos += ret;
1133		first = 0;
1134	}
1135
1136	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
1137		ret = os_snprintf(pos, end - pos, "%sWEP104",
1138				  first ? "" : " ");
1139		if (ret < 0 || ret >= end - pos)
1140			return pos - buf;
1141		pos += ret;
1142		first = 0;
1143	}
1144
1145	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
1146		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
1147		if (ret < 0 || ret >= end - pos)
1148			return pos - buf;
1149		pos += ret;
1150		first = 0;
1151	}
1152
1153	return pos - buf;
1154}
1155
1156
1157static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
1158					      struct wpa_driver_capa *capa,
1159					      char *buf, size_t buflen)
1160{
1161	int ret;
1162	char *pos, *end;
1163	size_t len;
1164
1165	pos = buf;
1166	end = pos + buflen;
1167
1168	if (res < 0) {
1169		if (strict)
1170			return 0;
1171		len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
1172				 "NONE", buflen);
1173		if (len >= buflen)
1174			return -1;
1175		return len;
1176	}
1177
1178	ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
1179	if (ret < 0 || ret >= end - pos)
1180		return pos - buf;
1181	pos += ret;
1182
1183	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1184			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
1185		ret = os_snprintf(pos, end - pos, " WPA-EAP");
1186		if (ret < 0 || ret >= end - pos)
1187			return pos - buf;
1188		pos += ret;
1189	}
1190
1191	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
1192			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1193		ret = os_snprintf(pos, end - pos, " WPA-PSK");
1194		if (ret < 0 || ret >= end - pos)
1195			return pos - buf;
1196		pos += ret;
1197	}
1198
1199	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
1200		ret = os_snprintf(pos, end - pos, " WPA-NONE");
1201		if (ret < 0 || ret >= end - pos)
1202			return pos - buf;
1203		pos += ret;
1204	}
1205
1206	return pos - buf;
1207}
1208
1209
1210static int ctrl_iface_get_capability_proto(int res, char *strict,
1211					   struct wpa_driver_capa *capa,
1212					   char *buf, size_t buflen)
1213{
1214	int ret, first = 1;
1215	char *pos, *end;
1216	size_t len;
1217
1218	pos = buf;
1219	end = pos + buflen;
1220
1221	if (res < 0) {
1222		if (strict)
1223			return 0;
1224		len = os_strlcpy(buf, "RSN WPA", buflen);
1225		if (len >= buflen)
1226			return -1;
1227		return len;
1228	}
1229
1230	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
1231			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
1232		ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
1233		if (ret < 0 || ret >= end - pos)
1234			return pos - buf;
1235		pos += ret;
1236		first = 0;
1237	}
1238
1239	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
1240			      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
1241		ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
1242		if (ret < 0 || ret >= end - pos)
1243			return pos - buf;
1244		pos += ret;
1245		first = 0;
1246	}
1247
1248	return pos - buf;
1249}
1250
1251
1252static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
1253					      struct wpa_driver_capa *capa,
1254					      char *buf, size_t buflen)
1255{
1256	int ret, first = 1;
1257	char *pos, *end;
1258	size_t len;
1259
1260	pos = buf;
1261	end = pos + buflen;
1262
1263	if (res < 0) {
1264		if (strict)
1265			return 0;
1266		len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
1267		if (len >= buflen)
1268			return -1;
1269		return len;
1270	}
1271
1272	if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
1273		ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
1274		if (ret < 0 || ret >= end - pos)
1275			return pos - buf;
1276		pos += ret;
1277		first = 0;
1278	}
1279
1280	if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
1281		ret = os_snprintf(pos, end - pos, "%sSHARED",
1282				  first ? "" : " ");
1283		if (ret < 0 || ret >= end - pos)
1284			return pos - buf;
1285		pos += ret;
1286		first = 0;
1287	}
1288
1289	if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
1290		ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
1291		if (ret < 0 || ret >= end - pos)
1292			return pos - buf;
1293		pos += ret;
1294		first = 0;
1295	}
1296
1297	return pos - buf;
1298}
1299
1300
1301static int wpa_supplicant_ctrl_iface_get_capability(
1302	struct wpa_supplicant *wpa_s, const char *_field, char *buf,
1303	size_t buflen)
1304{
1305	struct wpa_driver_capa capa;
1306	int res;
1307	char *strict;
1308	char field[30];
1309	size_t len;
1310
1311	/* Determine whether or not strict checking was requested */
1312	len = os_strlcpy(field, _field, sizeof(field));
1313	if (len >= sizeof(field))
1314		return -1;
1315	strict = os_strchr(field, ' ');
1316	if (strict != NULL) {
1317		*strict++ = '\0';
1318		if (os_strcmp(strict, "strict") != 0)
1319			return -1;
1320	}
1321
1322	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
1323		field, strict ? strict : "");
1324
1325	if (os_strcmp(field, "eap") == 0) {
1326		return eap_get_names(buf, buflen);
1327	}
1328
1329	res = wpa_drv_get_capa(wpa_s, &capa);
1330
1331	if (os_strcmp(field, "pairwise") == 0)
1332		return ctrl_iface_get_capability_pairwise(res, strict, &capa,
1333							  buf, buflen);
1334
1335	if (os_strcmp(field, "group") == 0)
1336		return ctrl_iface_get_capability_group(res, strict, &capa,
1337						       buf, buflen);
1338
1339	if (os_strcmp(field, "key_mgmt") == 0)
1340		return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
1341							  buf, buflen);
1342
1343	if (os_strcmp(field, "proto") == 0)
1344		return ctrl_iface_get_capability_proto(res, strict, &capa,
1345						       buf, buflen);
1346
1347	if (os_strcmp(field, "auth_alg") == 0)
1348		return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
1349							  buf, buflen);
1350
1351	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
1352		   field);
1353
1354	return -1;
1355}
1356
1357
1358static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
1359					 const char *cmd, char *buf,
1360					 size_t buflen)
1361{
1362	u8 bssid[ETH_ALEN];
1363	size_t i;
1364	struct wpa_scan_results *results;
1365	struct wpa_scan_res *bss;
1366	int ret;
1367	char *pos, *end;
1368	const u8 *ie, *ie2;
1369
1370	if (wpa_s->scan_res == NULL &&
1371	    wpa_supplicant_get_scan_results(wpa_s) < 0)
1372		return 0;
1373
1374	results = wpa_s->scan_res;
1375	if (results == NULL)
1376		return 0;
1377
1378	if (hwaddr_aton(cmd, bssid) == 0) {
1379		for (i = 0; i < results->num; i++) {
1380			if (os_memcmp(bssid, results->res[i]->bssid, ETH_ALEN)
1381			    == 0)
1382				break;
1383		}
1384	} else
1385		i = atoi(cmd);
1386
1387	if (i >= results->num || results->res[i] == NULL)
1388		return 0; /* no match found */
1389
1390	bss = results->res[i];
1391	pos = buf;
1392	end = buf + buflen;
1393	ret = os_snprintf(pos, end - pos,
1394			  "bssid=" MACSTR "\n"
1395			  "freq=%d\n"
1396			  "beacon_int=%d\n"
1397			  "capabilities=0x%04x\n"
1398			  "qual=%d\n"
1399			  "noise=%d\n"
1400			  "level=%d\n"
1401			  "tsf=%016llu\n"
1402			  "ie=",
1403			  MAC2STR(bss->bssid), bss->freq, bss->beacon_int,
1404			  bss->caps, bss->qual, bss->noise, bss->level,
1405			  (unsigned long long) bss->tsf);
1406	if (ret < 0 || ret >= end - pos)
1407		return pos - buf;
1408	pos += ret;
1409
1410	ie = (const u8 *) (bss + 1);
1411	for (i = 0; i < bss->ie_len; i++) {
1412		ret = os_snprintf(pos, end - pos, "%02x", *ie++);
1413		if (ret < 0 || ret >= end - pos)
1414			return pos - buf;
1415		pos += ret;
1416	}
1417
1418	ret = os_snprintf(pos, end - pos, "\n");
1419	if (ret < 0 || ret >= end - pos)
1420		return pos - buf;
1421	pos += ret;
1422
1423	ret = os_snprintf(pos, end - pos, "flags=");
1424	if (ret < 0 || ret >= end - pos)
1425		return pos - buf;
1426	pos += ret;
1427
1428	ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
1429	if (ie)
1430		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
1431	ie2 = wpa_scan_get_ie(bss, WLAN_EID_RSN);
1432	if (ie2)
1433		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
1434	pos = wpa_supplicant_wps_ie_txt(pos, end, bss);
1435	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
1436		ret = os_snprintf(pos, end - pos, "[WEP]");
1437		if (ret < 0 || ret >= end - pos)
1438			return pos - buf;
1439		pos += ret;
1440	}
1441	if (bss->caps & IEEE80211_CAP_IBSS) {
1442		ret = os_snprintf(pos, end - pos, "[IBSS]");
1443		if (ret < 0 || ret >= end - pos)
1444			return pos - buf;
1445		pos += ret;
1446	}
1447
1448	ret = os_snprintf(pos, end - pos, "\n");
1449	if (ret < 0 || ret >= end - pos)
1450		return pos - buf;
1451	pos += ret;
1452
1453	ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
1454	ret = os_snprintf(pos, end - pos, "ssid=%s\n",
1455			  ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
1456	if (ret < 0 || ret >= end - pos)
1457		return pos - buf;
1458	pos += ret;
1459
1460	return pos - buf;
1461}
1462
1463
1464static int wpa_supplicant_ctrl_iface_ap_scan(
1465	struct wpa_supplicant *wpa_s, char *cmd)
1466{
1467	int ap_scan = atoi(cmd);
1468
1469	if (ap_scan < 0 || ap_scan > 2)
1470		return -1;
1471	wpa_s->conf->ap_scan = ap_scan;
1472	return 0;
1473}
1474
1475
1476char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
1477					 char *buf, size_t *resp_len)
1478{
1479	char *reply;
1480	const int reply_size = 2048;
1481	int ctrl_rsp = 0;
1482	int reply_len;
1483
1484	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
1485	    os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1486		wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
1487				      (const u8 *) buf, os_strlen(buf));
1488	} else {
1489		wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface",
1490				  (const u8 *) buf, os_strlen(buf));
1491	}
1492
1493	reply = os_malloc(reply_size);
1494	if (reply == NULL) {
1495		*resp_len = 1;
1496		return NULL;
1497	}
1498
1499	os_memcpy(reply, "OK\n", 3);
1500	reply_len = 3;
1501
1502	if (os_strcmp(buf, "PING") == 0) {
1503		os_memcpy(reply, "PONG\n", 5);
1504		reply_len = 5;
1505	} else if (os_strcmp(buf, "MIB") == 0) {
1506		reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
1507		if (reply_len >= 0) {
1508			int res;
1509			res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
1510					       reply_size - reply_len);
1511			if (res < 0)
1512				reply_len = -1;
1513			else
1514				reply_len += res;
1515		}
1516	} else if (os_strncmp(buf, "STATUS", 6) == 0) {
1517		reply_len = wpa_supplicant_ctrl_iface_status(
1518			wpa_s, buf + 6, reply, reply_size);
1519	} else if (os_strcmp(buf, "PMKSA") == 0) {
1520		reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size);
1521	} else if (os_strncmp(buf, "SET ", 4) == 0) {
1522		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
1523			reply_len = -1;
1524	} else if (os_strcmp(buf, "LOGON") == 0) {
1525		eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
1526	} else if (os_strcmp(buf, "LOGOFF") == 0) {
1527		eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
1528	} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
1529		wpa_s->disconnected = 0;
1530		wpa_s->reassociate = 1;
1531		wpa_supplicant_req_scan(wpa_s, 0, 0);
1532	} else if (os_strcmp(buf, "RECONNECT") == 0) {
1533		if (wpa_s->disconnected) {
1534			wpa_s->disconnected = 0;
1535			wpa_s->reassociate = 1;
1536			wpa_supplicant_req_scan(wpa_s, 0, 0);
1537		}
1538#ifdef IEEE8021X_EAPOL
1539	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
1540		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
1541			reply_len = -1;
1542#endif /* IEEE8021X_EAPOL */
1543#ifdef CONFIG_PEERKEY
1544	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
1545		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
1546			reply_len = -1;
1547#endif /* CONFIG_PEERKEY */
1548#ifdef CONFIG_IEEE80211R
1549	} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
1550		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
1551			reply_len = -1;
1552#endif /* CONFIG_IEEE80211R */
1553#ifdef CONFIG_WPS
1554	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
1555		if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL))
1556			reply_len = -1;
1557	} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
1558		if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8))
1559			reply_len = -1;
1560	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
1561		reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
1562							      reply,
1563							      reply_size);
1564	} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
1565		if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
1566			reply_len = -1;
1567#endif /* CONFIG_WPS */
1568	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
1569	{
1570		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
1571			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
1572			reply_len = -1;
1573		else
1574			ctrl_rsp = 1;
1575	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
1576		if (wpa_supplicant_reload_configuration(wpa_s))
1577			reply_len = -1;
1578	} else if (os_strcmp(buf, "TERMINATE") == 0) {
1579		eloop_terminate();
1580	} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
1581		if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
1582			reply_len = -1;
1583	} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
1584		reply_len = wpa_supplicant_ctrl_iface_list_networks(
1585			wpa_s, reply, reply_size);
1586	} else if (os_strcmp(buf, "DISCONNECT") == 0) {
1587		wpa_s->reassociate = 0;
1588		wpa_s->disconnected = 1;
1589		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1590	} else if (os_strcmp(buf, "SCAN") == 0) {
1591		wpa_s->scan_req = 2;
1592		wpa_supplicant_req_scan(wpa_s, 0, 0);
1593	} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
1594		reply_len = wpa_supplicant_ctrl_iface_scan_results(
1595			wpa_s, reply, reply_size);
1596	} else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
1597		if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
1598			reply_len = -1;
1599	} else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
1600		if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
1601			reply_len = -1;
1602	} else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
1603		if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
1604			reply_len = -1;
1605	} else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
1606		reply_len = wpa_supplicant_ctrl_iface_add_network(
1607			wpa_s, reply, reply_size);
1608	} else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
1609		if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
1610			reply_len = -1;
1611	} else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
1612		if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
1613			reply_len = -1;
1614	} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
1615		reply_len = wpa_supplicant_ctrl_iface_get_network(
1616			wpa_s, buf + 12, reply, reply_size);
1617#ifndef CONFIG_NO_CONFIG_WRITE
1618	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
1619		if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
1620			reply_len = -1;
1621#endif /* CONFIG_NO_CONFIG_WRITE */
1622	} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
1623		reply_len = wpa_supplicant_ctrl_iface_get_capability(
1624			wpa_s, buf + 15, reply, reply_size);
1625	} else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
1626		if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
1627			reply_len = -1;
1628	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
1629		reply_len = wpa_supplicant_global_iface_list(
1630			wpa_s->global, reply, reply_size);
1631	} else if (os_strcmp(buf, "INTERFACES") == 0) {
1632		reply_len = wpa_supplicant_global_iface_interfaces(
1633			wpa_s->global, reply, reply_size);
1634	} else if (os_strncmp(buf, "BSS ", 4) == 0) {
1635		reply_len = wpa_supplicant_ctrl_iface_bss(
1636			wpa_s, buf + 4, reply, reply_size);
1637	} else {
1638		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1639		reply_len = 16;
1640	}
1641
1642	if (reply_len < 0) {
1643		os_memcpy(reply, "FAIL\n", 5);
1644		reply_len = 5;
1645	}
1646
1647	if (ctrl_rsp)
1648		eapol_sm_notify_ctrl_response(wpa_s->eapol);
1649
1650	*resp_len = reply_len;
1651	return reply;
1652}
1653
1654
1655static int wpa_supplicant_global_iface_add(struct wpa_global *global,
1656					   char *cmd)
1657{
1658	struct wpa_interface iface;
1659	char *pos;
1660
1661	/*
1662	 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
1663	 * TAB<bridge_ifname>
1664	 */
1665	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
1666
1667	os_memset(&iface, 0, sizeof(iface));
1668
1669	do {
1670		iface.ifname = pos = cmd;
1671		pos = os_strchr(pos, '\t');
1672		if (pos)
1673			*pos++ = '\0';
1674		if (iface.ifname[0] == '\0')
1675			return -1;
1676		if (pos == NULL)
1677			break;
1678
1679		iface.confname = pos;
1680		pos = os_strchr(pos, '\t');
1681		if (pos)
1682			*pos++ = '\0';
1683		if (iface.confname[0] == '\0')
1684			iface.confname = NULL;
1685		if (pos == NULL)
1686			break;
1687
1688		iface.driver = pos;
1689		pos = os_strchr(pos, '\t');
1690		if (pos)
1691			*pos++ = '\0';
1692		if (iface.driver[0] == '\0')
1693			iface.driver = NULL;
1694		if (pos == NULL)
1695			break;
1696
1697		iface.ctrl_interface = pos;
1698		pos = os_strchr(pos, '\t');
1699		if (pos)
1700			*pos++ = '\0';
1701		if (iface.ctrl_interface[0] == '\0')
1702			iface.ctrl_interface = NULL;
1703		if (pos == NULL)
1704			break;
1705
1706		iface.driver_param = pos;
1707		pos = os_strchr(pos, '\t');
1708		if (pos)
1709			*pos++ = '\0';
1710		if (iface.driver_param[0] == '\0')
1711			iface.driver_param = NULL;
1712		if (pos == NULL)
1713			break;
1714
1715		iface.bridge_ifname = pos;
1716		pos = os_strchr(pos, '\t');
1717		if (pos)
1718			*pos++ = '\0';
1719		if (iface.bridge_ifname[0] == '\0')
1720			iface.bridge_ifname = NULL;
1721		if (pos == NULL)
1722			break;
1723	} while (0);
1724
1725	if (wpa_supplicant_get_iface(global, iface.ifname))
1726		return -1;
1727
1728	return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
1729}
1730
1731
1732static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
1733					      char *cmd)
1734{
1735	struct wpa_supplicant *wpa_s;
1736
1737	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
1738
1739	wpa_s = wpa_supplicant_get_iface(global, cmd);
1740	if (wpa_s == NULL)
1741		return -1;
1742	return wpa_supplicant_remove_iface(global, wpa_s);
1743}
1744
1745
1746static void wpa_free_iface_info(struct wpa_interface_info *iface)
1747{
1748	struct wpa_interface_info *prev;
1749
1750	while (iface) {
1751		prev = iface;
1752		iface = iface->next;
1753
1754		os_free(prev->ifname);
1755		os_free(prev->desc);
1756		os_free(prev);
1757	}
1758}
1759
1760
1761static int wpa_supplicant_global_iface_list(struct wpa_global *global,
1762					    char *buf, int len)
1763{
1764	int i, res;
1765	struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
1766	char *pos, *end;
1767
1768	for (i = 0; wpa_supplicant_drivers[i]; i++) {
1769		struct wpa_driver_ops *drv = wpa_supplicant_drivers[i];
1770		if (drv->get_interfaces == NULL)
1771			continue;
1772		tmp = drv->get_interfaces(global->drv_priv);
1773		if (tmp == NULL)
1774			continue;
1775
1776		if (last == NULL)
1777			iface = last = tmp;
1778		else
1779			last->next = tmp;
1780		while (last->next)
1781			last = last->next;
1782	}
1783
1784	pos = buf;
1785	end = buf + len;
1786	for (tmp = iface; tmp; tmp = tmp->next) {
1787		res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
1788				  tmp->drv_name, tmp->ifname,
1789				  tmp->desc ? tmp->desc : "");
1790		if (res < 0 || res >= end - pos) {
1791			*pos = '\0';
1792			break;
1793		}
1794		pos += res;
1795	}
1796
1797	wpa_free_iface_info(iface);
1798
1799	return pos - buf;
1800}
1801
1802
1803static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
1804						  char *buf, int len)
1805{
1806	int res;
1807	char *pos, *end;
1808	struct wpa_supplicant *wpa_s;
1809
1810	wpa_s = global->ifaces;
1811	pos = buf;
1812	end = buf + len;
1813
1814	while (wpa_s) {
1815		res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
1816		if (res < 0 || res >= end - pos) {
1817			*pos = '\0';
1818			break;
1819		}
1820		pos += res;
1821		wpa_s = wpa_s->next;
1822	}
1823	return pos - buf;
1824}
1825
1826
1827char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
1828						char *buf, size_t *resp_len)
1829{
1830	char *reply;
1831	const int reply_size = 2048;
1832	int reply_len;
1833
1834	wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
1835			  (const u8 *) buf, os_strlen(buf));
1836
1837	reply = os_malloc(reply_size);
1838	if (reply == NULL) {
1839		*resp_len = 1;
1840		return NULL;
1841	}
1842
1843	os_memcpy(reply, "OK\n", 3);
1844	reply_len = 3;
1845
1846	if (os_strcmp(buf, "PING") == 0) {
1847		os_memcpy(reply, "PONG\n", 5);
1848		reply_len = 5;
1849	} else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
1850		if (wpa_supplicant_global_iface_add(global, buf + 14))
1851			reply_len = -1;
1852	} else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
1853		if (wpa_supplicant_global_iface_remove(global, buf + 17))
1854			reply_len = -1;
1855	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
1856		reply_len = wpa_supplicant_global_iface_list(
1857			global, reply, reply_size);
1858	} else if (os_strcmp(buf, "INTERFACES") == 0) {
1859		reply_len = wpa_supplicant_global_iface_interfaces(
1860			global, reply, reply_size);
1861	} else if (os_strcmp(buf, "TERMINATE") == 0) {
1862		eloop_terminate();
1863	} else {
1864		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1865		reply_len = 16;
1866	}
1867
1868	if (reply_len < 0) {
1869		os_memcpy(reply, "FAIL\n", 5);
1870		reply_len = 5;
1871	}
1872
1873	*resp_len = reply_len;
1874	return reply;
1875}
1876