ctrl_iface.c revision 337817
1114402Sru/*
2151497Sru * WPA Supplicant / Control interface (shared code for all backends)
3151497Sru * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
4114402Sru *
5114402Sru * This software may be distributed under the terms of the BSD license.
6114402Sru * See README for more details.
7114402Sru */
8114402Sru
9114402Sru#include "utils/includes.h"
10114402Sru#ifdef CONFIG_TESTING_OPTIONS
11114402Sru#include <net/ethernet.h>
12114402Sru#include <netinet/ip.h>
13114402Sru#endif /* CONFIG_TESTING_OPTIONS */
14114402Sru
15114402Sru#include "utils/common.h"
16114402Sru#include "utils/eloop.h"
17114402Sru#include "utils/uuid.h"
18114402Sru#include "utils/module_tests.h"
19114402Sru#include "common/version.h"
20114402Sru#include "common/ieee802_11_defs.h"
21114402Sru#include "common/ieee802_11_common.h"
22114402Sru#include "common/wpa_ctrl.h"
23114402Sru#include "crypto/tls.h"
24114402Sru#include "ap/hostapd.h"
25151497Sru#include "eap_peer/eap.h"
26114402Sru#include "eapol_supp/eapol_supp_sm.h"
27114402Sru#include "rsn_supp/wpa.h"
28114402Sru#include "rsn_supp/preauth.h"
29114402Sru#include "rsn_supp/pmksa_cache.h"
30114402Sru#include "l2_packet/l2_packet.h"
31114402Sru#include "wps/wps.h"
32114402Sru#include "fst/fst.h"
33114402Sru#include "fst/fst_ctrl_iface.h"
34114402Sru#include "config.h"
35114402Sru#include "wpa_supplicant_i.h"
36114402Sru#include "driver_i.h"
37114402Sru#include "wps_supplicant.h"
38114402Sru#include "ibss_rsn.h"
39114402Sru#include "ap.h"
40114402Sru#include "p2p_supplicant.h"
41114402Sru#include "p2p/p2p.h"
42151497Sru#include "hs20_supplicant.h"
43114402Sru#include "wifi_display.h"
44114402Sru#include "notify.h"
45114402Sru#include "bss.h"
46114402Sru#include "scan.h"
47114402Sru#include "ctrl_iface.h"
48114402Sru#include "interworking.h"
49114402Sru#include "blacklist.h"
50114402Sru#include "autoscan.h"
51114402Sru#include "wnm_sta.h"
52114402Sru#include "offchannel.h"
53114402Sru#include "drivers/driver.h"
54114402Sru#include "mesh.h"
55151497Sru
56114402Srustatic int wpa_supplicant_global_iface_list(struct wpa_global *global,
57114402Sru					    char *buf, int len);
58114402Srustatic int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
59114402Sru						  const char *input,
60114402Sru						  char *buf, int len);
61114402Srustatic int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s,
62114402Sru					char *val);
63114402Sru
64151497Srustatic int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
65114402Sru{
66114402Sru	char *pos;
67114402Sru	u8 addr[ETH_ALEN], *filter = NULL, *n;
68114402Sru	size_t count = 0;
69114402Sru
70114402Sru	pos = val;
71114402Sru	while (pos) {
72114402Sru		if (*pos == '\0')
73114402Sru			break;
74114402Sru		if (hwaddr_aton(pos, addr)) {
75114402Sru			os_free(filter);
76114402Sru			return -1;
77114402Sru		}
78114402Sru		n = os_realloc_array(filter, count + 1, ETH_ALEN);
79114402Sru		if (n == NULL) {
80114402Sru			os_free(filter);
81114402Sru			return -1;
82151497Sru		}
83151497Sru		filter = n;
84151497Sru		os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
85151497Sru		count++;
86151497Sru
87151497Sru		pos = os_strchr(pos, ' ');
88151497Sru		if (pos)
89151497Sru			pos++;
90151497Sru	}
91151497Sru
92114402Sru	wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
93114402Sru	os_free(wpa_s->bssid_filter);
94114402Sru	wpa_s->bssid_filter = filter;
95114402Sru	wpa_s->bssid_filter_count = count;
96114402Sru
97114402Sru	return 0;
98114402Sru}
99114402Sru
100114402Sru
101114402Srustatic int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
102114402Sru{
103114402Sru	char *pos;
104114402Sru	u8 addr[ETH_ALEN], *bssid = NULL, *n;
105114402Sru	struct wpa_ssid_value *ssid = NULL, *ns;
106114402Sru	size_t count = 0, ssid_count = 0;
107114402Sru	struct wpa_ssid *c;
108114402Sru
109114402Sru	/*
110114402Sru	 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
111114402Sru	 * SSID_SPEC ::= ssid <SSID_HEX>
112114402Sru	 * BSSID_SPEC ::= bssid <BSSID_HEX>
113114402Sru	 */
114114402Sru
115114402Sru	pos = val;
116114402Sru	while (pos) {
117114402Sru		if (*pos == '\0')
118114402Sru			break;
119114402Sru		if (os_strncmp(pos, "bssid ", 6) == 0) {
120114402Sru			int res;
121114402Sru			pos += 6;
122114402Sru			res = hwaddr_aton2(pos, addr);
123151497Sru			if (res < 0) {
124114402Sru				os_free(ssid);
125114402Sru				os_free(bssid);
126114402Sru				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
127114402Sru					   "BSSID value '%s'", pos);
128114402Sru				return -1;
129114402Sru			}
130114402Sru			pos += res;
131114402Sru			n = os_realloc_array(bssid, count + 1, ETH_ALEN);
132151497Sru			if (n == NULL) {
133114402Sru				os_free(ssid);
134114402Sru				os_free(bssid);
135114402Sru				return -1;
136114402Sru			}
137114402Sru			bssid = n;
138114402Sru			os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
139114402Sru			count++;
140114402Sru		} else if (os_strncmp(pos, "ssid ", 5) == 0) {
141114402Sru			char *end;
142151497Sru			pos += 5;
143151497Sru
144151497Sru			end = pos;
145114402Sru			while (*end) {
146114402Sru				if (*end == '\0' || *end == ' ')
147114402Sru					break;
148114402Sru				end++;
149114402Sru			}
150114402Sru
151114402Sru			ns = os_realloc_array(ssid, ssid_count + 1,
152114402Sru					      sizeof(struct wpa_ssid_value));
153114402Sru			if (ns == NULL) {
154151497Sru				os_free(ssid);
155151497Sru				os_free(bssid);
156114402Sru				return -1;
157114402Sru			}
158114402Sru			ssid = ns;
159114402Sru
160114402Sru			if ((end - pos) & 0x01 ||
161151497Sru			    end - pos > 2 * SSID_MAX_LEN ||
162151497Sru			    hexstr2bin(pos, ssid[ssid_count].ssid,
163151497Sru				       (end - pos) / 2) < 0) {
164151497Sru				os_free(ssid);
165151497Sru				os_free(bssid);
166151497Sru				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
167151497Sru					   "SSID value '%s'", pos);
168151497Sru				return -1;
169151497Sru			}
170151497Sru			ssid[ssid_count].ssid_len = (end - pos) / 2;
171151497Sru			wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
172114402Sru					  ssid[ssid_count].ssid,
173151497Sru					  ssid[ssid_count].ssid_len);
174151497Sru			ssid_count++;
175151497Sru			pos = end;
176114402Sru		} else {
177114402Sru			wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
178114402Sru				   "'%s'", pos);
179114402Sru			os_free(ssid);
180114402Sru			os_free(bssid);
181114402Sru			return -1;
182114402Sru		}
183151497Sru
184114402Sru		pos = os_strchr(pos, ' ');
185114402Sru		if (pos)
186114402Sru			pos++;
187114402Sru	}
188114402Sru
189114402Sru	wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
190114402Sru	os_free(wpa_s->disallow_aps_bssid);
191114402Sru	wpa_s->disallow_aps_bssid = bssid;
192114402Sru	wpa_s->disallow_aps_bssid_count = count;
193151497Sru
194151497Sru	wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
195151497Sru	os_free(wpa_s->disallow_aps_ssid);
196151497Sru	wpa_s->disallow_aps_ssid = ssid;
197114402Sru	wpa_s->disallow_aps_ssid_count = ssid_count;
198114402Sru
199114402Sru	if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
200114402Sru		return 0;
201114402Sru
202114402Sru	c = wpa_s->current_ssid;
203114402Sru	if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
204114402Sru		return 0;
205114402Sru
206114402Sru	if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
207114402Sru	    !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
208114402Sru		return 0;
209114402Sru
210114402Sru	wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
211114402Sru		   "because current AP was marked disallowed");
212114402Sru
213114402Sru#ifdef CONFIG_SME
214151497Sru	wpa_s->sme.prev_bssid_set = 0;
215114402Sru#endif /* CONFIG_SME */
216114402Sru	wpa_s->reassociate = 1;
217114402Sru	wpa_s->own_disconnect_req = 1;
218114402Sru	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
219114402Sru	wpa_supplicant_req_scan(wpa_s, 0, 0);
220114402Sru
221114402Sru	return 0;
222114402Sru}
223114402Sru
224151497Sru
225114402Sru#ifndef CONFIG_NO_CONFIG_BLOBS
226114402Srustatic int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos)
227114402Sru{
228114402Sru	char *name = pos;
229114402Sru	struct wpa_config_blob *blob;
230114402Sru	size_t len;
231114402Sru
232114402Sru	pos = os_strchr(pos, ' ');
233114402Sru	if (pos == NULL)
234114402Sru		return -1;
235151497Sru	*pos++ = '\0';
236151497Sru	len = os_strlen(pos);
237151497Sru	if (len & 1)
238151497Sru		return -1;
239151497Sru
240151497Sru	wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name);
241151497Sru	blob = os_zalloc(sizeof(*blob));
242151497Sru	if (blob == NULL)
243151497Sru		return -1;
244151497Sru	blob->name = os_strdup(name);
245151497Sru	blob->data = os_malloc(len / 2);
246151497Sru	if (blob->name == NULL || blob->data == NULL) {
247151497Sru		wpa_config_free_blob(blob);
248151497Sru		return -1;
249151497Sru	}
250151497Sru
251151497Sru	if (hexstr2bin(pos, blob->data, len / 2) < 0) {
252151497Sru		wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data");
253151497Sru		wpa_config_free_blob(blob);
254151497Sru		return -1;
255151497Sru	}
256151497Sru	blob->len = len / 2;
257151497Sru
258151497Sru	wpa_config_set_blob(wpa_s->conf, blob);
259151497Sru
260151497Sru	return 0;
261151497Sru}
262151497Sru#endif /* CONFIG_NO_CONFIG_BLOBS */
263151497Sru
264151497Sru
265151497Srustatic int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
266151497Sru{
267151497Sru	char *params;
268151497Sru	char *pos;
269151497Sru	int *freqs = NULL;
270151497Sru	int ret;
271151497Sru
272151497Sru	if (atoi(cmd)) {
273151497Sru		params = os_strchr(cmd, ' ');
274151497Sru		os_free(wpa_s->manual_sched_scan_freqs);
275151497Sru		if (params) {
276151497Sru			params++;
277151497Sru			pos = os_strstr(params, "freq=");
278151497Sru			if (pos)
279151497Sru				freqs = freq_range_to_channel_list(wpa_s,
280151497Sru								   pos + 5);
281151497Sru		}
282151497Sru		wpa_s->manual_sched_scan_freqs = freqs;
283151497Sru		ret = wpas_start_pno(wpa_s);
284151497Sru	} else {
285151497Sru		ret = wpas_stop_pno(wpa_s);
286151497Sru	}
287151497Sru	return ret;
288151497Sru}
289151497Sru
290151497Sru
291151497Srustatic int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
292151497Sru{
293151497Sru	union wpa_event_data event;
294151497Sru
295151497Sru	if (os_strcmp(band, "AUTO") == 0)
296151497Sru		wpa_s->setband = WPA_SETBAND_AUTO;
297151497Sru	else if (os_strcmp(band, "5G") == 0)
298151497Sru		wpa_s->setband = WPA_SETBAND_5G;
299151497Sru	else if (os_strcmp(band, "2G") == 0)
300151497Sru		wpa_s->setband = WPA_SETBAND_2G;
301151497Sru	else
302151497Sru		return -1;
303151497Sru
304151497Sru	if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) {
305114402Sru		os_memset(&event, 0, sizeof(event));
306114402Sru		event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
307114402Sru		event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
308114402Sru		wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event);
309114402Sru	}
310114402Sru
311114402Sru	return 0;
312114402Sru}
313114402Sru
314114402Sru
315114402Srustatic int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s,
316114402Sru				   const char *cmd)
317114402Sru{
318114402Sru	struct wpabuf *lci;
319114402Sru
320114402Sru	if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
321114402Sru		wpabuf_free(wpa_s->lci);
322151497Sru		wpa_s->lci = NULL;
323114402Sru		return 0;
324114402Sru	}
325114402Sru
326114402Sru	lci = wpabuf_parse_bin(cmd);
327114402Sru	if (!lci)
328114402Sru		return -1;
329114402Sru
330114402Sru	if (os_get_reltime(&wpa_s->lci_time)) {
331114402Sru		wpabuf_free(lci);
332114402Sru		return -1;
333114402Sru	}
334114402Sru
335114402Sru	wpabuf_free(wpa_s->lci);
336114402Sru	wpa_s->lci = lci;
337114402Sru
338114402Sru	return 0;
339114402Sru}
340114402Sru
341114402Sru
342114402Srustatic int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
343114402Sru					 char *cmd)
344114402Sru{
345114402Sru	char *value;
346114402Sru	int ret = 0;
347114402Sru
348114402Sru	value = os_strchr(cmd, ' ');
349114402Sru	if (value == NULL)
350114402Sru		return -1;
351114402Sru	*value++ = '\0';
352114402Sru
353114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
354114402Sru	if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
355114402Sru		eapol_sm_configure(wpa_s->eapol,
356114402Sru				   atoi(value), -1, -1, -1);
357114402Sru	} else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
358151497Sru		eapol_sm_configure(wpa_s->eapol,
359114402Sru				   -1, atoi(value), -1, -1);
360114402Sru	} else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
361114402Sru		eapol_sm_configure(wpa_s->eapol,
362114402Sru				   -1, -1, atoi(value), -1);
363151497Sru	} else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
364114402Sru		eapol_sm_configure(wpa_s->eapol,
365151497Sru				   -1, -1, -1, atoi(value));
366114402Sru	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
367114402Sru		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
368114402Sru				     atoi(value)))
369114402Sru			ret = -1;
370114402Sru	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
371114402Sru		   0) {
372114402Sru		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
373151497Sru				     atoi(value)))
374114402Sru			ret = -1;
375114402Sru	} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
376114402Sru		if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
377114402Sru			ret = -1;
378114402Sru	} else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
379114402Sru		wpa_s->wps_fragment_size = atoi(value);
380114402Sru#ifdef CONFIG_WPS_TESTING
381114402Sru	} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
382114402Sru		long int val;
383114402Sru		val = strtol(value, NULL, 0);
384114402Sru		if (val < 0 || val > 0xff) {
385114402Sru			ret = -1;
386114402Sru			wpa_printf(MSG_DEBUG, "WPS: Invalid "
387114402Sru				   "wps_version_number %ld", val);
388151497Sru		} else {
389114402Sru			wps_version_number = val;
390114402Sru			wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
391114402Sru				   "version %u.%u",
392114402Sru				   (wps_version_number & 0xf0) >> 4,
393114402Sru				   wps_version_number & 0x0f);
394151497Sru		}
395114402Sru	} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
396114402Sru		wps_testing_dummy_cred = atoi(value);
397114402Sru		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
398114402Sru			   wps_testing_dummy_cred);
399114402Sru	} else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
400114402Sru		wps_corrupt_pkhash = atoi(value);
401114402Sru		wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
402114402Sru			   wps_corrupt_pkhash);
403114402Sru	} else if (os_strcasecmp(cmd, "wps_force_auth_types") == 0) {
404114402Sru		if (value[0] == '\0') {
405114402Sru			wps_force_auth_types_in_use = 0;
406114402Sru		} else {
407114402Sru			wps_force_auth_types = strtol(value, NULL, 0);
408114402Sru			wps_force_auth_types_in_use = 1;
409151497Sru		}
410114402Sru	} else if (os_strcasecmp(cmd, "wps_force_encr_types") == 0) {
411114402Sru		if (value[0] == '\0') {
412114402Sru			wps_force_encr_types_in_use = 0;
413114402Sru		} else {
414114402Sru			wps_force_encr_types = strtol(value, NULL, 0);
415114402Sru			wps_force_encr_types_in_use = 1;
416114402Sru		}
417114402Sru#endif /* CONFIG_WPS_TESTING */
418114402Sru	} else if (os_strcasecmp(cmd, "ampdu") == 0) {
419114402Sru		if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
420114402Sru			ret = -1;
421114402Sru#ifdef CONFIG_TDLS
422114402Sru#ifdef CONFIG_TDLS_TESTING
423114402Sru	} else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
424114402Sru		tdls_testing = strtol(value, NULL, 0);
425114402Sru		wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
426114402Sru#endif /* CONFIG_TDLS_TESTING */
427114402Sru	} else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
428114402Sru		int disabled = atoi(value);
429114402Sru		wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
430114402Sru		if (disabled) {
431114402Sru			if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
432114402Sru				ret = -1;
433114402Sru		} else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
434151497Sru			ret = -1;
435114402Sru		wpa_tdls_enable(wpa_s->wpa, !disabled);
436114402Sru#endif /* CONFIG_TDLS */
437114402Sru	} else if (os_strcasecmp(cmd, "pno") == 0) {
438114402Sru		ret = wpas_ctrl_pno(wpa_s, value);
439114402Sru	} else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
440114402Sru		int disabled = atoi(value);
441114402Sru		if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
442114402Sru			ret = -1;
443114402Sru		else if (disabled)
444114402Sru			wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
445114402Sru	} else if (os_strcasecmp(cmd, "uapsd") == 0) {
446114402Sru		if (os_strcmp(value, "disable") == 0)
447114402Sru			wpa_s->set_sta_uapsd = 0;
448114402Sru		else {
449114402Sru			int be, bk, vi, vo;
450114402Sru			char *pos;
451114402Sru			/* format: BE,BK,VI,VO;max SP Length */
452114402Sru			be = atoi(value);
453114402Sru			pos = os_strchr(value, ',');
454114402Sru			if (pos == NULL)
455114402Sru				return -1;
456114402Sru			pos++;
457114402Sru			bk = atoi(pos);
458114402Sru			pos = os_strchr(pos, ',');
459114402Sru			if (pos == NULL)
460114402Sru				return -1;
461114402Sru			pos++;
462114402Sru			vi = atoi(pos);
463114402Sru			pos = os_strchr(pos, ',');
464114402Sru			if (pos == NULL)
465114402Sru				return -1;
466114402Sru			pos++;
467114402Sru			vo = atoi(pos);
468114402Sru			/* ignore max SP Length for now */
469114402Sru
470114402Sru			wpa_s->set_sta_uapsd = 1;
471114402Sru			wpa_s->sta_uapsd = 0;
472114402Sru			if (be)
473114402Sru				wpa_s->sta_uapsd |= BIT(0);
474114402Sru			if (bk)
475151497Sru				wpa_s->sta_uapsd |= BIT(1);
476114402Sru			if (vi)
477151497Sru				wpa_s->sta_uapsd |= BIT(2);
478151497Sru			if (vo)
479114402Sru				wpa_s->sta_uapsd |= BIT(3);
480114402Sru		}
481114402Sru	} else if (os_strcasecmp(cmd, "ps") == 0) {
482114402Sru		ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
483114402Sru#ifdef CONFIG_WIFI_DISPLAY
484114402Sru	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
485114402Sru		int enabled = !!atoi(value);
486114402Sru		if (enabled && !wpa_s->global->p2p)
487114402Sru			ret = -1;
488151497Sru		else
489114402Sru			wifi_display_enable(wpa_s->global, enabled);
490114402Sru#endif /* CONFIG_WIFI_DISPLAY */
491114402Sru	} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
492114402Sru		ret = set_bssid_filter(wpa_s, value);
493114402Sru	} else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
494114402Sru		ret = set_disallow_aps(wpa_s, value);
495114402Sru	} else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
496114402Sru		wpa_s->no_keep_alive = !!atoi(value);
497114402Sru#ifdef CONFIG_TESTING_OPTIONS
498114402Sru	} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
499114402Sru		wpa_s->ext_mgmt_frame_handling = !!atoi(value);
500114402Sru	} else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
501114402Sru		wpa_s->ext_eapol_frame_io = !!atoi(value);
502114402Sru#ifdef CONFIG_AP
503114402Sru		if (wpa_s->ap_iface) {
504114402Sru			wpa_s->ap_iface->bss[0]->ext_eapol_frame_io =
505114402Sru				wpa_s->ext_eapol_frame_io;
506114402Sru		}
507114402Sru#endif /* CONFIG_AP */
508114402Sru	} else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
509114402Sru		wpa_s->extra_roc_dur = atoi(value);
510114402Sru	} else if (os_strcasecmp(cmd, "test_failure") == 0) {
511114402Sru		wpa_s->test_failure = atoi(value);
512114402Sru	} else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
513114402Sru		wpa_s->p2p_go_csa_on_inv = !!atoi(value);
514114402Sru	} else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) {
515114402Sru		wpa_s->ignore_auth_resp = !!atoi(value);
516114402Sru	} else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
517114402Sru		wpa_s->ignore_assoc_disallow = !!atoi(value);
518114402Sru	} else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
519114402Sru		wpa_s->reject_btm_req_reason = atoi(value);
520151497Sru#endif /* CONFIG_TESTING_OPTIONS */
521114402Sru#ifndef CONFIG_NO_CONFIG_BLOBS
522114402Sru	} else if (os_strcmp(cmd, "blob") == 0) {
523114402Sru		ret = wpas_ctrl_set_blob(wpa_s, value);
524151497Sru#endif /* CONFIG_NO_CONFIG_BLOBS */
525114402Sru	} else if (os_strcasecmp(cmd, "setband") == 0) {
526114402Sru		ret = wpas_ctrl_set_band(wpa_s, value);
527114402Sru#ifdef CONFIG_MBO
528114402Sru	} else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
529151497Sru		ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
530114402Sru	} else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
531114402Sru		wpas_mbo_update_cell_capa(wpa_s, atoi(value));
532114402Sru#endif /* CONFIG_MBO */
533114402Sru	} else if (os_strcasecmp(cmd, "lci") == 0) {
534114402Sru		ret = wpas_ctrl_iface_set_lci(wpa_s, value);
535114402Sru	} else {
536114402Sru		value[-1] = '=';
537114402Sru		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
538114402Sru		if (ret == 0)
539114402Sru			wpa_supplicant_update_config(wpa_s);
540114402Sru	}
541114402Sru
542114402Sru	return ret;
543114402Sru}
544114402Sru
545114402Sru
546114402Srustatic int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
547114402Sru					 char *cmd, char *buf, size_t buflen)
548114402Sru{
549114402Sru	int res = -1;
550114402Sru
551114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
552114402Sru
553114402Sru	if (os_strcmp(cmd, "version") == 0) {
554114402Sru		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
555114402Sru	} else if (os_strcasecmp(cmd, "country") == 0) {
556114402Sru		if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
557114402Sru			res = os_snprintf(buf, buflen, "%c%c",
558114402Sru					  wpa_s->conf->country[0],
559114402Sru					  wpa_s->conf->country[1]);
560114402Sru#ifdef CONFIG_WIFI_DISPLAY
561114402Sru	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
562114402Sru		int enabled;
563114402Sru		if (wpa_s->global->p2p == NULL ||
564114402Sru		    wpa_s->global->p2p_disabled)
565114402Sru			enabled = 0;
566114402Sru		else
567114402Sru			enabled = wpa_s->global->wifi_display;
568114402Sru		res = os_snprintf(buf, buflen, "%d", enabled);
569114402Sru#endif /* CONFIG_WIFI_DISPLAY */
570114402Sru#ifdef CONFIG_TESTING_GET_GTK
571114402Sru	} else if (os_strcmp(cmd, "gtk") == 0) {
572114402Sru		if (wpa_s->last_gtk_len == 0)
573114402Sru			return -1;
574114402Sru		res = wpa_snprintf_hex(buf, buflen, wpa_s->last_gtk,
575114402Sru				       wpa_s->last_gtk_len);
576114402Sru		return res;
577114402Sru#endif /* CONFIG_TESTING_GET_GTK */
578114402Sru	} else if (os_strcmp(cmd, "tls_library") == 0) {
579114402Sru		res = tls_get_library_version(buf, buflen);
580151497Sru	} else {
581114402Sru		res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen);
582114402Sru	}
583114402Sru
584151497Sru	if (os_snprintf_error(buflen, res))
585114402Sru		return -1;
586114402Sru	return res;
587114402Sru}
588114402Sru
589114402Sru
590114402Sru#ifdef IEEE8021X_EAPOL
591114402Srustatic int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
592114402Sru					     char *addr)
593114402Sru{
594114402Sru	u8 bssid[ETH_ALEN];
595114402Sru	struct wpa_ssid *ssid = wpa_s->current_ssid;
596114402Sru
597114402Sru	if (hwaddr_aton(addr, bssid)) {
598114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
599114402Sru			   "'%s'", addr);
600114402Sru		return -1;
601114402Sru	}
602114402Sru
603114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
604114402Sru	rsn_preauth_deinit(wpa_s->wpa);
605114402Sru	if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
606114402Sru		return -1;
607114402Sru
608114402Sru	return 0;
609114402Sru}
610114402Sru#endif /* IEEE8021X_EAPOL */
611114402Sru
612114402Sru
613114402Sru#ifdef CONFIG_PEERKEY
614114402Sru/* MLME-STKSTART.request(peer) */
615114402Srustatic int wpa_supplicant_ctrl_iface_stkstart(
616114402Sru	struct wpa_supplicant *wpa_s, char *addr)
617114402Sru{
618114402Sru	u8 peer[ETH_ALEN];
619114402Sru
620114402Sru	if (hwaddr_aton(addr, peer)) {
621114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
622114402Sru			   "address '%s'", addr);
623114402Sru		return -1;
624114402Sru	}
625114402Sru
626114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
627114402Sru		   MAC2STR(peer));
628114402Sru
629114402Sru	return wpa_sm_stkstart(wpa_s->wpa, peer);
630114402Sru}
631114402Sru#endif /* CONFIG_PEERKEY */
632114402Sru
633114402Sru
634114402Sru#ifdef CONFIG_TDLS
635114402Sru
636114402Srustatic int wpa_supplicant_ctrl_iface_tdls_discover(
637114402Sru	struct wpa_supplicant *wpa_s, char *addr)
638114402Sru{
639114402Sru	u8 peer[ETH_ALEN];
640114402Sru	int ret;
641114402Sru
642114402Sru	if (hwaddr_aton(addr, peer)) {
643114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
644114402Sru			   "address '%s'", addr);
645114402Sru		return -1;
646114402Sru	}
647114402Sru
648114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
649114402Sru		   MAC2STR(peer));
650114402Sru
651114402Sru	if (wpa_tdls_is_external_setup(wpa_s->wpa))
652114402Sru		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
653114402Sru	else
654114402Sru		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
655114402Sru
656114402Sru	return ret;
657114402Sru}
658114402Sru
659114402Sru
660114402Srustatic int wpa_supplicant_ctrl_iface_tdls_setup(
661114402Sru	struct wpa_supplicant *wpa_s, char *addr)
662151497Sru{
663114402Sru	u8 peer[ETH_ALEN];
664114402Sru	int ret;
665114402Sru
666114402Sru	if (hwaddr_aton(addr, peer)) {
667114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
668114402Sru			   "address '%s'", addr);
669114402Sru		return -1;
670114402Sru	}
671151497Sru
672114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
673114402Sru		   MAC2STR(peer));
674151497Sru
675151497Sru	if ((wpa_s->conf->tdls_external_control) &&
676151497Sru	    wpa_tdls_is_external_setup(wpa_s->wpa))
677114402Sru		return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
678151497Sru
679151497Sru	wpa_tdls_remove(wpa_s->wpa, peer);
680151497Sru
681151497Sru	if (wpa_tdls_is_external_setup(wpa_s->wpa))
682151497Sru		ret = wpa_tdls_start(wpa_s->wpa, peer);
683114402Sru	else
684151497Sru		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
685114402Sru
686114402Sru	return ret;
687151497Sru}
688151497Sru
689151497Sru
690151497Srustatic int wpa_supplicant_ctrl_iface_tdls_teardown(
691151497Sru	struct wpa_supplicant *wpa_s, char *addr)
692151497Sru{
693151497Sru	u8 peer[ETH_ALEN];
694151497Sru	int ret;
695151497Sru
696114402Sru	if (os_strcmp(addr, "*") == 0) {
697114402Sru		/* remove everyone */
698151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN *");
699151497Sru		wpa_tdls_teardown_peers(wpa_s->wpa);
700151497Sru		return 0;
701114402Sru	}
702114402Sru
703114402Sru	if (hwaddr_aton(addr, peer)) {
704151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
705114402Sru			   "address '%s'", addr);
706114402Sru		return -1;
707114402Sru	}
708114402Sru
709151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
710151497Sru		   MAC2STR(peer));
711151497Sru
712114402Sru	if ((wpa_s->conf->tdls_external_control) &&
713114402Sru	    wpa_tdls_is_external_setup(wpa_s->wpa))
714114402Sru		return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
715151497Sru
716151497Sru	if (wpa_tdls_is_external_setup(wpa_s->wpa))
717151497Sru		ret = wpa_tdls_teardown_link(
718151497Sru			wpa_s->wpa, peer,
719151497Sru			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
720151497Sru	else
721151497Sru		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
722151497Sru
723151497Sru	return ret;
724114402Sru}
725114402Sru
726114402Sru
727114402Srustatic int ctrl_iface_get_capability_tdls(
728114402Sru	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
729151497Sru{
730151497Sru	int ret;
731114402Sru
732114402Sru	ret = os_snprintf(buf, buflen, "%s\n",
733114402Sru			  wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ?
734114402Sru			  (wpa_s->drv_flags &
735114402Sru			   WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
736114402Sru			   "EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
737114402Sru	if (os_snprintf_error(buflen, ret))
738114402Sru		return -1;
739151497Sru	return ret;
740151497Sru}
741114402Sru
742114402Sru
743114402Srustatic int wpa_supplicant_ctrl_iface_tdls_chan_switch(
744114402Sru	struct wpa_supplicant *wpa_s, char *cmd)
745114402Sru{
746114402Sru	u8 peer[ETH_ALEN];
747114402Sru	struct hostapd_freq_params freq_params;
748114402Sru	u8 oper_class;
749151497Sru	char *pos, *end;
750151497Sru
751114402Sru	if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
752114402Sru		wpa_printf(MSG_INFO,
753114402Sru			   "tdls_chanswitch: Only supported with external setup");
754114402Sru		return -1;
755114402Sru	}
756114402Sru
757114402Sru	os_memset(&freq_params, 0, sizeof(freq_params));
758114402Sru
759151497Sru	pos = os_strchr(cmd, ' ');
760151497Sru	if (pos == NULL)
761114402Sru		return -1;
762114402Sru	*pos++ = '\0';
763114402Sru
764151497Sru	oper_class = strtol(pos, &end, 10);
765151497Sru	if (pos == end) {
766151497Sru		wpa_printf(MSG_INFO,
767151497Sru			   "tdls_chanswitch: Invalid op class provided");
768151497Sru		return -1;
769151497Sru	}
770151497Sru
771151497Sru	pos = end;
772151497Sru	freq_params.freq = atoi(pos);
773151497Sru	if (freq_params.freq == 0) {
774114402Sru		wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
775114402Sru		return -1;
776114402Sru	}
777114402Sru
778114402Sru#define SET_FREQ_SETTING(str) \
779151497Sru	do { \
780151497Sru		const char *pos2 = os_strstr(pos, " " #str "="); \
781114402Sru		if (pos2) { \
782114402Sru			pos2 += sizeof(" " #str "=") - 1; \
783114402Sru			freq_params.str = atoi(pos2); \
784114402Sru		} \
785114402Sru	} while (0)
786114402Sru
787114402Sru	SET_FREQ_SETTING(center_freq1);
788114402Sru	SET_FREQ_SETTING(center_freq2);
789151497Sru	SET_FREQ_SETTING(bandwidth);
790114402Sru	SET_FREQ_SETTING(sec_channel_offset);
791114402Sru#undef SET_FREQ_SETTING
792114402Sru
793114402Sru	freq_params.ht_enabled = !!os_strstr(pos, " ht");
794114402Sru	freq_params.vht_enabled = !!os_strstr(pos, " vht");
795114402Sru
796114402Sru	if (hwaddr_aton(cmd, peer)) {
797114402Sru		wpa_printf(MSG_DEBUG,
798151497Sru			   "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
799114402Sru			   cmd);
800114402Sru		return -1;
801114402Sru	}
802114402Sru
803114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
804114402Sru		   " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
805114402Sru		   MAC2STR(peer), oper_class, freq_params.freq,
806114402Sru		   freq_params.center_freq1, freq_params.center_freq2,
807151497Sru		   freq_params.bandwidth, freq_params.sec_channel_offset,
808151497Sru		   freq_params.ht_enabled ? " HT" : "",
809114402Sru		   freq_params.vht_enabled ? " VHT" : "");
810114402Sru
811114402Sru	return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
812114402Sru					   &freq_params);
813114402Sru}
814114402Sru
815114402Sru
816114402Srustatic int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
817151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
818151497Sru{
819114402Sru	u8 peer[ETH_ALEN];
820114402Sru
821114402Sru	if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
822114402Sru		wpa_printf(MSG_INFO,
823114402Sru			   "tdls_chanswitch: Only supported with external setup");
824114402Sru		return -1;
825114402Sru	}
826114402Sru
827151497Sru	if (hwaddr_aton(cmd, peer)) {
828151497Sru		wpa_printf(MSG_DEBUG,
829114402Sru			   "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
830114402Sru			   cmd);
831114402Sru		return -1;
832114402Sru	}
833114402Sru
834114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
835114402Sru		   MAC2STR(peer));
836114402Sru
837114402Sru	return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
838114402Sru}
839114402Sru
840114402Sru
841114402Srustatic int wpa_supplicant_ctrl_iface_tdls_link_status(
842114402Sru	struct wpa_supplicant *wpa_s, const char *addr,
843114402Sru	char *buf, size_t buflen)
844114402Sru{
845114402Sru	u8 peer[ETH_ALEN];
846114402Sru	const char *tdls_status;
847114402Sru	int ret;
848114402Sru
849114402Sru	if (hwaddr_aton(addr, peer)) {
850151497Sru		wpa_printf(MSG_DEBUG,
851151497Sru			   "CTRL_IFACE TDLS_LINK_STATUS: Invalid address '%s'",
852151497Sru			   addr);
853114402Sru		return -1;
854114402Sru	}
855114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS " MACSTR,
856114402Sru		   MAC2STR(peer));
857151497Sru
858114402Sru	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
859114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS: %s", tdls_status);
860114402Sru	ret = os_snprintf(buf, buflen, "TDLS link status: %s\n", tdls_status);
861114402Sru	if (os_snprintf_error(buflen, ret))
862114402Sru		return -1;
863114402Sru
864114402Sru	return ret;
865114402Sru}
866114402Sru
867114402Sru#endif /* CONFIG_TDLS */
868114402Sru
869114402Sru
870114402Srustatic int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd)
871114402Sru{
872114402Sru	char *token, *context = NULL;
873114402Sru	struct wmm_ac_ts_setup_params params = {
874114402Sru		.tsid = 0xff,
875114402Sru		.direction = 0xff,
876114402Sru	};
877151497Sru
878114402Sru	while ((token = str_token(cmd, " ", &context))) {
879114402Sru		if (sscanf(token, "tsid=%i", &params.tsid) == 1 ||
880114402Sru		    sscanf(token, "up=%i", &params.user_priority) == 1 ||
881114402Sru		    sscanf(token, "nominal_msdu_size=%i",
882114402Sru			   &params.nominal_msdu_size) == 1 ||
883114402Sru		    sscanf(token, "mean_data_rate=%i",
884114402Sru			   &params.mean_data_rate) == 1 ||
885114402Sru		    sscanf(token, "min_phy_rate=%i",
886114402Sru			   &params.minimum_phy_rate) == 1 ||
887114402Sru		    sscanf(token, "sba=%i",
888114402Sru			   &params.surplus_bandwidth_allowance) == 1)
889114402Sru			continue;
890114402Sru
891114402Sru		if (os_strcasecmp(token, "downlink") == 0) {
892114402Sru			params.direction = WMM_TSPEC_DIRECTION_DOWNLINK;
893114402Sru		} else if (os_strcasecmp(token, "uplink") == 0) {
894114402Sru			params.direction = WMM_TSPEC_DIRECTION_UPLINK;
895114402Sru		} else if (os_strcasecmp(token, "bidi") == 0) {
896114402Sru			params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL;
897114402Sru		} else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) {
898114402Sru			params.fixed_nominal_msdu = 1;
899114402Sru		} else {
900114402Sru			wpa_printf(MSG_DEBUG,
901114402Sru				   "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'",
902114402Sru				   token);
903114402Sru			return -1;
904114402Sru		}
905114402Sru
906114402Sru	}
907114402Sru
908114402Sru	return wpas_wmm_ac_addts(wpa_s, &params);
909114402Sru}
910114402Sru
911114402Sru
912114402Srustatic int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd)
913114402Sru{
914114402Sru	u8 tsid = atoi(cmd);
915114402Sru
916114402Sru	return wpas_wmm_ac_delts(wpa_s, tsid);
917114402Sru}
918114402Sru
919151497Sru
920151497Sru#ifdef CONFIG_IEEE80211R
921151497Srustatic int wpa_supplicant_ctrl_iface_ft_ds(
922151497Sru	struct wpa_supplicant *wpa_s, char *addr)
923151497Sru{
924114402Sru	u8 target_ap[ETH_ALEN];
925114402Sru	struct wpa_bss *bss;
926114402Sru	const u8 *mdie;
927114402Sru
928114402Sru	if (hwaddr_aton(addr, target_ap)) {
929114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
930114402Sru			   "address '%s'", addr);
931114402Sru		return -1;
932114402Sru	}
933114402Sru
934114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
935114402Sru
936114402Sru	bss = wpa_bss_get_bssid(wpa_s, target_ap);
937114402Sru	if (bss)
938114402Sru		mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
939114402Sru	else
940114402Sru		mdie = NULL;
941114402Sru
942114402Sru	return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
943114402Sru}
944114402Sru#endif /* CONFIG_IEEE80211R */
945114402Sru
946114402Sru
947114402Sru#ifdef CONFIG_WPS
948114402Srustatic int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
949114402Sru					     char *cmd)
950114402Sru{
951114402Sru	u8 bssid[ETH_ALEN], *_bssid = bssid;
952114402Sru#ifdef CONFIG_P2P
953114402Sru	u8 p2p_dev_addr[ETH_ALEN];
954114402Sru#endif /* CONFIG_P2P */
955114402Sru#ifdef CONFIG_AP
956114402Sru	u8 *_p2p_dev_addr = NULL;
957114402Sru#endif /* CONFIG_AP */
958114402Sru
959114402Sru	if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
960114402Sru		_bssid = NULL;
961114402Sru#ifdef CONFIG_P2P
962114402Sru	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
963114402Sru		if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
964114402Sru			wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
965114402Sru				   "P2P Device Address '%s'",
966114402Sru				   cmd + 13);
967114402Sru			return -1;
968114402Sru		}
969114402Sru		_p2p_dev_addr = p2p_dev_addr;
970114402Sru#endif /* CONFIG_P2P */
971114402Sru	} else if (hwaddr_aton(cmd, bssid)) {
972114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
973114402Sru			   cmd);
974114402Sru		return -1;
975114402Sru	}
976114402Sru
977114402Sru#ifdef CONFIG_AP
978114402Sru	if (wpa_s->ap_iface)
979114402Sru		return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
980114402Sru#endif /* CONFIG_AP */
981114402Sru
982114402Sru	return wpas_wps_start_pbc(wpa_s, _bssid, 0);
983114402Sru}
984114402Sru
985114402Sru
986114402Srustatic int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
987114402Sru					     char *cmd, char *buf,
988114402Sru					     size_t buflen)
989114402Sru{
990114402Sru	u8 bssid[ETH_ALEN], *_bssid = bssid;
991114402Sru	char *pin;
992114402Sru	int ret;
993114402Sru
994114402Sru	pin = os_strchr(cmd, ' ');
995114402Sru	if (pin)
996114402Sru		*pin++ = '\0';
997114402Sru
998114402Sru	if (os_strcmp(cmd, "any") == 0)
999114402Sru		_bssid = NULL;
1000114402Sru	else if (os_strcmp(cmd, "get") == 0) {
1001114402Sru		if (wps_generate_pin((unsigned int *) &ret) < 0)
1002114402Sru			return -1;
1003114402Sru		goto done;
1004114402Sru	} else if (hwaddr_aton(cmd, bssid)) {
1005114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
1006114402Sru			   cmd);
1007114402Sru		return -1;
1008114402Sru	}
1009114402Sru
1010114402Sru#ifdef CONFIG_AP
1011114402Sru	if (wpa_s->ap_iface) {
1012114402Sru		int timeout = 0;
1013114402Sru		char *pos;
1014114402Sru
1015114402Sru		if (pin) {
1016114402Sru			pos = os_strchr(pin, ' ');
1017114402Sru			if (pos) {
1018114402Sru				*pos++ = '\0';
1019114402Sru				timeout = atoi(pos);
1020114402Sru			}
1021114402Sru		}
1022114402Sru
1023114402Sru		return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
1024114402Sru						 buf, buflen, timeout);
1025114402Sru	}
1026114402Sru#endif /* CONFIG_AP */
1027114402Sru
1028114402Sru	if (pin) {
1029114402Sru		ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
1030114402Sru					 DEV_PW_DEFAULT);
1031114402Sru		if (ret < 0)
1032114402Sru			return -1;
1033114402Sru		ret = os_snprintf(buf, buflen, "%s", pin);
1034114402Sru		if (os_snprintf_error(buflen, ret))
1035114402Sru			return -1;
1036114402Sru		return ret;
1037114402Sru	}
1038114402Sru
1039151497Sru	ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
1040151497Sru	if (ret < 0)
1041114402Sru		return -1;
1042114402Sru
1043114402Srudone:
1044114402Sru	/* Return the generated PIN */
1045114402Sru	ret = os_snprintf(buf, buflen, "%08d", ret);
1046114402Sru	if (os_snprintf_error(buflen, ret))
1047114402Sru		return -1;
1048114402Sru	return ret;
1049151497Sru}
1050151497Sru
1051151497Sru
1052151497Srustatic int wpa_supplicant_ctrl_iface_wps_check_pin(
1053151497Sru	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
1054151497Sru{
1055151497Sru	char pin[9];
1056114402Sru	size_t len;
1057114402Sru	char *pos;
1058114402Sru	int ret;
1059114402Sru
1060114402Sru	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
1061114402Sru			      (u8 *) cmd, os_strlen(cmd));
1062114402Sru	for (pos = cmd, len = 0; *pos != '\0'; pos++) {
1063114402Sru		if (*pos < '0' || *pos > '9')
1064151497Sru			continue;
1065114402Sru		pin[len++] = *pos;
1066114402Sru		if (len == 9) {
1067114402Sru			wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
1068114402Sru			return -1;
1069114402Sru		}
1070114402Sru	}
1071114402Sru	if (len != 4 && len != 8) {
1072114402Sru		wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
1073151497Sru		return -1;
1074114402Sru	}
1075114402Sru	pin[len] = '\0';
1076114402Sru
1077114402Sru	if (len == 8) {
1078114402Sru		unsigned int pin_val;
1079114402Sru		pin_val = atoi(pin);
1080114402Sru		if (!wps_pin_valid(pin_val)) {
1081114402Sru			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
1082151497Sru			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
1083114402Sru			if (os_snprintf_error(buflen, ret))
1084114402Sru				return -1;
1085114402Sru			return ret;
1086114402Sru		}
1087114402Sru	}
1088114402Sru
1089114402Sru	ret = os_snprintf(buf, buflen, "%s", pin);
1090114402Sru	if (os_snprintf_error(buflen, ret))
1091114402Sru		return -1;
1092114402Sru
1093114402Sru	return ret;
1094114402Sru}
1095114402Sru
1096114402Sru
1097114402Sru#ifdef CONFIG_WPS_NFC
1098151497Sru
1099151497Srustatic int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
1100114402Sru					     char *cmd)
1101151497Sru{
1102151497Sru	u8 bssid[ETH_ALEN], *_bssid = bssid;
1103151497Sru
1104114402Sru	if (cmd == NULL || cmd[0] == '\0')
1105151497Sru		_bssid = NULL;
1106114402Sru	else if (hwaddr_aton(cmd, bssid))
1107151497Sru		return -1;
1108114402Sru
1109114402Sru	return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
1110114402Sru				  0, 0);
1111151497Sru}
1112114402Sru
1113114402Sru
1114114402Srustatic int wpa_supplicant_ctrl_iface_wps_nfc_config_token(
1115114402Sru	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1116114402Sru{
1117114402Sru	int ndef;
1118114402Sru	struct wpabuf *buf;
1119114402Sru	int res;
1120114402Sru	char *pos;
1121114402Sru
1122114402Sru	pos = os_strchr(cmd, ' ');
1123114402Sru	if (pos)
1124114402Sru		*pos++ = '\0';
1125114402Sru	if (os_strcmp(cmd, "WPS") == 0)
1126114402Sru		ndef = 0;
1127114402Sru	else if (os_strcmp(cmd, "NDEF") == 0)
1128114402Sru		ndef = 1;
1129114402Sru	else
1130114402Sru		return -1;
1131114402Sru
1132114402Sru	buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
1133114402Sru	if (buf == NULL)
1134114402Sru		return -1;
1135114402Sru
1136114402Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1137114402Sru					 wpabuf_len(buf));
1138114402Sru	reply[res++] = '\n';
1139151497Sru	reply[res] = '\0';
1140114402Sru
1141114402Sru	wpabuf_free(buf);
1142114402Sru
1143114402Sru	return res;
1144114402Sru}
1145114402Sru
1146114402Sru
1147114402Srustatic int wpa_supplicant_ctrl_iface_wps_nfc_token(
1148151497Sru	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1149114402Sru{
1150114402Sru	int ndef;
1151114402Sru	struct wpabuf *buf;
1152114402Sru	int res;
1153114402Sru
1154114402Sru	if (os_strcmp(cmd, "WPS") == 0)
1155114402Sru		ndef = 0;
1156114402Sru	else if (os_strcmp(cmd, "NDEF") == 0)
1157151497Sru		ndef = 1;
1158114402Sru	else
1159114402Sru		return -1;
1160114402Sru
1161114402Sru	buf = wpas_wps_nfc_token(wpa_s, ndef);
1162114402Sru	if (buf == NULL)
1163114402Sru		return -1;
1164114402Sru
1165114402Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1166114402Sru					 wpabuf_len(buf));
1167114402Sru	reply[res++] = '\n';
1168114402Sru	reply[res] = '\0';
1169114402Sru
1170114402Sru	wpabuf_free(buf);
1171114402Sru
1172114402Sru	return res;
1173114402Sru}
1174114402Sru
1175114402Sru
1176114402Srustatic int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
1177114402Sru	struct wpa_supplicant *wpa_s, char *pos)
1178114402Sru{
1179114402Sru	size_t len;
1180114402Sru	struct wpabuf *buf;
1181114402Sru	int ret;
1182114402Sru	char *freq;
1183114402Sru	int forced_freq = 0;
1184151497Sru
1185114402Sru	freq = strstr(pos, " freq=");
1186114402Sru	if (freq) {
1187114402Sru		*freq = '\0';
1188114402Sru		freq += 6;
1189114402Sru		forced_freq = atoi(freq);
1190114402Sru	}
1191114402Sru
1192114402Sru	len = os_strlen(pos);
1193114402Sru	if (len & 0x01)
1194114402Sru		return -1;
1195151497Sru	len /= 2;
1196151497Sru
1197151497Sru	buf = wpabuf_alloc(len);
1198151497Sru	if (buf == NULL)
1199114402Sru		return -1;
1200114402Sru	if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
1201114402Sru		wpabuf_free(buf);
1202114402Sru		return -1;
1203114402Sru	}
1204114402Sru
1205114402Sru	ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
1206114402Sru	wpabuf_free(buf);
1207114402Sru
1208114402Sru	return ret;
1209151497Sru}
1210151497Sru
1211151497Sru
1212151497Srustatic int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
1213114402Sru					      char *reply, size_t max_len,
1214114402Sru					      int ndef)
1215114402Sru{
1216114402Sru	struct wpabuf *buf;
1217114402Sru	int res;
1218114402Sru
1219114402Sru	buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
1220114402Sru	if (buf == NULL)
1221114402Sru		return -1;
1222114402Sru
1223114402Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1224151497Sru					 wpabuf_len(buf));
1225114402Sru	reply[res++] = '\n';
1226114402Sru	reply[res] = '\0';
1227114402Sru
1228114402Sru	wpabuf_free(buf);
1229114402Sru
1230114402Sru	return res;
1231114402Sru}
1232114402Sru
1233114402Sru
1234114402Sru#ifdef CONFIG_P2P
1235114402Srustatic int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
1236114402Sru					      char *reply, size_t max_len,
1237114402Sru					      int ndef)
1238114402Sru{
1239114402Sru	struct wpabuf *buf;
1240114402Sru	int res;
1241114402Sru
1242114402Sru	buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
1243114402Sru	if (buf == NULL) {
1244114402Sru		wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
1245114402Sru		return -1;
1246114402Sru	}
1247114402Sru
1248114402Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1249114402Sru					 wpabuf_len(buf));
1250114402Sru	reply[res++] = '\n';
1251114402Sru	reply[res] = '\0';
1252114402Sru
1253114402Sru	wpabuf_free(buf);
1254114402Sru
1255114402Sru	return res;
1256114402Sru}
1257114402Sru#endif /* CONFIG_P2P */
1258114402Sru
1259114402Sru
1260114402Srustatic int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
1261114402Sru					  char *cmd, char *reply,
1262114402Sru					  size_t max_len)
1263114402Sru{
1264114402Sru	char *pos;
1265114402Sru	int ndef;
1266114402Sru
1267151497Sru	pos = os_strchr(cmd, ' ');
1268151497Sru	if (pos == NULL)
1269114402Sru		return -1;
1270114402Sru	*pos++ = '\0';
1271114402Sru
1272114402Sru	if (os_strcmp(cmd, "WPS") == 0)
1273114402Sru		ndef = 0;
1274114402Sru	else if (os_strcmp(cmd, "NDEF") == 0)
1275114402Sru		ndef = 1;
1276114402Sru	else
1277114402Sru		return -1;
1278114402Sru
1279114402Sru	if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
1280114402Sru		if (!ndef)
1281114402Sru			return -1;
1282114402Sru		return wpas_ctrl_nfc_get_handover_req_wps(
1283114402Sru			wpa_s, reply, max_len, ndef);
1284114402Sru	}
1285114402Sru
1286114402Sru#ifdef CONFIG_P2P
1287114402Sru	if (os_strcmp(pos, "P2P-CR") == 0) {
1288114402Sru		return wpas_ctrl_nfc_get_handover_req_p2p(
1289114402Sru			wpa_s, reply, max_len, ndef);
1290114402Sru	}
1291114402Sru#endif /* CONFIG_P2P */
1292114402Sru
1293114402Sru	return -1;
1294114402Sru}
1295114402Sru
1296114402Sru
1297114402Srustatic int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
1298114402Sru					      char *reply, size_t max_len,
1299114402Sru					      int ndef, int cr, char *uuid)
1300114402Sru{
1301114402Sru	struct wpabuf *buf;
1302114402Sru	int res;
1303114402Sru
1304114402Sru	buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid);
1305114402Sru	if (buf == NULL)
1306114402Sru		return -1;
1307114402Sru
1308114402Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1309114402Sru					 wpabuf_len(buf));
1310114402Sru	reply[res++] = '\n';
1311114402Sru	reply[res] = '\0';
1312114402Sru
1313114402Sru	wpabuf_free(buf);
1314114402Sru
1315114402Sru	return res;
1316114402Sru}
1317114402Sru
1318114402Sru
1319114402Sru#ifdef CONFIG_P2P
1320114402Srustatic int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
1321114402Sru					      char *reply, size_t max_len,
1322114402Sru					      int ndef, int tag)
1323114402Sru{
1324114402Sru	struct wpabuf *buf;
1325114402Sru	int res;
1326114402Sru
1327114402Sru	buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
1328114402Sru	if (buf == NULL)
1329114402Sru		return -1;
1330151497Sru
1331151497Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1332114402Sru					 wpabuf_len(buf));
1333114402Sru	reply[res++] = '\n';
1334114402Sru	reply[res] = '\0';
1335114402Sru
1336114402Sru	wpabuf_free(buf);
1337114402Sru
1338114402Sru	return res;
1339114402Sru}
1340114402Sru#endif /* CONFIG_P2P */
1341114402Sru
1342114402Sru
1343114402Srustatic int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
1344114402Sru					  char *cmd, char *reply,
1345114402Sru					  size_t max_len)
1346114402Sru{
1347114402Sru	char *pos, *pos2;
1348114402Sru	int ndef;
1349114402Sru
1350151497Sru	pos = os_strchr(cmd, ' ');
1351114402Sru	if (pos == NULL)
1352114402Sru		return -1;
1353151497Sru	*pos++ = '\0';
1354114402Sru
1355114402Sru	if (os_strcmp(cmd, "WPS") == 0)
1356151497Sru		ndef = 0;
1357151497Sru	else if (os_strcmp(cmd, "NDEF") == 0)
1358114402Sru		ndef = 1;
1359151497Sru	else
1360151497Sru		return -1;
1361151497Sru
1362114402Sru	pos2 = os_strchr(pos, ' ');
1363114402Sru	if (pos2)
1364114402Sru		*pos2++ = '\0';
1365114402Sru	if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
1366114402Sru		if (!ndef)
1367114402Sru			return -1;
1368114402Sru		return wpas_ctrl_nfc_get_handover_sel_wps(
1369114402Sru			wpa_s, reply, max_len, ndef,
1370114402Sru			os_strcmp(pos, "WPS-CR") == 0, pos2);
1371114402Sru	}
1372114402Sru
1373114402Sru#ifdef CONFIG_P2P
1374114402Sru	if (os_strcmp(pos, "P2P-CR") == 0) {
1375114402Sru		return wpas_ctrl_nfc_get_handover_sel_p2p(
1376114402Sru			wpa_s, reply, max_len, ndef, 0);
1377114402Sru	}
1378114402Sru
1379114402Sru	if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
1380114402Sru		return wpas_ctrl_nfc_get_handover_sel_p2p(
1381114402Sru			wpa_s, reply, max_len, ndef, 1);
1382114402Sru	}
1383114402Sru#endif /* CONFIG_P2P */
1384114402Sru
1385114402Sru	return -1;
1386114402Sru}
1387114402Sru
1388114402Sru
1389114402Srustatic int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
1390114402Sru					 char *cmd)
1391151497Sru{
1392151497Sru	size_t len;
1393114402Sru	struct wpabuf *req, *sel;
1394114402Sru	int ret;
1395114402Sru	char *pos, *role, *type, *pos2;
1396114402Sru#ifdef CONFIG_P2P
1397114402Sru	char *freq;
1398114402Sru	int forced_freq = 0;
1399114402Sru
1400114402Sru	freq = strstr(cmd, " freq=");
1401114402Sru	if (freq) {
1402114402Sru		*freq = '\0';
1403114402Sru		freq += 6;
1404114402Sru		forced_freq = atoi(freq);
1405114402Sru	}
1406114402Sru#endif /* CONFIG_P2P */
1407114402Sru
1408114402Sru	role = cmd;
1409114402Sru	pos = os_strchr(role, ' ');
1410114402Sru	if (pos == NULL) {
1411114402Sru		wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
1412114402Sru		return -1;
1413114402Sru	}
1414114402Sru	*pos++ = '\0';
1415114402Sru
1416114402Sru	type = pos;
1417114402Sru	pos = os_strchr(type, ' ');
1418114402Sru	if (pos == NULL) {
1419151497Sru		wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
1420114402Sru		return -1;
1421151497Sru	}
1422151497Sru	*pos++ = '\0';
1423114402Sru
1424114402Sru	pos2 = os_strchr(pos, ' ');
1425114402Sru	if (pos2 == NULL) {
1426114402Sru		wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
1427114402Sru		return -1;
1428114402Sru	}
1429114402Sru	*pos2++ = '\0';
1430114402Sru
1431151497Sru	len = os_strlen(pos);
1432151497Sru	if (len & 0x01) {
1433151497Sru		wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
1434151497Sru		return -1;
1435151497Sru	}
1436151497Sru	len /= 2;
1437151497Sru
1438151497Sru	req = wpabuf_alloc(len);
1439151497Sru	if (req == NULL) {
1440151497Sru		wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
1441151497Sru		return -1;
1442151497Sru	}
1443114402Sru	if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
1444114402Sru		wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
1445114402Sru		wpabuf_free(req);
1446114402Sru		return -1;
1447114402Sru	}
1448114402Sru
1449114402Sru	len = os_strlen(pos2);
1450114402Sru	if (len & 0x01) {
1451114402Sru		wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
1452114402Sru		wpabuf_free(req);
1453114402Sru		return -1;
1454114402Sru	}
1455114402Sru	len /= 2;
1456114402Sru
1457114402Sru	sel = wpabuf_alloc(len);
1458114402Sru	if (sel == NULL) {
1459114402Sru		wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
1460114402Sru		wpabuf_free(req);
1461114402Sru		return -1;
1462114402Sru	}
1463114402Sru	if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
1464114402Sru		wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
1465114402Sru		wpabuf_free(req);
1466114402Sru		wpabuf_free(sel);
1467114402Sru		return -1;
1468114402Sru	}
1469114402Sru
1470114402Sru	wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
1471114402Sru		   role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
1472114402Sru
1473114402Sru	if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
1474114402Sru		ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
1475114402Sru#ifdef CONFIG_AP
1476114402Sru	} else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
1477114402Sru	{
1478114402Sru		ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
1479114402Sru		if (ret < 0)
1480114402Sru			ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
1481114402Sru#endif /* CONFIG_AP */
1482114402Sru#ifdef CONFIG_P2P
1483114402Sru	} else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
1484114402Sru	{
1485114402Sru		ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
1486114402Sru	} else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
1487114402Sru	{
1488114402Sru		ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
1489114402Sru						   forced_freq);
1490114402Sru#endif /* CONFIG_P2P */
1491114402Sru	} else {
1492114402Sru		wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
1493114402Sru			   "reported: role=%s type=%s", role, type);
1494114402Sru		ret = -1;
1495114402Sru	}
1496114402Sru	wpabuf_free(req);
1497114402Sru	wpabuf_free(sel);
1498114402Sru
1499114402Sru	if (ret)
1500114402Sru		wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
1501114402Sru
1502114402Sru	return ret;
1503114402Sru}
1504114402Sru
1505114402Sru#endif /* CONFIG_WPS_NFC */
1506114402Sru
1507114402Sru
1508114402Srustatic int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
1509114402Sru					     char *cmd)
1510114402Sru{
1511114402Sru	u8 bssid[ETH_ALEN];
1512114402Sru	char *pin;
1513114402Sru	char *new_ssid;
1514114402Sru	char *new_auth;
1515114402Sru	char *new_encr;
1516114402Sru	char *new_key;
1517114402Sru	struct wps_new_ap_settings ap;
1518114402Sru
1519114402Sru	pin = os_strchr(cmd, ' ');
1520114402Sru	if (pin == NULL)
1521114402Sru		return -1;
1522114402Sru	*pin++ = '\0';
1523114402Sru
1524114402Sru	if (hwaddr_aton(cmd, bssid)) {
1525114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
1526114402Sru			   cmd);
1527114402Sru		return -1;
1528114402Sru	}
1529114402Sru
1530114402Sru	new_ssid = os_strchr(pin, ' ');
1531114402Sru	if (new_ssid == NULL)
1532114402Sru		return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
1533114402Sru	*new_ssid++ = '\0';
1534114402Sru
1535114402Sru	new_auth = os_strchr(new_ssid, ' ');
1536114402Sru	if (new_auth == NULL)
1537114402Sru		return -1;
1538114402Sru	*new_auth++ = '\0';
1539114402Sru
1540114402Sru	new_encr = os_strchr(new_auth, ' ');
1541151497Sru	if (new_encr == NULL)
1542151497Sru		return -1;
1543151497Sru	*new_encr++ = '\0';
1544151497Sru
1545151497Sru	new_key = os_strchr(new_encr, ' ');
1546151497Sru	if (new_key == NULL)
1547151497Sru		return -1;
1548151497Sru	*new_key++ = '\0';
1549114402Sru
1550114402Sru	os_memset(&ap, 0, sizeof(ap));
1551114402Sru	ap.ssid_hex = new_ssid;
1552114402Sru	ap.auth = new_auth;
1553114402Sru	ap.encr = new_encr;
1554151497Sru	ap.key_hex = new_key;
1555151497Sru	return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
1556114402Sru}
1557114402Sru
1558114402Sru
1559114402Sru#ifdef CONFIG_AP
1560114402Srustatic int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
1561114402Sru						char *cmd, char *buf,
1562114402Sru						size_t buflen)
1563114402Sru{
1564114402Sru	int timeout = 300;
1565114402Sru	char *pos;
1566114402Sru	const char *pin_txt;
1567114402Sru
1568114402Sru	if (!wpa_s->ap_iface)
1569114402Sru		return -1;
1570114402Sru
1571114402Sru	pos = os_strchr(cmd, ' ');
1572114402Sru	if (pos)
1573114402Sru		*pos++ = '\0';
1574114402Sru
1575114402Sru	if (os_strcmp(cmd, "disable") == 0) {
1576151497Sru		wpas_wps_ap_pin_disable(wpa_s);
1577114402Sru		return os_snprintf(buf, buflen, "OK\n");
1578114402Sru	}
1579151497Sru
1580151497Sru	if (os_strcmp(cmd, "random") == 0) {
1581151497Sru		if (pos)
1582151497Sru			timeout = atoi(pos);
1583151497Sru		pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
1584151497Sru		if (pin_txt == NULL)
1585114402Sru			return -1;
1586114402Sru		return os_snprintf(buf, buflen, "%s", pin_txt);
1587114402Sru	}
1588114402Sru
1589114402Sru	if (os_strcmp(cmd, "get") == 0) {
1590222083Sbenl		pin_txt = wpas_wps_ap_pin_get(wpa_s);
1591114402Sru		if (pin_txt == NULL)
1592114402Sru			return -1;
1593114402Sru		return os_snprintf(buf, buflen, "%s", pin_txt);
1594114402Sru	}
1595114402Sru
1596114402Sru	if (os_strcmp(cmd, "set") == 0) {
1597114402Sru		char *pin;
1598151497Sru		if (pos == NULL)
1599151497Sru			return -1;
1600114402Sru		pin = pos;
1601114402Sru		pos = os_strchr(pos, ' ');
1602114402Sru		if (pos) {
1603114402Sru			*pos++ = '\0';
1604114402Sru			timeout = atoi(pos);
1605114402Sru		}
1606151497Sru		if (os_strlen(pin) > buflen)
1607151497Sru			return -1;
1608151497Sru		if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
1609151497Sru			return -1;
1610151497Sru		return os_snprintf(buf, buflen, "%s", pin);
1611151497Sru	}
1612151497Sru
1613151497Sru	return -1;
1614151497Sru}
1615151497Sru#endif /* CONFIG_AP */
1616151497Sru
1617151497Sru
1618151497Sru#ifdef CONFIG_WPS_ER
1619151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
1620151497Sru						char *cmd)
1621151497Sru{
1622151497Sru	char *uuid = cmd, *pin, *pos;
1623151497Sru	u8 addr_buf[ETH_ALEN], *addr = NULL;
1624151497Sru	pin = os_strchr(uuid, ' ');
1625151497Sru	if (pin == NULL)
1626151497Sru		return -1;
1627151497Sru	*pin++ = '\0';
1628151497Sru	pos = os_strchr(pin, ' ');
1629151497Sru	if (pos) {
1630151497Sru		*pos++ = '\0';
1631151497Sru		if (hwaddr_aton(pos, addr_buf) == 0)
1632151497Sru			addr = addr_buf;
1633151497Sru	}
1634151497Sru	return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
1635151497Sru}
1636151497Sru
1637151497Sru
1638151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
1639151497Sru						  char *cmd)
1640151497Sru{
1641151497Sru	char *uuid = cmd, *pin;
1642151497Sru	pin = os_strchr(uuid, ' ');
1643151497Sru	if (pin == NULL)
1644151497Sru		return -1;
1645151497Sru	*pin++ = '\0';
1646151497Sru	return wpas_wps_er_learn(wpa_s, uuid, pin);
1647151497Sru}
1648151497Sru
1649151497Sru
1650151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_set_config(
1651151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
1652151497Sru{
1653151497Sru	char *uuid = cmd, *id;
1654151497Sru	id = os_strchr(uuid, ' ');
1655151497Sru	if (id == NULL)
1656151497Sru		return -1;
1657151497Sru	*id++ = '\0';
1658151497Sru	return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
1659151497Sru}
1660151497Sru
1661151497Sru
1662151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_config(
1663151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
1664151497Sru{
1665151497Sru	char *pin;
1666151497Sru	char *new_ssid;
1667151497Sru	char *new_auth;
1668151497Sru	char *new_encr;
1669151497Sru	char *new_key;
1670151497Sru	struct wps_new_ap_settings ap;
1671151497Sru
1672151497Sru	pin = os_strchr(cmd, ' ');
1673151497Sru	if (pin == NULL)
1674151497Sru		return -1;
1675151497Sru	*pin++ = '\0';
1676151497Sru
1677151497Sru	new_ssid = os_strchr(pin, ' ');
1678151497Sru	if (new_ssid == NULL)
1679151497Sru		return -1;
1680151497Sru	*new_ssid++ = '\0';
1681151497Sru
1682151497Sru	new_auth = os_strchr(new_ssid, ' ');
1683151497Sru	if (new_auth == NULL)
1684151497Sru		return -1;
1685151497Sru	*new_auth++ = '\0';
1686151497Sru
1687151497Sru	new_encr = os_strchr(new_auth, ' ');
1688151497Sru	if (new_encr == NULL)
1689151497Sru		return -1;
1690151497Sru	*new_encr++ = '\0';
1691151497Sru
1692151497Sru	new_key = os_strchr(new_encr, ' ');
1693151497Sru	if (new_key == NULL)
1694151497Sru		return -1;
1695151497Sru	*new_key++ = '\0';
1696151497Sru
1697151497Sru	os_memset(&ap, 0, sizeof(ap));
1698151497Sru	ap.ssid_hex = new_ssid;
1699151497Sru	ap.auth = new_auth;
1700151497Sru	ap.encr = new_encr;
1701151497Sru	ap.key_hex = new_key;
1702151497Sru	return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
1703151497Sru}
1704151497Sru
1705151497Sru
1706151497Sru#ifdef CONFIG_WPS_NFC
1707151497Srustatic int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
1708151497Sru	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
1709151497Sru{
1710151497Sru	int ndef;
1711151497Sru	struct wpabuf *buf;
1712151497Sru	int res;
1713151497Sru	char *uuid;
1714151497Sru
1715151497Sru	uuid = os_strchr(cmd, ' ');
1716151497Sru	if (uuid == NULL)
1717151497Sru		return -1;
1718151497Sru	*uuid++ = '\0';
1719151497Sru
1720151497Sru	if (os_strcmp(cmd, "WPS") == 0)
1721151497Sru		ndef = 0;
1722151497Sru	else if (os_strcmp(cmd, "NDEF") == 0)
1723151497Sru		ndef = 1;
1724151497Sru	else
1725151497Sru		return -1;
1726151497Sru
1727151497Sru	buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
1728151497Sru	if (buf == NULL)
1729151497Sru		return -1;
1730151497Sru
1731151497Sru	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
1732151497Sru					 wpabuf_len(buf));
1733151497Sru	reply[res++] = '\n';
1734151497Sru	reply[res] = '\0';
1735151497Sru
1736151497Sru	wpabuf_free(buf);
1737151497Sru
1738151497Sru	return res;
1739151497Sru}
1740151497Sru#endif /* CONFIG_WPS_NFC */
1741151497Sru#endif /* CONFIG_WPS_ER */
1742151497Sru
1743151497Sru#endif /* CONFIG_WPS */
1744151497Sru
1745151497Sru
1746151497Sru#ifdef CONFIG_IBSS_RSN
1747151497Srustatic int wpa_supplicant_ctrl_iface_ibss_rsn(
1748151497Sru	struct wpa_supplicant *wpa_s, char *addr)
1749151497Sru{
1750151497Sru	u8 peer[ETH_ALEN];
1751151497Sru
1752151497Sru	if (hwaddr_aton(addr, peer)) {
1753151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
1754151497Sru			   "address '%s'", addr);
1755151497Sru		return -1;
1756151497Sru	}
1757151497Sru
1758151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
1759151497Sru		   MAC2STR(peer));
1760151497Sru
1761151497Sru	return ibss_rsn_start(wpa_s->ibss_rsn, peer);
1762151497Sru}
1763151497Sru#endif /* CONFIG_IBSS_RSN */
1764151497Sru
1765151497Sru
1766151497Srustatic int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
1767151497Sru					      char *rsp)
1768151497Sru{
1769151497Sru#ifdef IEEE8021X_EAPOL
1770151497Sru	char *pos, *id_pos;
1771151497Sru	int id;
1772151497Sru	struct wpa_ssid *ssid;
1773151497Sru
1774151497Sru	pos = os_strchr(rsp, '-');
1775151497Sru	if (pos == NULL)
1776151497Sru		return -1;
1777151497Sru	*pos++ = '\0';
1778151497Sru	id_pos = pos;
1779151497Sru	pos = os_strchr(pos, ':');
1780151497Sru	if (pos == NULL)
1781151497Sru		return -1;
1782151497Sru	*pos++ = '\0';
1783151497Sru	id = atoi(id_pos);
1784151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
1785151497Sru	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
1786151497Sru			      (u8 *) pos, os_strlen(pos));
1787151497Sru
1788151497Sru	ssid = wpa_config_get_network(wpa_s->conf, id);
1789151497Sru	if (ssid == NULL) {
1790151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
1791151497Sru			   "to update", id);
1792151497Sru		return -1;
1793151497Sru	}
1794151497Sru
1795151497Sru	return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
1796151497Sru							 pos);
1797151497Sru#else /* IEEE8021X_EAPOL */
1798151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
1799151497Sru	return -1;
1800151497Sru#endif /* IEEE8021X_EAPOL */
1801151497Sru}
1802151497Sru
1803151497Sru
1804151497Srustatic int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
1805151497Sru					    const char *params,
1806151497Sru					    char *buf, size_t buflen)
1807151497Sru{
1808151497Sru	char *pos, *end, tmp[30];
1809151497Sru	int res, verbose, wps, ret;
1810151497Sru#ifdef CONFIG_HS20
1811151497Sru	const u8 *hs20;
1812151497Sru#endif /* CONFIG_HS20 */
1813151497Sru	const u8 *sess_id;
1814151497Sru	size_t sess_id_len;
1815151497Sru
1816151497Sru	if (os_strcmp(params, "-DRIVER") == 0)
1817151497Sru		return wpa_drv_status(wpa_s, buf, buflen);
1818151497Sru	verbose = os_strcmp(params, "-VERBOSE") == 0;
1819151497Sru	wps = os_strcmp(params, "-WPS") == 0;
1820151497Sru	pos = buf;
1821151497Sru	end = buf + buflen;
1822151497Sru	if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
1823151497Sru		struct wpa_ssid *ssid = wpa_s->current_ssid;
1824151497Sru		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
1825151497Sru				  MAC2STR(wpa_s->bssid));
1826151497Sru		if (os_snprintf_error(end - pos, ret))
1827151497Sru			return pos - buf;
1828151497Sru		pos += ret;
1829151497Sru		ret = os_snprintf(pos, end - pos, "freq=%u\n",
1830151497Sru				  wpa_s->assoc_freq);
1831151497Sru		if (os_snprintf_error(end - pos, ret))
1832151497Sru			return pos - buf;
1833151497Sru		pos += ret;
1834151497Sru		if (ssid) {
1835151497Sru			u8 *_ssid = ssid->ssid;
1836151497Sru			size_t ssid_len = ssid->ssid_len;
1837151497Sru			u8 ssid_buf[SSID_MAX_LEN];
1838151497Sru			if (ssid_len == 0) {
1839151497Sru				int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
1840151497Sru				if (_res < 0)
1841151497Sru					ssid_len = 0;
1842151497Sru				else
1843151497Sru					ssid_len = _res;
1844151497Sru				_ssid = ssid_buf;
1845151497Sru			}
1846151497Sru			ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
1847151497Sru					  wpa_ssid_txt(_ssid, ssid_len),
1848151497Sru					  ssid->id);
1849151497Sru			if (os_snprintf_error(end - pos, ret))
1850151497Sru				return pos - buf;
1851151497Sru			pos += ret;
1852151497Sru
1853151497Sru			if (wps && ssid->passphrase &&
1854151497Sru			    wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
1855151497Sru			    (ssid->mode == WPAS_MODE_AP ||
1856151497Sru			     ssid->mode == WPAS_MODE_P2P_GO)) {
1857151497Sru				ret = os_snprintf(pos, end - pos,
1858151497Sru						  "passphrase=%s\n",
1859151497Sru						  ssid->passphrase);
1860151497Sru				if (os_snprintf_error(end - pos, ret))
1861151497Sru					return pos - buf;
1862151497Sru				pos += ret;
1863151497Sru			}
1864151497Sru			if (ssid->id_str) {
1865151497Sru				ret = os_snprintf(pos, end - pos,
1866151497Sru						  "id_str=%s\n",
1867151497Sru						  ssid->id_str);
1868151497Sru				if (os_snprintf_error(end - pos, ret))
1869151497Sru					return pos - buf;
1870151497Sru				pos += ret;
1871151497Sru			}
1872151497Sru
1873151497Sru			switch (ssid->mode) {
1874151497Sru			case WPAS_MODE_INFRA:
1875151497Sru				ret = os_snprintf(pos, end - pos,
1876151497Sru						  "mode=station\n");
1877151497Sru				break;
1878151497Sru			case WPAS_MODE_IBSS:
1879151497Sru				ret = os_snprintf(pos, end - pos,
1880151497Sru						  "mode=IBSS\n");
1881151497Sru				break;
1882151497Sru			case WPAS_MODE_AP:
1883151497Sru				ret = os_snprintf(pos, end - pos,
1884151497Sru						  "mode=AP\n");
1885151497Sru				break;
1886151497Sru			case WPAS_MODE_P2P_GO:
1887151497Sru				ret = os_snprintf(pos, end - pos,
1888151497Sru						  "mode=P2P GO\n");
1889151497Sru				break;
1890151497Sru			case WPAS_MODE_P2P_GROUP_FORMATION:
1891151497Sru				ret = os_snprintf(pos, end - pos,
1892151497Sru						  "mode=P2P GO - group "
1893151497Sru						  "formation\n");
1894151497Sru				break;
1895151497Sru			case WPAS_MODE_MESH:
1896151497Sru				ret = os_snprintf(pos, end - pos,
1897151497Sru						  "mode=mesh\n");
1898151497Sru				break;
1899151497Sru			default:
1900151497Sru				ret = 0;
1901151497Sru				break;
1902151497Sru			}
1903151497Sru			if (os_snprintf_error(end - pos, ret))
1904151497Sru				return pos - buf;
1905151497Sru			pos += ret;
1906151497Sru		}
1907151497Sru
1908151497Sru#ifdef CONFIG_AP
1909151497Sru		if (wpa_s->ap_iface) {
1910151497Sru			pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
1911151497Sru							    end - pos,
1912151497Sru							    verbose);
1913151497Sru		} else
1914151497Sru#endif /* CONFIG_AP */
1915151497Sru		pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
1916151497Sru	}
1917151497Sru#ifdef CONFIG_SAE
1918151497Sru	if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
1919151497Sru#ifdef CONFIG_AP
1920151497Sru	    !wpa_s->ap_iface &&
1921151497Sru#endif /* CONFIG_AP */
1922151497Sru	    wpa_s->sme.sae.state == SAE_ACCEPTED) {
1923151497Sru		ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
1924151497Sru				  wpa_s->sme.sae.group);
1925151497Sru		if (os_snprintf_error(end - pos, ret))
1926151497Sru			return pos - buf;
1927151497Sru		pos += ret;
1928151497Sru	}
1929151497Sru#endif /* CONFIG_SAE */
1930151497Sru	ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
1931151497Sru			  wpa_supplicant_state_txt(wpa_s->wpa_state));
1932151497Sru	if (os_snprintf_error(end - pos, ret))
1933151497Sru		return pos - buf;
1934151497Sru	pos += ret;
1935151497Sru
1936151497Sru	if (wpa_s->l2 &&
1937114402Sru	    l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
1938114402Sru		ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
1939114402Sru		if (os_snprintf_error(end - pos, ret))
1940114402Sru			return pos - buf;
1941114402Sru		pos += ret;
1942114402Sru	}
1943114402Sru
1944114402Sru#ifdef CONFIG_P2P
1945114402Sru	if (wpa_s->global->p2p) {
1946114402Sru		ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
1947114402Sru				  "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
1948114402Sru		if (os_snprintf_error(end - pos, ret))
1949114402Sru			return pos - buf;
1950114402Sru		pos += ret;
1951114402Sru	}
1952114402Sru#endif /* CONFIG_P2P */
1953114402Sru
1954114402Sru	ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
1955114402Sru			  MAC2STR(wpa_s->own_addr));
1956114402Sru	if (os_snprintf_error(end - pos, ret))
1957114402Sru		return pos - buf;
1958114402Sru	pos += ret;
1959114402Sru
1960114402Sru#ifdef CONFIG_HS20
1961114402Sru	if (wpa_s->current_bss &&
1962114402Sru	    (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss,
1963114402Sru					  HS20_IE_VENDOR_TYPE)) &&
1964114402Sru	    wpa_s->wpa_proto == WPA_PROTO_RSN &&
1965114402Sru	    wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
1966114402Sru		int release = 1;
1967114402Sru		if (hs20[1] >= 5) {
1968114402Sru			u8 rel_num = (hs20[6] & 0xf0) >> 4;
1969114402Sru			release = rel_num + 1;
1970114402Sru		}
1971114402Sru		ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
1972114402Sru		if (os_snprintf_error(end - pos, ret))
1973114402Sru			return pos - buf;
1974114402Sru		pos += ret;
1975114402Sru	}
1976114402Sru
1977114402Sru	if (wpa_s->current_ssid) {
1978114402Sru		struct wpa_cred *cred;
1979114402Sru		char *type;
1980151497Sru
1981151497Sru		for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1982151497Sru			size_t i;
1983114402Sru
1984114402Sru			if (wpa_s->current_ssid->parent_cred != cred)
1985114402Sru				continue;
1986114402Sru
1987151497Sru			if (cred->provisioning_sp) {
1988151497Sru				ret = os_snprintf(pos, end - pos,
1989151497Sru						  "provisioning_sp=%s\n",
1990151497Sru						  cred->provisioning_sp);
1991151497Sru				if (os_snprintf_error(end - pos, ret))
1992151497Sru					return pos - buf;
1993151497Sru				pos += ret;
1994151497Sru			}
1995151497Sru
1996151497Sru			if (!cred->domain)
1997151497Sru				goto no_domain;
1998151497Sru
1999151497Sru			i = 0;
2000114402Sru			if (wpa_s->current_bss && wpa_s->current_bss->anqp) {
2001114402Sru				struct wpabuf *names =
2002114402Sru					wpa_s->current_bss->anqp->domain_name;
2003114402Sru				for (i = 0; names && i < cred->num_domain; i++)
2004114402Sru				{
2005114402Sru					if (domain_name_list_contains(
2006114402Sru						    names, cred->domain[i], 1))
2007114402Sru						break;
2008114402Sru				}
2009114402Sru				if (i == cred->num_domain)
2010114402Sru					i = 0; /* show first entry by default */
2011114402Sru			}
2012114402Sru			ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
2013114402Sru					  cred->domain[i]);
2014114402Sru			if (os_snprintf_error(end - pos, ret))
2015114402Sru				return pos - buf;
2016114402Sru			pos += ret;
2017114402Sru
2018114402Sru		no_domain:
2019114402Sru			if (wpa_s->current_bss == NULL ||
2020114402Sru			    wpa_s->current_bss->anqp == NULL)
2021114402Sru				res = -1;
2022114402Sru			else
2023114402Sru				res = interworking_home_sp_cred(
2024114402Sru					wpa_s, cred,
2025151497Sru					wpa_s->current_bss->anqp->domain_name);
2026114402Sru			if (res > 0)
2027114402Sru				type = "home";
2028114402Sru			else if (res == 0)
2029114402Sru				type = "roaming";
2030151497Sru			else
2031114402Sru				type = "unknown";
2032151497Sru
2033114402Sru			ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
2034114402Sru			if (os_snprintf_error(end - pos, ret))
2035114402Sru				return pos - buf;
2036151497Sru			pos += ret;
2037114402Sru
2038114402Sru			break;
2039114402Sru		}
2040114402Sru	}
2041114402Sru#endif /* CONFIG_HS20 */
2042114402Sru
2043114402Sru	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
2044114402Sru	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
2045114402Sru		res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
2046114402Sru					  verbose);
2047114402Sru		if (res >= 0)
2048114402Sru			pos += res;
2049114402Sru	}
2050114402Sru
2051114402Sru	sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
2052114402Sru	if (sess_id) {
2053151497Sru		char *start = pos;
2054151497Sru
2055151497Sru		ret = os_snprintf(pos, end - pos, "eap_session_id=");
2056114402Sru		if (os_snprintf_error(end - pos, ret))
2057114402Sru			return start - buf;
2058114402Sru		pos += ret;
2059114402Sru		ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len);
2060114402Sru		if (ret <= 0)
2061114402Sru			return start - buf;
2062114402Sru		pos += ret;
2063114402Sru		ret = os_snprintf(pos, end - pos, "\n");
2064114402Sru		if (os_snprintf_error(end - pos, ret))
2065114402Sru			return start - buf;
2066114402Sru		pos += ret;
2067114402Sru	}
2068114402Sru
2069114402Sru	res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
2070114402Sru	if (res >= 0)
2071114402Sru		pos += res;
2072114402Sru
2073114402Sru#ifdef CONFIG_WPS
2074114402Sru	{
2075114402Sru		char uuid_str[100];
2076114402Sru		uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
2077114402Sru		ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
2078114402Sru		if (os_snprintf_error(end - pos, ret))
2079114402Sru			return pos - buf;
2080114402Sru		pos += ret;
2081114402Sru	}
2082114402Sru#endif /* CONFIG_WPS */
2083114402Sru
2084114402Sru#ifdef ANDROID
2085114402Sru	/*
2086151497Sru	 * Allow using the STATUS command with default behavior, say for debug,
2087151497Sru	 * i.e., don't generate a "fake" CONNECTION and SUPPLICANT_STATE_CHANGE
2088151497Sru	 * events with STATUS-NO_EVENTS.
2089151497Sru	 */
2090151497Sru	if (os_strcmp(params, "-NO_EVENTS")) {
2091151497Sru		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
2092151497Sru			     "id=%d state=%d BSSID=" MACSTR " SSID=%s",
2093151497Sru			     wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
2094151497Sru			     wpa_s->wpa_state,
2095151497Sru			     MAC2STR(wpa_s->bssid),
2096151497Sru			     wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
2097151497Sru			     wpa_ssid_txt(wpa_s->current_ssid->ssid,
2098114402Sru					  wpa_s->current_ssid->ssid_len) : "");
2099114402Sru		if (wpa_s->wpa_state == WPA_COMPLETED) {
2100114402Sru			struct wpa_ssid *ssid = wpa_s->current_ssid;
2101114402Sru			wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
2102114402Sru				     "- connection to " MACSTR
2103114402Sru				     " completed %s [id=%d id_str=%s]",
2104114402Sru				     MAC2STR(wpa_s->bssid), "(auth)",
2105151497Sru				     ssid ? ssid->id : -1,
2106151497Sru				     ssid && ssid->id_str ? ssid->id_str : "");
2107114402Sru		}
2108114402Sru	}
2109114402Sru#endif /* ANDROID */
2110114402Sru
2111151497Sru	return pos - buf;
2112114402Sru}
2113114402Sru
2114114402Sru
2115114402Srustatic int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
2116114402Sru					   char *cmd)
2117114402Sru{
2118114402Sru	char *pos;
2119114402Sru	int id;
2120114402Sru	struct wpa_ssid *ssid;
2121114402Sru	u8 bssid[ETH_ALEN];
2122114402Sru
2123114402Sru	/* cmd: "<network id> <BSSID>" */
2124114402Sru	pos = os_strchr(cmd, ' ');
2125114402Sru	if (pos == NULL)
2126114402Sru		return -1;
2127114402Sru	*pos++ = '\0';
2128114402Sru	id = atoi(cmd);
2129114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
2130114402Sru	if (hwaddr_aton(pos, bssid)) {
2131114402Sru		wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
2132114402Sru		return -1;
2133114402Sru	}
2134114402Sru
2135114402Sru	ssid = wpa_config_get_network(wpa_s->conf, id);
2136114402Sru	if (ssid == NULL) {
2137114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
2138114402Sru			   "to update", id);
2139114402Sru		return -1;
2140114402Sru	}
2141114402Sru
2142114402Sru	os_memcpy(ssid->bssid, bssid, ETH_ALEN);
2143114402Sru	ssid->bssid_set = !is_zero_ether_addr(bssid);
2144114402Sru
2145114402Sru	return 0;
2146114402Sru}
2147114402Sru
2148114402Sru
2149114402Srustatic int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
2150114402Sru					       char *cmd, char *buf,
2151114402Sru					       size_t buflen)
2152114402Sru{
2153114402Sru	u8 bssid[ETH_ALEN];
2154114402Sru	struct wpa_blacklist *e;
2155114402Sru	char *pos, *end;
2156114402Sru	int ret;
2157114402Sru
2158114402Sru	/* cmd: "BLACKLIST [<BSSID>]" */
2159114402Sru	if (*cmd == '\0') {
2160114402Sru		pos = buf;
2161114402Sru		end = buf + buflen;
2162114402Sru		e = wpa_s->blacklist;
2163114402Sru		while (e) {
2164114402Sru			ret = os_snprintf(pos, end - pos, MACSTR "\n",
2165114402Sru					  MAC2STR(e->bssid));
2166114402Sru			if (os_snprintf_error(end - pos, ret))
2167114402Sru				return pos - buf;
2168114402Sru			pos += ret;
2169114402Sru			e = e->next;
2170114402Sru		}
2171114402Sru		return pos - buf;
2172114402Sru	}
2173114402Sru
2174114402Sru	cmd++;
2175114402Sru	if (os_strncmp(cmd, "clear", 5) == 0) {
2176114402Sru		wpa_blacklist_clear(wpa_s);
2177114402Sru		os_memcpy(buf, "OK\n", 3);
2178151497Sru		return 3;
2179151497Sru	}
2180151497Sru
2181151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
2182151497Sru	if (hwaddr_aton(cmd, bssid)) {
2183151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
2184151497Sru		return -1;
2185151497Sru	}
2186151497Sru
2187151497Sru	/*
2188151497Sru	 * Add the BSSID twice, so its count will be 2, causing it to be
2189151497Sru	 * skipped when processing scan results.
2190151497Sru	 */
2191151497Sru	ret = wpa_blacklist_add(wpa_s, bssid);
2192151497Sru	if (ret < 0)
2193151497Sru		return -1;
2194151497Sru	ret = wpa_blacklist_add(wpa_s, bssid);
2195151497Sru	if (ret < 0)
2196114402Sru		return -1;
2197114402Sru	os_memcpy(buf, "OK\n", 3);
2198114402Sru	return 3;
2199114402Sru}
2200114402Sru
2201114402Sru
2202114402Srustatic int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
2203114402Sru					       char *cmd, char *buf,
2204114402Sru					       size_t buflen)
2205114402Sru{
2206151497Sru	char *pos, *end, *stamp;
2207151497Sru	int ret;
2208114402Sru
2209151497Sru	/* cmd: "LOG_LEVEL [<level>]" */
2210114402Sru	if (*cmd == '\0') {
2211114402Sru		pos = buf;
2212114402Sru		end = buf + buflen;
2213151497Sru		ret = os_snprintf(pos, end - pos, "Current level: %s\n"
2214114402Sru				  "Timestamp: %d\n",
2215114402Sru				  debug_level_str(wpa_debug_level),
2216151497Sru				  wpa_debug_timestamp);
2217114402Sru		if (os_snprintf_error(end - pos, ret))
2218114402Sru			ret = 0;
2219151497Sru
2220114402Sru		return ret;
2221114402Sru	}
2222114402Sru
2223114402Sru	while (*cmd == ' ')
2224114402Sru		cmd++;
2225114402Sru
2226114402Sru	stamp = os_strchr(cmd, ' ');
2227114402Sru	if (stamp) {
2228151497Sru		*stamp++ = '\0';
2229151497Sru		while (*stamp == ' ') {
2230114402Sru			stamp++;
2231114402Sru		}
2232114402Sru	}
2233114402Sru
2234151497Sru	if (os_strlen(cmd)) {
2235151497Sru		int level = str_to_debug_level(cmd);
2236151497Sru		if (level < 0)
2237151497Sru			return -1;
2238151497Sru		wpa_debug_level = level;
2239151497Sru	}
2240151497Sru
2241151497Sru	if (stamp && os_strlen(stamp))
2242151497Sru		wpa_debug_timestamp = atoi(stamp);
2243151497Sru
2244151497Sru	os_memcpy(buf, "OK\n", 3);
2245151497Sru	return 3;
2246151497Sru}
2247151497Sru
2248114402Sru
2249114402Srustatic int wpa_supplicant_ctrl_iface_list_networks(
2250114402Sru	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
2251114402Sru{
2252114402Sru	char *pos, *end, *prev;
2253151497Sru	struct wpa_ssid *ssid;
2254151497Sru	int ret;
2255114402Sru
2256114402Sru	pos = buf;
2257114402Sru	end = buf + buflen;
2258151497Sru	ret = os_snprintf(pos, end - pos,
2259114402Sru			  "network id / ssid / bssid / flags\n");
2260114402Sru	if (os_snprintf_error(end - pos, ret))
2261114402Sru		return pos - buf;
2262114402Sru	pos += ret;
2263114402Sru
2264114402Sru	ssid = wpa_s->conf->ssid;
2265114402Sru
2266114402Sru	/* skip over ssids until we find next one */
2267114402Sru	if (cmd != NULL && os_strncmp(cmd, "LAST_ID=", 8) == 0) {
2268151497Sru		int last_id = atoi(cmd + 8);
2269114402Sru		if (last_id != -1) {
2270114402Sru			while (ssid != NULL && ssid->id <= last_id) {
2271114402Sru				ssid = ssid->next;
2272114402Sru			}
2273114402Sru		}
2274114402Sru	}
2275114402Sru
2276114402Sru	while (ssid) {
2277114402Sru		prev = pos;
2278151497Sru		ret = os_snprintf(pos, end - pos, "%d\t%s",
2279114402Sru				  ssid->id,
2280114402Sru				  wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
2281114402Sru		if (os_snprintf_error(end - pos, ret))
2282114402Sru			return prev - buf;
2283114402Sru		pos += ret;
2284114402Sru		if (ssid->bssid_set) {
2285114402Sru			ret = os_snprintf(pos, end - pos, "\t" MACSTR,
2286114402Sru					  MAC2STR(ssid->bssid));
2287114402Sru		} else {
2288114402Sru			ret = os_snprintf(pos, end - pos, "\tany");
2289114402Sru		}
2290114402Sru		if (os_snprintf_error(end - pos, ret))
2291114402Sru			return prev - buf;
2292114402Sru		pos += ret;
2293114402Sru		ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
2294114402Sru				  ssid == wpa_s->current_ssid ?
2295114402Sru				  "[CURRENT]" : "",
2296114402Sru				  ssid->disabled ? "[DISABLED]" : "",
2297114402Sru				  ssid->disabled_until.sec ?
2298114402Sru				  "[TEMP-DISABLED]" : "",
2299114402Sru				  ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
2300114402Sru				  "");
2301114402Sru		if (os_snprintf_error(end - pos, ret))
2302114402Sru			return prev - buf;
2303114402Sru		pos += ret;
2304114402Sru		ret = os_snprintf(pos, end - pos, "\n");
2305114402Sru		if (os_snprintf_error(end - pos, ret))
2306114402Sru			return prev - buf;
2307114402Sru		pos += ret;
2308114402Sru
2309114402Sru		ssid = ssid->next;
2310114402Sru	}
2311114402Sru
2312114402Sru	return pos - buf;
2313114402Sru}
2314114402Sru
2315114402Sru
2316151497Srustatic char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
2317151497Sru{
2318114402Sru	int ret;
2319114402Sru	ret = os_snprintf(pos, end - pos, "-");
2320114402Sru	if (os_snprintf_error(end - pos, ret))
2321114402Sru		return pos;
2322114402Sru	pos += ret;
2323114402Sru	ret = wpa_write_ciphers(pos, end, cipher, "+");
2324114402Sru	if (ret < 0)
2325114402Sru		return pos;
2326114402Sru	pos += ret;
2327114402Sru	return pos;
2328114402Sru}
2329114402Sru
2330114402Sru
2331114402Srustatic char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
2332114402Sru				    const u8 *ie, size_t ie_len)
2333114402Sru{
2334114402Sru	struct wpa_ie_data data;
2335114402Sru	char *start;
2336114402Sru	int ret;
2337114402Sru
2338114402Sru	ret = os_snprintf(pos, end - pos, "[%s-", proto);
2339114402Sru	if (os_snprintf_error(end - pos, ret))
2340114402Sru		return pos;
2341114402Sru	pos += ret;
2342114402Sru
2343114402Sru	if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
2344114402Sru		ret = os_snprintf(pos, end - pos, "?]");
2345114402Sru		if (os_snprintf_error(end - pos, ret))
2346114402Sru			return pos;
2347114402Sru		pos += ret;
2348114402Sru		return pos;
2349114402Sru	}
2350114402Sru
2351114402Sru	start = pos;
2352114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
2353114402Sru		ret = os_snprintf(pos, end - pos, "%sEAP",
2354114402Sru				  pos == start ? "" : "+");
2355114402Sru		if (os_snprintf_error(end - pos, ret))
2356114402Sru			return pos;
2357114402Sru		pos += ret;
2358114402Sru	}
2359114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
2360114402Sru		ret = os_snprintf(pos, end - pos, "%sPSK",
2361114402Sru				  pos == start ? "" : "+");
2362114402Sru		if (os_snprintf_error(end - pos, ret))
2363114402Sru			return pos;
2364114402Sru		pos += ret;
2365114402Sru	}
2366114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
2367114402Sru		ret = os_snprintf(pos, end - pos, "%sNone",
2368114402Sru				  pos == start ? "" : "+");
2369114402Sru		if (os_snprintf_error(end - pos, ret))
2370114402Sru			return pos;
2371114402Sru		pos += ret;
2372114402Sru	}
2373114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
2374114402Sru		ret = os_snprintf(pos, end - pos, "%sSAE",
2375114402Sru				  pos == start ? "" : "+");
2376114402Sru		if (os_snprintf_error(end - pos, ret))
2377114402Sru			return pos;
2378114402Sru		pos += ret;
2379114402Sru	}
2380114402Sru#ifdef CONFIG_IEEE80211R
2381114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
2382114402Sru		ret = os_snprintf(pos, end - pos, "%sFT/EAP",
2383114402Sru				  pos == start ? "" : "+");
2384114402Sru		if (os_snprintf_error(end - pos, ret))
2385114402Sru			return pos;
2386114402Sru		pos += ret;
2387151497Sru	}
2388114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
2389114402Sru		ret = os_snprintf(pos, end - pos, "%sFT/PSK",
2390114402Sru				  pos == start ? "" : "+");
2391114402Sru		if (os_snprintf_error(end - pos, ret))
2392114402Sru			return pos;
2393151497Sru		pos += ret;
2394151497Sru	}
2395151497Sru	if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
2396151497Sru		ret = os_snprintf(pos, end - pos, "%sFT/SAE",
2397114402Sru				  pos == start ? "" : "+");
2398114402Sru		if (os_snprintf_error(end - pos, ret))
2399114402Sru			return pos;
2400114402Sru		pos += ret;
2401114402Sru	}
2402114402Sru#endif /* CONFIG_IEEE80211R */
2403114402Sru#ifdef CONFIG_IEEE80211W
2404114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
2405114402Sru		ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
2406114402Sru				  pos == start ? "" : "+");
2407114402Sru		if (os_snprintf_error(end - pos, ret))
2408114402Sru			return pos;
2409114402Sru		pos += ret;
2410151497Sru	}
2411151497Sru	if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
2412114402Sru		ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
2413114402Sru				  pos == start ? "" : "+");
2414114402Sru		if (os_snprintf_error(end - pos, ret))
2415114402Sru			return pos;
2416114402Sru		pos += ret;
2417114402Sru	}
2418114402Sru#endif /* CONFIG_IEEE80211W */
2419151497Sru
2420151497Sru#ifdef CONFIG_SUITEB
2421114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
2422114402Sru		ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
2423114402Sru				  pos == start ? "" : "+");
2424114402Sru		if (os_snprintf_error(end - pos, ret))
2425114402Sru			return pos;
2426114402Sru		pos += ret;
2427114402Sru	}
2428114402Sru#endif /* CONFIG_SUITEB */
2429114402Sru
2430114402Sru#ifdef CONFIG_SUITEB192
2431114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
2432114402Sru		ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
2433114402Sru				  pos == start ? "" : "+");
2434114402Sru		if (os_snprintf_error(end - pos, ret))
2435114402Sru			return pos;
2436114402Sru		pos += ret;
2437114402Sru	}
2438114402Sru#endif /* CONFIG_SUITEB192 */
2439114402Sru
2440114402Sru	if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
2441114402Sru		ret = os_snprintf(pos, end - pos, "%sOSEN",
2442114402Sru				  pos == start ? "" : "+");
2443114402Sru		if (os_snprintf_error(end - pos, ret))
2444114402Sru			return pos;
2445114402Sru		pos += ret;
2446114402Sru	}
2447114402Sru
2448151497Sru	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
2449114402Sru
2450114402Sru	if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
2451114402Sru		ret = os_snprintf(pos, end - pos, "-preauth");
2452114402Sru		if (os_snprintf_error(end - pos, ret))
2453114402Sru			return pos;
2454114402Sru		pos += ret;
2455114402Sru	}
2456114402Sru
2457114402Sru	ret = os_snprintf(pos, end - pos, "]");
2458114402Sru	if (os_snprintf_error(end - pos, ret))
2459114402Sru		return pos;
2460114402Sru	pos += ret;
2461114402Sru
2462114402Sru	return pos;
2463114402Sru}
2464114402Sru
2465114402Sru
2466114402Sru#ifdef CONFIG_WPS
2467114402Srustatic char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
2468114402Sru					    char *pos, char *end,
2469114402Sru					    struct wpabuf *wps_ie)
2470114402Sru{
2471114402Sru	int ret;
2472114402Sru	const char *txt;
2473114402Sru
2474114402Sru	if (wps_ie == NULL)
2475114402Sru		return pos;
2476114402Sru	if (wps_is_selected_pbc_registrar(wps_ie))
2477114402Sru		txt = "[WPS-PBC]";
2478114402Sru	else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
2479114402Sru		txt = "[WPS-AUTH]";
2480114402Sru	else if (wps_is_selected_pin_registrar(wps_ie))
2481114402Sru		txt = "[WPS-PIN]";
2482114402Sru	else
2483114402Sru		txt = "[WPS]";
2484114402Sru
2485114402Sru	ret = os_snprintf(pos, end - pos, "%s", txt);
2486114402Sru	if (!os_snprintf_error(end - pos, ret))
2487114402Sru		pos += ret;
2488151497Sru	wpabuf_free(wps_ie);
2489151497Sru	return pos;
2490151497Sru}
2491151497Sru#endif /* CONFIG_WPS */
2492151497Sru
2493151497Sru
2494151497Srustatic char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
2495151497Sru					char *pos, char *end,
2496151497Sru					const struct wpa_bss *bss)
2497151497Sru{
2498151497Sru#ifdef CONFIG_WPS
2499151497Sru	struct wpabuf *wps_ie;
2500151497Sru	wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
2501151497Sru	return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
2502151497Sru#else /* CONFIG_WPS */
2503151497Sru	return pos;
2504151497Sru#endif /* CONFIG_WPS */
2505114402Sru}
2506114402Sru
2507114402Sru
2508114402Sru/* Format one result on one text line into a buffer. */
2509114402Srustatic int wpa_supplicant_ctrl_iface_scan_result(
2510114402Sru	struct wpa_supplicant *wpa_s,
2511114402Sru	const struct wpa_bss *bss, char *buf, size_t buflen)
2512114402Sru{
2513114402Sru	char *pos, *end;
2514114402Sru	int ret;
2515114402Sru	const u8 *ie, *ie2, *osen_ie, *p2p, *mesh;
2516114402Sru
2517114402Sru	mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
2518114402Sru	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
2519114402Sru	if (!p2p)
2520114402Sru		p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
2521114402Sru	if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
2522151497Sru	    os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
2523151497Sru	    0)
2524151497Sru		return 0; /* Do not show P2P listen discovery results here */
2525151497Sru
2526114402Sru	pos = buf;
2527114402Sru	end = buf + buflen;
2528114402Sru
2529114402Sru	ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
2530114402Sru			  MAC2STR(bss->bssid), bss->freq, bss->level);
2531114402Sru	if (os_snprintf_error(end - pos, ret))
2532114402Sru		return -1;
2533114402Sru	pos += ret;
2534114402Sru	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
2535114402Sru	if (ie)
2536151497Sru		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
2537114402Sru	ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
2538114402Sru	if (ie2) {
2539114402Sru		pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
2540114402Sru					    ie2, 2 + ie2[1]);
2541114402Sru	}
2542151497Sru	osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
2543114402Sru	if (osen_ie)
2544114402Sru		pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
2545114402Sru					    osen_ie, 2 + osen_ie[1]);
2546114402Sru	pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
2547114402Sru	if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {
2548114402Sru		ret = os_snprintf(pos, end - pos, "[WEP]");
2549151497Sru		if (os_snprintf_error(end - pos, ret))
2550114402Sru			return -1;
2551114402Sru		pos += ret;
2552114402Sru	}
2553114402Sru	if (mesh) {
2554151497Sru		ret = os_snprintf(pos, end - pos, "[MESH]");
2555151497Sru		if (os_snprintf_error(end - pos, ret))
2556151497Sru			return -1;
2557151497Sru		pos += ret;
2558151497Sru	}
2559151497Sru	if (bss_is_dmg(bss)) {
2560151497Sru		const char *s;
2561151497Sru		ret = os_snprintf(pos, end - pos, "[DMG]");
2562114402Sru		if (os_snprintf_error(end - pos, ret))
2563151497Sru			return -1;
2564114402Sru		pos += ret;
2565151497Sru		switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
2566114402Sru		case IEEE80211_CAP_DMG_IBSS:
2567114402Sru			s = "[IBSS]";
2568151497Sru			break;
2569114402Sru		case IEEE80211_CAP_DMG_AP:
2570114402Sru			s = "[ESS]";
2571114402Sru			break;
2572114402Sru		case IEEE80211_CAP_DMG_PBSS:
2573114402Sru			s = "[PBSS]";
2574151497Sru			break;
2575114402Sru		default:
2576114402Sru			s = "";
2577114402Sru			break;
2578114402Sru		}
2579114402Sru		ret = os_snprintf(pos, end - pos, "%s", s);
2580114402Sru		if (os_snprintf_error(end - pos, ret))
2581114402Sru			return -1;
2582114402Sru		pos += ret;
2583114402Sru	} else {
2584114402Sru		if (bss->caps & IEEE80211_CAP_IBSS) {
2585114402Sru			ret = os_snprintf(pos, end - pos, "[IBSS]");
2586114402Sru			if (os_snprintf_error(end - pos, ret))
2587114402Sru				return -1;
2588114402Sru			pos += ret;
2589114402Sru		}
2590114402Sru		if (bss->caps & IEEE80211_CAP_ESS) {
2591114402Sru			ret = os_snprintf(pos, end - pos, "[ESS]");
2592114402Sru			if (os_snprintf_error(end - pos, ret))
2593114402Sru				return -1;
2594114402Sru			pos += ret;
2595114402Sru		}
2596114402Sru	}
2597114402Sru	if (p2p) {
2598114402Sru		ret = os_snprintf(pos, end - pos, "[P2P]");
2599114402Sru		if (os_snprintf_error(end - pos, ret))
2600114402Sru			return -1;
2601114402Sru		pos += ret;
2602114402Sru	}
2603114402Sru#ifdef CONFIG_HS20
2604114402Sru	if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
2605114402Sru		ret = os_snprintf(pos, end - pos, "[HS20]");
2606114402Sru		if (os_snprintf_error(end - pos, ret))
2607114402Sru			return -1;
2608114402Sru		pos += ret;
2609114402Sru	}
2610114402Sru#endif /* CONFIG_HS20 */
2611114402Sru#ifdef CONFIG_FST
2612114402Sru	if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) {
2613114402Sru		ret = os_snprintf(pos, end - pos, "[FST]");
2614114402Sru		if (os_snprintf_error(end - pos, ret))
2615114402Sru			return -1;
2616114402Sru		pos += ret;
2617114402Sru	}
2618114402Sru#endif /* CONFIG_FST */
2619114402Sru
2620114402Sru	ret = os_snprintf(pos, end - pos, "\t%s",
2621114402Sru			  wpa_ssid_txt(bss->ssid, bss->ssid_len));
2622114402Sru	if (os_snprintf_error(end - pos, ret))
2623114402Sru		return -1;
2624151497Sru	pos += ret;
2625151497Sru
2626114402Sru	ret = os_snprintf(pos, end - pos, "\n");
2627114402Sru	if (os_snprintf_error(end - pos, ret))
2628114402Sru		return -1;
2629114402Sru	pos += ret;
2630114402Sru
2631114402Sru	return pos - buf;
2632114402Sru}
2633114402Sru
2634151497Sru
2635151497Srustatic int wpa_supplicant_ctrl_iface_scan_results(
2636114402Sru	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2637114402Sru{
2638114402Sru	char *pos, *end;
2639151497Sru	struct wpa_bss *bss;
2640151497Sru	int ret;
2641151497Sru
2642151497Sru	pos = buf;
2643151497Sru	end = buf + buflen;
2644151497Sru	ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
2645151497Sru			  "flags / ssid\n");
2646151497Sru	if (os_snprintf_error(end - pos, ret))
2647151497Sru		return pos - buf;
2648151497Sru	pos += ret;
2649151497Sru
2650151497Sru	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
2651114402Sru		ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
2652114402Sru							    end - pos);
2653114402Sru		if (ret < 0 || ret >= end - pos)
2654114402Sru			return pos - buf;
2655114402Sru		pos += ret;
2656151497Sru	}
2657151497Sru
2658114402Sru	return pos - buf;
2659114402Sru}
2660114402Sru
2661114402Sru
2662114402Sru#ifdef CONFIG_MESH
2663114402Sru
2664114402Srustatic int wpa_supplicant_ctrl_iface_mesh_interface_add(
2665114402Sru	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
2666114402Sru{
2667151497Sru	char *pos, ifname[IFNAMSIZ + 1];
2668151497Sru
2669151497Sru	ifname[0] = '\0';
2670151497Sru
2671151497Sru	pos = os_strstr(cmd, "ifname=");
2672151497Sru	if (pos) {
2673114402Sru		pos += 7;
2674114402Sru		os_strlcpy(ifname, pos, sizeof(ifname));
2675114402Sru	}
2676114402Sru
2677114402Sru	if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
2678114402Sru		return -1;
2679114402Sru
2680114402Sru	os_strlcpy(reply, ifname, max_len);
2681114402Sru	return os_strlen(ifname);
2682114402Sru}
2683114402Sru
2684114402Sru
2685114402Srustatic int wpa_supplicant_ctrl_iface_mesh_group_add(
2686114402Sru	struct wpa_supplicant *wpa_s, char *cmd)
2687114402Sru{
2688114402Sru	int id;
2689114402Sru	struct wpa_ssid *ssid;
2690114402Sru
2691114402Sru	id = atoi(cmd);
2692114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
2693114402Sru
2694114402Sru	ssid = wpa_config_get_network(wpa_s->conf, id);
2695114402Sru	if (ssid == NULL) {
2696114402Sru		wpa_printf(MSG_DEBUG,
2697114402Sru			   "CTRL_IFACE: Could not find network id=%d", id);
2698151497Sru		return -1;
2699151497Sru	}
2700151497Sru	if (ssid->mode != WPAS_MODE_MESH) {
2701151497Sru		wpa_printf(MSG_DEBUG,
2702114402Sru			   "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network");
2703114402Sru		return -1;
2704151497Sru	}
2705114402Sru	if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
2706114402Sru	    ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
2707114402Sru		wpa_printf(MSG_ERROR,
2708114402Sru			   "CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
2709151497Sru		return -1;
2710151497Sru	}
2711114402Sru
2712114402Sru	/*
2713114402Sru	 * TODO: If necessary write our own group_add function,
2714114402Sru	 * for now we can reuse select_network
2715114402Sru	 */
2716114402Sru	wpa_supplicant_select_network(wpa_s, ssid);
2717114402Sru
2718114402Sru	return 0;
2719114402Sru}
2720114402Sru
2721114402Sru
2722114402Srustatic int wpa_supplicant_ctrl_iface_mesh_group_remove(
2723114402Sru	struct wpa_supplicant *wpa_s, char *cmd)
2724114402Sru{
2725114402Sru	struct wpa_supplicant *orig;
2726114402Sru	struct wpa_global *global;
2727114402Sru	int found = 0;
2728114402Sru
2729151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
2730151497Sru
2731151497Sru	global = wpa_s->global;
2732151497Sru	orig = wpa_s;
2733151497Sru
2734151497Sru	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
2735151497Sru		if (os_strcmp(wpa_s->ifname, cmd) == 0) {
2736151497Sru			found = 1;
2737151497Sru			break;
2738151497Sru		}
2739151497Sru	}
2740151497Sru	if (!found) {
2741151497Sru		wpa_printf(MSG_ERROR,
2742151497Sru			   "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
2743151497Sru			   cmd);
2744151497Sru		return -1;
2745151497Sru	}
2746151497Sru	if (wpa_s->mesh_if_created && wpa_s == orig) {
2747151497Sru		wpa_printf(MSG_ERROR,
2748151497Sru			   "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
2749151497Sru		return -1;
2750151497Sru	}
2751151497Sru
2752151497Sru	wpa_s->reassociate = 0;
2753151497Sru	wpa_s->disconnected = 1;
2754151497Sru	wpa_supplicant_cancel_sched_scan(wpa_s);
2755151497Sru	wpa_supplicant_cancel_scan(wpa_s);
2756151497Sru
2757151497Sru	/*
2758151497Sru	 * TODO: If necessary write our own group_remove function,
2759151497Sru	 * for now we can reuse deauthenticate
2760151497Sru	 */
2761151497Sru	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
2762151497Sru
2763114402Sru	if (wpa_s->mesh_if_created)
2764114402Sru		wpa_supplicant_remove_iface(global, wpa_s, 0);
2765114402Sru
2766114402Sru	return 0;
2767114402Sru}
2768114402Sru
2769151497Sru
2770114402Srustatic int wpa_supplicant_ctrl_iface_mesh_peer_remove(
2771151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
2772151497Sru{
2773151497Sru	u8 addr[ETH_ALEN];
2774114402Sru
2775114402Sru	if (hwaddr_aton(cmd, addr) < 0)
2776114402Sru		return -1;
2777114402Sru
2778151497Sru	return wpas_mesh_peer_remove(wpa_s, addr);
2779114402Sru}
2780114402Sru
2781114402Sru
2782114402Srustatic int wpa_supplicant_ctrl_iface_mesh_peer_add(
2783114402Sru	struct wpa_supplicant *wpa_s, char *cmd)
2784114402Sru{
2785114402Sru	u8 addr[ETH_ALEN];
2786114402Sru	int duration;
2787114402Sru	char *pos;
2788114402Sru
2789114402Sru	pos = os_strstr(cmd, " duration=");
2790114402Sru	if (pos) {
2791114402Sru		*pos = '\0';
2792114402Sru		duration = atoi(pos + 10);
2793114402Sru	} else {
2794114402Sru		duration = -1;
2795151497Sru	}
2796114402Sru
2797114402Sru	if (hwaddr_aton(cmd, addr))
2798114402Sru		return -1;
2799151497Sru
2800151497Sru	return wpas_mesh_peer_add(wpa_s, addr, duration);
2801151497Sru}
2802151497Sru
2803151497Sru#endif /* CONFIG_MESH */
2804151497Sru
2805151497Sru
2806151497Srustatic int wpa_supplicant_ctrl_iface_select_network(
2807151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
2808151497Sru{
2809151497Sru	int id;
2810151497Sru	struct wpa_ssid *ssid;
2811151497Sru	char *pos;
2812151497Sru
2813151497Sru	/* cmd: "<network id>" or "any" */
2814151497Sru	if (os_strncmp(cmd, "any", 3) == 0) {
2815151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
2816151497Sru		ssid = NULL;
2817151497Sru	} else {
2818151497Sru		id = atoi(cmd);
2819151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
2820151497Sru
2821151497Sru		ssid = wpa_config_get_network(wpa_s->conf, id);
2822151497Sru		if (ssid == NULL) {
2823151497Sru			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2824151497Sru				   "network id=%d", id);
2825151497Sru			return -1;
2826151497Sru		}
2827151497Sru		if (ssid->disabled == 2) {
2828151497Sru			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2829151497Sru				   "SELECT_NETWORK with persistent P2P group");
2830151497Sru			return -1;
2831151497Sru		}
2832151497Sru	}
2833151497Sru
2834151497Sru	pos = os_strstr(cmd, " freq=");
2835151497Sru	if (pos) {
2836151497Sru		int *freqs = freq_range_to_channel_list(wpa_s, pos + 6);
2837151497Sru		if (freqs) {
2838151497Sru			wpa_s->scan_req = MANUAL_SCAN_REQ;
2839151497Sru			os_free(wpa_s->manual_scan_freqs);
2840151497Sru			wpa_s->manual_scan_freqs = freqs;
2841151497Sru		}
2842151497Sru	}
2843151497Sru
2844151497Sru	wpa_s->scan_min_time.sec = 0;
2845114402Sru	wpa_s->scan_min_time.usec = 0;
2846114402Sru	wpa_supplicant_select_network(wpa_s, ssid);
2847114402Sru
2848114402Sru	return 0;
2849114402Sru}
2850114402Sru
2851114402Sru
2852114402Srustatic int wpa_supplicant_ctrl_iface_enable_network(
2853114402Sru	struct wpa_supplicant *wpa_s, char *cmd)
2854114402Sru{
2855114402Sru	int id;
2856114402Sru	struct wpa_ssid *ssid;
2857114402Sru
2858114402Sru	/* cmd: "<network id>" or "all" */
2859114402Sru	if (os_strcmp(cmd, "all") == 0) {
2860114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
2861114402Sru		ssid = NULL;
2862114402Sru	} else {
2863114402Sru		id = atoi(cmd);
2864114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
2865114402Sru
2866114402Sru		ssid = wpa_config_get_network(wpa_s->conf, id);
2867114402Sru		if (ssid == NULL) {
2868114402Sru			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2869114402Sru				   "network id=%d", id);
2870114402Sru			return -1;
2871114402Sru		}
2872114402Sru		if (ssid->disabled == 2) {
2873114402Sru			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2874114402Sru				   "ENABLE_NETWORK with persistent P2P group");
2875114402Sru			return -1;
2876114402Sru		}
2877114402Sru
2878151497Sru		if (os_strstr(cmd, " no-connect")) {
2879114402Sru			ssid->disabled = 0;
2880114402Sru			return 0;
2881151497Sru		}
2882114402Sru	}
2883114402Sru	wpa_s->scan_min_time.sec = 0;
2884114402Sru	wpa_s->scan_min_time.usec = 0;
2885114402Sru	wpa_supplicant_enable_network(wpa_s, ssid);
2886151497Sru
2887151497Sru	return 0;
2888151497Sru}
2889151497Sru
2890151497Sru
2891151497Srustatic int wpa_supplicant_ctrl_iface_disable_network(
2892151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
2893151497Sru{
2894151497Sru	int id;
2895151497Sru	struct wpa_ssid *ssid;
2896151497Sru
2897151497Sru	/* cmd: "<network id>" or "all" */
2898151497Sru	if (os_strcmp(cmd, "all") == 0) {
2899151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
2900151497Sru		ssid = NULL;
2901151497Sru	} else {
2902151497Sru		id = atoi(cmd);
2903151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
2904151497Sru
2905151497Sru		ssid = wpa_config_get_network(wpa_s->conf, id);
2906151497Sru		if (ssid == NULL) {
2907151497Sru			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
2908151497Sru				   "network id=%d", id);
2909151497Sru			return -1;
2910151497Sru		}
2911151497Sru		if (ssid->disabled == 2) {
2912151497Sru			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
2913151497Sru				   "DISABLE_NETWORK with persistent P2P "
2914151497Sru				   "group");
2915151497Sru			return -1;
2916151497Sru		}
2917151497Sru	}
2918151497Sru	wpa_supplicant_disable_network(wpa_s, ssid);
2919151497Sru
2920151497Sru	return 0;
2921151497Sru}
2922151497Sru
2923151497Sru
2924151497Srustatic int wpa_supplicant_ctrl_iface_add_network(
2925151497Sru	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
2926151497Sru{
2927151497Sru	struct wpa_ssid *ssid;
2928151497Sru	int ret;
2929151497Sru
2930151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
2931151497Sru
2932151497Sru	ssid = wpa_supplicant_add_network(wpa_s);
2933151497Sru	if (ssid == NULL)
2934114402Sru		return -1;
2935151497Sru
2936151497Sru	ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
2937151497Sru	if (os_snprintf_error(buflen, ret))
2938114402Sru		return -1;
2939114402Sru	return ret;
2940114402Sru}
2941114402Sru
2942151497Sru
2943151497Srustatic int wpa_supplicant_ctrl_iface_remove_network(
2944114402Sru	struct wpa_supplicant *wpa_s, char *cmd)
2945114402Sru{
2946114402Sru	int id;
2947151497Sru	struct wpa_ssid *ssid;
2948151497Sru	int result;
2949114402Sru
2950151497Sru	/* cmd: "<network id>" or "all" */
2951151497Sru	if (os_strcmp(cmd, "all") == 0) {
2952151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
2953151497Sru		if (wpa_s->sched_scanning)
2954151497Sru			wpa_supplicant_cancel_sched_scan(wpa_s);
2955151497Sru
2956151497Sru		eapol_sm_invalidate_cached_session(wpa_s->eapol);
2957151497Sru		if (wpa_s->current_ssid) {
2958151497Sru#ifdef CONFIG_SME
2959151497Sru			wpa_s->sme.prev_bssid_set = 0;
2960151497Sru#endif /* CONFIG_SME */
2961151497Sru			wpa_sm_set_config(wpa_s->wpa, NULL);
2962151497Sru			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
2963151497Sru			if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
2964114402Sru				wpa_s->own_disconnect_req = 1;
2965114402Sru			wpa_supplicant_deauthenticate(
2966114402Sru				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
2967151497Sru		}
2968151497Sru		ssid = wpa_s->conf->ssid;
2969151497Sru		while (ssid) {
2970151497Sru			struct wpa_ssid *remove_ssid = ssid;
2971151497Sru			id = ssid->id;
2972151497Sru			ssid = ssid->next;
2973151497Sru			if (wpa_s->last_ssid == remove_ssid)
2974151497Sru				wpa_s->last_ssid = NULL;
2975151497Sru			wpas_notify_network_removed(wpa_s, remove_ssid);
2976151497Sru			wpa_config_remove_network(wpa_s->conf, id);
2977151497Sru		}
2978151497Sru		return 0;
2979151497Sru	}
2980151497Sru
2981151497Sru	id = atoi(cmd);
2982151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
2983151497Sru
2984151497Sru	result = wpa_supplicant_remove_network(wpa_s, id);
2985114402Sru	if (result == -1) {
2986114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
2987114402Sru			   "id=%d", id);
2988114402Sru		return -1;
2989114402Sru	}
2990114402Sru	if (result == -2) {
2991114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
2992114402Sru			   "network id=%d", id);
2993114402Sru		return -1;
2994151497Sru	}
2995114402Sru	return 0;
2996114402Sru}
2997151497Sru
2998114402Sru
2999151497Srustatic int wpa_supplicant_ctrl_iface_update_network(
3000114402Sru	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
3001151497Sru	char *name, char *value)
3002114402Sru{
3003114402Sru	int ret;
3004114402Sru
3005151497Sru	ret = wpa_config_set(ssid, name, value, 0);
3006151497Sru	if (ret < 0) {
3007151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
3008114402Sru			   "variable '%s'", name);
3009151497Sru		return -1;
3010151497Sru	}
3011151497Sru	if (ret == 1)
3012114402Sru		return 0; /* No change to the previously configured value */
3013114402Sru
3014114402Sru	if (os_strcmp(name, "bssid") != 0 &&
3015114402Sru	    os_strcmp(name, "priority") != 0) {
3016114402Sru		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
3017114402Sru
3018114402Sru		if (wpa_s->current_ssid == ssid ||
3019114402Sru		    wpa_s->current_ssid == NULL) {
3020114402Sru			/*
3021114402Sru			 * Invalidate the EAP session cache if anything in the
3022114402Sru			 * current or previously used configuration changes.
3023114402Sru			 */
3024114402Sru			eapol_sm_invalidate_cached_session(wpa_s->eapol);
3025151497Sru		}
3026114402Sru	}
3027114402Sru
3028114402Sru	if ((os_strcmp(name, "psk") == 0 &&
3029114402Sru	     value[0] == '"' && ssid->ssid_len) ||
3030151497Sru	    (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
3031114402Sru		wpa_config_update_psk(ssid);
3032114402Sru	else if (os_strcmp(name, "priority") == 0)
3033114402Sru		wpa_config_update_prio_list(wpa_s->conf);
3034151497Sru
3035114402Sru	return 0;
3036114402Sru}
3037114402Sru
3038114402Sru
3039114402Srustatic int wpa_supplicant_ctrl_iface_set_network(
3040114402Sru	struct wpa_supplicant *wpa_s, char *cmd)
3041114402Sru{
3042114402Sru	int id, ret, prev_bssid_set, prev_disabled;
3043151497Sru	struct wpa_ssid *ssid;
3044114402Sru	char *name, *value;
3045114402Sru	u8 prev_bssid[ETH_ALEN];
3046114402Sru
3047114402Sru	/* cmd: "<network id> <variable name> <value>" */
3048114402Sru	name = os_strchr(cmd, ' ');
3049114402Sru	if (name == NULL)
3050114402Sru		return -1;
3051114402Sru	*name++ = '\0';
3052151497Sru
3053114402Sru	value = os_strchr(name, ' ');
3054114402Sru	if (value == NULL)
3055114402Sru		return -1;
3056114402Sru	*value++ = '\0';
3057114402Sru
3058151497Sru	id = atoi(cmd);
3059114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
3060114402Sru		   id, name);
3061114402Sru	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
3062114402Sru			      (u8 *) value, os_strlen(value));
3063114402Sru
3064114402Sru	ssid = wpa_config_get_network(wpa_s->conf, id);
3065114402Sru	if (ssid == NULL) {
3066114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
3067114402Sru			   "id=%d", id);
3068114402Sru		return -1;
3069114402Sru	}
3070114402Sru
3071114402Sru	prev_bssid_set = ssid->bssid_set;
3072114402Sru	prev_disabled = ssid->disabled;
3073151497Sru	os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN);
3074151497Sru	ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name,
3075151497Sru						       value);
3076151497Sru	if (ret == 0 &&
3077114402Sru	    (ssid->bssid_set != prev_bssid_set ||
3078151497Sru	     os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0))
3079151497Sru		wpas_notify_network_bssid_set_changed(wpa_s, ssid);
3080114402Sru
3081114402Sru	if (prev_disabled != ssid->disabled &&
3082114402Sru	    (prev_disabled == 2 || ssid->disabled == 2))
3083114402Sru		wpas_notify_network_type_changed(wpa_s, ssid);
3084151497Sru
3085151497Sru	return ret;
3086114402Sru}
3087114402Sru
3088114402Sru
3089114402Srustatic int wpa_supplicant_ctrl_iface_get_network(
3090114402Sru	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
3091151497Sru{
3092114402Sru	int id;
3093151497Sru	size_t res;
3094114402Sru	struct wpa_ssid *ssid;
3095151497Sru	char *name, *value;
3096151497Sru
3097151497Sru	/* cmd: "<network id> <variable name>" */
3098114402Sru	name = os_strchr(cmd, ' ');
3099114402Sru	if (name == NULL || buflen == 0)
3100114402Sru		return -1;
3101114402Sru	*name++ = '\0';
3102151497Sru
3103151497Sru	id = atoi(cmd);
3104114402Sru	wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
3105151497Sru		   id, name);
3106151497Sru
3107114402Sru	ssid = wpa_config_get_network(wpa_s->conf, id);
3108114402Sru	if (ssid == NULL) {
3109114402Sru		wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Could not find network "
3110114402Sru			   "id=%d", id);
3111114402Sru		return -1;
3112114402Sru	}
3113114402Sru
3114114402Sru	value = wpa_config_get_no_key(ssid, name);
3115114402Sru	if (value == NULL) {
3116114402Sru		wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Failed to get network "
3117114402Sru			   "variable '%s'", name);
3118114402Sru		return -1;
3119114402Sru	}
3120114402Sru
3121151497Sru	res = os_strlcpy(buf, value, buflen);
3122114402Sru	if (res >= buflen) {
3123114402Sru		os_free(value);
3124114402Sru		return -1;
3125114402Sru	}
3126114402Sru
3127114402Sru	os_free(value);
3128114402Sru
3129114402Sru	return res;
3130151497Sru}
3131151497Sru
3132114402Sru
3133114402Srustatic int wpa_supplicant_ctrl_iface_dup_network(
3134114402Sru	struct wpa_supplicant *wpa_s, char *cmd,
3135114402Sru	struct wpa_supplicant *dst_wpa_s)
3136114402Sru{
3137114402Sru	struct wpa_ssid *ssid_s, *ssid_d;
3138114402Sru	char *name, *id, *value;
3139114402Sru	int id_s, id_d, ret;
3140114402Sru
3141114402Sru	/* cmd: "<src network id> <dst network id> <variable name>" */
3142114402Sru	id = os_strchr(cmd, ' ');
3143114402Sru	if (id == NULL)
3144114402Sru		return -1;
3145114402Sru	*id++ = '\0';
3146114402Sru
3147114402Sru	name = os_strchr(id, ' ');
3148114402Sru	if (name == NULL)
3149114402Sru		return -1;
3150114402Sru	*name++ = '\0';
3151114402Sru
3152114402Sru	id_s = atoi(cmd);
3153114402Sru	id_d = atoi(id);
3154114402Sru
3155151497Sru	wpa_printf(MSG_DEBUG,
3156151497Sru		   "CTRL_IFACE: DUP_NETWORK ifname=%s->%s id=%d->%d name='%s'",
3157151497Sru		   wpa_s->ifname, dst_wpa_s->ifname, id_s, id_d, name);
3158151497Sru
3159151497Sru	ssid_s = wpa_config_get_network(wpa_s->conf, id_s);
3160151497Sru	if (ssid_s == NULL) {
3161114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3162114402Sru			   "network id=%d", id_s);
3163114402Sru		return -1;
3164114402Sru	}
3165114402Sru
3166114402Sru	ssid_d = wpa_config_get_network(dst_wpa_s->conf, id_d);
3167114402Sru	if (ssid_d == NULL) {
3168114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
3169114402Sru			   "network id=%d", id_d);
3170114402Sru		return -1;
3171114402Sru	}
3172114402Sru
3173114402Sru	value = wpa_config_get(ssid_s, name);
3174114402Sru	if (value == NULL) {
3175114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
3176114402Sru			   "variable '%s'", name);
3177114402Sru		return -1;
3178114402Sru	}
3179114402Sru
3180114402Sru	ret = wpa_supplicant_ctrl_iface_update_network(dst_wpa_s, ssid_d, name,
3181114402Sru						       value);
3182114402Sru
3183114402Sru	os_free(value);
3184151497Sru
3185151497Sru	return ret;
3186114402Sru}
3187114402Sru
3188114402Sru
3189114402Srustatic int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
3190114402Sru						char *buf, size_t buflen)
3191114402Sru{
3192114402Sru	char *pos, *end;
3193114402Sru	struct wpa_cred *cred;
3194114402Sru	int ret;
3195114402Sru
3196114402Sru	pos = buf;
3197114402Sru	end = buf + buflen;
3198114402Sru	ret = os_snprintf(pos, end - pos,
3199114402Sru			  "cred id / realm / username / domain / imsi\n");
3200151497Sru	if (os_snprintf_error(end - pos, ret))
3201151497Sru		return pos - buf;
3202151497Sru	pos += ret;
3203151497Sru
3204151497Sru	cred = wpa_s->conf->cred;
3205114402Sru	while (cred) {
3206151497Sru		ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
3207151497Sru				  cred->id, cred->realm ? cred->realm : "",
3208114402Sru				  cred->username ? cred->username : "",
3209114402Sru				  cred->domain ? cred->domain[0] : "",
3210114402Sru				  cred->imsi ? cred->imsi : "");
3211151497Sru		if (os_snprintf_error(end - pos, ret))
3212114402Sru			return pos - buf;
3213151497Sru		pos += ret;
3214114402Sru
3215151497Sru		cred = cred->next;
3216151497Sru	}
3217151497Sru
3218151497Sru	return pos - buf;
3219151497Sru}
3220114402Sru
3221114402Sru
3222151497Srustatic int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
3223151497Sru					      char *buf, size_t buflen)
3224151497Sru{
3225114402Sru	struct wpa_cred *cred;
3226114402Sru	int ret;
3227114402Sru
3228114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
3229114402Sru
3230114402Sru	cred = wpa_config_add_cred(wpa_s->conf);
3231114402Sru	if (cred == NULL)
3232114402Sru		return -1;
3233114402Sru
3234114402Sru	wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id);
3235114402Sru
3236114402Sru	ret = os_snprintf(buf, buflen, "%d\n", cred->id);
3237114402Sru	if (os_snprintf_error(buflen, ret))
3238114402Sru		return -1;
3239114402Sru	return ret;
3240114402Sru}
3241114402Sru
3242114402Sru
3243151497Srustatic int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
3244151497Sru				 struct wpa_cred *cred)
3245114402Sru{
3246151497Sru	struct wpa_ssid *ssid;
3247151497Sru	char str[20];
3248151497Sru	int id;
3249114402Sru
3250151497Sru	if (cred == NULL) {
3251114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3252151497Sru		return -1;
3253114402Sru	}
3254114402Sru
3255114402Sru	id = cred->id;
3256114402Sru	if (wpa_config_remove_cred(wpa_s->conf, id) < 0) {
3257114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
3258114402Sru		return -1;
3259114402Sru	}
3260114402Sru
3261114402Sru	wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id);
3262114402Sru
3263151497Sru	/* Remove any network entry created based on the removed credential */
3264114402Sru	ssid = wpa_s->conf->ssid;
3265114402Sru	while (ssid) {
3266114402Sru		if (ssid->parent_cred == cred) {
3267151497Sru			int res;
3268151497Sru
3269151497Sru			wpa_printf(MSG_DEBUG, "Remove network id %d since it "
3270151497Sru				   "used the removed credential", ssid->id);
3271151497Sru			res = os_snprintf(str, sizeof(str), "%d", ssid->id);
3272114402Sru			if (os_snprintf_error(sizeof(str), res))
3273114402Sru				str[sizeof(str) - 1] = '\0';
3274114402Sru			ssid = ssid->next;
3275114402Sru			wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
3276114402Sru		} else
3277114402Sru			ssid = ssid->next;
3278114402Sru	}
3279114402Sru
3280114402Sru	return 0;
3281114402Sru}
3282151497Sru
3283114402Sru
3284114402Srustatic int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
3285114402Sru						 char *cmd)
3286114402Sru{
3287151497Sru	int id;
3288114402Sru	struct wpa_cred *cred, *prev;
3289151497Sru
3290151497Sru	/* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or
3291114402Sru	 * "provisioning_sp=<FQDN> */
3292114402Sru	if (os_strcmp(cmd, "all") == 0) {
3293114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
3294114402Sru		cred = wpa_s->conf->cred;
3295114402Sru		while (cred) {
3296114402Sru			prev = cred;
3297114402Sru			cred = cred->next;
3298114402Sru			wpas_ctrl_remove_cred(wpa_s, prev);
3299114402Sru		}
3300114402Sru		return 0;
3301114402Sru	}
3302114402Sru
3303114402Sru	if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
3304114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
3305114402Sru			   cmd + 8);
3306114402Sru		cred = wpa_s->conf->cred;
3307114402Sru		while (cred) {
3308114402Sru			prev = cred;
3309114402Sru			cred = cred->next;
3310151497Sru			if (prev->domain) {
3311114402Sru				size_t i;
3312114402Sru				for (i = 0; i < prev->num_domain; i++) {
3313114402Sru					if (os_strcmp(prev->domain[i], cmd + 8)
3314114402Sru					    != 0)
3315114402Sru						continue;
3316114402Sru					wpas_ctrl_remove_cred(wpa_s, prev);
3317114402Sru					break;
3318114402Sru				}
3319114402Sru			}
3320114402Sru		}
3321114402Sru		return 0;
3322114402Sru	}
3323114402Sru
3324114402Sru	if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) {
3325114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'",
3326114402Sru			   cmd + 16);
3327114402Sru		cred = wpa_s->conf->cred;
3328114402Sru		while (cred) {
3329114402Sru			prev = cred;
3330151497Sru			cred = cred->next;
3331114402Sru			if (prev->provisioning_sp &&
3332114402Sru			    os_strcmp(prev->provisioning_sp, cmd + 16) == 0)
3333114402Sru				wpas_ctrl_remove_cred(wpa_s, prev);
3334114402Sru		}
3335114402Sru		return 0;
3336114402Sru	}
3337114402Sru
3338114402Sru	id = atoi(cmd);
3339114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
3340114402Sru
3341114402Sru	cred = wpa_config_get_cred(wpa_s->conf, id);
3342114402Sru	return wpas_ctrl_remove_cred(wpa_s, cred);
3343114402Sru}
3344114402Sru
3345114402Sru
3346151497Srustatic int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
3347114402Sru					      char *cmd)
3348114402Sru{
3349114402Sru	int id;
3350114402Sru	struct wpa_cred *cred;
3351114402Sru	char *name, *value;
3352114402Sru
3353114402Sru	/* cmd: "<cred id> <variable name> <value>" */
3354114402Sru	name = os_strchr(cmd, ' ');
3355114402Sru	if (name == NULL)
3356114402Sru		return -1;
3357114402Sru	*name++ = '\0';
3358114402Sru
3359114402Sru	value = os_strchr(name, ' ');
3360114402Sru	if (value == NULL)
3361114402Sru		return -1;
3362114402Sru	*value++ = '\0';
3363114402Sru
3364114402Sru	id = atoi(cmd);
3365114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
3366114402Sru		   id, name);
3367114402Sru	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
3368114402Sru			      (u8 *) value, os_strlen(value));
3369114402Sru
3370114402Sru	cred = wpa_config_get_cred(wpa_s->conf, id);
3371114402Sru	if (cred == NULL) {
3372114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3373114402Sru			   id);
3374114402Sru		return -1;
3375114402Sru	}
3376114402Sru
3377114402Sru	if (wpa_config_set_cred(cred, name, value, 0) < 0) {
3378114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
3379114402Sru			   "variable '%s'", name);
3380114402Sru		return -1;
3381114402Sru	}
3382114402Sru
3383114402Sru	wpa_msg(wpa_s, MSG_INFO, CRED_MODIFIED "%d %s", cred->id, name);
3384114402Sru
3385114402Sru	return 0;
3386114402Sru}
3387114402Sru
3388151497Sru
3389114402Srustatic int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s,
3390114402Sru					      char *cmd, char *buf,
3391114402Sru					      size_t buflen)
3392151497Sru{
3393114402Sru	int id;
3394114402Sru	size_t res;
3395114402Sru	struct wpa_cred *cred;
3396114402Sru	char *name, *value;
3397114402Sru
3398114402Sru	/* cmd: "<cred id> <variable name>" */
3399114402Sru	name = os_strchr(cmd, ' ');
3400114402Sru	if (name == NULL)
3401114402Sru		return -1;
3402151497Sru	*name++ = '\0';
3403151497Sru
3404114402Sru	id = atoi(cmd);
3405114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'",
3406114402Sru		   id, name);
3407114402Sru
3408114402Sru	cred = wpa_config_get_cred(wpa_s->conf, id);
3409114402Sru	if (cred == NULL) {
3410114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
3411114402Sru			   id);
3412114402Sru		return -1;
3413114402Sru	}
3414114402Sru
3415114402Sru	value = wpa_config_get_cred_no_key(cred, name);
3416114402Sru	if (value == NULL) {
3417114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'",
3418114402Sru			   name);
3419151497Sru		return -1;
3420114402Sru	}
3421114402Sru
3422114402Sru	res = os_strlcpy(buf, value, buflen);
3423151497Sru	if (res >= buflen) {
3424114402Sru		os_free(value);
3425114402Sru		return -1;
3426114402Sru	}
3427114402Sru
3428114402Sru	os_free(value);
3429114402Sru
3430114402Sru	return res;
3431114402Sru}
3432114402Sru
3433114402Sru
3434114402Sru#ifndef CONFIG_NO_CONFIG_WRITE
3435114402Srustatic int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
3436151497Sru{
3437114402Sru	int ret;
3438114402Sru
3439114402Sru	if (!wpa_s->conf->update_config) {
3440114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
3441114402Sru			   "to update configuration (update_config=0)");
3442114402Sru		return -1;
3443114402Sru	}
3444114402Sru
3445114402Sru	ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
3446114402Sru	if (ret) {
3447114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
3448114402Sru			   "update configuration");
3449114402Sru	} else {
3450114402Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
3451114402Sru			   " updated");
3452114402Sru	}
3453114402Sru
3454114402Sru	return ret;
3455114402Sru}
3456114402Sru#endif /* CONFIG_NO_CONFIG_WRITE */
3457114402Sru
3458114402Sru
3459114402Srustruct cipher_info {
3460114402Sru	unsigned int capa;
3461114402Sru	const char *name;
3462114402Sru	int group_only;
3463114402Sru};
3464114402Sru
3465114402Srustatic const struct cipher_info ciphers[] = {
3466114402Sru	{ WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
3467114402Sru	{ WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
3468114402Sru	{ WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
3469114402Sru	{ WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
3470114402Sru	{ WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
3471114402Sru	{ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
3472114402Sru	{ WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
3473114402Sru	{ WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
3474114402Sru};
3475114402Sru
3476114402Srustatic const struct cipher_info ciphers_group_mgmt[] = {
3477114402Sru	{ WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 },
3478114402Sru	{ WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 },
3479114402Sru	{ WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 },
3480114402Sru	{ WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 },
3481114402Sru};
3482114402Sru
3483114402Sru
3484114402Srustatic int ctrl_iface_get_capability_pairwise(int res, char *strict,
3485114402Sru					      struct wpa_driver_capa *capa,
3486114402Sru					      char *buf, size_t buflen)
3487114402Sru{
3488114402Sru	int ret;
3489114402Sru	char *pos, *end;
3490114402Sru	size_t len;
3491114402Sru	unsigned int i;
3492114402Sru
3493114402Sru	pos = buf;
3494114402Sru	end = pos + buflen;
3495114402Sru
3496114402Sru	if (res < 0) {
3497114402Sru		if (strict)
3498114402Sru			return 0;
3499114402Sru		len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
3500114402Sru		if (len >= buflen)
3501114402Sru			return -1;
3502114402Sru		return len;
3503114402Sru	}
3504151497Sru
3505151497Sru	for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3506114402Sru		if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
3507114402Sru			ret = os_snprintf(pos, end - pos, "%s%s",
3508114402Sru					  pos == buf ? "" : " ",
3509114402Sru					  ciphers[i].name);
3510114402Sru			if (os_snprintf_error(end - pos, ret))
3511114402Sru				return pos - buf;
3512114402Sru			pos += ret;
3513114402Sru		}
3514114402Sru	}
3515114402Sru
3516114402Sru	return pos - buf;
3517114402Sru}
3518114402Sru
3519151497Sru
3520151497Srustatic int ctrl_iface_get_capability_group(int res, char *strict,
3521151497Sru					   struct wpa_driver_capa *capa,
3522114402Sru					   char *buf, size_t buflen)
3523114402Sru{
3524114402Sru	int ret;
3525114402Sru	char *pos, *end;
3526114402Sru	size_t len;
3527114402Sru	unsigned int i;
3528114402Sru
3529114402Sru	pos = buf;
3530114402Sru	end = pos + buflen;
3531114402Sru
3532114402Sru	if (res < 0) {
3533151497Sru		if (strict)
3534114402Sru			return 0;
3535151497Sru		len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
3536151497Sru		if (len >= buflen)
3537151497Sru			return -1;
3538151497Sru		return len;
3539151497Sru	}
3540151497Sru
3541151497Sru	for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
3542151497Sru		if (capa->enc & ciphers[i].capa) {
3543151497Sru			ret = os_snprintf(pos, end - pos, "%s%s",
3544151497Sru					  pos == buf ? "" : " ",
3545151497Sru					  ciphers[i].name);
3546151497Sru			if (os_snprintf_error(end - pos, ret))
3547151497Sru				return pos - buf;
3548151497Sru			pos += ret;
3549151497Sru		}
3550151497Sru	}
3551151497Sru
3552151497Sru	return pos - buf;
3553151497Sru}
3554151497Sru
3555114402Sru
3556114402Srustatic int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
3557114402Sru						struct wpa_driver_capa *capa,
3558114402Sru						char *buf, size_t buflen)
3559114402Sru{
3560114402Sru	int ret;
3561114402Sru	char *pos, *end;
3562114402Sru	unsigned int i;
3563114402Sru
3564114402Sru	pos = buf;
3565114402Sru	end = pos + buflen;
3566114402Sru
3567114402Sru	if (res < 0)
3568114402Sru		return 0;
3569114402Sru
3570114402Sru	for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) {
3571151497Sru		if (capa->enc & ciphers_group_mgmt[i].capa) {
3572151497Sru			ret = os_snprintf(pos, end - pos, "%s%s",
3573114402Sru					  pos == buf ? "" : " ",
3574114402Sru					  ciphers_group_mgmt[i].name);
3575151497Sru			if (os_snprintf_error(end - pos, ret))
3576114402Sru				return pos - buf;
3577114402Sru			pos += ret;
3578114402Sru		}
3579114402Sru	}
3580114402Sru
3581114402Sru	return pos - buf;
3582114402Sru}
3583114402Sru
3584114402Sru
3585114402Srustatic int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
3586114402Sru					      struct wpa_driver_capa *capa,
3587114402Sru					      char *buf, size_t buflen)
3588114402Sru{
3589151497Sru	int ret;
3590151497Sru	char *pos, *end;
3591151497Sru	size_t len;
3592114402Sru
3593151497Sru	pos = buf;
3594114402Sru	end = pos + buflen;
3595114402Sru
3596114402Sru	if (res < 0) {
3597114402Sru		if (strict)
3598151497Sru			return 0;
3599151497Sru		len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
3600114402Sru				 "NONE", buflen);
3601114402Sru		if (len >= buflen)
3602114402Sru			return -1;
3603114402Sru		return len;
3604114402Sru	}
3605151497Sru
3606114402Sru	ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
3607114402Sru	if (os_snprintf_error(end - pos, ret))
3608114402Sru		return pos - buf;
3609114402Sru	pos += ret;
3610151497Sru
3611114402Sru	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3612114402Sru			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
3613114402Sru		ret = os_snprintf(pos, end - pos, " WPA-EAP");
3614114402Sru		if (os_snprintf_error(end - pos, ret))
3615114402Sru			return pos - buf;
3616114402Sru		pos += ret;
3617114402Sru	}
3618114402Sru
3619114402Sru	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
3620114402Sru			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
3621114402Sru		ret = os_snprintf(pos, end - pos, " WPA-PSK");
3622114402Sru		if (os_snprintf_error(end - pos, ret))
3623114402Sru			return pos - buf;
3624151497Sru		pos += ret;
3625151497Sru	}
3626114402Sru
3627114402Sru	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
3628114402Sru		ret = os_snprintf(pos, end - pos, " WPA-NONE");
3629114402Sru		if (os_snprintf_error(end - pos, ret))
3630151497Sru			return pos - buf;
3631151497Sru		pos += ret;
3632151497Sru	}
3633151497Sru
3634151497Sru#ifdef CONFIG_SUITEB
3635114402Sru	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
3636114402Sru		ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
3637151497Sru		if (os_snprintf_error(end - pos, ret))
3638151497Sru			return pos - buf;
3639114402Sru		pos += ret;
3640114402Sru	}
3641114402Sru#endif /* CONFIG_SUITEB */
3642114402Sru#ifdef CONFIG_SUITEB192
3643151497Sru	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
3644114402Sru		ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
3645114402Sru		if (os_snprintf_error(end - pos, ret))
3646114402Sru			return pos - buf;
3647114402Sru		pos += ret;
3648114402Sru	}
3649151497Sru#endif /* CONFIG_SUITEB192 */
3650114402Sru
3651114402Sru	return pos - buf;
3652114402Sru}
3653114402Sru
3654114402Sru
3655151497Srustatic int ctrl_iface_get_capability_proto(int res, char *strict,
3656151497Sru					   struct wpa_driver_capa *capa,
3657114402Sru					   char *buf, size_t buflen)
3658114402Sru{
3659114402Sru	int ret;
3660114402Sru	char *pos, *end;
3661114402Sru	size_t len;
3662114402Sru
3663114402Sru	pos = buf;
3664114402Sru	end = pos + buflen;
3665114402Sru
3666114402Sru	if (res < 0) {
3667151497Sru		if (strict)
3668114402Sru			return 0;
3669114402Sru		len = os_strlcpy(buf, "RSN WPA", buflen);
3670114402Sru		if (len >= buflen)
3671114402Sru			return -1;
3672151497Sru		return len;
3673114402Sru	}
3674114402Sru
3675114402Sru	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
3676114402Sru			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
3677114402Sru		ret = os_snprintf(pos, end - pos, "%sRSN",
3678114402Sru				  pos == buf ? "" : " ");
3679151497Sru		if (os_snprintf_error(end - pos, ret))
3680114402Sru			return pos - buf;
3681114402Sru		pos += ret;
3682114402Sru	}
3683114402Sru
3684114402Sru	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3685114402Sru			      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
3686114402Sru		ret = os_snprintf(pos, end - pos, "%sWPA",
3687114402Sru				  pos == buf ? "" : " ");
3688114402Sru		if (os_snprintf_error(end - pos, ret))
3689114402Sru			return pos - buf;
3690114402Sru		pos += ret;
3691114402Sru	}
3692114402Sru
3693114402Sru	return pos - buf;
3694114402Sru}
3695114402Sru
3696114402Sru
3697114402Srustatic int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
3698114402Sru					      int res, char *strict,
3699114402Sru					      struct wpa_driver_capa *capa,
3700114402Sru					      char *buf, size_t buflen)
3701114402Sru{
3702114402Sru	int ret;
3703151497Sru	char *pos, *end;
3704151497Sru	size_t len;
3705114402Sru
3706114402Sru	pos = buf;
3707114402Sru	end = pos + buflen;
3708151497Sru
3709151497Sru	if (res < 0) {
3710151497Sru		if (strict)
3711151497Sru			return 0;
3712114402Sru		len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
3713114402Sru		if (len >= buflen)
3714114402Sru			return -1;
3715151497Sru		return len;
3716151497Sru	}
3717114402Sru
3718114402Sru	if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
3719114402Sru		ret = os_snprintf(pos, end - pos, "%sOPEN",
3720114402Sru				  pos == buf ? "" : " ");
3721114402Sru		if (os_snprintf_error(end - pos, ret))
3722114402Sru			return pos - buf;
3723114402Sru		pos += ret;
3724114402Sru	}
3725114402Sru
3726114402Sru	if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
3727114402Sru		ret = os_snprintf(pos, end - pos, "%sSHARED",
3728114402Sru				  pos == buf ? "" : " ");
3729114402Sru		if (os_snprintf_error(end - pos, ret))
3730114402Sru			return pos - buf;
3731114402Sru		pos += ret;
3732114402Sru	}
3733114402Sru
3734114402Sru	if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
3735114402Sru		ret = os_snprintf(pos, end - pos, "%sLEAP",
3736114402Sru				  pos == buf ? "" : " ");
3737114402Sru		if (os_snprintf_error(end - pos, ret))
3738114402Sru			return pos - buf;
3739114402Sru		pos += ret;
3740114402Sru	}
3741114402Sru
3742114402Sru#ifdef CONFIG_SAE
3743114402Sru	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
3744114402Sru		ret = os_snprintf(pos, end - pos, "%sSAE",
3745114402Sru				  pos == buf ? "" : " ");
3746114402Sru		if (os_snprintf_error(end - pos, ret))
3747114402Sru			return pos - buf;
3748114402Sru		pos += ret;
3749114402Sru	}
3750114402Sru#endif /* CONFIG_SAE */
3751114402Sru
3752114402Sru	return pos - buf;
3753114402Sru}
3754114402Sru
3755114402Sru
3756114402Srustatic int ctrl_iface_get_capability_modes(int res, char *strict,
3757114402Sru					   struct wpa_driver_capa *capa,
3758114402Sru					   char *buf, size_t buflen)
3759114402Sru{
3760114402Sru	int ret;
3761114402Sru	char *pos, *end;
3762114402Sru	size_t len;
3763114402Sru
3764151497Sru	pos = buf;
3765151497Sru	end = pos + buflen;
3766151497Sru
3767151497Sru	if (res < 0) {
3768151497Sru		if (strict)
3769151497Sru			return 0;
3770151497Sru		len = os_strlcpy(buf, "IBSS AP", buflen);
3771151497Sru		if (len >= buflen)
3772151497Sru			return -1;
3773151497Sru		return len;
3774151497Sru	}
3775151497Sru
3776151497Sru	if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
3777151497Sru		ret = os_snprintf(pos, end - pos, "%sIBSS",
3778151497Sru				  pos == buf ? "" : " ");
3779151497Sru		if (os_snprintf_error(end - pos, ret))
3780151497Sru			return pos - buf;
3781151497Sru		pos += ret;
3782151497Sru	}
3783151497Sru
3784151497Sru	if (capa->flags & WPA_DRIVER_FLAGS_AP) {
3785151497Sru		ret = os_snprintf(pos, end - pos, "%sAP",
3786151497Sru				  pos == buf ? "" : " ");
3787151497Sru		if (os_snprintf_error(end - pos, ret))
3788151497Sru			return pos - buf;
3789151497Sru		pos += ret;
3790151497Sru	}
3791151497Sru
3792151497Sru#ifdef CONFIG_MESH
3793151497Sru	if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
3794151497Sru		ret = os_snprintf(pos, end - pos, "%sMESH",
3795114402Sru				  pos == buf ? "" : " ");
3796114402Sru		if (os_snprintf_error(end - pos, ret))
3797114402Sru			return pos - buf;
3798114402Sru		pos += ret;
3799114402Sru	}
3800114402Sru#endif /* CONFIG_MESH */
3801114402Sru
3802114402Sru	return pos - buf;
3803114402Sru}
3804114402Sru
3805151497Sru
3806114402Srustatic int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
3807114402Sru					      char *buf, size_t buflen)
3808114402Sru{
3809114402Sru	struct hostapd_channel_data *chnl;
3810114402Sru	int ret, i, j;
3811114402Sru	char *pos, *end, *hmode;
3812114402Sru
3813114402Sru	pos = buf;
3814114402Sru	end = pos + buflen;
3815114402Sru
3816114402Sru	for (j = 0; j < wpa_s->hw.num_modes; j++) {
3817114402Sru		switch (wpa_s->hw.modes[j].mode) {
3818114402Sru		case HOSTAPD_MODE_IEEE80211B:
3819114402Sru			hmode = "B";
3820114402Sru			break;
3821114402Sru		case HOSTAPD_MODE_IEEE80211G:
3822114402Sru			hmode = "G";
3823114402Sru			break;
3824114402Sru		case HOSTAPD_MODE_IEEE80211A:
3825114402Sru			hmode = "A";
3826114402Sru			break;
3827114402Sru		case HOSTAPD_MODE_IEEE80211AD:
3828114402Sru			hmode = "AD";
3829114402Sru			break;
3830114402Sru		default:
3831114402Sru			continue;
3832114402Sru		}
3833114402Sru		ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
3834114402Sru		if (os_snprintf_error(end - pos, ret))
3835114402Sru			return pos - buf;
3836114402Sru		pos += ret;
3837114402Sru		chnl = wpa_s->hw.modes[j].channels;
3838114402Sru		for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
3839114402Sru			if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
3840114402Sru				continue;
3841114402Sru			ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
3842114402Sru			if (os_snprintf_error(end - pos, ret))
3843114402Sru				return pos - buf;
3844114402Sru			pos += ret;
3845114402Sru		}
3846114402Sru		ret = os_snprintf(pos, end - pos, "\n");
3847114402Sru		if (os_snprintf_error(end - pos, ret))
3848114402Sru			return pos - buf;
3849114402Sru		pos += ret;
3850114402Sru	}
3851114402Sru
3852114402Sru	return pos - buf;
3853114402Sru}
3854151497Sru
3855151497Sru
3856114402Srustatic int ctrl_iface_get_capability_freq(struct wpa_supplicant *wpa_s,
3857114402Sru					  char *buf, size_t buflen)
3858114402Sru{
3859114402Sru	struct hostapd_channel_data *chnl;
3860151497Sru	int ret, i, j;
3861151497Sru	char *pos, *end, *hmode;
3862114402Sru
3863114402Sru	pos = buf;
3864114402Sru	end = pos + buflen;
3865114402Sru
3866114402Sru	for (j = 0; j < wpa_s->hw.num_modes; j++) {
3867151497Sru		switch (wpa_s->hw.modes[j].mode) {
3868151497Sru		case HOSTAPD_MODE_IEEE80211B:
3869114402Sru			hmode = "B";
3870114402Sru			break;
3871114402Sru		case HOSTAPD_MODE_IEEE80211G:
3872114402Sru			hmode = "G";
3873114402Sru			break;
3874151497Sru		case HOSTAPD_MODE_IEEE80211A:
3875151497Sru			hmode = "A";
3876114402Sru			break;
3877114402Sru		case HOSTAPD_MODE_IEEE80211AD:
3878114402Sru			hmode = "AD";
3879114402Sru			break;
3880114402Sru		default:
3881114402Sru			continue;
3882114402Sru		}
3883114402Sru		ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
3884114402Sru				  hmode);
3885114402Sru		if (os_snprintf_error(end - pos, ret))
3886114402Sru			return pos - buf;
3887114402Sru		pos += ret;
3888114402Sru		chnl = wpa_s->hw.modes[j].channels;
3889114402Sru		for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
3890114402Sru			if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
3891114402Sru				continue;
3892114402Sru			ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
3893114402Sru					  chnl[i].chan, chnl[i].freq,
3894114402Sru					  chnl[i].flag & HOSTAPD_CHAN_NO_IR ?
3895114402Sru					  " (NO_IR)" : "",
3896114402Sru					  chnl[i].flag & HOSTAPD_CHAN_RADAR ?
3897114402Sru					  " (DFS)" : "");
3898114402Sru
3899114402Sru			if (os_snprintf_error(end - pos, ret))
3900114402Sru				return pos - buf;
3901114402Sru			pos += ret;
3902114402Sru		}
3903114402Sru		ret = os_snprintf(pos, end - pos, "\n");
3904114402Sru		if (os_snprintf_error(end - pos, ret))
3905114402Sru			return pos - buf;
3906114402Sru		pos += ret;
3907114402Sru	}
3908114402Sru
3909114402Sru	return pos - buf;
3910114402Sru}
3911114402Sru
3912114402Sru
3913114402Srustatic int wpa_supplicant_ctrl_iface_get_capability(
3914114402Sru	struct wpa_supplicant *wpa_s, const char *_field, char *buf,
3915114402Sru	size_t buflen)
3916114402Sru{
3917114402Sru	struct wpa_driver_capa capa;
3918114402Sru	int res;
3919114402Sru	char *strict;
3920114402Sru	char field[30];
3921114402Sru	size_t len;
3922114402Sru
3923114402Sru	/* Determine whether or not strict checking was requested */
3924114402Sru	len = os_strlcpy(field, _field, sizeof(field));
3925114402Sru	if (len >= sizeof(field))
3926114402Sru		return -1;
3927114402Sru	strict = os_strchr(field, ' ');
3928114402Sru	if (strict != NULL) {
3929114402Sru		*strict++ = '\0';
3930114402Sru		if (os_strcmp(strict, "strict") != 0)
3931114402Sru			return -1;
3932114402Sru	}
3933114402Sru
3934114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
3935114402Sru		field, strict ? strict : "");
3936114402Sru
3937114402Sru	if (os_strcmp(field, "eap") == 0) {
3938114402Sru		return eap_get_names(buf, buflen);
3939114402Sru	}
3940114402Sru
3941114402Sru	res = wpa_drv_get_capa(wpa_s, &capa);
3942114402Sru
3943114402Sru	if (os_strcmp(field, "pairwise") == 0)
3944114402Sru		return ctrl_iface_get_capability_pairwise(res, strict, &capa,
3945114402Sru							  buf, buflen);
3946114402Sru
3947114402Sru	if (os_strcmp(field, "group") == 0)
3948114402Sru		return ctrl_iface_get_capability_group(res, strict, &capa,
3949114402Sru						       buf, buflen);
3950114402Sru
3951114402Sru	if (os_strcmp(field, "group_mgmt") == 0)
3952114402Sru		return ctrl_iface_get_capability_group_mgmt(res, strict, &capa,
3953114402Sru							    buf, buflen);
3954114402Sru
3955114402Sru	if (os_strcmp(field, "key_mgmt") == 0)
3956114402Sru		return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
3957114402Sru							  buf, buflen);
3958114402Sru
3959114402Sru	if (os_strcmp(field, "proto") == 0)
3960114402Sru		return ctrl_iface_get_capability_proto(res, strict, &capa,
3961114402Sru						       buf, buflen);
3962114402Sru
3963114402Sru	if (os_strcmp(field, "auth_alg") == 0)
3964114402Sru		return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
3965114402Sru							  &capa, buf, buflen);
3966114402Sru
3967114402Sru	if (os_strcmp(field, "modes") == 0)
3968114402Sru		return ctrl_iface_get_capability_modes(res, strict, &capa,
3969114402Sru						       buf, buflen);
3970114402Sru
3971114402Sru	if (os_strcmp(field, "channels") == 0)
3972114402Sru		return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
3973114402Sru
3974114402Sru	if (os_strcmp(field, "freq") == 0)
3975114402Sru		return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
3976114402Sru
3977114402Sru#ifdef CONFIG_TDLS
3978114402Sru	if (os_strcmp(field, "tdls") == 0)
3979114402Sru		return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
3980114402Sru#endif /* CONFIG_TDLS */
3981114402Sru
3982114402Sru#ifdef CONFIG_ERP
3983114402Sru	if (os_strcmp(field, "erp") == 0) {
3984114402Sru		res = os_snprintf(buf, buflen, "ERP");
3985114402Sru		if (os_snprintf_error(buflen, res))
3986114402Sru			return -1;
3987114402Sru		return res;
3988114402Sru	}
3989114402Sru#endif /* CONFIG_EPR */
3990114402Sru
3991114402Sru#ifdef CONFIG_FIPS
3992114402Sru	if (os_strcmp(field, "fips") == 0) {
3993114402Sru		res = os_snprintf(buf, buflen, "FIPS");
3994114402Sru		if (os_snprintf_error(buflen, res))
3995114402Sru			return -1;
3996114402Sru		return res;
3997114402Sru	}
3998114402Sru#endif /* CONFIG_FIPS */
3999114402Sru
4000114402Sru#ifdef CONFIG_ACS
4001114402Sru	if (os_strcmp(field, "acs") == 0) {
4002114402Sru		res = os_snprintf(buf, buflen, "ACS");
4003114402Sru		if (os_snprintf_error(buflen, res))
4004114402Sru			return -1;
4005114402Sru		return res;
4006114402Sru	}
4007114402Sru#endif /* CONFIG_ACS */
4008114402Sru
4009114402Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
4010114402Sru		   field);
4011114402Sru
4012114402Sru	return -1;
4013114402Sru}
4014114402Sru
4015114402Sru
4016114402Sru#ifdef CONFIG_INTERWORKING
4017114402Srustatic char * anqp_add_hex(char *pos, char *end, const char *title,
4018114402Sru			   struct wpabuf *data)
4019114402Sru{
4020114402Sru	char *start = pos;
4021114402Sru	size_t i;
4022114402Sru	int ret;
4023114402Sru	const u8 *d;
4024114402Sru
4025114402Sru	if (data == NULL)
4026114402Sru		return start;
4027114402Sru
4028151497Sru	ret = os_snprintf(pos, end - pos, "%s=", title);
4029151497Sru	if (os_snprintf_error(end - pos, ret))
4030151497Sru		return start;
4031151497Sru	pos += ret;
4032151497Sru
4033151497Sru	d = wpabuf_head_u8(data);
4034151497Sru	for (i = 0; i < wpabuf_len(data); i++) {
4035151497Sru		ret = os_snprintf(pos, end - pos, "%02x", *d++);
4036151497Sru		if (os_snprintf_error(end - pos, ret))
4037151497Sru			return start;
4038151497Sru		pos += ret;
4039151497Sru	}
4040151497Sru
4041151497Sru	ret = os_snprintf(pos, end - pos, "\n");
4042151497Sru	if (os_snprintf_error(end - pos, ret))
4043151497Sru		return start;
4044151497Sru	pos += ret;
4045114402Sru
4046114402Sru	return pos;
4047114402Sru}
4048114402Sru#endif /* CONFIG_INTERWORKING */
4049114402Sru
4050114402Sru
4051114402Srustatic int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
4052114402Sru			  unsigned long mask, char *buf, size_t buflen)
4053114402Sru{
4054114402Sru	size_t i;
4055114402Sru	int ret;
4056114402Sru	char *pos, *end;
4057114402Sru	const u8 *ie, *ie2, *osen_ie;
4058114402Sru
4059114402Sru	pos = buf;
4060114402Sru	end = buf + buflen;
4061114402Sru
4062114402Sru	if (mask & WPA_BSS_MASK_ID) {
4063114402Sru		ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
4064114402Sru		if (os_snprintf_error(end - pos, ret))
4065114402Sru			return 0;
4066114402Sru		pos += ret;
4067114402Sru	}
4068151497Sru
4069114402Sru	if (mask & WPA_BSS_MASK_BSSID) {
4070114402Sru		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
4071114402Sru				  MAC2STR(bss->bssid));
4072114402Sru		if (os_snprintf_error(end - pos, ret))
4073114402Sru			return 0;
4074114402Sru		pos += ret;
4075114402Sru	}
4076114402Sru
4077114402Sru	if (mask & WPA_BSS_MASK_FREQ) {
4078114402Sru		ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
4079114402Sru		if (os_snprintf_error(end - pos, ret))
4080114402Sru			return 0;
4081114402Sru		pos += ret;
4082114402Sru	}
4083114402Sru
4084114402Sru	if (mask & WPA_BSS_MASK_BEACON_INT) {
4085114402Sru		ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
4086114402Sru				  bss->beacon_int);
4087114402Sru		if (os_snprintf_error(end - pos, ret))
4088114402Sru			return 0;
4089114402Sru		pos += ret;
4090114402Sru	}
4091114402Sru
4092114402Sru	if (mask & WPA_BSS_MASK_CAPABILITIES) {
4093114402Sru		ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
4094114402Sru				  bss->caps);
4095114402Sru		if (os_snprintf_error(end - pos, ret))
4096114402Sru			return 0;
4097114402Sru		pos += ret;
4098114402Sru	}
4099114402Sru
4100114402Sru	if (mask & WPA_BSS_MASK_QUAL) {
4101114402Sru		ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
4102114402Sru		if (os_snprintf_error(end - pos, ret))
4103114402Sru			return 0;
4104114402Sru		pos += ret;
4105114402Sru	}
4106114402Sru
4107114402Sru	if (mask & WPA_BSS_MASK_NOISE) {
4108114402Sru		ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
4109114402Sru		if (os_snprintf_error(end - pos, ret))
4110114402Sru			return 0;
4111114402Sru		pos += ret;
4112114402Sru	}
4113114402Sru
4114114402Sru	if (mask & WPA_BSS_MASK_LEVEL) {
4115114402Sru		ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
4116114402Sru		if (os_snprintf_error(end - pos, ret))
4117114402Sru			return 0;
4118114402Sru		pos += ret;
4119114402Sru	}
4120114402Sru
4121114402Sru	if (mask & WPA_BSS_MASK_TSF) {
4122114402Sru		ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
4123114402Sru				  (unsigned long long) bss->tsf);
4124114402Sru		if (os_snprintf_error(end - pos, ret))
4125114402Sru			return 0;
4126114402Sru		pos += ret;
4127114402Sru	}
4128114402Sru
4129114402Sru	if (mask & WPA_BSS_MASK_AGE) {
4130114402Sru		struct os_reltime now;
4131114402Sru
4132114402Sru		os_get_reltime(&now);
4133114402Sru		ret = os_snprintf(pos, end - pos, "age=%d\n",
4134114402Sru				  (int) (now.sec - bss->last_update.sec));
4135114402Sru		if (os_snprintf_error(end - pos, ret))
4136114402Sru			return 0;
4137114402Sru		pos += ret;
4138114402Sru	}
4139114402Sru
4140114402Sru	if (mask & WPA_BSS_MASK_IE) {
4141114402Sru		ret = os_snprintf(pos, end - pos, "ie=");
4142114402Sru		if (os_snprintf_error(end - pos, ret))
4143114402Sru			return 0;
4144114402Sru		pos += ret;
4145114402Sru
4146114402Sru		ie = (const u8 *) (bss + 1);
4147114402Sru		for (i = 0; i < bss->ie_len; i++) {
4148114402Sru			ret = os_snprintf(pos, end - pos, "%02x", *ie++);
4149114402Sru			if (os_snprintf_error(end - pos, ret))
4150114402Sru				return 0;
4151114402Sru			pos += ret;
4152114402Sru		}
4153114402Sru
4154114402Sru		ret = os_snprintf(pos, end - pos, "\n");
4155114402Sru		if (os_snprintf_error(end - pos, ret))
4156114402Sru			return 0;
4157114402Sru		pos += ret;
4158114402Sru	}
4159114402Sru
4160114402Sru	if (mask & WPA_BSS_MASK_FLAGS) {
4161114402Sru		ret = os_snprintf(pos, end - pos, "flags=");
4162114402Sru		if (os_snprintf_error(end - pos, ret))
4163114402Sru			return 0;
4164114402Sru		pos += ret;
4165114402Sru
4166114402Sru		ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
4167114402Sru		if (ie)
4168114402Sru			pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
4169114402Sru						    2 + ie[1]);
4170114402Sru		ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
4171114402Sru		if (ie2)
4172114402Sru			pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
4173114402Sru						    2 + ie2[1]);
4174114402Sru		osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
4175114402Sru		if (osen_ie)
4176114402Sru			pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
4177114402Sru						    osen_ie, 2 + osen_ie[1]);
4178114402Sru		pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
4179151497Sru		if (!ie && !ie2 && !osen_ie &&
4180151497Sru		    (bss->caps & IEEE80211_CAP_PRIVACY)) {
4181151497Sru			ret = os_snprintf(pos, end - pos, "[WEP]");
4182151497Sru			if (os_snprintf_error(end - pos, ret))
4183114402Sru				return 0;
4184151497Sru			pos += ret;
4185151497Sru		}
4186151497Sru		if (bss_is_dmg(bss)) {
4187151497Sru			const char *s;
4188151497Sru			ret = os_snprintf(pos, end - pos, "[DMG]");
4189151497Sru			if (os_snprintf_error(end - pos, ret))
4190151497Sru				return 0;
4191151497Sru			pos += ret;
4192151497Sru			switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
4193151497Sru			case IEEE80211_CAP_DMG_IBSS:
4194151497Sru				s = "[IBSS]";
4195151497Sru				break;
4196151497Sru			case IEEE80211_CAP_DMG_AP:
4197114402Sru				s = "[ESS]";
4198114402Sru				break;
4199114402Sru			case IEEE80211_CAP_DMG_PBSS:
4200114402Sru				s = "[PBSS]";
4201114402Sru				break;
4202114402Sru			default:
4203114402Sru				s = "";
4204114402Sru				break;
4205114402Sru			}
4206114402Sru			ret = os_snprintf(pos, end - pos, "%s", s);
4207114402Sru			if (os_snprintf_error(end - pos, ret))
4208114402Sru				return 0;
4209114402Sru			pos += ret;
4210114402Sru		} else {
4211114402Sru			if (bss->caps & IEEE80211_CAP_IBSS) {
4212114402Sru				ret = os_snprintf(pos, end - pos, "[IBSS]");
4213114402Sru				if (os_snprintf_error(end - pos, ret))
4214114402Sru					return 0;
4215114402Sru				pos += ret;
4216114402Sru			}
4217114402Sru			if (bss->caps & IEEE80211_CAP_ESS) {
4218114402Sru				ret = os_snprintf(pos, end - pos, "[ESS]");
4219114402Sru				if (os_snprintf_error(end - pos, ret))
4220114402Sru					return 0;
4221114402Sru				pos += ret;
4222114402Sru			}
4223114402Sru		}
4224114402Sru		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
4225114402Sru		    wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
4226114402Sru			ret = os_snprintf(pos, end - pos, "[P2P]");
4227114402Sru			if (os_snprintf_error(end - pos, ret))
4228114402Sru				return 0;
4229114402Sru			pos += ret;
4230114402Sru		}
4231151497Sru#ifdef CONFIG_HS20
4232114402Sru		if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
4233114402Sru			ret = os_snprintf(pos, end - pos, "[HS20]");
4234114402Sru			if (os_snprintf_error(end - pos, ret))
4235114402Sru				return 0;
4236114402Sru			pos += ret;
4237151497Sru		}
4238114402Sru#endif /* CONFIG_HS20 */
4239114402Sru
4240151497Sru		ret = os_snprintf(pos, end - pos, "\n");
4241151497Sru		if (os_snprintf_error(end - pos, ret))
4242114402Sru			return 0;
4243114402Sru		pos += ret;
4244114402Sru	}
4245114402Sru
4246114402Sru	if (mask & WPA_BSS_MASK_SSID) {
4247114402Sru		ret = os_snprintf(pos, end - pos, "ssid=%s\n",
4248114402Sru				  wpa_ssid_txt(bss->ssid, bss->ssid_len));
4249114402Sru		if (os_snprintf_error(end - pos, ret))
4250114402Sru			return 0;
4251114402Sru		pos += ret;
4252114402Sru	}
4253114402Sru
4254114402Sru#ifdef CONFIG_WPS
4255114402Sru	if (mask & WPA_BSS_MASK_WPS_SCAN) {
4256114402Sru		ie = (const u8 *) (bss + 1);
4257151497Sru		ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
4258114402Sru		if (ret >= end - pos)
4259114402Sru			return 0;
4260114402Sru		if (ret > 0)
4261114402Sru			pos += ret;
4262114402Sru	}
4263114402Sru#endif /* CONFIG_WPS */
4264114402Sru
4265114402Sru#ifdef CONFIG_P2P
4266114402Sru	if (mask & WPA_BSS_MASK_P2P_SCAN) {
4267151497Sru		ie = (const u8 *) (bss + 1);
4268114402Sru		ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
4269114402Sru		if (ret >= end - pos)
4270114402Sru			return 0;
4271114402Sru		if (ret > 0)
4272114402Sru			pos += ret;
4273114402Sru	}
4274114402Sru#endif /* CONFIG_P2P */
4275114402Sru
4276114402Sru#ifdef CONFIG_WIFI_DISPLAY
4277114402Sru	if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
4278114402Sru		struct wpabuf *wfd;
4279151497Sru		ie = (const u8 *) (bss + 1);
4280114402Sru		wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
4281114402Sru						  WFD_IE_VENDOR_TYPE);
4282114402Sru		if (wfd) {
4283114402Sru			ret = os_snprintf(pos, end - pos, "wfd_subelems=");
4284114402Sru			if (os_snprintf_error(end - pos, ret)) {
4285114402Sru				wpabuf_free(wfd);
4286114402Sru				return 0;
4287114402Sru			}
4288114402Sru			pos += ret;
4289114402Sru
4290114402Sru			pos += wpa_snprintf_hex(pos, end - pos,
4291114402Sru						wpabuf_head(wfd),
4292114402Sru						wpabuf_len(wfd));
4293114402Sru			wpabuf_free(wfd);
4294114402Sru
4295114402Sru			ret = os_snprintf(pos, end - pos, "\n");
4296151497Sru			if (os_snprintf_error(end - pos, ret))
4297114402Sru				return 0;
4298114402Sru			pos += ret;
4299114402Sru		}
4300114402Sru	}
4301151497Sru#endif /* CONFIG_WIFI_DISPLAY */
4302151497Sru
4303114402Sru#ifdef CONFIG_INTERWORKING
4304114402Sru	if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
4305114402Sru		struct wpa_bss_anqp *anqp = bss->anqp;
4306151497Sru		struct wpa_bss_anqp_elem *elem;
4307151497Sru
4308114402Sru		pos = anqp_add_hex(pos, end, "anqp_capability_list",
4309114402Sru				   anqp->capability_list);
4310114402Sru		pos = anqp_add_hex(pos, end, "anqp_venue_name",
4311114402Sru				   anqp->venue_name);
4312114402Sru		pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
4313114402Sru				   anqp->network_auth_type);
4314114402Sru		pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
4315114402Sru				   anqp->roaming_consortium);
4316114402Sru		pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
4317114402Sru				   anqp->ip_addr_type_availability);
4318114402Sru		pos = anqp_add_hex(pos, end, "anqp_nai_realm",
4319114402Sru				   anqp->nai_realm);
4320151497Sru		pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
4321114402Sru		pos = anqp_add_hex(pos, end, "anqp_domain_name",
4322114402Sru				   anqp->domain_name);
4323114402Sru#ifdef CONFIG_HS20
4324114402Sru		pos = anqp_add_hex(pos, end, "hs20_capability_list",
4325114402Sru				   anqp->hs20_capability_list);
4326114402Sru		pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
4327114402Sru				   anqp->hs20_operator_friendly_name);
4328114402Sru		pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
4329114402Sru				   anqp->hs20_wan_metrics);
4330151497Sru		pos = anqp_add_hex(pos, end, "hs20_connection_capability",
4331114402Sru				   anqp->hs20_connection_capability);
4332114402Sru		pos = anqp_add_hex(pos, end, "hs20_operating_class",
4333114402Sru				   anqp->hs20_operating_class);
4334114402Sru		pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
4335114402Sru				   anqp->hs20_osu_providers_list);
4336114402Sru#endif /* CONFIG_HS20 */
4337114402Sru
4338114402Sru		dl_list_for_each(elem, &anqp->anqp_elems,
4339151497Sru				 struct wpa_bss_anqp_elem, list) {
4340114402Sru			char title[20];
4341114402Sru
4342114402Sru			os_snprintf(title, sizeof(title), "anqp[%u]",
4343114402Sru				    elem->infoid);
4344114402Sru			pos = anqp_add_hex(pos, end, title, elem->payload);
4345114402Sru		}
4346114402Sru	}
4347114402Sru#endif /* CONFIG_INTERWORKING */
4348151497Sru
4349151497Sru#ifdef CONFIG_MESH
4350151497Sru	if (mask & WPA_BSS_MASK_MESH_SCAN) {
4351114402Sru		ie = (const u8 *) (bss + 1);
4352114402Sru		ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
4353151497Sru		if (ret >= end - pos)
4354151497Sru			return 0;
4355114402Sru		if (ret > 0)
4356114402Sru			pos += ret;
4357114402Sru	}
4358114402Sru#endif /* CONFIG_MESH */
4359114402Sru
4360114402Sru	if (mask & WPA_BSS_MASK_SNR) {
4361114402Sru		ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr);
4362114402Sru		if (os_snprintf_error(end - pos, ret))
4363114402Sru			return 0;
4364114402Sru		pos += ret;
4365114402Sru	}
4366114402Sru
4367114402Sru	if (mask & WPA_BSS_MASK_EST_THROUGHPUT) {
4368151497Sru		ret = os_snprintf(pos, end - pos, "est_throughput=%d\n",
4369151497Sru				  bss->est_throughput);
4370114402Sru		if (os_snprintf_error(end - pos, ret))
4371114402Sru			return 0;
4372114402Sru		pos += ret;
4373114402Sru	}
4374114402Sru
4375114402Sru#ifdef CONFIG_FST
4376114402Sru	if (mask & WPA_BSS_MASK_FST) {
4377114402Sru		ret = fst_ctrl_iface_mb_info(bss->bssid, pos, end - pos);
4378114402Sru		if (ret < 0 || ret >= end - pos)
4379114402Sru			return 0;
4380114402Sru		pos += ret;
4381114402Sru	}
4382114402Sru#endif /* CONFIG_FST */
4383114402Sru
4384114402Sru	if (mask & WPA_BSS_MASK_DELIM) {
4385114402Sru		ret = os_snprintf(pos, end - pos, "====\n");
4386114402Sru		if (os_snprintf_error(end - pos, ret))
4387114402Sru			return 0;
4388114402Sru		pos += ret;
4389114402Sru	}
4390114402Sru
4391114402Sru	return pos - buf;
4392114402Sru}
4393114402Sru
4394114402Sru
4395114402Srustatic int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
4396114402Sru					 const char *cmd, char *buf,
4397114402Sru					 size_t buflen)
4398114402Sru{
4399114402Sru	u8 bssid[ETH_ALEN];
4400114402Sru	size_t i;
4401114402Sru	struct wpa_bss *bss;
4402114402Sru	struct wpa_bss *bsslast = NULL;
4403114402Sru	struct dl_list *next;
4404114402Sru	int ret = 0;
4405114402Sru	int len;
4406114402Sru	char *ctmp, *end = buf + buflen;
4407114402Sru	unsigned long mask = WPA_BSS_MASK_ALL;
4408114402Sru
4409114402Sru	if (os_strncmp(cmd, "RANGE=", 6) == 0) {
4410114402Sru		if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
4411114402Sru			bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
4412114402Sru					    list_id);
4413114402Sru			bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
4414114402Sru					       list_id);
4415151497Sru		} else { /* N1-N2 */
4416114402Sru			unsigned int id1, id2;
4417114402Sru
4418114402Sru			if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
4419114402Sru				wpa_printf(MSG_INFO, "Wrong BSS range "
4420114402Sru					   "format");
4421151497Sru				return 0;
4422151497Sru			}
4423151497Sru
4424151497Sru			if (*(cmd + 6) == '-')
4425151497Sru				id1 = 0;
4426151497Sru			else
4427151497Sru				id1 = atoi(cmd + 6);
4428151497Sru			ctmp++;
4429151497Sru			if (*ctmp >= '0' && *ctmp <= '9')
4430151497Sru				id2 = atoi(ctmp);
4431151497Sru			else
4432151497Sru				id2 = (unsigned int) -1;
4433151497Sru			bss = wpa_bss_get_id_range(wpa_s, id1, id2);
4434151497Sru			if (id2 == (unsigned int) -1)
4435151497Sru				bsslast = dl_list_last(&wpa_s->bss_id,
4436151497Sru						       struct wpa_bss,
4437151497Sru						       list_id);
4438151497Sru			else {
4439151497Sru				bsslast = wpa_bss_get_id(wpa_s, id2);
4440151497Sru				if (bsslast == NULL && bss && id2 > id1) {
4441151497Sru					struct wpa_bss *tmp = bss;
4442151497Sru					for (;;) {
4443151497Sru						next = tmp->list_id.next;
4444151497Sru						if (next == &wpa_s->bss_id)
4445151497Sru							break;
4446151497Sru						tmp = dl_list_entry(
4447151497Sru							next, struct wpa_bss,
4448151497Sru							list_id);
4449151497Sru						if (tmp->id > id2)
4450151497Sru							break;
4451151497Sru						bsslast = tmp;
4452151497Sru					}
4453114402Sru				}
4454114402Sru			}
4455114402Sru		}
4456114402Sru	} else if (os_strncmp(cmd, "FIRST", 5) == 0)
4457114402Sru		bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
4458114402Sru	else if (os_strncmp(cmd, "LAST", 4) == 0)
4459114402Sru		bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
4460114402Sru	else if (os_strncmp(cmd, "ID-", 3) == 0) {
4461114402Sru		i = atoi(cmd + 3);
4462114402Sru		bss = wpa_bss_get_id(wpa_s, i);
4463114402Sru	} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
4464114402Sru		i = atoi(cmd + 5);
4465114402Sru		bss = wpa_bss_get_id(wpa_s, i);
4466114402Sru		if (bss) {
4467114402Sru			next = bss->list_id.next;
4468114402Sru			if (next == &wpa_s->bss_id)
4469114402Sru				bss = NULL;
4470114402Sru			else
4471114402Sru				bss = dl_list_entry(next, struct wpa_bss,
4472114402Sru						    list_id);
4473114402Sru		}
4474114402Sru#ifdef CONFIG_P2P
4475114402Sru	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
4476114402Sru		if (hwaddr_aton(cmd + 13, bssid) == 0)
4477114402Sru			bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
4478114402Sru		else
4479114402Sru			bss = NULL;
4480114402Sru#endif /* CONFIG_P2P */
4481114402Sru	} else if (hwaddr_aton(cmd, bssid) == 0)
4482114402Sru		bss = wpa_bss_get_bssid(wpa_s, bssid);
4483114402Sru	else {
4484114402Sru		struct wpa_bss *tmp;
4485114402Sru		i = atoi(cmd);
4486114402Sru		bss = NULL;
4487114402Sru		dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
4488114402Sru		{
4489114402Sru			if (i-- == 0) {
4490114402Sru				bss = tmp;
4491114402Sru				break;
4492114402Sru			}
4493114402Sru		}
4494114402Sru	}
4495114402Sru
4496114402Sru	if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
4497114402Sru		mask = strtoul(ctmp + 5, NULL, 0x10);
4498114402Sru		if (mask == 0)
4499114402Sru			mask = WPA_BSS_MASK_ALL;
4500114402Sru	}
4501114402Sru
4502114402Sru	if (bss == NULL)
4503114402Sru		return 0;
4504114402Sru
4505151497Sru	if (bsslast == NULL)
4506151497Sru		bsslast = bss;
4507114402Sru	do {
4508114402Sru		len = print_bss_info(wpa_s, bss, mask, buf, buflen);
4509114402Sru		ret += len;
4510114402Sru		buf += len;
4511114402Sru		buflen -= len;
4512114402Sru		if (bss == bsslast) {
4513114402Sru			if ((mask & WPA_BSS_MASK_DELIM) && len &&
4514114402Sru			    (bss == dl_list_last(&wpa_s->bss_id,
4515114402Sru						 struct wpa_bss, list_id))) {
4516114402Sru				int res;
4517114402Sru
4518114402Sru				res = os_snprintf(buf - 5, end - buf + 5,
4519114402Sru						  "####\n");
4520114402Sru				if (os_snprintf_error(end - buf + 5, res)) {
4521114402Sru					wpa_printf(MSG_DEBUG,
4522114402Sru						   "Could not add end delim");
4523114402Sru				}
4524114402Sru			}
4525114402Sru			break;
4526114402Sru		}
4527114402Sru		next = bss->list_id.next;
4528114402Sru		if (next == &wpa_s->bss_id)
4529114402Sru			break;
4530114402Sru		bss = dl_list_entry(next, struct wpa_bss, list_id);
4531114402Sru	} while (bss && len);
4532114402Sru
4533114402Sru	return ret;
4534114402Sru}
4535114402Sru
4536114402Sru
4537114402Srustatic int wpa_supplicant_ctrl_iface_ap_scan(
4538151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
4539151497Sru{
4540151497Sru	int ap_scan = atoi(cmd);
4541151497Sru	return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
4542151497Sru}
4543151497Sru
4544151497Sru
4545151497Srustatic int wpa_supplicant_ctrl_iface_scan_interval(
4546151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
4547151497Sru{
4548151497Sru	int scan_int = atoi(cmd);
4549151497Sru	return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
4550151497Sru}
4551151497Sru
4552151497Sru
4553151497Srustatic int wpa_supplicant_ctrl_iface_bss_expire_age(
4554151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
4555151497Sru{
4556151497Sru	int expire_age = atoi(cmd);
4557151497Sru	return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
4558151497Sru}
4559151497Sru
4560151497Sru
4561151497Srustatic int wpa_supplicant_ctrl_iface_bss_expire_count(
4562151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
4563151497Sru{
4564151497Sru	int expire_count = atoi(cmd);
4565151497Sru	return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
4566151497Sru}
4567151497Sru
4568151497Sru
4569151497Srustatic void wpa_supplicant_ctrl_iface_bss_flush(
4570151497Sru	struct wpa_supplicant *wpa_s, char *cmd)
4571151497Sru{
4572151497Sru	int flush_age = atoi(cmd);
4573151497Sru
4574151497Sru	if (flush_age == 0)
4575151497Sru		wpa_bss_flush(wpa_s);
4576151497Sru	else
4577151497Sru		wpa_bss_flush_by_age(wpa_s, flush_age);
4578151497Sru}
4579151497Sru
4580151497Sru
4581151497Sru#ifdef CONFIG_TESTING_OPTIONS
4582151497Srustatic void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
4583151497Sru{
4584151497Sru	wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
4585151497Sru	/* MLME-DELETEKEYS.request */
4586151497Sru	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
4587151497Sru	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
4588151497Sru	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
4589151497Sru	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
4590151497Sru#ifdef CONFIG_IEEE80211W
4591151497Sru	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
4592151497Sru	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
4593151497Sru#endif /* CONFIG_IEEE80211W */
4594151497Sru
4595151497Sru	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
4596151497Sru			0);
4597151497Sru	/* MLME-SETPROTECTION.request(None) */
4598151497Sru	wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
4599151497Sru				   MLME_SETPROTECTION_PROTECT_TYPE_NONE,
4600151497Sru				   MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
4601151497Sru	wpa_sm_drop_sa(wpa_s->wpa);
4602151497Sru}
4603151497Sru#endif /* CONFIG_TESTING_OPTIONS */
4604151497Sru
4605151497Sru
4606151497Srustatic int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
4607151497Sru					  char *addr)
4608151497Sru{
4609151497Sru#ifdef CONFIG_NO_SCAN_PROCESSING
4610151497Sru	return -1;
4611151497Sru#else /* CONFIG_NO_SCAN_PROCESSING */
4612151497Sru	u8 bssid[ETH_ALEN];
4613151497Sru	struct wpa_bss *bss;
4614151497Sru	struct wpa_ssid *ssid = wpa_s->current_ssid;
4615151497Sru
4616151497Sru	if (hwaddr_aton(addr, bssid)) {
4617151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
4618151497Sru			   "address '%s'", addr);
4619151497Sru		return -1;
4620151497Sru	}
4621151497Sru
4622151497Sru	wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
4623151497Sru
4624151497Sru	if (!ssid) {
4625151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
4626151497Sru			   "configuration known for the target AP");
4627151497Sru		return -1;
4628151497Sru	}
4629151497Sru
4630151497Sru	bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
4631151497Sru	if (!bss) {
4632151497Sru		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
4633151497Sru			   "from BSS table");
4634151497Sru		return -1;
4635151497Sru	}
4636151497Sru
4637151497Sru	/*
4638151497Sru	 * TODO: Find best network configuration block from configuration to
4639151497Sru	 * allow roaming to other networks
4640151497Sru	 */
4641151497Sru
4642151497Sru	wpa_s->reassociate = 1;
4643151497Sru	wpa_supplicant_connect(wpa_s, bss, ssid);
4644151497Sru
4645151497Sru	return 0;
4646151497Sru#endif /* CONFIG_NO_SCAN_PROCESSING */
4647151497Sru}
4648151497Sru
4649151497Sru
4650151497Sru#ifdef CONFIG_P2P
4651151497Srustatic int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
4652151497Sru{
4653151497Sru	unsigned int timeout = atoi(cmd);
4654151497Sru	enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
4655151497Sru	u8 dev_id[ETH_ALEN], *_dev_id = NULL;
4656151497Sru	u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
4657151497Sru	char *pos;
4658151497Sru	unsigned int search_delay;
4659151497Sru	const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
4660151497Sru	u8 seek_count = 0;
4661151497Sru	int freq = 0;
4662151497Sru
4663151497Sru	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
4664151497Sru		wpa_dbg(wpa_s, MSG_INFO,
4665114402Sru			"Reject P2P_FIND since interface is disabled");
4666114402Sru		return -1;
4667114402Sru	}
4668114402Sru	if (os_strstr(cmd, "type=social"))
4669114402Sru		type = P2P_FIND_ONLY_SOCIAL;
4670114402Sru	else if (os_strstr(cmd, "type=progressive"))
4671114402Sru		type = P2P_FIND_PROGRESSIVE;
4672114402Sru
4673114402Sru	pos = os_strstr(cmd, "dev_id=");
4674114402Sru	if (pos) {
4675114402Sru		pos += 7;
4676114402Sru		if (hwaddr_aton(pos, dev_id))
4677114402Sru			return -1;
4678114402Sru		_dev_id = dev_id;
4679114402Sru	}
4680114402Sru
4681114402Sru	pos = os_strstr(cmd, "dev_type=");
4682114402Sru	if (pos) {
4683114402Sru		pos += 9;
4684114402Sru		if (wps_dev_type_str2bin(pos, dev_type) < 0)
4685114402Sru			return -1;
4686114402Sru		_dev_type = dev_type;
4687151497Sru	}
4688114402Sru
4689114402Sru	pos = os_strstr(cmd, "delay=");
4690151497Sru	if (pos) {
4691151497Sru		pos += 6;
4692114402Sru		search_delay = atoi(pos);
4693114402Sru	} else
4694114402Sru		search_delay = wpas_p2p_search_delay(wpa_s);
4695114402Sru
4696114402Sru	pos = os_strstr(cmd, "freq=");
4697114402Sru	if (pos) {
4698114402Sru		pos += 5;
4699114402Sru		freq = atoi(pos);
4700114402Sru		if (freq <= 0)
4701114402Sru			return -1;
4702114402Sru	}
4703151497Sru
4704151497Sru	/* Must be searched for last, because it adds nul termination */
4705151497Sru	pos = os_strstr(cmd, " seek=");
4706151497Sru	if (pos)
4707151497Sru		pos += 6;
4708151497Sru	while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
4709151497Sru		char *term;
4710151497Sru
4711151497Sru		_seek[seek_count++] = pos;
4712114402Sru		seek = _seek;
4713114402Sru		term = os_strchr(pos, ' ');
4714114402Sru		if (!term)
4715114402Sru			break;
4716151497Sru		*term = '\0';
4717151497Sru		pos = os_strstr(term + 1, "seek=");
4718114402Sru		if (pos)
4719114402Sru			pos += 5;
4720151497Sru	}
4721151497Sru	if (seek_count > P2P_MAX_QUERY_HASH) {
4722151497Sru		seek[0] = NULL;
4723151497Sru		seek_count = 1;
4724151497Sru	}
4725151497Sru
4726151497Sru	return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
4727151497Sru			     _dev_id, search_delay, seek_count, seek, freq);
4728151497Sru}
4729151497Sru
4730151497Sru
4731151497Srustatic int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt)
4732151497Sru{
4733151497Sru	const char *last = NULL;
4734151497Sru	const char *token;
4735151497Sru	long int token_len;
4736151497Sru	unsigned int i;
4737151497Sru
4738151497Sru	/* Expected predefined CPT names delimited by ':' */
4739151497Sru	for (i = 0; (token = cstr_token(pos, ": \t", &last)); i++) {
4740151497Sru		if (i >= P2PS_FEATURE_CAPAB_CPT_MAX) {
4741151497Sru			wpa_printf(MSG_ERROR,
4742151497Sru				   "P2PS: CPT name list is too long, expected up to %d names",
4743151497Sru				   P2PS_FEATURE_CAPAB_CPT_MAX);
4744151497Sru			cpt[0] = 0;
4745151497Sru			return -1;
4746151497Sru		}
4747151497Sru
4748151497Sru		token_len = last - token;
4749151497Sru
4750151497Sru		if (token_len  == 3 &&
4751151497Sru		    os_memcmp(token, "UDP", token_len) == 0) {
4752151497Sru			cpt[i] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
4753151497Sru		} else if (token_len == 3 &&
4754151497Sru			   os_memcmp(token, "MAC", token_len) == 0) {
4755151497Sru			cpt[i] = P2PS_FEATURE_CAPAB_MAC_TRANSPORT;
4756151497Sru		} else {
4757151497Sru			wpa_printf(MSG_ERROR,
4758151497Sru				   "P2PS: Unsupported CPT name '%s'", token);
4759151497Sru			cpt[0] = 0;
4760151497Sru			return -1;
4761151497Sru		}
4762151497Sru
4763151497Sru		if (isblank((unsigned char) *last)) {
4764151497Sru			i++;
4765151497Sru			break;
4766151497Sru		}
4767151497Sru	}
4768151497Sru	cpt[i] = 0;
4769151497Sru	return 0;
4770151497Sru}
4771151497Sru
4772151497Sru
4773151497Srustatic struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
4774151497Sru{
4775151497Sru	struct p2ps_provision *p2ps_prov;
4776151497Sru	char *pos;
4777151497Sru	size_t info_len = 0;
4778151497Sru	char *info = NULL;
4779151497Sru	u8 role = P2PS_SETUP_NONE;
4780151497Sru	long long unsigned val;
4781151497Sru	int i;
4782151497Sru
4783151497Sru	pos = os_strstr(cmd, "info=");
4784151497Sru	if (pos) {
4785151497Sru		pos += 5;
4786151497Sru		info_len = os_strlen(pos);
4787151497Sru
4788151497Sru		if (info_len) {
4789151497Sru			info = os_malloc(info_len + 1);
4790151497Sru			if (info) {
4791151497Sru				info_len = utf8_unescape(pos, info_len,
4792151497Sru							 info, info_len + 1);
4793151497Sru			} else
4794151497Sru				info_len = 0;
4795151497Sru		}
4796151497Sru	}
4797151497Sru
4798151497Sru	p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1);
4799151497Sru	if (p2ps_prov == NULL) {
4800151497Sru		os_free(info);
4801151497Sru		return NULL;
4802151497Sru	}
4803151497Sru
4804151497Sru	if (info) {
4805151497Sru		os_memcpy(p2ps_prov->info, info, info_len);
4806151497Sru		p2ps_prov->info[info_len] = '\0';
4807151497Sru		os_free(info);
4808151497Sru	}
4809151497Sru
4810151497Sru	pos = os_strstr(cmd, "status=");
4811151497Sru	if (pos)
4812151497Sru		p2ps_prov->status = atoi(pos + 7);
4813151497Sru	else
4814151497Sru		p2ps_prov->status = -1;
4815151497Sru
4816151497Sru	pos = os_strstr(cmd, "adv_id=");
4817151497Sru	if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL)
4818151497Sru		goto invalid_args;
4819151497Sru	p2ps_prov->adv_id = val;
4820151497Sru
4821151497Sru	pos = os_strstr(cmd, "method=");
4822151497Sru	if (pos)
4823151497Sru		p2ps_prov->method = strtol(pos + 7, NULL, 16);
4824151497Sru	else
4825151497Sru		p2ps_prov->method = 0;
4826151497Sru
4827151497Sru	pos = os_strstr(cmd, "session=");
4828151497Sru	if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL)
4829151497Sru		goto invalid_args;
4830114402Sru	p2ps_prov->session_id = val;
4831114402Sru
4832114402Sru	pos = os_strstr(cmd, "adv_mac=");
4833114402Sru	if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac))
4834114402Sru		goto invalid_args;
4835114402Sru
4836114402Sru	pos = os_strstr(cmd, "session_mac=");
4837114402Sru	if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))
4838114402Sru		goto invalid_args;
4839114402Sru
4840114402Sru	pos = os_strstr(cmd, "cpt=");
4841114402Sru	if (pos) {
4842114402Sru		if (p2ps_ctrl_parse_cpt_priority(pos + 4,
4843114402Sru						 p2ps_prov->cpt_priority))
4844114402Sru			goto invalid_args;
4845114402Sru	} else {
4846114402Sru		p2ps_prov->cpt_priority[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
4847114402Sru	}
4848114402Sru
4849114402Sru	for (i = 0; p2ps_prov->cpt_priority[i]; i++)
4850114402Sru		p2ps_prov->cpt_mask |= p2ps_prov->cpt_priority[i];
4851114402Sru
4852114402Sru	/* force conncap with tstCap (no sanity checks) */
4853114402Sru	pos = os_strstr(cmd, "tstCap=");
4854114402Sru	if (pos) {
4855114402Sru		role = strtol(pos + 7, NULL, 16);
4856114402Sru	} else {
4857114402Sru		pos = os_strstr(cmd, "role=");
4858151497Sru		if (pos) {
4859151497Sru			role = strtol(pos + 5, NULL, 16);
4860114402Sru			if (role != P2PS_SETUP_CLIENT &&
4861114402Sru			    role != P2PS_SETUP_GROUP_OWNER)
4862151497Sru				role = P2PS_SETUP_NONE;
4863151497Sru		}
4864151497Sru	}
4865151497Sru	p2ps_prov->role = role;
4866114402Sru
4867151497Sru	return p2ps_prov;
4868151497Sru
4869151497Sruinvalid_args:
4870151497Sru	os_free(p2ps_prov);
4871151497Sru	return NULL;
4872151497Sru}
4873151497Sru
4874151497Sru
4875151497Srustatic int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
4876151497Sru{
4877151497Sru	u8 addr[ETH_ALEN];
4878151497Sru	struct p2ps_provision *p2ps_prov;
4879151497Sru	char *pos;
4880151497Sru
4881151497Sru	/* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */
4882151497Sru
4883151497Sru	wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
4884151497Sru
4885151497Sru	if (hwaddr_aton(cmd, addr))
4886151497Sru		return -1;
4887151497Sru
4888151497Sru	pos = cmd + 17;
4889151497Sru	if (*pos != ' ')
4890151497Sru		return -1;
4891151497Sru
4892114402Sru	p2ps_prov = p2p_parse_asp_provision_cmd(pos);
4893114402Sru	if (!p2ps_prov)
4894151497Sru		return -1;
4895114402Sru
4896114402Sru	if (p2ps_prov->status < 0) {
4897151497Sru		os_free(p2ps_prov);
4898151497Sru		return -1;
4899151497Sru	}
4900151497Sru
4901151497Sru	return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
4902151497Sru				  p2ps_prov);
4903151497Sru}
4904151497Sru
4905151497Sru
4906151497Srustatic int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
4907151497Sru{
4908151497Sru	u8 addr[ETH_ALEN];
4909151497Sru	struct p2ps_provision *p2ps_prov;
4910151497Sru	char *pos;
4911151497Sru
4912151497Sru	/* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap>
4913151497Sru	 *        session=<ses_id> mac=<ses_mac> [info=<infodata>]
4914151497Sru	 */
4915151497Sru
4916151497Sru	wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
4917151497Sru	if (hwaddr_aton(cmd, addr))
4918151497Sru		return -1;
4919151497Sru
4920151497Sru	pos = cmd + 17;
4921151497Sru	if (*pos != ' ')
4922151497Sru		return -1;
4923151497Sru
4924151497Sru	p2ps_prov = p2p_parse_asp_provision_cmd(pos);
4925151497Sru	if (!p2ps_prov)
4926151497Sru		return -1;
4927114402Sru
4928114402Sru	p2ps_prov->pd_seeker = 1;
4929114402Sru
4930114402Sru	return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
4931114402Sru				  p2ps_prov);
4932114402Sru}
4933114402Sru
4934114402Sru
4935151497Srustatic int parse_freq(int chwidth, int freq2)
4936151497Sru{
4937151497Sru	if (freq2 < 0)
4938151497Sru		return -1;
4939151497Sru	if (freq2)
4940151497Sru		return VHT_CHANWIDTH_80P80MHZ;
4941151497Sru
4942151497Sru	switch (chwidth) {
4943151497Sru	case 0:
4944151497Sru	case 20:
4945151497Sru	case 40:
4946151497Sru		return VHT_CHANWIDTH_USE_HT;
4947151497Sru	case 80:
4948151497Sru		return VHT_CHANWIDTH_80MHZ;
4949151497Sru	case 160:
4950151497Sru		return VHT_CHANWIDTH_160MHZ;
4951151497Sru	default:
4952151497Sru		wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
4953151497Sru			   chwidth);
4954151497Sru		return -1;
4955114402Sru	}
4956114402Sru}
4957114402Sru
4958114402Sru
4959114402Srustatic int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
4960114402Sru			    char *buf, size_t buflen)
4961114402Sru{
4962114402Sru	u8 addr[ETH_ALEN];
4963114402Sru	char *pos, *pos2;
4964114402Sru	char *pin = NULL;
4965114402Sru	enum p2p_wps_method wps_method;
4966151497Sru	int new_pin;
4967151497Sru	int ret;
4968114402Sru	int persistent_group, persistent_id = -1;
4969114402Sru	int join;
4970114402Sru	int auth;
4971114402Sru	int automatic;
4972114402Sru	int go_intent = -1;
4973114402Sru	int freq = 0;
4974114402Sru	int pd;
4975114402Sru	int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
4976114402Sru	u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
4977114402Sru	size_t group_ssid_len = 0;
4978151497Sru
4979151497Sru	if (!wpa_s->global->p2p_init_wpa_s)
4980151497Sru		return -1;
4981151497Sru	if (wpa_s->global->p2p_init_wpa_s != wpa_s) {
4982151497Sru		wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s",
4983151497Sru			wpa_s->global->p2p_init_wpa_s->ifname);
4984114402Sru		wpa_s = wpa_s->global->p2p_init_wpa_s;
4985114402Sru	}
4986114402Sru
4987151497Sru	/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
4988151497Sru	 * [persistent|persistent=<network id>]
4989114402Sru	 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
4990114402Sru	 * [ht40] [vht] [auto] [ssid=<hexdump>] */
4991114402Sru
4992114402Sru	if (hwaddr_aton(cmd, addr))
4993114402Sru		return -1;
4994114402Sru
4995114402Sru	pos = cmd + 17;
4996114402Sru	if (*pos != ' ')
4997114402Sru		return -1;
4998114402Sru	pos++;
4999114402Sru
5000151497Sru	persistent_group = os_strstr(pos, " persistent") != NULL;
5001151497Sru	pos2 = os_strstr(pos, " persistent=");
5002151497Sru	if (pos2) {
5003114402Sru		struct wpa_ssid *ssid;
5004151497Sru		persistent_id = atoi(pos2 + 12);
5005151497Sru		ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
5006151497Sru		if (ssid == NULL || ssid->disabled != 2 ||
5007114402Sru		    ssid->mode != WPAS_MODE_P2P_GO) {
5008114402Sru			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
5009114402Sru				   "SSID id=%d for persistent P2P group (GO)",
5010151497Sru				   persistent_id);
5011151497Sru			return -1;
5012151497Sru		}
5013151497Sru	}
5014151497Sru	join = os_strstr(pos, " join") != NULL;
5015151497Sru	auth = os_strstr(pos, " auth") != NULL;
5016151497Sru	automatic = os_strstr(pos, " auto") != NULL;
5017151497Sru	pd = os_strstr(pos, " provdisc") != NULL;
5018151497Sru	vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
5019151497Sru	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
5020151497Sru		vht;
5021151497Sru
5022151497Sru	pos2 = os_strstr(pos, " go_intent=");
5023151497Sru	if (pos2) {
5024151497Sru		pos2 += 11;
5025151497Sru		go_intent = atoi(pos2);
5026151497Sru		if (go_intent < 0 || go_intent > 15)
5027151497Sru			return -1;
5028151497Sru	}
5029114402Sru
5030114402Sru	pos2 = os_strstr(pos, " freq=");
5031114402Sru	if (pos2) {
5032114402Sru		pos2 += 6;
5033114402Sru		freq = atoi(pos2);
5034114402Sru		if (freq <= 0)
5035114402Sru			return -1;
5036114402Sru	}
5037114402Sru
5038114402Sru	pos2 = os_strstr(pos, " freq2=");
5039114402Sru	if (pos2)
5040114402Sru		freq2 = atoi(pos2 + 7);
5041114402Sru
5042114402Sru	pos2 = os_strstr(pos, " max_oper_chwidth=");
5043114402Sru	if (pos2)
5044114402Sru		chwidth = atoi(pos2 + 18);
5045114402Sru
5046114402Sru	max_oper_chwidth = parse_freq(chwidth, freq2);
5047114402Sru	if (max_oper_chwidth < 0)
5048114402Sru		return -1;
5049114402Sru
5050114402Sru	pos2 = os_strstr(pos, " ssid=");
5051114402Sru	if (pos2) {
5052114402Sru		char *end;
5053114402Sru
5054		pos2 += 6;
5055		end = os_strchr(pos2, ' ');
5056		if (!end)
5057			group_ssid_len = os_strlen(pos2) / 2;
5058		else
5059			group_ssid_len = (end - pos2) / 2;
5060		if (group_ssid_len == 0 || group_ssid_len > SSID_MAX_LEN ||
5061		    hexstr2bin(pos2, _group_ssid, group_ssid_len) < 0)
5062			return -1;
5063		group_ssid = _group_ssid;
5064	}
5065
5066	if (os_strncmp(pos, "pin", 3) == 0) {
5067		/* Request random PIN (to be displayed) and enable the PIN */
5068		wps_method = WPS_PIN_DISPLAY;
5069	} else if (os_strncmp(pos, "pbc", 3) == 0) {
5070		wps_method = WPS_PBC;
5071	} else if (os_strstr(pos, "p2ps") != NULL) {
5072		wps_method = WPS_P2PS;
5073	} else {
5074		pin = pos;
5075		pos = os_strchr(pin, ' ');
5076		wps_method = WPS_PIN_KEYPAD;
5077		if (pos) {
5078			*pos++ = '\0';
5079			if (os_strncmp(pos, "display", 7) == 0)
5080				wps_method = WPS_PIN_DISPLAY;
5081		}
5082		if (!wps_pin_str_valid(pin)) {
5083			os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
5084			return 17;
5085		}
5086	}
5087
5088	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
5089				   persistent_group, automatic, join,
5090				   auth, go_intent, freq, freq2, persistent_id,
5091				   pd, ht40, vht, max_oper_chwidth,
5092				   group_ssid, group_ssid_len);
5093	if (new_pin == -2) {
5094		os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
5095		return 25;
5096	}
5097	if (new_pin == -3) {
5098		os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
5099		return 25;
5100	}
5101	if (new_pin < 0)
5102		return -1;
5103	if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
5104		ret = os_snprintf(buf, buflen, "%08d", new_pin);
5105		if (os_snprintf_error(buflen, ret))
5106			return -1;
5107		return ret;
5108	}
5109
5110	os_memcpy(buf, "OK\n", 3);
5111	return 3;
5112}
5113
5114
5115static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
5116{
5117	unsigned int timeout = atoi(cmd);
5118	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
5119		wpa_dbg(wpa_s, MSG_INFO,
5120			"Reject P2P_LISTEN since interface is disabled");
5121		return -1;
5122	}
5123	return wpas_p2p_listen(wpa_s, timeout);
5124}
5125
5126
5127static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
5128{
5129	u8 addr[ETH_ALEN];
5130	char *pos;
5131	enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
5132
5133	/* <addr> <config method> [join|auto] */
5134
5135	if (hwaddr_aton(cmd, addr))
5136		return -1;
5137
5138	pos = cmd + 17;
5139	if (*pos != ' ')
5140		return -1;
5141	pos++;
5142
5143	if (os_strstr(pos, " join") != NULL)
5144		use = WPAS_P2P_PD_FOR_JOIN;
5145	else if (os_strstr(pos, " auto") != NULL)
5146		use = WPAS_P2P_PD_AUTO;
5147
5148	return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
5149}
5150
5151
5152static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
5153			      size_t buflen)
5154{
5155	struct wpa_ssid *ssid = wpa_s->current_ssid;
5156
5157	if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
5158	    ssid->passphrase == NULL)
5159		return -1;
5160
5161	os_strlcpy(buf, ssid->passphrase, buflen);
5162	return os_strlen(buf);
5163}
5164
5165
5166static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
5167				  char *buf, size_t buflen)
5168{
5169	u64 ref;
5170	int res;
5171	u8 dst_buf[ETH_ALEN], *dst;
5172	struct wpabuf *tlvs;
5173	char *pos;
5174	size_t len;
5175
5176	if (hwaddr_aton(cmd, dst_buf))
5177		return -1;
5178	dst = dst_buf;
5179	if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
5180	    dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
5181		dst = NULL;
5182	pos = cmd + 17;
5183	if (*pos != ' ')
5184		return -1;
5185	pos++;
5186
5187	if (os_strncmp(pos, "upnp ", 5) == 0) {
5188		u8 version;
5189		pos += 5;
5190		if (hexstr2bin(pos, &version, 1) < 0)
5191			return -1;
5192		pos += 2;
5193		if (*pos != ' ')
5194			return -1;
5195		pos++;
5196		ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
5197#ifdef CONFIG_WIFI_DISPLAY
5198	} else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
5199		ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
5200#endif /* CONFIG_WIFI_DISPLAY */
5201	} else if (os_strncmp(pos, "asp ", 4) == 0) {
5202		char *svc_str;
5203		char *svc_info = NULL;
5204		u32 id;
5205
5206		pos += 4;
5207		if (sscanf(pos, "%x", &id) != 1 || id > 0xff)
5208			return -1;
5209
5210		pos = os_strchr(pos, ' ');
5211		if (pos == NULL || pos[1] == '\0' || pos[1] == ' ')
5212			return -1;
5213
5214		svc_str = pos + 1;
5215
5216		pos = os_strchr(svc_str, ' ');
5217
5218		if (pos)
5219			*pos++ = '\0';
5220
5221		/* All remaining data is the svc_info string */
5222		if (pos && pos[0] && pos[0] != ' ') {
5223			len = os_strlen(pos);
5224
5225			/* Unescape in place */
5226			len = utf8_unescape(pos, len, pos, len);
5227			if (len > 0xff)
5228				return -1;
5229
5230			svc_info = pos;
5231		}
5232
5233		ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id,
5234					      svc_str, svc_info);
5235	} else {
5236		len = os_strlen(pos);
5237		if (len & 1)
5238			return -1;
5239		len /= 2;
5240		tlvs = wpabuf_alloc(len);
5241		if (tlvs == NULL)
5242			return -1;
5243		if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
5244			wpabuf_free(tlvs);
5245			return -1;
5246		}
5247
5248		ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
5249		wpabuf_free(tlvs);
5250	}
5251	if (ref == 0)
5252		return -1;
5253	res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
5254	if (os_snprintf_error(buflen, res))
5255		return -1;
5256	return res;
5257}
5258
5259
5260static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
5261					 char *cmd)
5262{
5263	long long unsigned val;
5264	u64 req;
5265	if (sscanf(cmd, "%llx", &val) != 1)
5266		return -1;
5267	req = val;
5268	return wpas_p2p_sd_cancel_request(wpa_s, req);
5269}
5270
5271
5272static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
5273{
5274	int freq;
5275	u8 dst[ETH_ALEN];
5276	u8 dialog_token;
5277	struct wpabuf *resp_tlvs;
5278	char *pos, *pos2;
5279	size_t len;
5280
5281	pos = os_strchr(cmd, ' ');
5282	if (pos == NULL)
5283		return -1;
5284	*pos++ = '\0';
5285	freq = atoi(cmd);
5286	if (freq == 0)
5287		return -1;
5288
5289	if (hwaddr_aton(pos, dst))
5290		return -1;
5291	pos += 17;
5292	if (*pos != ' ')
5293		return -1;
5294	pos++;
5295
5296	pos2 = os_strchr(pos, ' ');
5297	if (pos2 == NULL)
5298		return -1;
5299	*pos2++ = '\0';
5300	dialog_token = atoi(pos);
5301
5302	len = os_strlen(pos2);
5303	if (len & 1)
5304		return -1;
5305	len /= 2;
5306	resp_tlvs = wpabuf_alloc(len);
5307	if (resp_tlvs == NULL)
5308		return -1;
5309	if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
5310		wpabuf_free(resp_tlvs);
5311		return -1;
5312	}
5313
5314	wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
5315	wpabuf_free(resp_tlvs);
5316	return 0;
5317}
5318
5319
5320static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
5321				       char *cmd)
5322{
5323	if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
5324		return -1;
5325	wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
5326	return 0;
5327}
5328
5329
5330static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
5331					char *cmd)
5332{
5333	char *pos;
5334	size_t len;
5335	struct wpabuf *query, *resp;
5336
5337	pos = os_strchr(cmd, ' ');
5338	if (pos == NULL)
5339		return -1;
5340	*pos++ = '\0';
5341
5342	len = os_strlen(cmd);
5343	if (len & 1)
5344		return -1;
5345	len /= 2;
5346	query = wpabuf_alloc(len);
5347	if (query == NULL)
5348		return -1;
5349	if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
5350		wpabuf_free(query);
5351		return -1;
5352	}
5353
5354	len = os_strlen(pos);
5355	if (len & 1) {
5356		wpabuf_free(query);
5357		return -1;
5358	}
5359	len /= 2;
5360	resp = wpabuf_alloc(len);
5361	if (resp == NULL) {
5362		wpabuf_free(query);
5363		return -1;
5364	}
5365	if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
5366		wpabuf_free(query);
5367		wpabuf_free(resp);
5368		return -1;
5369	}
5370
5371	if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
5372		wpabuf_free(query);
5373		wpabuf_free(resp);
5374		return -1;
5375	}
5376	return 0;
5377}
5378
5379
5380static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
5381{
5382	char *pos;
5383	u8 version;
5384
5385	pos = os_strchr(cmd, ' ');
5386	if (pos == NULL)
5387		return -1;
5388	*pos++ = '\0';
5389
5390	if (hexstr2bin(cmd, &version, 1) < 0)
5391		return -1;
5392
5393	return wpas_p2p_service_add_upnp(wpa_s, version, pos);
5394}
5395
5396
5397static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,
5398				    u8 replace, char *cmd)
5399{
5400	char *pos;
5401	char *adv_str;
5402	u32 auto_accept, adv_id, svc_state, config_methods;
5403	char *svc_info = NULL;
5404	char *cpt_prio_str;
5405	u8 cpt_prio[P2PS_FEATURE_CAPAB_CPT_MAX + 1];
5406
5407	pos = os_strchr(cmd, ' ');
5408	if (pos == NULL)
5409		return -1;
5410	*pos++ = '\0';
5411
5412	/* Auto-Accept value is mandatory, and must be one of the
5413	 * single values (0, 1, 2, 4) */
5414	auto_accept = atoi(cmd);
5415	switch (auto_accept) {
5416	case P2PS_SETUP_NONE: /* No auto-accept */
5417	case P2PS_SETUP_NEW:
5418	case P2PS_SETUP_CLIENT:
5419	case P2PS_SETUP_GROUP_OWNER:
5420		break;
5421	default:
5422		return -1;
5423	}
5424
5425	/* Advertisement ID is mandatory */
5426	cmd = pos;
5427	pos = os_strchr(cmd, ' ');
5428	if (pos == NULL)
5429		return -1;
5430	*pos++ = '\0';
5431
5432	/* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */
5433	if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0)
5434		return -1;
5435
5436	/* Only allow replacements if exist, and adds if not */
5437	if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) {
5438		if (!replace)
5439			return -1;
5440	} else {
5441		if (replace)
5442			return -1;
5443	}
5444
5445	/* svc_state between 0 - 0xff is mandatory */
5446	if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff)
5447		return -1;
5448
5449	pos = os_strchr(pos, ' ');
5450	if (pos == NULL)
5451		return -1;
5452
5453	/* config_methods is mandatory */
5454	pos++;
5455	if (sscanf(pos, "%x", &config_methods) != 1)
5456		return -1;
5457
5458	if (!(config_methods &
5459	      (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS)))
5460		return -1;
5461
5462	pos = os_strchr(pos, ' ');
5463	if (pos == NULL)
5464		return -1;
5465
5466	pos++;
5467	adv_str = pos;
5468
5469	/* Advertisement string is mandatory */
5470	if (!pos[0] || pos[0] == ' ')
5471		return -1;
5472
5473	/* Terminate svc string */
5474	pos = os_strchr(pos, ' ');
5475	if (pos != NULL)
5476		*pos++ = '\0';
5477
5478	cpt_prio_str = (pos && pos[0]) ? os_strstr(pos, "cpt=") : NULL;
5479	if (cpt_prio_str) {
5480		pos = os_strchr(pos, ' ');
5481		if (pos != NULL)
5482			*pos++ = '\0';
5483
5484		if (p2ps_ctrl_parse_cpt_priority(cpt_prio_str + 4, cpt_prio))
5485			return -1;
5486	} else {
5487		cpt_prio[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT;
5488		cpt_prio[1] = 0;
5489	}
5490
5491	/* Service and Response Information are optional */
5492	if (pos && pos[0]) {
5493		size_t len;
5494
5495		/* Note the bare ' included, which cannot exist legally
5496		 * in unescaped string. */
5497		svc_info = os_strstr(pos, "svc_info='");
5498
5499		if (svc_info) {
5500			svc_info += 9;
5501			len = os_strlen(svc_info);
5502			utf8_unescape(svc_info, len, svc_info, len);
5503		}
5504	}
5505
5506	return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,
5507					(u8) svc_state, (u16) config_methods,
5508					svc_info, cpt_prio);
5509}
5510
5511
5512static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
5513{
5514	char *pos;
5515
5516	pos = os_strchr(cmd, ' ');
5517	if (pos == NULL)
5518		return -1;
5519	*pos++ = '\0';
5520
5521	if (os_strcmp(cmd, "bonjour") == 0)
5522		return p2p_ctrl_service_add_bonjour(wpa_s, pos);
5523	if (os_strcmp(cmd, "upnp") == 0)
5524		return p2p_ctrl_service_add_upnp(wpa_s, pos);
5525	if (os_strcmp(cmd, "asp") == 0)
5526		return p2p_ctrl_service_add_asp(wpa_s, 0, pos);
5527	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5528	return -1;
5529}
5530
5531
5532static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
5533					char *cmd)
5534{
5535	size_t len;
5536	struct wpabuf *query;
5537	int ret;
5538
5539	len = os_strlen(cmd);
5540	if (len & 1)
5541		return -1;
5542	len /= 2;
5543	query = wpabuf_alloc(len);
5544	if (query == NULL)
5545		return -1;
5546	if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
5547		wpabuf_free(query);
5548		return -1;
5549	}
5550
5551	ret = wpas_p2p_service_del_bonjour(wpa_s, query);
5552	wpabuf_free(query);
5553	return ret;
5554}
5555
5556
5557static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
5558{
5559	char *pos;
5560	u8 version;
5561
5562	pos = os_strchr(cmd, ' ');
5563	if (pos == NULL)
5564		return -1;
5565	*pos++ = '\0';
5566
5567	if (hexstr2bin(cmd, &version, 1) < 0)
5568		return -1;
5569
5570	return wpas_p2p_service_del_upnp(wpa_s, version, pos);
5571}
5572
5573
5574static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)
5575{
5576	u32 adv_id;
5577
5578	if (os_strcmp(cmd, "all") == 0) {
5579		wpas_p2p_service_flush_asp(wpa_s);
5580		return 0;
5581	}
5582
5583	if (sscanf(cmd, "%x", &adv_id) != 1)
5584		return -1;
5585
5586	return wpas_p2p_service_del_asp(wpa_s, adv_id);
5587}
5588
5589
5590static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
5591{
5592	char *pos;
5593
5594	pos = os_strchr(cmd, ' ');
5595	if (pos == NULL)
5596		return -1;
5597	*pos++ = '\0';
5598
5599	if (os_strcmp(cmd, "bonjour") == 0)
5600		return p2p_ctrl_service_del_bonjour(wpa_s, pos);
5601	if (os_strcmp(cmd, "upnp") == 0)
5602		return p2p_ctrl_service_del_upnp(wpa_s, pos);
5603	if (os_strcmp(cmd, "asp") == 0)
5604		return p2p_ctrl_service_del_asp(wpa_s, pos);
5605	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5606	return -1;
5607}
5608
5609
5610static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd)
5611{
5612	char *pos;
5613
5614	pos = os_strchr(cmd, ' ');
5615	if (pos == NULL)
5616		return -1;
5617	*pos++ = '\0';
5618
5619	if (os_strcmp(cmd, "asp") == 0)
5620		return p2p_ctrl_service_add_asp(wpa_s, 1, pos);
5621
5622	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
5623	return -1;
5624}
5625
5626
5627static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
5628{
5629	u8 addr[ETH_ALEN];
5630
5631	/* <addr> */
5632
5633	if (hwaddr_aton(cmd, addr))
5634		return -1;
5635
5636	return wpas_p2p_reject(wpa_s, addr);
5637}
5638
5639
5640static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
5641{
5642	char *pos;
5643	int id;
5644	struct wpa_ssid *ssid;
5645	u8 *_peer = NULL, peer[ETH_ALEN];
5646	int freq = 0, pref_freq = 0;
5647	int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
5648
5649	id = atoi(cmd);
5650	pos = os_strstr(cmd, " peer=");
5651	if (pos) {
5652		pos += 6;
5653		if (hwaddr_aton(pos, peer))
5654			return -1;
5655		_peer = peer;
5656	}
5657	ssid = wpa_config_get_network(wpa_s->conf, id);
5658	if (ssid == NULL || ssid->disabled != 2) {
5659		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
5660			   "for persistent P2P group",
5661			   id);
5662		return -1;
5663	}
5664
5665	pos = os_strstr(cmd, " freq=");
5666	if (pos) {
5667		pos += 6;
5668		freq = atoi(pos);
5669		if (freq <= 0)
5670			return -1;
5671	}
5672
5673	pos = os_strstr(cmd, " pref=");
5674	if (pos) {
5675		pos += 6;
5676		pref_freq = atoi(pos);
5677		if (pref_freq <= 0)
5678			return -1;
5679	}
5680
5681	vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
5682	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
5683		vht;
5684
5685	pos = os_strstr(cmd, "freq2=");
5686	if (pos)
5687		freq2 = atoi(pos + 6);
5688
5689	pos = os_strstr(cmd, " max_oper_chwidth=");
5690	if (pos)
5691		chwidth = atoi(pos + 18);
5692
5693	max_oper_chwidth = parse_freq(chwidth, freq2);
5694	if (max_oper_chwidth < 0)
5695		return -1;
5696
5697	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
5698			       max_oper_chwidth, pref_freq);
5699}
5700
5701
5702static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
5703{
5704	char *pos;
5705	u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
5706
5707	pos = os_strstr(cmd, " peer=");
5708	if (!pos)
5709		return -1;
5710
5711	*pos = '\0';
5712	pos += 6;
5713	if (hwaddr_aton(pos, peer)) {
5714		wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
5715		return -1;
5716	}
5717
5718	pos = os_strstr(pos, " go_dev_addr=");
5719	if (pos) {
5720		pos += 13;
5721		if (hwaddr_aton(pos, go_dev_addr)) {
5722			wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
5723				   pos);
5724			return -1;
5725		}
5726		go_dev = go_dev_addr;
5727	}
5728
5729	return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
5730}
5731
5732
5733static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
5734{
5735	if (os_strncmp(cmd, "persistent=", 11) == 0)
5736		return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
5737	if (os_strncmp(cmd, "group=", 6) == 0)
5738		return p2p_ctrl_invite_group(wpa_s, cmd + 6);
5739
5740	return -1;
5741}
5742
5743
5744static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
5745					 int id, int freq, int vht_center_freq2,
5746					 int ht40, int vht, int vht_chwidth)
5747{
5748	struct wpa_ssid *ssid;
5749
5750	ssid = wpa_config_get_network(wpa_s->conf, id);
5751	if (ssid == NULL || ssid->disabled != 2) {
5752		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
5753			   "for persistent P2P group",
5754			   id);
5755		return -1;
5756	}
5757
5758	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
5759					     vht_center_freq2, 0, ht40, vht,
5760					     vht_chwidth, NULL, 0, 0);
5761}
5762
5763
5764static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
5765{
5766	int freq = 0, persistent = 0, group_id = -1;
5767	int vht = wpa_s->conf->p2p_go_vht;
5768	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
5769	int max_oper_chwidth, chwidth = 0, freq2 = 0;
5770	char *token, *context = NULL;
5771
5772	while ((token = str_token(cmd, " ", &context))) {
5773		if (sscanf(token, "freq=%d", &freq) == 1 ||
5774		    sscanf(token, "freq2=%d", &freq2) == 1 ||
5775		    sscanf(token, "persistent=%d", &group_id) == 1 ||
5776		    sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
5777			continue;
5778		} else if (os_strcmp(token, "ht40") == 0) {
5779			ht40 = 1;
5780		} else if (os_strcmp(token, "vht") == 0) {
5781			vht = 1;
5782			ht40 = 1;
5783		} else if (os_strcmp(token, "persistent") == 0) {
5784			persistent = 1;
5785		} else {
5786			wpa_printf(MSG_DEBUG,
5787				   "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'",
5788				   token);
5789			return -1;
5790		}
5791	}
5792
5793	max_oper_chwidth = parse_freq(chwidth, freq2);
5794	if (max_oper_chwidth < 0)
5795		return -1;
5796
5797	if (group_id >= 0)
5798		return p2p_ctrl_group_add_persistent(wpa_s, group_id,
5799						     freq, freq2, ht40, vht,
5800						     max_oper_chwidth);
5801
5802	return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
5803				  max_oper_chwidth);
5804}
5805
5806
5807static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd,
5808				 char *buf, size_t buflen)
5809{
5810	u8 dev_addr[ETH_ALEN];
5811	struct wpa_ssid *ssid;
5812	int res;
5813	const u8 *iaddr;
5814
5815	ssid = wpa_s->current_ssid;
5816	if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO ||
5817	    hwaddr_aton(cmd, dev_addr))
5818		return -1;
5819
5820	iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr);
5821	if (!iaddr)
5822		return -1;
5823	res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr));
5824	if (os_snprintf_error(buflen, res))
5825		return -1;
5826	return res;
5827}
5828
5829
5830static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
5831			 char *buf, size_t buflen)
5832{
5833	u8 addr[ETH_ALEN], *addr_ptr;
5834	int next, res;
5835	const struct p2p_peer_info *info;
5836	char *pos, *end;
5837	char devtype[WPS_DEV_TYPE_BUFSIZE];
5838	struct wpa_ssid *ssid;
5839	size_t i;
5840
5841	if (!wpa_s->global->p2p)
5842		return -1;
5843
5844	if (os_strcmp(cmd, "FIRST") == 0) {
5845		addr_ptr = NULL;
5846		next = 0;
5847	} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
5848		if (hwaddr_aton(cmd + 5, addr) < 0)
5849			return -1;
5850		addr_ptr = addr;
5851		next = 1;
5852	} else {
5853		if (hwaddr_aton(cmd, addr) < 0)
5854			return -1;
5855		addr_ptr = addr;
5856		next = 0;
5857	}
5858
5859	info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
5860	if (info == NULL)
5861		return -1;
5862
5863	pos = buf;
5864	end = buf + buflen;
5865
5866	res = os_snprintf(pos, end - pos, MACSTR "\n"
5867			  "pri_dev_type=%s\n"
5868			  "device_name=%s\n"
5869			  "manufacturer=%s\n"
5870			  "model_name=%s\n"
5871			  "model_number=%s\n"
5872			  "serial_number=%s\n"
5873			  "config_methods=0x%x\n"
5874			  "dev_capab=0x%x\n"
5875			  "group_capab=0x%x\n"
5876			  "level=%d\n",
5877			  MAC2STR(info->p2p_device_addr),
5878			  wps_dev_type_bin2str(info->pri_dev_type,
5879					       devtype, sizeof(devtype)),
5880			  info->device_name,
5881			  info->manufacturer,
5882			  info->model_name,
5883			  info->model_number,
5884			  info->serial_number,
5885			  info->config_methods,
5886			  info->dev_capab,
5887			  info->group_capab,
5888			  info->level);
5889	if (os_snprintf_error(end - pos, res))
5890		return pos - buf;
5891	pos += res;
5892
5893	for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
5894	{
5895		const u8 *t;
5896		t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
5897		res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
5898				  wps_dev_type_bin2str(t, devtype,
5899						       sizeof(devtype)));
5900		if (os_snprintf_error(end - pos, res))
5901			return pos - buf;
5902		pos += res;
5903	}
5904
5905	ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
5906	if (ssid) {
5907		res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
5908		if (os_snprintf_error(end - pos, res))
5909			return pos - buf;
5910		pos += res;
5911	}
5912
5913	res = p2p_get_peer_info_txt(info, pos, end - pos);
5914	if (res < 0)
5915		return pos - buf;
5916	pos += res;
5917
5918	if (info->vendor_elems) {
5919		res = os_snprintf(pos, end - pos, "vendor_elems=");
5920		if (os_snprintf_error(end - pos, res))
5921			return pos - buf;
5922		pos += res;
5923
5924		pos += wpa_snprintf_hex(pos, end - pos,
5925					wpabuf_head(info->vendor_elems),
5926					wpabuf_len(info->vendor_elems));
5927
5928		res = os_snprintf(pos, end - pos, "\n");
5929		if (os_snprintf_error(end - pos, res))
5930			return pos - buf;
5931		pos += res;
5932	}
5933
5934	return pos - buf;
5935}
5936
5937
5938static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
5939				  const char *param)
5940{
5941	unsigned int i;
5942
5943	if (wpa_s->global->p2p == NULL)
5944		return -1;
5945
5946	if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
5947		return -1;
5948
5949	for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
5950		struct wpa_freq_range *freq;
5951		freq = &wpa_s->global->p2p_disallow_freq.range[i];
5952		wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
5953			   freq->min, freq->max);
5954	}
5955
5956	wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW);
5957	return 0;
5958}
5959
5960
5961static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
5962{
5963	char *param;
5964
5965	if (wpa_s->global->p2p == NULL)
5966		return -1;
5967
5968	param = os_strchr(cmd, ' ');
5969	if (param == NULL)
5970		return -1;
5971	*param++ = '\0';
5972
5973	if (os_strcmp(cmd, "discoverability") == 0) {
5974		p2p_set_client_discoverability(wpa_s->global->p2p,
5975					       atoi(param));
5976		return 0;
5977	}
5978
5979	if (os_strcmp(cmd, "managed") == 0) {
5980		p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
5981		return 0;
5982	}
5983
5984	if (os_strcmp(cmd, "listen_channel") == 0) {
5985		char *pos;
5986		u8 channel, op_class;
5987
5988		channel = atoi(param);
5989		pos = os_strchr(param, ' ');
5990		op_class = pos ? atoi(pos) : 81;
5991
5992		return p2p_set_listen_channel(wpa_s->global->p2p, op_class,
5993					      channel, 1);
5994	}
5995
5996	if (os_strcmp(cmd, "ssid_postfix") == 0) {
5997		return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
5998					    os_strlen(param));
5999	}
6000
6001	if (os_strcmp(cmd, "noa") == 0) {
6002		char *pos;
6003		int count, start, duration;
6004		/* GO NoA parameters: count,start_offset(ms),duration(ms) */
6005		count = atoi(param);
6006		pos = os_strchr(param, ',');
6007		if (pos == NULL)
6008			return -1;
6009		pos++;
6010		start = atoi(pos);
6011		pos = os_strchr(pos, ',');
6012		if (pos == NULL)
6013			return -1;
6014		pos++;
6015		duration = atoi(pos);
6016		if (count < 0 || count > 255 || start < 0 || duration < 0)
6017			return -1;
6018		if (count == 0 && duration > 0)
6019			return -1;
6020		wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
6021			   "start=%d duration=%d", count, start, duration);
6022		return wpas_p2p_set_noa(wpa_s, count, start, duration);
6023	}
6024
6025	if (os_strcmp(cmd, "ps") == 0)
6026		return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
6027
6028	if (os_strcmp(cmd, "oppps") == 0)
6029		return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
6030
6031	if (os_strcmp(cmd, "ctwindow") == 0)
6032		return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
6033
6034	if (os_strcmp(cmd, "disabled") == 0) {
6035		wpa_s->global->p2p_disabled = atoi(param);
6036		wpa_printf(MSG_DEBUG, "P2P functionality %s",
6037			   wpa_s->global->p2p_disabled ?
6038			   "disabled" : "enabled");
6039		if (wpa_s->global->p2p_disabled) {
6040			wpas_p2p_stop_find(wpa_s);
6041			os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
6042			p2p_flush(wpa_s->global->p2p);
6043		}
6044		return 0;
6045	}
6046
6047	if (os_strcmp(cmd, "conc_pref") == 0) {
6048		if (os_strcmp(param, "sta") == 0)
6049			wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
6050		else if (os_strcmp(param, "p2p") == 0)
6051			wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
6052		else {
6053			wpa_printf(MSG_INFO, "Invalid conc_pref value");
6054			return -1;
6055		}
6056		wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
6057			   "%s", param);
6058		return 0;
6059	}
6060
6061	if (os_strcmp(cmd, "force_long_sd") == 0) {
6062		wpa_s->force_long_sd = atoi(param);
6063		return 0;
6064	}
6065
6066	if (os_strcmp(cmd, "peer_filter") == 0) {
6067		u8 addr[ETH_ALEN];
6068		if (hwaddr_aton(param, addr))
6069			return -1;
6070		p2p_set_peer_filter(wpa_s->global->p2p, addr);
6071		return 0;
6072	}
6073
6074	if (os_strcmp(cmd, "cross_connect") == 0)
6075		return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
6076
6077	if (os_strcmp(cmd, "go_apsd") == 0) {
6078		if (os_strcmp(param, "disable") == 0)
6079			wpa_s->set_ap_uapsd = 0;
6080		else {
6081			wpa_s->set_ap_uapsd = 1;
6082			wpa_s->ap_uapsd = atoi(param);
6083		}
6084		return 0;
6085	}
6086
6087	if (os_strcmp(cmd, "client_apsd") == 0) {
6088		if (os_strcmp(param, "disable") == 0)
6089			wpa_s->set_sta_uapsd = 0;
6090		else {
6091			int be, bk, vi, vo;
6092			char *pos;
6093			/* format: BE,BK,VI,VO;max SP Length */
6094			be = atoi(param);
6095			pos = os_strchr(param, ',');
6096			if (pos == NULL)
6097				return -1;
6098			pos++;
6099			bk = atoi(pos);
6100			pos = os_strchr(pos, ',');
6101			if (pos == NULL)
6102				return -1;
6103			pos++;
6104			vi = atoi(pos);
6105			pos = os_strchr(pos, ',');
6106			if (pos == NULL)
6107				return -1;
6108			pos++;
6109			vo = atoi(pos);
6110			/* ignore max SP Length for now */
6111
6112			wpa_s->set_sta_uapsd = 1;
6113			wpa_s->sta_uapsd = 0;
6114			if (be)
6115				wpa_s->sta_uapsd |= BIT(0);
6116			if (bk)
6117				wpa_s->sta_uapsd |= BIT(1);
6118			if (vi)
6119				wpa_s->sta_uapsd |= BIT(2);
6120			if (vo)
6121				wpa_s->sta_uapsd |= BIT(3);
6122		}
6123		return 0;
6124	}
6125
6126	if (os_strcmp(cmd, "disallow_freq") == 0)
6127		return p2p_ctrl_disallow_freq(wpa_s, param);
6128
6129	if (os_strcmp(cmd, "disc_int") == 0) {
6130		int min_disc_int, max_disc_int, max_disc_tu;
6131		char *pos;
6132
6133		pos = param;
6134
6135		min_disc_int = atoi(pos);
6136		pos = os_strchr(pos, ' ');
6137		if (pos == NULL)
6138			return -1;
6139		*pos++ = '\0';
6140
6141		max_disc_int = atoi(pos);
6142		pos = os_strchr(pos, ' ');
6143		if (pos == NULL)
6144			return -1;
6145		*pos++ = '\0';
6146
6147		max_disc_tu = atoi(pos);
6148
6149		return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
6150					max_disc_int, max_disc_tu);
6151	}
6152
6153	if (os_strcmp(cmd, "per_sta_psk") == 0) {
6154		wpa_s->global->p2p_per_sta_psk = !!atoi(param);
6155		return 0;
6156	}
6157
6158#ifdef CONFIG_WPS_NFC
6159	if (os_strcmp(cmd, "nfc_tag") == 0)
6160		return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
6161#endif /* CONFIG_WPS_NFC */
6162
6163	if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
6164		wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
6165		return 0;
6166	}
6167
6168	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
6169		   cmd);
6170
6171	return -1;
6172}
6173
6174
6175static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
6176{
6177	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
6178	wpa_s->force_long_sd = 0;
6179	wpas_p2p_stop_find(wpa_s);
6180	wpa_s->parent->p2ps_method_config_any = 0;
6181	if (wpa_s->global->p2p)
6182		p2p_flush(wpa_s->global->p2p);
6183}
6184
6185
6186static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
6187{
6188	char *pos, *pos2;
6189	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
6190
6191	if (cmd[0]) {
6192		pos = os_strchr(cmd, ' ');
6193		if (pos == NULL)
6194			return -1;
6195		*pos++ = '\0';
6196		dur1 = atoi(cmd);
6197
6198		pos2 = os_strchr(pos, ' ');
6199		if (pos2)
6200			*pos2++ = '\0';
6201		int1 = atoi(pos);
6202	} else
6203		pos2 = NULL;
6204
6205	if (pos2) {
6206		pos = os_strchr(pos2, ' ');
6207		if (pos == NULL)
6208			return -1;
6209		*pos++ = '\0';
6210		dur2 = atoi(pos2);
6211		int2 = atoi(pos);
6212	}
6213
6214	return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
6215}
6216
6217
6218static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
6219{
6220	char *pos;
6221	unsigned int period = 0, interval = 0;
6222
6223	if (cmd[0]) {
6224		pos = os_strchr(cmd, ' ');
6225		if (pos == NULL)
6226			return -1;
6227		*pos++ = '\0';
6228		period = atoi(cmd);
6229		interval = atoi(pos);
6230	}
6231
6232	return wpas_p2p_ext_listen(wpa_s, period, interval);
6233}
6234
6235
6236static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
6237{
6238	const char *pos;
6239	u8 peer[ETH_ALEN];
6240	int iface_addr = 0;
6241
6242	pos = cmd;
6243	if (os_strncmp(pos, "iface=", 6) == 0) {
6244		iface_addr = 1;
6245		pos += 6;
6246	}
6247	if (hwaddr_aton(pos, peer))
6248		return -1;
6249
6250	wpas_p2p_remove_client(wpa_s, peer, iface_addr);
6251	return 0;
6252}
6253
6254
6255static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
6256{
6257	int freq = 0, period = 0, interval = 0, count = 0;
6258
6259	if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
6260	{
6261		wpa_printf(MSG_DEBUG,
6262			   "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
6263		return -1;
6264	}
6265
6266	return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
6267}
6268
6269#endif /* CONFIG_P2P */
6270
6271
6272static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
6273{
6274	struct wpa_freq_range_list ranges;
6275	int *freqs = NULL;
6276	struct hostapd_hw_modes *mode;
6277	u16 i;
6278
6279	if (wpa_s->hw.modes == NULL)
6280		return NULL;
6281
6282	os_memset(&ranges, 0, sizeof(ranges));
6283	if (freq_range_list_parse(&ranges, val) < 0)
6284		return NULL;
6285
6286	for (i = 0; i < wpa_s->hw.num_modes; i++) {
6287		int j;
6288
6289		mode = &wpa_s->hw.modes[i];
6290		for (j = 0; j < mode->num_channels; j++) {
6291			unsigned int freq;
6292
6293			if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
6294				continue;
6295
6296			freq = mode->channels[j].freq;
6297			if (!freq_range_list_includes(&ranges, freq))
6298				continue;
6299
6300			int_array_add_unique(&freqs, freq);
6301		}
6302	}
6303
6304	os_free(ranges.range);
6305	return freqs;
6306}
6307
6308
6309#ifdef CONFIG_INTERWORKING
6310
6311static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
6312{
6313	int auto_sel = 0;
6314	int *freqs = NULL;
6315
6316	if (param) {
6317		char *pos;
6318
6319		auto_sel = os_strstr(param, "auto") != NULL;
6320
6321		pos = os_strstr(param, "freq=");
6322		if (pos) {
6323			freqs = freq_range_to_channel_list(wpa_s, pos + 5);
6324			if (freqs == NULL)
6325				return -1;
6326		}
6327
6328	}
6329
6330	return interworking_select(wpa_s, auto_sel, freqs);
6331}
6332
6333
6334static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
6335				     int only_add)
6336{
6337	u8 bssid[ETH_ALEN];
6338	struct wpa_bss *bss;
6339
6340	if (hwaddr_aton(dst, bssid)) {
6341		wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
6342		return -1;
6343	}
6344
6345	bss = wpa_bss_get_bssid(wpa_s, bssid);
6346	if (bss == NULL) {
6347		wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
6348			   MAC2STR(bssid));
6349		return -1;
6350	}
6351
6352	if (bss->ssid_len == 0) {
6353		int found = 0;
6354
6355		wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
6356			   " does not have SSID information", MAC2STR(bssid));
6357
6358		dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
6359					 list) {
6360			if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
6361			    bss->ssid_len > 0) {
6362				found = 1;
6363				break;
6364			}
6365		}
6366
6367		if (!found)
6368			return -1;
6369		wpa_printf(MSG_DEBUG,
6370			   "Found another matching BSS entry with SSID");
6371	}
6372
6373	return interworking_connect(wpa_s, bss, only_add);
6374}
6375
6376
6377static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
6378{
6379	u8 dst_addr[ETH_ALEN];
6380	int used;
6381	char *pos;
6382#define MAX_ANQP_INFO_ID 100
6383	u16 id[MAX_ANQP_INFO_ID];
6384	size_t num_id = 0;
6385	u32 subtypes = 0;
6386	int get_cell_pref = 0;
6387
6388	used = hwaddr_aton2(dst, dst_addr);
6389	if (used < 0)
6390		return -1;
6391	pos = dst + used;
6392	if (*pos == ' ')
6393		pos++;
6394	while (num_id < MAX_ANQP_INFO_ID) {
6395		if (os_strncmp(pos, "hs20:", 5) == 0) {
6396#ifdef CONFIG_HS20
6397			int num = atoi(pos + 5);
6398			if (num <= 0 || num > 31)
6399				return -1;
6400			subtypes |= BIT(num);
6401#else /* CONFIG_HS20 */
6402			return -1;
6403#endif /* CONFIG_HS20 */
6404		} else if (os_strncmp(pos, "mbo:", 4) == 0) {
6405#ifdef CONFIG_MBO
6406			int num = atoi(pos + 4);
6407			if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
6408				return -1;
6409			get_cell_pref = 1;
6410#else /* CONFIG_MBO */
6411			return -1;
6412#endif /* CONFIG_MBO */
6413		} else {
6414			id[num_id] = atoi(pos);
6415			if (id[num_id])
6416				num_id++;
6417		}
6418		pos = os_strchr(pos + 1, ',');
6419		if (pos == NULL)
6420			break;
6421		pos++;
6422	}
6423
6424	if (num_id == 0)
6425		return -1;
6426
6427	return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
6428			     get_cell_pref);
6429}
6430
6431
6432static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
6433{
6434	u8 dst_addr[ETH_ALEN];
6435	struct wpabuf *advproto, *query = NULL;
6436	int used, ret = -1;
6437	char *pos, *end;
6438	size_t len;
6439
6440	used = hwaddr_aton2(cmd, dst_addr);
6441	if (used < 0)
6442		return -1;
6443
6444	pos = cmd + used;
6445	while (*pos == ' ')
6446		pos++;
6447
6448	/* Advertisement Protocol ID */
6449	end = os_strchr(pos, ' ');
6450	if (end)
6451		len = end - pos;
6452	else
6453		len = os_strlen(pos);
6454	if (len & 0x01)
6455		return -1;
6456	len /= 2;
6457	if (len == 0)
6458		return -1;
6459	advproto = wpabuf_alloc(len);
6460	if (advproto == NULL)
6461		return -1;
6462	if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
6463		goto fail;
6464
6465	if (end) {
6466		/* Optional Query Request */
6467		pos = end + 1;
6468		while (*pos == ' ')
6469			pos++;
6470
6471		len = os_strlen(pos);
6472		if (len) {
6473			if (len & 0x01)
6474				goto fail;
6475			len /= 2;
6476			if (len == 0)
6477				goto fail;
6478			query = wpabuf_alloc(len);
6479			if (query == NULL)
6480				goto fail;
6481			if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
6482				goto fail;
6483		}
6484	}
6485
6486	ret = gas_send_request(wpa_s, dst_addr, advproto, query);
6487
6488fail:
6489	wpabuf_free(advproto);
6490	wpabuf_free(query);
6491
6492	return ret;
6493}
6494
6495
6496static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
6497			    size_t buflen)
6498{
6499	u8 addr[ETH_ALEN];
6500	int dialog_token;
6501	int used;
6502	char *pos;
6503	size_t resp_len, start, requested_len;
6504	struct wpabuf *resp;
6505	int ret;
6506
6507	used = hwaddr_aton2(cmd, addr);
6508	if (used < 0)
6509		return -1;
6510
6511	pos = cmd + used;
6512	while (*pos == ' ')
6513		pos++;
6514	dialog_token = atoi(pos);
6515
6516	if (wpa_s->last_gas_resp &&
6517	    os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
6518	    dialog_token == wpa_s->last_gas_dialog_token)
6519		resp = wpa_s->last_gas_resp;
6520	else if (wpa_s->prev_gas_resp &&
6521		 os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
6522		 dialog_token == wpa_s->prev_gas_dialog_token)
6523		resp = wpa_s->prev_gas_resp;
6524	else
6525		return -1;
6526
6527	resp_len = wpabuf_len(resp);
6528	start = 0;
6529	requested_len = resp_len;
6530
6531	pos = os_strchr(pos, ' ');
6532	if (pos) {
6533		start = atoi(pos);
6534		if (start > resp_len)
6535			return os_snprintf(buf, buflen, "FAIL-Invalid range");
6536		pos = os_strchr(pos, ',');
6537		if (pos == NULL)
6538			return -1;
6539		pos++;
6540		requested_len = atoi(pos);
6541		if (start + requested_len > resp_len)
6542			return os_snprintf(buf, buflen, "FAIL-Invalid range");
6543	}
6544
6545	if (requested_len * 2 + 1 > buflen)
6546		return os_snprintf(buf, buflen, "FAIL-Too long response");
6547
6548	ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
6549			       requested_len);
6550
6551	if (start + requested_len == resp_len) {
6552		/*
6553		 * Free memory by dropping the response after it has been
6554		 * fetched.
6555		 */
6556		if (resp == wpa_s->prev_gas_resp) {
6557			wpabuf_free(wpa_s->prev_gas_resp);
6558			wpa_s->prev_gas_resp = NULL;
6559		} else {
6560			wpabuf_free(wpa_s->last_gas_resp);
6561			wpa_s->last_gas_resp = NULL;
6562		}
6563	}
6564
6565	return ret;
6566}
6567#endif /* CONFIG_INTERWORKING */
6568
6569
6570#ifdef CONFIG_HS20
6571
6572static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
6573{
6574	u8 dst_addr[ETH_ALEN];
6575	int used;
6576	char *pos;
6577	u32 subtypes = 0;
6578
6579	used = hwaddr_aton2(dst, dst_addr);
6580	if (used < 0)
6581		return -1;
6582	pos = dst + used;
6583	if (*pos == ' ')
6584		pos++;
6585	for (;;) {
6586		int num = atoi(pos);
6587		if (num <= 0 || num > 31)
6588			return -1;
6589		subtypes |= BIT(num);
6590		pos = os_strchr(pos + 1, ',');
6591		if (pos == NULL)
6592			break;
6593		pos++;
6594	}
6595
6596	if (subtypes == 0)
6597		return -1;
6598
6599	return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0);
6600}
6601
6602
6603static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
6604				    const u8 *addr, const char *realm)
6605{
6606	u8 *buf;
6607	size_t rlen, len;
6608	int ret;
6609
6610	rlen = os_strlen(realm);
6611	len = 3 + rlen;
6612	buf = os_malloc(len);
6613	if (buf == NULL)
6614		return -1;
6615	buf[0] = 1; /* NAI Home Realm Count */
6616	buf[1] = 0; /* Formatted in accordance with RFC 4282 */
6617	buf[2] = rlen;
6618	os_memcpy(buf + 3, realm, rlen);
6619
6620	ret = hs20_anqp_send_req(wpa_s, addr,
6621				 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
6622				 buf, len, 0);
6623
6624	os_free(buf);
6625
6626	return ret;
6627}
6628
6629
6630static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
6631					char *dst)
6632{
6633	struct wpa_cred *cred = wpa_s->conf->cred;
6634	u8 dst_addr[ETH_ALEN];
6635	int used;
6636	u8 *buf;
6637	size_t len;
6638	int ret;
6639
6640	used = hwaddr_aton2(dst, dst_addr);
6641	if (used < 0)
6642		return -1;
6643
6644	while (dst[used] == ' ')
6645		used++;
6646	if (os_strncmp(dst + used, "realm=", 6) == 0)
6647		return hs20_nai_home_realm_list(wpa_s, dst_addr,
6648						dst + used + 6);
6649
6650	len = os_strlen(dst + used);
6651
6652	if (len == 0 && cred && cred->realm)
6653		return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
6654
6655	if (len & 1)
6656		return -1;
6657	len /= 2;
6658	buf = os_malloc(len);
6659	if (buf == NULL)
6660		return -1;
6661	if (hexstr2bin(dst + used, buf, len) < 0) {
6662		os_free(buf);
6663		return -1;
6664	}
6665
6666	ret = hs20_anqp_send_req(wpa_s, dst_addr,
6667				 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
6668				 buf, len, 0);
6669	os_free(buf);
6670
6671	return ret;
6672}
6673
6674
6675static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply,
6676			 int buflen)
6677{
6678	u8 dst_addr[ETH_ALEN];
6679	int used;
6680	char *ctx = NULL, *icon, *poffset, *psize;
6681
6682	used = hwaddr_aton2(cmd, dst_addr);
6683	if (used < 0)
6684		return -1;
6685	cmd += used;
6686
6687	icon = str_token(cmd, " ", &ctx);
6688	poffset = str_token(cmd, " ", &ctx);
6689	psize = str_token(cmd, " ", &ctx);
6690	if (!icon || !poffset || !psize)
6691		return -1;
6692
6693	wpa_s->fetch_osu_icon_in_progress = 0;
6694	return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize),
6695			     reply, buflen);
6696}
6697
6698
6699static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd)
6700{
6701	u8 dst_addr[ETH_ALEN];
6702	int used;
6703	char *icon;
6704
6705	if (!cmd[0])
6706		return hs20_del_icon(wpa_s, NULL, NULL);
6707
6708	used = hwaddr_aton2(cmd, dst_addr);
6709	if (used < 0)
6710		return -1;
6711
6712	while (cmd[used] == ' ')
6713		used++;
6714	icon = cmd[used] ? &cmd[used] : NULL;
6715
6716	return hs20_del_icon(wpa_s, dst_addr, icon);
6717}
6718
6719
6720static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem)
6721{
6722	u8 dst_addr[ETH_ALEN];
6723	int used;
6724	char *icon;
6725
6726	used = hwaddr_aton2(cmd, dst_addr);
6727	if (used < 0)
6728		return -1;
6729
6730	while (cmd[used] == ' ')
6731		used++;
6732	icon = &cmd[used];
6733
6734	wpa_s->fetch_osu_icon_in_progress = 0;
6735	return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
6736				  (u8 *) icon, os_strlen(icon), inmem);
6737}
6738
6739#endif /* CONFIG_HS20 */
6740
6741
6742#ifdef CONFIG_AUTOSCAN
6743
6744static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
6745					      char *cmd)
6746{
6747	enum wpa_states state = wpa_s->wpa_state;
6748	char *new_params = NULL;
6749
6750	if (os_strlen(cmd) > 0) {
6751		new_params = os_strdup(cmd);
6752		if (new_params == NULL)
6753			return -1;
6754	}
6755
6756	os_free(wpa_s->conf->autoscan);
6757	wpa_s->conf->autoscan = new_params;
6758
6759	if (wpa_s->conf->autoscan == NULL)
6760		autoscan_deinit(wpa_s);
6761	else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
6762		autoscan_init(wpa_s, 1);
6763	else if (state == WPA_SCANNING)
6764		wpa_supplicant_reinit_autoscan(wpa_s);
6765
6766	return 0;
6767}
6768
6769#endif /* CONFIG_AUTOSCAN */
6770
6771
6772#ifdef CONFIG_WNM
6773
6774static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
6775{
6776	int enter;
6777	int intval = 0;
6778	char *pos;
6779	int ret;
6780	struct wpabuf *tfs_req = NULL;
6781
6782	if (os_strncmp(cmd, "enter", 5) == 0)
6783		enter = 1;
6784	else if (os_strncmp(cmd, "exit", 4) == 0)
6785		enter = 0;
6786	else
6787		return -1;
6788
6789	pos = os_strstr(cmd, " interval=");
6790	if (pos)
6791		intval = atoi(pos + 10);
6792
6793	pos = os_strstr(cmd, " tfs_req=");
6794	if (pos) {
6795		char *end;
6796		size_t len;
6797		pos += 9;
6798		end = os_strchr(pos, ' ');
6799		if (end)
6800			len = end - pos;
6801		else
6802			len = os_strlen(pos);
6803		if (len & 1)
6804			return -1;
6805		len /= 2;
6806		tfs_req = wpabuf_alloc(len);
6807		if (tfs_req == NULL)
6808			return -1;
6809		if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
6810			wpabuf_free(tfs_req);
6811			return -1;
6812		}
6813	}
6814
6815	ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
6816					   WNM_SLEEP_MODE_EXIT, intval,
6817					   tfs_req);
6818	wpabuf_free(tfs_req);
6819
6820	return ret;
6821}
6822
6823
6824static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
6825{
6826	int query_reason, list = 0;
6827
6828	query_reason = atoi(cmd);
6829
6830	cmd = os_strchr(cmd, ' ');
6831	if (cmd) {
6832		cmd++;
6833		if (os_strncmp(cmd, "list", 4) == 0) {
6834			list = 1;
6835		} else {
6836			wpa_printf(MSG_DEBUG, "WNM Query: Invalid option %s",
6837				   cmd);
6838			return -1;
6839		}
6840	}
6841
6842	wpa_printf(MSG_DEBUG,
6843		   "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d%s",
6844		   query_reason, list ? " candidate list" : "");
6845
6846	return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, list);
6847}
6848
6849#endif /* CONFIG_WNM */
6850
6851
6852static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
6853				      size_t buflen)
6854{
6855	struct wpa_signal_info si;
6856	int ret;
6857	char *pos, *end;
6858
6859	ret = wpa_drv_signal_poll(wpa_s, &si);
6860	if (ret)
6861		return -1;
6862
6863	pos = buf;
6864	end = buf + buflen;
6865
6866	ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
6867			  "NOISE=%d\nFREQUENCY=%u\n",
6868			  si.current_signal, si.current_txrate / 1000,
6869			  si.current_noise, si.frequency);
6870	if (os_snprintf_error(end - pos, ret))
6871		return -1;
6872	pos += ret;
6873
6874	if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
6875		ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
6876				  channel_width_to_string(si.chanwidth));
6877		if (os_snprintf_error(end - pos, ret))
6878			return -1;
6879		pos += ret;
6880	}
6881
6882	if (si.center_frq1 > 0 && si.center_frq2 > 0) {
6883		ret = os_snprintf(pos, end - pos,
6884				  "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
6885				  si.center_frq1, si.center_frq2);
6886		if (os_snprintf_error(end - pos, ret))
6887			return -1;
6888		pos += ret;
6889	}
6890
6891	if (si.avg_signal) {
6892		ret = os_snprintf(pos, end - pos,
6893				  "AVG_RSSI=%d\n", si.avg_signal);
6894		if (os_snprintf_error(end - pos, ret))
6895			return -1;
6896		pos += ret;
6897	}
6898
6899	if (si.avg_beacon_signal) {
6900		ret = os_snprintf(pos, end - pos,
6901				  "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal);
6902		if (os_snprintf_error(end - pos, ret))
6903			return -1;
6904		pos += ret;
6905	}
6906
6907	return pos - buf;
6908}
6909
6910
6911static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s,
6912					  const char *cmd)
6913{
6914	const char *pos;
6915	int threshold = 0;
6916	int hysteresis = 0;
6917
6918	if (wpa_s->bgscan && wpa_s->bgscan_priv) {
6919		wpa_printf(MSG_DEBUG,
6920			   "Reject SIGNAL_MONITOR command - bgscan is active");
6921		return -1;
6922	}
6923	pos = os_strstr(cmd, "THRESHOLD=");
6924	if (pos)
6925		threshold = atoi(pos + 10);
6926	pos = os_strstr(cmd, "HYSTERESIS=");
6927	if (pos)
6928		hysteresis = atoi(pos + 11);
6929	return wpa_drv_signal_monitor(wpa_s, threshold, hysteresis);
6930}
6931
6932
6933static int wpas_ctrl_iface_get_pref_freq_list(
6934	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
6935{
6936	unsigned int freq_list[100], num = 100, i;
6937	int ret;
6938	enum wpa_driver_if_type iface_type;
6939	char *pos, *end;
6940
6941	pos = buf;
6942	end = buf + buflen;
6943
6944	/* buf: "<interface_type>" */
6945	if (os_strcmp(cmd, "STATION") == 0)
6946		iface_type = WPA_IF_STATION;
6947	else if (os_strcmp(cmd, "AP") == 0)
6948		iface_type = WPA_IF_AP_BSS;
6949	else if (os_strcmp(cmd, "P2P_GO") == 0)
6950		iface_type = WPA_IF_P2P_GO;
6951	else if (os_strcmp(cmd, "P2P_CLIENT") == 0)
6952		iface_type = WPA_IF_P2P_CLIENT;
6953	else if (os_strcmp(cmd, "IBSS") == 0)
6954		iface_type = WPA_IF_IBSS;
6955	else if (os_strcmp(cmd, "TDLS") == 0)
6956		iface_type = WPA_IF_TDLS;
6957	else
6958		return -1;
6959
6960	wpa_printf(MSG_DEBUG,
6961		   "CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)",
6962		   iface_type, buf);
6963
6964	ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list);
6965	if (ret)
6966		return -1;
6967
6968	for (i = 0; i < num; i++) {
6969		ret = os_snprintf(pos, end - pos, "%s%u",
6970				  i > 0 ? "," : "", freq_list[i]);
6971		if (os_snprintf_error(end - pos, ret))
6972			return -1;
6973		pos += ret;
6974	}
6975
6976	return pos - buf;
6977}
6978
6979
6980static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
6981					char *buf, size_t buflen)
6982{
6983	int ret, i;
6984	char *pos, *end;
6985
6986	ret = os_snprintf(buf, buflen, "%016llX:\n",
6987			  (long long unsigned) wpa_s->drv_flags);
6988	if (os_snprintf_error(buflen, ret))
6989		return -1;
6990
6991	pos = buf + ret;
6992	end = buf + buflen;
6993
6994	for (i = 0; i < 64; i++) {
6995		if (wpa_s->drv_flags & (1LLU << i)) {
6996			ret = os_snprintf(pos, end - pos, "%s\n",
6997					  driver_flag_to_string(1LLU << i));
6998			if (os_snprintf_error(end - pos, ret))
6999				return -1;
7000			pos += ret;
7001		}
7002	}
7003
7004	return pos - buf;
7005}
7006
7007
7008static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
7009				      size_t buflen)
7010{
7011	struct hostap_sta_driver_data sta;
7012	int ret;
7013
7014	ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
7015	if (ret)
7016		return -1;
7017
7018	ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
7019			  sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
7020	if (os_snprintf_error(buflen, ret))
7021		return -1;
7022	return ret;
7023}
7024
7025
7026#ifdef ANDROID
7027static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
7028				     char *buf, size_t buflen)
7029{
7030	int ret;
7031
7032	ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
7033	if (ret == 0) {
7034		if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
7035			struct p2p_data *p2p = wpa_s->global->p2p;
7036			if (p2p) {
7037				char country[3];
7038				country[0] = cmd[8];
7039				country[1] = cmd[9];
7040				country[2] = 0x04;
7041				p2p_set_country(p2p, country);
7042			}
7043		}
7044		ret = os_snprintf(buf, buflen, "%s\n", "OK");
7045		if (os_snprintf_error(buflen, ret))
7046			ret = -1;
7047	}
7048	return ret;
7049}
7050#endif /* ANDROID */
7051
7052
7053static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
7054				     char *buf, size_t buflen)
7055{
7056	int ret;
7057	char *pos;
7058	u8 *data = NULL;
7059	unsigned int vendor_id, subcmd;
7060	struct wpabuf *reply;
7061	size_t data_len = 0;
7062
7063	/* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
7064	vendor_id = strtoul(cmd, &pos, 16);
7065	if (!isblank((unsigned char) *pos))
7066		return -EINVAL;
7067
7068	subcmd = strtoul(pos, &pos, 10);
7069
7070	if (*pos != '\0') {
7071		if (!isblank((unsigned char) *pos++))
7072			return -EINVAL;
7073		data_len = os_strlen(pos);
7074	}
7075
7076	if (data_len) {
7077		data_len /= 2;
7078		data = os_malloc(data_len);
7079		if (!data)
7080			return -1;
7081
7082		if (hexstr2bin(pos, data, data_len)) {
7083			wpa_printf(MSG_DEBUG,
7084				   "Vendor command: wrong parameter format");
7085			os_free(data);
7086			return -EINVAL;
7087		}
7088	}
7089
7090	reply = wpabuf_alloc((buflen - 1) / 2);
7091	if (!reply) {
7092		os_free(data);
7093		return -1;
7094	}
7095
7096	ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
7097				 reply);
7098
7099	if (ret == 0)
7100		ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
7101				       wpabuf_len(reply));
7102
7103	wpabuf_free(reply);
7104	os_free(data);
7105
7106	return ret;
7107}
7108
7109
7110static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
7111{
7112#ifdef CONFIG_P2P
7113	struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
7114		wpa_s->global->p2p_init_wpa_s : wpa_s;
7115#endif /* CONFIG_P2P */
7116
7117	wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
7118
7119	wpas_abort_ongoing_scan(wpa_s);
7120
7121	if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
7122		/*
7123		 * Avoid possible auto connect re-connection on getting
7124		 * disconnected due to state flush.
7125		 */
7126		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
7127	}
7128
7129#ifdef CONFIG_P2P
7130	wpas_p2p_group_remove(p2p_wpa_s, "*");
7131	wpas_p2p_cancel(p2p_wpa_s);
7132	p2p_ctrl_flush(p2p_wpa_s);
7133	wpas_p2p_service_flush(p2p_wpa_s);
7134	p2p_wpa_s->global->p2p_disabled = 0;
7135	p2p_wpa_s->global->p2p_per_sta_psk = 0;
7136	p2p_wpa_s->conf->num_sec_device_types = 0;
7137	p2p_wpa_s->p2p_disable_ip_addr_req = 0;
7138	os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
7139	p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
7140	p2p_wpa_s->global->p2p_go_avoid_freq.num = 0;
7141	p2p_wpa_s->global->pending_p2ps_group = 0;
7142	p2p_wpa_s->global->pending_p2ps_group_freq = 0;
7143#endif /* CONFIG_P2P */
7144
7145#ifdef CONFIG_WPS_TESTING
7146	wps_version_number = 0x20;
7147	wps_testing_dummy_cred = 0;
7148	wps_corrupt_pkhash = 0;
7149	wps_force_auth_types_in_use = 0;
7150	wps_force_encr_types_in_use = 0;
7151#endif /* CONFIG_WPS_TESTING */
7152#ifdef CONFIG_WPS
7153	wpa_s->wps_fragment_size = 0;
7154	wpas_wps_cancel(wpa_s);
7155	wps_registrar_flush(wpa_s->wps->registrar);
7156#endif /* CONFIG_WPS */
7157	wpa_s->after_wps = 0;
7158	wpa_s->known_wps_freq = 0;
7159
7160#ifdef CONFIG_TDLS
7161#ifdef CONFIG_TDLS_TESTING
7162	tdls_testing = 0;
7163#endif /* CONFIG_TDLS_TESTING */
7164	wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
7165	wpa_tdls_enable(wpa_s->wpa, 1);
7166#endif /* CONFIG_TDLS */
7167
7168	eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
7169	wpa_supplicant_stop_countermeasures(wpa_s, NULL);
7170
7171	wpa_s->no_keep_alive = 0;
7172	wpa_s->own_disconnect_req = 0;
7173
7174	os_free(wpa_s->disallow_aps_bssid);
7175	wpa_s->disallow_aps_bssid = NULL;
7176	wpa_s->disallow_aps_bssid_count = 0;
7177	os_free(wpa_s->disallow_aps_ssid);
7178	wpa_s->disallow_aps_ssid = NULL;
7179	wpa_s->disallow_aps_ssid_count = 0;
7180
7181	wpa_s->set_sta_uapsd = 0;
7182	wpa_s->sta_uapsd = 0;
7183
7184	wpa_drv_radio_disable(wpa_s, 0);
7185	wpa_blacklist_clear(wpa_s);
7186	wpa_s->extra_blacklist_count = 0;
7187	wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
7188	wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
7189	wpa_config_flush_blobs(wpa_s->conf);
7190	wpa_s->conf->auto_interworking = 0;
7191	wpa_s->conf->okc = 0;
7192
7193	wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
7194	rsn_preauth_deinit(wpa_s->wpa);
7195
7196	wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
7197	wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
7198	wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
7199	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
7200
7201	radio_remove_works(wpa_s, NULL, 1);
7202	wpa_s->ext_work_in_progress = 0;
7203
7204	wpa_s->next_ssid = NULL;
7205
7206#ifdef CONFIG_INTERWORKING
7207#ifdef CONFIG_HS20
7208	hs20_cancel_fetch_osu(wpa_s);
7209	hs20_del_icon(wpa_s, NULL, NULL);
7210#endif /* CONFIG_HS20 */
7211#endif /* CONFIG_INTERWORKING */
7212
7213	wpa_s->ext_mgmt_frame_handling = 0;
7214	wpa_s->ext_eapol_frame_io = 0;
7215#ifdef CONFIG_TESTING_OPTIONS
7216	wpa_s->extra_roc_dur = 0;
7217	wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
7218	wpa_s->p2p_go_csa_on_inv = 0;
7219	wpa_s->ignore_auth_resp = 0;
7220	wpa_s->ignore_assoc_disallow = 0;
7221	wpa_s->reject_btm_req_reason = 0;
7222	wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
7223#endif /* CONFIG_TESTING_OPTIONS */
7224
7225	wpa_s->disconnected = 0;
7226	os_free(wpa_s->next_scan_freqs);
7227	wpa_s->next_scan_freqs = NULL;
7228
7229	wpa_bss_flush(wpa_s);
7230	if (!dl_list_empty(&wpa_s->bss)) {
7231		wpa_printf(MSG_DEBUG,
7232			   "BSS table not empty after flush: %u entries, current_bss=%p bssid="
7233			   MACSTR " pending_bssid=" MACSTR,
7234			   dl_list_len(&wpa_s->bss), wpa_s->current_bss,
7235			   MAC2STR(wpa_s->bssid),
7236			   MAC2STR(wpa_s->pending_bssid));
7237	}
7238
7239	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
7240	wpa_s->wnmsleep_used = 0;
7241
7242#ifdef CONFIG_SME
7243	wpa_s->sme.last_unprot_disconnect.sec = 0;
7244#endif /* CONFIG_SME */
7245}
7246
7247
7248static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
7249				     char *buf, size_t buflen)
7250{
7251	struct wpa_radio_work *work;
7252	char *pos, *end;
7253	struct os_reltime now, diff;
7254
7255	pos = buf;
7256	end = buf + buflen;
7257
7258	os_get_reltime(&now);
7259
7260	dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
7261	{
7262		int ret;
7263
7264		os_reltime_sub(&now, &work->time, &diff);
7265		ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
7266				  work->type, work->wpa_s->ifname, work->freq,
7267				  work->started, diff.sec, diff.usec);
7268		if (os_snprintf_error(end - pos, ret))
7269			break;
7270		pos += ret;
7271	}
7272
7273	return pos - buf;
7274}
7275
7276
7277static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
7278{
7279	struct wpa_radio_work *work = eloop_ctx;
7280	struct wpa_external_work *ework = work->ctx;
7281
7282	wpa_dbg(work->wpa_s, MSG_DEBUG,
7283		"Timing out external radio work %u (%s)",
7284		ework->id, work->type);
7285	wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
7286	work->wpa_s->ext_work_in_progress = 0;
7287	radio_work_done(work);
7288	os_free(ework);
7289}
7290
7291
7292static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
7293{
7294	struct wpa_external_work *ework = work->ctx;
7295
7296	if (deinit) {
7297		if (work->started)
7298			eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
7299					     work, NULL);
7300
7301		/*
7302		 * work->type points to a buffer in ework, so need to replace
7303		 * that here with a fixed string to avoid use of freed memory
7304		 * in debug prints.
7305		 */
7306		work->type = "freed-ext-work";
7307		work->ctx = NULL;
7308		os_free(ework);
7309		return;
7310	}
7311
7312	wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
7313		ework->id, ework->type);
7314	wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
7315	work->wpa_s->ext_work_in_progress = 1;
7316	if (!ework->timeout)
7317		ework->timeout = 10;
7318	eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
7319			       work, NULL);
7320}
7321
7322
7323static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
7324				    char *buf, size_t buflen)
7325{
7326	struct wpa_external_work *ework;
7327	char *pos, *pos2;
7328	size_t type_len;
7329	int ret;
7330	unsigned int freq = 0;
7331
7332	/* format: <name> [freq=<MHz>] [timeout=<seconds>] */
7333
7334	ework = os_zalloc(sizeof(*ework));
7335	if (ework == NULL)
7336		return -1;
7337
7338	pos = os_strchr(cmd, ' ');
7339	if (pos) {
7340		type_len = pos - cmd;
7341		pos++;
7342
7343		pos2 = os_strstr(pos, "freq=");
7344		if (pos2)
7345			freq = atoi(pos2 + 5);
7346
7347		pos2 = os_strstr(pos, "timeout=");
7348		if (pos2)
7349			ework->timeout = atoi(pos2 + 8);
7350	} else {
7351		type_len = os_strlen(cmd);
7352	}
7353	if (4 + type_len >= sizeof(ework->type))
7354		type_len = sizeof(ework->type) - 4 - 1;
7355	os_strlcpy(ework->type, "ext:", sizeof(ework->type));
7356	os_memcpy(ework->type + 4, cmd, type_len);
7357	ework->type[4 + type_len] = '\0';
7358
7359	wpa_s->ext_work_id++;
7360	if (wpa_s->ext_work_id == 0)
7361		wpa_s->ext_work_id++;
7362	ework->id = wpa_s->ext_work_id;
7363
7364	if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
7365			   ework) < 0) {
7366		os_free(ework);
7367		return -1;
7368	}
7369
7370	ret = os_snprintf(buf, buflen, "%u", ework->id);
7371	if (os_snprintf_error(buflen, ret))
7372		return -1;
7373	return ret;
7374}
7375
7376
7377static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
7378{
7379	struct wpa_radio_work *work;
7380	unsigned int id = atoi(cmd);
7381
7382	dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
7383	{
7384		struct wpa_external_work *ework;
7385
7386		if (os_strncmp(work->type, "ext:", 4) != 0)
7387			continue;
7388		ework = work->ctx;
7389		if (id && ework->id != id)
7390			continue;
7391		wpa_dbg(wpa_s, MSG_DEBUG,
7392			"Completed external radio work %u (%s)",
7393			ework->id, ework->type);
7394		eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
7395		wpa_s->ext_work_in_progress = 0;
7396		radio_work_done(work);
7397		os_free(ework);
7398		return 3; /* "OK\n" */
7399	}
7400
7401	return -1;
7402}
7403
7404
7405static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
7406				char *buf, size_t buflen)
7407{
7408	if (os_strcmp(cmd, "show") == 0)
7409		return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
7410	if (os_strncmp(cmd, "add ", 4) == 0)
7411		return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
7412	if (os_strncmp(cmd, "done ", 5) == 0)
7413		return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
7414	return -1;
7415}
7416
7417
7418void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
7419{
7420	struct wpa_radio_work *work, *tmp;
7421
7422	if (!wpa_s || !wpa_s->radio)
7423		return;
7424
7425	dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
7426			      struct wpa_radio_work, list) {
7427		struct wpa_external_work *ework;
7428
7429		if (os_strncmp(work->type, "ext:", 4) != 0)
7430			continue;
7431		ework = work->ctx;
7432		wpa_dbg(wpa_s, MSG_DEBUG,
7433			"Flushing%s external radio work %u (%s)",
7434			work->started ? " started" : "", ework->id,
7435			ework->type);
7436		if (work->started)
7437			eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
7438					     work, NULL);
7439		radio_work_done(work);
7440		os_free(ework);
7441	}
7442}
7443
7444
7445static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
7446{
7447	struct wpa_supplicant *wpa_s = eloop_ctx;
7448	eapol_sm_notify_ctrl_response(wpa_s->eapol);
7449}
7450
7451
7452static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value,
7453			      unsigned int *scan_id_count, int scan_id[])
7454{
7455	const char *pos = value;
7456
7457	while (pos) {
7458		if (*pos == ' ' || *pos == '\0')
7459			break;
7460		if (*scan_id_count == MAX_SCAN_ID)
7461			return -1;
7462		scan_id[(*scan_id_count)++] = atoi(pos);
7463		pos = os_strchr(pos, ',');
7464		if (pos)
7465			pos++;
7466	}
7467
7468	return 0;
7469}
7470
7471
7472static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
7473			   char *reply, int reply_size, int *reply_len)
7474{
7475	char *pos;
7476	unsigned int manual_scan_passive = 0;
7477	unsigned int manual_scan_use_id = 0;
7478	unsigned int manual_scan_only_new = 0;
7479	unsigned int scan_only = 0;
7480	unsigned int scan_id_count = 0;
7481	int scan_id[MAX_SCAN_ID];
7482	void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
7483				 struct wpa_scan_results *scan_res);
7484	int *manual_scan_freqs = NULL;
7485	struct wpa_ssid_value *ssid = NULL, *ns;
7486	unsigned int ssid_count = 0;
7487
7488	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
7489		*reply_len = -1;
7490		return;
7491	}
7492
7493	if (radio_work_pending(wpa_s, "scan")) {
7494		wpa_printf(MSG_DEBUG,
7495			   "Pending scan scheduled - reject new request");
7496		*reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
7497		return;
7498	}
7499
7500#ifdef CONFIG_INTERWORKING
7501	if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
7502		wpa_printf(MSG_DEBUG,
7503			   "Interworking select in progress - reject new scan");
7504		*reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
7505		return;
7506	}
7507#endif /* CONFIG_INTERWORKING */
7508
7509	if (params) {
7510		if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
7511			scan_only = 1;
7512
7513		pos = os_strstr(params, "freq=");
7514		if (pos) {
7515			manual_scan_freqs = freq_range_to_channel_list(wpa_s,
7516								       pos + 5);
7517			if (manual_scan_freqs == NULL) {
7518				*reply_len = -1;
7519				goto done;
7520			}
7521		}
7522
7523		pos = os_strstr(params, "passive=");
7524		if (pos)
7525			manual_scan_passive = !!atoi(pos + 8);
7526
7527		pos = os_strstr(params, "use_id=");
7528		if (pos)
7529			manual_scan_use_id = atoi(pos + 7);
7530
7531		pos = os_strstr(params, "only_new=1");
7532		if (pos)
7533			manual_scan_only_new = 1;
7534
7535		pos = os_strstr(params, "scan_id=");
7536		if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count,
7537					      scan_id) < 0) {
7538			*reply_len = -1;
7539			goto done;
7540		}
7541
7542		pos = params;
7543		while (pos && *pos != '\0') {
7544			if (os_strncmp(pos, "ssid ", 5) == 0) {
7545				char *end;
7546
7547				pos += 5;
7548				end = pos;
7549				while (*end) {
7550					if (*end == '\0' || *end == ' ')
7551						break;
7552					end++;
7553				}
7554
7555				ns = os_realloc_array(
7556					ssid, ssid_count + 1,
7557					sizeof(struct wpa_ssid_value));
7558				if (ns == NULL) {
7559					*reply_len = -1;
7560					goto done;
7561				}
7562				ssid = ns;
7563
7564				if ((end - pos) & 0x01 ||
7565				    end - pos > 2 * SSID_MAX_LEN ||
7566				    hexstr2bin(pos, ssid[ssid_count].ssid,
7567					       (end - pos) / 2) < 0) {
7568					wpa_printf(MSG_DEBUG,
7569						   "Invalid SSID value '%s'",
7570						   pos);
7571					*reply_len = -1;
7572					goto done;
7573				}
7574				ssid[ssid_count].ssid_len = (end - pos) / 2;
7575				wpa_hexdump_ascii(MSG_DEBUG, "scan SSID",
7576						  ssid[ssid_count].ssid,
7577						  ssid[ssid_count].ssid_len);
7578				ssid_count++;
7579				pos = end;
7580			}
7581
7582			pos = os_strchr(pos, ' ');
7583			if (pos)
7584				pos++;
7585		}
7586	}
7587
7588	wpa_s->num_ssids_from_scan_req = ssid_count;
7589	os_free(wpa_s->ssids_from_scan_req);
7590	if (ssid_count) {
7591		wpa_s->ssids_from_scan_req = ssid;
7592		ssid = NULL;
7593	} else {
7594		wpa_s->ssids_from_scan_req = NULL;
7595	}
7596
7597	if (scan_only)
7598		scan_res_handler = scan_only_handler;
7599	else if (wpa_s->scan_res_handler == scan_only_handler)
7600		scan_res_handler = NULL;
7601	else
7602		scan_res_handler = wpa_s->scan_res_handler;
7603
7604	if (!wpa_s->sched_scanning && !wpa_s->scanning &&
7605	    ((wpa_s->wpa_state <= WPA_SCANNING) ||
7606	     (wpa_s->wpa_state == WPA_COMPLETED))) {
7607		wpa_s->manual_scan_passive = manual_scan_passive;
7608		wpa_s->manual_scan_use_id = manual_scan_use_id;
7609		wpa_s->manual_scan_only_new = manual_scan_only_new;
7610		wpa_s->scan_id_count = scan_id_count;
7611		os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
7612		wpa_s->scan_res_handler = scan_res_handler;
7613		os_free(wpa_s->manual_scan_freqs);
7614		wpa_s->manual_scan_freqs = manual_scan_freqs;
7615		manual_scan_freqs = NULL;
7616
7617		wpa_s->normal_scans = 0;
7618		wpa_s->scan_req = MANUAL_SCAN_REQ;
7619		wpa_s->after_wps = 0;
7620		wpa_s->known_wps_freq = 0;
7621		wpa_supplicant_req_scan(wpa_s, 0, 0);
7622		if (wpa_s->manual_scan_use_id) {
7623			wpa_s->manual_scan_id++;
7624			wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
7625				wpa_s->manual_scan_id);
7626			*reply_len = os_snprintf(reply, reply_size, "%u\n",
7627						 wpa_s->manual_scan_id);
7628		}
7629	} else if (wpa_s->sched_scanning) {
7630		wpa_s->manual_scan_passive = manual_scan_passive;
7631		wpa_s->manual_scan_use_id = manual_scan_use_id;
7632		wpa_s->manual_scan_only_new = manual_scan_only_new;
7633		wpa_s->scan_id_count = scan_id_count;
7634		os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
7635		wpa_s->scan_res_handler = scan_res_handler;
7636		os_free(wpa_s->manual_scan_freqs);
7637		wpa_s->manual_scan_freqs = manual_scan_freqs;
7638		manual_scan_freqs = NULL;
7639
7640		wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
7641		wpa_supplicant_cancel_sched_scan(wpa_s);
7642		wpa_s->scan_req = MANUAL_SCAN_REQ;
7643		wpa_supplicant_req_scan(wpa_s, 0, 0);
7644		if (wpa_s->manual_scan_use_id) {
7645			wpa_s->manual_scan_id++;
7646			*reply_len = os_snprintf(reply, reply_size, "%u\n",
7647						 wpa_s->manual_scan_id);
7648			wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
7649				wpa_s->manual_scan_id);
7650		}
7651	} else {
7652		wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
7653		*reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
7654	}
7655
7656done:
7657	os_free(manual_scan_freqs);
7658	os_free(ssid);
7659}
7660
7661
7662#ifdef CONFIG_TESTING_OPTIONS
7663
7664static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s,
7665				       unsigned int freq, const u8 *dst,
7666				       const u8 *src, const u8 *bssid,
7667				       const u8 *data, size_t data_len,
7668				       enum offchannel_send_action_result
7669				       result)
7670{
7671	wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR
7672		" src=" MACSTR " bssid=" MACSTR " result=%s",
7673		freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
7674		result == OFFCHANNEL_SEND_ACTION_SUCCESS ?
7675		"SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ?
7676			     "NO_ACK" : "FAILED"));
7677}
7678
7679
7680static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd)
7681{
7682	char *pos, *param;
7683	size_t len;
7684	u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN];
7685	int res, used;
7686	int freq = 0, no_cck = 0, wait_time = 0;
7687
7688	/* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
7689	 *    <action=Action frame payload> */
7690
7691	wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
7692
7693	pos = cmd;
7694	used = hwaddr_aton2(pos, da);
7695	if (used < 0)
7696		return -1;
7697	pos += used;
7698	while (*pos == ' ')
7699		pos++;
7700	used = hwaddr_aton2(pos, bssid);
7701	if (used < 0)
7702		return -1;
7703	pos += used;
7704
7705	param = os_strstr(pos, " freq=");
7706	if (param) {
7707		param += 6;
7708		freq = atoi(param);
7709	}
7710
7711	param = os_strstr(pos, " no_cck=");
7712	if (param) {
7713		param += 8;
7714		no_cck = atoi(param);
7715	}
7716
7717	param = os_strstr(pos, " wait_time=");
7718	if (param) {
7719		param += 11;
7720		wait_time = atoi(param);
7721	}
7722
7723	param = os_strstr(pos, " action=");
7724	if (param == NULL)
7725		return -1;
7726	param += 8;
7727
7728	len = os_strlen(param);
7729	if (len & 1)
7730		return -1;
7731	len /= 2;
7732
7733	buf = os_malloc(len);
7734	if (buf == NULL)
7735		return -1;
7736
7737	if (hexstr2bin(param, buf, len) < 0) {
7738		os_free(buf);
7739		return -1;
7740	}
7741
7742	res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid,
7743				     buf, len, wait_time,
7744				     wpas_ctrl_iface_mgmt_tx_cb, no_cck);
7745	os_free(buf);
7746	return res;
7747}
7748
7749
7750static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
7751{
7752	wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting");
7753	offchannel_send_action_done(wpa_s);
7754}
7755
7756
7757static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s,
7758					   char *cmd)
7759{
7760	char *pos, *param;
7761	size_t len;
7762	u8 *buf;
7763	int freq = 0, datarate = 0, ssi_signal = 0;
7764	union wpa_event_data event;
7765
7766	if (!wpa_s->ext_mgmt_frame_handling)
7767		return -1;
7768
7769	/* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
7770
7771	wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
7772
7773	pos = cmd;
7774	param = os_strstr(pos, "freq=");
7775	if (param) {
7776		param += 5;
7777		freq = atoi(param);
7778	}
7779
7780	param = os_strstr(pos, " datarate=");
7781	if (param) {
7782		param += 10;
7783		datarate = atoi(param);
7784	}
7785
7786	param = os_strstr(pos, " ssi_signal=");
7787	if (param) {
7788		param += 12;
7789		ssi_signal = atoi(param);
7790	}
7791
7792	param = os_strstr(pos, " frame=");
7793	if (param == NULL)
7794		return -1;
7795	param += 7;
7796
7797	len = os_strlen(param);
7798	if (len & 1)
7799		return -1;
7800	len /= 2;
7801
7802	buf = os_malloc(len);
7803	if (buf == NULL)
7804		return -1;
7805
7806	if (hexstr2bin(param, buf, len) < 0) {
7807		os_free(buf);
7808		return -1;
7809	}
7810
7811	os_memset(&event, 0, sizeof(event));
7812	event.rx_mgmt.freq = freq;
7813	event.rx_mgmt.frame = buf;
7814	event.rx_mgmt.frame_len = len;
7815	event.rx_mgmt.ssi_signal = ssi_signal;
7816	event.rx_mgmt.datarate = datarate;
7817	wpa_s->ext_mgmt_frame_handling = 0;
7818	wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event);
7819	wpa_s->ext_mgmt_frame_handling = 1;
7820
7821	os_free(buf);
7822
7823	return 0;
7824}
7825
7826
7827static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
7828{
7829	char *pos, *param;
7830	union wpa_event_data event;
7831	enum wpa_event_type ev;
7832
7833	/* <event name> [parameters..] */
7834
7835	wpa_dbg(wpa_s, MSG_DEBUG, "Testing - external driver event: %s", cmd);
7836
7837	pos = cmd;
7838	param = os_strchr(pos, ' ');
7839	if (param)
7840		*param++ = '\0';
7841
7842	os_memset(&event, 0, sizeof(event));
7843
7844	if (os_strcmp(cmd, "INTERFACE_ENABLED") == 0) {
7845		ev = EVENT_INTERFACE_ENABLED;
7846	} else if (os_strcmp(cmd, "INTERFACE_DISABLED") == 0) {
7847		ev = EVENT_INTERFACE_DISABLED;
7848	} else if (os_strcmp(cmd, "AVOID_FREQUENCIES") == 0) {
7849		ev = EVENT_AVOID_FREQUENCIES;
7850		if (param == NULL)
7851			param = "";
7852		if (freq_range_list_parse(&event.freq_range, param) < 0)
7853			return -1;
7854		wpa_supplicant_event(wpa_s, ev, &event);
7855		os_free(event.freq_range.range);
7856		return 0;
7857	} else {
7858		wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
7859			cmd);
7860		return -1;
7861	}
7862
7863	wpa_supplicant_event(wpa_s, ev, &event);
7864
7865	return 0;
7866}
7867
7868
7869static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
7870{
7871	char *pos;
7872	u8 src[ETH_ALEN], *buf;
7873	int used;
7874	size_t len;
7875
7876	wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
7877
7878	pos = cmd;
7879	used = hwaddr_aton2(pos, src);
7880	if (used < 0)
7881		return -1;
7882	pos += used;
7883	while (*pos == ' ')
7884		pos++;
7885
7886	len = os_strlen(pos);
7887	if (len & 1)
7888		return -1;
7889	len /= 2;
7890
7891	buf = os_malloc(len);
7892	if (buf == NULL)
7893		return -1;
7894
7895	if (hexstr2bin(pos, buf, len) < 0) {
7896		os_free(buf);
7897		return -1;
7898	}
7899
7900	wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
7901	os_free(buf);
7902
7903	return 0;
7904}
7905
7906
7907static u16 ipv4_hdr_checksum(const void *buf, size_t len)
7908{
7909	size_t i;
7910	u32 sum = 0;
7911	const u16 *pos = buf;
7912
7913	for (i = 0; i < len / 2; i++)
7914		sum += *pos++;
7915
7916	while (sum >> 16)
7917		sum = (sum & 0xffff) + (sum >> 16);
7918
7919	return sum ^ 0xffff;
7920}
7921
7922
7923#define HWSIM_PACKETLEN 1500
7924#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
7925
7926static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
7927			      size_t len)
7928{
7929	struct wpa_supplicant *wpa_s = ctx;
7930	const struct ether_header *eth;
7931	struct iphdr ip;
7932	const u8 *pos;
7933	unsigned int i;
7934
7935	if (len != HWSIM_PACKETLEN)
7936		return;
7937
7938	eth = (const struct ether_header *) buf;
7939	os_memcpy(&ip, eth + 1, sizeof(ip));
7940	pos = &buf[sizeof(*eth) + sizeof(ip)];
7941
7942	if (ip.ihl != 5 || ip.version != 4 ||
7943	    ntohs(ip.tot_len) != HWSIM_IP_LEN)
7944		return;
7945
7946	for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
7947		if (*pos != (u8) i)
7948			return;
7949		pos++;
7950	}
7951
7952	wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
7953		MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
7954}
7955
7956
7957static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
7958					    char *cmd)
7959{
7960	int enabled = atoi(cmd);
7961	char *pos;
7962	const char *ifname;
7963
7964	if (!enabled) {
7965		if (wpa_s->l2_test) {
7966			l2_packet_deinit(wpa_s->l2_test);
7967			wpa_s->l2_test = NULL;
7968			wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled");
7969		}
7970		return 0;
7971	}
7972
7973	if (wpa_s->l2_test)
7974		return 0;
7975
7976	pos = os_strstr(cmd, " ifname=");
7977	if (pos)
7978		ifname = pos + 8;
7979	else
7980		ifname = wpa_s->ifname;
7981
7982	wpa_s->l2_test = l2_packet_init(ifname, wpa_s->own_addr,
7983					ETHERTYPE_IP, wpas_data_test_rx,
7984					wpa_s, 1);
7985	if (wpa_s->l2_test == NULL)
7986		return -1;
7987
7988	wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled");
7989
7990	return 0;
7991}
7992
7993
7994static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
7995{
7996	u8 dst[ETH_ALEN], src[ETH_ALEN];
7997	char *pos;
7998	int used;
7999	long int val;
8000	u8 tos;
8001	u8 buf[2 + HWSIM_PACKETLEN];
8002	struct ether_header *eth;
8003	struct iphdr *ip;
8004	u8 *dpos;
8005	unsigned int i;
8006
8007	if (wpa_s->l2_test == NULL)
8008		return -1;
8009
8010	/* format: <dst> <src> <tos> */
8011
8012	pos = cmd;
8013	used = hwaddr_aton2(pos, dst);
8014	if (used < 0)
8015		return -1;
8016	pos += used;
8017	while (*pos == ' ')
8018		pos++;
8019	used = hwaddr_aton2(pos, src);
8020	if (used < 0)
8021		return -1;
8022	pos += used;
8023
8024	val = strtol(pos, NULL, 0);
8025	if (val < 0 || val > 0xff)
8026		return -1;
8027	tos = val;
8028
8029	eth = (struct ether_header *) &buf[2];
8030	os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
8031	os_memcpy(eth->ether_shost, src, ETH_ALEN);
8032	eth->ether_type = htons(ETHERTYPE_IP);
8033	ip = (struct iphdr *) (eth + 1);
8034	os_memset(ip, 0, sizeof(*ip));
8035	ip->ihl = 5;
8036	ip->version = 4;
8037	ip->ttl = 64;
8038	ip->tos = tos;
8039	ip->tot_len = htons(HWSIM_IP_LEN);
8040	ip->protocol = 1;
8041	ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
8042	ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
8043	ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
8044	dpos = (u8 *) (ip + 1);
8045	for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
8046		*dpos++ = i;
8047
8048	if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],
8049			   HWSIM_PACKETLEN) < 0)
8050		return -1;
8051
8052	wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
8053		" tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
8054
8055	return 0;
8056}
8057
8058
8059static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s,
8060					   char *cmd)
8061{
8062	u8 *buf;
8063	struct ether_header *eth;
8064	struct l2_packet_data *l2 = NULL;
8065	size_t len;
8066	u16 ethertype;
8067	int res = -1;
8068
8069	len = os_strlen(cmd);
8070	if (len & 1 || len < ETH_HLEN * 2)
8071		return -1;
8072	len /= 2;
8073
8074	buf = os_malloc(len);
8075	if (buf == NULL)
8076		return -1;
8077
8078	if (hexstr2bin(cmd, buf, len) < 0)
8079		goto done;
8080
8081	eth = (struct ether_header *) buf;
8082	ethertype = ntohs(eth->ether_type);
8083
8084	l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype,
8085			    wpas_data_test_rx, wpa_s, 1);
8086	if (l2 == NULL)
8087		goto done;
8088
8089	res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
8090	wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res);
8091done:
8092	if (l2)
8093		l2_packet_deinit(l2);
8094	os_free(buf);
8095
8096	return res < 0 ? -1 : 0;
8097}
8098
8099
8100static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
8101{
8102#ifdef WPA_TRACE_BFD
8103	char *pos;
8104
8105	wpa_trace_fail_after = atoi(cmd);
8106	pos = os_strchr(cmd, ':');
8107	if (pos) {
8108		pos++;
8109		os_strlcpy(wpa_trace_fail_func, pos,
8110			   sizeof(wpa_trace_fail_func));
8111	} else {
8112		wpa_trace_fail_after = 0;
8113	}
8114	return 0;
8115#else /* WPA_TRACE_BFD */
8116	return -1;
8117#endif /* WPA_TRACE_BFD */
8118}
8119
8120
8121static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
8122				    char *buf, size_t buflen)
8123{
8124#ifdef WPA_TRACE_BFD
8125	return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
8126			   wpa_trace_fail_func);
8127#else /* WPA_TRACE_BFD */
8128	return -1;
8129#endif /* WPA_TRACE_BFD */
8130}
8131
8132
8133static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
8134{
8135#ifdef WPA_TRACE_BFD
8136	char *pos;
8137
8138	wpa_trace_test_fail_after = atoi(cmd);
8139	pos = os_strchr(cmd, ':');
8140	if (pos) {
8141		pos++;
8142		os_strlcpy(wpa_trace_test_fail_func, pos,
8143			   sizeof(wpa_trace_test_fail_func));
8144	} else {
8145		wpa_trace_test_fail_after = 0;
8146	}
8147	return 0;
8148#else /* WPA_TRACE_BFD */
8149	return -1;
8150#endif /* WPA_TRACE_BFD */
8151}
8152
8153
8154static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s,
8155				    char *buf, size_t buflen)
8156{
8157#ifdef WPA_TRACE_BFD
8158	return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
8159			   wpa_trace_test_fail_func);
8160#else /* WPA_TRACE_BFD */
8161	return -1;
8162#endif /* WPA_TRACE_BFD */
8163}
8164
8165
8166static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx)
8167{
8168	struct wpa_supplicant *wpa_s = eloop_ctx;
8169	int i, count = (intptr_t) timeout_ctx;
8170
8171	wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages",
8172		   count);
8173	for (i = 0; i < count; i++) {
8174		wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d",
8175			     i + 1, count);
8176	}
8177}
8178
8179
8180static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
8181{
8182	int count;
8183
8184	count = atoi(cmd);
8185	if (count <= 0)
8186		return -1;
8187
8188	return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s,
8189				      (void *) (intptr_t) count);
8190}
8191
8192
8193static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
8194				   const char *cmd)
8195{
8196	struct wpabuf *buf;
8197	size_t len;
8198
8199	len = os_strlen(cmd);
8200	if (len & 1)
8201		return -1;
8202	len /= 2;
8203
8204	if (len == 0) {
8205		buf = NULL;
8206	} else {
8207		buf = wpabuf_alloc(len);
8208		if (buf == NULL)
8209			return -1;
8210
8211		if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
8212			wpabuf_free(buf);
8213			return -1;
8214		}
8215	}
8216
8217	wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
8218	return 0;
8219}
8220
8221#endif /* CONFIG_TESTING_OPTIONS */
8222
8223
8224static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
8225{
8226	char *pos = cmd;
8227	int frame;
8228	size_t len;
8229	struct wpabuf *buf;
8230	struct ieee802_11_elems elems;
8231
8232	frame = atoi(pos);
8233	if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
8234		return -1;
8235	wpa_s = wpas_vendor_elem(wpa_s, frame);
8236
8237	pos = os_strchr(pos, ' ');
8238	if (pos == NULL)
8239		return -1;
8240	pos++;
8241
8242	len = os_strlen(pos);
8243	if (len == 0)
8244		return 0;
8245	if (len & 1)
8246		return -1;
8247	len /= 2;
8248
8249	buf = wpabuf_alloc(len);
8250	if (buf == NULL)
8251		return -1;
8252
8253	if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
8254		wpabuf_free(buf);
8255		return -1;
8256	}
8257
8258	if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) ==
8259	    ParseFailed) {
8260		wpabuf_free(buf);
8261		return -1;
8262	}
8263
8264	if (wpa_s->vendor_elem[frame] == NULL) {
8265		wpa_s->vendor_elem[frame] = buf;
8266		wpas_vendor_elem_update(wpa_s);
8267		return 0;
8268	}
8269
8270	if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
8271		wpabuf_free(buf);
8272		return -1;
8273	}
8274
8275	wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
8276	wpabuf_free(buf);
8277	wpas_vendor_elem_update(wpa_s);
8278
8279	return 0;
8280}
8281
8282
8283static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
8284				     char *buf, size_t buflen)
8285{
8286	int frame = atoi(cmd);
8287
8288	if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
8289		return -1;
8290	wpa_s = wpas_vendor_elem(wpa_s, frame);
8291
8292	if (wpa_s->vendor_elem[frame] == NULL)
8293		return 0;
8294
8295	return wpa_snprintf_hex(buf, buflen,
8296				wpabuf_head_u8(wpa_s->vendor_elem[frame]),
8297				wpabuf_len(wpa_s->vendor_elem[frame]));
8298}
8299
8300
8301static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
8302{
8303	char *pos = cmd;
8304	int frame;
8305	size_t len;
8306	u8 *buf;
8307	struct ieee802_11_elems elems;
8308	int res;
8309
8310	frame = atoi(pos);
8311	if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
8312		return -1;
8313	wpa_s = wpas_vendor_elem(wpa_s, frame);
8314
8315	pos = os_strchr(pos, ' ');
8316	if (pos == NULL)
8317		return -1;
8318	pos++;
8319
8320	if (*pos == '*') {
8321		wpabuf_free(wpa_s->vendor_elem[frame]);
8322		wpa_s->vendor_elem[frame] = NULL;
8323		wpas_vendor_elem_update(wpa_s);
8324		return 0;
8325	}
8326
8327	if (wpa_s->vendor_elem[frame] == NULL)
8328		return -1;
8329
8330	len = os_strlen(pos);
8331	if (len == 0)
8332		return 0;
8333	if (len & 1)
8334		return -1;
8335	len /= 2;
8336
8337	buf = os_malloc(len);
8338	if (buf == NULL)
8339		return -1;
8340
8341	if (hexstr2bin(pos, buf, len) < 0) {
8342		os_free(buf);
8343		return -1;
8344	}
8345
8346	if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) {
8347		os_free(buf);
8348		return -1;
8349	}
8350
8351	res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
8352	os_free(buf);
8353	return res;
8354}
8355
8356
8357static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
8358{
8359	struct wpa_supplicant *wpa_s = ctx;
8360	size_t len;
8361	const u8 *data;
8362
8363	/*
8364	 * Neighbor Report element (IEEE P802.11-REVmc/D5.0)
8365	 * BSSID[6]
8366	 * BSSID Information[4]
8367	 * Operating Class[1]
8368	 * Channel Number[1]
8369	 * PHY Type[1]
8370	 * Optional Subelements[variable]
8371	 */
8372#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
8373
8374	if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) {
8375		wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
8376		goto out;
8377	}
8378
8379	data = wpabuf_head_u8(neighbor_rep);
8380	len = wpabuf_len(neighbor_rep);
8381
8382	while (len >= 2 + NR_IE_MIN_LEN) {
8383		const u8 *nr;
8384		char lci[256 * 2 + 1];
8385		char civic[256 * 2 + 1];
8386		u8 nr_len = data[1];
8387		const u8 *pos = data, *end;
8388
8389		if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
8390		    nr_len < NR_IE_MIN_LEN) {
8391			wpa_printf(MSG_DEBUG,
8392				   "CTRL: Invalid Neighbor Report element: id=%u len=%u",
8393				   data[0], nr_len);
8394			goto out;
8395		}
8396
8397		if (2U + nr_len > len) {
8398			wpa_printf(MSG_DEBUG,
8399				   "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
8400				   data[0], len, nr_len);
8401			goto out;
8402		}
8403		pos += 2;
8404		end = pos + nr_len;
8405
8406		nr = pos;
8407		pos += NR_IE_MIN_LEN;
8408
8409		lci[0] = '\0';
8410		civic[0] = '\0';
8411		while (end - pos > 2) {
8412			u8 s_id, s_len;
8413
8414			s_id = *pos++;
8415			s_len = *pos++;
8416			if (s_len > end - pos)
8417				goto out;
8418			if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
8419				/* Measurement Token[1] */
8420				/* Measurement Report Mode[1] */
8421				/* Measurement Type[1] */
8422				/* Measurement Report[variable] */
8423				switch (pos[2]) {
8424				case MEASURE_TYPE_LCI:
8425					if (lci[0])
8426						break;
8427					wpa_snprintf_hex(lci, sizeof(lci),
8428							 pos, s_len);
8429					break;
8430				case MEASURE_TYPE_LOCATION_CIVIC:
8431					if (civic[0])
8432						break;
8433					wpa_snprintf_hex(civic, sizeof(civic),
8434							 pos, s_len);
8435					break;
8436				}
8437			}
8438
8439			pos += s_len;
8440		}
8441
8442		wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
8443			"bssid=" MACSTR
8444			" info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
8445			MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
8446			nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
8447			nr[ETH_ALEN + 6],
8448			lci[0] ? " lci=" : "", lci,
8449			civic[0] ? " civic=" : "", civic);
8450
8451		data = end;
8452		len -= 2 + nr_len;
8453	}
8454
8455out:
8456	wpabuf_free(neighbor_rep);
8457}
8458
8459
8460static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
8461					     char *cmd)
8462{
8463	struct wpa_ssid_value ssid, *ssid_p = NULL;
8464	int ret, lci = 0, civic = 0;
8465	char *ssid_s;
8466
8467	ssid_s = os_strstr(cmd, "ssid=");
8468	if (ssid_s) {
8469		if (ssid_parse(ssid_s + 5, &ssid)) {
8470			wpa_printf(MSG_ERROR,
8471				   "CTRL: Send Neighbor Report: bad SSID");
8472			return -1;
8473		}
8474
8475		ssid_p = &ssid;
8476
8477		/*
8478		 * Move cmd after the SSID text that may include "lci" or
8479		 * "civic".
8480		 */
8481		cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' ');
8482		if (cmd)
8483			cmd++;
8484
8485	}
8486
8487	if (cmd && os_strstr(cmd, "lci"))
8488		lci = 1;
8489
8490	if (cmd && os_strstr(cmd, "civic"))
8491		civic = 1;
8492
8493	ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic,
8494						 wpas_ctrl_neighbor_rep_cb,
8495						 wpa_s);
8496
8497	return ret;
8498}
8499
8500
8501static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
8502{
8503	eapol_sm_erp_flush(wpa_s->eapol);
8504	return 0;
8505}
8506
8507
8508static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
8509					 char *cmd)
8510{
8511	char *token, *context = NULL;
8512	unsigned int enable = ~0, type = 0;
8513	u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
8514	u8 *addr = NULL, *mask = NULL;
8515
8516	while ((token = str_token(cmd, " ", &context))) {
8517		if (os_strcasecmp(token, "scan") == 0) {
8518			type |= MAC_ADDR_RAND_SCAN;
8519		} else if (os_strcasecmp(token, "sched") == 0) {
8520			type |= MAC_ADDR_RAND_SCHED_SCAN;
8521		} else if (os_strcasecmp(token, "pno") == 0) {
8522			type |= MAC_ADDR_RAND_PNO;
8523		} else if (os_strcasecmp(token, "all") == 0) {
8524			type = wpa_s->mac_addr_rand_supported;
8525		} else if (os_strncasecmp(token, "enable=", 7) == 0) {
8526			enable = atoi(token + 7);
8527		} else if (os_strncasecmp(token, "addr=", 5) == 0) {
8528			addr = _addr;
8529			if (hwaddr_aton(token + 5, addr)) {
8530				wpa_printf(MSG_INFO,
8531					   "CTRL: Invalid MAC address: %s",
8532					   token);
8533				return -1;
8534			}
8535		} else if (os_strncasecmp(token, "mask=", 5) == 0) {
8536			mask = _mask;
8537			if (hwaddr_aton(token + 5, mask)) {
8538				wpa_printf(MSG_INFO,
8539					   "CTRL: Invalid MAC address mask: %s",
8540					   token);
8541				return -1;
8542			}
8543		} else {
8544			wpa_printf(MSG_INFO,
8545				   "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
8546				   token);
8547			return -1;
8548		}
8549	}
8550
8551	if (!type) {
8552		wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
8553		return -1;
8554	}
8555
8556	if ((wpa_s->mac_addr_rand_supported & type) != type) {
8557		wpa_printf(MSG_INFO,
8558			   "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
8559			   type, wpa_s->mac_addr_rand_supported);
8560		return -1;
8561	}
8562
8563	if (enable > 1) {
8564		wpa_printf(MSG_INFO,
8565			   "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
8566		return -1;
8567	}
8568
8569	if (!enable) {
8570		wpas_mac_addr_rand_scan_clear(wpa_s, type);
8571		if (wpa_s->pno) {
8572			if (type & MAC_ADDR_RAND_PNO) {
8573				wpas_stop_pno(wpa_s);
8574				wpas_start_pno(wpa_s);
8575			}
8576		} else if (wpa_s->sched_scanning &&
8577			   (type & MAC_ADDR_RAND_SCHED_SCAN)) {
8578			wpas_scan_restart_sched_scan(wpa_s);
8579		}
8580		return 0;
8581	}
8582
8583	if ((addr && !mask) || (!addr && mask)) {
8584		wpa_printf(MSG_INFO,
8585			   "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
8586		return -1;
8587	}
8588
8589	if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
8590		wpa_printf(MSG_INFO,
8591			   "CTRL: MAC_RAND_SCAN cannot allow multicast address");
8592		return -1;
8593	}
8594
8595	if (type & MAC_ADDR_RAND_SCAN) {
8596		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
8597					    addr, mask);
8598	}
8599
8600	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
8601		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
8602					    addr, mask);
8603
8604		if (wpa_s->sched_scanning && !wpa_s->pno)
8605			wpas_scan_restart_sched_scan(wpa_s);
8606	}
8607
8608	if (type & MAC_ADDR_RAND_PNO) {
8609		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
8610					    addr, mask);
8611		if (wpa_s->pno) {
8612			wpas_stop_pno(wpa_s);
8613			wpas_start_pno(wpa_s);
8614		}
8615	}
8616
8617	return 0;
8618}
8619
8620
8621static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
8622				 char *buf, size_t buflen)
8623{
8624	size_t reply_len;
8625
8626	reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
8627#ifdef CONFIG_AP
8628	reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
8629					      buflen - reply_len);
8630#endif /* CONFIG_AP */
8631	return reply_len;
8632}
8633
8634
8635static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
8636{
8637	wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
8638#ifdef CONFIG_AP
8639	wpas_ap_pmksa_cache_flush(wpa_s);
8640#endif /* CONFIG_AP */
8641}
8642
8643
8644static int wpas_ctrl_cmd_debug_level(const char *cmd)
8645{
8646	if (os_strcmp(cmd, "PING") == 0 ||
8647	    os_strncmp(cmd, "BSS ", 4) == 0 ||
8648	    os_strncmp(cmd, "GET_NETWORK ", 12) == 0 ||
8649	    os_strncmp(cmd, "STATUS", 6) == 0 ||
8650	    os_strncmp(cmd, "STA ", 4) == 0 ||
8651	    os_strncmp(cmd, "STA-", 4) == 0)
8652		return MSG_EXCESSIVE;
8653	return MSG_DEBUG;
8654}
8655
8656
8657char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
8658					 char *buf, size_t *resp_len)
8659{
8660	char *reply;
8661	const int reply_size = 4096;
8662	int reply_len;
8663
8664	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
8665	    os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
8666		if (wpa_debug_show_keys)
8667			wpa_dbg(wpa_s, MSG_DEBUG,
8668				"Control interface command '%s'", buf);
8669		else
8670			wpa_dbg(wpa_s, MSG_DEBUG,
8671				"Control interface command '%s [REMOVED]'",
8672				os_strncmp(buf, WPA_CTRL_RSP,
8673					   os_strlen(WPA_CTRL_RSP)) == 0 ?
8674				WPA_CTRL_RSP : "SET_NETWORK");
8675	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
8676		   os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0) {
8677		wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
8678				      (const u8 *) buf, os_strlen(buf));
8679	} else {
8680		int level = wpas_ctrl_cmd_debug_level(buf);
8681		wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
8682	}
8683
8684	reply = os_malloc(reply_size);
8685	if (reply == NULL) {
8686		*resp_len = 1;
8687		return NULL;
8688	}
8689
8690	os_memcpy(reply, "OK\n", 3);
8691	reply_len = 3;
8692
8693	if (os_strcmp(buf, "PING") == 0) {
8694		os_memcpy(reply, "PONG\n", 5);
8695		reply_len = 5;
8696	} else if (os_strcmp(buf, "IFNAME") == 0) {
8697		reply_len = os_strlen(wpa_s->ifname);
8698		os_memcpy(reply, wpa_s->ifname, reply_len);
8699	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
8700		if (wpa_debug_reopen_file() < 0)
8701			reply_len = -1;
8702	} else if (os_strncmp(buf, "NOTE ", 5) == 0) {
8703		wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
8704	} else if (os_strcmp(buf, "MIB") == 0) {
8705		reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
8706		if (reply_len >= 0) {
8707			reply_len += eapol_sm_get_mib(wpa_s->eapol,
8708						      reply + reply_len,
8709						      reply_size - reply_len);
8710		}
8711	} else if (os_strncmp(buf, "STATUS", 6) == 0) {
8712		reply_len = wpa_supplicant_ctrl_iface_status(
8713			wpa_s, buf + 6, reply, reply_size);
8714	} else if (os_strcmp(buf, "PMKSA") == 0) {
8715		reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
8716	} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
8717		wpas_ctrl_iface_pmksa_flush(wpa_s);
8718	} else if (os_strncmp(buf, "SET ", 4) == 0) {
8719		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
8720			reply_len = -1;
8721	} else if (os_strncmp(buf, "DUMP", 4) == 0) {
8722		reply_len = wpa_config_dump_values(wpa_s->conf,
8723						   reply, reply_size);
8724	} else if (os_strncmp(buf, "GET ", 4) == 0) {
8725		reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
8726							  reply, reply_size);
8727	} else if (os_strcmp(buf, "LOGON") == 0) {
8728		eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
8729	} else if (os_strcmp(buf, "LOGOFF") == 0) {
8730		eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
8731	} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
8732		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
8733			reply_len = -1;
8734		else
8735			wpas_request_connection(wpa_s);
8736	} else if (os_strcmp(buf, "REATTACH") == 0) {
8737		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED ||
8738		    !wpa_s->current_ssid)
8739			reply_len = -1;
8740		else {
8741			wpa_s->reattach = 1;
8742			wpas_request_connection(wpa_s);
8743		}
8744	} else if (os_strcmp(buf, "RECONNECT") == 0) {
8745		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
8746			reply_len = -1;
8747		else if (wpa_s->disconnected)
8748			wpas_request_connection(wpa_s);
8749#ifdef IEEE8021X_EAPOL
8750	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
8751		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
8752			reply_len = -1;
8753#endif /* IEEE8021X_EAPOL */
8754#ifdef CONFIG_PEERKEY
8755	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
8756		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
8757			reply_len = -1;
8758#endif /* CONFIG_PEERKEY */
8759#ifdef CONFIG_IEEE80211R
8760	} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
8761		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
8762			reply_len = -1;
8763#endif /* CONFIG_IEEE80211R */
8764#ifdef CONFIG_WPS
8765	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
8766		int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
8767		if (res == -2) {
8768			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
8769			reply_len = 17;
8770		} else if (res)
8771			reply_len = -1;
8772	} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
8773		int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
8774		if (res == -2) {
8775			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
8776			reply_len = 17;
8777		} else if (res)
8778			reply_len = -1;
8779	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
8780		reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
8781							      reply,
8782							      reply_size);
8783	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
8784		reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
8785			wpa_s, buf + 14, reply, reply_size);
8786	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
8787		if (wpas_wps_cancel(wpa_s))
8788			reply_len = -1;
8789#ifdef CONFIG_WPS_NFC
8790	} else if (os_strcmp(buf, "WPS_NFC") == 0) {
8791		if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
8792			reply_len = -1;
8793	} else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
8794		if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
8795			reply_len = -1;
8796	} else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
8797		reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
8798			wpa_s, buf + 21, reply, reply_size);
8799	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
8800		reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
8801			wpa_s, buf + 14, reply, reply_size);
8802	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
8803		if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
8804							       buf + 17))
8805			reply_len = -1;
8806	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
8807		reply_len = wpas_ctrl_nfc_get_handover_req(
8808			wpa_s, buf + 21, reply, reply_size);
8809	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
8810		reply_len = wpas_ctrl_nfc_get_handover_sel(
8811			wpa_s, buf + 21, reply, reply_size);
8812	} else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
8813		if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
8814			reply_len = -1;
8815#endif /* CONFIG_WPS_NFC */
8816	} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
8817		if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
8818			reply_len = -1;
8819#ifdef CONFIG_AP
8820	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
8821		reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
8822			wpa_s, buf + 11, reply, reply_size);
8823#endif /* CONFIG_AP */
8824#ifdef CONFIG_WPS_ER
8825	} else if (os_strcmp(buf, "WPS_ER_START") == 0) {
8826		if (wpas_wps_er_start(wpa_s, NULL))
8827			reply_len = -1;
8828	} else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
8829		if (wpas_wps_er_start(wpa_s, buf + 13))
8830			reply_len = -1;
8831	} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
8832		wpas_wps_er_stop(wpa_s);
8833	} else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
8834		if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
8835			reply_len = -1;
8836	} else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
8837		int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
8838		if (ret == -2) {
8839			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
8840			reply_len = 17;
8841		} else if (ret == -3) {
8842			os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
8843			reply_len = 18;
8844		} else if (ret == -4) {
8845			os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
8846			reply_len = 20;
8847		} else if (ret)
8848			reply_len = -1;
8849	} else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
8850		if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
8851			reply_len = -1;
8852	} else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
8853		if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
8854								buf + 18))
8855			reply_len = -1;
8856	} else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
8857		if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
8858			reply_len = -1;
8859#ifdef CONFIG_WPS_NFC
8860	} else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
8861		reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
8862			wpa_s, buf + 24, reply, reply_size);
8863#endif /* CONFIG_WPS_NFC */
8864#endif /* CONFIG_WPS_ER */
8865#endif /* CONFIG_WPS */
8866#ifdef CONFIG_IBSS_RSN
8867	} else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
8868		if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
8869			reply_len = -1;
8870#endif /* CONFIG_IBSS_RSN */
8871#ifdef CONFIG_MESH
8872	} else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
8873		reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
8874			wpa_s, buf + 19, reply, reply_size);
8875	} else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
8876		reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
8877			wpa_s, "", reply, reply_size);
8878	} else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
8879		if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
8880			reply_len = -1;
8881	} else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
8882		if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
8883								buf + 18))
8884			reply_len = -1;
8885	} else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
8886		if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
8887			reply_len = -1;
8888	} else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
8889		if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
8890			reply_len = -1;
8891#endif /* CONFIG_MESH */
8892#ifdef CONFIG_P2P
8893	} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
8894		if (p2p_ctrl_find(wpa_s, buf + 8))
8895			reply_len = -1;
8896	} else if (os_strcmp(buf, "P2P_FIND") == 0) {
8897		if (p2p_ctrl_find(wpa_s, ""))
8898			reply_len = -1;
8899	} else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
8900		wpas_p2p_stop_find(wpa_s);
8901	} else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) {
8902		if (p2p_ctrl_asp_provision(wpa_s, buf + 18))
8903			reply_len = -1;
8904	} else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) {
8905		if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23))
8906			reply_len = -1;
8907	} else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
8908		reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
8909					     reply_size);
8910	} else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
8911		if (p2p_ctrl_listen(wpa_s, buf + 11))
8912			reply_len = -1;
8913	} else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
8914		if (p2p_ctrl_listen(wpa_s, ""))
8915			reply_len = -1;
8916	} else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
8917		if (wpas_p2p_group_remove(wpa_s, buf + 17))
8918			reply_len = -1;
8919	} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
8920		if (p2p_ctrl_group_add(wpa_s, ""))
8921			reply_len = -1;
8922	} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
8923		if (p2p_ctrl_group_add(wpa_s, buf + 14))
8924			reply_len = -1;
8925	} else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) {
8926		reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply,
8927						  reply_size);
8928	} else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
8929		if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
8930			reply_len = -1;
8931	} else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
8932		reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
8933	} else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
8934		reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
8935						   reply_size);
8936	} else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
8937		if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
8938			reply_len = -1;
8939	} else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
8940		if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
8941			reply_len = -1;
8942	} else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
8943		wpas_p2p_sd_service_update(wpa_s);
8944	} else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
8945		if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
8946			reply_len = -1;
8947	} else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
8948		wpas_p2p_service_flush(wpa_s);
8949	} else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
8950		if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
8951			reply_len = -1;
8952	} else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
8953		if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
8954			reply_len = -1;
8955	} else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) {
8956		if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0)
8957			reply_len = -1;
8958	} else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
8959		if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
8960			reply_len = -1;
8961	} else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
8962		if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
8963			reply_len = -1;
8964	} else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
8965		reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
8966					      reply_size);
8967	} else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
8968		if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
8969			reply_len = -1;
8970	} else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
8971		p2p_ctrl_flush(wpa_s);
8972	} else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
8973		if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
8974			reply_len = -1;
8975	} else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
8976		if (wpas_p2p_cancel(wpa_s))
8977			reply_len = -1;
8978	} else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
8979		if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
8980			reply_len = -1;
8981	} else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
8982		if (p2p_ctrl_presence_req(wpa_s, "") < 0)
8983			reply_len = -1;
8984	} else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
8985		if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
8986			reply_len = -1;
8987	} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
8988		if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
8989			reply_len = -1;
8990	} else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
8991		if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
8992			reply_len = -1;
8993	} else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
8994		if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
8995			reply_len = -1;
8996	} else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
8997		if (wpas_p2p_lo_stop(wpa_s))
8998			reply_len = -1;
8999#endif /* CONFIG_P2P */
9000#ifdef CONFIG_WIFI_DISPLAY
9001	} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
9002		if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
9003			reply_len = -1;
9004	} else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
9005		reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
9006						     reply, reply_size);
9007#endif /* CONFIG_WIFI_DISPLAY */
9008#ifdef CONFIG_INTERWORKING
9009	} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
9010		if (interworking_fetch_anqp(wpa_s) < 0)
9011			reply_len = -1;
9012	} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
9013		interworking_stop_fetch_anqp(wpa_s);
9014	} else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
9015		if (ctrl_interworking_select(wpa_s, NULL) < 0)
9016			reply_len = -1;
9017	} else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
9018		if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
9019			reply_len = -1;
9020	} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
9021		if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0)
9022			reply_len = -1;
9023	} else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) {
9024		int id;
9025
9026		id = ctrl_interworking_connect(wpa_s, buf + 25, 1);
9027		if (id < 0)
9028			reply_len = -1;
9029		else {
9030			reply_len = os_snprintf(reply, reply_size, "%d\n", id);
9031			if (os_snprintf_error(reply_size, reply_len))
9032				reply_len = -1;
9033		}
9034	} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
9035		if (get_anqp(wpa_s, buf + 9) < 0)
9036			reply_len = -1;
9037	} else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
9038		if (gas_request(wpa_s, buf + 12) < 0)
9039			reply_len = -1;
9040	} else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
9041		reply_len = gas_response_get(wpa_s, buf + 17, reply,
9042					     reply_size);
9043#endif /* CONFIG_INTERWORKING */
9044#ifdef CONFIG_HS20
9045	} else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
9046		if (get_hs20_anqp(wpa_s, buf + 14) < 0)
9047			reply_len = -1;
9048	} else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
9049		if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
9050			reply_len = -1;
9051	} else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
9052		if (hs20_icon_request(wpa_s, buf + 18, 0) < 0)
9053			reply_len = -1;
9054	} else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) {
9055		if (hs20_icon_request(wpa_s, buf + 14, 1) < 0)
9056			reply_len = -1;
9057	} else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) {
9058		reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size);
9059	} else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) {
9060		if (del_hs20_icon(wpa_s, buf + 14) < 0)
9061			reply_len = -1;
9062	} else if (os_strcmp(buf, "FETCH_OSU") == 0) {
9063		if (hs20_fetch_osu(wpa_s, 0) < 0)
9064			reply_len = -1;
9065	} else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
9066		if (hs20_fetch_osu(wpa_s, 1) < 0)
9067			reply_len = -1;
9068	} else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
9069		hs20_cancel_fetch_osu(wpa_s);
9070#endif /* CONFIG_HS20 */
9071	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
9072	{
9073		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
9074			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
9075			reply_len = -1;
9076		else {
9077			/*
9078			 * Notify response from timeout to allow the control
9079			 * interface response to be sent first.
9080			 */
9081			eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
9082					       wpa_s, NULL);
9083		}
9084	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
9085		if (wpa_supplicant_reload_configuration(wpa_s))
9086			reply_len = -1;
9087	} else if (os_strcmp(buf, "TERMINATE") == 0) {
9088		wpa_supplicant_terminate_proc(wpa_s->global);
9089	} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
9090		if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
9091			reply_len = -1;
9092	} else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
9093		reply_len = wpa_supplicant_ctrl_iface_blacklist(
9094			wpa_s, buf + 9, reply, reply_size);
9095	} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
9096		reply_len = wpa_supplicant_ctrl_iface_log_level(
9097			wpa_s, buf + 9, reply, reply_size);
9098	} else if (os_strncmp(buf, "LIST_NETWORKS ", 14) == 0) {
9099		reply_len = wpa_supplicant_ctrl_iface_list_networks(
9100			wpa_s, buf + 14, reply, reply_size);
9101	} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
9102		reply_len = wpa_supplicant_ctrl_iface_list_networks(
9103			wpa_s, NULL, reply, reply_size);
9104	} else if (os_strcmp(buf, "DISCONNECT") == 0) {
9105		wpas_request_disconnection(wpa_s);
9106	} else if (os_strcmp(buf, "SCAN") == 0) {
9107		wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
9108	} else if (os_strncmp(buf, "SCAN ", 5) == 0) {
9109		wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
9110	} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
9111		reply_len = wpa_supplicant_ctrl_iface_scan_results(
9112			wpa_s, reply, reply_size);
9113	} else if (os_strcmp(buf, "ABORT_SCAN") == 0) {
9114		if (wpas_abort_ongoing_scan(wpa_s) < 0)
9115			reply_len = -1;
9116	} else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
9117		if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
9118			reply_len = -1;
9119	} else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
9120		if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
9121			reply_len = -1;
9122	} else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
9123		if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
9124			reply_len = -1;
9125	} else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
9126		reply_len = wpa_supplicant_ctrl_iface_add_network(
9127			wpa_s, reply, reply_size);
9128	} else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
9129		if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
9130			reply_len = -1;
9131	} else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
9132		if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
9133			reply_len = -1;
9134	} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
9135		reply_len = wpa_supplicant_ctrl_iface_get_network(
9136			wpa_s, buf + 12, reply, reply_size);
9137	} else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
9138		if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12,
9139							  wpa_s))
9140			reply_len = -1;
9141	} else if (os_strcmp(buf, "LIST_CREDS") == 0) {
9142		reply_len = wpa_supplicant_ctrl_iface_list_creds(
9143			wpa_s, reply, reply_size);
9144	} else if (os_strcmp(buf, "ADD_CRED") == 0) {
9145		reply_len = wpa_supplicant_ctrl_iface_add_cred(
9146			wpa_s, reply, reply_size);
9147	} else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
9148		if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
9149			reply_len = -1;
9150	} else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
9151		if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
9152			reply_len = -1;
9153	} else if (os_strncmp(buf, "GET_CRED ", 9) == 0) {
9154		reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9,
9155							       reply,
9156							       reply_size);
9157#ifndef CONFIG_NO_CONFIG_WRITE
9158	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
9159		if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
9160			reply_len = -1;
9161#endif /* CONFIG_NO_CONFIG_WRITE */
9162	} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
9163		reply_len = wpa_supplicant_ctrl_iface_get_capability(
9164			wpa_s, buf + 15, reply, reply_size);
9165	} else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
9166		if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
9167			reply_len = -1;
9168	} else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
9169		if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
9170			reply_len = -1;
9171	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
9172		reply_len = wpa_supplicant_global_iface_list(
9173			wpa_s->global, reply, reply_size);
9174	} else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
9175		reply_len = wpa_supplicant_global_iface_interfaces(
9176			wpa_s->global, buf + 10, reply, reply_size);
9177	} else if (os_strncmp(buf, "BSS ", 4) == 0) {
9178		reply_len = wpa_supplicant_ctrl_iface_bss(
9179			wpa_s, buf + 4, reply, reply_size);
9180#ifdef CONFIG_AP
9181	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
9182		reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
9183	} else if (os_strncmp(buf, "STA ", 4) == 0) {
9184		reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
9185					      reply_size);
9186	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
9187		reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
9188						   reply_size);
9189	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
9190		if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
9191			reply_len = -1;
9192	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
9193		if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
9194			reply_len = -1;
9195	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
9196		if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
9197			reply_len = -1;
9198	} else if (os_strcmp(buf, "STOP_AP") == 0) {
9199		if (wpas_ap_stop_ap(wpa_s))
9200			reply_len = -1;
9201#endif /* CONFIG_AP */
9202	} else if (os_strcmp(buf, "SUSPEND") == 0) {
9203		wpas_notify_suspend(wpa_s->global);
9204	} else if (os_strcmp(buf, "RESUME") == 0) {
9205		wpas_notify_resume(wpa_s->global);
9206#ifdef CONFIG_TESTING_OPTIONS
9207	} else if (os_strcmp(buf, "DROP_SA") == 0) {
9208		wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
9209#endif /* CONFIG_TESTING_OPTIONS */
9210	} else if (os_strncmp(buf, "ROAM ", 5) == 0) {
9211		if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
9212			reply_len = -1;
9213	} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
9214		wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0;
9215	} else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
9216		if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
9217			reply_len = -1;
9218	} else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
9219		if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
9220							       buf + 17))
9221			reply_len = -1;
9222	} else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
9223		wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10);
9224#ifdef CONFIG_TDLS
9225	} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
9226		if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
9227			reply_len = -1;
9228	} else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
9229		if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
9230			reply_len = -1;
9231	} else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
9232		if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
9233			reply_len = -1;
9234	} else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
9235		if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
9236							       buf + 17))
9237			reply_len = -1;
9238	} else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
9239		if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
9240								      buf + 24))
9241			reply_len = -1;
9242	} else if (os_strncmp(buf, "TDLS_LINK_STATUS ", 17) == 0) {
9243		reply_len = wpa_supplicant_ctrl_iface_tdls_link_status(
9244			wpa_s, buf + 17, reply, reply_size);
9245#endif /* CONFIG_TDLS */
9246	} else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
9247		reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
9248	} else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) {
9249		if (wmm_ac_ctrl_addts(wpa_s, buf + 13))
9250			reply_len = -1;
9251	} else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) {
9252		if (wmm_ac_ctrl_delts(wpa_s, buf + 13))
9253			reply_len = -1;
9254	} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
9255		reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
9256						       reply_size);
9257	} else if (os_strncmp(buf, "SIGNAL_MONITOR", 14) == 0) {
9258		if (wpas_ctrl_iface_signal_monitor(wpa_s, buf + 14))
9259			reply_len = -1;
9260	} else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
9261		reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
9262						       reply_size);
9263#ifdef CONFIG_AUTOSCAN
9264	} else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
9265		if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
9266			reply_len = -1;
9267#endif /* CONFIG_AUTOSCAN */
9268	} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
9269		reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
9270							 reply_size);
9271#ifdef ANDROID
9272	} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
9273		reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
9274						      reply_size);
9275#endif /* ANDROID */
9276	} else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
9277		reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply,
9278						      reply_size);
9279	} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
9280		pmksa_cache_clear_current(wpa_s->wpa);
9281		eapol_sm_request_reauth(wpa_s->eapol);
9282#ifdef CONFIG_WNM
9283	} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
9284		if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
9285			reply_len = -1;
9286	} else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
9287		if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
9288				reply_len = -1;
9289#endif /* CONFIG_WNM */
9290	} else if (os_strcmp(buf, "FLUSH") == 0) {
9291		wpa_supplicant_ctrl_iface_flush(wpa_s);
9292	} else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
9293		reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
9294						 reply_size);
9295#ifdef CONFIG_TESTING_OPTIONS
9296	} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
9297		if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0)
9298			reply_len = -1;
9299	} else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
9300		wpas_ctrl_iface_mgmt_tx_done(wpa_s);
9301	} else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
9302		if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0)
9303			reply_len = -1;
9304	} else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
9305		if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
9306			reply_len = -1;
9307	} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
9308		if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
9309			reply_len = -1;
9310	} else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
9311		if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
9312			reply_len = -1;
9313	} else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
9314		if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0)
9315			reply_len = -1;
9316	} else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
9317		if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
9318			reply_len = -1;
9319	} else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
9320		if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
9321			reply_len = -1;
9322	} else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
9323		reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
9324	} else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
9325		if (wpas_ctrl_test_fail(wpa_s, buf + 10) < 0)
9326			reply_len = -1;
9327	} else if (os_strcmp(buf, "GET_FAIL") == 0) {
9328		reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);
9329	} else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
9330		if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
9331			reply_len = -1;
9332	} else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
9333		if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
9334			reply_len = -1;
9335#endif /* CONFIG_TESTING_OPTIONS */
9336	} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
9337		if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
9338			reply_len = -1;
9339	} else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) {
9340		reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply,
9341						      reply_size);
9342	} else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) {
9343		if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
9344			reply_len = -1;
9345	} else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
9346		if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
9347			reply_len = -1;
9348	} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
9349		wpas_ctrl_iface_erp_flush(wpa_s);
9350	} else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
9351		if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
9352			reply_len = -1;
9353	} else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) {
9354		reply_len = wpas_ctrl_iface_get_pref_freq_list(
9355			wpa_s, buf + 19, reply, reply_size);
9356	} else {
9357		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
9358		reply_len = 16;
9359	}
9360
9361	if (reply_len < 0) {
9362		os_memcpy(reply, "FAIL\n", 5);
9363		reply_len = 5;
9364	}
9365
9366	*resp_len = reply_len;
9367	return reply;
9368}
9369
9370
9371static int wpa_supplicant_global_iface_add(struct wpa_global *global,
9372					   char *cmd)
9373{
9374	struct wpa_interface iface;
9375	char *pos, *extra;
9376	struct wpa_supplicant *wpa_s;
9377	unsigned int create_iface = 0;
9378	u8 mac_addr[ETH_ALEN];
9379	enum wpa_driver_if_type type = WPA_IF_STATION;
9380
9381	/*
9382	 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
9383	 * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]]
9384	 */
9385	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
9386
9387	os_memset(&iface, 0, sizeof(iface));
9388
9389	do {
9390		iface.ifname = pos = cmd;
9391		pos = os_strchr(pos, '\t');
9392		if (pos)
9393			*pos++ = '\0';
9394		if (iface.ifname[0] == '\0')
9395			return -1;
9396		if (pos == NULL)
9397			break;
9398
9399		iface.confname = pos;
9400		pos = os_strchr(pos, '\t');
9401		if (pos)
9402			*pos++ = '\0';
9403		if (iface.confname[0] == '\0')
9404			iface.confname = NULL;
9405		if (pos == NULL)
9406			break;
9407
9408		iface.driver = pos;
9409		pos = os_strchr(pos, '\t');
9410		if (pos)
9411			*pos++ = '\0';
9412		if (iface.driver[0] == '\0')
9413			iface.driver = NULL;
9414		if (pos == NULL)
9415			break;
9416
9417		iface.ctrl_interface = pos;
9418		pos = os_strchr(pos, '\t');
9419		if (pos)
9420			*pos++ = '\0';
9421		if (iface.ctrl_interface[0] == '\0')
9422			iface.ctrl_interface = NULL;
9423		if (pos == NULL)
9424			break;
9425
9426		iface.driver_param = pos;
9427		pos = os_strchr(pos, '\t');
9428		if (pos)
9429			*pos++ = '\0';
9430		if (iface.driver_param[0] == '\0')
9431			iface.driver_param = NULL;
9432		if (pos == NULL)
9433			break;
9434
9435		iface.bridge_ifname = pos;
9436		pos = os_strchr(pos, '\t');
9437		if (pos)
9438			*pos++ = '\0';
9439		if (iface.bridge_ifname[0] == '\0')
9440			iface.bridge_ifname = NULL;
9441		if (pos == NULL)
9442			break;
9443
9444		extra = pos;
9445		pos = os_strchr(pos, '\t');
9446		if (pos)
9447			*pos++ = '\0';
9448		if (!extra[0])
9449			break;
9450
9451		if (os_strcmp(extra, "create") == 0) {
9452			create_iface = 1;
9453			if (!pos)
9454				break;
9455
9456			if (os_strcmp(pos, "sta") == 0) {
9457				type = WPA_IF_STATION;
9458			} else if (os_strcmp(pos, "ap") == 0) {
9459				type = WPA_IF_AP_BSS;
9460			} else {
9461				wpa_printf(MSG_DEBUG,
9462					   "INTERFACE_ADD unsupported interface type: '%s'",
9463					   pos);
9464				return -1;
9465			}
9466		} else {
9467			wpa_printf(MSG_DEBUG,
9468				   "INTERFACE_ADD unsupported extra parameter: '%s'",
9469				   extra);
9470			return -1;
9471		}
9472	} while (0);
9473
9474	if (create_iface) {
9475		wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'",
9476			   iface.ifname);
9477		if (!global->ifaces)
9478			return -1;
9479		if (wpa_drv_if_add(global->ifaces, type, iface.ifname,
9480				   NULL, NULL, NULL, mac_addr, NULL) < 0) {
9481			wpa_printf(MSG_ERROR,
9482				   "CTRL_IFACE interface creation failed");
9483			return -1;
9484		}
9485
9486		wpa_printf(MSG_DEBUG,
9487			   "CTRL_IFACE interface '%s' created with MAC addr: "
9488			   MACSTR, iface.ifname, MAC2STR(mac_addr));
9489	}
9490
9491	if (wpa_supplicant_get_iface(global, iface.ifname))
9492		goto fail;
9493
9494	wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
9495	if (!wpa_s)
9496		goto fail;
9497	wpa_s->added_vif = create_iface;
9498	return 0;
9499
9500fail:
9501	if (create_iface)
9502		wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname);
9503	return -1;
9504}
9505
9506
9507static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
9508					      char *cmd)
9509{
9510	struct wpa_supplicant *wpa_s;
9511	int ret;
9512	unsigned int delete_iface;
9513
9514	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
9515
9516	wpa_s = wpa_supplicant_get_iface(global, cmd);
9517	if (wpa_s == NULL)
9518		return -1;
9519	delete_iface = wpa_s->added_vif;
9520	ret = wpa_supplicant_remove_iface(global, wpa_s, 0);
9521	if (!ret && delete_iface) {
9522		wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'",
9523			   cmd);
9524		ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd);
9525	}
9526	return ret;
9527}
9528
9529
9530static void wpa_free_iface_info(struct wpa_interface_info *iface)
9531{
9532	struct wpa_interface_info *prev;
9533
9534	while (iface) {
9535		prev = iface;
9536		iface = iface->next;
9537
9538		os_free(prev->ifname);
9539		os_free(prev->desc);
9540		os_free(prev);
9541	}
9542}
9543
9544
9545static int wpa_supplicant_global_iface_list(struct wpa_global *global,
9546					    char *buf, int len)
9547{
9548	int i, res;
9549	struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
9550	char *pos, *end;
9551
9552	for (i = 0; wpa_drivers[i]; i++) {
9553		const struct wpa_driver_ops *drv = wpa_drivers[i];
9554		if (drv->get_interfaces == NULL)
9555			continue;
9556		tmp = drv->get_interfaces(global->drv_priv[i]);
9557		if (tmp == NULL)
9558			continue;
9559
9560		if (last == NULL)
9561			iface = last = tmp;
9562		else
9563			last->next = tmp;
9564		while (last->next)
9565			last = last->next;
9566	}
9567
9568	pos = buf;
9569	end = buf + len;
9570	for (tmp = iface; tmp; tmp = tmp->next) {
9571		res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
9572				  tmp->drv_name, tmp->ifname,
9573				  tmp->desc ? tmp->desc : "");
9574		if (os_snprintf_error(end - pos, res)) {
9575			*pos = '\0';
9576			break;
9577		}
9578		pos += res;
9579	}
9580
9581	wpa_free_iface_info(iface);
9582
9583	return pos - buf;
9584}
9585
9586
9587static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
9588						  const char *input,
9589						  char *buf, int len)
9590{
9591	int res;
9592	char *pos, *end;
9593	struct wpa_supplicant *wpa_s;
9594	int show_ctrl = 0;
9595
9596	if (input)
9597		show_ctrl = !!os_strstr(input, "ctrl");
9598
9599	wpa_s = global->ifaces;
9600	pos = buf;
9601	end = buf + len;
9602
9603	while (wpa_s) {
9604		if (show_ctrl)
9605			res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n",
9606					  wpa_s->ifname,
9607					  wpa_s->conf->ctrl_interface ?
9608					  wpa_s->conf->ctrl_interface : "N/A");
9609		else
9610			res = os_snprintf(pos, end - pos, "%s\n",
9611					  wpa_s->ifname);
9612
9613		if (os_snprintf_error(end - pos, res)) {
9614			*pos = '\0';
9615			break;
9616		}
9617		pos += res;
9618		wpa_s = wpa_s->next;
9619	}
9620	return pos - buf;
9621}
9622
9623
9624static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global,
9625					    const char *ifname,
9626					    char *cmd, size_t *resp_len)
9627{
9628	struct wpa_supplicant *wpa_s;
9629
9630	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
9631		if (os_strcmp(ifname, wpa_s->ifname) == 0)
9632			break;
9633	}
9634
9635	if (wpa_s == NULL) {
9636		char *resp = os_strdup("FAIL-NO-IFNAME-MATCH\n");
9637		if (resp)
9638			*resp_len = os_strlen(resp);
9639		else
9640			*resp_len = 1;
9641		return resp;
9642	}
9643
9644	return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len);
9645}
9646
9647
9648static char * wpas_global_ctrl_iface_redir_p2p(struct wpa_global *global,
9649					       char *buf, size_t *resp_len)
9650{
9651#ifdef CONFIG_P2P
9652	static const char * cmd[] = {
9653		"LIST_NETWORKS",
9654		"P2P_FIND",
9655		"P2P_STOP_FIND",
9656		"P2P_LISTEN",
9657		"P2P_GROUP_ADD",
9658		"P2P_GET_PASSPHRASE",
9659		"P2P_SERVICE_UPDATE",
9660		"P2P_SERVICE_FLUSH",
9661		"P2P_FLUSH",
9662		"P2P_CANCEL",
9663		"P2P_PRESENCE_REQ",
9664		"P2P_EXT_LISTEN",
9665		NULL
9666	};
9667	static const char * prefix[] = {
9668#ifdef ANDROID
9669		"DRIVER ",
9670#endif /* ANDROID */
9671		"GET_NETWORK ",
9672		"REMOVE_NETWORK ",
9673		"P2P_FIND ",
9674		"P2P_CONNECT ",
9675		"P2P_LISTEN ",
9676		"P2P_GROUP_REMOVE ",
9677		"P2P_GROUP_ADD ",
9678		"P2P_GROUP_MEMBER ",
9679		"P2P_PROV_DISC ",
9680		"P2P_SERV_DISC_REQ ",
9681		"P2P_SERV_DISC_CANCEL_REQ ",
9682		"P2P_SERV_DISC_RESP ",
9683		"P2P_SERV_DISC_EXTERNAL ",
9684		"P2P_SERVICE_ADD ",
9685		"P2P_SERVICE_DEL ",
9686		"P2P_SERVICE_REP ",
9687		"P2P_REJECT ",
9688		"P2P_INVITE ",
9689		"P2P_PEER ",
9690		"P2P_SET ",
9691		"P2P_UNAUTHORIZE ",
9692		"P2P_PRESENCE_REQ ",
9693		"P2P_EXT_LISTEN ",
9694		"P2P_REMOVE_CLIENT ",
9695		"WPS_NFC_TOKEN ",
9696		"WPS_NFC_TAG_READ ",
9697		"NFC_GET_HANDOVER_SEL ",
9698		"NFC_GET_HANDOVER_REQ ",
9699		"NFC_REPORT_HANDOVER ",
9700		"P2P_ASP_PROVISION ",
9701		"P2P_ASP_PROVISION_RESP ",
9702		NULL
9703	};
9704	int found = 0;
9705	int i;
9706
9707	if (global->p2p_init_wpa_s == NULL)
9708		return NULL;
9709
9710	for (i = 0; !found && cmd[i]; i++) {
9711		if (os_strcmp(buf, cmd[i]) == 0)
9712			found = 1;
9713	}
9714
9715	for (i = 0; !found && prefix[i]; i++) {
9716		if (os_strncmp(buf, prefix[i], os_strlen(prefix[i])) == 0)
9717			found = 1;
9718	}
9719
9720	if (found)
9721		return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
9722							 buf, resp_len);
9723#endif /* CONFIG_P2P */
9724	return NULL;
9725}
9726
9727
9728static char * wpas_global_ctrl_iface_redir_wfd(struct wpa_global *global,
9729					       char *buf, size_t *resp_len)
9730{
9731#ifdef CONFIG_WIFI_DISPLAY
9732	if (global->p2p_init_wpa_s == NULL)
9733		return NULL;
9734	if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0 ||
9735	    os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0)
9736		return wpa_supplicant_ctrl_iface_process(global->p2p_init_wpa_s,
9737							 buf, resp_len);
9738#endif /* CONFIG_WIFI_DISPLAY */
9739	return NULL;
9740}
9741
9742
9743static char * wpas_global_ctrl_iface_redir(struct wpa_global *global,
9744					   char *buf, size_t *resp_len)
9745{
9746	char *ret;
9747
9748	ret = wpas_global_ctrl_iface_redir_p2p(global, buf, resp_len);
9749	if (ret)
9750		return ret;
9751
9752	ret = wpas_global_ctrl_iface_redir_wfd(global, buf, resp_len);
9753	if (ret)
9754		return ret;
9755
9756	return NULL;
9757}
9758
9759
9760static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
9761{
9762	char *value;
9763
9764	value = os_strchr(cmd, ' ');
9765	if (value == NULL)
9766		return -1;
9767	*value++ = '\0';
9768
9769	wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
9770
9771#ifdef CONFIG_WIFI_DISPLAY
9772	if (os_strcasecmp(cmd, "wifi_display") == 0) {
9773		wifi_display_enable(global, !!atoi(value));
9774		return 0;
9775	}
9776#endif /* CONFIG_WIFI_DISPLAY */
9777
9778	/* Restore cmd to its original value to allow redirection */
9779	value[-1] = ' ';
9780
9781	return -1;
9782}
9783
9784
9785static int wpas_global_ctrl_iface_dup_network(struct wpa_global *global,
9786					      char *cmd)
9787{
9788	struct wpa_supplicant *wpa_s[2]; /* src, dst */
9789	char *p;
9790	unsigned int i;
9791
9792	/* cmd: "<src ifname> <dst ifname> <src network id> <dst network id>
9793	 * <variable name> */
9794
9795	for (i = 0; i < ARRAY_SIZE(wpa_s) ; i++) {
9796		p = os_strchr(cmd, ' ');
9797		if (p == NULL)
9798			return -1;
9799		*p = '\0';
9800
9801		wpa_s[i] = global->ifaces;
9802		for (; wpa_s[i]; wpa_s[i] = wpa_s[i]->next) {
9803			if (os_strcmp(cmd, wpa_s[i]->ifname) == 0)
9804				break;
9805		}
9806
9807		if (!wpa_s[i]) {
9808			wpa_printf(MSG_DEBUG,
9809				   "CTRL_IFACE: Could not find iface=%s", cmd);
9810			return -1;
9811		}
9812
9813		cmd = p + 1;
9814	}
9815
9816	return wpa_supplicant_ctrl_iface_dup_network(wpa_s[0], cmd, wpa_s[1]);
9817}
9818
9819
9820#ifndef CONFIG_NO_CONFIG_WRITE
9821static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
9822{
9823	int ret = 0, saved = 0;
9824	struct wpa_supplicant *wpa_s;
9825
9826	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
9827		if (!wpa_s->conf->update_config) {
9828			wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
9829			continue;
9830		}
9831
9832		if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
9833			wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
9834			ret = 1;
9835		} else {
9836			wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
9837			saved++;
9838		}
9839	}
9840
9841	if (!saved && !ret) {
9842		wpa_dbg(wpa_s, MSG_DEBUG,
9843			"CTRL_IFACE: SAVE_CONFIG - No configuration files could be updated");
9844		ret = 1;
9845	}
9846
9847	return ret;
9848}
9849#endif /* CONFIG_NO_CONFIG_WRITE */
9850
9851
9852static int wpas_global_ctrl_iface_status(struct wpa_global *global,
9853					 char *buf, size_t buflen)
9854{
9855	char *pos, *end;
9856	int ret;
9857	struct wpa_supplicant *wpa_s;
9858
9859	pos = buf;
9860	end = buf + buflen;
9861
9862#ifdef CONFIG_P2P
9863	if (global->p2p && !global->p2p_disabled) {
9864		ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
9865				  "\n"
9866				  "p2p_state=%s\n",
9867				  MAC2STR(global->p2p_dev_addr),
9868				  p2p_get_state_txt(global->p2p));
9869		if (os_snprintf_error(end - pos, ret))
9870			return pos - buf;
9871		pos += ret;
9872	} else if (global->p2p) {
9873		ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
9874		if (os_snprintf_error(end - pos, ret))
9875			return pos - buf;
9876		pos += ret;
9877	}
9878#endif /* CONFIG_P2P */
9879
9880#ifdef CONFIG_WIFI_DISPLAY
9881	ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
9882			  !!global->wifi_display);
9883	if (os_snprintf_error(end - pos, ret))
9884		return pos - buf;
9885	pos += ret;
9886#endif /* CONFIG_WIFI_DISPLAY */
9887
9888	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
9889		ret = os_snprintf(pos, end - pos, "ifname=%s\n"
9890				  "address=" MACSTR "\n",
9891				  wpa_s->ifname, MAC2STR(wpa_s->own_addr));
9892		if (os_snprintf_error(end - pos, ret))
9893			return pos - buf;
9894		pos += ret;
9895	}
9896
9897	return pos - buf;
9898}
9899
9900
9901#ifdef CONFIG_FST
9902
9903static int wpas_global_ctrl_iface_fst_attach(struct wpa_global *global,
9904					     char *cmd, char *buf,
9905					     size_t reply_size)
9906{
9907	char ifname[IFNAMSIZ + 1];
9908	struct fst_iface_cfg cfg;
9909	struct wpa_supplicant *wpa_s;
9910	struct fst_wpa_obj iface_obj;
9911
9912	if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
9913		wpa_s = wpa_supplicant_get_iface(global, ifname);
9914		if (wpa_s) {
9915			if (wpa_s->fst) {
9916				wpa_printf(MSG_INFO, "FST: Already attached");
9917				return -1;
9918			}
9919			fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
9920			wpa_s->fst = fst_attach(ifname, wpa_s->own_addr,
9921						&iface_obj, &cfg);
9922			if (wpa_s->fst)
9923				return os_snprintf(buf, reply_size, "OK\n");
9924		}
9925	}
9926
9927	return -1;
9928}
9929
9930
9931static int wpas_global_ctrl_iface_fst_detach(struct wpa_global *global,
9932					     char *cmd, char *buf,
9933					     size_t reply_size)
9934{
9935	char ifname[IFNAMSIZ + 1];
9936	struct wpa_supplicant *wpa_s;
9937
9938	if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
9939		wpa_s = wpa_supplicant_get_iface(global, ifname);
9940		if (wpa_s) {
9941			if (!fst_iface_detach(ifname)) {
9942				wpa_s->fst = NULL;
9943				return os_snprintf(buf, reply_size, "OK\n");
9944			}
9945		}
9946	}
9947
9948	return -1;
9949}
9950
9951#endif /* CONFIG_FST */
9952
9953
9954char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
9955						char *buf, size_t *resp_len)
9956{
9957	char *reply;
9958	const int reply_size = 2048;
9959	int reply_len;
9960	int level = MSG_DEBUG;
9961
9962	if (os_strncmp(buf, "IFNAME=", 7) == 0) {
9963		char *pos = os_strchr(buf + 7, ' ');
9964		if (pos) {
9965			*pos++ = '\0';
9966			return wpas_global_ctrl_iface_ifname(global,
9967							     buf + 7, pos,
9968							     resp_len);
9969		}
9970	}
9971
9972	reply = wpas_global_ctrl_iface_redir(global, buf, resp_len);
9973	if (reply)
9974		return reply;
9975
9976	if (os_strcmp(buf, "PING") == 0)
9977		level = MSG_EXCESSIVE;
9978	wpa_hexdump_ascii(level, "RX global ctrl_iface",
9979			  (const u8 *) buf, os_strlen(buf));
9980
9981	reply = os_malloc(reply_size);
9982	if (reply == NULL) {
9983		*resp_len = 1;
9984		return NULL;
9985	}
9986
9987	os_memcpy(reply, "OK\n", 3);
9988	reply_len = 3;
9989
9990	if (os_strcmp(buf, "PING") == 0) {
9991		os_memcpy(reply, "PONG\n", 5);
9992		reply_len = 5;
9993	} else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
9994		if (wpa_supplicant_global_iface_add(global, buf + 14))
9995			reply_len = -1;
9996	} else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
9997		if (wpa_supplicant_global_iface_remove(global, buf + 17))
9998			reply_len = -1;
9999	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
10000		reply_len = wpa_supplicant_global_iface_list(
10001			global, reply, reply_size);
10002	} else if (os_strncmp(buf, "INTERFACES", 10) == 0) {
10003		reply_len = wpa_supplicant_global_iface_interfaces(
10004			global, buf + 10, reply, reply_size);
10005#ifdef CONFIG_FST
10006	} else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
10007		reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11,
10008							      reply,
10009							      reply_size);
10010	} else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
10011		reply_len = wpas_global_ctrl_iface_fst_detach(global, buf + 11,
10012							      reply,
10013							      reply_size);
10014	} else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
10015		reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
10016#endif /* CONFIG_FST */
10017	} else if (os_strcmp(buf, "TERMINATE") == 0) {
10018		wpa_supplicant_terminate_proc(global);
10019	} else if (os_strcmp(buf, "SUSPEND") == 0) {
10020		wpas_notify_suspend(global);
10021	} else if (os_strcmp(buf, "RESUME") == 0) {
10022		wpas_notify_resume(global);
10023	} else if (os_strncmp(buf, "SET ", 4) == 0) {
10024		if (wpas_global_ctrl_iface_set(global, buf + 4)) {
10025#ifdef CONFIG_P2P
10026			if (global->p2p_init_wpa_s) {
10027				os_free(reply);
10028				/* Check if P2P redirection would work for this
10029				 * command. */
10030				return wpa_supplicant_ctrl_iface_process(
10031					global->p2p_init_wpa_s,
10032					buf, resp_len);
10033			}
10034#endif /* CONFIG_P2P */
10035			reply_len = -1;
10036		}
10037	} else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
10038		if (wpas_global_ctrl_iface_dup_network(global, buf + 12))
10039			reply_len = -1;
10040#ifndef CONFIG_NO_CONFIG_WRITE
10041	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
10042		if (wpas_global_ctrl_iface_save_config(global))
10043			reply_len = -1;
10044#endif /* CONFIG_NO_CONFIG_WRITE */
10045	} else if (os_strcmp(buf, "STATUS") == 0) {
10046		reply_len = wpas_global_ctrl_iface_status(global, reply,
10047							  reply_size);
10048#ifdef CONFIG_MODULE_TESTS
10049	} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
10050		if (wpas_module_tests() < 0)
10051			reply_len = -1;
10052#endif /* CONFIG_MODULE_TESTS */
10053	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
10054		if (wpa_debug_reopen_file() < 0)
10055			reply_len = -1;
10056	} else {
10057		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
10058		reply_len = 16;
10059	}
10060
10061	if (reply_len < 0) {
10062		os_memcpy(reply, "FAIL\n", 5);
10063		reply_len = 5;
10064	}
10065
10066	*resp_len = reply_len;
10067	return reply;
10068}
10069