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