/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2013, 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 "blacklist.h"
#include "autoscan.h"
#include "wnm_sta.h"
-
-extern struct wpa_driver_ops *wpa_drivers[];
+#include "offchannel.h"
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,
char *buf, int len);
-
-static int pno_start(struct wpa_supplicant *wpa_s)
-{
- int ret, interval;
- size_t i, num_ssid;
- struct wpa_ssid *ssid;
- struct wpa_driver_scan_params params;
-
- if (wpa_s->pno)
- return 0;
-
- if (wpa_s->wpa_state == WPA_SCANNING) {
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_cancel_scan(wpa_s);
- }
-
- os_memset(¶ms, 0, sizeof(params));
-
- num_ssid = 0;
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- if (!wpas_network_disabled(wpa_s, ssid))
- num_ssid++;
- ssid = ssid->next;
- }
- if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
- wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
- "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
- num_ssid = WPAS_MAX_SCAN_SSIDS;
- }
-
- if (num_ssid == 0) {
- wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
- return -1;
- }
-
- params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
- num_ssid);
- if (params.filter_ssids == NULL)
- return -1;
- i = 0;
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- if (!wpas_network_disabled(wpa_s, ssid)) {
- params.ssids[i].ssid = ssid->ssid;
- params.ssids[i].ssid_len = ssid->ssid_len;
- params.num_ssids++;
- os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
- ssid->ssid_len);
- params.filter_ssids[i].ssid_len = ssid->ssid_len;
- params.num_filter_ssids++;
- i++;
- if (i == num_ssid)
- break;
- }
- ssid = ssid->next;
- }
-
- if (wpa_s->conf->filter_rssi)
- params.filter_rssi = wpa_s->conf->filter_rssi;
-
- interval = wpa_s->conf->sched_scan_interval ?
- wpa_s->conf->sched_scan_interval : 10;
-
- ret = wpa_drv_sched_scan(wpa_s, ¶ms, interval * 1000);
- os_free(params.filter_ssids);
- if (ret == 0)
- wpa_s->pno = 1;
- return ret;
-}
-
-
-static int pno_stop(struct wpa_supplicant *wpa_s)
-{
- int ret = 0;
-
- if (wpa_s->pno) {
- wpa_s->pno = 0;
- ret = wpa_drv_stop_sched_scan(wpa_s);
- }
-
- if (wpa_s->wpa_state == WPA_SCANNING)
- wpa_supplicant_req_scan(wpa_s, 0, 0);
-
- return ret;
-}
-
-
static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
{
char *pos;
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>
*/
wps_testing_dummy_cred = atoi(value);
wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
wps_testing_dummy_cred);
+ } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
+ wps_corrupt_pkhash = atoi(value);
+ wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
+ wps_corrupt_pkhash);
#endif /* CONFIG_WPS_TESTING */
} 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);
#endif /* CONFIG_TDLS */
} else if (os_strcasecmp(cmd, "pno") == 0) {
if (atoi(value))
- ret = pno_start(wpa_s);
+ ret = wpas_start_pno(wpa_s);
else
- ret = pno_stop(wpa_s);
+ ret = wpas_stop_pno(wpa_s);
} else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
int disabled = atoi(value);
if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
- wifi_display_enable(wpa_s->global, !!atoi(value));
+ int enabled = !!atoi(value);
+ if (enabled && !wpa_s->global->p2p)
+ ret = -1;
+ else
+ wifi_display_enable(wpa_s->global, enabled);
#endif /* CONFIG_WIFI_DISPLAY */
} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
ret = set_bssid_filter(wpa_s, value);
ret = set_disallow_aps(wpa_s, value);
} else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
wpa_s->no_keep_alive = !!atoi(value);
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
+ wpa_s->ext_mgmt_frame_handling = !!atoi(value);
+#endif /* CONFIG_TESTING_OPTIONS */
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
wpa_s->conf->country[1]);
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
- res = os_snprintf(buf, buflen, "%d",
- wpa_s->global->wifi_display);
+ int enabled;
+ if (wpa_s->global->p2p == NULL ||
+ wpa_s->global->p2p_disabled)
+ enabled = 0;
+ else
+ enabled = wpa_s->global->wifi_display;
+ res = os_snprintf(buf, buflen, "%d", enabled);
if (res < 0 || (unsigned int) res >= buflen)
return -1;
return res;
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))
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " 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_TEARDOWN, peer);
+
if (wpa_tdls_is_external_setup(wpa_s->wpa))
ret = wpa_tdls_teardown_link(
wpa_s->wpa, peer,
else if (hwaddr_aton(cmd, bssid))
return -1;
- return wpas_wps_start_nfc(wpa_s, _bssid);
+ return wpas_wps_start_nfc(wpa_s, NULL, _bssid, NULL, 0, 0, NULL, NULL,
+ 0, 0);
}
size_t len;
struct wpabuf *buf;
int ret;
+ char *freq;
+ int forced_freq = 0;
+
+ freq = strstr(pos, " freq=");
+ if (freq) {
+ *freq = '\0';
+ freq += 6;
+ forced_freq = atoi(freq);
+ }
len = os_strlen(pos);
if (len & 0x01)
return -1;
}
- ret = wpas_wps_nfc_tag_read(wpa_s, buf);
+ ret = wpas_wps_nfc_tag_read(wpa_s, buf, forced_freq);
wpabuf_free(buf);
return ret;
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;
}
+#ifdef CONFIG_P2P
+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;
+}
+#endif /* CONFIG_P2P */
+
+
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);
}
+#ifdef CONFIG_P2P
+ if (os_strcmp(pos, "P2P-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_req_p2p(
+ wpa_s, reply, max_len, ndef);
+ }
+#endif /* CONFIG_P2P */
+
return -1;
}
}
+#ifdef CONFIG_P2P
+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;
+}
+#endif /* CONFIG_P2P */
+
+
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);
}
- return -1;
-}
-
-
-static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
- char *cmd, char *reply,
- size_t max_len)
-{
- size_t len;
- struct wpabuf *buf;
- int ret;
-
- len = os_strlen(cmd);
- if (len & 0x01)
- return -1;
- len /= 2;
-
- buf = wpabuf_alloc(len);
- if (buf == NULL)
- return -1;
- if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
- wpabuf_free(buf);
- return -1;
+#ifdef CONFIG_P2P
+ if (os_strcmp(pos, "P2P-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_p2p(
+ wpa_s, reply, max_len, ndef, 0);
}
- ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
- wpabuf_free(buf);
+ if (os_strcmp(pos, "P2P-CR-TAG") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_p2p(
+ wpa_s, reply, max_len, ndef, 1);
+ }
+#endif /* CONFIG_P2P */
- return ret;
+ return -1;
}
struct wpabuf *req, *sel;
int ret;
char *pos, *role, *type, *pos2;
+#ifdef CONFIG_P2P
+ char *freq;
+ int forced_freq = 0;
+
+ freq = strstr(cmd, " freq=");
+ if (freq) {
+ *freq = '\0';
+ freq += 6;
+ forced_freq = atoi(freq);
+ }
+#endif /* CONFIG_P2P */
role = cmd;
pos = os_strchr(role, ' ');
- if (pos == NULL)
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Missing type in handover report");
return -1;
+ }
*pos++ = '\0';
type = pos;
pos = os_strchr(type, ' ');
- if (pos == NULL)
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Missing request message in handover report");
return -1;
+ }
*pos++ = '\0';
pos2 = os_strchr(pos, ' ');
- if (pos2 == NULL)
+ if (pos2 == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Missing select message in handover report");
return -1;
+ }
*pos2++ = '\0';
len = os_strlen(pos);
- if (len & 0x01)
+ if (len & 0x01) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid request message length in handover report");
return -1;
+ }
len /= 2;
req = wpabuf_alloc(len);
- if (req == NULL)
+ if (req == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for request message");
return -1;
+ }
if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid request message hexdump in handover report");
wpabuf_free(req);
return -1;
}
len = os_strlen(pos2);
if (len & 0x01) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid select message length in handover report");
wpabuf_free(req);
return -1;
}
sel = wpabuf_alloc(len);
if (sel == NULL) {
+ wpa_printf(MSG_DEBUG, "NFC: Failed to allocate memory for select message");
wpabuf_free(req);
return -1;
}
if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+ wpa_printf(MSG_DEBUG, "NFC: Invalid select message hexdump in handover report");
wpabuf_free(req);
wpabuf_free(sel);
return -1;
}
+ wpa_printf(MSG_DEBUG, "NFC: Connection handover reported - role=%s type=%s req_len=%d sel_len=%d",
+ role, type, (int) wpabuf_len(req), (int) wpabuf_len(sel));
+
if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
+#ifdef CONFIG_AP
+ } 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);
+#endif /* CONFIG_AP */
+#ifdef CONFIG_P2P
+ } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel, 0);
+ } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel,
+ forced_freq);
+#endif /* CONFIG_P2P */
} else {
wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
"reported: role=%s type=%s", role, type);
wpabuf_free(req);
wpabuf_free(sel);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "NFC: Failed to process reported handover messages");
+
return ret;
}
{
char *pos, *end, tmp[30];
int res, verbose, wps, ret;
+#ifdef CONFIG_HS20
+ const u8 *hs20;
+#endif /* CONFIG_HS20 */
if (os_strcmp(params, "-DRIVER") == 0)
return wpa_drv_status(wpa_s, buf, buflen);
#ifdef CONFIG_HS20
if (wpa_s->current_bss &&
- wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
+ (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss,
+ HS20_IE_VENDOR_TYPE)) &&
wpa_s->wpa_proto == WPA_PROTO_RSN &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
- ret = os_snprintf(pos, end - pos, "hs20=1\n");
+ int release = 1;
+ if (hs20[1] >= 5) {
+ u8 rel_num = (hs20[6] & 0xf0) >> 4;
+ release = rel_num + 1;
+ }
+ ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
if (wpa_s->current_ssid->parent_cred != cred)
continue;
- if (!cred->domain)
- continue;
- for (i = 0; i < cred->num_domain; i++) {
+ if (cred->provisioning_sp) {
ret = os_snprintf(pos, end - pos,
- "home_sp=%s\n",
- cred->domain[i]);
+ "provisioning_sp=%s\n",
+ cred->provisioning_sp);
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
}
+ if (!cred->domain)
+ goto no_domain;
+
+ i = 0;
+ if (wpa_s->current_bss && wpa_s->current_bss->anqp) {
+ struct wpabuf *names =
+ wpa_s->current_bss->anqp->domain_name;
+ for (i = 0; names && i < cred->num_domain; i++)
+ {
+ if (domain_name_list_contains(
+ names, cred->domain[i], 1))
+ break;
+ }
+ if (i == cred->num_domain)
+ i = 0; /* show first entry by default */
+ }
+ ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
+ cred->domain[i]);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ no_domain:
if (wpa_s->current_bss == NULL ||
wpa_s->current_bss->anqp == NULL)
res = -1;
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, size_t ie_len)
{
struct wpa_ie_data data;
- int first, ret;
+ char *start;
+ int ret;
ret = os_snprintf(pos, end - pos, "[%s-", proto);
if (ret < 0 || ret >= end - pos)
return pos;
}
- first = 1;
+ start = pos;
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
- ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sEAP",
+ pos == start ? "" : "+");
if (ret < 0 || ret >= end - pos)
return pos;
pos += ret;
- first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
- ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sPSK",
+ pos == start ? "" : "+");
if (ret < 0 || ret >= end - pos)
return pos;
pos += ret;
- first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sNone",
+ pos == start ? "" : "+");
if (ret < 0 || ret >= end - pos)
return pos;
pos += ret;
- first = 0;
}
#ifdef CONFIG_IEEE80211R
if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "%sFT/EAP",
- first ? "" : "+");
+ pos == start ? "" : "+");
if (ret < 0 || ret >= end - pos)
return pos;
pos += ret;
- first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, "%sFT/PSK",
- first ? "" : "+");
+ pos == start ? "" : "+");
if (ret < 0 || ret >= end - pos)
return pos;
pos += ret;
- first = 0;
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
- first ? "" : "+");
+ pos == start ? "" : "+");
if (ret < 0 || ret >= end - pos)
return pos;
pos += ret;
- first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
- first ? "" : "+");
+ pos == start ? "" : "+");
if (ret < 0 || ret >= end - pos)
return pos;
pos += ret;
- first = 0;
}
#endif /* CONFIG_IEEE80211W */
int id;
struct wpa_cred *cred, *prev;
- /* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
+ /* cmd: "<cred id>", "all", "sp_fqdn=<FQDN>", or
+ * "provisioning_sp=<FQDN> */
if (os_strcmp(cmd, "all") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
cred = wpa_s->conf->cred;
return 0;
}
+ if (os_strncmp(cmd, "provisioning_sp=", 16) == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED provisioning SP FQDN '%s'",
+ cmd + 16);
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ prev = cred;
+ cred = cred->next;
+ if (prev->provisioning_sp &&
+ os_strcmp(prev->provisioning_sp, cmd + 16) == 0)
+ wpas_ctrl_remove_cred(wpa_s, prev);
+ }
+ return 0;
+ }
+
id = atoi(cmd);
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
#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;
+ int ret;
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",
+ pos == buf ? "" : " ",
+ ciphers[i].name);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
}
return pos - buf;
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
- int ret, first = 1;
+ int ret;
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",
+ pos == buf ? "" : " ",
+ ciphers[i].name);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
}
return pos - buf;
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
- int ret, first = 1;
+ int ret;
char *pos, *end;
size_t len;
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sRSN",
+ pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- first = 0;
}
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
- ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sWPA",
+ pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- first = 0;
}
return pos - buf;
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
- int ret, first = 1;
+ int ret;
char *pos, *end;
size_t len;
}
if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
- ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sOPEN",
+ pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- first = 0;
}
if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
ret = os_snprintf(pos, end - pos, "%sSHARED",
- first ? "" : " ");
+ pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- first = 0;
}
if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
- ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sLEAP",
+ pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- first = 0;
}
return pos - buf;
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
- int ret, first = 1;
+ int ret;
char *pos, *end;
size_t len;
}
if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
- ret = os_snprintf(pos, end - pos, "%sIBSS", first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sIBSS",
+ pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- first = 0;
}
if (capa->flags & WPA_DRIVER_FLAGS_AP) {
- ret = os_snprintf(pos, end - pos, "%sAP", first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sAP",
+ pos == buf ? "" : " ");
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- first = 0;
}
return pos - buf;
for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
- ret = os_snprintf(pos, end - pos, " %d = %d MHz%s\n",
+ ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
chnl[i].chan, chnl[i].freq,
chnl[i].flag & HOSTAPD_CHAN_NO_IBSS ?
- " (NO_IBSS)" : "");
+ " (NO_IBSS)" : "",
+ chnl[i].flag & HOSTAPD_CHAN_RADAR ?
+ " (DFS)" : "");
+
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
}
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)
WFD_IE_VENDOR_TYPE);
if (wfd) {
ret = os_snprintf(pos, end - pos, "wfd_subelems=");
- if (ret < 0 || ret >= end - pos)
+ if (ret < 0 || ret >= end - pos) {
+ wpabuf_free(wfd);
return 0;
+ }
pos += ret;
pos += wpa_snprintf_hex(pos, end - pos,
anqp->hs20_wan_metrics);
pos = anqp_add_hex(pos, end, "hs20_connection_capability",
anqp->hs20_connection_capability);
+ pos = anqp_add_hex(pos, end, "hs20_operating_class",
+ anqp->hs20_operating_class);
+ pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
+ anqp->hs20_osu_providers_list);
#endif /* CONFIG_HS20 */
}
#endif /* CONFIG_INTERWORKING */
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, "delay=");
+ 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;
search_delay = atoi(pos);
} 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,
- 0);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 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;
}
return 0;
}
+#ifdef CONFIG_WPS_NFC
+ if (os_strcmp(cmd, "nfc_tag") == 0)
+ return wpas_p2p_nfc_tag_enabled(wpa_s, !!atoi(param));
+#endif /* CONFIG_WPS_NFC */
+
+ if (os_strcmp(cmd, "disable_ip_addr_req") == 0) {
+ wpa_s->p2p_disable_ip_addr_req = !!atoi(param);
+ return 0;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
cmd);
#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 */
return ret;
}
+
+static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 dst_addr[ETH_ALEN];
+ int used;
+ char *icon;
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+
+ while (cmd[used] == ' ')
+ used++;
+ icon = &cmd[used];
+
+ wpa_s->fetch_osu_icon_in_progress = 0;
+ return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
+ (u8 *) icon, os_strlen(icon));
+}
+
#endif /* CONFIG_HS20 */
}
+#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 int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ int ret;
+ char *pos;
+ u8 *data = NULL;
+ unsigned int vendor_id, subcmd;
+ struct wpabuf *reply;
+ size_t data_len = 0;
+
+ /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
+ vendor_id = strtoul(cmd, &pos, 16);
+ if (!isblank(*pos))
+ return -EINVAL;
+
+ subcmd = strtoul(pos, &pos, 10);
+
+ if (*pos != '\0') {
+ if (!isblank(*pos++))
+ return -EINVAL;
+ data_len = os_strlen(pos);
+ }
+
+ if (data_len) {
+ data_len /= 2;
+ data = os_malloc(data_len);
+ if (!data)
+ return -ENOBUFS;
+
+ if (hexstr2bin(pos, data, data_len)) {
+ wpa_printf(MSG_DEBUG,
+ "Vendor command: wrong parameter format");
+ os_free(data);
+ return -EINVAL;
+ }
+ }
+
+ reply = wpabuf_alloc((buflen - 1) / 2);
+ if (!reply) {
+ os_free(data);
+ return -ENOBUFS;
+ }
+
+ ret = wpa_drv_vendor_cmd(wpa_s, vendor_id, subcmd, data, data_len,
+ reply);
+
+ if (ret == 0)
+ ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
+ wpabuf_len(reply));
+
+ wpabuf_free(reply);
+ os_free(data);
+
+ return ret;
+}
+
+
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;
+ wpa_s->p2p_disable_ip_addr_req = 0;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS_TESTING
wps_version_number = 0x20;
wps_testing_dummy_cred = 0;
+ wps_corrupt_pkhash = 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_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_works(wpa_s, NULL, 1);
+
+ wpa_s->next_ssid = NULL;
+
+#ifdef CONFIG_INTERWORKING
+ hs20_cancel_fetch_osu(wpa_s);
+#endif /* CONFIG_INTERWORKING */
+
+ wpa_s->ext_mgmt_frame_handling = 0;
}
+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) {
+ if (work->started)
+ eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
+ work, NULL);
+
+ 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");
+ }
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+
+static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result
+ result)
+{
+ wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR
+ " src=" MACSTR " bssid=" MACSTR " result=%s",
+ freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+ result == OFFCHANNEL_SEND_ACTION_SUCCESS ?
+ "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ?
+ "NO_ACK" : "FAILED"));
+}
+
+
+static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN];
+ int res, used;
+ int freq = 0, no_cck = 0, wait_time = 0;
+
+ /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
+ * <action=Action frame payload> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, da);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+ used = hwaddr_aton2(pos, bssid);
+ if (used < 0)
+ return -1;
+ pos += used;
+
+ param = os_strstr(pos, " freq=");
+ if (param) {
+ param += 6;
+ freq = atoi(param);
+ }
+
+ param = os_strstr(pos, " no_cck=");
+ if (param) {
+ param += 8;
+ no_cck = atoi(param);
+ }
+
+ param = os_strstr(pos, " wait_time=");
+ if (param) {
+ param += 11;
+ wait_time = atoi(param);
+ }
+
+ param = os_strstr(pos, " action=");
+ if (param == NULL)
+ return -1;
+ param += 8;
+
+ len = os_strlen(param);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(param, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid,
+ buf, len, wait_time,
+ wpas_ctrl_iface_mgmt_tx_cb, no_cck);
+ os_free(buf);
+ return res;
+}
+
+
+static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting");
+ offchannel_send_action_done(wpa_s);
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
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);
}
reply_len = -1;
else
wpas_request_connection(wpa_s);
+ } else if (os_strcmp(buf, "REATTACH") == 0) {
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED ||
+ !wpa_s->current_ssid)
+ reply_len = -1;
+ else {
+ wpa_s->reattach = 1;
+ wpas_request_connection(wpa_s);
+ }
} else if (os_strcmp(buf, "RECONNECT") == 0) {
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
reply_len = wpas_ctrl_nfc_get_handover_sel(
wpa_s, buf + 21, reply, reply_size);
- } else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
- reply_len = wpas_ctrl_nfc_rx_handover_req(
- wpa_s, buf + 20, reply, reply_size);
} else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
reply_len = -1;
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))
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)
} else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
+ if (hs20_icon_request(wpa_s, buf + 18) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
+ if (hs20_fetch_osu(wpa_s) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
+ hs20_cancel_fetch_osu(wpa_s);
#endif /* CONFIG_HS20 */
} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 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_strncmp(buf, "VENDOR ", 7) == 0) {
+ reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply,
+ reply_size);
} 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);
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
+ if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
+ wpas_ctrl_iface_mgmt_tx_done(wpa_s);
+#endif /* CONFIG_TESTING_OPTIONS */
} 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 ",
} else if (os_strcmp(buf, "STATUS") == 0) {
reply_len = wpas_global_ctrl_iface_status(global, reply,
reply_size);
+#ifdef CONFIG_MODULE_TESTS
+ } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
+ int wpas_module_tests(void);
+ if (wpas_module_tests() < 0)
+ reply_len = -1;
+#endif /* CONFIG_MODULE_TESTS */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;