diff options
Diffstat (limited to 'wpa_supplicant/ctrl_iface.c')
| -rw-r--r-- | wpa_supplicant/ctrl_iface.c | 751 | 
1 files changed, 619 insertions, 132 deletions
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index b4aefb65ec25..3b97806d871d 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -28,6 +28,8 @@  #include "rsn_supp/pmksa_cache.h"  #include "l2_packet/l2_packet.h"  #include "wps/wps.h" +#include "fst/fst.h" +#include "fst/fst_ctrl_iface.h"  #include "config.h"  #include "wpa_supplicant_i.h"  #include "driver_i.h" @@ -153,7 +155,8 @@ static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)  			}  			ssid = ns; -			if ((end - pos) & 0x01 || end - pos > 2 * 32 || +			if ((end - pos) & 0x01 || +			    end - pos > 2 * SSID_MAX_LEN ||  			    hexstr2bin(pos, ssid[ssid_count].ssid,  				       (end - pos) / 2) < 0) {  				os_free(ssid); @@ -283,6 +286,30 @@ static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)  } +static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band) +{ +	union wpa_event_data event; + +	if (os_strcmp(band, "AUTO") == 0) +		wpa_s->setband = WPA_SETBAND_AUTO; +	else if (os_strcmp(band, "5G") == 0) +		wpa_s->setband = WPA_SETBAND_5G; +	else if (os_strcmp(band, "2G") == 0) +		wpa_s->setband = WPA_SETBAND_2G; +	else +		return -1; + +	if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) { +		os_memset(&event, 0, sizeof(event)); +		event.channel_list_changed.initiator = REGDOM_SET_BY_USER; +		event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; +		wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event); +	} + +	return 0; +} + +  static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,  					 char *cmd)  { @@ -446,14 +473,7 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,  		ret = wpas_ctrl_set_blob(wpa_s, value);  #endif /* CONFIG_NO_CONFIG_BLOBS */  	} else if (os_strcasecmp(cmd, "setband") == 0) { -		if (os_strcmp(value, "AUTO") == 0) -			wpa_s->setband = WPA_SETBAND_AUTO; -		else if (os_strcmp(value, "5G") == 0) -			wpa_s->setband = WPA_SETBAND_5G; -		else if (os_strcmp(value, "2G") == 0) -			wpa_s->setband = WPA_SETBAND_2G; -		else -			ret = -1; +		ret = wpas_ctrl_set_band(wpa_s, value);  	} else {  		value[-1] = '=';  		ret = wpa_config_process_global(wpa_s->conf, cmd, -1); @@ -759,6 +779,33 @@ static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(  	return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);  } + +static int wpa_supplicant_ctrl_iface_tdls_link_status( +	struct wpa_supplicant *wpa_s, const char *addr, +	char *buf, size_t buflen) +{ +	u8 peer[ETH_ALEN]; +	const char *tdls_status; +	int ret; + +	if (hwaddr_aton(addr, peer)) { +		wpa_printf(MSG_DEBUG, +			   "CTRL_IFACE TDLS_LINK_STATUS: Invalid address '%s'", +			   addr); +		return -1; +	} +	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS " MACSTR, +		   MAC2STR(peer)); + +	tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer); +	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_LINK_STATUS: %s", tdls_status); +	ret = os_snprintf(buf, buflen, "TDLS link status: %s\n", tdls_status); +	if (os_snprintf_error(buflen, ret)) +		return -1; + +	return ret; +} +  #endif /* CONFIG_TDLS */ @@ -1728,7 +1775,7 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,  		if (ssid) {  			u8 *_ssid = ssid->ssid;  			size_t ssid_len = ssid->ssid_len; -			u8 ssid_buf[MAX_SSID_LEN]; +			u8 ssid_buf[SSID_MAX_LEN];  			if (ssid_len == 0) {  				int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);  				if (_res < 0) @@ -2089,45 +2136,6 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,  } -static const char * debug_level_str(int level) -{ -	switch (level) { -	case MSG_EXCESSIVE: -		return "EXCESSIVE"; -	case MSG_MSGDUMP: -		return "MSGDUMP"; -	case MSG_DEBUG: -		return "DEBUG"; -	case MSG_INFO: -		return "INFO"; -	case MSG_WARNING: -		return "WARNING"; -	case MSG_ERROR: -		return "ERROR"; -	default: -		return "?"; -	} -} - - -static int str_to_debug_level(const char *s) -{ -	if (os_strcasecmp(s, "EXCESSIVE") == 0) -		return MSG_EXCESSIVE; -	if (os_strcasecmp(s, "MSGDUMP") == 0) -		return MSG_MSGDUMP; -	if (os_strcasecmp(s, "DEBUG") == 0) -		return MSG_DEBUG; -	if (os_strcasecmp(s, "INFO") == 0) -		return MSG_INFO; -	if (os_strcasecmp(s, "WARNING") == 0) -		return MSG_WARNING; -	if (os_strcasecmp(s, "ERROR") == 0) -		return MSG_ERROR; -	return -1; -} - -  static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,  					       char *cmd, char *buf,  					       size_t buflen) @@ -2160,7 +2168,7 @@ static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,  		}  	} -	if (cmd && os_strlen(cmd)) { +	if (os_strlen(cmd)) {  		int level = str_to_debug_level(cmd);  		if (level < 0)  			return -1; @@ -2366,6 +2374,14 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,  	}  #endif /* CONFIG_SUITEB192 */ +	if (data.key_mgmt & WPA_KEY_MGMT_OSEN) { +		ret = os_snprintf(pos, end - pos, "%sOSEN", +				  pos == start ? "" : "+"); +		if (os_snprintf_error(end - pos, ret)) +			return pos; +		pos += ret; +	} +  	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);  	if (data.capabilities & WPA_CAPABILITY_PREAUTH) { @@ -2433,7 +2449,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(  {  	char *pos, *end;  	int ret; -	const u8 *ie, *ie2, *p2p, *mesh; +	const u8 *ie, *ie2, *osen_ie, *p2p, *mesh;  	mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);  	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); @@ -2460,8 +2476,12 @@ static int wpa_supplicant_ctrl_iface_scan_result(  		pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",  					    ie2, 2 + ie2[1]);  	} +	osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); +	if (osen_ie) +		pos = wpa_supplicant_ie_txt(pos, end, "OSEN", +					    osen_ie, 2 + osen_ie[1]);  	pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); -	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) { +	if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {  		ret = os_snprintf(pos, end - pos, "[WEP]");  		if (os_snprintf_error(end - pos, ret))  			return -1; @@ -2525,6 +2545,14 @@ static int wpa_supplicant_ctrl_iface_scan_result(  		pos += ret;  	}  #endif /* CONFIG_HS20 */ +#ifdef CONFIG_FST +	if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) { +		ret = os_snprintf(pos, end - pos, "[FST]"); +		if (os_snprintf_error(end - pos, ret)) +			return -1; +		pos += ret; +	} +#endif /* CONFIG_FST */  	ret = os_snprintf(pos, end - pos, "\t%s",  			  wpa_ssid_txt(bss->ssid, bss->ssid_len)); @@ -2716,6 +2744,8 @@ static int wpa_supplicant_ctrl_iface_select_network(  		}  	} +	wpa_s->scan_min_time.sec = 0; +	wpa_s->scan_min_time.usec = 0;  	wpa_supplicant_select_network(wpa_s, ssid);  	return 0; @@ -2753,6 +2783,8 @@ static int wpa_supplicant_ctrl_iface_enable_network(  			return 0;  		}  	} +	wpa_s->scan_min_time.sec = 0; +	wpa_s->scan_min_time.usec = 0;  	wpa_supplicant_enable_network(wpa_s, ssid);  	return 0; @@ -2836,7 +2868,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(  #endif /* CONFIG_SME */  			wpa_sm_set_config(wpa_s->wpa, NULL);  			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); -			wpa_s->own_disconnect_req = 1; +			if (wpa_s->wpa_state >= WPA_AUTHENTICATING) +				wpa_s->own_disconnect_req = 1;  			wpa_supplicant_deauthenticate(  				wpa_s, WLAN_REASON_DEAUTH_LEAVING);  		} @@ -2883,7 +2916,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(  		wpa_sm_set_config(wpa_s->wpa, NULL);  		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); -		wpa_s->own_disconnect_req = 1; +		if (wpa_s->wpa_state >= WPA_AUTHENTICATING) +			wpa_s->own_disconnect_req = 1;  		wpa_supplicant_deauthenticate(wpa_s,  					      WLAN_REASON_DEAUTH_LEAVING);  	} @@ -3005,19 +3039,19 @@ static int wpa_supplicant_ctrl_iface_get_network(  	*name++ = '\0';  	id = atoi(cmd); -	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'", +	wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",  		   id, name);  	ssid = wpa_config_get_network(wpa_s->conf, id);  	if (ssid == NULL) { -		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network " +		wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Could not find network "  			   "id=%d", id);  		return -1;  	}  	value = wpa_config_get_no_key(ssid, name);  	if (value == NULL) { -		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network " +		wpa_printf(MSG_EXCESSIVE, "CTRL_IFACE: Failed to get network "  			   "variable '%s'", name);  		return -1;  	} @@ -3035,7 +3069,8 @@ static int wpa_supplicant_ctrl_iface_get_network(  static int wpa_supplicant_ctrl_iface_dup_network( -	struct wpa_supplicant *wpa_s, char *cmd) +	struct wpa_supplicant *wpa_s, char *cmd, +	struct wpa_supplicant *dst_wpa_s)  {  	struct wpa_ssid *ssid_s, *ssid_d;  	char *name, *id, *value; @@ -3054,8 +3089,10 @@ static int wpa_supplicant_ctrl_iface_dup_network(  	id_s = atoi(cmd);  	id_d = atoi(id); -	wpa_printf(MSG_DEBUG, "CTRL_IFACE: DUP_NETWORK id=%d -> %d name='%s'", -		   id_s, id_d, name); + +	wpa_printf(MSG_DEBUG, +		   "CTRL_IFACE: DUP_NETWORK ifname=%s->%s id=%d->%d name='%s'", +		   wpa_s->ifname, dst_wpa_s->ifname, id_s, id_d, name);  	ssid_s = wpa_config_get_network(wpa_s->conf, id_s);  	if (ssid_s == NULL) { @@ -3064,7 +3101,7 @@ static int wpa_supplicant_ctrl_iface_dup_network(  		return -1;  	} -	ssid_d = wpa_config_get_network(wpa_s->conf, id_d); +	ssid_d = wpa_config_get_network(dst_wpa_s->conf, id_d);  	if (ssid_d == NULL) {  		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "  			   "network id=%d", id_d); @@ -3078,7 +3115,7 @@ static int wpa_supplicant_ctrl_iface_dup_network(  		return -1;  	} -	ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid_d, name, +	ret = wpa_supplicant_ctrl_iface_update_network(dst_wpa_s, ssid_d, name,  						       value);  	os_free(value); @@ -3889,6 +3926,15 @@ static int wpa_supplicant_ctrl_iface_get_capability(  	}  #endif /* CONFIG_EPR */ +#ifdef CONFIG_FIPS +	if (os_strcmp(field, "fips") == 0) { +		res = os_snprintf(buf, buflen, "FIPS"); +		if (os_snprintf_error(buflen, res)) +			return -1; +		return res; +	} +#endif /* CONFIG_FIPS */ +  	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",  		   field); @@ -3937,7 +3983,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,  	size_t i;  	int ret;  	char *pos, *end; -	const u8 *ie, *ie2; +	const u8 *ie, *ie2, *osen_ie;  	pos = buf;  	end = buf + buflen; @@ -4054,8 +4100,13 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,  		if (ie2)  			pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,  						    2 + ie2[1]); +		osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); +		if (osen_ie) +			pos = wpa_supplicant_ie_txt(pos, end, "OSEN", +						    osen_ie, 2 + osen_ie[1]);  		pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); -		if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) { +		if (!ie && !ie2 && !osen_ie && +		    (bss->caps & IEEE80211_CAP_PRIVACY)) {  			ret = os_snprintf(pos, end - pos, "[WEP]");  			if (os_snprintf_error(end - pos, ret))  				return 0; @@ -4133,9 +4184,10 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,  	if (mask & WPA_BSS_MASK_WPS_SCAN) {  		ie = (const u8 *) (bss + 1);  		ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end); -		if (ret < 0 || ret >= end - pos) +		if (ret >= end - pos)  			return 0; -		pos += ret; +		if (ret > 0) +			pos += ret;  	}  #endif /* CONFIG_WPS */ @@ -4236,6 +4288,15 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,  		pos += ret;  	} +#ifdef CONFIG_FST +	if (mask & WPA_BSS_MASK_FST) { +		ret = fst_ctrl_iface_mb_info(bss->bssid, pos, end - pos); +		if (ret < 0 || ret >= end - pos) +			return 0; +		pos += ret; +	} +#endif /* CONFIG_FST */ +  	if (mask & WPA_BSS_MASK_DELIM) {  		ret = os_snprintf(pos, end - pos, "====\n");  		if (os_snprintf_error(end - pos, ret)) @@ -4548,37 +4609,83 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)  	} else  		search_delay = wpas_p2p_search_delay(wpa_s); +	pos = os_strstr(cmd, "freq="); +	if (pos) { +		pos += 5; +		freq = atoi(pos); +		if (freq <= 0) +			return -1; +	} +  	/* Must be searched for last, because it adds nul termination */  	pos = os_strstr(cmd, " seek="); +	if (pos) +		pos += 6;  	while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {  		char *term; -		term = os_strchr(pos + 1, ' '); -		_seek[seek_count++] = pos + 6; +		_seek[seek_count++] = pos;  		seek = _seek; -		pos = os_strstr(pos + 6, " seek="); - -		if (term) -			*term = '\0'; +		term = os_strchr(pos, ' '); +		if (!term) +			break; +		*term = '\0'; +		pos = os_strstr(term + 1, "seek="); +		if (pos) +			pos += 5;  	}  	if (seek_count > P2P_MAX_QUERY_HASH) {  		seek[0] = NULL;  		seek_count = 1;  	} -	pos = os_strstr(cmd, "freq="); -	if (pos) { -		pos += 5; -		freq = atoi(pos); -		if (freq <= 0) -			return -1; -	} -  	return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,  			     _dev_id, search_delay, seek_count, seek, freq);  } +static int p2ps_ctrl_parse_cpt_priority(const char *pos, u8 *cpt) +{ +	const char *last = NULL; +	const char *token; +	long int token_len; +	unsigned int i; + +	/* Expected predefined CPT names delimited by ':' */ +	for (i = 0; (token = cstr_token(pos, ": \t", &last)); i++) { +		if (i >= P2PS_FEATURE_CAPAB_CPT_MAX) { +			wpa_printf(MSG_ERROR, +				   "P2PS: CPT name list is too long, expected up to %d names", +				   P2PS_FEATURE_CAPAB_CPT_MAX); +			cpt[0] = 0; +			return -1; +		} + +		token_len = last - token; + +		if (token_len  == 3 && +		    os_memcmp(token, "UDP", token_len) == 0) { +			cpt[i] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT; +		} else if (token_len == 3 && +			   os_memcmp(token, "MAC", token_len) == 0) { +			cpt[i] = P2PS_FEATURE_CAPAB_MAC_TRANSPORT; +		} else { +			wpa_printf(MSG_ERROR, +				   "P2PS: Unsupported CPT name '%s'", token); +			cpt[0] = 0; +			return -1; +		} + +		if (isblank(*last)) { +			i++; +			break; +		} +	} +	cpt[i] = 0; +	return 0; +} + +  static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)  {  	struct p2ps_provision *p2ps_prov; @@ -4587,6 +4694,7 @@ static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)  	char *info = NULL;  	u8 role = P2PS_SETUP_NONE;  	long long unsigned val; +	int i;  	pos = os_strstr(cmd, "info=");  	if (pos) { @@ -4645,6 +4753,18 @@ static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)  	if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))  		goto invalid_args; +	pos = os_strstr(cmd, "cpt="); +	if (pos) { +		if (p2ps_ctrl_parse_cpt_priority(pos + 4, +						 p2ps_prov->cpt_priority)) +			goto invalid_args; +	} else { +		p2ps_prov->cpt_priority[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT; +	} + +	for (i = 0; p2ps_prov->cpt_priority[i]; i++) +		p2ps_prov->cpt_mask |= p2ps_prov->cpt_priority[i]; +  	/* force conncap with tstCap (no sanity checks) */  	pos = os_strstr(cmd, "tstCap=");  	if (pos) { @@ -4721,6 +4841,8 @@ static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)  	if (!p2ps_prov)  		return -1; +	p2ps_prov->pd_seeker = 1; +  	return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,  				  p2ps_prov);  } @@ -5140,6 +5262,8 @@ static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,  	char *adv_str;  	u32 auto_accept, adv_id, svc_state, config_methods;  	char *svc_info = NULL; +	char *cpt_prio_str; +	u8 cpt_prio[P2PS_FEATURE_CAPAB_CPT_MAX + 1];  	pos = os_strchr(cmd, ' ');  	if (pos == NULL) @@ -5212,6 +5336,19 @@ static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,  	if (pos != NULL)  		*pos++ = '\0'; +	cpt_prio_str = (pos && pos[0]) ? os_strstr(pos, "cpt=") : NULL; +	if (cpt_prio_str) { +		pos = os_strchr(pos, ' '); +		if (pos != NULL) +			*pos++ = '\0'; + +		if (p2ps_ctrl_parse_cpt_priority(cpt_prio_str + 4, cpt_prio)) +			return -1; +	} else { +		cpt_prio[0] = P2PS_FEATURE_CAPAB_UDP_TRANSPORT; +		cpt_prio[1] = 0; +	} +  	/* Service and Response Information are optional */  	if (pos && pos[0]) {  		size_t len; @@ -5229,7 +5366,7 @@ static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,  	return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,  					(u8) svc_state, (u16) config_methods, -					svc_info); +					svc_info, cpt_prio);  } @@ -5299,6 +5436,11 @@ static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)  {  	u32 adv_id; +	if (os_strcmp(cmd, "all") == 0) { +		wpas_p2p_service_flush_asp(wpa_s); +		return 0; +	} +  	if (sscanf(cmd, "%x", &adv_id) != 1)  		return -1; @@ -5449,13 +5591,10 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)  static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, -					 char *cmd, int freq, int ht40, -					 int vht) +					 int id, int freq, int ht40, int vht)  { -	int id;  	struct wpa_ssid *ssid; -	id = atoi(cmd);  	ssid = wpa_config_get_network(wpa_s->conf, id);  	if (ssid == NULL || ssid->disabled != 2) {  		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d " @@ -5465,37 +5604,41 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,  	}  	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht, -					     NULL, 0); +					     NULL, 0, 0);  }  static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)  { -	int freq = 0, ht40, vht; -	char *pos; +	int freq = 0, persistent = 0, group_id = -1; +	int vht = wpa_s->conf->p2p_go_vht; +	int ht40 = wpa_s->conf->p2p_go_ht40 || vht; +	char *token, *context = NULL; -	pos = os_strstr(cmd, "freq="); -	if (pos) -		freq = atoi(pos + 5); +	while ((token = str_token(cmd, " ", &context))) { +		if (sscanf(token, "freq=%d", &freq) == 1 || +		    sscanf(token, "persistent=%d", &group_id) == 1) { +			continue; +		} else if (os_strcmp(token, "ht40") == 0) { +			ht40 = 1; +		} else if (os_strcmp(token, "vht") == 0) { +			vht = 1; +			ht40 = 1; +		} else if (os_strcmp(token, "persistent") == 0) { +			persistent = 1; +		} else { +			wpa_printf(MSG_DEBUG, +				   "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'", +				   token); +			return -1; +		} +	} -	vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht; -	ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 || -		vht; +	if (group_id >= 0) +		return p2p_ctrl_group_add_persistent(wpa_s, group_id, +						     freq, ht40, vht); -	if (os_strncmp(cmd, "persistent=", 11) == 0) -		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq, -						     ht40, vht); -	if (os_strcmp(cmd, "persistent") == 0 || -	    os_strncmp(cmd, "persistent ", 11) == 0) -		return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht); -	if (os_strncmp(cmd, "freq=", 5) == 0) -		return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht); -	if (ht40) -		return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht); - -	wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'", -		   cmd); -	return -1; +	return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht);  } @@ -5625,7 +5768,7 @@ static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,  			   freq->min, freq->max);  	} -	wpas_p2p_update_channel_list(wpa_s); +	wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW);  	return 0;  } @@ -5842,6 +5985,7 @@ static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)  	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);  	wpa_s->force_long_sd = 0;  	wpas_p2p_stop_find(wpa_s); +	wpa_s->parent->p2ps_method_config_any = 0;  	if (wpa_s->global->p2p)  		p2p_flush(wpa_s->global->p2p);  } @@ -6476,6 +6620,61 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,  		pos += ret;  	} +	if (si.avg_beacon_signal) { +		ret = os_snprintf(pos, end - pos, +				  "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal); +		if (os_snprintf_error(end - pos, ret)) +			return -1; +		pos += ret; +	} + +	return pos - buf; +} + + +static int wpas_ctrl_iface_get_pref_freq_list( +	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) +{ +	unsigned int freq_list[100], num = 100, i; +	int ret; +	enum wpa_driver_if_type iface_type; +	char *pos, *end; + +	pos = buf; +	end = buf + buflen; + +	/* buf: "<interface_type>" */ +	if (os_strcmp(cmd, "STATION") == 0) +		iface_type = WPA_IF_STATION; +	else if (os_strcmp(cmd, "AP") == 0) +		iface_type = WPA_IF_AP_BSS; +	else if (os_strcmp(cmd, "P2P_GO") == 0) +		iface_type = WPA_IF_P2P_GO; +	else if (os_strcmp(cmd, "P2P_CLIENT") == 0) +		iface_type = WPA_IF_P2P_CLIENT; +	else if (os_strcmp(cmd, "IBSS") == 0) +		iface_type = WPA_IF_IBSS; +	else if (os_strcmp(cmd, "TDLS") == 0) +		iface_type = WPA_IF_TDLS; +	else +		return -1; + +	wpa_printf(MSG_DEBUG, +		   "CTRL_IFACE: GET_PREF_FREQ_LIST iface_type=%d (%s)", +		   iface_type, buf); + +	ret = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &num, freq_list); +	if (ret) +		return -1; + +	for (i = 0; i < num; i++) { +		ret = os_snprintf(pos, end - pos, "%s%u", +				  i > 0 ? "," : "", freq_list[i]); +		if (os_snprintf_error(end - pos, ret)) +			return -1; +		pos += ret; +	} +  	return pos - buf;  } @@ -6602,6 +6801,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)  	p2p_wpa_s->p2p_disable_ip_addr_req = 0;  	os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);  	p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL; +	p2p_wpa_s->global->p2p_go_avoid_freq.num = 0;  	p2p_wpa_s->global->pending_p2ps_group = 0;  #endif /* CONFIG_P2P */ @@ -6689,6 +6889,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)  			   MAC2STR(wpa_s->bssid),  			   MAC2STR(wpa_s->pending_bssid));  	} + +	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);  } @@ -6922,6 +7124,8 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,  	void (*scan_res_handler)(struct wpa_supplicant *wpa_s,  				 struct wpa_scan_results *scan_res);  	int *manual_scan_freqs = NULL; +	struct wpa_ssid_value *ssid = NULL, *ns; +	unsigned int ssid_count = 0;  	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {  		*reply_len = -1; @@ -6935,6 +7139,15 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,  		return;  	} +#ifdef CONFIG_INTERWORKING +	if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) { +		wpa_printf(MSG_DEBUG, +			   "Interworking select in progress - reject new scan"); +		*reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); +		return; +	} +#endif /* CONFIG_INTERWORKING */ +  	if (params) {  		if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)  			scan_only = 1; @@ -6967,6 +7180,60 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,  			*reply_len = -1;  			goto done;  		} + +		pos = params; +		while (pos && *pos != '\0') { +			if (os_strncmp(pos, "ssid ", 5) == 0) { +				char *end; + +				pos += 5; +				end = pos; +				while (*end) { +					if (*end == '\0' || *end == ' ') +						break; +					end++; +				} + +				ns = os_realloc_array( +					ssid, ssid_count + 1, +					sizeof(struct wpa_ssid_value)); +				if (ns == NULL) { +					*reply_len = -1; +					goto done; +				} +				ssid = ns; + +				if ((end - pos) & 0x01 || +				    end - pos > 2 * SSID_MAX_LEN || +				    hexstr2bin(pos, ssid[ssid_count].ssid, +					       (end - pos) / 2) < 0) { +					wpa_printf(MSG_DEBUG, +						   "Invalid SSID value '%s'", +						   pos); +					*reply_len = -1; +					goto done; +				} +				ssid[ssid_count].ssid_len = (end - pos) / 2; +				wpa_hexdump_ascii(MSG_DEBUG, "scan SSID", +						  ssid[ssid_count].ssid, +						  ssid[ssid_count].ssid_len); +				ssid_count++; +				pos = end; +			} + +			pos = os_strchr(pos, ' '); +			if (pos) +				pos++; +		} +	} + +	wpa_s->num_ssids_from_scan_req = ssid_count; +	os_free(wpa_s->ssids_from_scan_req); +	if (ssid_count) { +		wpa_s->ssids_from_scan_req = ssid; +		ssid = NULL; +	} else { +		wpa_s->ssids_from_scan_req = NULL;  	}  	if (scan_only) @@ -7030,6 +7297,7 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,  done:  	os_free(manual_scan_freqs); +	os_free(ssid);  } @@ -7231,7 +7499,7 @@ void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)  {  	struct wpa_supplicant *wpa_s = ctx;  	const struct ether_header *eth; -	const struct iphdr *ip; +	struct iphdr ip;  	const u8 *pos;  	unsigned int i; @@ -7239,14 +7507,14 @@ void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)  		return;  	eth = (const struct ether_header *) buf; -	ip = (const struct iphdr *) (eth + 1); -	pos = (const u8 *) (ip + 1); +	os_memcpy(&ip, eth + 1, sizeof(ip)); +	pos = &buf[sizeof(*eth) + sizeof(ip)]; -	if (ip->ihl != 5 || ip->version != 4 || -	    ntohs(ip->tot_len) != HWSIM_IP_LEN) +	if (ip.ihl != 5 || ip.version != 4 || +	    ntohs(ip.tot_len) != HWSIM_IP_LEN)  		return; -	for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) { +	for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {  		if (*pos != (u8) i)  			return;  		pos++; @@ -7293,7 +7561,7 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)  	int used;  	long int val;  	u8 tos; -	u8 buf[HWSIM_PACKETLEN]; +	u8 buf[2 + HWSIM_PACKETLEN];  	struct ether_header *eth;  	struct iphdr *ip;  	u8 *dpos; @@ -7321,7 +7589,7 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)  		return -1;  	tos = val; -	eth = (struct ether_header *) buf; +	eth = (struct ether_header *) &buf[2];  	os_memcpy(eth->ether_dhost, dst, ETH_ALEN);  	os_memcpy(eth->ether_shost, src, ETH_ALEN);  	eth->ether_type = htons(ETHERTYPE_IP); @@ -7333,14 +7601,14 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)  	ip->tos = tos;  	ip->tot_len = htons(HWSIM_IP_LEN);  	ip->protocol = 1; -	ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1); -	ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2); +	ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1); +	ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);  	ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));  	dpos = (u8 *) (ip + 1);  	for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)  		*dpos++ = i; -	if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, buf, +	if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],  			   HWSIM_PACKETLEN) < 0)  		return -1; @@ -7429,6 +7697,44 @@ static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,  #endif /* WPA_TRACE_BFD */  } + +static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd) +{ +#ifdef WPA_TRACE_BFD +	extern char wpa_trace_test_fail_func[256]; +	extern unsigned int wpa_trace_test_fail_after; +	char *pos; + +	wpa_trace_test_fail_after = atoi(cmd); +	pos = os_strchr(cmd, ':'); +	if (pos) { +		pos++; +		os_strlcpy(wpa_trace_test_fail_func, pos, +			   sizeof(wpa_trace_test_fail_func)); +	} else { +		wpa_trace_test_fail_after = 0; +	} +	return 0; +#else /* WPA_TRACE_BFD */ +	return -1; +#endif /* WPA_TRACE_BFD */ +} + + +static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s, +				    char *buf, size_t buflen) +{ +#ifdef WPA_TRACE_BFD +	extern char wpa_trace_test_fail_func[256]; +	extern unsigned int wpa_trace_test_fail_after; + +	return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after, +			   wpa_trace_test_fail_func); +#else /* WPA_TRACE_BFD */ +	return -1; +#endif /* WPA_TRACE_BFD */ +} +  #endif /* CONFIG_TESTING_OPTIONS */ @@ -7665,7 +7971,7 @@ static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,  	if (os_strncmp(cmd, " ssid=", 6) == 0) {  		ssid.ssid_len = os_strlen(cmd + 6); -		if (ssid.ssid_len > 32) +		if (ssid.ssid_len > SSID_MAX_LEN)  			return -1;  		ssid.ssid = (u8 *) (cmd + 6);  		ssid_p = &ssid; @@ -7806,6 +8112,19 @@ static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,  } +static int wpas_ctrl_cmd_debug_level(const char *cmd) +{ +	if (os_strcmp(cmd, "PING") == 0 || +	    os_strncmp(cmd, "BSS ", 4) == 0 || +	    os_strncmp(cmd, "GET_NETWORK ", 12) == 0 || +	    os_strncmp(cmd, "STATUS", 6) == 0 || +	    os_strncmp(cmd, "STA ", 4) == 0 || +	    os_strncmp(cmd, "STA-", 4) == 0) +		return MSG_EXCESSIVE; +	return MSG_DEBUG; +} + +  char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,  					 char *buf, size_t *resp_len)  { @@ -7829,9 +8148,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,  		wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",  				      (const u8 *) buf, os_strlen(buf));  	} else { -		int level = MSG_DEBUG; -		if (os_strcmp(buf, "PING") == 0) -			level = MSG_EXCESSIVE; +		int level = wpas_ctrl_cmd_debug_level(buf);  		wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);  	} @@ -8066,7 +8383,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,  		if (wpas_p2p_group_remove(wpa_s, buf + 17))  			reply_len = -1;  	} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) { -		if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0)) +		if (p2p_ctrl_group_add(wpa_s, ""))  			reply_len = -1;  	} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {  		if (p2p_ctrl_group_add(wpa_s, buf + 14)) @@ -8240,6 +8557,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,  		wpa_supplicant_cancel_scan(wpa_s);  		wpa_supplicant_deauthenticate(wpa_s,  					      WLAN_REASON_DEAUTH_LEAVING); +		eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);  	} else if (os_strcmp(buf, "SCAN") == 0) {  		wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);  	} else if (os_strncmp(buf, "SCAN ", 5) == 0) { @@ -8269,7 +8587,8 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,  		reply_len = wpa_supplicant_ctrl_iface_get_network(  			wpa_s, buf + 12, reply, reply_size);  	} else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) { -		if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12)) +		if (wpa_supplicant_ctrl_iface_dup_network(wpa_s, buf + 12, +							  wpa_s))  			reply_len = -1;  	} else if (os_strcmp(buf, "LIST_CREDS") == 0) {  		reply_len = wpa_supplicant_ctrl_iface_list_creds( @@ -8372,6 +8691,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,  		if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,  								      buf + 24))  			reply_len = -1; +	} else if (os_strncmp(buf, "TDLS_LINK_STATUS ", 17) == 0) { +		reply_len = wpa_supplicant_ctrl_iface_tdls_link_status( +			wpa_s, buf + 17, reply, reply_size);  #endif /* CONFIG_TDLS */  	} else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {  		reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size); @@ -8442,6 +8764,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,  			reply_len = -1;  	} else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {  		reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size); +	} else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) { +		if (wpas_ctrl_test_fail(wpa_s, buf + 10) < 0) +			reply_len = -1; +	} else if (os_strcmp(buf, "GET_FAIL") == 0) { +		reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size);  #endif /* CONFIG_TESTING_OPTIONS */  	} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {  		if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0) @@ -8460,6 +8787,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,  	} else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {  		if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))  			reply_len = -1; +	} else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) { +		reply_len = wpas_ctrl_iface_get_pref_freq_list( +			wpa_s, buf + 19, reply, reply_size);  	} else {  		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);  		reply_len = 16; @@ -8479,11 +8809,14 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,  					   char *cmd)  {  	struct wpa_interface iface; -	char *pos; +	char *pos, *extra; +	struct wpa_supplicant *wpa_s; +	unsigned int create_iface = 0; +	u8 mac_addr[ETH_ALEN];  	/*  	 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param> -	 * TAB<bridge_ifname> +	 * TAB<bridge_ifname>[TAB<create>]  	 */  	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); @@ -8543,12 +8876,54 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,  			iface.bridge_ifname = NULL;  		if (pos == NULL)  			break; + +		extra = pos; +		pos = os_strchr(pos, '\t'); +		if (pos) +			*pos++ = '\0'; +		if (!extra[0]) +			break; + +		if (os_strcmp(extra, "create") == 0) +			create_iface = 1; +		else { +			wpa_printf(MSG_DEBUG, +				   "INTERFACE_ADD unsupported extra parameter: '%s'", +				   extra); +			return -1; +		}  	} while (0); +	if (create_iface) { +		wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'", +			   iface.ifname); +		if (!global->ifaces) +			return -1; +		if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname, +				   NULL, NULL, NULL, mac_addr, NULL) < 0) { +			wpa_printf(MSG_ERROR, +				   "CTRL_IFACE interface creation failed"); +			return -1; +		} + +		wpa_printf(MSG_DEBUG, +			   "CTRL_IFACE interface '%s' created with MAC addr: " +			   MACSTR, iface.ifname, MAC2STR(mac_addr)); +	} +  	if (wpa_supplicant_get_iface(global, iface.ifname)) -		return -1; +		goto fail; + +	wpa_s = wpa_supplicant_add_iface(global, &iface, NULL); +	if (!wpa_s) +		goto fail; +	wpa_s->added_vif = create_iface; +	return 0; -	return wpa_supplicant_add_iface(global, &iface, NULL) ? 0 : -1; +fail: +	if (create_iface) +		wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname); +	return -1;  } @@ -8556,13 +8931,22 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global,  					      char *cmd)  {  	struct wpa_supplicant *wpa_s; +	int ret; +	unsigned int delete_iface;  	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);  	wpa_s = wpa_supplicant_get_iface(global, cmd);  	if (wpa_s == NULL)  		return -1; -	return wpa_supplicant_remove_iface(global, wpa_s, 0); +	delete_iface = wpa_s->added_vif; +	ret = wpa_supplicant_remove_iface(global, wpa_s, 0); +	if (!ret && delete_iface) { +		wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'", +			   cmd); +		ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd); +	} +	return ret;  } @@ -8589,7 +8973,7 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global,  	char *pos, *end;  	for (i = 0; wpa_drivers[i]; i++) { -		struct wpa_driver_ops *drv = wpa_drivers[i]; +		const struct wpa_driver_ops *drv = wpa_drivers[i];  		if (drv->get_interfaces == NULL)  			continue;  		tmp = drv->get_interfaces(global->drv_priv[i]); @@ -8807,6 +9191,41 @@ static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)  } +static int wpas_global_ctrl_iface_dup_network(struct wpa_global *global, +					      char *cmd) +{ +	struct wpa_supplicant *wpa_s[2]; /* src, dst */ +	char *p; +	unsigned int i; + +	/* cmd: "<src ifname> <dst ifname> <src network id> <dst network id> +	 * <variable name> */ + +	for (i = 0; i < ARRAY_SIZE(wpa_s) ; i++) { +		p = os_strchr(cmd, ' '); +		if (p == NULL) +			return -1; +		*p = '\0'; + +		wpa_s[i] = global->ifaces; +		for (; wpa_s[i]; wpa_s[i] = wpa_s[i]->next) { +			if (os_strcmp(cmd, wpa_s[i]->ifname) == 0) +				break; +		} + +		if (!wpa_s[i]) { +			wpa_printf(MSG_DEBUG, +				   "CTRL_IFACE: Could not find iface=%s", cmd); +			return -1; +		} + +		cmd = p + 1; +	} + +	return wpa_supplicant_ctrl_iface_dup_network(wpa_s[0], cmd, wpa_s[1]); +} + +  #ifndef CONFIG_NO_CONFIG_WRITE  static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)  { @@ -8888,6 +9307,59 @@ static int wpas_global_ctrl_iface_status(struct wpa_global *global,  } +#ifdef CONFIG_FST + +static int wpas_global_ctrl_iface_fst_attach(struct wpa_global *global, +					     char *cmd, char *buf, +					     size_t reply_size) +{ +	char ifname[IFNAMSIZ + 1]; +	struct fst_iface_cfg cfg; +	struct wpa_supplicant *wpa_s; +	struct fst_wpa_obj iface_obj; + +	if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) { +		wpa_s = wpa_supplicant_get_iface(global, ifname); +		if (wpa_s) { +			if (wpa_s->fst) { +				wpa_printf(MSG_INFO, "FST: Already attached"); +				return -1; +			} +			fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj); +			wpa_s->fst = fst_attach(ifname, wpa_s->own_addr, +						&iface_obj, &cfg); +			if (wpa_s->fst) +				return os_snprintf(buf, reply_size, "OK\n"); +		} +	} + +	return -1; +} + + +static int wpas_global_ctrl_iface_fst_detach(struct wpa_global *global, +					     char *cmd, char *buf, +					     size_t reply_size) +{ +	char ifname[IFNAMSIZ + 1]; +	struct wpa_supplicant *wpa_s; + +	if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) { +		wpa_s = wpa_supplicant_get_iface(global, ifname); +		if (wpa_s) { +			if (!fst_iface_detach(ifname)) { +				wpa_s->fst = NULL; +				return os_snprintf(buf, reply_size, "OK\n"); +			} +		} +	} + +	return -1; +} + +#endif /* CONFIG_FST */ + +  char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,  						char *buf, size_t *resp_len)  { @@ -8939,6 +9411,18 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,  	} else if (os_strcmp(buf, "INTERFACES") == 0) {  		reply_len = wpa_supplicant_global_iface_interfaces(  			global, reply, reply_size); +#ifdef CONFIG_FST +	} else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) { +		reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11, +							      reply, +							      reply_size); +	} else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) { +		reply_len = wpas_global_ctrl_iface_fst_detach(global, buf + 11, +							      reply, +							      reply_size); +	} else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) { +		reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size); +#endif /* CONFIG_FST */  	} else if (os_strcmp(buf, "TERMINATE") == 0) {  		wpa_supplicant_terminate_proc(global);  	} else if (os_strcmp(buf, "SUSPEND") == 0) { @@ -8959,6 +9443,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,  #endif /* CONFIG_P2P */  			reply_len = -1;  		} +	} else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) { +		if (wpas_global_ctrl_iface_dup_network(global, buf + 12)) +			reply_len = -1;  #ifndef CONFIG_NO_CONFIG_WRITE  	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {  		if (wpas_global_ctrl_iface_save_config(global))  | 
