#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"
}
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);
wpa_s->sme.prev_bssid_set = 0;
#endif /* CONFIG_SME */
wpa_s->reassociate = 1;
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
+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)
{
wpa_s->extra_roc_dur = atoi(value);
} else if (os_strcasecmp(cmd, "test_failure") == 0) {
wpa_s->test_failure = atoi(value);
+ } else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
+ wpa_s->p2p_go_csa_on_inv = !!atoi(value);
#endif /* CONFIG_TESTING_OPTIONS */
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strcmp(cmd, "blob") == 0) {
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);
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 */
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)
}
-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)
}
}
- if (cmd && os_strlen(cmd)) {
+ if (os_strlen(cmd)) {
int level = str_to_debug_level(cmd);
if (level < 0)
return -1;
}
#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) {
{
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);
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;
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));
}
}
+ wpa_s->scan_min_time.sec = 0;
+ wpa_s->scan_min_time.usec = 0;
wpa_supplicant_select_network(wpa_s, ssid);
return 0;
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;
#endif /* CONFIG_SME */
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
}
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
}
*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;
}
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;
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) {
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);
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);
}
#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);
size_t i;
int ret;
char *pos, *end;
- const u8 *ie, *ie2;
+ const u8 *ie, *ie2, *osen_ie;
pos = buf;
end = buf + buflen;
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;
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 */
#ifdef CONFIG_INTERWORKING
if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
struct wpa_bss_anqp *anqp = bss->anqp;
+ struct wpa_bss_anqp_elem *elem;
+
pos = anqp_add_hex(pos, end, "anqp_capability_list",
anqp->capability_list);
pos = anqp_add_hex(pos, end, "anqp_venue_name",
pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
anqp->hs20_osu_providers_list);
#endif /* CONFIG_HS20 */
+
+ dl_list_for_each(elem, &anqp->anqp_elems,
+ struct wpa_bss_anqp_elem, list) {
+ char title[20];
+
+ os_snprintf(title, sizeof(title), "anqp[%u]",
+ elem->infoid);
+ pos = anqp_add_hex(pos, end, title, elem->payload);
+ }
}
#endif /* CONFIG_INTERWORKING */
}
#endif /* CONFIG_MESH */
+ if (mask & WPA_BSS_MASK_SNR) {
+ ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ if (mask & WPA_BSS_MASK_EST_THROUGHPUT) {
+ ret = os_snprintf(pos, end - pos, "est_throughput=%d\n",
+ bss->est_throughput);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ 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))
u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
char *pos;
unsigned int search_delay;
- const char *seek[P2P_MAX_QUERY_HASH + 1];
+ const char *_seek[P2P_MAX_QUERY_HASH + 1], **seek = NULL;
u8 seek_count = 0;
+ int freq = 0;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_INFO,
} 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;
- pos = os_strstr(pos + 6, " seek=");
-
- if (term)
- *term = '\0';
+ _seek[seek_count++] = pos;
+ seek = _seek;
+ term = os_strchr(pos, ' ');
+ if (!term)
+ break;
+ *term = '\0';
+ pos = os_strstr(term + 1, "seek=");
+ if (pos)
+ pos += 5;
}
-
- if (!seek_count)
- return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL,
- _dev_type, _dev_id,
- search_delay, 0, NULL);
-
if (seek_count > P2P_MAX_QUERY_HASH) {
seek[0] = NULL;
- return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL,
- _dev_type, _dev_id,
- search_delay, 1, seek);
+ seek_count = 1;
}
return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
- _dev_id, search_delay, seek_count, seek);
+ _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;
}
char *info = NULL;
u8 role = P2PS_SETUP_NONE;
long long unsigned val;
+ int i;
pos = os_strstr(cmd, "info=");
if (pos) {
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) {
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);
}
+static int parse_freq(int chwidth, int freq2)
+{
+ if (freq2 < 0)
+ return -1;
+ if (freq2)
+ return VHT_CHANWIDTH_80P80MHZ;
+
+ switch (chwidth) {
+ case 0:
+ case 20:
+ case 40:
+ return VHT_CHANWIDTH_USE_HT;
+ case 80:
+ return VHT_CHANWIDTH_80MHZ;
+ case 160:
+ return VHT_CHANWIDTH_160MHZ;
+ default:
+ wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
+ chwidth);
+ return -1;
+ }
+}
+
+
static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
char *buf, size_t buflen)
{
int go_intent = -1;
int freq = 0;
int pd;
- int ht40, vht;
+ int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+
+ if (!wpa_s->global->p2p_init_wpa_s)
+ return -1;
+ if (wpa_s->global->p2p_init_wpa_s != wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Direct P2P_CONNECT command to %s",
+ wpa_s->global->p2p_init_wpa_s->ifname);
+ wpa_s = wpa_s->global->p2p_init_wpa_s;
+ }
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
return -1;
}
+ pos2 = os_strstr(pos, " freq2=");
+ if (pos2)
+ freq2 = atoi(pos2 + 7);
+
+ pos2 = os_strstr(pos, " max_oper_chwidth=");
+ if (pos2)
+ chwidth = atoi(pos2 + 18);
+
+ max_oper_chwidth = parse_freq(chwidth, freq2);
+ if (max_oper_chwidth < 0)
+ return -1;
+
if (os_strncmp(pos, "pin", 3) == 0) {
/* Request random PIN (to be displayed) and enable the PIN */
wps_method = WPS_PIN_DISPLAY;
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
- auth, go_intent, freq, persistent_id, pd,
- ht40, vht);
+ auth, go_intent, freq, freq2, persistent_id,
+ pd, ht40, vht, max_oper_chwidth);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
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)
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;
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);
}
{
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;
struct wpa_ssid *ssid;
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
- int ht40, vht;
+ int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
- return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
- pref_freq);
+ pos = os_strstr(cmd, "freq2=");
+ if (pos)
+ freq2 = atoi(pos + 6);
+
+ pos = os_strstr(cmd, " max_oper_chwidth=");
+ if (pos)
+ chwidth = atoi(pos + 18);
+
+ max_oper_chwidth = parse_freq(chwidth, freq2);
+ if (max_oper_chwidth < 0)
+ return -1;
+
+ return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
+ max_oper_chwidth, pref_freq);
}
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 vht_center_freq2,
+ int ht40, int vht, int vht_chwidth)
{
- 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 "
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, ht40, vht,
- NULL, 0);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
+ vht_center_freq2, 0, ht40, vht,
+ vht_chwidth, 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;
+ int max_oper_chwidth, chwidth = 0, freq2 = 0;
+ 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, "freq2=%d", &freq2) == 1 ||
+ sscanf(token, "persistent=%d", &group_id) == 1 ||
+ sscanf(token, "max_oper_chwidth=%d", &chwidth) == 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;
+ max_oper_chwidth = parse_freq(chwidth, freq2);
+ if (max_oper_chwidth < 0)
+ return -1;
- 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;
+ if (group_id >= 0)
+ return p2p_ctrl_group_add_persistent(wpa_s, group_id,
+ freq, freq2, ht40, vht,
+ max_oper_chwidth);
+
+ return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
+ max_oper_chwidth);
}
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;
}
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);
}
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;
}
wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
+ wpas_abort_ongoing_scan(wpa_s);
+
#ifdef CONFIG_P2P
wpas_p2p_cancel(p2p_wpa_s);
p2p_ctrl_flush(p2p_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;
+ p2p_wpa_s->global->pending_p2ps_group_freq = 0;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS_TESTING
wpa_supplicant_stop_countermeasures(wpa_s, NULL);
wpa_s->no_keep_alive = 0;
+ wpa_s->own_disconnect_req = 0;
os_free(wpa_s->disallow_aps_bssid);
wpa_s->disallow_aps_bssid = NULL;
wpa_s->next_ssid = NULL;
#ifdef CONFIG_INTERWORKING
+#ifdef CONFIG_HS20
hs20_cancel_fetch_osu(wpa_s);
+#endif /* CONFIG_HS20 */
#endif /* CONFIG_INTERWORKING */
wpa_s->ext_mgmt_frame_handling = 0;
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->extra_roc_dur = 0;
wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
+ wpa_s->p2p_go_csa_on_inv = 0;
#endif /* CONFIG_TESTING_OPTIONS */
wpa_s->disconnected = 0;
MAC2STR(wpa_s->bssid),
MAC2STR(wpa_s->pending_bssid));
}
+
+ eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ wpa_s->wnmsleep_used = 0;
}
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;
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;
*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)
done:
os_free(manual_scan_freqs);
+ os_free(ssid);
}
{
struct wpa_supplicant *wpa_s = ctx;
const struct ether_header *eth;
- const struct iphdr *ip;
+ struct iphdr ip;
const u8 *pos;
unsigned int i;
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++;
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;
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);
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;
#endif /* WPA_TRACE_BFD */
}
-#endif /* CONFIG_TESTING_OPTIONS */
-
-static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s)
+static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
{
- unsigned int i;
- char buf[30];
+#ifdef WPA_TRACE_BFD
+ extern char wpa_trace_test_fail_func[256];
+ extern unsigned int wpa_trace_test_fail_after;
+ char *pos;
- wpa_printf(MSG_DEBUG, "Update vendor elements");
+ 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 */
+}
- for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
- if (wpa_s->vendor_elem[i]) {
- int res;
- res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
- if (!os_snprintf_error(sizeof(buf), res)) {
- wpa_hexdump_buf(MSG_DEBUG, buf,
- wpa_s->vendor_elem[i]);
- }
- }
- }
+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;
-#ifdef CONFIG_P2P
- if (wpa_s->parent == wpa_s &&
- wpa_s->global->p2p &&
- !wpa_s->global->p2p_disabled)
- p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
-#endif /* CONFIG_P2P */
+ 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 */
}
-static struct wpa_supplicant *
-wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s,
- enum wpa_vendor_elem_frame frame)
+static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx)
{
- switch (frame) {
-#ifdef CONFIG_P2P
- case VENDOR_ELEM_PROBE_REQ_P2P:
- case VENDOR_ELEM_PROBE_RESP_P2P:
- case VENDOR_ELEM_PROBE_RESP_P2P_GO:
- case VENDOR_ELEM_BEACON_P2P_GO:
- case VENDOR_ELEM_P2P_PD_REQ:
- case VENDOR_ELEM_P2P_PD_RESP:
- case VENDOR_ELEM_P2P_GO_NEG_REQ:
- case VENDOR_ELEM_P2P_GO_NEG_RESP:
- case VENDOR_ELEM_P2P_GO_NEG_CONF:
- case VENDOR_ELEM_P2P_INV_REQ:
- case VENDOR_ELEM_P2P_INV_RESP:
- case VENDOR_ELEM_P2P_ASSOC_REQ:
- return wpa_s->parent;
-#endif /* CONFIG_P2P */
- default:
- return wpa_s;
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ int i, count = (intptr_t) timeout_ctx;
+
+ wpa_printf(MSG_DEBUG, "TEST: Send %d control interface event messages",
+ count);
+ for (i = 0; i < count; i++) {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, "TEST-EVENT-MESSAGE %d/%d",
+ i + 1, count);
}
}
+static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int count;
+
+ count = atoi(cmd);
+ if (count <= 0)
+ return -1;
+
+ return eloop_register_timeout(0, 0, wpas_ctrl_event_test_cb, wpa_s,
+ (void *) (intptr_t) count);
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos = cmd;
frame = atoi(pos);
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
pos = os_strchr(pos, ' ');
if (pos == NULL)
if (wpa_s->vendor_elem[frame] == NULL) {
wpa_s->vendor_elem[frame] = buf;
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
wpabuf_free(buf);
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
if (wpa_s->vendor_elem[frame] == NULL)
return 0;
size_t len;
u8 *buf;
struct ieee802_11_elems elems;
- u8 *ie, *end;
+ int res;
frame = atoi(pos);
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
pos = os_strchr(pos, ' ');
if (pos == NULL)
if (*pos == '*') {
wpabuf_free(wpa_s->vendor_elem[frame]);
wpa_s->vendor_elem[frame] = NULL;
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
return -1;
}
- ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
- end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
-
- for (; ie + 1 < end; ie += 2 + ie[1]) {
- if (ie + len > end)
- break;
- if (os_memcmp(ie, buf, len) != 0)
- continue;
-
- if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
- wpabuf_free(wpa_s->vendor_elem[frame]);
- wpa_s->vendor_elem[frame] = NULL;
- } else {
- os_memmove(ie, ie + len,
- end - (ie + len));
- wpa_s->vendor_elem[frame]->used -= len;
- }
- os_free(buf);
- wpas_ctrl_vendor_elem_update(wpa_s);
- return 0;
- }
-
+ res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
os_free(buf);
-
- return -1;
+ return res;
}
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;
}
+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)
{
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);
}
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))
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) {
} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_scan_results(
wpa_s, reply, reply_size);
+ } else if (os_strcmp(buf, "ABORT_SCAN") == 0) {
+ if (wpas_abort_ongoing_scan(wpa_s) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
reply_len = -1;
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(
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);
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);
+ } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
+ if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
+ reply_len = -1;
#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)
} 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;
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];
+ enum wpa_driver_if_type type = WPA_IF_STATION;
/*
* <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
- * TAB<bridge_ifname>
+ * TAB<bridge_ifname>[TAB<create>[TAB<interface_type>]]
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
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;
+ if (!pos)
+ break;
+
+ if (os_strcmp(pos, "sta") == 0) {
+ type = WPA_IF_STATION;
+ } else if (os_strcmp(pos, "ap") == 0) {
+ type = WPA_IF_AP_BSS;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "INTERFACE_ADD unsupported interface type: '%s'",
+ pos);
+ return -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, type, 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) ? 0 : -1;
+fail:
+ if (create_iface)
+ wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname);
+ return -1;
}
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;
}
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]);
}
+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)
{
}
+#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)
{
} 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) {
#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))