mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-28 18:28:23 -05:00
d601247ca9
An optional parameter, p2p_dev_addr, can now be given to WPS_PBC command on P2P GO to indicate that only the P2P device with the specified P2P Device Address is allowed to connect using PBC. If any other device tries to use PBC, a session overlap is indicated and the negotiation is rejected with M2D. The command format for specifying the address is "WPS_PBC p2p_dev_addr=<address>", e.g., WPS_PBC p2p_dev_addr=02:03:04:05:06:07 In addition, show the PBC session overlap indication as a WPS failure event on an AP/GO interface. This particular new case shows up as "WPS-FAIL msg=4 config_error=12".
3363 lines
80 KiB
C
3363 lines
80 KiB
C
/*
|
|
* WPA Supplicant / Control interface (shared code for all backends)
|
|
* Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* Alternatively, this software may be distributed under the terms of BSD
|
|
* license.
|
|
*
|
|
* See README and COPYING for more details.
|
|
*/
|
|
|
|
#include "utils/includes.h"
|
|
|
|
#include "utils/common.h"
|
|
#include "utils/eloop.h"
|
|
#include "common/version.h"
|
|
#include "common/ieee802_11_defs.h"
|
|
#include "common/wpa_ctrl.h"
|
|
#include "eap_peer/eap.h"
|
|
#include "eapol_supp/eapol_supp_sm.h"
|
|
#include "rsn_supp/wpa.h"
|
|
#include "rsn_supp/preauth.h"
|
|
#include "rsn_supp/pmksa_cache.h"
|
|
#include "l2_packet/l2_packet.h"
|
|
#include "wps/wps.h"
|
|
#include "config.h"
|
|
#include "wpa_supplicant_i.h"
|
|
#include "driver_i.h"
|
|
#include "wps_supplicant.h"
|
|
#include "ibss_rsn.h"
|
|
#include "ap.h"
|
|
#include "p2p_supplicant.h"
|
|
#include "p2p/p2p.h"
|
|
#include "notify.h"
|
|
#include "bss.h"
|
|
#include "scan.h"
|
|
#include "ctrl_iface.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,
|
|
char *buf, int len);
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
char *value;
|
|
int ret = 0;
|
|
|
|
value = os_strchr(cmd, ' ');
|
|
if (value == NULL)
|
|
return -1;
|
|
*value++ = '\0';
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
|
|
if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
|
|
eapol_sm_configure(wpa_s->eapol,
|
|
atoi(value), -1, -1, -1);
|
|
} else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
|
|
eapol_sm_configure(wpa_s->eapol,
|
|
-1, atoi(value), -1, -1);
|
|
} else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
|
|
eapol_sm_configure(wpa_s->eapol,
|
|
-1, -1, atoi(value), -1);
|
|
} else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
|
|
eapol_sm_configure(wpa_s->eapol,
|
|
-1, -1, -1, atoi(value));
|
|
} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
|
|
if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
|
|
atoi(value)))
|
|
ret = -1;
|
|
} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
|
|
0) {
|
|
if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
|
|
atoi(value)))
|
|
ret = -1;
|
|
} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
|
|
if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
|
|
ret = -1;
|
|
} else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
|
|
wpa_s->wps_fragment_size = atoi(value);
|
|
#ifdef CONFIG_WPS_TESTING
|
|
} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
|
|
long int val;
|
|
val = strtol(value, NULL, 0);
|
|
if (val < 0 || val > 0xff) {
|
|
ret = -1;
|
|
wpa_printf(MSG_DEBUG, "WPS: Invalid "
|
|
"wps_version_number %ld", val);
|
|
} else {
|
|
wps_version_number = val;
|
|
wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
|
|
"version %u.%u",
|
|
(wps_version_number & 0xf0) >> 4,
|
|
wps_version_number & 0x0f);
|
|
}
|
|
} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
|
|
wps_testing_dummy_cred = atoi(value);
|
|
wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
|
|
wps_testing_dummy_cred);
|
|
#endif /* CONFIG_WPS_TESTING */
|
|
} else if (os_strcasecmp(cmd, "ampdu") == 0) {
|
|
if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
|
|
ret = -1;
|
|
} else {
|
|
value[-1] = '=';
|
|
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
|
|
if (ret == 0)
|
|
wpa_supplicant_update_config(wpa_s);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
|
|
char *cmd, char *buf, size_t buflen)
|
|
{
|
|
int res;
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
|
|
|
|
if (os_strcmp(cmd, "version") == 0) {
|
|
res = os_snprintf(buf, buflen, "%s", VERSION_STR);
|
|
if (res < 0 || (unsigned int) res >= buflen)
|
|
return -1;
|
|
return res;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
#ifdef IEEE8021X_EAPOL
|
|
static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
|
|
char *addr)
|
|
{
|
|
u8 bssid[ETH_ALEN];
|
|
struct wpa_ssid *ssid = wpa_s->current_ssid;
|
|
|
|
if (hwaddr_aton(addr, bssid)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
|
|
"'%s'", addr);
|
|
return -1;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
|
|
rsn_preauth_deinit(wpa_s->wpa);
|
|
if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* IEEE8021X_EAPOL */
|
|
|
|
|
|
#ifdef CONFIG_PEERKEY
|
|
/* MLME-STKSTART.request(peer) */
|
|
static int wpa_supplicant_ctrl_iface_stkstart(
|
|
struct wpa_supplicant *wpa_s, char *addr)
|
|
{
|
|
u8 peer[ETH_ALEN];
|
|
|
|
if (hwaddr_aton(addr, peer)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
|
|
"address '%s'", addr);
|
|
return -1;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
|
|
MAC2STR(peer));
|
|
|
|
return wpa_sm_stkstart(wpa_s->wpa, peer);
|
|
}
|
|
#endif /* CONFIG_PEERKEY */
|
|
|
|
|
|
#ifdef CONFIG_IEEE80211R
|
|
static int wpa_supplicant_ctrl_iface_ft_ds(
|
|
struct wpa_supplicant *wpa_s, char *addr)
|
|
{
|
|
u8 target_ap[ETH_ALEN];
|
|
struct wpa_bss *bss;
|
|
const u8 *mdie;
|
|
|
|
if (hwaddr_aton(addr, target_ap)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
|
|
"address '%s'", addr);
|
|
return -1;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
|
|
|
|
bss = wpa_bss_get_bssid(wpa_s, target_ap);
|
|
if (bss)
|
|
mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
|
|
else
|
|
mdie = NULL;
|
|
|
|
return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
|
|
}
|
|
#endif /* CONFIG_IEEE80211R */
|
|
|
|
|
|
#ifdef CONFIG_WPS
|
|
static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
u8 bssid[ETH_ALEN], *_bssid = bssid;
|
|
u8 p2p_dev_addr[ETH_ALEN], *_p2p_dev_addr = NULL;
|
|
|
|
if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
|
|
_bssid = NULL;
|
|
#ifdef CONFIG_P2P
|
|
} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
|
|
if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
|
|
"P2P Device Address '%s'",
|
|
cmd + 13);
|
|
return -1;
|
|
}
|
|
_p2p_dev_addr = p2p_dev_addr;
|
|
#endif /* CONFIG_P2P */
|
|
} else if (hwaddr_aton(cmd, bssid)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
|
|
cmd);
|
|
return -1;
|
|
}
|
|
|
|
#ifdef CONFIG_AP
|
|
if (wpa_s->ap_iface)
|
|
return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
|
|
#endif /* CONFIG_AP */
|
|
|
|
return wpas_wps_start_pbc(wpa_s, _bssid, 0);
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
|
|
char *cmd, char *buf,
|
|
size_t buflen)
|
|
{
|
|
u8 bssid[ETH_ALEN], *_bssid = bssid;
|
|
char *pin;
|
|
int ret;
|
|
|
|
pin = os_strchr(cmd, ' ');
|
|
if (pin)
|
|
*pin++ = '\0';
|
|
|
|
if (os_strcmp(cmd, "any") == 0)
|
|
_bssid = NULL;
|
|
else if (hwaddr_aton(cmd, bssid)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
|
|
cmd);
|
|
return -1;
|
|
}
|
|
|
|
#ifdef CONFIG_AP
|
|
if (wpa_s->ap_iface)
|
|
return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
|
|
buf, buflen);
|
|
#endif /* CONFIG_AP */
|
|
|
|
if (pin) {
|
|
ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
|
|
DEV_PW_DEFAULT);
|
|
if (ret < 0)
|
|
return -1;
|
|
ret = os_snprintf(buf, buflen, "%s", pin);
|
|
if (ret < 0 || (size_t) ret >= buflen)
|
|
return -1;
|
|
return ret;
|
|
}
|
|
|
|
ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
|
|
if (ret < 0)
|
|
return -1;
|
|
|
|
/* Return the generated PIN */
|
|
ret = os_snprintf(buf, buflen, "%08d", ret);
|
|
if (ret < 0 || (size_t) ret >= buflen)
|
|
return -1;
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_wps_check_pin(
|
|
struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
|
|
{
|
|
char pin[9];
|
|
size_t len;
|
|
char *pos;
|
|
int ret;
|
|
|
|
wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
|
|
(u8 *) cmd, os_strlen(cmd));
|
|
for (pos = cmd, len = 0; *pos != '\0'; pos++) {
|
|
if (*pos < '0' || *pos > '9')
|
|
continue;
|
|
pin[len++] = *pos;
|
|
if (len == 9) {
|
|
wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
|
|
return -1;
|
|
}
|
|
}
|
|
if (len != 4 && len != 8) {
|
|
wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
|
|
return -1;
|
|
}
|
|
pin[len] = '\0';
|
|
|
|
if (len == 8) {
|
|
unsigned int pin_val;
|
|
pin_val = atoi(pin);
|
|
if (!wps_pin_valid(pin_val)) {
|
|
wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
|
|
ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
|
|
if (ret < 0 || (size_t) ret >= buflen)
|
|
return -1;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ret = os_snprintf(buf, buflen, "%s", pin);
|
|
if (ret < 0 || (size_t) ret >= buflen)
|
|
return -1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_WPS_OOB
|
|
static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
char *path, *method, *name;
|
|
|
|
path = os_strchr(cmd, ' ');
|
|
if (path == NULL)
|
|
return -1;
|
|
*path++ = '\0';
|
|
|
|
method = os_strchr(path, ' ');
|
|
if (method == NULL)
|
|
return -1;
|
|
*method++ = '\0';
|
|
|
|
name = os_strchr(method, ' ');
|
|
if (name != NULL)
|
|
*name++ = '\0';
|
|
|
|
return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
|
|
}
|
|
#endif /* CONFIG_WPS_OOB */
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
u8 bssid[ETH_ALEN];
|
|
char *pin;
|
|
char *new_ssid;
|
|
char *new_auth;
|
|
char *new_encr;
|
|
char *new_key;
|
|
struct wps_new_ap_settings ap;
|
|
|
|
pin = os_strchr(cmd, ' ');
|
|
if (pin == NULL)
|
|
return -1;
|
|
*pin++ = '\0';
|
|
|
|
if (hwaddr_aton(cmd, bssid)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
|
|
cmd);
|
|
return -1;
|
|
}
|
|
|
|
new_ssid = os_strchr(pin, ' ');
|
|
if (new_ssid == NULL)
|
|
return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
|
|
*new_ssid++ = '\0';
|
|
|
|
new_auth = os_strchr(new_ssid, ' ');
|
|
if (new_auth == NULL)
|
|
return -1;
|
|
*new_auth++ = '\0';
|
|
|
|
new_encr = os_strchr(new_auth, ' ');
|
|
if (new_encr == NULL)
|
|
return -1;
|
|
*new_encr++ = '\0';
|
|
|
|
new_key = os_strchr(new_encr, ' ');
|
|
if (new_key == NULL)
|
|
return -1;
|
|
*new_key++ = '\0';
|
|
|
|
os_memset(&ap, 0, sizeof(ap));
|
|
ap.ssid_hex = new_ssid;
|
|
ap.auth = new_auth;
|
|
ap.encr = new_encr;
|
|
ap.key_hex = new_key;
|
|
return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_AP
|
|
static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
|
|
char *cmd, char *buf,
|
|
size_t buflen)
|
|
{
|
|
int timeout = 300;
|
|
char *pos;
|
|
const char *pin_txt;
|
|
|
|
if (!wpa_s->ap_iface)
|
|
return -1;
|
|
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos)
|
|
*pos++ = '\0';
|
|
|
|
if (os_strcmp(cmd, "disable") == 0) {
|
|
wpas_wps_ap_pin_disable(wpa_s);
|
|
return os_snprintf(buf, buflen, "OK\n");
|
|
}
|
|
|
|
if (os_strcmp(cmd, "random") == 0) {
|
|
if (pos)
|
|
timeout = atoi(pos);
|
|
pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
|
|
if (pin_txt == NULL)
|
|
return -1;
|
|
return os_snprintf(buf, buflen, "%s", pin_txt);
|
|
}
|
|
|
|
if (os_strcmp(cmd, "get") == 0) {
|
|
pin_txt = wpas_wps_ap_pin_get(wpa_s);
|
|
if (pin_txt == NULL)
|
|
return -1;
|
|
return os_snprintf(buf, buflen, "%s", pin_txt);
|
|
}
|
|
|
|
if (os_strcmp(cmd, "set") == 0) {
|
|
char *pin;
|
|
if (pos == NULL)
|
|
return -1;
|
|
pin = pos;
|
|
pos = os_strchr(pos, ' ');
|
|
if (pos) {
|
|
*pos++ = '\0';
|
|
timeout = atoi(pos);
|
|
}
|
|
if (os_strlen(pin) > buflen)
|
|
return -1;
|
|
if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
|
|
return -1;
|
|
return os_snprintf(buf, buflen, "%s", pin);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
#endif /* CONFIG_AP */
|
|
|
|
|
|
#ifdef CONFIG_WPS_ER
|
|
static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
char *uuid = cmd, *pin, *pos;
|
|
u8 addr_buf[ETH_ALEN], *addr = NULL;
|
|
pin = os_strchr(uuid, ' ');
|
|
if (pin == NULL)
|
|
return -1;
|
|
*pin++ = '\0';
|
|
pos = os_strchr(pin, ' ');
|
|
if (pos) {
|
|
*pos++ = '\0';
|
|
if (hwaddr_aton(pos, addr_buf) == 0)
|
|
addr = addr_buf;
|
|
}
|
|
return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
char *uuid = cmd, *pin;
|
|
pin = os_strchr(uuid, ' ');
|
|
if (pin == NULL)
|
|
return -1;
|
|
*pin++ = '\0';
|
|
return wpas_wps_er_learn(wpa_s, uuid, pin);
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_wps_er_set_config(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *uuid = cmd, *id;
|
|
id = os_strchr(uuid, ' ');
|
|
if (id == NULL)
|
|
return -1;
|
|
*id++ = '\0';
|
|
return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_wps_er_config(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *pin;
|
|
char *new_ssid;
|
|
char *new_auth;
|
|
char *new_encr;
|
|
char *new_key;
|
|
struct wps_new_ap_settings ap;
|
|
|
|
pin = os_strchr(cmd, ' ');
|
|
if (pin == NULL)
|
|
return -1;
|
|
*pin++ = '\0';
|
|
|
|
new_ssid = os_strchr(pin, ' ');
|
|
if (new_ssid == NULL)
|
|
return -1;
|
|
*new_ssid++ = '\0';
|
|
|
|
new_auth = os_strchr(new_ssid, ' ');
|
|
if (new_auth == NULL)
|
|
return -1;
|
|
*new_auth++ = '\0';
|
|
|
|
new_encr = os_strchr(new_auth, ' ');
|
|
if (new_encr == NULL)
|
|
return -1;
|
|
*new_encr++ = '\0';
|
|
|
|
new_key = os_strchr(new_encr, ' ');
|
|
if (new_key == NULL)
|
|
return -1;
|
|
*new_key++ = '\0';
|
|
|
|
os_memset(&ap, 0, sizeof(ap));
|
|
ap.ssid_hex = new_ssid;
|
|
ap.auth = new_auth;
|
|
ap.encr = new_encr;
|
|
ap.key_hex = new_key;
|
|
return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
|
|
}
|
|
#endif /* CONFIG_WPS_ER */
|
|
|
|
#endif /* CONFIG_WPS */
|
|
|
|
|
|
#ifdef CONFIG_IBSS_RSN
|
|
static int wpa_supplicant_ctrl_iface_ibss_rsn(
|
|
struct wpa_supplicant *wpa_s, char *addr)
|
|
{
|
|
u8 peer[ETH_ALEN];
|
|
|
|
if (hwaddr_aton(addr, peer)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
|
|
"address '%s'", addr);
|
|
return -1;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
|
|
MAC2STR(peer));
|
|
|
|
return ibss_rsn_start(wpa_s->ibss_rsn, peer);
|
|
}
|
|
#endif /* CONFIG_IBSS_RSN */
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
|
|
char *rsp)
|
|
{
|
|
#ifdef IEEE8021X_EAPOL
|
|
char *pos, *id_pos;
|
|
int id;
|
|
struct wpa_ssid *ssid;
|
|
struct eap_peer_config *eap;
|
|
|
|
pos = os_strchr(rsp, '-');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
id_pos = pos;
|
|
pos = os_strchr(pos, ':');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
id = atoi(id_pos);
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
|
|
wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
|
|
(u8 *) pos, os_strlen(pos));
|
|
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
|
|
"to update", id);
|
|
return -1;
|
|
}
|
|
eap = &ssid->eap;
|
|
|
|
if (os_strcmp(rsp, "IDENTITY") == 0) {
|
|
os_free(eap->identity);
|
|
eap->identity = (u8 *) os_strdup(pos);
|
|
eap->identity_len = os_strlen(pos);
|
|
eap->pending_req_identity = 0;
|
|
if (ssid == wpa_s->current_ssid)
|
|
wpa_s->reassociate = 1;
|
|
} else if (os_strcmp(rsp, "PASSWORD") == 0) {
|
|
os_free(eap->password);
|
|
eap->password = (u8 *) os_strdup(pos);
|
|
eap->password_len = os_strlen(pos);
|
|
eap->pending_req_password = 0;
|
|
if (ssid == wpa_s->current_ssid)
|
|
wpa_s->reassociate = 1;
|
|
} else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
|
|
os_free(eap->new_password);
|
|
eap->new_password = (u8 *) os_strdup(pos);
|
|
eap->new_password_len = os_strlen(pos);
|
|
eap->pending_req_new_password = 0;
|
|
if (ssid == wpa_s->current_ssid)
|
|
wpa_s->reassociate = 1;
|
|
} else if (os_strcmp(rsp, "PIN") == 0) {
|
|
os_free(eap->pin);
|
|
eap->pin = os_strdup(pos);
|
|
eap->pending_req_pin = 0;
|
|
if (ssid == wpa_s->current_ssid)
|
|
wpa_s->reassociate = 1;
|
|
} else if (os_strcmp(rsp, "OTP") == 0) {
|
|
os_free(eap->otp);
|
|
eap->otp = (u8 *) os_strdup(pos);
|
|
eap->otp_len = os_strlen(pos);
|
|
os_free(eap->pending_req_otp);
|
|
eap->pending_req_otp = NULL;
|
|
eap->pending_req_otp_len = 0;
|
|
} else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
|
|
os_free(eap->private_key_passwd);
|
|
eap->private_key_passwd = (u8 *) os_strdup(pos);
|
|
eap->pending_req_passphrase = 0;
|
|
if (ssid == wpa_s->current_ssid)
|
|
wpa_s->reassociate = 1;
|
|
} else {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
#else /* IEEE8021X_EAPOL */
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
|
|
return -1;
|
|
#endif /* IEEE8021X_EAPOL */
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
|
|
const char *params,
|
|
char *buf, size_t buflen)
|
|
{
|
|
char *pos, *end, tmp[30];
|
|
int res, verbose, ret;
|
|
|
|
verbose = os_strcmp(params, "-VERBOSE") == 0;
|
|
pos = buf;
|
|
end = buf + buflen;
|
|
if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
|
|
struct wpa_ssid *ssid = wpa_s->current_ssid;
|
|
ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
|
|
MAC2STR(wpa_s->bssid));
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
if (ssid) {
|
|
u8 *_ssid = ssid->ssid;
|
|
size_t ssid_len = ssid->ssid_len;
|
|
u8 ssid_buf[MAX_SSID_LEN];
|
|
if (ssid_len == 0) {
|
|
int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
|
|
if (_res < 0)
|
|
ssid_len = 0;
|
|
else
|
|
ssid_len = _res;
|
|
_ssid = ssid_buf;
|
|
}
|
|
ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
|
|
wpa_ssid_txt(_ssid, ssid_len),
|
|
ssid->id);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
if (ssid->id_str) {
|
|
ret = os_snprintf(pos, end - pos,
|
|
"id_str=%s\n",
|
|
ssid->id_str);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
switch (ssid->mode) {
|
|
case WPAS_MODE_INFRA:
|
|
ret = os_snprintf(pos, end - pos,
|
|
"mode=station\n");
|
|
break;
|
|
case WPAS_MODE_IBSS:
|
|
ret = os_snprintf(pos, end - pos,
|
|
"mode=IBSS\n");
|
|
break;
|
|
case WPAS_MODE_AP:
|
|
ret = os_snprintf(pos, end - pos,
|
|
"mode=AP\n");
|
|
break;
|
|
case WPAS_MODE_P2P_GO:
|
|
ret = os_snprintf(pos, end - pos,
|
|
"mode=P2P GO\n");
|
|
break;
|
|
case WPAS_MODE_P2P_GROUP_FORMATION:
|
|
ret = os_snprintf(pos, end - pos,
|
|
"mode=P2P GO - group "
|
|
"formation\n");
|
|
break;
|
|
default:
|
|
ret = 0;
|
|
break;
|
|
}
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
#ifdef CONFIG_AP
|
|
if (wpa_s->ap_iface) {
|
|
pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
|
|
end - pos,
|
|
verbose);
|
|
} else
|
|
#endif /* CONFIG_AP */
|
|
pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
|
|
}
|
|
ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
|
|
wpa_supplicant_state_txt(wpa_s->wpa_state));
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
if (wpa_s->l2 &&
|
|
l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
|
|
ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
#ifdef CONFIG_P2P
|
|
if (wpa_s->global->p2p) {
|
|
ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
|
|
"\n", MAC2STR(wpa_s->global->p2p_dev_addr));
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
#endif /* CONFIG_P2P */
|
|
|
|
ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
|
|
MAC2STR(wpa_s->own_addr));
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
|
|
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
|
|
res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
|
|
verbose);
|
|
if (res >= 0)
|
|
pos += res;
|
|
}
|
|
|
|
res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
|
|
if (res >= 0)
|
|
pos += res;
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
char *pos;
|
|
int id;
|
|
struct wpa_ssid *ssid;
|
|
u8 bssid[ETH_ALEN];
|
|
|
|
/* cmd: "<network id> <BSSID>" */
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
id = atoi(cmd);
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
|
|
if (hwaddr_aton(pos, bssid)) {
|
|
wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
|
|
return -1;
|
|
}
|
|
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
|
|
"to update", id);
|
|
return -1;
|
|
}
|
|
|
|
os_memcpy(ssid->bssid, bssid, ETH_ALEN);
|
|
ssid->bssid_set = !is_zero_ether_addr(bssid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_list_networks(
|
|
struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
|
|
{
|
|
char *pos, *end;
|
|
struct wpa_ssid *ssid;
|
|
int ret;
|
|
|
|
pos = buf;
|
|
end = buf + buflen;
|
|
ret = os_snprintf(pos, end - pos,
|
|
"network id / ssid / bssid / flags\n");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
ssid = wpa_s->conf->ssid;
|
|
while (ssid) {
|
|
ret = os_snprintf(pos, end - pos, "%d\t%s",
|
|
ssid->id,
|
|
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
if (ssid->bssid_set) {
|
|
ret = os_snprintf(pos, end - pos, "\t" MACSTR,
|
|
MAC2STR(ssid->bssid));
|
|
} else {
|
|
ret = os_snprintf(pos, end - pos, "\tany");
|
|
}
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
ret = os_snprintf(pos, end - pos, "\t%s%s%s",
|
|
ssid == wpa_s->current_ssid ?
|
|
"[CURRENT]" : "",
|
|
ssid->disabled ? "[DISABLED]" : "",
|
|
ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
|
|
"");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
ret = os_snprintf(pos, end - pos, "\n");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
ssid = ssid->next;
|
|
}
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
|
|
{
|
|
int first = 1, ret;
|
|
ret = os_snprintf(pos, end - pos, "-");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
if (cipher & WPA_CIPHER_NONE) {
|
|
ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
first = 0;
|
|
}
|
|
if (cipher & WPA_CIPHER_WEP40) {
|
|
ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
first = 0;
|
|
}
|
|
if (cipher & WPA_CIPHER_WEP104) {
|
|
ret = os_snprintf(pos, end - pos, "%sWEP104",
|
|
first ? "" : "+");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
first = 0;
|
|
}
|
|
if (cipher & WPA_CIPHER_TKIP) {
|
|
ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
first = 0;
|
|
}
|
|
if (cipher & WPA_CIPHER_CCMP) {
|
|
ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
first = 0;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
|
|
static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
|
|
const u8 *ie, size_t ie_len)
|
|
{
|
|
struct wpa_ie_data data;
|
|
int first, ret;
|
|
|
|
ret = os_snprintf(pos, end - pos, "[%s-", proto);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
|
|
if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
|
|
ret = os_snprintf(pos, end - pos, "?]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
return pos;
|
|
}
|
|
|
|
first = 1;
|
|
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
|
|
ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
|
|
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 ? "" : "+");
|
|
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 ? "" : "+");
|
|
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 ? "" : "+");
|
|
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 ? "" : "+");
|
|
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 ? "" : "+");
|
|
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 ? "" : "+");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
first = 0;
|
|
}
|
|
#endif /* CONFIG_IEEE80211W */
|
|
|
|
pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
|
|
|
|
if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
|
|
ret = os_snprintf(pos, end - pos, "-preauth");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
}
|
|
|
|
ret = os_snprintf(pos, end - pos, "]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos;
|
|
pos += ret;
|
|
|
|
return pos;
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_WPS
|
|
static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
|
|
char *pos, char *end,
|
|
struct wpabuf *wps_ie)
|
|
{
|
|
int ret;
|
|
const char *txt;
|
|
|
|
if (wps_ie == NULL)
|
|
return pos;
|
|
if (wps_is_selected_pbc_registrar(wps_ie))
|
|
txt = "[WPS-PBC]";
|
|
#ifdef CONFIG_WPS2
|
|
else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
|
|
txt = "[WPS-AUTH]";
|
|
#endif /* CONFIG_WPS2 */
|
|
else if (wps_is_selected_pin_registrar(wps_ie))
|
|
txt = "[WPS-PIN]";
|
|
else
|
|
txt = "[WPS]";
|
|
|
|
ret = os_snprintf(pos, end - pos, "%s", txt);
|
|
if (ret >= 0 && ret < end - pos)
|
|
pos += ret;
|
|
wpabuf_free(wps_ie);
|
|
return pos;
|
|
}
|
|
#endif /* CONFIG_WPS */
|
|
|
|
|
|
static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
|
|
char *pos, char *end,
|
|
const struct wpa_bss *bss)
|
|
{
|
|
#ifdef CONFIG_WPS
|
|
struct wpabuf *wps_ie;
|
|
wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
|
|
return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
|
|
#else /* CONFIG_WPS */
|
|
return pos;
|
|
#endif /* CONFIG_WPS */
|
|
}
|
|
|
|
|
|
/* Format one result on one text line into a buffer. */
|
|
static int wpa_supplicant_ctrl_iface_scan_result(
|
|
struct wpa_supplicant *wpa_s,
|
|
const struct wpa_bss *bss, char *buf, size_t buflen)
|
|
{
|
|
char *pos, *end;
|
|
int ret;
|
|
const u8 *ie, *ie2, *p2p;
|
|
|
|
p2p = wpa_bss_get_vendor_ie(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)
|
|
return 0; /* Do not show P2P listen discovery results here */
|
|
|
|
pos = buf;
|
|
end = buf + buflen;
|
|
|
|
ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
|
|
MAC2STR(bss->bssid), bss->freq, bss->level);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
|
|
if (ie)
|
|
pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
|
|
ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
|
|
if (ie2)
|
|
pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
|
|
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
|
|
if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
|
|
ret = os_snprintf(pos, end - pos, "[WEP]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
if (bss->caps & IEEE80211_CAP_IBSS) {
|
|
ret = os_snprintf(pos, end - pos, "[IBSS]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
if (bss->caps & IEEE80211_CAP_ESS) {
|
|
ret = os_snprintf(pos, end - pos, "[ESS]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
if (p2p) {
|
|
ret = os_snprintf(pos, end - pos, "[P2P]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
ret = os_snprintf(pos, end - pos, "\t%s",
|
|
wpa_ssid_txt(bss->ssid, bss->ssid_len));
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
ret = os_snprintf(pos, end - pos, "\n");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_scan_results(
|
|
struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
|
|
{
|
|
char *pos, *end;
|
|
struct wpa_bss *bss;
|
|
int ret;
|
|
|
|
pos = buf;
|
|
end = buf + buflen;
|
|
ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
|
|
"flags / ssid\n");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
|
|
ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
|
|
end - pos);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_select_network(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
int id;
|
|
struct wpa_ssid *ssid;
|
|
|
|
/* cmd: "<network id>" or "any" */
|
|
if (os_strcmp(cmd, "any") == 0) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
|
|
ssid = NULL;
|
|
} else {
|
|
id = atoi(cmd);
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
|
|
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
|
|
"network id=%d", id);
|
|
return -1;
|
|
}
|
|
if (ssid->disabled == 2) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
|
|
"SELECT_NETWORK with persistent P2P group");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
wpa_supplicant_select_network(wpa_s, ssid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_enable_network(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
int id;
|
|
struct wpa_ssid *ssid;
|
|
|
|
/* cmd: "<network id>" or "all" */
|
|
if (os_strcmp(cmd, "all") == 0) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
|
|
ssid = NULL;
|
|
} else {
|
|
id = atoi(cmd);
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
|
|
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
|
|
"network id=%d", id);
|
|
return -1;
|
|
}
|
|
if (ssid->disabled == 2) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
|
|
"ENABLE_NETWORK with persistent P2P group");
|
|
return -1;
|
|
}
|
|
}
|
|
wpa_supplicant_enable_network(wpa_s, ssid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_disable_network(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
int id;
|
|
struct wpa_ssid *ssid;
|
|
|
|
/* cmd: "<network id>" or "all" */
|
|
if (os_strcmp(cmd, "all") == 0) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
|
|
ssid = NULL;
|
|
} else {
|
|
id = atoi(cmd);
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
|
|
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
|
|
"network id=%d", id);
|
|
return -1;
|
|
}
|
|
if (ssid->disabled == 2) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
|
|
"DISABLE_NETWORK with persistent P2P "
|
|
"group");
|
|
return -1;
|
|
}
|
|
}
|
|
wpa_supplicant_disable_network(wpa_s, ssid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_add_network(
|
|
struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
|
|
{
|
|
struct wpa_ssid *ssid;
|
|
int ret;
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
|
|
|
|
ssid = wpa_config_add_network(wpa_s->conf);
|
|
if (ssid == NULL)
|
|
return -1;
|
|
|
|
wpas_notify_network_added(wpa_s, ssid);
|
|
|
|
ssid->disabled = 1;
|
|
wpa_config_set_network_defaults(ssid);
|
|
|
|
ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
|
|
if (ret < 0 || (size_t) ret >= buflen)
|
|
return -1;
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_remove_network(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
int id;
|
|
struct wpa_ssid *ssid;
|
|
|
|
/* cmd: "<network id>" or "all" */
|
|
if (os_strcmp(cmd, "all") == 0) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
|
|
ssid = wpa_s->conf->ssid;
|
|
while (ssid) {
|
|
struct wpa_ssid *remove_ssid = ssid;
|
|
id = ssid->id;
|
|
ssid = ssid->next;
|
|
wpas_notify_network_removed(wpa_s, remove_ssid);
|
|
wpa_config_remove_network(wpa_s->conf, id);
|
|
}
|
|
if (wpa_s->current_ssid) {
|
|
eapol_sm_invalidate_cached_session(wpa_s->eapol);
|
|
wpa_supplicant_disassociate(wpa_s,
|
|
WLAN_REASON_DEAUTH_LEAVING);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
id = atoi(cmd);
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
|
|
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL ||
|
|
wpa_config_remove_network(wpa_s->conf, id) < 0) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
|
|
"id=%d", id);
|
|
return -1;
|
|
}
|
|
|
|
if (ssid == wpa_s->current_ssid) {
|
|
/*
|
|
* Invalidate the EAP session cache if the current network is
|
|
* removed.
|
|
*/
|
|
eapol_sm_invalidate_cached_session(wpa_s->eapol);
|
|
|
|
wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_set_network(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
int id;
|
|
struct wpa_ssid *ssid;
|
|
char *name, *value;
|
|
|
|
/* cmd: "<network id> <variable name> <value>" */
|
|
name = os_strchr(cmd, ' ');
|
|
if (name == NULL)
|
|
return -1;
|
|
*name++ = '\0';
|
|
|
|
value = os_strchr(name, ' ');
|
|
if (value == NULL)
|
|
return -1;
|
|
*value++ = '\0';
|
|
|
|
id = atoi(cmd);
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
|
|
id, name);
|
|
wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
|
|
(u8 *) value, os_strlen(value));
|
|
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
|
|
"id=%d", id);
|
|
return -1;
|
|
}
|
|
|
|
if (wpa_config_set(ssid, name, value, 0) < 0) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
|
|
"variable '%s'", name);
|
|
return -1;
|
|
}
|
|
|
|
if (wpa_s->current_ssid == ssid) {
|
|
/*
|
|
* Invalidate the EAP session cache if anything in the current
|
|
* configuration changes.
|
|
*/
|
|
eapol_sm_invalidate_cached_session(wpa_s->eapol);
|
|
}
|
|
|
|
if ((os_strcmp(name, "psk") == 0 &&
|
|
value[0] == '"' && ssid->ssid_len) ||
|
|
(os_strcmp(name, "ssid") == 0 && ssid->passphrase))
|
|
wpa_config_update_psk(ssid);
|
|
else if (os_strcmp(name, "priority") == 0)
|
|
wpa_config_update_prio_list(wpa_s->conf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_get_network(
|
|
struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
|
|
{
|
|
int id;
|
|
size_t res;
|
|
struct wpa_ssid *ssid;
|
|
char *name, *value;
|
|
|
|
/* cmd: "<network id> <variable name>" */
|
|
name = os_strchr(cmd, ' ');
|
|
if (name == NULL || buflen == 0)
|
|
return -1;
|
|
*name++ = '\0';
|
|
|
|
id = atoi(cmd);
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
|
|
id, name);
|
|
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
|
|
"id=%d", id);
|
|
return -1;
|
|
}
|
|
|
|
value = wpa_config_get_no_key(ssid, name);
|
|
if (value == NULL) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
|
|
"variable '%s'", name);
|
|
return -1;
|
|
}
|
|
|
|
res = os_strlcpy(buf, value, buflen);
|
|
if (res >= buflen) {
|
|
os_free(value);
|
|
return -1;
|
|
}
|
|
|
|
os_free(value);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
#ifndef CONFIG_NO_CONFIG_WRITE
|
|
static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
|
|
{
|
|
int ret;
|
|
|
|
if (!wpa_s->conf->update_config) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
|
|
"to update configuration (update_config=0)");
|
|
return -1;
|
|
}
|
|
|
|
ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
|
|
if (ret) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
|
|
"update configuration");
|
|
} else {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
|
|
" updated");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif /* CONFIG_NO_CONFIG_WRITE */
|
|
|
|
|
|
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;
|
|
|
|
pos = buf;
|
|
end = pos + buflen;
|
|
|
|
if (res < 0) {
|
|
if (strict)
|
|
return 0;
|
|
len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
|
|
if (len >= buflen)
|
|
return -1;
|
|
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_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;
|
|
}
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int ctrl_iface_get_capability_group(int res, char *strict,
|
|
struct wpa_driver_capa *capa,
|
|
char *buf, size_t buflen)
|
|
{
|
|
int ret, first = 1;
|
|
char *pos, *end;
|
|
size_t len;
|
|
|
|
pos = buf;
|
|
end = pos + buflen;
|
|
|
|
if (res < 0) {
|
|
if (strict)
|
|
return 0;
|
|
len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
|
|
if (len >= buflen)
|
|
return -1;
|
|
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_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;
|
|
}
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
|
|
struct wpa_driver_capa *capa,
|
|
char *buf, size_t buflen)
|
|
{
|
|
int ret;
|
|
char *pos, *end;
|
|
size_t len;
|
|
|
|
pos = buf;
|
|
end = pos + buflen;
|
|
|
|
if (res < 0) {
|
|
if (strict)
|
|
return 0;
|
|
len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
|
|
"NONE", buflen);
|
|
if (len >= buflen)
|
|
return -1;
|
|
return len;
|
|
}
|
|
|
|
ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
|
|
WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
|
|
ret = os_snprintf(pos, end - pos, " WPA-EAP");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
|
|
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
|
|
ret = os_snprintf(pos, end - pos, " WPA-PSK");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
|
|
ret = os_snprintf(pos, end - pos, " WPA-NONE");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int ctrl_iface_get_capability_proto(int res, char *strict,
|
|
struct wpa_driver_capa *capa,
|
|
char *buf, size_t buflen)
|
|
{
|
|
int ret, first = 1;
|
|
char *pos, *end;
|
|
size_t len;
|
|
|
|
pos = buf;
|
|
end = pos + buflen;
|
|
|
|
if (res < 0) {
|
|
if (strict)
|
|
return 0;
|
|
len = os_strlcpy(buf, "RSN WPA", buflen);
|
|
if (len >= buflen)
|
|
return -1;
|
|
return 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 ? "" : " ");
|
|
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 ? "" : " ");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
first = 0;
|
|
}
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
|
|
struct wpa_driver_capa *capa,
|
|
char *buf, size_t buflen)
|
|
{
|
|
int ret, first = 1;
|
|
char *pos, *end;
|
|
size_t len;
|
|
|
|
pos = buf;
|
|
end = pos + buflen;
|
|
|
|
if (res < 0) {
|
|
if (strict)
|
|
return 0;
|
|
len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
|
|
if (len >= buflen)
|
|
return -1;
|
|
return len;
|
|
}
|
|
|
|
if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
|
|
ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
|
|
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 ? "" : " ");
|
|
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 ? "" : " ");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
first = 0;
|
|
}
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_get_capability(
|
|
struct wpa_supplicant *wpa_s, const char *_field, char *buf,
|
|
size_t buflen)
|
|
{
|
|
struct wpa_driver_capa capa;
|
|
int res;
|
|
char *strict;
|
|
char field[30];
|
|
size_t len;
|
|
|
|
/* Determine whether or not strict checking was requested */
|
|
len = os_strlcpy(field, _field, sizeof(field));
|
|
if (len >= sizeof(field))
|
|
return -1;
|
|
strict = os_strchr(field, ' ');
|
|
if (strict != NULL) {
|
|
*strict++ = '\0';
|
|
if (os_strcmp(strict, "strict") != 0)
|
|
return -1;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
|
|
field, strict ? strict : "");
|
|
|
|
if (os_strcmp(field, "eap") == 0) {
|
|
return eap_get_names(buf, buflen);
|
|
}
|
|
|
|
res = wpa_drv_get_capa(wpa_s, &capa);
|
|
|
|
if (os_strcmp(field, "pairwise") == 0)
|
|
return ctrl_iface_get_capability_pairwise(res, strict, &capa,
|
|
buf, buflen);
|
|
|
|
if (os_strcmp(field, "group") == 0)
|
|
return ctrl_iface_get_capability_group(res, strict, &capa,
|
|
buf, buflen);
|
|
|
|
if (os_strcmp(field, "key_mgmt") == 0)
|
|
return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
|
|
buf, buflen);
|
|
|
|
if (os_strcmp(field, "proto") == 0)
|
|
return ctrl_iface_get_capability_proto(res, strict, &capa,
|
|
buf, buflen);
|
|
|
|
if (os_strcmp(field, "auth_alg") == 0)
|
|
return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
|
|
buf, buflen);
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
|
|
field);
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
|
|
const char *cmd, char *buf,
|
|
size_t buflen)
|
|
{
|
|
u8 bssid[ETH_ALEN];
|
|
size_t i;
|
|
struct wpa_bss *bss;
|
|
int ret;
|
|
char *pos, *end;
|
|
const u8 *ie, *ie2;
|
|
|
|
if (os_strcmp(cmd, "FIRST") == 0)
|
|
bss = dl_list_first(&wpa_s->bss, struct wpa_bss, list);
|
|
else if (os_strncmp(cmd, "ID-", 3) == 0) {
|
|
i = atoi(cmd + 3);
|
|
bss = wpa_bss_get_id(wpa_s, i);
|
|
} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
|
|
i = atoi(cmd + 5);
|
|
bss = wpa_bss_get_id(wpa_s, i);
|
|
if (bss) {
|
|
struct dl_list *next = bss->list_id.next;
|
|
if (next == &wpa_s->bss_id)
|
|
bss = NULL;
|
|
else
|
|
bss = dl_list_entry(next, struct wpa_bss,
|
|
list_id);
|
|
}
|
|
} else if (hwaddr_aton(cmd, bssid) == 0)
|
|
bss = wpa_bss_get_bssid(wpa_s, bssid);
|
|
else {
|
|
struct wpa_bss *tmp;
|
|
i = atoi(cmd);
|
|
bss = NULL;
|
|
dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
|
|
{
|
|
if (i-- == 0) {
|
|
bss = tmp;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bss == NULL)
|
|
return 0;
|
|
|
|
pos = buf;
|
|
end = buf + buflen;
|
|
ret = os_snprintf(pos, end - pos,
|
|
"id=%u\n"
|
|
"bssid=" MACSTR "\n"
|
|
"freq=%d\n"
|
|
"beacon_int=%d\n"
|
|
"capabilities=0x%04x\n"
|
|
"qual=%d\n"
|
|
"noise=%d\n"
|
|
"level=%d\n"
|
|
"tsf=%016llu\n"
|
|
"ie=",
|
|
bss->id,
|
|
MAC2STR(bss->bssid), bss->freq, bss->beacon_int,
|
|
bss->caps, bss->qual, bss->noise, bss->level,
|
|
(unsigned long long) bss->tsf);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
ie = (const u8 *) (bss + 1);
|
|
for (i = 0; i < bss->ie_len; i++) {
|
|
ret = os_snprintf(pos, end - pos, "%02x", *ie++);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
|
|
ret = os_snprintf(pos, end - pos, "[P2P]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
ret = os_snprintf(pos, end - pos, "\n");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
ret = os_snprintf(pos, end - pos, "flags=");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
|
|
if (ie)
|
|
pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
|
|
ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
|
|
if (ie2)
|
|
pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
|
|
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
|
|
if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
|
|
ret = os_snprintf(pos, end - pos, "[WEP]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
if (bss->caps & IEEE80211_CAP_IBSS) {
|
|
ret = os_snprintf(pos, end - pos, "[IBSS]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
if (bss->caps & IEEE80211_CAP_ESS) {
|
|
ret = os_snprintf(pos, end - pos, "[ESS]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
ret = os_snprintf(pos, end - pos, "\n");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
ret = os_snprintf(pos, end - pos, "ssid=%s\n",
|
|
wpa_ssid_txt(bss->ssid, bss->ssid_len));
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
#ifdef CONFIG_WPS
|
|
ie = (const u8 *) (bss + 1);
|
|
ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
#endif /* CONFIG_WPS */
|
|
|
|
#ifdef CONFIG_P2P
|
|
ie = (const u8 *) (bss + 1);
|
|
ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
#endif /* CONFIG_P2P */
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_ap_scan(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
int ap_scan = atoi(cmd);
|
|
return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
|
|
}
|
|
|
|
|
|
static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
|
|
{
|
|
wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
|
|
/* MLME-DELETEKEYS.request */
|
|
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
|
|
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
|
|
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
|
|
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
|
|
#ifdef CONFIG_IEEE80211W
|
|
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
|
|
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
|
|
#endif /* CONFIG_IEEE80211W */
|
|
|
|
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
|
|
0);
|
|
/* MLME-SETPROTECTION.request(None) */
|
|
wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
|
|
MLME_SETPROTECTION_PROTECT_TYPE_NONE,
|
|
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
|
|
wpa_sm_drop_sa(wpa_s->wpa);
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
|
|
char *addr)
|
|
{
|
|
u8 bssid[ETH_ALEN];
|
|
struct wpa_bss *bss;
|
|
struct wpa_ssid *ssid = wpa_s->current_ssid;
|
|
|
|
if (hwaddr_aton(addr, bssid)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
|
|
"address '%s'", addr);
|
|
return -1;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
|
|
|
|
bss = wpa_bss_get_bssid(wpa_s, bssid);
|
|
if (!bss) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
|
|
"from BSS table");
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* TODO: Find best network configuration block from configuration to
|
|
* allow roaming to other networks
|
|
*/
|
|
|
|
if (!ssid) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
|
|
"configuration known for the target AP");
|
|
return -1;
|
|
}
|
|
|
|
wpa_s->reassociate = 1;
|
|
wpa_supplicant_connect(wpa_s, bss, ssid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_P2P
|
|
static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
unsigned int timeout = atoi(cmd);
|
|
enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
|
|
|
|
if (os_strstr(cmd, "type=social"))
|
|
type = P2P_FIND_ONLY_SOCIAL;
|
|
else if (os_strstr(cmd, "type=progressive"))
|
|
type = P2P_FIND_PROGRESSIVE;
|
|
|
|
return wpas_p2p_find(wpa_s, timeout, type);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
|
|
char *buf, size_t buflen)
|
|
{
|
|
u8 addr[ETH_ALEN];
|
|
char *pos, *pos2;
|
|
char *pin = NULL;
|
|
enum p2p_wps_method wps_method;
|
|
int new_pin;
|
|
int ret;
|
|
int persistent_group;
|
|
int join;
|
|
int auth;
|
|
int go_intent = -1;
|
|
int freq = 0;
|
|
|
|
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad] [persistent]
|
|
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] */
|
|
|
|
if (hwaddr_aton(cmd, addr))
|
|
return -1;
|
|
|
|
pos = cmd + 17;
|
|
if (*pos != ' ')
|
|
return -1;
|
|
pos++;
|
|
|
|
persistent_group = os_strstr(pos, " persistent") != NULL;
|
|
join = os_strstr(pos, " join") != NULL;
|
|
auth = os_strstr(pos, " auth") != NULL;
|
|
|
|
pos2 = os_strstr(pos, " go_intent=");
|
|
if (pos2) {
|
|
pos2 += 11;
|
|
go_intent = atoi(pos2);
|
|
if (go_intent < 0 || go_intent > 15)
|
|
return -1;
|
|
}
|
|
|
|
pos2 = os_strstr(pos, " freq=");
|
|
if (pos2) {
|
|
pos2 += 6;
|
|
freq = atoi(pos2);
|
|
if (freq <= 0)
|
|
return -1;
|
|
}
|
|
|
|
if (os_strncmp(pos, "pin", 3) == 0) {
|
|
/* Request random PIN (to be displayed) and enable the PIN */
|
|
wps_method = WPS_PIN_DISPLAY;
|
|
} else if (os_strncmp(pos, "pbc", 3) == 0) {
|
|
wps_method = WPS_PBC;
|
|
} else {
|
|
pin = pos;
|
|
pos = os_strchr(pin, ' ');
|
|
wps_method = WPS_PIN_KEYPAD;
|
|
if (pos) {
|
|
*pos++ = '\0';
|
|
if (os_strncmp(pos, "label", 5) == 0)
|
|
wps_method = WPS_PIN_LABEL;
|
|
else if (os_strncmp(pos, "display", 7) == 0)
|
|
wps_method = WPS_PIN_DISPLAY;
|
|
}
|
|
}
|
|
|
|
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
|
|
persistent_group, join, auth, go_intent,
|
|
freq);
|
|
if (new_pin == -2) {
|
|
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
|
|
return 25;
|
|
}
|
|
if (new_pin == -3) {
|
|
os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
|
|
return 25;
|
|
}
|
|
if (new_pin < 0)
|
|
return -1;
|
|
if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
|
|
ret = os_snprintf(buf, buflen, "%08d", new_pin);
|
|
if (ret < 0 || (size_t) ret >= buflen)
|
|
return -1;
|
|
return ret;
|
|
}
|
|
|
|
os_memcpy(buf, "OK\n", 3);
|
|
return 3;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
unsigned int timeout = atoi(cmd);
|
|
return wpas_p2p_listen(wpa_s, timeout);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
u8 addr[ETH_ALEN];
|
|
char *pos;
|
|
|
|
/* <addr> <config method> */
|
|
|
|
if (hwaddr_aton(cmd, addr))
|
|
return -1;
|
|
|
|
pos = cmd + 17;
|
|
if (*pos != ' ')
|
|
return -1;
|
|
pos++;
|
|
|
|
return wpas_p2p_prov_disc(wpa_s, addr, pos);
|
|
}
|
|
|
|
|
|
static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
|
|
size_t buflen)
|
|
{
|
|
struct wpa_ssid *ssid = wpa_s->current_ssid;
|
|
|
|
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
|
|
ssid->passphrase == NULL)
|
|
return -1;
|
|
|
|
os_strlcpy(buf, ssid->passphrase, buflen);
|
|
return os_strlen(buf);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
|
|
char *buf, size_t buflen)
|
|
{
|
|
u64 ref;
|
|
int res;
|
|
u8 dst_buf[ETH_ALEN], *dst;
|
|
struct wpabuf *tlvs;
|
|
char *pos;
|
|
size_t len;
|
|
|
|
if (hwaddr_aton(cmd, dst_buf))
|
|
return -1;
|
|
dst = dst_buf;
|
|
if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
|
|
dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
|
|
dst = NULL;
|
|
pos = cmd + 17;
|
|
if (*pos != ' ')
|
|
return -1;
|
|
pos++;
|
|
|
|
if (os_strncmp(pos, "upnp ", 5) == 0) {
|
|
u8 version;
|
|
pos += 5;
|
|
if (hexstr2bin(pos, &version, 1) < 0)
|
|
return -1;
|
|
pos += 2;
|
|
if (*pos != ' ')
|
|
return -1;
|
|
pos++;
|
|
ref = (unsigned long) wpas_p2p_sd_request_upnp(wpa_s, dst,
|
|
version, pos);
|
|
} else {
|
|
len = os_strlen(pos);
|
|
if (len & 1)
|
|
return -1;
|
|
len /= 2;
|
|
tlvs = wpabuf_alloc(len);
|
|
if (tlvs == NULL)
|
|
return -1;
|
|
if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
|
|
wpabuf_free(tlvs);
|
|
return -1;
|
|
}
|
|
|
|
ref = (unsigned long) wpas_p2p_sd_request(wpa_s, dst, tlvs);
|
|
wpabuf_free(tlvs);
|
|
}
|
|
res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
|
|
if (res < 0 || (unsigned) res >= buflen)
|
|
return -1;
|
|
return res;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
long long unsigned val;
|
|
u64 req;
|
|
if (sscanf(cmd, "%llx", &val) != 1)
|
|
return -1;
|
|
req = val;
|
|
return wpas_p2p_sd_cancel_request(wpa_s, (void *) (unsigned long) req);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
int freq;
|
|
u8 dst[ETH_ALEN];
|
|
u8 dialog_token;
|
|
struct wpabuf *resp_tlvs;
|
|
char *pos, *pos2;
|
|
size_t len;
|
|
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
freq = atoi(cmd);
|
|
if (freq == 0)
|
|
return -1;
|
|
|
|
if (hwaddr_aton(pos, dst))
|
|
return -1;
|
|
pos += 17;
|
|
if (*pos != ' ')
|
|
return -1;
|
|
pos++;
|
|
|
|
pos2 = os_strchr(pos, ' ');
|
|
if (pos2 == NULL)
|
|
return -1;
|
|
*pos2++ = '\0';
|
|
dialog_token = atoi(pos);
|
|
|
|
len = os_strlen(pos2);
|
|
if (len & 1)
|
|
return -1;
|
|
len /= 2;
|
|
resp_tlvs = wpabuf_alloc(len);
|
|
if (resp_tlvs == NULL)
|
|
return -1;
|
|
if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
|
|
wpabuf_free(resp_tlvs);
|
|
return -1;
|
|
}
|
|
|
|
wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
|
|
wpabuf_free(resp_tlvs);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
char *pos;
|
|
size_t len;
|
|
struct wpabuf *query, *resp;
|
|
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
|
|
len = os_strlen(cmd);
|
|
if (len & 1)
|
|
return -1;
|
|
len /= 2;
|
|
query = wpabuf_alloc(len);
|
|
if (query == NULL)
|
|
return -1;
|
|
if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
|
|
wpabuf_free(query);
|
|
return -1;
|
|
}
|
|
|
|
len = os_strlen(pos);
|
|
if (len & 1) {
|
|
wpabuf_free(query);
|
|
return -1;
|
|
}
|
|
len /= 2;
|
|
resp = wpabuf_alloc(len);
|
|
if (resp == NULL) {
|
|
wpabuf_free(query);
|
|
return -1;
|
|
}
|
|
if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
|
|
wpabuf_free(query);
|
|
wpabuf_free(resp);
|
|
return -1;
|
|
}
|
|
|
|
if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
|
|
wpabuf_free(query);
|
|
wpabuf_free(resp);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *pos;
|
|
u8 version;
|
|
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
|
|
if (hexstr2bin(cmd, &version, 1) < 0)
|
|
return -1;
|
|
|
|
return wpas_p2p_service_add_upnp(wpa_s, version, pos);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *pos;
|
|
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
|
|
if (os_strcmp(cmd, "bonjour") == 0)
|
|
return p2p_ctrl_service_add_bonjour(wpa_s, pos);
|
|
if (os_strcmp(cmd, "upnp") == 0)
|
|
return p2p_ctrl_service_add_upnp(wpa_s, pos);
|
|
wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
size_t len;
|
|
struct wpabuf *query;
|
|
int ret;
|
|
|
|
len = os_strlen(cmd);
|
|
if (len & 1)
|
|
return -1;
|
|
len /= 2;
|
|
query = wpabuf_alloc(len);
|
|
if (query == NULL)
|
|
return -1;
|
|
if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
|
|
wpabuf_free(query);
|
|
return -1;
|
|
}
|
|
|
|
ret = wpas_p2p_service_del_bonjour(wpa_s, query);
|
|
wpabuf_free(query);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *pos;
|
|
u8 version;
|
|
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
|
|
if (hexstr2bin(cmd, &version, 1) < 0)
|
|
return -1;
|
|
|
|
return wpas_p2p_service_del_upnp(wpa_s, version, pos);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *pos;
|
|
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
|
|
if (os_strcmp(cmd, "bonjour") == 0)
|
|
return p2p_ctrl_service_del_bonjour(wpa_s, pos);
|
|
if (os_strcmp(cmd, "upnp") == 0)
|
|
return p2p_ctrl_service_del_upnp(wpa_s, pos);
|
|
wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
u8 addr[ETH_ALEN];
|
|
|
|
/* <addr> */
|
|
|
|
if (hwaddr_aton(cmd, addr))
|
|
return -1;
|
|
|
|
return wpas_p2p_reject(wpa_s, addr);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *pos;
|
|
int id;
|
|
struct wpa_ssid *ssid;
|
|
u8 peer[ETH_ALEN];
|
|
|
|
id = atoi(cmd);
|
|
pos = os_strstr(cmd, " peer=");
|
|
if (pos) {
|
|
pos += 6;
|
|
if (hwaddr_aton(pos, peer))
|
|
return -1;
|
|
}
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL || ssid->disabled != 2) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
|
|
"for persistent P2P group",
|
|
id);
|
|
return -1;
|
|
}
|
|
|
|
return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *pos;
|
|
u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
|
|
|
|
pos = os_strstr(cmd, " peer=");
|
|
if (!pos)
|
|
return -1;
|
|
|
|
*pos = '\0';
|
|
pos += 6;
|
|
if (hwaddr_aton(pos, peer)) {
|
|
wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
|
|
return -1;
|
|
}
|
|
|
|
pos = os_strstr(pos, " go_dev_addr=");
|
|
if (pos) {
|
|
pos += 13;
|
|
if (hwaddr_aton(pos, go_dev_addr)) {
|
|
wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
|
|
pos);
|
|
return -1;
|
|
}
|
|
go_dev = go_dev_addr;
|
|
}
|
|
|
|
return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
if (os_strncmp(cmd, "persistent=", 11) == 0)
|
|
return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
|
|
if (os_strncmp(cmd, "group=", 6) == 0)
|
|
return p2p_ctrl_invite_group(wpa_s, cmd + 6);
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
|
|
char *cmd, int freq)
|
|
{
|
|
int id;
|
|
struct wpa_ssid *ssid;
|
|
|
|
id = atoi(cmd);
|
|
ssid = wpa_config_get_network(wpa_s->conf, id);
|
|
if (ssid == NULL || ssid->disabled != 2) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
|
|
"for persistent P2P group",
|
|
id);
|
|
return -1;
|
|
}
|
|
|
|
return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
int freq = 0;
|
|
char *pos;
|
|
|
|
pos = os_strstr(cmd, "freq=");
|
|
if (pos)
|
|
freq = atoi(pos + 5);
|
|
|
|
if (os_strncmp(cmd, "persistent=", 11) == 0)
|
|
return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
|
|
if (os_strcmp(cmd, "persistent") == 0 ||
|
|
os_strncmp(cmd, "persistent ", 11) == 0)
|
|
return wpas_p2p_group_add(wpa_s, 1, freq);
|
|
if (os_strncmp(cmd, "freq=", 5) == 0)
|
|
return wpas_p2p_group_add(wpa_s, 0, freq);
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
|
|
cmd);
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
|
|
char *buf, size_t buflen)
|
|
{
|
|
u8 addr[ETH_ALEN], *addr_ptr;
|
|
int next;
|
|
|
|
if (!wpa_s->global->p2p)
|
|
return -1;
|
|
|
|
if (os_strcmp(cmd, "FIRST") == 0) {
|
|
addr_ptr = NULL;
|
|
next = 0;
|
|
} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
|
|
if (hwaddr_aton(cmd + 5, addr) < 0)
|
|
return -1;
|
|
addr_ptr = addr;
|
|
next = 1;
|
|
} else {
|
|
if (hwaddr_aton(cmd, addr) < 0)
|
|
return -1;
|
|
addr_ptr = addr;
|
|
next = 0;
|
|
}
|
|
|
|
return p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next,
|
|
buf, buflen);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *param;
|
|
|
|
if (wpa_s->global->p2p == NULL)
|
|
return -1;
|
|
|
|
param = os_strchr(cmd, ' ');
|
|
if (param == NULL)
|
|
return -1;
|
|
*param++ = '\0';
|
|
|
|
if (os_strcmp(cmd, "discoverability") == 0) {
|
|
p2p_set_client_discoverability(wpa_s->global->p2p,
|
|
atoi(param));
|
|
return 0;
|
|
}
|
|
|
|
if (os_strcmp(cmd, "managed") == 0) {
|
|
p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
|
|
return 0;
|
|
}
|
|
|
|
if (os_strcmp(cmd, "listen_channel") == 0) {
|
|
return p2p_set_listen_channel(wpa_s->global->p2p, 81,
|
|
atoi(param));
|
|
}
|
|
|
|
if (os_strcmp(cmd, "ssid_postfix") == 0) {
|
|
return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
|
|
os_strlen(param));
|
|
}
|
|
|
|
if (os_strcmp(cmd, "noa") == 0) {
|
|
char *pos;
|
|
int count, start, duration;
|
|
/* GO NoA parameters: count,start_offset(ms),duration(ms) */
|
|
count = atoi(param);
|
|
pos = os_strchr(param, ',');
|
|
if (pos == NULL)
|
|
return -1;
|
|
pos++;
|
|
start = atoi(pos);
|
|
pos = os_strchr(pos, ',');
|
|
if (pos == NULL)
|
|
return -1;
|
|
pos++;
|
|
duration = atoi(pos);
|
|
if (count < 0 || count > 255 || start < 0 || duration < 0)
|
|
return -1;
|
|
if (count == 0 && duration > 0)
|
|
return -1;
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
|
|
"start=%d duration=%d", count, start, duration);
|
|
return wpas_p2p_set_noa(wpa_s, count, start, duration);
|
|
}
|
|
|
|
if (os_strcmp(cmd, "ps") == 0)
|
|
return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
|
|
|
|
if (os_strcmp(cmd, "oppps") == 0)
|
|
return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
|
|
|
|
if (os_strcmp(cmd, "ctwindow") == 0)
|
|
return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
|
|
|
|
if (os_strcmp(cmd, "disabled") == 0) {
|
|
wpa_s->global->p2p_disabled = atoi(param);
|
|
wpa_printf(MSG_DEBUG, "P2P functionality %s",
|
|
wpa_s->global->p2p_disabled ?
|
|
"disabled" : "enabled");
|
|
if (wpa_s->global->p2p_disabled) {
|
|
wpas_p2p_stop_find(wpa_s);
|
|
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
|
|
p2p_flush(wpa_s->global->p2p);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (os_strcmp(cmd, "force_long_sd") == 0) {
|
|
wpa_s->force_long_sd = atoi(param);
|
|
return 0;
|
|
}
|
|
|
|
if (os_strcmp(cmd, "peer_filter") == 0) {
|
|
u8 addr[ETH_ALEN];
|
|
if (hwaddr_aton(param, addr))
|
|
return -1;
|
|
p2p_set_peer_filter(wpa_s->global->p2p, addr);
|
|
return 0;
|
|
}
|
|
|
|
if (os_strcmp(cmd, "cross_connect") == 0)
|
|
return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
|
|
|
|
if (os_strcmp(cmd, "go_apsd") == 0) {
|
|
if (os_strcmp(param, "disable") == 0)
|
|
wpa_s->set_ap_uapsd = 0;
|
|
else {
|
|
wpa_s->set_ap_uapsd = 1;
|
|
wpa_s->ap_uapsd = atoi(param);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (os_strcmp(cmd, "client_apsd") == 0) {
|
|
if (os_strcmp(param, "disable") == 0)
|
|
wpa_s->set_sta_uapsd = 0;
|
|
else {
|
|
int be, bk, vi, vo;
|
|
char *pos;
|
|
/* format: BE,BK,VI,VO;max SP Length */
|
|
be = atoi(param);
|
|
pos = os_strchr(param, ',');
|
|
if (pos == NULL)
|
|
return -1;
|
|
pos++;
|
|
bk = atoi(pos);
|
|
pos = os_strchr(pos, ',');
|
|
if (pos == NULL)
|
|
return -1;
|
|
pos++;
|
|
vi = atoi(pos);
|
|
pos = os_strchr(pos, ',');
|
|
if (pos == NULL)
|
|
return -1;
|
|
pos++;
|
|
vo = atoi(pos);
|
|
/* ignore max SP Length for now */
|
|
|
|
wpa_s->set_sta_uapsd = 1;
|
|
wpa_s->sta_uapsd = 0;
|
|
if (be)
|
|
wpa_s->sta_uapsd |= BIT(0);
|
|
if (bk)
|
|
wpa_s->sta_uapsd |= BIT(1);
|
|
if (vi)
|
|
wpa_s->sta_uapsd |= BIT(2);
|
|
if (vo)
|
|
wpa_s->sta_uapsd |= BIT(3);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
|
|
cmd);
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *pos, *pos2;
|
|
unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
|
|
|
|
if (cmd[0]) {
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
dur1 = atoi(cmd);
|
|
|
|
pos2 = os_strchr(pos, ' ');
|
|
if (pos2)
|
|
*pos2++ = '\0';
|
|
int1 = atoi(pos);
|
|
} else
|
|
pos2 = NULL;
|
|
|
|
if (pos2) {
|
|
pos = os_strchr(pos2, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
dur2 = atoi(pos2);
|
|
int2 = atoi(pos);
|
|
}
|
|
|
|
return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
|
|
}
|
|
|
|
|
|
static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
char *pos;
|
|
unsigned int period = 0, interval = 0;
|
|
|
|
if (cmd[0]) {
|
|
pos = os_strchr(cmd, ' ');
|
|
if (pos == NULL)
|
|
return -1;
|
|
*pos++ = '\0';
|
|
period = atoi(cmd);
|
|
interval = atoi(pos);
|
|
}
|
|
|
|
return wpas_p2p_ext_listen(wpa_s, period, interval);
|
|
}
|
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_sta_autoconnect(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
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) {
|
|
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));
|
|
}
|
|
|
|
reply = os_malloc(reply_size);
|
|
if (reply == NULL) {
|
|
*resp_len = 1;
|
|
return NULL;
|
|
}
|
|
|
|
os_memcpy(reply, "OK\n", 3);
|
|
reply_len = 3;
|
|
|
|
if (os_strcmp(buf, "PING") == 0) {
|
|
os_memcpy(reply, "PONG\n", 5);
|
|
reply_len = 5;
|
|
} else if (os_strncmp(buf, "RELOG", 5) == 0) {
|
|
if (wpa_debug_reopen_file() < 0)
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "NOTE ", 5) == 0) {
|
|
wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
|
|
} else if (os_strcmp(buf, "MIB") == 0) {
|
|
reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
|
|
if (reply_len >= 0) {
|
|
int res;
|
|
res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
|
|
reply_size - reply_len);
|
|
if (res < 0)
|
|
reply_len = -1;
|
|
else
|
|
reply_len += res;
|
|
}
|
|
} else if (os_strncmp(buf, "STATUS", 6) == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_status(
|
|
wpa_s, buf + 6, reply, reply_size);
|
|
} else if (os_strcmp(buf, "PMKSA") == 0) {
|
|
reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
|
|
reply_size);
|
|
} else if (os_strncmp(buf, "SET ", 4) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "GET ", 4) == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
|
|
reply, reply_size);
|
|
} else if (os_strcmp(buf, "LOGON") == 0) {
|
|
eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
|
|
} else if (os_strcmp(buf, "LOGOFF") == 0) {
|
|
eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
|
|
} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
|
|
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
|
|
reply_len = -1;
|
|
else {
|
|
wpa_s->disconnected = 0;
|
|
wpa_s->reassociate = 1;
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
}
|
|
} else if (os_strcmp(buf, "RECONNECT") == 0) {
|
|
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
|
|
reply_len = -1;
|
|
else if (wpa_s->disconnected) {
|
|
wpa_s->disconnected = 0;
|
|
wpa_s->reassociate = 1;
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
}
|
|
#ifdef IEEE8021X_EAPOL
|
|
} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
|
|
reply_len = -1;
|
|
#endif /* IEEE8021X_EAPOL */
|
|
#ifdef CONFIG_PEERKEY
|
|
} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
|
|
reply_len = -1;
|
|
#endif /* CONFIG_PEERKEY */
|
|
#ifdef CONFIG_IEEE80211R
|
|
} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
|
|
reply_len = -1;
|
|
#endif /* CONFIG_IEEE80211R */
|
|
#ifdef CONFIG_WPS
|
|
} else if (os_strcmp(buf, "WPS_PBC") == 0) {
|
|
if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
|
|
reply,
|
|
reply_size);
|
|
} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
|
|
wpa_s, buf + 14, reply, reply_size);
|
|
} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
|
|
if (wpas_wps_cancel(wpa_s))
|
|
reply_len = -1;
|
|
#ifdef CONFIG_WPS_OOB
|
|
} else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
|
|
reply_len = -1;
|
|
#endif /* CONFIG_WPS_OOB */
|
|
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
|
|
reply_len = -1;
|
|
#ifdef CONFIG_AP
|
|
} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
|
|
wpa_s, buf + 11, reply, reply_size);
|
|
#endif /* CONFIG_AP */
|
|
#ifdef CONFIG_WPS_ER
|
|
} else if (os_strcmp(buf, "WPS_ER_START") == 0) {
|
|
if (wpas_wps_er_start(wpa_s, NULL))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
|
|
if (wpas_wps_er_start(wpa_s, buf + 13))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
|
|
if (wpas_wps_er_stop(wpa_s))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
|
|
int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
|
|
if (ret == -2) {
|
|
os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
|
|
reply_len = 17;
|
|
} else if (ret == -3) {
|
|
os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
|
|
reply_len = 18;
|
|
} else if (ret == -4) {
|
|
os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
|
|
reply_len = 20;
|
|
} else if (ret)
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
|
|
buf + 18))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
|
|
reply_len = -1;
|
|
#endif /* CONFIG_WPS_ER */
|
|
#endif /* CONFIG_WPS */
|
|
#ifdef CONFIG_IBSS_RSN
|
|
} else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
|
|
reply_len = -1;
|
|
#endif /* CONFIG_IBSS_RSN */
|
|
#ifdef CONFIG_P2P
|
|
} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
|
|
if (p2p_ctrl_find(wpa_s, buf + 9))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_FIND") == 0) {
|
|
if (p2p_ctrl_find(wpa_s, ""))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
|
|
wpas_p2p_stop_find(wpa_s);
|
|
} else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
|
|
reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
|
|
reply_size);
|
|
} else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
|
|
if (p2p_ctrl_listen(wpa_s, buf + 11))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
|
|
if (p2p_ctrl_listen(wpa_s, ""))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
|
|
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))
|
|
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_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
|
|
if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
|
|
reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
|
|
} else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
|
|
reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
|
|
reply_size);
|
|
} else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
|
|
if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
|
|
if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
|
|
wpas_p2p_sd_service_update(wpa_s);
|
|
} else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
|
|
if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
|
|
wpas_p2p_service_flush(wpa_s);
|
|
} else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
|
|
if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
|
|
if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
|
|
if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
|
|
if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
|
|
reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
|
|
reply_size);
|
|
} else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
|
|
if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
|
|
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
|
|
wpa_s->force_long_sd = 0;
|
|
p2p_flush(wpa_s->global->p2p);
|
|
} else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
|
|
if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
|
|
if (wpas_p2p_cancel(wpa_s))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
|
|
if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
|
|
if (p2p_ctrl_presence_req(wpa_s, "") < 0)
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
|
|
if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
|
|
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
|
|
reply_len = -1;
|
|
#endif /* CONFIG_P2P */
|
|
} 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 if (os_strcmp(buf, "RECONFIGURE") == 0) {
|
|
if (wpa_supplicant_reload_configuration(wpa_s))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "TERMINATE") == 0) {
|
|
wpa_supplicant_terminate_proc(wpa_s->global);
|
|
} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_list_networks(
|
|
wpa_s, reply, reply_size);
|
|
} else if (os_strcmp(buf, "DISCONNECT") == 0) {
|
|
wpa_s->reassociate = 0;
|
|
wpa_s->disconnected = 1;
|
|
wpa_supplicant_deauthenticate(wpa_s,
|
|
WLAN_REASON_DEAUTH_LEAVING);
|
|
} else if (os_strcmp(buf, "SCAN") == 0) {
|
|
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
|
|
reply_len = -1;
|
|
else {
|
|
wpa_s->scan_req = 2;
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
}
|
|
} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_scan_results(
|
|
wpa_s, reply, reply_size);
|
|
} else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_add_network(
|
|
wpa_s, reply, reply_size);
|
|
} else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_get_network(
|
|
wpa_s, buf + 12, reply, reply_size);
|
|
#ifndef CONFIG_NO_CONFIG_WRITE
|
|
} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
|
|
if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
|
|
reply_len = -1;
|
|
#endif /* CONFIG_NO_CONFIG_WRITE */
|
|
} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_get_capability(
|
|
wpa_s, buf + 15, reply, reply_size);
|
|
} else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
|
|
reply_len = wpa_supplicant_global_iface_list(
|
|
wpa_s->global, reply, reply_size);
|
|
} else if (os_strcmp(buf, "INTERFACES") == 0) {
|
|
reply_len = wpa_supplicant_global_iface_interfaces(
|
|
wpa_s->global, reply, reply_size);
|
|
} else if (os_strncmp(buf, "BSS ", 4) == 0) {
|
|
reply_len = wpa_supplicant_ctrl_iface_bss(
|
|
wpa_s, buf + 4, reply, reply_size);
|
|
#ifdef CONFIG_AP
|
|
} else if (os_strcmp(buf, "STA-FIRST") == 0) {
|
|
reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
|
|
} else if (os_strncmp(buf, "STA ", 4) == 0) {
|
|
reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
|
|
reply_size);
|
|
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
|
|
reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
|
|
reply_size);
|
|
#endif /* CONFIG_AP */
|
|
} else if (os_strcmp(buf, "SUSPEND") == 0) {
|
|
wpas_notify_suspend(wpa_s->global);
|
|
} else if (os_strcmp(buf, "RESUME") == 0) {
|
|
wpas_notify_resume(wpa_s->global);
|
|
} else if (os_strcmp(buf, "DROP_SA") == 0) {
|
|
wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
|
|
} else if (os_strncmp(buf, "ROAM ", 5) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
|
|
reply_len = -1;
|
|
} else {
|
|
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
|
|
reply_len = 16;
|
|
}
|
|
|
|
if (reply_len < 0) {
|
|
os_memcpy(reply, "FAIL\n", 5);
|
|
reply_len = 5;
|
|
}
|
|
|
|
if (ctrl_rsp)
|
|
eapol_sm_notify_ctrl_response(wpa_s->eapol);
|
|
|
|
*resp_len = reply_len;
|
|
return reply;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_global_iface_add(struct wpa_global *global,
|
|
char *cmd)
|
|
{
|
|
struct wpa_interface iface;
|
|
char *pos;
|
|
|
|
/*
|
|
* <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
|
|
* TAB<bridge_ifname>
|
|
*/
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
|
|
|
|
os_memset(&iface, 0, sizeof(iface));
|
|
|
|
do {
|
|
iface.ifname = pos = cmd;
|
|
pos = os_strchr(pos, '\t');
|
|
if (pos)
|
|
*pos++ = '\0';
|
|
if (iface.ifname[0] == '\0')
|
|
return -1;
|
|
if (pos == NULL)
|
|
break;
|
|
|
|
iface.confname = pos;
|
|
pos = os_strchr(pos, '\t');
|
|
if (pos)
|
|
*pos++ = '\0';
|
|
if (iface.confname[0] == '\0')
|
|
iface.confname = NULL;
|
|
if (pos == NULL)
|
|
break;
|
|
|
|
iface.driver = pos;
|
|
pos = os_strchr(pos, '\t');
|
|
if (pos)
|
|
*pos++ = '\0';
|
|
if (iface.driver[0] == '\0')
|
|
iface.driver = NULL;
|
|
if (pos == NULL)
|
|
break;
|
|
|
|
iface.ctrl_interface = pos;
|
|
pos = os_strchr(pos, '\t');
|
|
if (pos)
|
|
*pos++ = '\0';
|
|
if (iface.ctrl_interface[0] == '\0')
|
|
iface.ctrl_interface = NULL;
|
|
if (pos == NULL)
|
|
break;
|
|
|
|
iface.driver_param = pos;
|
|
pos = os_strchr(pos, '\t');
|
|
if (pos)
|
|
*pos++ = '\0';
|
|
if (iface.driver_param[0] == '\0')
|
|
iface.driver_param = NULL;
|
|
if (pos == NULL)
|
|
break;
|
|
|
|
iface.bridge_ifname = pos;
|
|
pos = os_strchr(pos, '\t');
|
|
if (pos)
|
|
*pos++ = '\0';
|
|
if (iface.bridge_ifname[0] == '\0')
|
|
iface.bridge_ifname = NULL;
|
|
if (pos == NULL)
|
|
break;
|
|
} while (0);
|
|
|
|
if (wpa_supplicant_get_iface(global, iface.ifname))
|
|
return -1;
|
|
|
|
return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
|
|
char *cmd)
|
|
{
|
|
struct wpa_supplicant *wpa_s;
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
|
|
|
|
wpa_s = wpa_supplicant_get_iface(global, cmd);
|
|
if (wpa_s == NULL)
|
|
return -1;
|
|
return wpa_supplicant_remove_iface(global, wpa_s);
|
|
}
|
|
|
|
|
|
static void wpa_free_iface_info(struct wpa_interface_info *iface)
|
|
{
|
|
struct wpa_interface_info *prev;
|
|
|
|
while (iface) {
|
|
prev = iface;
|
|
iface = iface->next;
|
|
|
|
os_free(prev->ifname);
|
|
os_free(prev->desc);
|
|
os_free(prev);
|
|
}
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
|
|
char *buf, int len)
|
|
{
|
|
int i, res;
|
|
struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
|
|
char *pos, *end;
|
|
|
|
for (i = 0; wpa_drivers[i]; i++) {
|
|
struct wpa_driver_ops *drv = wpa_drivers[i];
|
|
if (drv->get_interfaces == NULL)
|
|
continue;
|
|
tmp = drv->get_interfaces(global->drv_priv[i]);
|
|
if (tmp == NULL)
|
|
continue;
|
|
|
|
if (last == NULL)
|
|
iface = last = tmp;
|
|
else
|
|
last->next = tmp;
|
|
while (last->next)
|
|
last = last->next;
|
|
}
|
|
|
|
pos = buf;
|
|
end = buf + len;
|
|
for (tmp = iface; tmp; tmp = tmp->next) {
|
|
res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
|
|
tmp->drv_name, tmp->ifname,
|
|
tmp->desc ? tmp->desc : "");
|
|
if (res < 0 || res >= end - pos) {
|
|
*pos = '\0';
|
|
break;
|
|
}
|
|
pos += res;
|
|
}
|
|
|
|
wpa_free_iface_info(iface);
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
|
|
char *buf, int len)
|
|
{
|
|
int res;
|
|
char *pos, *end;
|
|
struct wpa_supplicant *wpa_s;
|
|
|
|
wpa_s = global->ifaces;
|
|
pos = buf;
|
|
end = buf + len;
|
|
|
|
while (wpa_s) {
|
|
res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
|
|
if (res < 0 || res >= end - pos) {
|
|
*pos = '\0';
|
|
break;
|
|
}
|
|
pos += res;
|
|
wpa_s = wpa_s->next;
|
|
}
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
|
|
char *buf, size_t *resp_len)
|
|
{
|
|
char *reply;
|
|
const int reply_size = 2048;
|
|
int reply_len;
|
|
|
|
wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
|
|
(const u8 *) buf, os_strlen(buf));
|
|
|
|
reply = os_malloc(reply_size);
|
|
if (reply == NULL) {
|
|
*resp_len = 1;
|
|
return NULL;
|
|
}
|
|
|
|
os_memcpy(reply, "OK\n", 3);
|
|
reply_len = 3;
|
|
|
|
if (os_strcmp(buf, "PING") == 0) {
|
|
os_memcpy(reply, "PONG\n", 5);
|
|
reply_len = 5;
|
|
} else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
|
|
if (wpa_supplicant_global_iface_add(global, buf + 14))
|
|
reply_len = -1;
|
|
} else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
|
|
if (wpa_supplicant_global_iface_remove(global, buf + 17))
|
|
reply_len = -1;
|
|
} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
|
|
reply_len = wpa_supplicant_global_iface_list(
|
|
global, reply, reply_size);
|
|
} else if (os_strcmp(buf, "INTERFACES") == 0) {
|
|
reply_len = wpa_supplicant_global_iface_interfaces(
|
|
global, reply, reply_size);
|
|
} else if (os_strcmp(buf, "TERMINATE") == 0) {
|
|
wpa_supplicant_terminate_proc(global);
|
|
} else if (os_strcmp(buf, "SUSPEND") == 0) {
|
|
wpas_notify_suspend(global);
|
|
} else if (os_strcmp(buf, "RESUME") == 0) {
|
|
wpas_notify_resume(global);
|
|
} else {
|
|
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
|
|
reply_len = 16;
|
|
}
|
|
|
|
if (reply_len < 0) {
|
|
os_memcpy(reply, "FAIL\n", 5);
|
|
reply_len = 5;
|
|
}
|
|
|
|
*resp_len = reply_len;
|
|
return reply;
|
|
}
|