1151497Sru/*
2151497Sru * WPA Supplicant / Control interface (shared code for all backends)
3151497Sru * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4151497Sru *
5151497Sru * This software may be distributed under the terms of the BSD license.
6151497Sru * See README for more details.
7151497Sru */
8151497Sru
9151497Sru#include "utils/includes.h"
10151497Sru
11151497Sru#include "utils/common.h"
12151497Sru#include "utils/eloop.h"
13151497Sru#include "common/version.h"
14151497Sru#include "common/ieee802_11_defs.h"
15151497Sru#include "common/ieee802_11_common.h"
16151497Sru#include "common/wpa_ctrl.h"
17151497Sru#include "eap_peer/eap.h"
18151497Sru#include "eapol_supp/eapol_supp_sm.h"
19151497Sru#include "rsn_supp/wpa.h"
20151497Sru#include "rsn_supp/preauth.h"
21151497Sru#include "rsn_supp/pmksa_cache.h"
22151497Sru#include "l2_packet/l2_packet.h"
23151497Sru#include "wps/wps.h"
24151497Sru#include "config.h"
25151497Sru#include "wpa_supplicant_i.h"
26151497Sru#include "driver_i.h"
27151497Sru#include "wps_supplicant.h"
28151497Sru#include "ibss_rsn.h"
29151497Sru#include "ap.h"
30151497Sru#include "p2p_supplicant.h"
31151497Sru#include "p2p/p2p.h"
32151497Sru#include "hs20_supplicant.h"
33151497Sru#include "wifi_display.h"
34151497Sru#include "notify.h"
35151497Sru#include "bss.h"
36151497Sru#include "scan.h"
37151497Sru#include "ctrl_iface.h"
38151497Sru#include "interworking.h"
39151497Sru#include "blacklist.h"
40151497Sru#include "autoscan.h"
41151497Sru#include "wnm_sta.h"
42151497Sru
43151497Sruextern struct wpa_driver_ops *wpa_drivers[];
44151497Sru
45151497Srustatic int wpa_supplicant_global_iface_list(struct wpa_global *global,
46151497Sru					    char *buf, int len);
47151497Srustatic int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
48151497Sru						  char *buf, int len);
49151497Sru
50151497Sru
51151497Srustatic int pno_start(struct wpa_supplicant *wpa_s)
52151497Sru{
53151497Sru	int ret;
54151497Sru	size_t i, num_ssid;
55151497Sru	struct wpa_ssid *ssid;
56151497Sru	struct wpa_driver_scan_params params;
57151497Sru
58151497Sru	if (wpa_s->pno)
59151497Sru		return 0;
60151497Sru
61151497Sru	if (wpa_s->wpa_state == WPA_SCANNING) {
62151497Sru		wpa_supplicant_cancel_sched_scan(wpa_s);
63151497Sru		wpa_supplicant_cancel_scan(wpa_s);
64151497Sru	}
65151497Sru
66151497Sru	os_memset(&params, 0, sizeof(params));
67151497Sru
68151497Sru	num_ssid = 0;
69151497Sru	ssid = wpa_s->conf->ssid;
70151497Sru	while (ssid) {
71151497Sru		if (!wpas_network_disabled(wpa_s, ssid))
72151497Sru			num_ssid++;
73151497Sru		ssid = ssid->next;
74151497Sru	}
75151497Sru	if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
76151497Sru		wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
77151497Sru			   "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
78151497Sru		num_ssid = WPAS_MAX_SCAN_SSIDS;
79151497Sru	}
80151497Sru
81151497Sru	if (num_ssid == 0) {
82151497Sru		wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
83151497Sru		return -1;
84151497Sru	}
85151497Sru
86151497Sru	params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
87151497Sru					num_ssid);
88151497Sru	if (params.filter_ssids == NULL)
89151497Sru		return -1;
90151497Sru	i = 0;
91151497Sru	ssid = wpa_s->conf->ssid;
92151497Sru	while (ssid) {
93151497Sru		if (!wpas_network_disabled(wpa_s, ssid)) {
94151497Sru			params.ssids[i].ssid = ssid->ssid;
95151497Sru			params.ssids[i].ssid_len = ssid->ssid_len;
96151497Sru			params.num_ssids++;
97151497Sru			os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
98151497Sru				  ssid->ssid_len);
99151497Sru			params.filter_ssids[i].ssid_len = ssid->ssid_len;
100151497Sru			params.num_filter_ssids++;
101151497Sru			i++;
102151497Sru			if (i == num_ssid)
103151497Sru				break;
104151497Sru		}
105151497Sru		ssid = ssid->next;
106151497Sru	}
107151497Sru
108151497Sru	if (wpa_s->conf->filter_rssi)
109151497Sru		params.filter_rssi = wpa_s->conf->filter_rssi;
110151497Sru
111151497Sru	ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
112151497Sru	os_free(params.filter_ssids);
113151497Sru	if (ret == 0)
114151497Sru		wpa_s->pno = 1;
115151497Sru	return ret;
116151497Sru}
117151497Sru
118151497Sru
119151497Srustatic int pno_stop(struct wpa_supplicant *wpa_s)
120151497Sru{
121151497Sru	int ret = 0;
122151497Sru
123151497Sru	if (wpa_s->pno) {
124151497Sru		wpa_s->pno = 0;
125151497Sru		ret = wpa_drv_stop_sched_scan(wpa_s);
126151497Sru	}
127151497Sru
128151497Sru	if (wpa_s->wpa_state == WPA_SCANNING)
129151497Sru		wpa_supplicant_req_scan(wpa_s, 0, 0);
130151497Sru
131151497Sru	return ret;
132151497Sru}
133151497Sru
134151497Sru
135151497Srustatic int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
136151497Sru{
137151497Sru	char *pos;
138151497Sru	u8 addr[ETH_ALEN], *filter = NULL, *n;
139151497Sru	size_t count = 0;
140151497Sru
141151497Sru	pos = val;
142151497Sru	while (pos) {
143151497Sru		if (*pos == '\0')
144151497Sru			break;
145151497Sru		if (hwaddr_aton(pos, addr)) {
146151497Sru			os_free(filter);
147151497Sru			return -1;
148151497Sru		}
149151497Sru		n = os_realloc_array(filter, count + 1, ETH_ALEN);
150151497Sru		if (n == NULL) {
151151497Sru			os_free(filter);
152151497Sru			return -1;
153151497Sru		}
154151497Sru		filter = n;
155151497Sru		os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
156151497Sru		count++;
157151497Sru
158151497Sru		pos = os_strchr(pos, ' ');
159151497Sru		if (pos)
160151497Sru			pos++;
161151497Sru	}
162151497Sru
163151497Sru	wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
164151497Sru	os_free(wpa_s->bssid_filter);
165151497Sru	wpa_s->bssid_filter = filter;
166151497Sru	wpa_s->bssid_filter_count = count;
167151497Sru
168151497Sru	return 0;
169151497Sru}
170151497Sru
171151497Sru
172151497Srustatic int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
173151497Sru{
174151497Sru	char *pos;
175151497Sru	u8 addr[ETH_ALEN], *bssid = NULL, *n;
176151497Sru	struct wpa_ssid_value *ssid = NULL, *ns;
177151497Sru	size_t count = 0, ssid_count = 0;
178151497Sru	struct wpa_ssid *c;
179151497Sru
180151497Sru	/*
181151497Sru	 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ������
182151497Sru	 * SSID_SPEC ::= ssid <SSID_HEX>
183151497Sru	 * BSSID_SPEC ::= bssid <BSSID_HEX>
184151497Sru	 */
185151497Sru
186151497Sru	pos = val;
187151497Sru	while (pos) {
188151497Sru		if (*pos == '\0')
189151497Sru			break;
190151497Sru		if (os_strncmp(pos, "bssid ", 6) == 0) {
191151497Sru			int res;
192151497Sru			pos += 6;
193151497Sru			res = hwaddr_aton2(pos, addr);
194151497Sru			if (res < 0) {
195151497Sru				os_free(ssid);
196151497Sru				os_free(bssid);
197151497Sru				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
198151497Sru					   "BSSID value '%s'", pos);
199151497Sru				return -1;
200151497Sru			}
201151497Sru			pos += res;
202151497Sru			n = os_realloc_array(bssid, count + 1, ETH_ALEN);
203151497Sru			if (n == NULL) {
204151497Sru				os_free(ssid);
205151497Sru				os_free(bssid);
206151497Sru				return -1;
207151497Sru			}
208151497Sru			bssid = n;
209151497Sru			os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
210151497Sru			count++;
211151497Sru		} else if (os_strncmp(pos, "ssid ", 5) == 0) {
212151497Sru			char *end;
213151497Sru			pos += 5;
214151497Sru
215151497Sru			end = pos;
216151497Sru			while (*end) {
217151497Sru				if (*end == '\0' || *end == ' ')
218151497Sru					break;
219151497Sru				end++;
220151497Sru			}
221151497Sru
222151497Sru			ns = os_realloc_array(ssid, ssid_count + 1,
223151497Sru					      sizeof(struct wpa_ssid_value));
224151497Sru			if (ns == NULL) {
225151497Sru				os_free(ssid);
226151497Sru				os_free(bssid);
227151497Sru				return -1;
228151497Sru			}
229151497Sru			ssid = ns;
230151497Sru
231151497Sru			if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
232151497Sru			    hexstr2bin(pos, ssid[ssid_count].ssid,
233151497Sru				       (end - pos) / 2) < 0) {
234151497Sru				os_free(ssid);
235151497Sru				os_free(bssid);
236151497Sru				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
237151497Sru					   "SSID value '%s'", pos);
238151497Sru				return -1;
239151497Sru			}
240151497Sru			ssid[ssid_count].ssid_len = (end - pos) / 2;
241151497Sru			wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
242151497Sru					  ssid[ssid_count].ssid,
243151497Sru					  ssid[ssid_count].ssid_len);
244151497Sru			ssid_count++;
245151497Sru			pos = end;
246151497Sru		} else {
247151497Sru			wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
248151497Sru				   "'%s'", pos);
249151497Sru			os_free(ssid);
250151497Sru			os_free(bssid);
251151497Sru			return -1;
252151497Sru		}
253151497Sru
254151497Sru		pos = os_strchr(pos, ' ');
255151497Sru		if (pos)
256151497Sru			pos++;
257151497Sru	}
258151497Sru
259151497Sru	wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
260151497Sru	os_free(wpa_s->disallow_aps_bssid);
261151497Sru	wpa_s->disallow_aps_bssid = bssid;
262151497Sru	wpa_s->disallow_aps_bssid_count = count;
263151497Sru
264151497Sru	wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
265151497Sru	os_free(wpa_s->disallow_aps_ssid);
266151497Sru	wpa_s->disallow_aps_ssid = ssid;
267151497Sru	wpa_s->disallow_aps_ssid_count = ssid_count;
268151497Sru
269151497Sru	if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
270151497Sru		return 0;
271151497Sru
272151497Sru	c = wpa_s->current_ssid;
273151497Sru	if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
274151497Sru		return 0;
275151497Sru
276151497Sru	if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
277151497Sru	    !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
278151497Sru		return 0;
279151497Sru
280151497Sru	wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
281151497Sru		   "because current AP was marked disallowed");
282151497Sru
283151497Sru#ifdef CONFIG_SME
284151497Sru	wpa_s->sme.prev_bssid_set = 0;
285151497Sru#endif /* CONFIG_SME */
286151497Sru	wpa_s->reassociate = 1;
287151497Sru	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
288151497Sru	wpa_supplicant_req_scan(wpa_s, 0, 0);
289151497Sru
290151497Sru	return 0;
291151497Sru}
292151497Sru
293151497Sru
294151497Srustatic int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
295151497Sru					 char *cmd)
296151497Sru{
297151497Sru	char *value;
298151497Sru	int ret = 0;
299151497Sru
300151497Sru	value = os_strchr(cmd, ' ');
301151497Sru	if (value == NULL)
302151497Sru		return -1;
303151497Sru	*value++ = '\0';
304151497Sru
305151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
306151497Sru	if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
307151497Sru		eapol_sm_configure(wpa_s->eapol,
308151497Sru				   atoi(value), -1, -1, -1);
309151497Sru	} else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
310151497Sru		eapol_sm_configure(wpa_s->eapol,
311151497Sru				   -1, atoi(value), -1, -1);
312151497Sru	} else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
313151497Sru		eapol_sm_configure(wpa_s->eapol,
314151497Sru				   -1, -1, atoi(value), -1);
315151497Sru	} else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
316151497Sru		eapol_sm_configure(wpa_s->eapol,
317151497Sru				   -1, -1, -1, atoi(value));
318151497Sru	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
319151497Sru		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
320151497Sru				     atoi(value)))
321151497Sru			ret = -1;
322151497Sru	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
323151497Sru		   0) {
324151497Sru		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
325151497Sru				     atoi(value)))
326151497Sru			ret = -1;
327151497Sru	} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
328151497Sru		if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
329151497Sru			ret = -1;
330151497Sru	} else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
331151497Sru		wpa_s->wps_fragment_size = atoi(value);
332151497Sru#ifdef CONFIG_WPS_TESTING
333151497Sru	} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
334151497Sru		long int val;
335151497Sru		val = strtol(value, NULL, 0);
336151497Sru		if (val < 0 || val > 0xff) {
337151497Sru			ret = -1;
338151497Sru			wpa_printf(MSG_DEBUG, "WPS: Invalid "
339151497Sru				   "wps_version_number %ld", val);
340151497Sru		} else {
341151497Sru			wps_version_number = val;
342151497Sru			wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
343151497Sru				   "version %u.%u",
344151497Sru				   (wps_version_number & 0xf0) >> 4,
345151497Sru				   wps_version_number & 0x0f);
346151497Sru		}
347151497Sru	} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
348151497Sru		wps_testing_dummy_cred = atoi(value);
349151497Sru		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
350151497Sru			   wps_testing_dummy_cred);
351151497Sru#endif /* CONFIG_WPS_TESTING */
352151497Sru	} else if (os_strcasecmp(cmd, "ampdu") == 0) {
353151497Sru		if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
354151497Sru			ret = -1;
355151497Sru#ifdef CONFIG_TDLS_TESTING
356151497Sru	} else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
357151497Sru		extern unsigned int tdls_testing;
358151497Sru		tdls_testing = strtol(value, NULL, 0);
359151497Sru		wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
360151497Sru#endif /* CONFIG_TDLS_TESTING */
361151497Sru#ifdef CONFIG_TDLS
362151497Sru	} else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
363151497Sru		int disabled = atoi(value);
364151497Sru		wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
365151497Sru		if (disabled) {
366151497Sru			if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
367151497Sru				ret = -1;
368151497Sru		} else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
369151497Sru			ret = -1;
370151497Sru		wpa_tdls_enable(wpa_s->wpa, !disabled);
371151497Sru#endif /* CONFIG_TDLS */
372151497Sru	} else if (os_strcasecmp(cmd, "pno") == 0) {
373151497Sru		if (atoi(value))
374151497Sru			ret = pno_start(wpa_s);
375151497Sru		else
376151497Sru			ret = pno_stop(wpa_s);
377151497Sru	} else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
378151497Sru		int disabled = atoi(value);
379151497Sru		if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
380151497Sru			ret = -1;
381151497Sru		else if (disabled)
382151497Sru			wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
383151497Sru	} else if (os_strcasecmp(cmd, "uapsd") == 0) {
384151497Sru		if (os_strcmp(value, "disable") == 0)
385151497Sru			wpa_s->set_sta_uapsd = 0;
386151497Sru		else {
387151497Sru			int be, bk, vi, vo;
388151497Sru			char *pos;
389151497Sru			/* format: BE,BK,VI,VO;max SP Length */
390151497Sru			be = atoi(value);
391151497Sru			pos = os_strchr(value, ',');
392151497Sru			if (pos == NULL)
393151497Sru				return -1;
394151497Sru			pos++;
395151497Sru			bk = atoi(pos);
396151497Sru			pos = os_strchr(pos, ',');
397151497Sru			if (pos == NULL)
398151497Sru				return -1;
399151497Sru			pos++;
400151497Sru			vi = atoi(pos);
401151497Sru			pos = os_strchr(pos, ',');
402151497Sru			if (pos == NULL)
403151497Sru				return -1;
404151497Sru			pos++;
405151497Sru			vo = atoi(pos);
406151497Sru			/* ignore max SP Length for now */
407151497Sru
408151497Sru			wpa_s->set_sta_uapsd = 1;
409151497Sru			wpa_s->sta_uapsd = 0;
410151497Sru			if (be)
411151497Sru				wpa_s->sta_uapsd |= BIT(0);
412151497Sru			if (bk)
413151497Sru				wpa_s->sta_uapsd |= BIT(1);
414151497Sru			if (vi)
415151497Sru				wpa_s->sta_uapsd |= BIT(2);
416151497Sru			if (vo)
417151497Sru				wpa_s->sta_uapsd |= BIT(3);
418151497Sru		}
419151497Sru	} else if (os_strcasecmp(cmd, "ps") == 0) {
420151497Sru		ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
421151497Sru#ifdef CONFIG_WIFI_DISPLAY
422151497Sru	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
423151497Sru		wifi_display_enable(wpa_s->global, !!atoi(value));
424151497Sru#endif /* CONFIG_WIFI_DISPLAY */
425151497Sru	} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
426151497Sru		ret = set_bssid_filter(wpa_s, value);
427151497Sru	} else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
428151497Sru		ret = set_disallow_aps(wpa_s, value);
429151497Sru	} else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
430151497Sru		wpa_s->no_keep_alive = !!atoi(value);
431151497Sru	} else {
432151497Sru		value[-1] = '=';
433151497Sru		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
434151497Sru		if (ret == 0)
435151497Sru			wpa_supplicant_update_config(wpa_s);
436151497Sru	}
437151497Sru
438151497Sru	return ret;
439151497Sru}
440151497Sru
441151497Sru
442151497Srustatic int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
443151497Sru					 char *cmd, char *buf, size_t buflen)
444151497Sru{
445151497Sru	int res = -1;
446151497Sru
447151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
448151497Sru
449151497Sru	if (os_strcmp(cmd, "version") == 0) {
450151497Sru		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
451151497Sru	} else if (os_strcasecmp(cmd, "country") == 0) {
452151497Sru		if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
453151497Sru			res = os_snprintf(buf, buflen, "%c%c",
454151497Sru					  wpa_s->conf->country[0],
455151497Sru					  wpa_s->conf->country[1]);
456151497Sru#ifdef CONFIG_WIFI_DISPLAY
457151497Sru	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
458151497Sru		res = os_snprintf(buf, buflen, "%d",
459151497Sru				  wpa_s->global->wifi_display);
460151497Sru		if (res < 0 || (unsigned int) res >= buflen)
461151497Sru			return -1;
462151497Sru		return res;
463151497Sru#endif /* CONFIG_WIFI_DISPLAY */
464151497Sru	}
465151497Sru
466151497Sru	if (res < 0 || (unsigned int) res >= buflen)
467151497Sru		return -1;
468151497Sru	return res;
469151497Sru}
470151497Sru
471151497Sru
472151497Sru#ifdef IEEE8021X_EAPOL
473151497Srustatic int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
474151497Sru					     char *addr)
475151497Sru{
476151497Sru	u8 bssid[ETH_ALEN];
477151497Sru	struct wpa_ssid *ssid = wpa_s->current_ssid;
478151497Sru
479151497Sru	if (hwaddr_aton(addr, bssid)) {
480151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
481151497Sru			   "'%s'", addr);
482151497Sru		return -1;
483151497Sru	}
484151497Sru
485151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
486151497Sru	rsn_preauth_deinit(wpa_s->wpa);
487151497Sru	if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
488151497Sru		return -1;
489151497Sru
490151497Sru	return 0;
491151497Sru}
492151497Sru#endif /* IEEE8021X_EAPOL */
493151497Sru
494151497Sru
495151497Sru#ifdef CONFIG_PEERKEY
496151497Sru/* MLME-STKSTART.request(peer) */
497151497Srustatic int wpa_supplicant_ctrl_iface_stkstart(
498151497Sru	struct wpa_supplicant *wpa_s, char *addr)
499151497Sru{
500151497Sru	u8 peer[ETH_ALEN];
501151497Sru
502151497Sru	if (hwaddr_aton(addr, peer)) {
503151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
504151497Sru			   "address '%s'", addr);
505151497Sru		return -1;
506151497Sru	}
507151497Sru
508151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
509151497Sru		   MAC2STR(peer));
510151497Sru
511151497Sru	return wpa_sm_stkstart(wpa_s->wpa, peer);
512151497Sru}
513151497Sru#endif /* CONFIG_PEERKEY */
514151497Sru
515151497Sru
516151497Sru#ifdef CONFIG_TDLS
517151497Sru
518151497Srustatic int wpa_supplicant_ctrl_iface_tdls_discover(
519151497Sru	struct wpa_supplicant *wpa_s, char *addr)
520151497Sru{
521151497Sru	u8 peer[ETH_ALEN];
522151497Sru	int ret;
523151497Sru
524151497Sru	if (hwaddr_aton(addr, peer)) {
525151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
526151497Sru			   "address '%s'", addr);
527151497Sru		return -1;
528151497Sru	}
529151497Sru
530151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
531151497Sru		   MAC2STR(peer));
532151497Sru
533151497Sru	if (wpa_tdls_is_external_setup(wpa_s->wpa))
534151497Sru		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
535151497Sru	else
536151497Sru		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
537151497Sru
538151497Sru	return ret;
539151497Sru}
540151497Sru
541151497Sru
542151497Srustatic int wpa_supplicant_ctrl_iface_tdls_setup(
543151497Sru	struct wpa_supplicant *wpa_s, char *addr)
544151497Sru{
545151497Sru	u8 peer[ETH_ALEN];
546151497Sru	int ret;
547151497Sru
548151497Sru	if (hwaddr_aton(addr, peer)) {
549151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
550151497Sru			   "address '%s'", addr);
551151497Sru		return -1;
552151497Sru	}
553151497Sru
554151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
555151497Sru		   MAC2STR(peer));
556151497Sru
557151497Sru	ret = wpa_tdls_reneg(wpa_s->wpa, peer);
558151497Sru	if (ret) {
559151497Sru		if (wpa_tdls_is_external_setup(wpa_s->wpa))
560151497Sru			ret = wpa_tdls_start(wpa_s->wpa, peer);
561151497Sru		else
562151497Sru			ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
563151497Sru	}
564151497Sru
565151497Sru	return ret;
566151497Sru}
567151497Sru
568151497Sru
569151497Srustatic int wpa_supplicant_ctrl_iface_tdls_teardown(
570151497Sru	struct wpa_supplicant *wpa_s, char *addr)
571151497Sru{
572151497Sru	u8 peer[ETH_ALEN];
573151497Sru
574151497Sru	if (hwaddr_aton(addr, peer)) {
575151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
576151497Sru			   "address '%s'", addr);
577151497Sru		return -1;
578151497Sru	}
579151497Sru
580151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
581151497Sru		   MAC2STR(peer));
582151497Sru
583151497Sru	return wpa_tdls_teardown_link(wpa_s->wpa, peer,
584151497Sru				      WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
585151497Sru}
586151497Sru
587151497Sru#endif /* CONFIG_TDLS */
588151497Sru
589151497Sru
590151497Sru#ifdef CONFIG_IEEE80211R
591151497Srustatic int wpa_supplicant_ctrl_iface_ft_ds(
592151497Sru	struct wpa_supplicant *wpa_s, char *addr)
593151497Sru{
594151497Sru	u8 target_ap[ETH_ALEN];
595151497Sru	struct wpa_bss *bss;
596151497Sru	const u8 *mdie;
597151497Sru
598151497Sru	if (hwaddr_aton(addr, target_ap)) {
599151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
600151497Sru			   "address '%s'", addr);
601151497Sru		return -1;
602151497Sru	}
603151497Sru
604151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
605151497Sru
606151497Sru	bss = wpa_bss_get_bssid(wpa_s, target_ap);
607151497Sru	if (bss)
608151497Sru		mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
609151497Sru	else
610151497Sru		mdie = NULL;
611151497Sru
612151497Sru	return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
613151497Sru}
614151497Sru#endif /* CONFIG_IEEE80211R */
615151497Sru
616151497Sru
617151497Sru#ifdef CONFIG_WPS
618151497Srustatic int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
619151497Sru					     char *cmd)
620151497Sru{
621151497Sru	u8 bssid[ETH_ALEN], *_bssid = bssid;
622151497Sru#ifdef CONFIG_P2P
623151497Sru	u8 p2p_dev_addr[ETH_ALEN];
624151497Sru#endif /* CONFIG_P2P */
625151497Sru#ifdef CONFIG_AP
626151497Sru	u8 *_p2p_dev_addr = NULL;
627151497Sru#endif /* CONFIG_AP */
628151497Sru
629151497Sru	if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
630151497Sru		_bssid = NULL;
631151497Sru#ifdef CONFIG_P2P
632151497Sru	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
633151497Sru		if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
634151497Sru			wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
635151497Sru				   "P2P Device Address '%s'",
636151497Sru				   cmd + 13);
637151497Sru			return -1;
638151497Sru		}
639151497Sru		_p2p_dev_addr = p2p_dev_addr;
640151497Sru#endif /* CONFIG_P2P */
641151497Sru	} else if (hwaddr_aton(cmd, bssid)) {
642151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
643151497Sru			   cmd);
644151497Sru		return -1;
645151497Sru	}
646151497Sru
647151497Sru#ifdef CONFIG_AP
648151497Sru	if (wpa_s->ap_iface)
649151497Sru		return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
650151497Sru#endif /* CONFIG_AP */
651151497Sru
652151497Sru	return wpas_wps_start_pbc(wpa_s, _bssid, 0);
653151497Sru}
654151497Sru
655151497Sru
656151497Srustatic int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
657151497Sru					     char *cmd, char *buf,
658151497Sru					     size_t buflen)
659151497Sru{
660151497Sru	u8 bssid[ETH_ALEN], *_bssid = bssid;
661151497Sru	char *pin;
662151497Sru	int ret;
663151497Sru
664151497Sru	pin = os_strchr(cmd, ' ');
665151497Sru	if (pin)
666151497Sru		*pin++ = '\0';
667151497Sru
668151497Sru	if (os_strcmp(cmd, "any") == 0)
669151497Sru		_bssid = NULL;
670151497Sru	else if (os_strcmp(cmd, "get") == 0) {
671151497Sru		ret = wps_generate_pin();
672151497Sru		goto done;
673151497Sru	} else if (hwaddr_aton(cmd, bssid)) {
674151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
675151497Sru			   cmd);
676151497Sru		return -1;
677151497Sru	}
678151497Sru
679151497Sru#ifdef CONFIG_AP
680151497Sru	if (wpa_s->ap_iface) {
681151497Sru		int timeout = 0;
682151497Sru		char *pos;
683151497Sru
684151497Sru		if (pin) {
685151497Sru			pos = os_strchr(pin, ' ');
686151497Sru			if (pos) {
687151497Sru				*pos++ = '\0';
688151497Sru				timeout = atoi(pos);
689151497Sru			}
690151497Sru		}
691151497Sru
692151497Sru		return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
693151497Sru						 buf, buflen, timeout);
694151497Sru	}
695151497Sru#endif /* CONFIG_AP */
696151497Sru
697151497Sru	if (pin) {
698151497Sru		ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
699151497Sru					 DEV_PW_DEFAULT);
700151497Sru		if (ret < 0)
701151497Sru			return -1;
702151497Sru		ret = os_snprintf(buf, buflen, "%s", pin);
703151497Sru		if (ret < 0 || (size_t) ret >= buflen)
704151497Sru			return -1;
705151497Sru		return ret;
706151497Sru	}
707151497Sru
708151497Sru	ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
709151497Sru	if (ret < 0)
710151497Sru		return -1;
711151497Sru
712151497Srudone:
713151497Sru	/* Return the generated PIN */
714151497Sru	ret = os_snprintf(buf, buflen, "%08d", ret);
715151497Sru	if (ret < 0 || (size_t) ret >= buflen)
716151497Sru		return -1;
717151497Sru	return ret;
718151497Sru}
719151497Sru
720151497Sru
721151497Srustatic int wpa_supplicant_ctrl_iface_wps_check_pin(
722151497Sru	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
723151497Sru{
724151497Sru	char pin[9];
725151497Sru	size_t len;
726151497Sru	char *pos;
727151497Sru	int ret;
728151497Sru
729151497Sru	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
730151497Sru			      (u8 *) cmd, os_strlen(cmd));
731151497Sru	for (pos = cmd, len = 0; *pos != '\0'; pos++) {
732151497Sru		if (*pos < '0' || *pos > '9')
733151497Sru			continue;
734151497Sru		pin[len++] = *pos;
735151497Sru		if (len == 9) {
736151497Sru			wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
737151497Sru			return -1;
738151497Sru		}
739151497Sru	}
740151497Sru	if (len != 4 && len != 8) {
741151497Sru		wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
742151497Sru		return -1;
743151497Sru	}
744151497Sru	pin[len] = '\0';
745151497Sru
746151497Sru	if (len == 8) {
747151497Sru		unsigned int pin_val;
748151497Sru		pin_val = atoi(pin);
749151497Sru		if (!wps_pin_valid(pin_val)) {
750151497Sru			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
751151497Sru			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
752151497Sru			if (ret < 0 || (size_t) ret >= buflen)
753151497Sru				return -1;
754151497Sru			return ret;
755151497Sru		}
756151497Sru	}
757151497Sru
758151497Sru	ret = os_snprintf(buf, buflen, "%s", pin);
759151497Sru	if (ret < 0 || (size_t) ret >= buflen)
760151497Sru		return -1;
761151497Sru
762151497Sru	return ret;
763151497Sru}
764151497Sru
765151497Sru
766151497Sru#ifdef CONFIG_WPS_NFC
767151497Sru
768151497Srustatic int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
769151497Sru					     char *cmd)
770151497Sru{
771151497Sru	u8 bssid[ETH_ALEN], *_bssid = bssid;
772151497Sru
773151497Sru	if (cmd == NULL || cmd[0] == '\0')
774151497Sru		_bssid = NULL;
775151497Sru	else if (hwaddr_aton(cmd, bssid))
776151497Sru		return -1;
777151497Sru
778151497Sru	return wpas_wps_start_nfc(wpa_s, _bssid);
779151497Sru}
780151497Sru
781151497Sru
782151497Srustatic int wpa_supplicant_ctrl_iface_wps_nfc_token(
783151497Sru	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
784151497Sru{
785151497Sru	int ndef;
786151497Sru	struct wpabuf *buf;
787151497Sru	int res;
788151497Sru
789151497Sru	if (os_strcmp(cmd, "WPS") == 0)
790151497Sru		ndef = 0;
791151497Sru	else if (os_strcmp(cmd, "NDEF") == 0)
792151497Sru		ndef = 1;
793151497Sru	else
794151497Sru		return -1;
795151497Sru
796151497Sru	buf = wpas_wps_nfc_token(wpa_s, ndef);
797151497Sru	if (buf == NULL)
798151497Sru		return -1;
799151497Sru
800151497Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
801151497Sru					 wpabuf_len(buf));
802151497Sru	reply[res++] = '\n';
803151497Sru	reply[res] = '\0';
804151497Sru
805151497Sru	wpabuf_free(buf);
806151497Sru
807151497Sru	return res;
808151497Sru}
809151497Sru
810151497Sru
811151497Srustatic int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
812151497Sru	struct wpa_supplicant *wpa_s, char *pos)
813151497Sru{
814151497Sru	size_t len;
815151497Sru	struct wpabuf *buf;
816151497Sru	int ret;
817151497Sru
818151497Sru	len = os_strlen(pos);
819151497Sru	if (len & 0x01)
820151497Sru		return -1;
821151497Sru	len /= 2;
822151497Sru
823151497Sru	buf = wpabuf_alloc(len);
824151497Sru	if (buf == NULL)
825151497Sru		return -1;
826151497Sru	if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
827151497Sru		wpabuf_free(buf);
828151497Sru		return -1;
829151497Sru	}
830151497Sru
831151497Sru	ret = wpas_wps_nfc_tag_read(wpa_s, buf);
832151497Sru	wpabuf_free(buf);
833151497Sru
834151497Sru	return ret;
835151497Sru}
836151497Sru
837151497Sru
838151497Srustatic int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
839151497Sru					      char *reply, size_t max_len)
840151497Sru{
841151497Sru	struct wpabuf *buf;
842151497Sru	int res;
843151497Sru
844151497Sru	buf = wpas_wps_nfc_handover_req(wpa_s);
845151497Sru	if (buf == NULL)
846151497Sru		return -1;
847151497Sru
848151497Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
849151497Sru					 wpabuf_len(buf));
850151497Sru	reply[res++] = '\n';
851151497Sru	reply[res] = '\0';
852151497Sru
853151497Sru	wpabuf_free(buf);
854151497Sru
855151497Sru	return res;
856151497Sru}
857151497Sru
858151497Sru
859151497Srustatic int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
860151497Sru					  char *cmd, char *reply,
861151497Sru					  size_t max_len)
862151497Sru{
863151497Sru	char *pos;
864151497Sru
865151497Sru	pos = os_strchr(cmd, ' ');
866151497Sru	if (pos == NULL)
867151497Sru		return -1;
868151497Sru	*pos++ = '\0';
869151497Sru
870151497Sru	if (os_strcmp(cmd, "NDEF") != 0)
871151497Sru		return -1;
872151497Sru
873151497Sru	if (os_strcmp(pos, "WPS") == 0) {
874151497Sru		return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
875151497Sru							  max_len);
876151497Sru	}
877151497Sru
878151497Sru	return -1;
879151497Sru}
880151497Sru
881151497Sru
882151497Srustatic int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
883151497Sru					      char *reply, size_t max_len)
884151497Sru{
885151497Sru	struct wpabuf *buf;
886151497Sru	int res;
887151497Sru
888151497Sru	buf = wpas_wps_nfc_handover_sel(wpa_s);
889151497Sru	if (buf == NULL)
890151497Sru		return -1;
891151497Sru
892151497Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
893151497Sru					 wpabuf_len(buf));
894151497Sru	reply[res++] = '\n';
895151497Sru	reply[res] = '\0';
896151497Sru
897151497Sru	wpabuf_free(buf);
898151497Sru
899151497Sru	return res;
900151497Sru}
901151497Sru
902151497Sru
903151497Srustatic int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
904151497Sru					  char *cmd, char *reply,
905151497Sru					  size_t max_len)
906151497Sru{
907151497Sru	char *pos;
908151497Sru
909151497Sru	pos = os_strchr(cmd, ' ');
910151497Sru	if (pos == NULL)
911151497Sru		return -1;
912151497Sru	*pos++ = '\0';
913151497Sru
914151497Sru	if (os_strcmp(cmd, "NDEF") != 0)
915151497Sru		return -1;
916151497Sru
917151497Sru	if (os_strcmp(pos, "WPS") == 0) {
918151497Sru		return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
919151497Sru							  max_len);
920151497Sru	}
921151497Sru
922151497Sru	return -1;
923151497Sru}
924151497Sru
925151497Sru
926151497Srustatic int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
927151497Sru					 char *cmd, char *reply,
928151497Sru					 size_t max_len)
929151497Sru{
930151497Sru	size_t len;
931151497Sru	struct wpabuf *buf;
932151497Sru	int ret;
933151497Sru
934151497Sru	len = os_strlen(cmd);
935151497Sru	if (len & 0x01)
936151497Sru		return -1;
937151497Sru	len /= 2;
938151497Sru
939151497Sru	buf = wpabuf_alloc(len);
940151497Sru	if (buf == NULL)
941151497Sru		return -1;
942151497Sru	if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
943151497Sru		wpabuf_free(buf);
944151497Sru		return -1;
945151497Sru	}
946151497Sru
947151497Sru	ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
948151497Sru	wpabuf_free(buf);
949151497Sru
950151497Sru	return ret;
951151497Sru}
952151497Sru
953151497Sru
954151497Srustatic int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
955151497Sru					 char *cmd)
956151497Sru{
957151497Sru	size_t len;
958151497Sru	struct wpabuf *buf;
959151497Sru	int ret;
960151497Sru
961151497Sru	len = os_strlen(cmd);
962151497Sru	if (len & 0x01)
963151497Sru		return -1;
964151497Sru	len /= 2;
965151497Sru
966151497Sru	buf = wpabuf_alloc(len);
967151497Sru	if (buf == NULL)
968151497Sru		return -1;
969151497Sru	if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
970151497Sru		wpabuf_free(buf);
971151497Sru		return -1;
972151497Sru	}
973151497Sru
974151497Sru	ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
975151497Sru	wpabuf_free(buf);
976151497Sru
977151497Sru	return ret;
978151497Sru}
979151497Sru
980151497Sru#endif /* CONFIG_WPS_NFC */
981151497Sru
982151497Sru
983151497Srustatic int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
984151497Sru					     char *cmd)
985151497Sru{
986151497Sru	u8 bssid[ETH_ALEN];
987151497Sru	char *pin;
988151497Sru	char *new_ssid;
989151497Sru	char *new_auth;
990151497Sru	char *new_encr;
991151497Sru	char *new_key;
992151497Sru	struct wps_new_ap_settings ap;
993151497Sru
994151497Sru	pin = os_strchr(cmd, ' ');
995151497Sru	if (pin == NULL)
996151497Sru		return -1;
997151497Sru	*pin++ = '\0';
998151497Sru
999151497Sru	if (hwaddr_aton(cmd, bssid)) {
1000151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
1001151497Sru			   cmd);
1002151497Sru		return -1;
1003151497Sru	}
1004151497Sru
1005151497Sru	new_ssid = os_strchr(pin, ' ');
1006151497Sru	if (new_ssid == NULL)
1007151497Sru		return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
1008151497Sru	*new_ssid++ = '\0';
1009151497Sru
1010151497Sru	new_auth = os_strchr(new_ssid, ' ');
1011151497Sru	if (new_auth == NULL)
1012151497Sru		return -1;
1013151497Sru	*new_auth++ = '\0';
1014151497Sru
1015151497Sru	new_encr = os_strchr(new_auth, ' ');
1016151497Sru	if (new_encr == NULL)
1017151497Sru		return -1;
1018151497Sru	*new_encr++ = '\0';
1019151497Sru
1020151497Sru	new_key = os_strchr(new_encr, ' ');
1021151497Sru	if (new_key == NULL)
1022151497Sru		return -1;
1023151497Sru	*new_key++ = '\0';
1024151497Sru
1025151497Sru	os_memset(&ap, 0, sizeof(ap));
1026151497Sru	ap.ssid_hex = new_ssid;
1027151497Sru	ap.auth = new_auth;
1028151497Sru	ap.encr = new_encr;
1029151497Sru	ap.key_hex = new_key;
1030151497Sru	return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
1031151497Sru}
1032151497Sru
1033151497Sru
1034151497Sru#ifdef CONFIG_AP
1035151497Srustatic int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
1036151497Sru						char *cmd, char *buf,
1037151497Sru						size_t buflen)
1038151497Sru{
1039151497Sru	int timeout = 300;
1040151497Sru	char *pos;
1041151497Sru	const char *pin_txt;
1042151497Sru
1043151497Sru	if (!wpa_s->ap_iface)
1044151497Sru		return -1;
1045151497Sru
1046151497Sru	pos = os_strchr(cmd, ' ');
1047151497Sru	if (pos)
1048151497Sru		*pos++ = '\0';
1049151497Sru
1050151497Sru	if (os_strcmp(cmd, "disable") == 0) {
1051151497Sru		wpas_wps_ap_pin_disable(wpa_s);
1052151497Sru		return os_snprintf(buf, buflen, "OK\n");
1053151497Sru	}
1054151497Sru
1055151497Sru	if (os_strcmp(cmd, "random") == 0) {
1056151497Sru		if (pos)
1057151497Sru			timeout = atoi(pos);
1058151497Sru		pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
1059151497Sru		if (pin_txt == NULL)
1060151497Sru			return -1;
1061151497Sru		return os_snprintf(buf, buflen, "%s", pin_txt);
1062151497Sru	}
1063151497Sru
1064151497Sru	if (os_strcmp(cmd, "get") == 0) {
1065151497Sru		pin_txt = wpas_wps_ap_pin_get(wpa_s);
1066151497Sru		if (pin_txt == NULL)
1067151497Sru			return -1;
1068151497Sru		return os_snprintf(buf, buflen, "%s", pin_txt);
1069151497Sru	}
1070151497Sru
1071151497Sru	if (os_strcmp(cmd, "set") == 0) {
1072151497Sru		char *pin;
1073151497Sru		if (pos == NULL)
1074151497Sru			return -1;
1075151497Sru		pin = pos;
1076151497Sru		pos = os_strchr(pos, ' ');
1077151497Sru		if (pos) {
1078151497Sru			*pos++ = '\0';
1079151497Sru			timeout = atoi(pos);
1080151497Sru		}
1081151497Sru		if (os_strlen(pin) > buflen)
1082151497Sru			return -1;
1083151497Sru		if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
1084151497Sru			return -1;
1085151497Sru		return os_snprintf(buf, buflen, "%s", pin);
1086151497Sru	}
1087151497Sru
1088151497Sru	return -1;
1089151497Sru}
1090151497Sru#endif /* CONFIG_AP */
1091151497Sru
1092151497Sru
1093151497Sru#ifdef CONFIG_WPS_ER
1094151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
1095151497Sru						char *cmd)
1096151497Sru{
1097151497Sru	char *uuid = cmd, *pin, *pos;
1098151497Sru	u8 addr_buf[ETH_ALEN], *addr = NULL;
1099151497Sru	pin = os_strchr(uuid, ' ');
1100151497Sru	if (pin == NULL)
1101151497Sru		return -1;
1102151497Sru	*pin++ = '\0';
1103151497Sru	pos = os_strchr(pin, ' ');
1104151497Sru	if (pos) {
1105151497Sru		*pos++ = '\0';
1106151497Sru		if (hwaddr_aton(pos, addr_buf) == 0)
1107151497Sru			addr = addr_buf;
1108151497Sru	}
1109151497Sru	return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
1110151497Sru}
1111151497Sru
1112151497Sru
1113151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
1114151497Sru						  char *cmd)
1115151497Sru{
1116151497Sru	char *uuid = cmd, *pin;
1117151497Sru	pin = os_strchr(uuid, ' ');
1118151497Sru	if (pin == NULL)
1119151497Sru		return -1;
1120151497Sru	*pin++ = '\0';
1121151497Sru	return wpas_wps_er_learn(wpa_s, uuid, pin);
1122151497Sru}
1123151497Sru
1124151497Sru
1125151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_set_config(
1126151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
1127151497Sru{
1128151497Sru	char *uuid = cmd, *id;
1129151497Sru	id = os_strchr(uuid, ' ');
1130151497Sru	if (id == NULL)
1131151497Sru		return -1;
1132151497Sru	*id++ = '\0';
1133151497Sru	return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
1134151497Sru}
1135151497Sru
1136151497Sru
1137151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_config(
1138151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
1139151497Sru{
1140151497Sru	char *pin;
1141151497Sru	char *new_ssid;
1142151497Sru	char *new_auth;
1143151497Sru	char *new_encr;
1144151497Sru	char *new_key;
1145151497Sru	struct wps_new_ap_settings ap;
1146151497Sru
1147151497Sru	pin = os_strchr(cmd, ' ');
1148151497Sru	if (pin == NULL)
1149151497Sru		return -1;
1150151497Sru	*pin++ = '\0';
1151151497Sru
1152151497Sru	new_ssid = os_strchr(pin, ' ');
1153151497Sru	if (new_ssid == NULL)
1154151497Sru		return -1;
1155151497Sru	*new_ssid++ = '\0';
1156151497Sru
1157151497Sru	new_auth = os_strchr(new_ssid, ' ');
1158151497Sru	if (new_auth == NULL)
1159151497Sru		return -1;
1160151497Sru	*new_auth++ = '\0';
1161151497Sru
1162151497Sru	new_encr = os_strchr(new_auth, ' ');
1163151497Sru	if (new_encr == NULL)
1164151497Sru		return -1;
1165151497Sru	*new_encr++ = '\0';
1166151497Sru
1167151497Sru	new_key = os_strchr(new_encr, ' ');
1168151497Sru	if (new_key == NULL)
1169151497Sru		return -1;
1170151497Sru	*new_key++ = '\0';
1171151497Sru
1172151497Sru	os_memset(&ap, 0, sizeof(ap));
1173151497Sru	ap.ssid_hex = new_ssid;
1174151497Sru	ap.auth = new_auth;
1175151497Sru	ap.encr = new_encr;
1176151497Sru	ap.key_hex = new_key;
1177151497Sru	return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
1178151497Sru}
1179151497Sru
1180151497Sru
1181151497Sru#ifdef CONFIG_WPS_NFC
1182151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
1183151497Sru	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1184151497Sru{
1185151497Sru	int ndef;
1186151497Sru	struct wpabuf *buf;
1187151497Sru	int res;
1188151497Sru	char *uuid;
1189151497Sru
1190151497Sru	uuid = os_strchr(cmd, ' ');
1191151497Sru	if (uuid == NULL)
1192151497Sru		return -1;
1193151497Sru	*uuid++ = '\0';
1194151497Sru
1195151497Sru	if (os_strcmp(cmd, "WPS") == 0)
1196151497Sru		ndef = 0;
1197151497Sru	else if (os_strcmp(cmd, "NDEF") == 0)
1198151497Sru		ndef = 1;
1199151497Sru	else
1200151497Sru		return -1;
1201151497Sru
1202151497Sru	buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
1203151497Sru	if (buf == NULL)
1204151497Sru		return -1;
1205151497Sru
1206151497Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1207151497Sru					 wpabuf_len(buf));
1208151497Sru	reply[res++] = '\n';
1209151497Sru	reply[res] = '\0';
1210151497Sru
1211151497Sru	wpabuf_free(buf);
1212151497Sru
1213151497Sru	return res;
1214151497Sru}
1215151497Sru#endif /* CONFIG_WPS_NFC */
1216151497Sru#endif /* CONFIG_WPS_ER */
1217151497Sru
1218151497Sru#endif /* CONFIG_WPS */
1219151497Sru
1220151497Sru
1221151497Sru#ifdef CONFIG_IBSS_RSN
1222151497Srustatic int wpa_supplicant_ctrl_iface_ibss_rsn(
1223151497Sru	struct wpa_supplicant *wpa_s, char *addr)
1224151497Sru{
1225151497Sru	u8 peer[ETH_ALEN];
1226151497Sru
1227151497Sru	if (hwaddr_aton(addr, peer)) {
1228151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
1229151497Sru			   "address '%s'", addr);
1230151497Sru		return -1;
1231151497Sru	}
1232151497Sru
1233151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
1234151497Sru		   MAC2STR(peer));
1235151497Sru
1236151497Sru	return ibss_rsn_start(wpa_s->ibss_rsn, peer);
1237151497Sru}
1238151497Sru#endif /* CONFIG_IBSS_RSN */
1239151497Sru
1240151497Sru
1241151497Srustatic int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
1242151497Sru					      char *rsp)
1243151497Sru{
1244151497Sru#ifdef IEEE8021X_EAPOL
1245151497Sru	char *pos, *id_pos;
1246151497Sru	int id;
1247151497Sru	struct wpa_ssid *ssid;
1248151497Sru
1249151497Sru	pos = os_strchr(rsp, '-');
1250151497Sru	if (pos == NULL)
1251151497Sru		return -1;
1252151497Sru	*pos++ = '\0';
1253151497Sru	id_pos = pos;
1254151497Sru	pos = os_strchr(pos, ':');
1255151497Sru	if (pos == NULL)
1256151497Sru		return -1;
1257151497Sru	*pos++ = '\0';
1258151497Sru	id = atoi(id_pos);
1259151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
1260151497Sru	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1261151497Sru			      (u8 *) pos, os_strlen(pos));
1262151497Sru
1263151497Sru	ssid = wpa_config_get_network(wpa_s->conf, id);
1264151497Sru	if (ssid == NULL) {
1265151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1266151497Sru			   "to update", id);
1267151497Sru		return -1;
1268151497Sru	}
1269151497Sru
1270151497Sru	return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
1271151497Sru							 pos);
1272151497Sru#else /* IEEE8021X_EAPOL */
1273151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1274151497Sru	return -1;
1275151497Sru#endif /* IEEE8021X_EAPOL */
1276151497Sru}
1277151497Sru
1278151497Sru
1279151497Srustatic int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
1280151497Sru					    const char *params,
1281151497Sru					    char *buf, size_t buflen)
1282151497Sru{
1283151497Sru	char *pos, *end, tmp[30];
1284151497Sru	int res, verbose, wps, ret;
1285151497Sru
1286151497Sru	verbose = os_strcmp(params, "-VERBOSE") == 0;
1287151497Sru	wps = os_strcmp(params, "-WPS") == 0;
1288151497Sru	pos = buf;
1289151497Sru	end = buf + buflen;
1290151497Sru	if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1291151497Sru		struct wpa_ssid *ssid = wpa_s->current_ssid;
1292151497Sru		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
1293151497Sru				  MAC2STR(wpa_s->bssid));
1294151497Sru		if (ret < 0 || ret >= end - pos)
1295151497Sru			return pos - buf;
1296151497Sru		pos += ret;
1297151497Sru		if (ssid) {
1298151497Sru			u8 *_ssid = ssid->ssid;
1299151497Sru			size_t ssid_len = ssid->ssid_len;
1300151497Sru			u8 ssid_buf[MAX_SSID_LEN];
1301151497Sru			if (ssid_len == 0) {
1302151497Sru				int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
1303151497Sru				if (_res < 0)
1304151497Sru					ssid_len = 0;
1305151497Sru				else
1306151497Sru					ssid_len = _res;
1307151497Sru				_ssid = ssid_buf;
1308151497Sru			}
1309151497Sru			ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
1310151497Sru					  wpa_ssid_txt(_ssid, ssid_len),
1311151497Sru					  ssid->id);
1312151497Sru			if (ret < 0 || ret >= end - pos)
1313151497Sru				return pos - buf;
1314151497Sru			pos += ret;
1315151497Sru
1316151497Sru			if (wps && ssid->passphrase &&
1317151497Sru			    wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
1318151497Sru			    (ssid->mode == WPAS_MODE_AP ||
1319151497Sru			     ssid->mode == WPAS_MODE_P2P_GO)) {
1320151497Sru				ret = os_snprintf(pos, end - pos,
1321151497Sru						  "passphrase=%s\n",
1322151497Sru						  ssid->passphrase);
1323151497Sru				if (ret < 0 || ret >= end - pos)
1324151497Sru					return pos - buf;
1325151497Sru				pos += ret;
1326151497Sru			}
1327151497Sru			if (ssid->id_str) {
1328151497Sru				ret = os_snprintf(pos, end - pos,
1329151497Sru						  "id_str=%s\n",
1330151497Sru						  ssid->id_str);
1331151497Sru				if (ret < 0 || ret >= end - pos)
1332151497Sru					return pos - buf;
1333151497Sru				pos += ret;
1334151497Sru			}
1335151497Sru
1336151497Sru			switch (ssid->mode) {
1337151497Sru			case WPAS_MODE_INFRA:
1338151497Sru				ret = os_snprintf(pos, end - pos,
1339151497Sru						  "mode=station\n");
1340151497Sru				break;
1341151497Sru			case WPAS_MODE_IBSS:
1342151497Sru				ret = os_snprintf(pos, end - pos,
1343151497Sru						  "mode=IBSS\n");
1344151497Sru				break;
1345151497Sru			case WPAS_MODE_AP:
1346151497Sru				ret = os_snprintf(pos, end - pos,
1347151497Sru						  "mode=AP\n");
1348151497Sru				break;
1349151497Sru			case WPAS_MODE_P2P_GO:
1350151497Sru				ret = os_snprintf(pos, end - pos,
1351151497Sru						  "mode=P2P GO\n");
1352151497Sru				break;
1353151497Sru			case WPAS_MODE_P2P_GROUP_FORMATION:
1354151497Sru				ret = os_snprintf(pos, end - pos,
1355151497Sru						  "mode=P2P GO - group "
1356151497Sru						  "formation\n");
1357151497Sru				break;
1358151497Sru			default:
1359151497Sru				ret = 0;
1360151497Sru				break;
1361151497Sru			}
1362151497Sru			if (ret < 0 || ret >= end - pos)
1363151497Sru				return pos - buf;
1364151497Sru			pos += ret;
1365151497Sru		}
1366151497Sru
1367151497Sru#ifdef CONFIG_AP
1368151497Sru		if (wpa_s->ap_iface) {
1369151497Sru			pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
1370151497Sru							    end - pos,
1371151497Sru							    verbose);
1372151497Sru		} else
1373151497Sru#endif /* CONFIG_AP */
1374151497Sru		pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
1375151497Sru	}
1376151497Sru	ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
1377151497Sru			  wpa_supplicant_state_txt(wpa_s->wpa_state));
1378151497Sru	if (ret < 0 || ret >= end - pos)
1379151497Sru		return pos - buf;
1380151497Sru	pos += ret;
1381151497Sru
1382151497Sru	if (wpa_s->l2 &&
1383151497Sru	    l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
1384151497Sru		ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
1385151497Sru		if (ret < 0 || ret >= end - pos)
1386151497Sru			return pos - buf;
1387151497Sru		pos += ret;
1388151497Sru	}
1389151497Sru
1390151497Sru#ifdef CONFIG_P2P
1391151497Sru	if (wpa_s->global->p2p) {
1392151497Sru		ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
1393151497Sru				  "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
1394151497Sru		if (ret < 0 || ret >= end - pos)
1395151497Sru			return pos - buf;
1396151497Sru		pos += ret;
1397151497Sru	}
1398151497Sru#endif /* CONFIG_P2P */
1399151497Sru
1400151497Sru	ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
1401151497Sru			  MAC2STR(wpa_s->own_addr));
1402151497Sru	if (ret < 0 || ret >= end - pos)
1403151497Sru		return pos - buf;
1404151497Sru	pos += ret;
1405151497Sru
1406151497Sru#ifdef CONFIG_HS20
1407151497Sru	if (wpa_s->current_bss &&
1408151497Sru	    wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
1409151497Sru	    wpa_s->wpa_proto == WPA_PROTO_RSN &&
1410151497Sru	    wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
1411151497Sru		ret = os_snprintf(pos, end - pos, "hs20=1\n");
1412151497Sru		if (ret < 0 || ret >= end - pos)
1413151497Sru			return pos - buf;
1414151497Sru		pos += ret;
1415151497Sru	}
1416151497Sru
1417151497Sru	if (wpa_s->current_ssid) {
1418151497Sru		struct wpa_cred *cred;
1419151497Sru		char *type;
1420151497Sru
1421151497Sru		for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1422151497Sru			if (wpa_s->current_ssid->parent_cred != cred)
1423151497Sru				continue;
1424151497Sru			if (!cred->domain)
1425151497Sru				continue;
1426151497Sru
1427151497Sru			ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
1428151497Sru					  cred->domain);
1429151497Sru			if (ret < 0 || ret >= end - pos)
1430151497Sru				return pos - buf;
1431151497Sru			pos += ret;
1432151497Sru
1433151497Sru			if (wpa_s->current_bss == NULL ||
1434151497Sru			    wpa_s->current_bss->anqp == NULL)
1435151497Sru				res = -1;
1436151497Sru			else
1437151497Sru				res = interworking_home_sp_cred(
1438151497Sru					wpa_s, cred,
1439151497Sru					wpa_s->current_bss->anqp->domain_name);
1440151497Sru			if (res > 0)
1441151497Sru				type = "home";
1442151497Sru			else if (res == 0)
1443151497Sru				type = "roaming";
1444151497Sru			else
1445151497Sru				type = "unknown";
1446151497Sru
1447151497Sru			ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
1448151497Sru			if (ret < 0 || ret >= end - pos)
1449151497Sru				return pos - buf;
1450151497Sru			pos += ret;
1451151497Sru
1452151497Sru			break;
1453151497Sru		}
1454151497Sru	}
1455151497Sru#endif /* CONFIG_HS20 */
1456151497Sru
1457151497Sru	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
1458151497Sru	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
1459151497Sru		res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
1460151497Sru					  verbose);
1461151497Sru		if (res >= 0)
1462151497Sru			pos += res;
1463151497Sru	}
1464151497Sru
1465151497Sru	res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
1466151497Sru	if (res >= 0)
1467151497Sru		pos += res;
1468151497Sru
1469151497Sru	return pos - buf;
1470151497Sru}
1471151497Sru
1472151497Sru
1473151497Srustatic int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
1474151497Sru					   char *cmd)
1475151497Sru{
1476151497Sru	char *pos;
1477151497Sru	int id;
1478151497Sru	struct wpa_ssid *ssid;
1479151497Sru	u8 bssid[ETH_ALEN];
1480151497Sru
1481151497Sru	/* cmd: "<network id> <BSSID>" */
1482151497Sru	pos = os_strchr(cmd, ' ');
1483151497Sru	if (pos == NULL)
1484151497Sru		return -1;
1485151497Sru	*pos++ = '\0';
1486151497Sru	id = atoi(cmd);
1487151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
1488151497Sru	if (hwaddr_aton(pos, bssid)) {
1489151497Sru		wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
1490151497Sru		return -1;
1491151497Sru	}
1492151497Sru
1493151497Sru	ssid = wpa_config_get_network(wpa_s->conf, id);
1494151497Sru	if (ssid == NULL) {
1495151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1496151497Sru			   "to update", id);
1497151497Sru		return -1;
1498151497Sru	}
1499151497Sru
1500151497Sru	os_memcpy(ssid->bssid, bssid, ETH_ALEN);
1501151497Sru	ssid->bssid_set = !is_zero_ether_addr(bssid);
1502151497Sru
1503151497Sru	return 0;
1504151497Sru}
1505151497Sru
1506151497Sru
1507151497Srustatic int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
1508151497Sru					       char *cmd, char *buf,
1509151497Sru					       size_t buflen)
1510151497Sru{
1511151497Sru	u8 bssid[ETH_ALEN];
1512151497Sru	struct wpa_blacklist *e;
1513151497Sru	char *pos, *end;
1514151497Sru	int ret;
1515151497Sru
1516151497Sru	/* cmd: "BLACKLIST [<BSSID>]" */
1517151497Sru	if (*cmd == '\0') {
1518151497Sru		pos = buf;
1519151497Sru		end = buf + buflen;
1520151497Sru		e = wpa_s->blacklist;
1521151497Sru		while (e) {
1522151497Sru			ret = os_snprintf(pos, end - pos, MACSTR "\n",
1523151497Sru					  MAC2STR(e->bssid));
1524151497Sru			if (ret < 0 || ret >= end - pos)
1525151497Sru				return pos - buf;
1526151497Sru			pos += ret;
1527151497Sru			e = e->next;
1528151497Sru		}
1529151497Sru		return pos - buf;
1530151497Sru	}
1531151497Sru
1532151497Sru	cmd++;
1533151497Sru	if (os_strncmp(cmd, "clear", 5) == 0) {
1534151497Sru		wpa_blacklist_clear(wpa_s);
1535151497Sru		os_memcpy(buf, "OK\n", 3);
1536151497Sru		return 3;
1537151497Sru	}
1538151497Sru
1539151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
1540151497Sru	if (hwaddr_aton(cmd, bssid)) {
1541151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
1542151497Sru		return -1;
1543151497Sru	}
1544151497Sru
1545151497Sru	/*
1546151497Sru	 * Add the BSSID twice, so its count will be 2, causing it to be
1547151497Sru	 * skipped when processing scan results.
1548151497Sru	 */
1549151497Sru	ret = wpa_blacklist_add(wpa_s, bssid);
1550151497Sru	if (ret != 0)
1551151497Sru		return -1;
1552151497Sru	ret = wpa_blacklist_add(wpa_s, bssid);
1553151497Sru	if (ret != 0)
1554151497Sru		return -1;
1555151497Sru	os_memcpy(buf, "OK\n", 3);
1556151497Sru	return 3;
1557151497Sru}
1558151497Sru
1559151497Sru
1560151497Sruextern int wpa_debug_level;
1561151497Sruextern int wpa_debug_timestamp;
1562151497Sru
1563static const char * debug_level_str(int level)
1564{
1565	switch (level) {
1566	case MSG_EXCESSIVE:
1567		return "EXCESSIVE";
1568	case MSG_MSGDUMP:
1569		return "MSGDUMP";
1570	case MSG_DEBUG:
1571		return "DEBUG";
1572	case MSG_INFO:
1573		return "INFO";
1574	case MSG_WARNING:
1575		return "WARNING";
1576	case MSG_ERROR:
1577		return "ERROR";
1578	default:
1579		return "?";
1580	}
1581}
1582
1583
1584static int str_to_debug_level(const char *s)
1585{
1586	if (os_strcasecmp(s, "EXCESSIVE") == 0)
1587		return MSG_EXCESSIVE;
1588	if (os_strcasecmp(s, "MSGDUMP") == 0)
1589		return MSG_MSGDUMP;
1590	if (os_strcasecmp(s, "DEBUG") == 0)
1591		return MSG_DEBUG;
1592	if (os_strcasecmp(s, "INFO") == 0)
1593		return MSG_INFO;
1594	if (os_strcasecmp(s, "WARNING") == 0)
1595		return MSG_WARNING;
1596	if (os_strcasecmp(s, "ERROR") == 0)
1597		return MSG_ERROR;
1598	return -1;
1599}
1600
1601
1602static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
1603					       char *cmd, char *buf,
1604					       size_t buflen)
1605{
1606	char *pos, *end, *stamp;
1607	int ret;
1608
1609	if (cmd == NULL) {
1610		return -1;
1611	}
1612
1613	/* cmd: "LOG_LEVEL [<level>]" */
1614	if (*cmd == '\0') {
1615		pos = buf;
1616		end = buf + buflen;
1617		ret = os_snprintf(pos, end - pos, "Current level: %s\n"
1618				  "Timestamp: %d\n",
1619				  debug_level_str(wpa_debug_level),
1620				  wpa_debug_timestamp);
1621		if (ret < 0 || ret >= end - pos)
1622			ret = 0;
1623
1624		return ret;
1625	}
1626
1627	while (*cmd == ' ')
1628		cmd++;
1629
1630	stamp = os_strchr(cmd, ' ');
1631	if (stamp) {
1632		*stamp++ = '\0';
1633		while (*stamp == ' ') {
1634			stamp++;
1635		}
1636	}
1637
1638	if (cmd && os_strlen(cmd)) {
1639		int level = str_to_debug_level(cmd);
1640		if (level < 0)
1641			return -1;
1642		wpa_debug_level = level;
1643	}
1644
1645	if (stamp && os_strlen(stamp))
1646		wpa_debug_timestamp = atoi(stamp);
1647
1648	os_memcpy(buf, "OK\n", 3);
1649	return 3;
1650}
1651
1652
1653static int wpa_supplicant_ctrl_iface_list_networks(
1654	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1655{
1656	char *pos, *end;
1657	struct wpa_ssid *ssid;
1658	int ret;
1659
1660	pos = buf;
1661	end = buf + buflen;
1662	ret = os_snprintf(pos, end - pos,
1663			  "network id / ssid / bssid / flags\n");
1664	if (ret < 0 || ret >= end - pos)
1665		return pos - buf;
1666	pos += ret;
1667
1668	ssid = wpa_s->conf->ssid;
1669	while (ssid) {
1670		ret = os_snprintf(pos, end - pos, "%d\t%s",
1671				  ssid->id,
1672				  wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
1673		if (ret < 0 || ret >= end - pos)
1674			return pos - buf;
1675		pos += ret;
1676		if (ssid->bssid_set) {
1677			ret = os_snprintf(pos, end - pos, "\t" MACSTR,
1678					  MAC2STR(ssid->bssid));
1679		} else {
1680			ret = os_snprintf(pos, end - pos, "\tany");
1681		}
1682		if (ret < 0 || ret >= end - pos)
1683			return pos - buf;
1684		pos += ret;
1685		ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
1686				  ssid == wpa_s->current_ssid ?
1687				  "[CURRENT]" : "",
1688				  ssid->disabled ? "[DISABLED]" : "",
1689				  ssid->disabled_until.sec ?
1690				  "[TEMP-DISABLED]" : "",
1691				  ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
1692				  "");
1693		if (ret < 0 || ret >= end - pos)
1694			return pos - buf;
1695		pos += ret;
1696		ret = os_snprintf(pos, end - pos, "\n");
1697		if (ret < 0 || ret >= end - pos)
1698			return pos - buf;
1699		pos += ret;
1700
1701		ssid = ssid->next;
1702	}
1703
1704	return pos - buf;
1705}
1706
1707
1708static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
1709{
1710	int first = 1, ret;
1711	ret = os_snprintf(pos, end - pos, "-");
1712	if (ret < 0 || ret >= end - pos)
1713		return pos;
1714	pos += ret;
1715	if (cipher & WPA_CIPHER_NONE) {
1716		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
1717		if (ret < 0 || ret >= end - pos)
1718			return pos;
1719		pos += ret;
1720		first = 0;
1721	}
1722	if (cipher & WPA_CIPHER_WEP40) {
1723		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
1724		if (ret < 0 || ret >= end - pos)
1725			return pos;
1726		pos += ret;
1727		first = 0;
1728	}
1729	if (cipher & WPA_CIPHER_WEP104) {
1730		ret = os_snprintf(pos, end - pos, "%sWEP104",
1731				  first ? "" : "+");
1732		if (ret < 0 || ret >= end - pos)
1733			return pos;
1734		pos += ret;
1735		first = 0;
1736	}
1737	if (cipher & WPA_CIPHER_TKIP) {
1738		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
1739		if (ret < 0 || ret >= end - pos)
1740			return pos;
1741		pos += ret;
1742		first = 0;
1743	}
1744	if (cipher & WPA_CIPHER_CCMP) {
1745		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
1746		if (ret < 0 || ret >= end - pos)
1747			return pos;
1748		pos += ret;
1749		first = 0;
1750	}
1751	if (cipher & WPA_CIPHER_GCMP) {
1752		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+");
1753		if (ret < 0 || ret >= end - pos)
1754			return pos;
1755		pos += ret;
1756		first = 0;
1757	}
1758	return pos;
1759}
1760
1761
1762static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
1763				    const u8 *ie, size_t ie_len)
1764{
1765	struct wpa_ie_data data;
1766	int first, ret;
1767
1768	ret = os_snprintf(pos, end - pos, "[%s-", proto);
1769	if (ret < 0 || ret >= end - pos)
1770		return pos;
1771	pos += ret;
1772
1773	if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
1774		ret = os_snprintf(pos, end - pos, "?]");
1775		if (ret < 0 || ret >= end - pos)
1776			return pos;
1777		pos += ret;
1778		return pos;
1779	}
1780
1781	first = 1;
1782	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
1783		ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
1784		if (ret < 0 || ret >= end - pos)
1785			return pos;
1786		pos += ret;
1787		first = 0;
1788	}
1789	if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
1790		ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
1791		if (ret < 0 || ret >= end - pos)
1792			return pos;
1793		pos += ret;
1794		first = 0;
1795	}
1796	if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
1797		ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
1798		if (ret < 0 || ret >= end - pos)
1799			return pos;
1800		pos += ret;
1801		first = 0;
1802	}
1803#ifdef CONFIG_IEEE80211R
1804	if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
1805		ret = os_snprintf(pos, end - pos, "%sFT/EAP",
1806				  first ? "" : "+");
1807		if (ret < 0 || ret >= end - pos)
1808			return pos;
1809		pos += ret;
1810		first = 0;
1811	}
1812	if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
1813		ret = os_snprintf(pos, end - pos, "%sFT/PSK",
1814				  first ? "" : "+");
1815		if (ret < 0 || ret >= end - pos)
1816			return pos;
1817		pos += ret;
1818		first = 0;
1819	}
1820#endif /* CONFIG_IEEE80211R */
1821#ifdef CONFIG_IEEE80211W
1822	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
1823		ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
1824				  first ? "" : "+");
1825		if (ret < 0 || ret >= end - pos)
1826			return pos;
1827		pos += ret;
1828		first = 0;
1829	}
1830	if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
1831		ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
1832				  first ? "" : "+");
1833		if (ret < 0 || ret >= end - pos)
1834			return pos;
1835		pos += ret;
1836		first = 0;
1837	}
1838#endif /* CONFIG_IEEE80211W */
1839
1840	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
1841
1842	if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
1843		ret = os_snprintf(pos, end - pos, "-preauth");
1844		if (ret < 0 || ret >= end - pos)
1845			return pos;
1846		pos += ret;
1847	}
1848
1849	ret = os_snprintf(pos, end - pos, "]");
1850	if (ret < 0 || ret >= end - pos)
1851		return pos;
1852	pos += ret;
1853
1854	return pos;
1855}
1856
1857
1858#ifdef CONFIG_WPS
1859static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
1860					    char *pos, char *end,
1861					    struct wpabuf *wps_ie)
1862{
1863	int ret;
1864	const char *txt;
1865
1866	if (wps_ie == NULL)
1867		return pos;
1868	if (wps_is_selected_pbc_registrar(wps_ie))
1869		txt = "[WPS-PBC]";
1870#ifdef CONFIG_WPS2
1871	else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
1872		txt = "[WPS-AUTH]";
1873#endif /* CONFIG_WPS2 */
1874	else if (wps_is_selected_pin_registrar(wps_ie))
1875		txt = "[WPS-PIN]";
1876	else
1877		txt = "[WPS]";
1878
1879	ret = os_snprintf(pos, end - pos, "%s", txt);
1880	if (ret >= 0 && ret < end - pos)
1881		pos += ret;
1882	wpabuf_free(wps_ie);
1883	return pos;
1884}
1885#endif /* CONFIG_WPS */
1886
1887
1888static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
1889					char *pos, char *end,
1890					const struct wpa_bss *bss)
1891{
1892#ifdef CONFIG_WPS
1893	struct wpabuf *wps_ie;
1894	wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
1895	return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
1896#else /* CONFIG_WPS */
1897	return pos;
1898#endif /* CONFIG_WPS */
1899}
1900
1901
1902/* Format one result on one text line into a buffer. */
1903static int wpa_supplicant_ctrl_iface_scan_result(
1904	struct wpa_supplicant *wpa_s,
1905	const struct wpa_bss *bss, char *buf, size_t buflen)
1906{
1907	char *pos, *end;
1908	int ret;
1909	const u8 *ie, *ie2, *p2p;
1910
1911	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
1912	if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
1913	    os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
1914	    0)
1915		return 0; /* Do not show P2P listen discovery results here */
1916
1917	pos = buf;
1918	end = buf + buflen;
1919
1920	ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
1921			  MAC2STR(bss->bssid), bss->freq, bss->level);
1922	if (ret < 0 || ret >= end - pos)
1923		return -1;
1924	pos += ret;
1925	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
1926	if (ie)
1927		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
1928	ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
1929	if (ie2)
1930		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
1931	pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
1932	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
1933		ret = os_snprintf(pos, end - pos, "[WEP]");
1934		if (ret < 0 || ret >= end - pos)
1935			return -1;
1936		pos += ret;
1937	}
1938	if (bss->caps & IEEE80211_CAP_IBSS) {
1939		ret = os_snprintf(pos, end - pos, "[IBSS]");
1940		if (ret < 0 || ret >= end - pos)
1941			return -1;
1942		pos += ret;
1943	}
1944	if (bss->caps & IEEE80211_CAP_ESS) {
1945		ret = os_snprintf(pos, end - pos, "[ESS]");
1946		if (ret < 0 || ret >= end - pos)
1947			return -1;
1948		pos += ret;
1949	}
1950	if (p2p) {
1951		ret = os_snprintf(pos, end - pos, "[P2P]");
1952		if (ret < 0 || ret >= end - pos)
1953			return -1;
1954		pos += ret;
1955	}
1956#ifdef CONFIG_HS20
1957	if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
1958		ret = os_snprintf(pos, end - pos, "[HS20]");
1959		if (ret < 0 || ret >= end - pos)
1960			return -1;
1961		pos += ret;
1962	}
1963#endif /* CONFIG_HS20 */
1964
1965	ret = os_snprintf(pos, end - pos, "\t%s",
1966			  wpa_ssid_txt(bss->ssid, bss->ssid_len));
1967	if (ret < 0 || ret >= end - pos)
1968		return -1;
1969	pos += ret;
1970
1971	ret = os_snprintf(pos, end - pos, "\n");
1972	if (ret < 0 || ret >= end - pos)
1973		return -1;
1974	pos += ret;
1975
1976	return pos - buf;
1977}
1978
1979
1980static int wpa_supplicant_ctrl_iface_scan_results(
1981	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
1982{
1983	char *pos, *end;
1984	struct wpa_bss *bss;
1985	int ret;
1986
1987	pos = buf;
1988	end = buf + buflen;
1989	ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
1990			  "flags / ssid\n");
1991	if (ret < 0 || ret >= end - pos)
1992		return pos - buf;
1993	pos += ret;
1994
1995	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
1996		ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
1997							    end - pos);
1998		if (ret < 0 || ret >= end - pos)
1999			return pos - buf;
2000		pos += ret;
2001	}
2002
2003	return pos - buf;
2004}
2005
2006
2007static int wpa_supplicant_ctrl_iface_select_network(
2008	struct wpa_supplicant *wpa_s, char *cmd)
2009{
2010	int id;
2011	struct wpa_ssid *ssid;
2012
2013	/* cmd: "<network id>" or "any" */
2014	if (os_strcmp(cmd, "any") == 0) {
2015		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
2016		ssid = NULL;
2017	} else {
2018		id = atoi(cmd);
2019		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
2020
2021		ssid = wpa_config_get_network(wpa_s->conf, id);
2022		if (ssid == NULL) {
2023			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2024				   "network id=%d", id);
2025			return -1;
2026		}
2027		if (ssid->disabled == 2) {
2028			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2029				   "SELECT_NETWORK with persistent P2P group");
2030			return -1;
2031		}
2032	}
2033
2034	wpa_supplicant_select_network(wpa_s, ssid);
2035
2036	return 0;
2037}
2038
2039
2040static int wpa_supplicant_ctrl_iface_enable_network(
2041	struct wpa_supplicant *wpa_s, char *cmd)
2042{
2043	int id;
2044	struct wpa_ssid *ssid;
2045
2046	/* cmd: "<network id>" or "all" */
2047	if (os_strcmp(cmd, "all") == 0) {
2048		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
2049		ssid = NULL;
2050	} else {
2051		id = atoi(cmd);
2052		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
2053
2054		ssid = wpa_config_get_network(wpa_s->conf, id);
2055		if (ssid == NULL) {
2056			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2057				   "network id=%d", id);
2058			return -1;
2059		}
2060		if (ssid->disabled == 2) {
2061			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2062				   "ENABLE_NETWORK with persistent P2P group");
2063			return -1;
2064		}
2065
2066		if (os_strstr(cmd, " no-connect")) {
2067			ssid->disabled = 0;
2068			return 0;
2069		}
2070	}
2071	wpa_supplicant_enable_network(wpa_s, ssid);
2072
2073	return 0;
2074}
2075
2076
2077static int wpa_supplicant_ctrl_iface_disable_network(
2078	struct wpa_supplicant *wpa_s, char *cmd)
2079{
2080	int id;
2081	struct wpa_ssid *ssid;
2082
2083	/* cmd: "<network id>" or "all" */
2084	if (os_strcmp(cmd, "all") == 0) {
2085		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
2086		ssid = NULL;
2087	} else {
2088		id = atoi(cmd);
2089		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
2090
2091		ssid = wpa_config_get_network(wpa_s->conf, id);
2092		if (ssid == NULL) {
2093			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2094				   "network id=%d", id);
2095			return -1;
2096		}
2097		if (ssid->disabled == 2) {
2098			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2099				   "DISABLE_NETWORK with persistent P2P "
2100				   "group");
2101			return -1;
2102		}
2103	}
2104	wpa_supplicant_disable_network(wpa_s, ssid);
2105
2106	return 0;
2107}
2108
2109
2110static int wpa_supplicant_ctrl_iface_add_network(
2111	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2112{
2113	struct wpa_ssid *ssid;
2114	int ret;
2115
2116	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
2117
2118	ssid = wpa_config_add_network(wpa_s->conf);
2119	if (ssid == NULL)
2120		return -1;
2121
2122	wpas_notify_network_added(wpa_s, ssid);
2123
2124	ssid->disabled = 1;
2125	wpa_config_set_network_defaults(ssid);
2126
2127	ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
2128	if (ret < 0 || (size_t) ret >= buflen)
2129		return -1;
2130	return ret;
2131}
2132
2133
2134static int wpa_supplicant_ctrl_iface_remove_network(
2135	struct wpa_supplicant *wpa_s, char *cmd)
2136{
2137	int id;
2138	struct wpa_ssid *ssid;
2139
2140	/* cmd: "<network id>" or "all" */
2141	if (os_strcmp(cmd, "all") == 0) {
2142		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
2143		ssid = wpa_s->conf->ssid;
2144		while (ssid) {
2145			struct wpa_ssid *remove_ssid = ssid;
2146			id = ssid->id;
2147			ssid = ssid->next;
2148			wpas_notify_network_removed(wpa_s, remove_ssid);
2149			wpa_config_remove_network(wpa_s->conf, id);
2150		}
2151		eapol_sm_invalidate_cached_session(wpa_s->eapol);
2152		if (wpa_s->current_ssid) {
2153#ifdef CONFIG_SME
2154			wpa_s->sme.prev_bssid_set = 0;
2155#endif /* CONFIG_SME */
2156			wpa_sm_set_config(wpa_s->wpa, NULL);
2157			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
2158			wpa_supplicant_deauthenticate(
2159				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
2160		}
2161		return 0;
2162	}
2163
2164	id = atoi(cmd);
2165	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
2166
2167	ssid = wpa_config_get_network(wpa_s->conf, id);
2168	if (ssid)
2169		wpas_notify_network_removed(wpa_s, ssid);
2170	if (ssid == NULL) {
2171		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2172			   "id=%d", id);
2173		return -1;
2174	}
2175
2176	if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
2177#ifdef CONFIG_SME
2178		wpa_s->sme.prev_bssid_set = 0;
2179#endif /* CONFIG_SME */
2180		/*
2181		 * Invalidate the EAP session cache if the current or
2182		 * previously used network is removed.
2183		 */
2184		eapol_sm_invalidate_cached_session(wpa_s->eapol);
2185	}
2186
2187	if (ssid == wpa_s->current_ssid) {
2188		wpa_sm_set_config(wpa_s->wpa, NULL);
2189		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
2190
2191		wpa_supplicant_deauthenticate(wpa_s,
2192					      WLAN_REASON_DEAUTH_LEAVING);
2193	}
2194
2195	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
2196		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
2197			   "network id=%d", id);
2198		return -1;
2199	}
2200
2201	return 0;
2202}
2203
2204
2205static int wpa_supplicant_ctrl_iface_set_network(
2206	struct wpa_supplicant *wpa_s, char *cmd)
2207{
2208	int id;
2209	struct wpa_ssid *ssid;
2210	char *name, *value;
2211
2212	/* cmd: "<network id> <variable name> <value>" */
2213	name = os_strchr(cmd, ' ');
2214	if (name == NULL)
2215		return -1;
2216	*name++ = '\0';
2217
2218	value = os_strchr(name, ' ');
2219	if (value == NULL)
2220		return -1;
2221	*value++ = '\0';
2222
2223	id = atoi(cmd);
2224	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
2225		   id, name);
2226	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
2227			      (u8 *) value, os_strlen(value));
2228
2229	ssid = wpa_config_get_network(wpa_s->conf, id);
2230	if (ssid == NULL) {
2231		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2232			   "id=%d", id);
2233		return -1;
2234	}
2235
2236	if (wpa_config_set(ssid, name, value, 0) < 0) {
2237		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
2238			   "variable '%s'", name);
2239		return -1;
2240	}
2241
2242	if (os_strcmp(name, "bssid") != 0 &&
2243	    os_strcmp(name, "priority") != 0)
2244		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
2245
2246	if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
2247		/*
2248		 * Invalidate the EAP session cache if anything in the current
2249		 * or previously used configuration changes.
2250		 */
2251		eapol_sm_invalidate_cached_session(wpa_s->eapol);
2252	}
2253
2254	if ((os_strcmp(name, "psk") == 0 &&
2255	     value[0] == '"' && ssid->ssid_len) ||
2256	    (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
2257		wpa_config_update_psk(ssid);
2258	else if (os_strcmp(name, "priority") == 0)
2259		wpa_config_update_prio_list(wpa_s->conf);
2260
2261	return 0;
2262}
2263
2264
2265static int wpa_supplicant_ctrl_iface_get_network(
2266	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
2267{
2268	int id;
2269	size_t res;
2270	struct wpa_ssid *ssid;
2271	char *name, *value;
2272
2273	/* cmd: "<network id> <variable name>" */
2274	name = os_strchr(cmd, ' ');
2275	if (name == NULL || buflen == 0)
2276		return -1;
2277	*name++ = '\0';
2278
2279	id = atoi(cmd);
2280	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
2281		   id, name);
2282
2283	ssid = wpa_config_get_network(wpa_s->conf, id);
2284	if (ssid == NULL) {
2285		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2286			   "id=%d", id);
2287		return -1;
2288	}
2289
2290	value = wpa_config_get_no_key(ssid, name);
2291	if (value == NULL) {
2292		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
2293			   "variable '%s'", name);
2294		return -1;
2295	}
2296
2297	res = os_strlcpy(buf, value, buflen);
2298	if (res >= buflen) {
2299		os_free(value);
2300		return -1;
2301	}
2302
2303	os_free(value);
2304
2305	return res;
2306}
2307
2308
2309static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
2310						char *buf, size_t buflen)
2311{
2312	char *pos, *end;
2313	struct wpa_cred *cred;
2314	int ret;
2315
2316	pos = buf;
2317	end = buf + buflen;
2318	ret = os_snprintf(pos, end - pos,
2319			  "cred id / realm / username / domain / imsi\n");
2320	if (ret < 0 || ret >= end - pos)
2321		return pos - buf;
2322	pos += ret;
2323
2324	cred = wpa_s->conf->cred;
2325	while (cred) {
2326		ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
2327				  cred->id, cred->realm ? cred->realm : "",
2328				  cred->username ? cred->username : "",
2329				  cred->domain ? cred->domain : "",
2330				  cred->imsi ? cred->imsi : "");
2331		if (ret < 0 || ret >= end - pos)
2332			return pos - buf;
2333		pos += ret;
2334
2335		cred = cred->next;
2336	}
2337
2338	return pos - buf;
2339}
2340
2341
2342static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
2343					      char *buf, size_t buflen)
2344{
2345	struct wpa_cred *cred;
2346	int ret;
2347
2348	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
2349
2350	cred = wpa_config_add_cred(wpa_s->conf);
2351	if (cred == NULL)
2352		return -1;
2353
2354	ret = os_snprintf(buf, buflen, "%d\n", cred->id);
2355	if (ret < 0 || (size_t) ret >= buflen)
2356		return -1;
2357	return ret;
2358}
2359
2360
2361static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
2362				 struct wpa_cred *cred)
2363{
2364	struct wpa_ssid *ssid;
2365	char str[20];
2366
2367	if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
2368		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
2369		return -1;
2370	}
2371
2372	/* Remove any network entry created based on the removed credential */
2373	ssid = wpa_s->conf->ssid;
2374	while (ssid) {
2375		if (ssid->parent_cred == cred) {
2376			wpa_printf(MSG_DEBUG, "Remove network id %d since it "
2377				   "used the removed credential", ssid->id);
2378			os_snprintf(str, sizeof(str), "%d", ssid->id);
2379			ssid = ssid->next;
2380			wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
2381		} else
2382			ssid = ssid->next;
2383	}
2384
2385	return 0;
2386}
2387
2388
2389static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
2390						 char *cmd)
2391{
2392	int id;
2393	struct wpa_cred *cred, *prev;
2394
2395	/* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
2396	if (os_strcmp(cmd, "all") == 0) {
2397		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
2398		cred = wpa_s->conf->cred;
2399		while (cred) {
2400			prev = cred;
2401			cred = cred->next;
2402			wpas_ctrl_remove_cred(wpa_s, prev);
2403		}
2404		return 0;
2405	}
2406
2407	if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
2408		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
2409			   cmd + 8);
2410		cred = wpa_s->conf->cred;
2411		while (cred) {
2412			prev = cred;
2413			cred = cred->next;
2414			if (prev->domain &&
2415			    os_strcmp(prev->domain, cmd + 8) == 0)
2416				wpas_ctrl_remove_cred(wpa_s, prev);
2417		}
2418		return 0;
2419	}
2420
2421	id = atoi(cmd);
2422	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
2423
2424	cred = wpa_config_get_cred(wpa_s->conf, id);
2425	return wpas_ctrl_remove_cred(wpa_s, cred);
2426}
2427
2428
2429static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
2430					      char *cmd)
2431{
2432	int id;
2433	struct wpa_cred *cred;
2434	char *name, *value;
2435
2436	/* cmd: "<cred id> <variable name> <value>" */
2437	name = os_strchr(cmd, ' ');
2438	if (name == NULL)
2439		return -1;
2440	*name++ = '\0';
2441
2442	value = os_strchr(name, ' ');
2443	if (value == NULL)
2444		return -1;
2445	*value++ = '\0';
2446
2447	id = atoi(cmd);
2448	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
2449		   id, name);
2450	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
2451			      (u8 *) value, os_strlen(value));
2452
2453	cred = wpa_config_get_cred(wpa_s->conf, id);
2454	if (cred == NULL) {
2455		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
2456			   id);
2457		return -1;
2458	}
2459
2460	if (wpa_config_set_cred(cred, name, value, 0) < 0) {
2461		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
2462			   "variable '%s'", name);
2463		return -1;
2464	}
2465
2466	return 0;
2467}
2468
2469
2470#ifndef CONFIG_NO_CONFIG_WRITE
2471static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
2472{
2473	int ret;
2474
2475	if (!wpa_s->conf->update_config) {
2476		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
2477			   "to update configuration (update_config=0)");
2478		return -1;
2479	}
2480
2481	ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
2482	if (ret) {
2483		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
2484			   "update configuration");
2485	} else {
2486		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
2487			   " updated");
2488	}
2489
2490	return ret;
2491}
2492#endif /* CONFIG_NO_CONFIG_WRITE */
2493
2494
2495static int ctrl_iface_get_capability_pairwise(int res, char *strict,
2496					      struct wpa_driver_capa *capa,
2497					      char *buf, size_t buflen)
2498{
2499	int ret, first = 1;
2500	char *pos, *end;
2501	size_t len;
2502
2503	pos = buf;
2504	end = pos + buflen;
2505
2506	if (res < 0) {
2507		if (strict)
2508			return 0;
2509		len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
2510		if (len >= buflen)
2511			return -1;
2512		return len;
2513	}
2514
2515	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2516		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
2517		if (ret < 0 || ret >= end - pos)
2518			return pos - buf;
2519		pos += ret;
2520		first = 0;
2521	}
2522
2523	if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2524		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
2525		if (ret < 0 || ret >= end - pos)
2526			return pos - buf;
2527		pos += ret;
2528		first = 0;
2529	}
2530
2531	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2532		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
2533		if (ret < 0 || ret >= end - pos)
2534			return pos - buf;
2535		pos += ret;
2536		first = 0;
2537	}
2538
2539	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2540		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
2541		if (ret < 0 || ret >= end - pos)
2542			return pos - buf;
2543		pos += ret;
2544		first = 0;
2545	}
2546
2547	return pos - buf;
2548}
2549
2550
2551static int ctrl_iface_get_capability_group(int res, char *strict,
2552					   struct wpa_driver_capa *capa,
2553					   char *buf, size_t buflen)
2554{
2555	int ret, first = 1;
2556	char *pos, *end;
2557	size_t len;
2558
2559	pos = buf;
2560	end = pos + buflen;
2561
2562	if (res < 0) {
2563		if (strict)
2564			return 0;
2565		len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
2566		if (len >= buflen)
2567			return -1;
2568		return len;
2569	}
2570
2571	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
2572		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
2573		if (ret < 0 || ret >= end - pos)
2574			return pos - buf;
2575		pos += ret;
2576		first = 0;
2577	}
2578
2579	if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
2580		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
2581		if (ret < 0 || ret >= end - pos)
2582			return pos - buf;
2583		pos += ret;
2584		first = 0;
2585	}
2586
2587	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
2588		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
2589		if (ret < 0 || ret >= end - pos)
2590			return pos - buf;
2591		pos += ret;
2592		first = 0;
2593	}
2594
2595	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
2596		ret = os_snprintf(pos, end - pos, "%sWEP104",
2597				  first ? "" : " ");
2598		if (ret < 0 || ret >= end - pos)
2599			return pos - buf;
2600		pos += ret;
2601		first = 0;
2602	}
2603
2604	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
2605		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
2606		if (ret < 0 || ret >= end - pos)
2607			return pos - buf;
2608		pos += ret;
2609		first = 0;
2610	}
2611
2612	return pos - buf;
2613}
2614
2615
2616static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
2617					      struct wpa_driver_capa *capa,
2618					      char *buf, size_t buflen)
2619{
2620	int ret;
2621	char *pos, *end;
2622	size_t len;
2623
2624	pos = buf;
2625	end = pos + buflen;
2626
2627	if (res < 0) {
2628		if (strict)
2629			return 0;
2630		len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
2631				 "NONE", buflen);
2632		if (len >= buflen)
2633			return -1;
2634		return len;
2635	}
2636
2637	ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
2638	if (ret < 0 || ret >= end - pos)
2639		return pos - buf;
2640	pos += ret;
2641
2642	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2643			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2644		ret = os_snprintf(pos, end - pos, " WPA-EAP");
2645		if (ret < 0 || ret >= end - pos)
2646			return pos - buf;
2647		pos += ret;
2648	}
2649
2650	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2651			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2652		ret = os_snprintf(pos, end - pos, " WPA-PSK");
2653		if (ret < 0 || ret >= end - pos)
2654			return pos - buf;
2655		pos += ret;
2656	}
2657
2658	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
2659		ret = os_snprintf(pos, end - pos, " WPA-NONE");
2660		if (ret < 0 || ret >= end - pos)
2661			return pos - buf;
2662		pos += ret;
2663	}
2664
2665	return pos - buf;
2666}
2667
2668
2669static int ctrl_iface_get_capability_proto(int res, char *strict,
2670					   struct wpa_driver_capa *capa,
2671					   char *buf, size_t buflen)
2672{
2673	int ret, first = 1;
2674	char *pos, *end;
2675	size_t len;
2676
2677	pos = buf;
2678	end = pos + buflen;
2679
2680	if (res < 0) {
2681		if (strict)
2682			return 0;
2683		len = os_strlcpy(buf, "RSN WPA", buflen);
2684		if (len >= buflen)
2685			return -1;
2686		return len;
2687	}
2688
2689	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2690			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2691		ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
2692		if (ret < 0 || ret >= end - pos)
2693			return pos - buf;
2694		pos += ret;
2695		first = 0;
2696	}
2697
2698	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2699			      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
2700		ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
2701		if (ret < 0 || ret >= end - pos)
2702			return pos - buf;
2703		pos += ret;
2704		first = 0;
2705	}
2706
2707	return pos - buf;
2708}
2709
2710
2711static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
2712					      struct wpa_driver_capa *capa,
2713					      char *buf, size_t buflen)
2714{
2715	int ret, first = 1;
2716	char *pos, *end;
2717	size_t len;
2718
2719	pos = buf;
2720	end = pos + buflen;
2721
2722	if (res < 0) {
2723		if (strict)
2724			return 0;
2725		len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
2726		if (len >= buflen)
2727			return -1;
2728		return len;
2729	}
2730
2731	if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
2732		ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
2733		if (ret < 0 || ret >= end - pos)
2734			return pos - buf;
2735		pos += ret;
2736		first = 0;
2737	}
2738
2739	if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
2740		ret = os_snprintf(pos, end - pos, "%sSHARED",
2741				  first ? "" : " ");
2742		if (ret < 0 || ret >= end - pos)
2743			return pos - buf;
2744		pos += ret;
2745		first = 0;
2746	}
2747
2748	if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
2749		ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
2750		if (ret < 0 || ret >= end - pos)
2751			return pos - buf;
2752		pos += ret;
2753		first = 0;
2754	}
2755
2756	return pos - buf;
2757}
2758
2759
2760static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
2761					      char *buf, size_t buflen)
2762{
2763	struct hostapd_channel_data *chnl;
2764	int ret, i, j;
2765	char *pos, *end, *hmode;
2766
2767	pos = buf;
2768	end = pos + buflen;
2769
2770	for (j = 0; j < wpa_s->hw.num_modes; j++) {
2771		switch (wpa_s->hw.modes[j].mode) {
2772		case HOSTAPD_MODE_IEEE80211B:
2773			hmode = "B";
2774			break;
2775		case HOSTAPD_MODE_IEEE80211G:
2776			hmode = "G";
2777			break;
2778		case HOSTAPD_MODE_IEEE80211A:
2779			hmode = "A";
2780			break;
2781		case HOSTAPD_MODE_IEEE80211AD:
2782			hmode = "AD";
2783			break;
2784		default:
2785			continue;
2786		}
2787		ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
2788		if (ret < 0 || ret >= end - pos)
2789			return pos - buf;
2790		pos += ret;
2791		chnl = wpa_s->hw.modes[j].channels;
2792		for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
2793			if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
2794				continue;
2795			ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
2796			if (ret < 0 || ret >= end - pos)
2797				return pos - buf;
2798			pos += ret;
2799		}
2800		ret = os_snprintf(pos, end - pos, "\n");
2801		if (ret < 0 || ret >= end - pos)
2802			return pos - buf;
2803		pos += ret;
2804	}
2805
2806	return pos - buf;
2807}
2808
2809
2810static int wpa_supplicant_ctrl_iface_get_capability(
2811	struct wpa_supplicant *wpa_s, const char *_field, char *buf,
2812	size_t buflen)
2813{
2814	struct wpa_driver_capa capa;
2815	int res;
2816	char *strict;
2817	char field[30];
2818	size_t len;
2819
2820	/* Determine whether or not strict checking was requested */
2821	len = os_strlcpy(field, _field, sizeof(field));
2822	if (len >= sizeof(field))
2823		return -1;
2824	strict = os_strchr(field, ' ');
2825	if (strict != NULL) {
2826		*strict++ = '\0';
2827		if (os_strcmp(strict, "strict") != 0)
2828			return -1;
2829	}
2830
2831	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
2832		field, strict ? strict : "");
2833
2834	if (os_strcmp(field, "eap") == 0) {
2835		return eap_get_names(buf, buflen);
2836	}
2837
2838	res = wpa_drv_get_capa(wpa_s, &capa);
2839
2840	if (os_strcmp(field, "pairwise") == 0)
2841		return ctrl_iface_get_capability_pairwise(res, strict, &capa,
2842							  buf, buflen);
2843
2844	if (os_strcmp(field, "group") == 0)
2845		return ctrl_iface_get_capability_group(res, strict, &capa,
2846						       buf, buflen);
2847
2848	if (os_strcmp(field, "key_mgmt") == 0)
2849		return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
2850							  buf, buflen);
2851
2852	if (os_strcmp(field, "proto") == 0)
2853		return ctrl_iface_get_capability_proto(res, strict, &capa,
2854						       buf, buflen);
2855
2856	if (os_strcmp(field, "auth_alg") == 0)
2857		return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
2858							  buf, buflen);
2859
2860	if (os_strcmp(field, "channels") == 0)
2861		return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
2862
2863	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
2864		   field);
2865
2866	return -1;
2867}
2868
2869
2870#ifdef CONFIG_INTERWORKING
2871static char * anqp_add_hex(char *pos, char *end, const char *title,
2872			   struct wpabuf *data)
2873{
2874	char *start = pos;
2875	size_t i;
2876	int ret;
2877	const u8 *d;
2878
2879	if (data == NULL)
2880		return start;
2881
2882	ret = os_snprintf(pos, end - pos, "%s=", title);
2883	if (ret < 0 || ret >= end - pos)
2884		return start;
2885	pos += ret;
2886
2887	d = wpabuf_head_u8(data);
2888	for (i = 0; i < wpabuf_len(data); i++) {
2889		ret = os_snprintf(pos, end - pos, "%02x", *d++);
2890		if (ret < 0 || ret >= end - pos)
2891			return start;
2892		pos += ret;
2893	}
2894
2895	ret = os_snprintf(pos, end - pos, "\n");
2896	if (ret < 0 || ret >= end - pos)
2897		return start;
2898	pos += ret;
2899
2900	return pos;
2901}
2902#endif /* CONFIG_INTERWORKING */
2903
2904
2905static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
2906			  unsigned long mask, char *buf, size_t buflen)
2907{
2908	size_t i;
2909	int ret;
2910	char *pos, *end;
2911	const u8 *ie, *ie2;
2912
2913	pos = buf;
2914	end = buf + buflen;
2915
2916	if (mask & WPA_BSS_MASK_ID) {
2917		ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
2918		if (ret < 0 || ret >= end - pos)
2919			return 0;
2920		pos += ret;
2921	}
2922
2923	if (mask & WPA_BSS_MASK_BSSID) {
2924		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
2925				  MAC2STR(bss->bssid));
2926		if (ret < 0 || ret >= end - pos)
2927			return 0;
2928		pos += ret;
2929	}
2930
2931	if (mask & WPA_BSS_MASK_FREQ) {
2932		ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
2933		if (ret < 0 || ret >= end - pos)
2934			return 0;
2935		pos += ret;
2936	}
2937
2938	if (mask & WPA_BSS_MASK_BEACON_INT) {
2939		ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
2940				  bss->beacon_int);
2941		if (ret < 0 || ret >= end - pos)
2942			return 0;
2943		pos += ret;
2944	}
2945
2946	if (mask & WPA_BSS_MASK_CAPABILITIES) {
2947		ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
2948				  bss->caps);
2949		if (ret < 0 || ret >= end - pos)
2950			return 0;
2951		pos += ret;
2952	}
2953
2954	if (mask & WPA_BSS_MASK_QUAL) {
2955		ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
2956		if (ret < 0 || ret >= end - pos)
2957			return 0;
2958		pos += ret;
2959	}
2960
2961	if (mask & WPA_BSS_MASK_NOISE) {
2962		ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
2963		if (ret < 0 || ret >= end - pos)
2964			return 0;
2965		pos += ret;
2966	}
2967
2968	if (mask & WPA_BSS_MASK_LEVEL) {
2969		ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
2970		if (ret < 0 || ret >= end - pos)
2971			return 0;
2972		pos += ret;
2973	}
2974
2975	if (mask & WPA_BSS_MASK_TSF) {
2976		ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
2977				  (unsigned long long) bss->tsf);
2978		if (ret < 0 || ret >= end - pos)
2979			return 0;
2980		pos += ret;
2981	}
2982
2983	if (mask & WPA_BSS_MASK_AGE) {
2984		struct os_time now;
2985
2986		os_get_time(&now);
2987		ret = os_snprintf(pos, end - pos, "age=%d\n",
2988				  (int) (now.sec - bss->last_update.sec));
2989		if (ret < 0 || ret >= end - pos)
2990			return 0;
2991		pos += ret;
2992	}
2993
2994	if (mask & WPA_BSS_MASK_IE) {
2995		ret = os_snprintf(pos, end - pos, "ie=");
2996		if (ret < 0 || ret >= end - pos)
2997			return 0;
2998		pos += ret;
2999
3000		ie = (const u8 *) (bss + 1);
3001		for (i = 0; i < bss->ie_len; i++) {
3002			ret = os_snprintf(pos, end - pos, "%02x", *ie++);
3003			if (ret < 0 || ret >= end - pos)
3004				return 0;
3005			pos += ret;
3006		}
3007
3008		ret = os_snprintf(pos, end - pos, "\n");
3009		if (ret < 0 || ret >= end - pos)
3010			return 0;
3011		pos += ret;
3012	}
3013
3014	if (mask & WPA_BSS_MASK_FLAGS) {
3015		ret = os_snprintf(pos, end - pos, "flags=");
3016		if (ret < 0 || ret >= end - pos)
3017			return 0;
3018		pos += ret;
3019
3020		ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
3021		if (ie)
3022			pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
3023						    2 + ie[1]);
3024		ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
3025		if (ie2)
3026			pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
3027						    2 + ie2[1]);
3028		pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
3029		if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
3030			ret = os_snprintf(pos, end - pos, "[WEP]");
3031			if (ret < 0 || ret >= end - pos)
3032				return 0;
3033			pos += ret;
3034		}
3035		if (bss->caps & IEEE80211_CAP_IBSS) {
3036			ret = os_snprintf(pos, end - pos, "[IBSS]");
3037			if (ret < 0 || ret >= end - pos)
3038				return 0;
3039			pos += ret;
3040		}
3041		if (bss->caps & IEEE80211_CAP_ESS) {
3042			ret = os_snprintf(pos, end - pos, "[ESS]");
3043			if (ret < 0 || ret >= end - pos)
3044				return 0;
3045			pos += ret;
3046		}
3047		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
3048			ret = os_snprintf(pos, end - pos, "[P2P]");
3049			if (ret < 0 || ret >= end - pos)
3050				return 0;
3051			pos += ret;
3052		}
3053#ifdef CONFIG_HS20
3054		if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
3055			ret = os_snprintf(pos, end - pos, "[HS20]");
3056			if (ret < 0 || ret >= end - pos)
3057				return -1;
3058			pos += ret;
3059		}
3060#endif /* CONFIG_HS20 */
3061
3062		ret = os_snprintf(pos, end - pos, "\n");
3063		if (ret < 0 || ret >= end - pos)
3064			return 0;
3065		pos += ret;
3066	}
3067
3068	if (mask & WPA_BSS_MASK_SSID) {
3069		ret = os_snprintf(pos, end - pos, "ssid=%s\n",
3070				  wpa_ssid_txt(bss->ssid, bss->ssid_len));
3071		if (ret < 0 || ret >= end - pos)
3072			return 0;
3073		pos += ret;
3074	}
3075
3076#ifdef CONFIG_WPS
3077	if (mask & WPA_BSS_MASK_WPS_SCAN) {
3078		ie = (const u8 *) (bss + 1);
3079		ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
3080		if (ret < 0 || ret >= end - pos)
3081			return 0;
3082		pos += ret;
3083	}
3084#endif /* CONFIG_WPS */
3085
3086#ifdef CONFIG_P2P
3087	if (mask & WPA_BSS_MASK_P2P_SCAN) {
3088		ie = (const u8 *) (bss + 1);
3089		ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
3090		if (ret < 0 || ret >= end - pos)
3091			return 0;
3092		pos += ret;
3093	}
3094#endif /* CONFIG_P2P */
3095
3096#ifdef CONFIG_WIFI_DISPLAY
3097	if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
3098		struct wpabuf *wfd;
3099		ie = (const u8 *) (bss + 1);
3100		wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
3101						  WFD_IE_VENDOR_TYPE);
3102		if (wfd) {
3103			ret = os_snprintf(pos, end - pos, "wfd_subelems=");
3104			if (ret < 0 || ret >= end - pos)
3105				return pos - buf;
3106			pos += ret;
3107
3108			pos += wpa_snprintf_hex(pos, end - pos,
3109						wpabuf_head(wfd),
3110						wpabuf_len(wfd));
3111			wpabuf_free(wfd);
3112
3113			ret = os_snprintf(pos, end - pos, "\n");
3114			if (ret < 0 || ret >= end - pos)
3115				return pos - buf;
3116			pos += ret;
3117		}
3118	}
3119#endif /* CONFIG_WIFI_DISPLAY */
3120
3121#ifdef CONFIG_INTERWORKING
3122	if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
3123		struct wpa_bss_anqp *anqp = bss->anqp;
3124		pos = anqp_add_hex(pos, end, "anqp_venue_name",
3125				   anqp->venue_name);
3126		pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
3127				   anqp->network_auth_type);
3128		pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
3129				   anqp->roaming_consortium);
3130		pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
3131				   anqp->ip_addr_type_availability);
3132		pos = anqp_add_hex(pos, end, "anqp_nai_realm",
3133				   anqp->nai_realm);
3134		pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
3135		pos = anqp_add_hex(pos, end, "anqp_domain_name",
3136				   anqp->domain_name);
3137#ifdef CONFIG_HS20
3138		pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
3139				   anqp->hs20_operator_friendly_name);
3140		pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
3141				   anqp->hs20_wan_metrics);
3142		pos = anqp_add_hex(pos, end, "hs20_connection_capability",
3143				   anqp->hs20_connection_capability);
3144#endif /* CONFIG_HS20 */
3145	}
3146#endif /* CONFIG_INTERWORKING */
3147
3148	return pos - buf;
3149}
3150
3151
3152static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
3153					 const char *cmd, char *buf,
3154					 size_t buflen)
3155{
3156	u8 bssid[ETH_ALEN];
3157	size_t i;
3158	struct wpa_bss *bss;
3159	struct wpa_bss *bsslast = NULL;
3160	struct dl_list *next;
3161	int ret = 0;
3162	int len;
3163	char *ctmp;
3164	unsigned long mask = WPA_BSS_MASK_ALL;
3165
3166	if (os_strncmp(cmd, "RANGE=", 6) == 0) {
3167		if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
3168			bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
3169					    list_id);
3170			bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
3171					       list_id);
3172		} else { /* N1-N2 */
3173			unsigned int id1, id2;
3174
3175			if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
3176				wpa_printf(MSG_INFO, "Wrong BSS range "
3177					   "format");
3178				return 0;
3179			}
3180
3181			id1 = atoi(cmd + 6);
3182			bss = wpa_bss_get_id(wpa_s, id1);
3183			id2 = atoi(ctmp + 1);
3184			if (id2 == 0)
3185				bsslast = dl_list_last(&wpa_s->bss_id,
3186						       struct wpa_bss,
3187						       list_id);
3188			else {
3189				bsslast = wpa_bss_get_id(wpa_s, id2);
3190				if (bsslast == NULL && bss && id2 > id1) {
3191					struct wpa_bss *tmp = bss;
3192					for (;;) {
3193						next = tmp->list_id.next;
3194						if (next == &wpa_s->bss_id)
3195							break;
3196						tmp = dl_list_entry(
3197							next, struct wpa_bss,
3198							list_id);
3199						if (tmp->id > id2)
3200							break;
3201						bsslast = tmp;
3202					}
3203				}
3204			}
3205		}
3206	} else if (os_strcmp(cmd, "FIRST") == 0)
3207		bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
3208	else if (os_strncmp(cmd, "ID-", 3) == 0) {
3209		i = atoi(cmd + 3);
3210		bss = wpa_bss_get_id(wpa_s, i);
3211	} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
3212		i = atoi(cmd + 5);
3213		bss = wpa_bss_get_id(wpa_s, i);
3214		if (bss) {
3215			next = bss->list_id.next;
3216			if (next == &wpa_s->bss_id)
3217				bss = NULL;
3218			else
3219				bss = dl_list_entry(next, struct wpa_bss,
3220						    list_id);
3221		}
3222#ifdef CONFIG_P2P
3223	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
3224		if (hwaddr_aton(cmd + 13, bssid) == 0)
3225			bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
3226		else
3227			bss = NULL;
3228#endif /* CONFIG_P2P */
3229	} else if (hwaddr_aton(cmd, bssid) == 0)
3230		bss = wpa_bss_get_bssid(wpa_s, bssid);
3231	else {
3232		struct wpa_bss *tmp;
3233		i = atoi(cmd);
3234		bss = NULL;
3235		dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
3236		{
3237			if (i-- == 0) {
3238				bss = tmp;
3239				break;
3240			}
3241		}
3242	}
3243
3244	if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
3245		mask = strtoul(ctmp + 5, NULL, 0x10);
3246		if (mask == 0)
3247			mask = WPA_BSS_MASK_ALL;
3248	}
3249
3250	if (bss == NULL)
3251		return 0;
3252
3253	if (bsslast == NULL)
3254		bsslast = bss;
3255	do {
3256		len = print_bss_info(wpa_s, bss, mask, buf, buflen);
3257		ret += len;
3258		buf += len;
3259		buflen -= len;
3260		if (bss == bsslast)
3261			break;
3262		next = bss->list_id.next;
3263		if (next == &wpa_s->bss_id)
3264			break;
3265		bss = dl_list_entry(next, struct wpa_bss, list_id);
3266	} while (bss && len);
3267
3268	return ret;
3269}
3270
3271
3272static int wpa_supplicant_ctrl_iface_ap_scan(
3273	struct wpa_supplicant *wpa_s, char *cmd)
3274{
3275	int ap_scan = atoi(cmd);
3276	return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
3277}
3278
3279
3280static int wpa_supplicant_ctrl_iface_scan_interval(
3281	struct wpa_supplicant *wpa_s, char *cmd)
3282{
3283	int scan_int = atoi(cmd);
3284	return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
3285}
3286
3287
3288static int wpa_supplicant_ctrl_iface_bss_expire_age(
3289	struct wpa_supplicant *wpa_s, char *cmd)
3290{
3291	int expire_age = atoi(cmd);
3292	return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
3293}
3294
3295
3296static int wpa_supplicant_ctrl_iface_bss_expire_count(
3297	struct wpa_supplicant *wpa_s, char *cmd)
3298{
3299	int expire_count = atoi(cmd);
3300	return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
3301}
3302
3303
3304static int wpa_supplicant_ctrl_iface_bss_flush(
3305	struct wpa_supplicant *wpa_s, char *cmd)
3306{
3307	int flush_age = atoi(cmd);
3308
3309	if (flush_age == 0)
3310		wpa_bss_flush(wpa_s);
3311	else
3312		wpa_bss_flush_by_age(wpa_s, flush_age);
3313	return 0;
3314}
3315
3316
3317static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
3318{
3319	wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
3320	/* MLME-DELETEKEYS.request */
3321	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
3322	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
3323	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
3324	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
3325#ifdef CONFIG_IEEE80211W
3326	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
3327	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
3328#endif /* CONFIG_IEEE80211W */
3329
3330	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
3331			0);
3332	/* MLME-SETPROTECTION.request(None) */
3333	wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
3334				   MLME_SETPROTECTION_PROTECT_TYPE_NONE,
3335				   MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
3336	wpa_sm_drop_sa(wpa_s->wpa);
3337}
3338
3339
3340static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
3341					  char *addr)
3342{
3343#ifdef CONFIG_NO_SCAN_PROCESSING
3344	return -1;
3345#else /* CONFIG_NO_SCAN_PROCESSING */
3346	u8 bssid[ETH_ALEN];
3347	struct wpa_bss *bss;
3348	struct wpa_ssid *ssid = wpa_s->current_ssid;
3349
3350	if (hwaddr_aton(addr, bssid)) {
3351		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
3352			   "address '%s'", addr);
3353		return -1;
3354	}
3355
3356	wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
3357
3358	bss = wpa_bss_get_bssid(wpa_s, bssid);
3359	if (!bss) {
3360		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
3361			   "from BSS table");
3362		return -1;
3363	}
3364
3365	/*
3366	 * TODO: Find best network configuration block from configuration to
3367	 * allow roaming to other networks
3368	 */
3369
3370	if (!ssid) {
3371		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
3372			   "configuration known for the target AP");
3373		return -1;
3374	}
3375
3376	wpa_s->reassociate = 1;
3377	wpa_supplicant_connect(wpa_s, bss, ssid);
3378
3379	return 0;
3380#endif /* CONFIG_NO_SCAN_PROCESSING */
3381}
3382
3383
3384#ifdef CONFIG_P2P
3385static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
3386{
3387	unsigned int timeout = atoi(cmd);
3388	enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
3389	u8 dev_id[ETH_ALEN], *_dev_id = NULL;
3390	char *pos;
3391	unsigned int search_delay;
3392
3393	if (os_strstr(cmd, "type=social"))
3394		type = P2P_FIND_ONLY_SOCIAL;
3395	else if (os_strstr(cmd, "type=progressive"))
3396		type = P2P_FIND_PROGRESSIVE;
3397
3398	pos = os_strstr(cmd, "dev_id=");
3399	if (pos) {
3400		pos += 7;
3401		if (hwaddr_aton(pos, dev_id))
3402			return -1;
3403		_dev_id = dev_id;
3404	}
3405
3406	pos = os_strstr(cmd, "delay=");
3407	if (pos) {
3408		pos += 6;
3409		search_delay = atoi(pos);
3410	} else
3411		search_delay = wpas_p2p_search_delay(wpa_s);
3412
3413	return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
3414			     search_delay);
3415}
3416
3417
3418static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
3419			    char *buf, size_t buflen)
3420{
3421	u8 addr[ETH_ALEN];
3422	char *pos, *pos2;
3423	char *pin = NULL;
3424	enum p2p_wps_method wps_method;
3425	int new_pin;
3426	int ret;
3427	int persistent_group, persistent_id = -1;
3428	int join;
3429	int auth;
3430	int automatic;
3431	int go_intent = -1;
3432	int freq = 0;
3433	int pd;
3434	int ht40;
3435
3436	/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
3437	 * [persistent|persistent=<network id>]
3438	 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
3439	 * [ht40] */
3440
3441	if (hwaddr_aton(cmd, addr))
3442		return -1;
3443
3444	pos = cmd + 17;
3445	if (*pos != ' ')
3446		return -1;
3447	pos++;
3448
3449	persistent_group = os_strstr(pos, " persistent") != NULL;
3450	pos2 = os_strstr(pos, " persistent=");
3451	if (pos2) {
3452		struct wpa_ssid *ssid;
3453		persistent_id = atoi(pos2 + 12);
3454		ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
3455		if (ssid == NULL || ssid->disabled != 2 ||
3456		    ssid->mode != WPAS_MODE_P2P_GO) {
3457			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3458				   "SSID id=%d for persistent P2P group (GO)",
3459				   persistent_id);
3460			return -1;
3461		}
3462	}
3463	join = os_strstr(pos, " join") != NULL;
3464	auth = os_strstr(pos, " auth") != NULL;
3465	automatic = os_strstr(pos, " auto") != NULL;
3466	pd = os_strstr(pos, " provdisc") != NULL;
3467	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
3468
3469	pos2 = os_strstr(pos, " go_intent=");
3470	if (pos2) {
3471		pos2 += 11;
3472		go_intent = atoi(pos2);
3473		if (go_intent < 0 || go_intent > 15)
3474			return -1;
3475	}
3476
3477	pos2 = os_strstr(pos, " freq=");
3478	if (pos2) {
3479		pos2 += 6;
3480		freq = atoi(pos2);
3481		if (freq <= 0)
3482			return -1;
3483	}
3484
3485	if (os_strncmp(pos, "pin", 3) == 0) {
3486		/* Request random PIN (to be displayed) and enable the PIN */
3487		wps_method = WPS_PIN_DISPLAY;
3488	} else if (os_strncmp(pos, "pbc", 3) == 0) {
3489		wps_method = WPS_PBC;
3490	} else {
3491		pin = pos;
3492		pos = os_strchr(pin, ' ');
3493		wps_method = WPS_PIN_KEYPAD;
3494		if (pos) {
3495			*pos++ = '\0';
3496			if (os_strncmp(pos, "display", 7) == 0)
3497				wps_method = WPS_PIN_DISPLAY;
3498		}
3499		if (!wps_pin_str_valid(pin)) {
3500			os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
3501			return 17;
3502		}
3503	}
3504
3505	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
3506				   persistent_group, automatic, join,
3507				   auth, go_intent, freq, persistent_id, pd,
3508				   ht40);
3509	if (new_pin == -2) {
3510		os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
3511		return 25;
3512	}
3513	if (new_pin == -3) {
3514		os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
3515		return 25;
3516	}
3517	if (new_pin < 0)
3518		return -1;
3519	if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
3520		ret = os_snprintf(buf, buflen, "%08d", new_pin);
3521		if (ret < 0 || (size_t) ret >= buflen)
3522			return -1;
3523		return ret;
3524	}
3525
3526	os_memcpy(buf, "OK\n", 3);
3527	return 3;
3528}
3529
3530
3531static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
3532{
3533	unsigned int timeout = atoi(cmd);
3534	return wpas_p2p_listen(wpa_s, timeout);
3535}
3536
3537
3538static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
3539{
3540	u8 addr[ETH_ALEN];
3541	char *pos;
3542	enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
3543
3544	/* <addr> <config method> [join|auto] */
3545
3546	if (hwaddr_aton(cmd, addr))
3547		return -1;
3548
3549	pos = cmd + 17;
3550	if (*pos != ' ')
3551		return -1;
3552	pos++;
3553
3554	if (os_strstr(pos, " join") != NULL)
3555		use = WPAS_P2P_PD_FOR_JOIN;
3556	else if (os_strstr(pos, " auto") != NULL)
3557		use = WPAS_P2P_PD_AUTO;
3558
3559	return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
3560}
3561
3562
3563static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
3564			      size_t buflen)
3565{
3566	struct wpa_ssid *ssid = wpa_s->current_ssid;
3567
3568	if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
3569	    ssid->passphrase == NULL)
3570		return -1;
3571
3572	os_strlcpy(buf, ssid->passphrase, buflen);
3573	return os_strlen(buf);
3574}
3575
3576
3577static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
3578				  char *buf, size_t buflen)
3579{
3580	u64 ref;
3581	int res;
3582	u8 dst_buf[ETH_ALEN], *dst;
3583	struct wpabuf *tlvs;
3584	char *pos;
3585	size_t len;
3586
3587	if (hwaddr_aton(cmd, dst_buf))
3588		return -1;
3589	dst = dst_buf;
3590	if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
3591	    dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
3592		dst = NULL;
3593	pos = cmd + 17;
3594	if (*pos != ' ')
3595		return -1;
3596	pos++;
3597
3598	if (os_strncmp(pos, "upnp ", 5) == 0) {
3599		u8 version;
3600		pos += 5;
3601		if (hexstr2bin(pos, &version, 1) < 0)
3602			return -1;
3603		pos += 2;
3604		if (*pos != ' ')
3605			return -1;
3606		pos++;
3607		ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
3608#ifdef CONFIG_WIFI_DISPLAY
3609	} else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
3610		ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
3611#endif /* CONFIG_WIFI_DISPLAY */
3612	} else {
3613		len = os_strlen(pos);
3614		if (len & 1)
3615			return -1;
3616		len /= 2;
3617		tlvs = wpabuf_alloc(len);
3618		if (tlvs == NULL)
3619			return -1;
3620		if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
3621			wpabuf_free(tlvs);
3622			return -1;
3623		}
3624
3625		ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
3626		wpabuf_free(tlvs);
3627	}
3628	if (ref == 0)
3629		return -1;
3630	res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
3631	if (res < 0 || (unsigned) res >= buflen)
3632		return -1;
3633	return res;
3634}
3635
3636
3637static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
3638					 char *cmd)
3639{
3640	long long unsigned val;
3641	u64 req;
3642	if (sscanf(cmd, "%llx", &val) != 1)
3643		return -1;
3644	req = val;
3645	return wpas_p2p_sd_cancel_request(wpa_s, req);
3646}
3647
3648
3649static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
3650{
3651	int freq;
3652	u8 dst[ETH_ALEN];
3653	u8 dialog_token;
3654	struct wpabuf *resp_tlvs;
3655	char *pos, *pos2;
3656	size_t len;
3657
3658	pos = os_strchr(cmd, ' ');
3659	if (pos == NULL)
3660		return -1;
3661	*pos++ = '\0';
3662	freq = atoi(cmd);
3663	if (freq == 0)
3664		return -1;
3665
3666	if (hwaddr_aton(pos, dst))
3667		return -1;
3668	pos += 17;
3669	if (*pos != ' ')
3670		return -1;
3671	pos++;
3672
3673	pos2 = os_strchr(pos, ' ');
3674	if (pos2 == NULL)
3675		return -1;
3676	*pos2++ = '\0';
3677	dialog_token = atoi(pos);
3678
3679	len = os_strlen(pos2);
3680	if (len & 1)
3681		return -1;
3682	len /= 2;
3683	resp_tlvs = wpabuf_alloc(len);
3684	if (resp_tlvs == NULL)
3685		return -1;
3686	if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
3687		wpabuf_free(resp_tlvs);
3688		return -1;
3689	}
3690
3691	wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
3692	wpabuf_free(resp_tlvs);
3693	return 0;
3694}
3695
3696
3697static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
3698				       char *cmd)
3699{
3700	if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
3701		return -1;
3702	wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
3703	return 0;
3704}
3705
3706
3707static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
3708					char *cmd)
3709{
3710	char *pos;
3711	size_t len;
3712	struct wpabuf *query, *resp;
3713
3714	pos = os_strchr(cmd, ' ');
3715	if (pos == NULL)
3716		return -1;
3717	*pos++ = '\0';
3718
3719	len = os_strlen(cmd);
3720	if (len & 1)
3721		return -1;
3722	len /= 2;
3723	query = wpabuf_alloc(len);
3724	if (query == NULL)
3725		return -1;
3726	if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
3727		wpabuf_free(query);
3728		return -1;
3729	}
3730
3731	len = os_strlen(pos);
3732	if (len & 1) {
3733		wpabuf_free(query);
3734		return -1;
3735	}
3736	len /= 2;
3737	resp = wpabuf_alloc(len);
3738	if (resp == NULL) {
3739		wpabuf_free(query);
3740		return -1;
3741	}
3742	if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
3743		wpabuf_free(query);
3744		wpabuf_free(resp);
3745		return -1;
3746	}
3747
3748	if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
3749		wpabuf_free(query);
3750		wpabuf_free(resp);
3751		return -1;
3752	}
3753	return 0;
3754}
3755
3756
3757static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
3758{
3759	char *pos;
3760	u8 version;
3761
3762	pos = os_strchr(cmd, ' ');
3763	if (pos == NULL)
3764		return -1;
3765	*pos++ = '\0';
3766
3767	if (hexstr2bin(cmd, &version, 1) < 0)
3768		return -1;
3769
3770	return wpas_p2p_service_add_upnp(wpa_s, version, pos);
3771}
3772
3773
3774static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
3775{
3776	char *pos;
3777
3778	pos = os_strchr(cmd, ' ');
3779	if (pos == NULL)
3780		return -1;
3781	*pos++ = '\0';
3782
3783	if (os_strcmp(cmd, "bonjour") == 0)
3784		return p2p_ctrl_service_add_bonjour(wpa_s, pos);
3785	if (os_strcmp(cmd, "upnp") == 0)
3786		return p2p_ctrl_service_add_upnp(wpa_s, pos);
3787	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
3788	return -1;
3789}
3790
3791
3792static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
3793					char *cmd)
3794{
3795	size_t len;
3796	struct wpabuf *query;
3797	int ret;
3798
3799	len = os_strlen(cmd);
3800	if (len & 1)
3801		return -1;
3802	len /= 2;
3803	query = wpabuf_alloc(len);
3804	if (query == NULL)
3805		return -1;
3806	if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
3807		wpabuf_free(query);
3808		return -1;
3809	}
3810
3811	ret = wpas_p2p_service_del_bonjour(wpa_s, query);
3812	wpabuf_free(query);
3813	return ret;
3814}
3815
3816
3817static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
3818{
3819	char *pos;
3820	u8 version;
3821
3822	pos = os_strchr(cmd, ' ');
3823	if (pos == NULL)
3824		return -1;
3825	*pos++ = '\0';
3826
3827	if (hexstr2bin(cmd, &version, 1) < 0)
3828		return -1;
3829
3830	return wpas_p2p_service_del_upnp(wpa_s, version, pos);
3831}
3832
3833
3834static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
3835{
3836	char *pos;
3837
3838	pos = os_strchr(cmd, ' ');
3839	if (pos == NULL)
3840		return -1;
3841	*pos++ = '\0';
3842
3843	if (os_strcmp(cmd, "bonjour") == 0)
3844		return p2p_ctrl_service_del_bonjour(wpa_s, pos);
3845	if (os_strcmp(cmd, "upnp") == 0)
3846		return p2p_ctrl_service_del_upnp(wpa_s, pos);
3847	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
3848	return -1;
3849}
3850
3851
3852static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
3853{
3854	u8 addr[ETH_ALEN];
3855
3856	/* <addr> */
3857
3858	if (hwaddr_aton(cmd, addr))
3859		return -1;
3860
3861	return wpas_p2p_reject(wpa_s, addr);
3862}
3863
3864
3865static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
3866{
3867	char *pos;
3868	int id;
3869	struct wpa_ssid *ssid;
3870	u8 *_peer = NULL, peer[ETH_ALEN];
3871	int freq = 0;
3872	int ht40;
3873
3874	id = atoi(cmd);
3875	pos = os_strstr(cmd, " peer=");
3876	if (pos) {
3877		pos += 6;
3878		if (hwaddr_aton(pos, peer))
3879			return -1;
3880		_peer = peer;
3881	}
3882	ssid = wpa_config_get_network(wpa_s->conf, id);
3883	if (ssid == NULL || ssid->disabled != 2) {
3884		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
3885			   "for persistent P2P group",
3886			   id);
3887		return -1;
3888	}
3889
3890	pos = os_strstr(cmd, " freq=");
3891	if (pos) {
3892		pos += 6;
3893		freq = atoi(pos);
3894		if (freq <= 0)
3895			return -1;
3896	}
3897
3898	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
3899
3900	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
3901}
3902
3903
3904static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
3905{
3906	char *pos;
3907	u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
3908
3909	pos = os_strstr(cmd, " peer=");
3910	if (!pos)
3911		return -1;
3912
3913	*pos = '\0';
3914	pos += 6;
3915	if (hwaddr_aton(pos, peer)) {
3916		wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
3917		return -1;
3918	}
3919
3920	pos = os_strstr(pos, " go_dev_addr=");
3921	if (pos) {
3922		pos += 13;
3923		if (hwaddr_aton(pos, go_dev_addr)) {
3924			wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
3925				   pos);
3926			return -1;
3927		}
3928		go_dev = go_dev_addr;
3929	}
3930
3931	return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
3932}
3933
3934
3935static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
3936{
3937	if (os_strncmp(cmd, "persistent=", 11) == 0)
3938		return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
3939	if (os_strncmp(cmd, "group=", 6) == 0)
3940		return p2p_ctrl_invite_group(wpa_s, cmd + 6);
3941
3942	return -1;
3943}
3944
3945
3946static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
3947					 char *cmd, int freq, int ht40)
3948{
3949	int id;
3950	struct wpa_ssid *ssid;
3951
3952	id = atoi(cmd);
3953	ssid = wpa_config_get_network(wpa_s->conf, id);
3954	if (ssid == NULL || ssid->disabled != 2) {
3955		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
3956			   "for persistent P2P group",
3957			   id);
3958		return -1;
3959	}
3960
3961	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
3962}
3963
3964
3965static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
3966{
3967	int freq = 0, ht40;
3968	char *pos;
3969
3970	pos = os_strstr(cmd, "freq=");
3971	if (pos)
3972		freq = atoi(pos + 5);
3973
3974	ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
3975
3976	if (os_strncmp(cmd, "persistent=", 11) == 0)
3977		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
3978						     ht40);
3979	if (os_strcmp(cmd, "persistent") == 0 ||
3980	    os_strncmp(cmd, "persistent ", 11) == 0)
3981		return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
3982	if (os_strncmp(cmd, "freq=", 5) == 0)
3983		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
3984	if (ht40)
3985		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
3986
3987	wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
3988		   cmd);
3989	return -1;
3990}
3991
3992
3993static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
3994			 char *buf, size_t buflen)
3995{
3996	u8 addr[ETH_ALEN], *addr_ptr;
3997	int next, res;
3998	const struct p2p_peer_info *info;
3999	char *pos, *end;
4000	char devtype[WPS_DEV_TYPE_BUFSIZE];
4001	struct wpa_ssid *ssid;
4002	size_t i;
4003
4004	if (!wpa_s->global->p2p)
4005		return -1;
4006
4007	if (os_strcmp(cmd, "FIRST") == 0) {
4008		addr_ptr = NULL;
4009		next = 0;
4010	} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
4011		if (hwaddr_aton(cmd + 5, addr) < 0)
4012			return -1;
4013		addr_ptr = addr;
4014		next = 1;
4015	} else {
4016		if (hwaddr_aton(cmd, addr) < 0)
4017			return -1;
4018		addr_ptr = addr;
4019		next = 0;
4020	}
4021
4022	info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
4023	if (info == NULL)
4024		return -1;
4025
4026	pos = buf;
4027	end = buf + buflen;
4028
4029	res = os_snprintf(pos, end - pos, MACSTR "\n"
4030			  "pri_dev_type=%s\n"
4031			  "device_name=%s\n"
4032			  "manufacturer=%s\n"
4033			  "model_name=%s\n"
4034			  "model_number=%s\n"
4035			  "serial_number=%s\n"
4036			  "config_methods=0x%x\n"
4037			  "dev_capab=0x%x\n"
4038			  "group_capab=0x%x\n"
4039			  "level=%d\n",
4040			  MAC2STR(info->p2p_device_addr),
4041			  wps_dev_type_bin2str(info->pri_dev_type,
4042					       devtype, sizeof(devtype)),
4043			  info->device_name,
4044			  info->manufacturer,
4045			  info->model_name,
4046			  info->model_number,
4047			  info->serial_number,
4048			  info->config_methods,
4049			  info->dev_capab,
4050			  info->group_capab,
4051			  info->level);
4052	if (res < 0 || res >= end - pos)
4053		return pos - buf;
4054	pos += res;
4055
4056	for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
4057	{
4058		const u8 *t;
4059		t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
4060		res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
4061				  wps_dev_type_bin2str(t, devtype,
4062						       sizeof(devtype)));
4063		if (res < 0 || res >= end - pos)
4064			return pos - buf;
4065		pos += res;
4066	}
4067
4068	ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
4069	if (ssid) {
4070		res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
4071		if (res < 0 || res >= end - pos)
4072			return pos - buf;
4073		pos += res;
4074	}
4075
4076	res = p2p_get_peer_info_txt(info, pos, end - pos);
4077	if (res < 0)
4078		return pos - buf;
4079	pos += res;
4080
4081	return pos - buf;
4082}
4083
4084
4085static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
4086				  const char *param)
4087{
4088	struct wpa_freq_range *freq = NULL, *n;
4089	unsigned int count = 0, i;
4090	const char *pos, *pos2, *pos3;
4091
4092	if (wpa_s->global->p2p == NULL)
4093		return -1;
4094
4095	/*
4096	 * param includes comma separated frequency range.
4097	 * For example: 2412-2432,2462,5000-6000
4098	 */
4099	pos = param;
4100	while (pos && pos[0]) {
4101		n = os_realloc_array(freq, count + 1,
4102				     sizeof(struct wpa_freq_range));
4103		if (n == NULL) {
4104			os_free(freq);
4105			return -1;
4106		}
4107		freq = n;
4108		freq[count].min = atoi(pos);
4109		pos2 = os_strchr(pos, '-');
4110		pos3 = os_strchr(pos, ',');
4111		if (pos2 && (!pos3 || pos2 < pos3)) {
4112			pos2++;
4113			freq[count].max = atoi(pos2);
4114		} else
4115			freq[count].max = freq[count].min;
4116		pos = pos3;
4117		if (pos)
4118			pos++;
4119		count++;
4120	}
4121
4122	for (i = 0; i < count; i++) {
4123		wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
4124			   freq[i].min, freq[i].max);
4125	}
4126
4127	os_free(wpa_s->global->p2p_disallow_freq);
4128	wpa_s->global->p2p_disallow_freq = freq;
4129	wpa_s->global->num_p2p_disallow_freq = count;
4130	wpas_p2p_update_channel_list(wpa_s);
4131	return 0;
4132}
4133
4134
4135static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
4136{
4137	char *param;
4138
4139	if (wpa_s->global->p2p == NULL)
4140		return -1;
4141
4142	param = os_strchr(cmd, ' ');
4143	if (param == NULL)
4144		return -1;
4145	*param++ = '\0';
4146
4147	if (os_strcmp(cmd, "discoverability") == 0) {
4148		p2p_set_client_discoverability(wpa_s->global->p2p,
4149					       atoi(param));
4150		return 0;
4151	}
4152
4153	if (os_strcmp(cmd, "managed") == 0) {
4154		p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
4155		return 0;
4156	}
4157
4158	if (os_strcmp(cmd, "listen_channel") == 0) {
4159		return p2p_set_listen_channel(wpa_s->global->p2p, 81,
4160					      atoi(param));
4161	}
4162
4163	if (os_strcmp(cmd, "ssid_postfix") == 0) {
4164		return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
4165					    os_strlen(param));
4166	}
4167
4168	if (os_strcmp(cmd, "noa") == 0) {
4169		char *pos;
4170		int count, start, duration;
4171		/* GO NoA parameters: count,start_offset(ms),duration(ms) */
4172		count = atoi(param);
4173		pos = os_strchr(param, ',');
4174		if (pos == NULL)
4175			return -1;
4176		pos++;
4177		start = atoi(pos);
4178		pos = os_strchr(pos, ',');
4179		if (pos == NULL)
4180			return -1;
4181		pos++;
4182		duration = atoi(pos);
4183		if (count < 0 || count > 255 || start < 0 || duration < 0)
4184			return -1;
4185		if (count == 0 && duration > 0)
4186			return -1;
4187		wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
4188			   "start=%d duration=%d", count, start, duration);
4189		return wpas_p2p_set_noa(wpa_s, count, start, duration);
4190	}
4191
4192	if (os_strcmp(cmd, "ps") == 0)
4193		return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
4194
4195	if (os_strcmp(cmd, "oppps") == 0)
4196		return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
4197
4198	if (os_strcmp(cmd, "ctwindow") == 0)
4199		return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
4200
4201	if (os_strcmp(cmd, "disabled") == 0) {
4202		wpa_s->global->p2p_disabled = atoi(param);
4203		wpa_printf(MSG_DEBUG, "P2P functionality %s",
4204			   wpa_s->global->p2p_disabled ?
4205			   "disabled" : "enabled");
4206		if (wpa_s->global->p2p_disabled) {
4207			wpas_p2p_stop_find(wpa_s);
4208			os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
4209			p2p_flush(wpa_s->global->p2p);
4210		}
4211		return 0;
4212	}
4213
4214	if (os_strcmp(cmd, "conc_pref") == 0) {
4215		if (os_strcmp(param, "sta") == 0)
4216			wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
4217		else if (os_strcmp(param, "p2p") == 0)
4218			wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
4219		else {
4220			wpa_printf(MSG_INFO, "Invalid conc_pref value");
4221			return -1;
4222		}
4223		wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
4224			   "%s", param);
4225		return 0;
4226	}
4227
4228	if (os_strcmp(cmd, "force_long_sd") == 0) {
4229		wpa_s->force_long_sd = atoi(param);
4230		return 0;
4231	}
4232
4233	if (os_strcmp(cmd, "peer_filter") == 0) {
4234		u8 addr[ETH_ALEN];
4235		if (hwaddr_aton(param, addr))
4236			return -1;
4237		p2p_set_peer_filter(wpa_s->global->p2p, addr);
4238		return 0;
4239	}
4240
4241	if (os_strcmp(cmd, "cross_connect") == 0)
4242		return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
4243
4244	if (os_strcmp(cmd, "go_apsd") == 0) {
4245		if (os_strcmp(param, "disable") == 0)
4246			wpa_s->set_ap_uapsd = 0;
4247		else {
4248			wpa_s->set_ap_uapsd = 1;
4249			wpa_s->ap_uapsd = atoi(param);
4250		}
4251		return 0;
4252	}
4253
4254	if (os_strcmp(cmd, "client_apsd") == 0) {
4255		if (os_strcmp(param, "disable") == 0)
4256			wpa_s->set_sta_uapsd = 0;
4257		else {
4258			int be, bk, vi, vo;
4259			char *pos;
4260			/* format: BE,BK,VI,VO;max SP Length */
4261			be = atoi(param);
4262			pos = os_strchr(param, ',');
4263			if (pos == NULL)
4264				return -1;
4265			pos++;
4266			bk = atoi(pos);
4267			pos = os_strchr(pos, ',');
4268			if (pos == NULL)
4269				return -1;
4270			pos++;
4271			vi = atoi(pos);
4272			pos = os_strchr(pos, ',');
4273			if (pos == NULL)
4274				return -1;
4275			pos++;
4276			vo = atoi(pos);
4277			/* ignore max SP Length for now */
4278
4279			wpa_s->set_sta_uapsd = 1;
4280			wpa_s->sta_uapsd = 0;
4281			if (be)
4282				wpa_s->sta_uapsd |= BIT(0);
4283			if (bk)
4284				wpa_s->sta_uapsd |= BIT(1);
4285			if (vi)
4286				wpa_s->sta_uapsd |= BIT(2);
4287			if (vo)
4288				wpa_s->sta_uapsd |= BIT(3);
4289		}
4290		return 0;
4291	}
4292
4293	if (os_strcmp(cmd, "disallow_freq") == 0)
4294		return p2p_ctrl_disallow_freq(wpa_s, param);
4295
4296	if (os_strcmp(cmd, "disc_int") == 0) {
4297		int min_disc_int, max_disc_int, max_disc_tu;
4298		char *pos;
4299
4300		pos = param;
4301
4302		min_disc_int = atoi(pos);
4303		pos = os_strchr(pos, ' ');
4304		if (pos == NULL)
4305			return -1;
4306		*pos++ = '\0';
4307
4308		max_disc_int = atoi(pos);
4309		pos = os_strchr(pos, ' ');
4310		if (pos == NULL)
4311			return -1;
4312		*pos++ = '\0';
4313
4314		max_disc_tu = atoi(pos);
4315
4316		return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
4317					max_disc_int, max_disc_tu);
4318	}
4319
4320	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
4321		   cmd);
4322
4323	return -1;
4324}
4325
4326
4327static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
4328{
4329	char *pos, *pos2;
4330	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
4331
4332	if (cmd[0]) {
4333		pos = os_strchr(cmd, ' ');
4334		if (pos == NULL)
4335			return -1;
4336		*pos++ = '\0';
4337		dur1 = atoi(cmd);
4338
4339		pos2 = os_strchr(pos, ' ');
4340		if (pos2)
4341			*pos2++ = '\0';
4342		int1 = atoi(pos);
4343	} else
4344		pos2 = NULL;
4345
4346	if (pos2) {
4347		pos = os_strchr(pos2, ' ');
4348		if (pos == NULL)
4349			return -1;
4350		*pos++ = '\0';
4351		dur2 = atoi(pos2);
4352		int2 = atoi(pos);
4353	}
4354
4355	return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
4356}
4357
4358
4359static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
4360{
4361	char *pos;
4362	unsigned int period = 0, interval = 0;
4363
4364	if (cmd[0]) {
4365		pos = os_strchr(cmd, ' ');
4366		if (pos == NULL)
4367			return -1;
4368		*pos++ = '\0';
4369		period = atoi(cmd);
4370		interval = atoi(pos);
4371	}
4372
4373	return wpas_p2p_ext_listen(wpa_s, period, interval);
4374}
4375
4376#endif /* CONFIG_P2P */
4377
4378
4379#ifdef CONFIG_INTERWORKING
4380static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
4381{
4382	u8 bssid[ETH_ALEN];
4383	struct wpa_bss *bss;
4384
4385	if (hwaddr_aton(dst, bssid)) {
4386		wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
4387		return -1;
4388	}
4389
4390	bss = wpa_bss_get_bssid(wpa_s, bssid);
4391	if (bss == NULL) {
4392		wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
4393			   MAC2STR(bssid));
4394		return -1;
4395	}
4396
4397	return interworking_connect(wpa_s, bss);
4398}
4399
4400
4401static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
4402{
4403	u8 dst_addr[ETH_ALEN];
4404	int used;
4405	char *pos;
4406#define MAX_ANQP_INFO_ID 100
4407	u16 id[MAX_ANQP_INFO_ID];
4408	size_t num_id = 0;
4409
4410	used = hwaddr_aton2(dst, dst_addr);
4411	if (used < 0)
4412		return -1;
4413	pos = dst + used;
4414	while (num_id < MAX_ANQP_INFO_ID) {
4415		id[num_id] = atoi(pos);
4416		if (id[num_id])
4417			num_id++;
4418		pos = os_strchr(pos + 1, ',');
4419		if (pos == NULL)
4420			break;
4421		pos++;
4422	}
4423
4424	if (num_id == 0)
4425		return -1;
4426
4427	return anqp_send_req(wpa_s, dst_addr, id, num_id);
4428}
4429
4430
4431static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
4432{
4433	u8 dst_addr[ETH_ALEN];
4434	struct wpabuf *advproto, *query = NULL;
4435	int used, ret = -1;
4436	char *pos, *end;
4437	size_t len;
4438
4439	used = hwaddr_aton2(cmd, dst_addr);
4440	if (used < 0)
4441		return -1;
4442
4443	pos = cmd + used;
4444	while (*pos == ' ')
4445		pos++;
4446
4447	/* Advertisement Protocol ID */
4448	end = os_strchr(pos, ' ');
4449	if (end)
4450		len = end - pos;
4451	else
4452		len = os_strlen(pos);
4453	if (len & 0x01)
4454		return -1;
4455	len /= 2;
4456	if (len == 0)
4457		return -1;
4458	advproto = wpabuf_alloc(len);
4459	if (advproto == NULL)
4460		return -1;
4461	if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
4462		goto fail;
4463
4464	if (end) {
4465		/* Optional Query Request */
4466		pos = end + 1;
4467		while (*pos == ' ')
4468			pos++;
4469
4470		len = os_strlen(pos);
4471		if (len) {
4472			if (len & 0x01)
4473				goto fail;
4474			len /= 2;
4475			if (len == 0)
4476				goto fail;
4477			query = wpabuf_alloc(len);
4478			if (query == NULL)
4479				goto fail;
4480			if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
4481				goto fail;
4482		}
4483	}
4484
4485	ret = gas_send_request(wpa_s, dst_addr, advproto, query);
4486
4487fail:
4488	wpabuf_free(advproto);
4489	wpabuf_free(query);
4490
4491	return ret;
4492}
4493
4494
4495static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
4496			    size_t buflen)
4497{
4498	u8 addr[ETH_ALEN];
4499	int dialog_token;
4500	int used;
4501	char *pos;
4502	size_t resp_len, start, requested_len;
4503
4504	if (!wpa_s->last_gas_resp)
4505		return -1;
4506
4507	used = hwaddr_aton2(cmd, addr);
4508	if (used < 0)
4509		return -1;
4510
4511	pos = cmd + used;
4512	while (*pos == ' ')
4513		pos++;
4514	dialog_token = atoi(pos);
4515
4516	if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
4517	    dialog_token != wpa_s->last_gas_dialog_token)
4518		return -1;
4519
4520	resp_len = wpabuf_len(wpa_s->last_gas_resp);
4521	start = 0;
4522	requested_len = resp_len;
4523
4524	pos = os_strchr(pos, ' ');
4525	if (pos) {
4526		start = atoi(pos);
4527		if (start > resp_len)
4528			return os_snprintf(buf, buflen, "FAIL-Invalid range");
4529		pos = os_strchr(pos, ',');
4530		if (pos == NULL)
4531			return -1;
4532		pos++;
4533		requested_len = atoi(pos);
4534		if (start + requested_len > resp_len)
4535			return os_snprintf(buf, buflen, "FAIL-Invalid range");
4536	}
4537
4538	if (requested_len * 2 + 1 > buflen)
4539		return os_snprintf(buf, buflen, "FAIL-Too long response");
4540
4541	return wpa_snprintf_hex(buf, buflen,
4542				wpabuf_head_u8(wpa_s->last_gas_resp) + start,
4543				requested_len);
4544}
4545#endif /* CONFIG_INTERWORKING */
4546
4547
4548#ifdef CONFIG_HS20
4549
4550static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
4551{
4552	u8 dst_addr[ETH_ALEN];
4553	int used;
4554	char *pos;
4555	u32 subtypes = 0;
4556
4557	used = hwaddr_aton2(dst, dst_addr);
4558	if (used < 0)
4559		return -1;
4560	pos = dst + used;
4561	for (;;) {
4562		int num = atoi(pos);
4563		if (num <= 0 || num > 31)
4564			return -1;
4565		subtypes |= BIT(num);
4566		pos = os_strchr(pos + 1, ',');
4567		if (pos == NULL)
4568			break;
4569		pos++;
4570	}
4571
4572	if (subtypes == 0)
4573		return -1;
4574
4575	return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
4576}
4577
4578
4579static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
4580				    const u8 *addr, const char *realm)
4581{
4582	u8 *buf;
4583	size_t rlen, len;
4584	int ret;
4585
4586	rlen = os_strlen(realm);
4587	len = 3 + rlen;
4588	buf = os_malloc(len);
4589	if (buf == NULL)
4590		return -1;
4591	buf[0] = 1; /* NAI Home Realm Count */
4592	buf[1] = 0; /* Formatted in accordance with RFC 4282 */
4593	buf[2] = rlen;
4594	os_memcpy(buf + 3, realm, rlen);
4595
4596	ret = hs20_anqp_send_req(wpa_s, addr,
4597				 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
4598				 buf, len);
4599
4600	os_free(buf);
4601
4602	return ret;
4603}
4604
4605
4606static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
4607					char *dst)
4608{
4609	struct wpa_cred *cred = wpa_s->conf->cred;
4610	u8 dst_addr[ETH_ALEN];
4611	int used;
4612	u8 *buf;
4613	size_t len;
4614	int ret;
4615
4616	used = hwaddr_aton2(dst, dst_addr);
4617	if (used < 0)
4618		return -1;
4619
4620	while (dst[used] == ' ')
4621		used++;
4622	if (os_strncmp(dst + used, "realm=", 6) == 0)
4623		return hs20_nai_home_realm_list(wpa_s, dst_addr,
4624						dst + used + 6);
4625
4626	len = os_strlen(dst + used);
4627
4628	if (len == 0 && cred && cred->realm)
4629		return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
4630
4631	if (len % 1)
4632		return -1;
4633	len /= 2;
4634	buf = os_malloc(len);
4635	if (buf == NULL)
4636		return -1;
4637	if (hexstr2bin(dst + used, buf, len) < 0) {
4638		os_free(buf);
4639		return -1;
4640	}
4641
4642	ret = hs20_anqp_send_req(wpa_s, dst_addr,
4643				 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
4644				 buf, len);
4645	os_free(buf);
4646
4647	return ret;
4648}
4649
4650#endif /* CONFIG_HS20 */
4651
4652
4653static int wpa_supplicant_ctrl_iface_sta_autoconnect(
4654	struct wpa_supplicant *wpa_s, char *cmd)
4655{
4656	wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
4657	return 0;
4658}
4659
4660
4661#ifdef CONFIG_AUTOSCAN
4662
4663static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
4664					      char *cmd)
4665{
4666	enum wpa_states state = wpa_s->wpa_state;
4667	char *new_params = NULL;
4668
4669	if (os_strlen(cmd) > 0) {
4670		new_params = os_strdup(cmd);
4671		if (new_params == NULL)
4672			return -1;
4673	}
4674
4675	os_free(wpa_s->conf->autoscan);
4676	wpa_s->conf->autoscan = new_params;
4677
4678	if (wpa_s->conf->autoscan == NULL)
4679		autoscan_deinit(wpa_s);
4680	else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
4681		autoscan_init(wpa_s, 1);
4682	else if (state == WPA_SCANNING)
4683		wpa_supplicant_reinit_autoscan(wpa_s);
4684
4685	return 0;
4686}
4687
4688#endif /* CONFIG_AUTOSCAN */
4689
4690
4691#ifdef CONFIG_WNM
4692
4693static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
4694{
4695	int enter;
4696	int intval = 0;
4697	char *pos;
4698	int ret;
4699	struct wpabuf *tfs_req = NULL;
4700
4701	if (os_strncmp(cmd, "enter", 5) == 0)
4702		enter = 1;
4703	else if (os_strncmp(cmd, "exit", 4) == 0)
4704		enter = 0;
4705	else
4706		return -1;
4707
4708	pos = os_strstr(cmd, " interval=");
4709	if (pos)
4710		intval = atoi(pos + 10);
4711
4712	pos = os_strstr(cmd, " tfs_req=");
4713	if (pos) {
4714		char *end;
4715		size_t len;
4716		pos += 9;
4717		end = os_strchr(pos, ' ');
4718		if (end)
4719			len = end - pos;
4720		else
4721			len = os_strlen(pos);
4722		if (len & 1)
4723			return -1;
4724		len /= 2;
4725		tfs_req = wpabuf_alloc(len);
4726		if (tfs_req == NULL)
4727			return -1;
4728		if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
4729			wpabuf_free(tfs_req);
4730			return -1;
4731		}
4732	}
4733
4734	ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
4735					   WNM_SLEEP_MODE_EXIT, intval,
4736					   tfs_req);
4737	wpabuf_free(tfs_req);
4738
4739	return ret;
4740}
4741
4742#endif /* CONFIG_WNM */
4743
4744
4745static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
4746				      size_t buflen)
4747{
4748	struct wpa_signal_info si;
4749	int ret;
4750
4751	ret = wpa_drv_signal_poll(wpa_s, &si);
4752	if (ret)
4753		return -1;
4754
4755	ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
4756			  "NOISE=%d\nFREQUENCY=%u\n",
4757			  si.current_signal, si.current_txrate / 1000,
4758			  si.current_noise, si.frequency);
4759	if (ret < 0 || (unsigned int) ret > buflen)
4760		return -1;
4761	return ret;
4762}
4763
4764
4765static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
4766				      size_t buflen)
4767{
4768	struct hostap_sta_driver_data sta;
4769	int ret;
4770
4771	ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
4772	if (ret)
4773		return -1;
4774
4775	ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
4776			  sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
4777	if (ret < 0 || (size_t) ret > buflen)
4778		return -1;
4779	return ret;
4780}
4781
4782
4783char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
4784					 char *buf, size_t *resp_len)
4785{
4786	char *reply;
4787	const int reply_size = 4096;
4788	int ctrl_rsp = 0;
4789	int reply_len;
4790
4791	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
4792	    os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
4793	    os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
4794	    os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
4795		wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
4796				      (const u8 *) buf, os_strlen(buf));
4797	} else {
4798		int level = MSG_DEBUG;
4799		if (os_strcmp(buf, "PING") == 0)
4800			level = MSG_EXCESSIVE;
4801		wpa_hexdump_ascii(level, "RX ctrl_iface",
4802				  (const u8 *) buf, os_strlen(buf));
4803		wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
4804	}
4805
4806	reply = os_malloc(reply_size);
4807	if (reply == NULL) {
4808		*resp_len = 1;
4809		return NULL;
4810	}
4811
4812	os_memcpy(reply, "OK\n", 3);
4813	reply_len = 3;
4814
4815	if (os_strcmp(buf, "PING") == 0) {
4816		os_memcpy(reply, "PONG\n", 5);
4817		reply_len = 5;
4818	} else if (os_strcmp(buf, "IFNAME") == 0) {
4819		reply_len = os_strlen(wpa_s->ifname);
4820		os_memcpy(reply, wpa_s->ifname, reply_len);
4821	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
4822		if (wpa_debug_reopen_file() < 0)
4823			reply_len = -1;
4824	} else if (os_strncmp(buf, "NOTE ", 5) == 0) {
4825		wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
4826	} else if (os_strcmp(buf, "MIB") == 0) {
4827		reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
4828		if (reply_len >= 0) {
4829			int res;
4830			res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
4831					       reply_size - reply_len);
4832			if (res < 0)
4833				reply_len = -1;
4834			else
4835				reply_len += res;
4836		}
4837	} else if (os_strncmp(buf, "STATUS", 6) == 0) {
4838		reply_len = wpa_supplicant_ctrl_iface_status(
4839			wpa_s, buf + 6, reply, reply_size);
4840	} else if (os_strcmp(buf, "PMKSA") == 0) {
4841		reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
4842						    reply_size);
4843	} else if (os_strncmp(buf, "SET ", 4) == 0) {
4844		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
4845			reply_len = -1;
4846	} else if (os_strncmp(buf, "GET ", 4) == 0) {
4847		reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
4848							  reply, reply_size);
4849	} else if (os_strcmp(buf, "LOGON") == 0) {
4850		eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
4851	} else if (os_strcmp(buf, "LOGOFF") == 0) {
4852		eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
4853	} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
4854		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4855			reply_len = -1;
4856		else
4857			wpas_request_connection(wpa_s);
4858	} else if (os_strcmp(buf, "RECONNECT") == 0) {
4859		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
4860			reply_len = -1;
4861		else if (wpa_s->disconnected)
4862			wpas_request_connection(wpa_s);
4863#ifdef IEEE8021X_EAPOL
4864	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
4865		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
4866			reply_len = -1;
4867#endif /* IEEE8021X_EAPOL */
4868#ifdef CONFIG_PEERKEY
4869	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
4870		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
4871			reply_len = -1;
4872#endif /* CONFIG_PEERKEY */
4873#ifdef CONFIG_IEEE80211R
4874	} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
4875		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
4876			reply_len = -1;
4877#endif /* CONFIG_IEEE80211R */
4878#ifdef CONFIG_WPS
4879	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
4880		int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
4881		if (res == -2) {
4882			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4883			reply_len = 17;
4884		} else if (res)
4885			reply_len = -1;
4886	} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
4887		int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
4888		if (res == -2) {
4889			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4890			reply_len = 17;
4891		} else if (res)
4892			reply_len = -1;
4893	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
4894		reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
4895							      reply,
4896							      reply_size);
4897	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
4898		reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
4899			wpa_s, buf + 14, reply, reply_size);
4900	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
4901		if (wpas_wps_cancel(wpa_s))
4902			reply_len = -1;
4903#ifdef CONFIG_WPS_NFC
4904	} else if (os_strcmp(buf, "WPS_NFC") == 0) {
4905		if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
4906			reply_len = -1;
4907	} else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
4908		if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
4909			reply_len = -1;
4910	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
4911		reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
4912			wpa_s, buf + 14, reply, reply_size);
4913	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
4914		if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
4915							       buf + 17))
4916			reply_len = -1;
4917	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
4918		reply_len = wpas_ctrl_nfc_get_handover_req(
4919			wpa_s, buf + 21, reply, reply_size);
4920	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
4921		reply_len = wpas_ctrl_nfc_get_handover_sel(
4922			wpa_s, buf + 21, reply, reply_size);
4923	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
4924		reply_len = wpas_ctrl_nfc_rx_handover_req(
4925			wpa_s, buf + 20, reply, reply_size);
4926	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
4927		if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
4928			reply_len = -1;
4929#endif /* CONFIG_WPS_NFC */
4930	} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
4931		if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
4932			reply_len = -1;
4933#ifdef CONFIG_AP
4934	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
4935		reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
4936			wpa_s, buf + 11, reply, reply_size);
4937#endif /* CONFIG_AP */
4938#ifdef CONFIG_WPS_ER
4939	} else if (os_strcmp(buf, "WPS_ER_START") == 0) {
4940		if (wpas_wps_er_start(wpa_s, NULL))
4941			reply_len = -1;
4942	} else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
4943		if (wpas_wps_er_start(wpa_s, buf + 13))
4944			reply_len = -1;
4945	} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
4946		if (wpas_wps_er_stop(wpa_s))
4947			reply_len = -1;
4948	} else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
4949		if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
4950			reply_len = -1;
4951	} else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
4952		int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
4953		if (ret == -2) {
4954			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
4955			reply_len = 17;
4956		} else if (ret == -3) {
4957			os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
4958			reply_len = 18;
4959		} else if (ret == -4) {
4960			os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
4961			reply_len = 20;
4962		} else if (ret)
4963			reply_len = -1;
4964	} else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
4965		if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
4966			reply_len = -1;
4967	} else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
4968		if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
4969								buf + 18))
4970			reply_len = -1;
4971	} else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
4972		if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
4973			reply_len = -1;
4974#ifdef CONFIG_WPS_NFC
4975	} else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
4976		reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
4977			wpa_s, buf + 24, reply, reply_size);
4978#endif /* CONFIG_WPS_NFC */
4979#endif /* CONFIG_WPS_ER */
4980#endif /* CONFIG_WPS */
4981#ifdef CONFIG_IBSS_RSN
4982	} else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
4983		if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
4984			reply_len = -1;
4985#endif /* CONFIG_IBSS_RSN */
4986#ifdef CONFIG_P2P
4987	} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
4988		if (p2p_ctrl_find(wpa_s, buf + 9))
4989			reply_len = -1;
4990	} else if (os_strcmp(buf, "P2P_FIND") == 0) {
4991		if (p2p_ctrl_find(wpa_s, ""))
4992			reply_len = -1;
4993	} else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
4994		wpas_p2p_stop_find(wpa_s);
4995	} else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
4996		reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
4997					     reply_size);
4998	} else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
4999		if (p2p_ctrl_listen(wpa_s, buf + 11))
5000			reply_len = -1;
5001	} else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
5002		if (p2p_ctrl_listen(wpa_s, ""))
5003			reply_len = -1;
5004	} else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
5005		if (wpas_p2p_group_remove(wpa_s, buf + 17))
5006			reply_len = -1;
5007	} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
5008		if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
5009			reply_len = -1;
5010	} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
5011		if (p2p_ctrl_group_add(wpa_s, buf + 14))
5012			reply_len = -1;
5013	} else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
5014		if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
5015			reply_len = -1;
5016	} else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
5017		reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
5018	} else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
5019		reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
5020						   reply_size);
5021	} else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
5022		if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
5023			reply_len = -1;
5024	} else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
5025		if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
5026			reply_len = -1;
5027	} else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
5028		wpas_p2p_sd_service_update(wpa_s);
5029	} else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
5030		if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
5031			reply_len = -1;
5032	} else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
5033		wpas_p2p_service_flush(wpa_s);
5034	} else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
5035		if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
5036			reply_len = -1;
5037	} else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
5038		if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
5039			reply_len = -1;
5040	} else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
5041		if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
5042			reply_len = -1;
5043	} else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
5044		if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
5045			reply_len = -1;
5046	} else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
5047		reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
5048					      reply_size);
5049	} else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
5050		if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
5051			reply_len = -1;
5052	} else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
5053		os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
5054		wpa_s->force_long_sd = 0;
5055		if (wpa_s->global->p2p)
5056			p2p_flush(wpa_s->global->p2p);
5057	} else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
5058		if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
5059			reply_len = -1;
5060	} else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
5061		if (wpas_p2p_cancel(wpa_s))
5062			reply_len = -1;
5063	} else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
5064		if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
5065			reply_len = -1;
5066	} else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
5067		if (p2p_ctrl_presence_req(wpa_s, "") < 0)
5068			reply_len = -1;
5069	} else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
5070		if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
5071			reply_len = -1;
5072	} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
5073		if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
5074			reply_len = -1;
5075#endif /* CONFIG_P2P */
5076#ifdef CONFIG_WIFI_DISPLAY
5077	} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
5078		if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
5079			reply_len = -1;
5080	} else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
5081		reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
5082						     reply, reply_size);
5083#endif /* CONFIG_WIFI_DISPLAY */
5084#ifdef CONFIG_INTERWORKING
5085	} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
5086		if (interworking_fetch_anqp(wpa_s) < 0)
5087			reply_len = -1;
5088	} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
5089		interworking_stop_fetch_anqp(wpa_s);
5090	} else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
5091		if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
5092					NULL) < 0)
5093			reply_len = -1;
5094	} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
5095		if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
5096			reply_len = -1;
5097	} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
5098		if (get_anqp(wpa_s, buf + 9) < 0)
5099			reply_len = -1;
5100	} else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
5101		if (gas_request(wpa_s, buf + 12) < 0)
5102			reply_len = -1;
5103	} else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
5104		reply_len = gas_response_get(wpa_s, buf + 17, reply,
5105					     reply_size);
5106#endif /* CONFIG_INTERWORKING */
5107#ifdef CONFIG_HS20
5108	} else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
5109		if (get_hs20_anqp(wpa_s, buf + 14) < 0)
5110			reply_len = -1;
5111	} else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
5112		if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
5113			reply_len = -1;
5114#endif /* CONFIG_HS20 */
5115	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
5116	{
5117		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
5118			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
5119			reply_len = -1;
5120		else
5121			ctrl_rsp = 1;
5122	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
5123		if (wpa_supplicant_reload_configuration(wpa_s))
5124			reply_len = -1;
5125	} else if (os_strcmp(buf, "TERMINATE") == 0) {
5126		wpa_supplicant_terminate_proc(wpa_s->global);
5127	} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
5128		if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
5129			reply_len = -1;
5130	} else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
5131		reply_len = wpa_supplicant_ctrl_iface_blacklist(
5132			wpa_s, buf + 9, reply, reply_size);
5133	} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
5134		reply_len = wpa_supplicant_ctrl_iface_log_level(
5135			wpa_s, buf + 9, reply, reply_size);
5136	} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
5137		reply_len = wpa_supplicant_ctrl_iface_list_networks(
5138			wpa_s, reply, reply_size);
5139	} else if (os_strcmp(buf, "DISCONNECT") == 0) {
5140#ifdef CONFIG_SME
5141		wpa_s->sme.prev_bssid_set = 0;
5142#endif /* CONFIG_SME */
5143		wpa_s->reassociate = 0;
5144		wpa_s->disconnected = 1;
5145		wpa_supplicant_cancel_sched_scan(wpa_s);
5146		wpa_supplicant_cancel_scan(wpa_s);
5147		wpa_supplicant_deauthenticate(wpa_s,
5148					      WLAN_REASON_DEAUTH_LEAVING);
5149	} else if (os_strcmp(buf, "SCAN") == 0) {
5150		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
5151			reply_len = -1;
5152		else {
5153			if (!wpa_s->sched_scanning && !wpa_s->scanning &&
5154			    ((wpa_s->wpa_state <= WPA_SCANNING) ||
5155			     (wpa_s->wpa_state == WPA_COMPLETED))) {
5156				wpa_s->normal_scans = 0;
5157				wpa_s->scan_req = MANUAL_SCAN_REQ;
5158				wpa_supplicant_req_scan(wpa_s, 0, 0);
5159			} else if (wpa_s->sched_scanning) {
5160				wpa_printf(MSG_DEBUG, "Stop ongoing "
5161					   "sched_scan to allow requested "
5162					   "full scan to proceed");
5163				wpa_supplicant_cancel_sched_scan(wpa_s);
5164				wpa_s->scan_req = MANUAL_SCAN_REQ;
5165				wpa_supplicant_req_scan(wpa_s, 0, 0);
5166			} else {
5167				wpa_printf(MSG_DEBUG, "Ongoing scan action - "
5168					   "reject new request");
5169				reply_len = os_snprintf(reply, reply_size,
5170							"FAIL-BUSY\n");
5171			}
5172		}
5173	} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
5174		reply_len = wpa_supplicant_ctrl_iface_scan_results(
5175			wpa_s, reply, reply_size);
5176	} else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
5177		if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
5178			reply_len = -1;
5179	} else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
5180		if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
5181			reply_len = -1;
5182	} else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
5183		if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
5184			reply_len = -1;
5185	} else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
5186		reply_len = wpa_supplicant_ctrl_iface_add_network(
5187			wpa_s, reply, reply_size);
5188	} else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
5189		if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
5190			reply_len = -1;
5191	} else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
5192		if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
5193			reply_len = -1;
5194	} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
5195		reply_len = wpa_supplicant_ctrl_iface_get_network(
5196			wpa_s, buf + 12, reply, reply_size);
5197	} else if (os_strcmp(buf, "LIST_CREDS") == 0) {
5198		reply_len = wpa_supplicant_ctrl_iface_list_creds(
5199			wpa_s, reply, reply_size);
5200	} else if (os_strcmp(buf, "ADD_CRED") == 0) {
5201		reply_len = wpa_supplicant_ctrl_iface_add_cred(
5202			wpa_s, reply, reply_size);
5203	} else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
5204		if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
5205			reply_len = -1;
5206	} else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
5207		if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
5208			reply_len = -1;
5209#ifndef CONFIG_NO_CONFIG_WRITE
5210	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
5211		if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
5212			reply_len = -1;
5213#endif /* CONFIG_NO_CONFIG_WRITE */
5214	} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
5215		reply_len = wpa_supplicant_ctrl_iface_get_capability(
5216			wpa_s, buf + 15, reply, reply_size);
5217	} else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
5218		if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
5219			reply_len = -1;
5220	} else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
5221		if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
5222			reply_len = -1;
5223	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
5224		reply_len = wpa_supplicant_global_iface_list(
5225			wpa_s->global, reply, reply_size);
5226	} else if (os_strcmp(buf, "INTERFACES") == 0) {
5227		reply_len = wpa_supplicant_global_iface_interfaces(
5228			wpa_s->global, reply, reply_size);
5229	} else if (os_strncmp(buf, "BSS ", 4) == 0) {
5230		reply_len = wpa_supplicant_ctrl_iface_bss(
5231			wpa_s, buf + 4, reply, reply_size);
5232#ifdef CONFIG_AP
5233	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
5234		reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
5235	} else if (os_strncmp(buf, "STA ", 4) == 0) {
5236		reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
5237					      reply_size);
5238	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
5239		reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
5240						   reply_size);
5241	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
5242		if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
5243			reply_len = -1;
5244	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
5245		if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
5246			reply_len = -1;
5247#endif /* CONFIG_AP */
5248	} else if (os_strcmp(buf, "SUSPEND") == 0) {
5249		wpas_notify_suspend(wpa_s->global);
5250	} else if (os_strcmp(buf, "RESUME") == 0) {
5251		wpas_notify_resume(wpa_s->global);
5252	} else if (os_strcmp(buf, "DROP_SA") == 0) {
5253		wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
5254	} else if (os_strncmp(buf, "ROAM ", 5) == 0) {
5255		if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
5256			reply_len = -1;
5257	} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
5258		if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
5259			reply_len = -1;
5260	} else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
5261		if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
5262			reply_len = -1;
5263	} else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
5264		if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
5265							       buf + 17))
5266			reply_len = -1;
5267	} else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
5268		if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
5269			reply_len = -1;
5270#ifdef CONFIG_TDLS
5271	} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
5272		if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
5273			reply_len = -1;
5274	} else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
5275		if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
5276			reply_len = -1;
5277	} else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
5278		if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
5279			reply_len = -1;
5280#endif /* CONFIG_TDLS */
5281	} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
5282		reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
5283						       reply_size);
5284	} else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
5285		reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
5286						       reply_size);
5287#ifdef CONFIG_AUTOSCAN
5288	} else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
5289		if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
5290			reply_len = -1;
5291#endif /* CONFIG_AUTOSCAN */
5292	} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
5293		pmksa_cache_clear_current(wpa_s->wpa);
5294		eapol_sm_request_reauth(wpa_s->eapol);
5295#ifdef CONFIG_WNM
5296	} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
5297		if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
5298			reply_len = -1;
5299#endif /* CONFIG_WNM */
5300	} else {
5301		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
5302		reply_len = 16;
5303	}
5304
5305	if (reply_len < 0) {
5306		os_memcpy(reply, "FAIL\n", 5);
5307		reply_len = 5;
5308	}
5309
5310	if (ctrl_rsp)
5311		eapol_sm_notify_ctrl_response(wpa_s->eapol);
5312
5313	*resp_len = reply_len;
5314	return reply;
5315}
5316
5317
5318static int wpa_supplicant_global_iface_add(struct wpa_global *global,
5319					   char *cmd)
5320{
5321	struct wpa_interface iface;
5322	char *pos;
5323
5324	/*
5325	 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
5326	 * TAB<bridge_ifname>
5327	 */
5328	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
5329
5330	os_memset(&iface, 0, sizeof(iface));
5331
5332	do {
5333		iface.ifname = pos = cmd;
5334		pos = os_strchr(pos, '\t');
5335		if (pos)
5336			*pos++ = '\0';
5337		if (iface.ifname[0] == '\0')
5338			return -1;
5339		if (pos == NULL)
5340			break;
5341
5342		iface.confname = pos;
5343		pos = os_strchr(pos, '\t');
5344		if (pos)
5345			*pos++ = '\0';
5346		if (iface.confname[0] == '\0')
5347			iface.confname = NULL;
5348		if (pos == NULL)
5349			break;
5350
5351		iface.driver = pos;
5352		pos = os_strchr(pos, '\t');
5353		if (pos)
5354			*pos++ = '\0';
5355		if (iface.driver[0] == '\0')
5356			iface.driver = NULL;
5357		if (pos == NULL)
5358			break;
5359
5360		iface.ctrl_interface = pos;
5361		pos = os_strchr(pos, '\t');
5362		if (pos)
5363			*pos++ = '\0';
5364		if (iface.ctrl_interface[0] == '\0')
5365			iface.ctrl_interface = NULL;
5366		if (pos == NULL)
5367			break;
5368
5369		iface.driver_param = pos;
5370		pos = os_strchr(pos, '\t');
5371		if (pos)
5372			*pos++ = '\0';
5373		if (iface.driver_param[0] == '\0')
5374			iface.driver_param = NULL;
5375		if (pos == NULL)
5376			break;
5377
5378		iface.bridge_ifname = pos;
5379		pos = os_strchr(pos, '\t');
5380		if (pos)
5381			*pos++ = '\0';
5382		if (iface.bridge_ifname[0] == '\0')
5383			iface.bridge_ifname = NULL;
5384		if (pos == NULL)
5385			break;
5386	} while (0);
5387
5388	if (wpa_supplicant_get_iface(global, iface.ifname))
5389		return -1;
5390
5391	return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
5392}
5393
5394
5395static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
5396					      char *cmd)
5397{
5398	struct wpa_supplicant *wpa_s;
5399
5400	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
5401
5402	wpa_s = wpa_supplicant_get_iface(global, cmd);
5403	if (wpa_s == NULL)
5404		return -1;
5405	return wpa_supplicant_remove_iface(global, wpa_s, 0);
5406}
5407
5408
5409static void wpa_free_iface_info(struct wpa_interface_info *iface)
5410{
5411	struct wpa_interface_info *prev;
5412
5413	while (iface) {
5414		prev = iface;
5415		iface = iface->next;
5416
5417		os_free(prev->ifname);
5418		os_free(prev->desc);
5419		os_free(prev);
5420	}
5421}
5422
5423
5424static int wpa_supplicant_global_iface_list(struct wpa_global *global,
5425					    char *buf, int len)
5426{
5427	int i, res;
5428	struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
5429	char *pos, *end;
5430
5431	for (i = 0; wpa_drivers[i]; i++) {
5432		struct wpa_driver_ops *drv = wpa_drivers[i];
5433		if (drv->get_interfaces == NULL)
5434			continue;
5435		tmp = drv->get_interfaces(global->drv_priv[i]);
5436		if (tmp == NULL)
5437			continue;
5438
5439		if (last == NULL)
5440			iface = last = tmp;
5441		else
5442			last->next = tmp;
5443		while (last->next)
5444			last = last->next;
5445	}
5446
5447	pos = buf;
5448	end = buf + len;
5449	for (tmp = iface; tmp; tmp = tmp->next) {
5450		res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
5451				  tmp->drv_name, tmp->ifname,
5452				  tmp->desc ? tmp->desc : "");
5453		if (res < 0 || res >= end - pos) {
5454			*pos = '\0';
5455			break;
5456		}
5457		pos += res;
5458	}
5459
5460	wpa_free_iface_info(iface);
5461
5462	return pos - buf;
5463}
5464
5465
5466static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
5467						  char *buf, int len)
5468{
5469	int res;
5470	char *pos, *end;
5471	struct wpa_supplicant *wpa_s;
5472
5473	wpa_s = global->ifaces;
5474	pos = buf;
5475	end = buf + len;
5476
5477	while (wpa_s) {
5478		res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
5479		if (res < 0 || res >= end - pos) {
5480			*pos = '\0';
5481			break;
5482		}
5483		pos += res;
5484		wpa_s = wpa_s->next;
5485	}
5486	return pos - buf;
5487}
5488
5489
5490char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
5491						char *buf, size_t *resp_len)
5492{
5493	char *reply;
5494	const int reply_size = 2048;
5495	int reply_len;
5496	int level = MSG_DEBUG;
5497
5498	if (os_strcmp(buf, "PING") == 0)
5499		level = MSG_EXCESSIVE;
5500	wpa_hexdump_ascii(level, "RX global ctrl_iface",
5501			  (const u8 *) buf, os_strlen(buf));
5502
5503	reply = os_malloc(reply_size);
5504	if (reply == NULL) {
5505		*resp_len = 1;
5506		return NULL;
5507	}
5508
5509	os_memcpy(reply, "OK\n", 3);
5510	reply_len = 3;
5511
5512	if (os_strcmp(buf, "PING") == 0) {
5513		os_memcpy(reply, "PONG\n", 5);
5514		reply_len = 5;
5515	} else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
5516		if (wpa_supplicant_global_iface_add(global, buf + 14))
5517			reply_len = -1;
5518	} else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
5519		if (wpa_supplicant_global_iface_remove(global, buf + 17))
5520			reply_len = -1;
5521	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
5522		reply_len = wpa_supplicant_global_iface_list(
5523			global, reply, reply_size);
5524	} else if (os_strcmp(buf, "INTERFACES") == 0) {
5525		reply_len = wpa_supplicant_global_iface_interfaces(
5526			global, reply, reply_size);
5527	} else if (os_strcmp(buf, "TERMINATE") == 0) {
5528		wpa_supplicant_terminate_proc(global);
5529	} else if (os_strcmp(buf, "SUSPEND") == 0) {
5530		wpas_notify_suspend(global);
5531	} else if (os_strcmp(buf, "RESUME") == 0) {
5532		wpas_notify_resume(global);
5533	} else {
5534		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
5535		reply_len = 16;
5536	}
5537
5538	if (reply_len < 0) {
5539		os_memcpy(reply, "FAIL\n", 5);
5540		reply_len = 5;
5541	}
5542
5543	*resp_len = reply_len;
5544	return reply;
5545}
5546