/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/uuid.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "autoscan.h"
#include "wnm_sta.h"
-extern struct wpa_driver_ops *wpa_drivers[];
-
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
static int pno_start(struct wpa_supplicant *wpa_s)
{
- int ret;
+ int ret, interval;
size_t i, num_ssid;
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
- if (wpa_s->pno)
+ if (wpa_s->pno || wpa_s->pno_sched_pending)
return 0;
+ if ((wpa_s->wpa_state > WPA_SCANNING) &&
+ (wpa_s->wpa_state <= WPA_COMPLETED)) {
+ wpa_printf(MSG_ERROR, "PNO: In assoc process");
+ return -EAGAIN;
+ }
+
if (wpa_s->wpa_state == WPA_SCANNING) {
- wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_cancel_scan(wpa_s);
+ if (wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Schedule PNO on completion of "
+ "ongoing sched scan");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->pno_sched_pending = 1;
+ return 0;
+ }
}
os_memset(¶ms, 0, sizeof(params));
if (wpa_s->conf->filter_rssi)
params.filter_rssi = wpa_s->conf->filter_rssi;
- ret = wpa_drv_sched_scan(wpa_s, ¶ms, 10 * 1000);
+ interval = wpa_s->conf->sched_scan_interval ?
+ wpa_s->conf->sched_scan_interval : 10;
+
+ ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms, interval);
os_free(params.filter_ssids);
if (ret == 0)
wpa_s->pno = 1;
{
int ret = 0;
- if (wpa_s->pno) {
+ if (wpa_s->pno || wpa_s->sched_scanning) {
wpa_s->pno = 0;
- ret = wpa_drv_stop_sched_scan(wpa_s);
+ ret = wpa_supplicant_stop_sched_scan(wpa_s);
}
+ wpa_s->pno_sched_pending = 0;
+
if (wpa_s->wpa_state == WPA_SCANNING)
wpa_supplicant_req_scan(wpa_s, 0, 0);
struct wpa_ssid *c;
/*
- * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
+ * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | ""
* SSID_SPEC ::= ssid <SSID_HEX>
* BSSID_SPEC ::= bssid <BSSID_HEX>
*/
} else if (os_strcasecmp(cmd, "ampdu") == 0) {
if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
ret = -1;
+#ifdef CONFIG_TDLS
#ifdef CONFIG_TDLS_TESTING
} else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
extern unsigned int tdls_testing;
tdls_testing = strtol(value, NULL, 0);
wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
#endif /* CONFIG_TDLS_TESTING */
-#ifdef CONFIG_TDLS
} else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
int disabled = atoi(value);
wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
MAC2STR(peer));
+ if ((wpa_s->conf->tdls_external_control) &&
+ wpa_tdls_is_external_setup(wpa_s->wpa))
+ return wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+
wpa_tdls_remove(wpa_s->wpa, peer);
if (wpa_tdls_is_external_setup(wpa_s->wpa))
struct wpa_supplicant *wpa_s, char *addr)
{
u8 peer[ETH_ALEN];
+ int ret;
if (hwaddr_aton(addr, peer)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
MAC2STR(peer));
- return wpa_tdls_teardown_link(wpa_s->wpa, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ if ((wpa_s->conf->tdls_external_control) &&
+ wpa_tdls_is_external_setup(wpa_s->wpa))
+ return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_teardown_link(
+ wpa_s->wpa, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+ return ret;
}
#endif /* CONFIG_TDLS */
else if (hwaddr_aton(cmd, bssid))
return -1;
- return wpas_wps_start_nfc(wpa_s, _bssid);
+ return wpas_wps_start_nfc(wpa_s, _bssid, NULL, 0, 0, NULL, NULL, 0);
}
static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
char *reply, size_t max_len,
- int cr)
+ int ndef)
{
struct wpabuf *buf;
int res;
- buf = wpas_wps_nfc_handover_req(wpa_s, cr);
+ buf = wpas_wps_nfc_handover_req(wpa_s, ndef);
if (buf == NULL)
return -1;
}
+static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int ndef)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_p2p_nfc_handover_req(wpa_s, ndef);
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request");
+ return -1;
+ }
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
char *cmd, char *reply,
size_t max_len)
{
char *pos;
+ int ndef;
pos = os_strchr(cmd, ' ');
if (pos == NULL)
return -1;
*pos++ = '\0';
- if (os_strcmp(cmd, "NDEF") != 0)
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
return -1;
if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ if (!ndef)
+ return -1;
return wpas_ctrl_nfc_get_handover_req_wps(
- wpa_s, reply, max_len, os_strcmp(pos, "WPS-CR") == 0);
+ wpa_s, reply, max_len, ndef);
+ }
+
+ if (os_strcmp(pos, "P2P-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_req_p2p(
+ wpa_s, reply, max_len, ndef);
}
return -1;
}
+static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int ndef, int tag)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
char *cmd, char *reply,
size_t max_len)
if (pos2)
*pos2++ = '\0';
if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ if (!ndef)
+ return -1;
return wpas_ctrl_nfc_get_handover_sel_wps(
wpa_s, reply, max_len, ndef,
os_strcmp(pos, "WPS-CR") == 0, pos2);
}
+ if (os_strcmp(pos, "P2P-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_p2p(
+ wpa_s, reply, max_len, ndef, 0);
+ }
+
+ if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_p2p(
+ wpa_s, reply, max_len, ndef, 1);
+ }
+
return -1;
}
if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
+ } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0)
+ {
+ ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
+ if (ret < 0)
+ ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
+ } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel);
+ } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel);
} else {
wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
"reported: role=%s type=%s", role, type);
char *pos, *end, tmp[30];
int res, verbose, wps, ret;
+ if (os_strcmp(params, "-DRIVER") == 0)
+ return wpa_drv_status(wpa_s, buf, buflen);
verbose = os_strcmp(params, "-VERBOSE") == 0;
wps = os_strcmp(params, "-WPS") == 0;
pos = buf;
}
#ifdef CONFIG_SAE
if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
- wpa_s->sme.sae.state == SAE_ACCEPTED && !wpa_s->ap_iface) {
+#ifdef CONFIG_AP
+ !wpa_s->ap_iface &&
+#endif /* CONFIG_AP */
+ wpa_s->sme.sae.state == SAE_ACCEPTED) {
ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
wpa_s->sme.sae.group);
if (ret < 0 || ret >= end - pos)
char *type;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ size_t i;
+
if (wpa_s->current_ssid->parent_cred != cred)
continue;
- if (!cred->domain)
- continue;
- ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
- cred->domain);
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
+ for (i = 0; cred->domain && i < cred->num_domain; i++) {
+ ret = os_snprintf(pos, end - pos,
+ "home_sp=%s\n",
+ cred->domain[i]);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
if (wpa_s->current_bss == NULL ||
wpa_s->current_bss->anqp == NULL)
if (res >= 0)
pos += res;
+#ifdef CONFIG_WPS
+ {
+ char uuid_str[100];
+ uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
+ ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_WPS */
+
+#ifdef ANDROID
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
+ "id=%d state=%d BSSID=" MACSTR " SSID=%s",
+ wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
+ wpa_s->wpa_state,
+ MAC2STR(wpa_s->bssid),
+ wpa_s->current_ssid && wpa_s->current_ssid->ssid ?
+ wpa_ssid_txt(wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len) : "");
+ if (wpa_s->wpa_state == WPA_COMPLETED) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
+ "- connection to " MACSTR
+ " completed %s [id=%d id_str=%s]",
+ MAC2STR(wpa_s->bssid), "(auth)",
+ ssid ? ssid->id : -1,
+ ssid && ssid->id_str ? ssid->id_str : "");
+ }
+#endif /* ANDROID */
+
return pos - buf;
}
}
-extern int wpa_debug_level;
-extern int wpa_debug_timestamp;
-
static const char * debug_level_str(int level)
{
switch (level) {
const u8 *ie, *ie2, *p2p;
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (!p2p)
+ p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
0)
ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
cred->id, cred->realm ? cred->realm : "",
cred->username ? cred->username : "",
- cred->domain ? cred->domain : "",
+ cred->domain ? cred->domain[0] : "",
cred->imsi ? cred->imsi : "");
if (ret < 0 || ret >= end - pos)
return pos - buf;
while (cred) {
prev = cred;
cred = cred->next;
- if (prev->domain &&
- os_strcmp(prev->domain, cmd + 8) == 0)
- wpas_ctrl_remove_cred(wpa_s, prev);
+ if (prev->domain) {
+ size_t i;
+ for (i = 0; i < prev->num_domain; i++) {
+ if (os_strcmp(prev->domain[i], cmd + 8)
+ != 0)
+ continue;
+ wpas_ctrl_remove_cred(wpa_s, prev);
+ break;
+ }
+ }
}
return 0;
}
#endif /* CONFIG_NO_CONFIG_WRITE */
+struct cipher_info {
+ unsigned int capa;
+ const char *name;
+ int group_only;
+};
+
+static const struct cipher_info ciphers[] = {
+ { WPA_DRIVER_CAPA_ENC_CCMP_256, "CCMP-256", 0 },
+ { WPA_DRIVER_CAPA_ENC_GCMP_256, "GCMP-256", 0 },
+ { WPA_DRIVER_CAPA_ENC_CCMP, "CCMP", 0 },
+ { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 },
+ { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 },
+ { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 },
+ { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 },
+ { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
+};
+
+
static int ctrl_iface_get_capability_pairwise(int res, char *strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
int ret, first = 1;
char *pos, *end;
size_t len;
+ unsigned int i;
pos = buf;
end = pos + buflen;
return len;
}
- if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
- ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
+ for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
+ if (!ciphers[i].group_only && capa->enc & ciphers[i].capa) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ first ? "" : " ", ciphers[i].name);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
}
return pos - buf;
int ret, first = 1;
char *pos, *end;
size_t len;
+ unsigned int i;
pos = buf;
end = pos + buflen;
return len;
}
- if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
- ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
- first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
- }
-
- if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- first = 0;
+ for (i = 0; i < ARRAY_SIZE(ciphers); i++) {
+ if (capa->enc & ciphers[i].capa) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ first ? "" : " ", ciphers[i].name);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
}
return pos - buf;
}
if (mask & WPA_BSS_MASK_AGE) {
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
ret = os_snprintf(pos, end - pos, "age=%d\n",
(int) (now.sec - bss->last_update.sec));
if (ret < 0 || ret >= end - pos)
return 0;
pos += ret;
}
- if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
+ if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+ wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
ret = os_snprintf(pos, end - pos, "[P2P]");
if (ret < 0 || ret >= end - pos)
return 0;
unsigned int timeout = atoi(cmd);
enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
u8 dev_id[ETH_ALEN], *_dev_id = NULL;
+ u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
char *pos;
unsigned int search_delay;
_dev_id = dev_id;
}
+ pos = os_strstr(cmd, "dev_type=");
+ if (pos) {
+ pos += 9;
+ if (wps_dev_type_str2bin(pos, dev_type) < 0)
+ return -1;
+ _dev_type = dev_type;
+ }
+
pos = os_strstr(cmd, "delay=");
if (pos) {
pos += 6;
} else
search_delay = wpas_p2p_search_delay(wpa_s);
- return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
- search_delay);
+ return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
+ _dev_id, search_delay);
}
int go_intent = -1;
int freq = 0;
int pd;
- int ht40;
+ int ht40, vht;
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] */
+ * [ht40] [vht] */
if (hwaddr_aton(cmd, addr))
return -1;
auth = os_strstr(pos, " auth") != NULL;
automatic = os_strstr(pos, " auto") != NULL;
pd = os_strstr(pos, " provdisc") != NULL;
- ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+ 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;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
auth, go_intent, freq, persistent_id, pd,
- ht40);
+ ht40, vht);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
struct wpa_ssid *ssid;
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
- int ht40;
+ int ht40, vht;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
return -1;
}
- ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+ 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;
- return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, pref_freq);
+ return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
+ pref_freq);
}
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
- char *cmd, int freq, int ht40)
+ char *cmd, int freq, int ht40,
+ int vht)
{
int id;
struct wpa_ssid *ssid;
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, vht,
+ NULL, 0);
}
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
{
- int freq = 0, ht40;
+ int freq = 0, ht40, vht;
char *pos;
pos = os_strstr(cmd, "freq=");
if (pos)
freq = atoi(pos + 5);
- ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+ 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 (os_strncmp(cmd, "persistent=", 11) == 0)
return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
- ht40);
+ ht40, vht);
if (os_strcmp(cmd, "persistent") == 0 ||
os_strncmp(cmd, "persistent ", 11) == 0)
- return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
+ 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);
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
if (ht40)
- return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
cmd);
static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
const char *param)
{
- struct wpa_freq_range *freq = NULL, *n;
- unsigned int count = 0, i;
- const char *pos, *pos2, *pos3;
+ unsigned int i;
if (wpa_s->global->p2p == NULL)
return -1;
- /*
- * param includes comma separated frequency range.
- * For example: 2412-2432,2462,5000-6000
- */
- pos = param;
- while (pos && pos[0]) {
- n = os_realloc_array(freq, count + 1,
- sizeof(struct wpa_freq_range));
- if (n == NULL) {
- os_free(freq);
- return -1;
- }
- freq = n;
- freq[count].min = atoi(pos);
- pos2 = os_strchr(pos, '-');
- pos3 = os_strchr(pos, ',');
- if (pos2 && (!pos3 || pos2 < pos3)) {
- pos2++;
- freq[count].max = atoi(pos2);
- } else
- freq[count].max = freq[count].min;
- pos = pos3;
- if (pos)
- pos++;
- count++;
- }
+ if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0)
+ return -1;
- for (i = 0; i < count; i++) {
+ for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) {
+ struct wpa_freq_range *freq;
+ freq = &wpa_s->global->p2p_disallow_freq.range[i];
wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
- freq[i].min, freq[i].max);
+ freq->min, freq->max);
}
- os_free(wpa_s->global->p2p_disallow_freq);
- wpa_s->global->p2p_disallow_freq = freq;
- wpa_s->global->num_p2p_disallow_freq = count;
wpas_p2p_update_channel_list(wpa_s);
return 0;
}
max_disc_int, max_disc_tu);
}
+ if (os_strcmp(cmd, "per_sta_psk") == 0) {
+ wpa_s->global->p2p_per_sta_psk = !!atoi(param);
+ return 0;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
cmd);
return wpas_p2p_ext_listen(wpa_s, period, interval);
}
+
+static int p2p_ctrl_remove_client(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ u8 peer[ETH_ALEN];
+ int iface_addr = 0;
+
+ pos = cmd;
+ if (os_strncmp(pos, "iface=", 6) == 0) {
+ iface_addr = 1;
+ pos += 6;
+ }
+ if (hwaddr_aton(pos, peer))
+ return -1;
+
+ wpas_p2p_remove_client(wpa_s, peer, iface_addr);
+ return 0;
+}
+
#endif /* CONFIG_P2P */
+static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val)
+{
+ struct wpa_freq_range_list ranges;
+ int *freqs = NULL;
+ struct hostapd_hw_modes *mode;
+ u16 i;
+
+ if (wpa_s->hw.modes == NULL)
+ return NULL;
+
+ os_memset(&ranges, 0, sizeof(ranges));
+ if (freq_range_list_parse(&ranges, val) < 0)
+ return NULL;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ int j;
+
+ mode = &wpa_s->hw.modes[i];
+ for (j = 0; j < mode->num_channels; j++) {
+ unsigned int freq;
+
+ if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ freq = mode->channels[j].freq;
+ if (!freq_range_list_includes(&ranges, freq))
+ continue;
+
+ int_array_add_unique(&freqs, freq);
+ }
+ }
+
+ os_free(ranges.range);
+ return freqs;
+}
+
+
#ifdef CONFIG_INTERWORKING
+
+static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param)
+{
+ int auto_sel = 0;
+ int *freqs = NULL;
+
+ if (param) {
+ char *pos;
+
+ auto_sel = os_strstr(param, "auto") != NULL;
+
+ pos = os_strstr(param, "freq=");
+ if (pos) {
+ freqs = freq_range_to_channel_list(wpa_s, pos + 5);
+ if (freqs == NULL)
+ return -1;
+ }
+
+ }
+
+ return interworking_select(wpa_s, auto_sel, freqs);
+}
+
+
static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
{
u8 bssid[ETH_ALEN];
int used;
char *pos;
size_t resp_len, start, requested_len;
-
- if (!wpa_s->last_gas_resp)
- return -1;
+ struct wpabuf *resp;
+ int ret;
used = hwaddr_aton2(cmd, addr);
if (used < 0)
pos++;
dialog_token = atoi(pos);
- if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
- dialog_token != wpa_s->last_gas_dialog_token)
+ if (wpa_s->last_gas_resp &&
+ os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 &&
+ dialog_token == wpa_s->last_gas_dialog_token)
+ resp = wpa_s->last_gas_resp;
+ else if (wpa_s->prev_gas_resp &&
+ os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 &&
+ dialog_token == wpa_s->prev_gas_dialog_token)
+ resp = wpa_s->prev_gas_resp;
+ else
return -1;
- resp_len = wpabuf_len(wpa_s->last_gas_resp);
+ resp_len = wpabuf_len(resp);
start = 0;
requested_len = resp_len;
if (requested_len * 2 + 1 > buflen)
return os_snprintf(buf, buflen, "FAIL-Too long response");
- return wpa_snprintf_hex(buf, buflen,
- wpabuf_head_u8(wpa_s->last_gas_resp) + start,
- requested_len);
+ ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start,
+ requested_len);
+
+ if (start + requested_len == resp_len) {
+ /*
+ * Free memory by dropping the response after it has been
+ * fetched.
+ */
+ if (resp == wpa_s->prev_gas_resp) {
+ wpabuf_free(wpa_s->prev_gas_resp);
+ wpa_s->prev_gas_resp = NULL;
+ } else {
+ wpabuf_free(wpa_s->last_gas_resp);
+ wpa_s->last_gas_resp = NULL;
+ }
+ }
+
+ return ret;
}
#endif /* CONFIG_INTERWORKING */
pos += ret;
}
+ if (si.avg_signal) {
+ ret = os_snprintf(pos, end - pos,
+ "AVG_RSSI=%d\n", si.avg_signal);
+ if (ret < 0 || ret >= end - pos)
+ return -1;
+ pos += ret;
+ }
+
return pos - buf;
}
}
+#ifdef ANDROID
+static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ int ret;
+
+ ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
+ if (ret == 0) {
+ if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ if (p2p) {
+ char country[3];
+ country[0] = cmd[8];
+ country[1] = cmd[9];
+ country[2] = 0x04;
+ p2p_set_country(p2p, country);
+ }
+ }
+ ret = os_snprintf(buf, buflen, "%s\n", "OK");
+ }
+ return ret;
+}
+#endif /* ANDROID */
+
+
static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
{
wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
wpas_p2p_stop_find(wpa_s);
p2p_ctrl_flush(wpa_s);
wpas_p2p_group_remove(wpa_s, "*");
+ wpas_p2p_service_flush(wpa_s);
+ wpa_s->global->p2p_disabled = 0;
+ wpa_s->global->p2p_per_sta_psk = 0;
+ wpa_s->conf->num_sec_device_types = 0;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS_TESTING
wps_testing_dummy_cred = 0;
#endif /* CONFIG_WPS_TESTING */
#ifdef CONFIG_WPS
+ wpa_s->wps_fragment_size = 0;
wpas_wps_cancel(wpa_s);
#endif /* CONFIG_WPS */
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+#ifdef CONFIG_TDLS
#ifdef CONFIG_TDLS_TESTING
extern unsigned int tdls_testing;
tdls_testing = 0;
#endif /* CONFIG_TDLS_TESTING */
-#ifdef CONFIG_TDLS
wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
wpa_tdls_enable(wpa_s->wpa, 1);
#endif /* CONFIG_TDLS */
wpa_s->extra_blacklist_count = 0;
wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
+ wpa_config_flush_blobs(wpa_s->conf);
+ wpa_s->conf->auto_interworking = 0;
+ wpa_s->conf->okc = 0;
+ wpa_s->conf->pmf = 0;
+
+ wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
+ wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
+ wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
+ eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+
+ radio_remove_unstarted_work(wpa_s, NULL);
+}
+
+
+static int wpas_ctrl_radio_work_show(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ struct wpa_radio_work *work;
+ char *pos, *end;
+ struct os_reltime now, diff;
+
+ pos = buf;
+ end = buf + buflen;
+
+ os_get_reltime(&now);
+
+ dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+ {
+ int ret;
+
+ os_reltime_sub(&now, &work->time, &diff);
+ ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
+ work->type, work->wpa_s->ifname, work->freq,
+ work->started, diff.sec, diff.usec);
+ if (ret < 0 || ret >= end - pos)
+ break;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
+static void wpas_ctrl_radio_work_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_radio_work *work = eloop_ctx;
+ struct wpa_external_work *ework = work->ctx;
+
+ wpa_dbg(work->wpa_s, MSG_DEBUG,
+ "Timing out external radio work %u (%s)",
+ ework->id, work->type);
+ wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
+ os_free(ework);
+ radio_work_done(work);
+}
+
+
+static void wpas_ctrl_radio_work_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_external_work *ework = work->ctx;
+
+ if (deinit) {
+ os_free(ework);
+ return;
+ }
+
+ wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
+ ework->id, ework->type);
+ wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
+ if (!ework->timeout)
+ ework->timeout = 10;
+ eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
+ work, NULL);
+}
+
+
+static int wpas_ctrl_radio_work_add(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ struct wpa_external_work *ework;
+ char *pos, *pos2;
+ size_t type_len;
+ int ret;
+ unsigned int freq = 0;
+
+ /* format: <name> [freq=<MHz>] [timeout=<seconds>] */
+
+ ework = os_zalloc(sizeof(*ework));
+ if (ework == NULL)
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos) {
+ type_len = pos - cmd;
+ pos++;
+
+ pos2 = os_strstr(pos, "freq=");
+ if (pos2)
+ freq = atoi(pos2 + 5);
+
+ pos2 = os_strstr(pos, "timeout=");
+ if (pos2)
+ ework->timeout = atoi(pos2 + 8);
+ } else {
+ type_len = os_strlen(cmd);
+ }
+ if (4 + type_len >= sizeof(ework->type))
+ type_len = sizeof(ework->type) - 4 - 1;
+ os_strlcpy(ework->type, "ext:", sizeof(ework->type));
+ os_memcpy(ework->type + 4, cmd, type_len);
+ ework->type[4 + type_len] = '\0';
+
+ wpa_s->ext_work_id++;
+ if (wpa_s->ext_work_id == 0)
+ wpa_s->ext_work_id++;
+ ework->id = wpa_s->ext_work_id;
+
+ if (radio_add_work(wpa_s, freq, ework->type, 0, wpas_ctrl_radio_work_cb,
+ ework) < 0) {
+ os_free(ework);
+ return -1;
+ }
+
+ ret = os_snprintf(buf, buflen, "%u", ework->id);
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+}
+
+
+static int wpas_ctrl_radio_work_done(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ struct wpa_radio_work *work;
+ unsigned int id = atoi(cmd);
+
+ dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+ {
+ struct wpa_external_work *ework;
+
+ if (os_strncmp(work->type, "ext:", 4) != 0)
+ continue;
+ ework = work->ctx;
+ if (id && ework->id != id)
+ continue;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Completed external radio work %u (%s)",
+ ework->id, ework->type);
+ eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
+ os_free(ework);
+ radio_work_done(work);
+ return 3; /* "OK\n" */
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_radio_work(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ if (os_strcmp(cmd, "show") == 0)
+ return wpas_ctrl_radio_work_show(wpa_s, buf, buflen);
+ if (os_strncmp(cmd, "add ", 4) == 0)
+ return wpas_ctrl_radio_work_add(wpa_s, cmd + 4, buf, buflen);
+ if (os_strncmp(cmd, "done ", 5) == 0)
+ return wpas_ctrl_radio_work_done(wpa_s, cmd + 4);
+ return -1;
+}
+
+
+void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_radio_work *work, *tmp;
+
+ if (!wpa_s || !wpa_s->radio)
+ return;
+
+ dl_list_for_each_safe(work, tmp, &wpa_s->radio->work,
+ struct wpa_radio_work, list) {
+ struct wpa_external_work *ework;
+
+ if (os_strncmp(work->type, "ext:", 4) != 0)
+ continue;
+ ework = work->ctx;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Flushing %sexternal radio work %u (%s)",
+ work->started ? " started" : "", ework->id,
+ ework->type);
+ if (work->started)
+ eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
+ work, NULL);
+ os_free(ework);
+ radio_work_done(work);
+ }
+}
+
+
+static void wpas_ctrl_eapol_response(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+}
+
+
+static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val)
+{
+ int *freqs = NULL;
+
+ freqs = freq_range_to_channel_list(wpa_s, val);
+ if (freqs == NULL)
+ return -1;
+
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = freqs;
+
+ return 0;
+}
+
+
+static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params,
+ char *reply, int reply_size, int *reply_len)
+{
+ char *pos;
+
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ *reply_len = -1;
+ return;
+ }
+
+ wpa_s->manual_scan_passive = 0;
+ wpa_s->manual_scan_use_id = 0;
+ wpa_s->manual_scan_only_new = 0;
+
+ if (params) {
+ if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
+ wpa_s->scan_res_handler = scan_only_handler;
+
+ pos = os_strstr(params, "freq=");
+ if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) {
+ *reply_len = -1;
+ return;
+ }
+
+ pos = os_strstr(params, "passive=");
+ if (pos)
+ wpa_s->manual_scan_passive = !!atoi(pos + 8);
+
+ pos = os_strstr(params, "use_id=");
+ if (pos)
+ wpa_s->manual_scan_use_id = atoi(pos + 7);
+
+ pos = os_strstr(params, "only_new=1");
+ if (pos)
+ wpa_s->manual_scan_only_new = 1;
+ } else {
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = NULL;
+ if (wpa_s->scan_res_handler == scan_only_handler)
+ wpa_s->scan_res_handler = NULL;
+ }
+
+ if (!wpa_s->sched_scanning && !wpa_s->scanning &&
+ ((wpa_s->wpa_state <= WPA_SCANNING) ||
+ (wpa_s->wpa_state == WPA_COMPLETED))) {
+ wpa_s->normal_scans = 0;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ if (wpa_s->manual_scan_use_id) {
+ wpa_s->manual_scan_id++;
+ wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
+ wpa_s->manual_scan_id);
+ *reply_len = os_snprintf(reply, reply_size, "%u\n",
+ wpa_s->manual_scan_id);
+ }
+ } else if (wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ if (wpa_s->manual_scan_use_id) {
+ wpa_s->manual_scan_id++;
+ *reply_len = os_snprintf(reply, reply_size, "%u\n",
+ wpa_s->manual_scan_id);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Assigned scan id %u",
+ wpa_s->manual_scan_id);
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
+ *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+ }
}
{
char *reply;
const int reply_size = 4096;
- int ctrl_rsp = 0;
int reply_len;
if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
- os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
- os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
- os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 ||
- os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
+ os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+ if (wpa_debug_show_keys)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Control interface command '%s'", buf);
+ else
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Control interface command '%s [REMOVED]'",
+ os_strncmp(buf, WPA_CTRL_RSP,
+ os_strlen(WPA_CTRL_RSP)) == 0 ?
+ WPA_CTRL_RSP : "SET_NETWORK");
+ } else if (os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+ os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 ||
+ os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
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;
- wpa_hexdump_ascii(level, "RX ctrl_iface",
- (const u8 *) buf, os_strlen(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))
+ if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
reply_len = -1;
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
+ if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
+ reply_len = -1;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
reply_len = -1;
} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
interworking_stop_fetch_anqp(wpa_s);
- } else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
- if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
- NULL) < 0)
+ } else if (os_strcmp(buf, "INTERWORKING_SELECT") == 0) {
+ if (ctrl_interworking_select(wpa_s, NULL) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "INTERWORKING_SELECT ", 20) == 0) {
+ if (ctrl_interworking_select(wpa_s, buf + 20) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
if (wpa_supplicant_ctrl_iface_ctrl_rsp(
wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
reply_len = -1;
- else
- ctrl_rsp = 1;
+ else {
+ /*
+ * Notify response from timeout to allow the control
+ * interface response to be sent first.
+ */
+ eloop_register_timeout(0, 0, wpas_ctrl_eapol_response,
+ wpa_s, NULL);
+ }
} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
if (wpa_supplicant_reload_configuration(wpa_s))
reply_len = -1;
wpa_supplicant_cancel_scan(wpa_s);
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
- } else if (os_strcmp(buf, "SCAN") == 0 ||
- os_strncmp(buf, "SCAN ", 5) == 0) {
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
- reply_len = -1;
- else {
- if (os_strlen(buf) > 4 &&
- os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0)
- wpa_s->scan_res_handler = scan_only_handler;
- if (!wpa_s->sched_scanning && !wpa_s->scanning &&
- ((wpa_s->wpa_state <= WPA_SCANNING) ||
- (wpa_s->wpa_state == WPA_COMPLETED))) {
- wpa_s->normal_scans = 0;
- wpa_s->scan_req = MANUAL_SCAN_REQ;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else if (wpa_s->sched_scanning) {
- wpa_printf(MSG_DEBUG, "Stop ongoing "
- "sched_scan to allow requested "
- "full scan to proceed");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_s->scan_req = MANUAL_SCAN_REQ;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else {
- wpa_printf(MSG_DEBUG, "Ongoing scan action - "
- "reject new request");
- reply_len = os_snprintf(reply, reply_size,
- "FAIL-BUSY\n");
- }
- }
+ } 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) {
+ wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len);
} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_scan_results(
wpa_s, reply, reply_size);
} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
reply_len = -1;
+ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
+ if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12))
+ reply_len = -1;
#endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
reply_len = -1;
#endif /* CONFIG_AUTOSCAN */
+#ifdef ANDROID
+ } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
+ reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
+ reply_size);
+#endif /* ANDROID */
} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
pmksa_cache_clear_current(wpa_s->wpa);
eapol_sm_request_reauth(wpa_s->eapol);
#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "FLUSH") == 0) {
wpa_supplicant_ctrl_iface_flush(wpa_s);
+ } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
+ reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply,
+ reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
reply_len = 5;
}
- if (ctrl_rsp)
- eapol_sm_notify_ctrl_response(wpa_s->eapol);
-
*resp_len = reply_len;
return reply;
}
{
#ifdef CONFIG_P2P
static const char * cmd[] = {
+ "LIST_NETWORKS",
+ "SAVE_CONFIG",
"P2P_FIND",
"P2P_STOP_FIND",
"P2P_LISTEN",
NULL
};
static const char * prefix[] = {
+#ifdef ANDROID
+ "DRIVER ",
+#endif /* ANDROID */
+ "GET_NETWORK ",
+ "REMOVE_NETWORK ",
+ "SET ",
"P2P_FIND ",
"P2P_CONNECT ",
"P2P_LISTEN ",
"P2P_UNAUTHORIZE ",
"P2P_PRESENCE_REQ ",
"P2P_EXT_LISTEN ",
+ "P2P_REMOVE_CLIENT ",
NULL
};
int found = 0;
}
+static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
+{
+ char *value;
+
+ value = os_strchr(cmd, ' ');
+ if (value == NULL)
+ return -1;
+ *value++ = '\0';
+
+ wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ wifi_display_enable(global, !!atoi(value));
+ return 0;
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ return -1;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
+{
+ int ret = 0;
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (!wpa_s->conf->update_config) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
+ continue;
+ }
+
+ if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
+ ret = 1;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
+ }
+ }
+
+ return ret;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
+static int wpas_global_ctrl_iface_status(struct wpa_global *global,
+ char *buf, size_t buflen)
+{
+ char *pos, *end;
+ int ret;
+ struct wpa_supplicant *wpa_s;
+
+ pos = buf;
+ end = buf + buflen;
+
+#ifdef CONFIG_P2P
+ if (global->p2p && !global->p2p_disabled) {
+ ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+ "\n"
+ "p2p_state=%s\n",
+ MAC2STR(global->p2p_dev_addr),
+ p2p_get_state_txt(global->p2p));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ } else if (global->p2p) {
+ ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+ ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
+ !!global->wifi_display);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ ret = os_snprintf(pos, end - pos, "ifname=%s\n"
+ "address=" MACSTR "\n",
+ wpa_s->ifname, MAC2STR(wpa_s->own_addr));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
char *buf, size_t *resp_len)
{
wpas_notify_suspend(global);
} else if (os_strcmp(buf, "RESUME") == 0) {
wpas_notify_resume(global);
+ } else if (os_strncmp(buf, "SET ", 4) == 0) {
+ if (wpas_global_ctrl_iface_set(global, buf + 4))
+ reply_len = -1;
+#ifndef CONFIG_NO_CONFIG_WRITE
+ } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
+ if (wpas_global_ctrl_iface_save_config(global))
+ reply_len = -1;
+#endif /* CONFIG_NO_CONFIG_WRITE */
+ } else if (os_strcmp(buf, "STATUS") == 0) {
+ reply_len = wpas_global_ctrl_iface_status(global, reply,
+ reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;