11ef8d3578
This commit adds a new build option, CONFIG_IBSS_RSN=y, that can be used to enable RSN support for IBSS. This links in RSN Authenticator code from hostapd and adds code for managing per-peer information for IBSS. A new wpa_cli command or driver event can be used to request RSN authentication with an IBSS peer. New RSN Authenticator and Supplicant will be allocated for each peer. The basic state machine setup code is included in this commit, but the state machines are not properly started yet. In addition, some of the callback functions are not yet complete.
1902 lines
45 KiB
C
1902 lines
45 KiB
C
/*
|
|
* WPA Supplicant / Control interface (shared code for all backends)
|
|
* Copyright (c) 2004-2008, 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 "includes.h"
|
|
|
|
#include "common.h"
|
|
#include "eloop.h"
|
|
#include "wpa.h"
|
|
#include "config.h"
|
|
#include "eapol_supp/eapol_supp_sm.h"
|
|
#include "wpa_supplicant_i.h"
|
|
#include "ctrl_iface.h"
|
|
#include "l2_packet/l2_packet.h"
|
|
#include "preauth.h"
|
|
#include "pmksa_cache.h"
|
|
#include "wpa_ctrl.h"
|
|
#include "eap_peer/eap.h"
|
|
#include "ieee802_11_defs.h"
|
|
#include "wps_supplicant.h"
|
|
#include "wps/wps.h"
|
|
#include "ibss_rsn.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 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
|
|
ret = -1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
#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'", peer);
|
|
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];
|
|
|
|
if (hwaddr_aton(addr, target_ap)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
|
|
"address '%s'", target_ap);
|
|
return -1;
|
|
}
|
|
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
|
|
|
|
return wpa_ft_start_over_ds(wpa_s->wpa, target_ap);
|
|
}
|
|
#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];
|
|
|
|
if (cmd == NULL || os_strcmp(cmd, "any") == 0)
|
|
return wpas_wps_start_pbc(wpa_s, NULL);
|
|
|
|
if (hwaddr_aton(cmd, bssid)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
|
|
cmd);
|
|
return -1;
|
|
}
|
|
|
|
return wpas_wps_start_pbc(wpa_s, bssid);
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
if (pin) {
|
|
ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
|
|
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);
|
|
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_reg(struct wpa_supplicant *wpa_s,
|
|
char *cmd)
|
|
{
|
|
u8 bssid[ETH_ALEN], *_bssid = bssid;
|
|
char *pin;
|
|
|
|
pin = os_strchr(cmd, ' ');
|
|
if (pin == NULL)
|
|
return -1;
|
|
*pin++ = '\0';
|
|
|
|
if (os_strcmp(cmd, "any") == 0)
|
|
_bssid = NULL;
|
|
else if (hwaddr_aton(cmd, bssid)) {
|
|
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
|
|
cmd);
|
|
return -1;
|
|
}
|
|
|
|
return wpas_wps_start_reg(wpa_s, _bssid, pin);
|
|
}
|
|
#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'", peer);
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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",
|
|
ssid == wpa_s->current_ssid ?
|
|
"[CURRENT]" : "",
|
|
ssid->disabled ? "[DISABLED]" : "");
|
|
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;
|
|
}
|
|
|
|
static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
|
|
const struct wpa_scan_res *res)
|
|
{
|
|
#ifdef CONFIG_WPS
|
|
struct wpabuf *wps_ie;
|
|
int ret;
|
|
const char *txt;
|
|
|
|
wps_ie = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
|
|
if (wps_ie == NULL)
|
|
return pos;
|
|
|
|
if (wps_is_selected_pbc_registrar(wps_ie))
|
|
txt = "[WPS-PBC]";
|
|
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);
|
|
#endif /* CONFIG_WPS */
|
|
|
|
return pos;
|
|
}
|
|
|
|
|
|
/* Format one result on one text line into a buffer. */
|
|
static int wpa_supplicant_ctrl_iface_scan_result(
|
|
const struct wpa_scan_res *res, char *buf, size_t buflen)
|
|
{
|
|
char *pos, *end;
|
|
int ret;
|
|
const u8 *ie, *ie2;
|
|
|
|
pos = buf;
|
|
end = buf + buflen;
|
|
|
|
ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
|
|
MAC2STR(res->bssid), res->freq, res->level);
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
|
|
if (ie)
|
|
pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
|
|
ie2 = wpa_scan_get_ie(res, WLAN_EID_RSN);
|
|
if (ie2)
|
|
pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
|
|
pos = wpa_supplicant_wps_ie_txt(pos, end, res);
|
|
if (!ie && !ie2 && res->caps & IEEE80211_CAP_PRIVACY) {
|
|
ret = os_snprintf(pos, end - pos, "[WEP]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
if (res->caps & IEEE80211_CAP_IBSS) {
|
|
ret = os_snprintf(pos, end - pos, "[IBSS]");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
}
|
|
|
|
ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
|
|
ret = os_snprintf(pos, end - pos, "\t%s",
|
|
ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
|
|
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_scan_res *res;
|
|
int ret;
|
|
size_t i;
|
|
|
|
if (wpa_s->scan_res == NULL &&
|
|
wpa_supplicant_get_scan_results(wpa_s) < 0)
|
|
return 0;
|
|
|
|
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;
|
|
|
|
for (i = 0; i < wpa_s->scan_res->num; i++) {
|
|
res = wpa_s->scan_res->res[i];
|
|
ret = wpa_supplicant_ctrl_iface_scan_result(res, 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 = wpa_s->conf->ssid;
|
|
while (ssid) {
|
|
ssid->disabled = 0;
|
|
ssid = ssid->next;
|
|
}
|
|
wpa_s->reassociate = 1;
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
return 0;
|
|
}
|
|
|
|
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 != wpa_s->current_ssid && wpa_s->current_ssid)
|
|
wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
|
|
|
|
/* Mark all other networks disabled and trigger reassociation */
|
|
ssid = wpa_s->conf->ssid;
|
|
while (ssid) {
|
|
ssid->disabled = id != ssid->id;
|
|
ssid = ssid->next;
|
|
}
|
|
wpa_s->reassociate = 1;
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
|
|
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 = wpa_s->conf->ssid;
|
|
while (ssid) {
|
|
if (ssid == wpa_s->current_ssid && ssid->disabled)
|
|
wpa_s->reassociate = 1;
|
|
ssid->disabled = 0;
|
|
ssid = ssid->next;
|
|
}
|
|
if (wpa_s->reassociate)
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
return 0;
|
|
}
|
|
|
|
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 (wpa_s->current_ssid == NULL && ssid->disabled) {
|
|
/*
|
|
* Try to reassociate since there is no current configuration
|
|
* and a new network was made available. */
|
|
wpa_s->reassociate = 1;
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
}
|
|
ssid->disabled = 0;
|
|
|
|
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 = wpa_s->conf->ssid;
|
|
while (ssid) {
|
|
ssid->disabled = 1;
|
|
ssid = ssid->next;
|
|
}
|
|
if (wpa_s->current_ssid)
|
|
wpa_supplicant_disassociate(wpa_s,
|
|
WLAN_REASON_DEAUTH_LEAVING);
|
|
return 0;
|
|
}
|
|
|
|
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 == wpa_s->current_ssid)
|
|
wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
|
|
ssid->disabled = 1;
|
|
|
|
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;
|
|
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) {
|
|
id = ssid->id;
|
|
ssid = ssid->next;
|
|
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);
|
|
|
|
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_scan_results *results;
|
|
struct wpa_scan_res *bss;
|
|
int ret;
|
|
char *pos, *end;
|
|
const u8 *ie, *ie2;
|
|
|
|
if (wpa_s->scan_res == NULL &&
|
|
wpa_supplicant_get_scan_results(wpa_s) < 0)
|
|
return 0;
|
|
|
|
results = wpa_s->scan_res;
|
|
if (results == NULL)
|
|
return 0;
|
|
|
|
if (hwaddr_aton(cmd, bssid) == 0) {
|
|
for (i = 0; i < results->num; i++) {
|
|
if (os_memcmp(bssid, results->res[i]->bssid, ETH_ALEN)
|
|
== 0)
|
|
break;
|
|
}
|
|
} else
|
|
i = atoi(cmd);
|
|
|
|
if (i >= results->num || results->res[i] == NULL)
|
|
return 0; /* no match found */
|
|
|
|
bss = results->res[i];
|
|
pos = buf;
|
|
end = buf + buflen;
|
|
ret = os_snprintf(pos, end - pos,
|
|
"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=",
|
|
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;
|
|
}
|
|
|
|
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_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
|
|
if (ie)
|
|
pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
|
|
ie2 = wpa_scan_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(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;
|
|
}
|
|
|
|
ret = os_snprintf(pos, end - pos, "\n");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
|
|
ret = os_snprintf(pos, end - pos, "ssid=%s\n",
|
|
ie ? wpa_ssid_txt(ie + 2, ie[1]) : "");
|
|
if (ret < 0 || ret >= end - pos)
|
|
return pos - buf;
|
|
pos += ret;
|
|
|
|
return pos - buf;
|
|
}
|
|
|
|
|
|
static int wpa_supplicant_ctrl_iface_ap_scan(
|
|
struct wpa_supplicant *wpa_s, char *cmd)
|
|
{
|
|
int ap_scan = atoi(cmd);
|
|
|
|
if (ap_scan < 0 || ap_scan > 2)
|
|
return -1;
|
|
wpa_s->conf->ap_scan = ap_scan;
|
|
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 = 2048;
|
|
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 {
|
|
wpa_hexdump_ascii(MSG_DEBUG, "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_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_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) {
|
|
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->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_REG ", 8) == 0) {
|
|
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
|
|
reply_len = -1;
|
|
#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 */
|
|
} 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) {
|
|
eloop_terminate();
|
|
} 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_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
|
|
} else if (os_strcmp(buf, "SCAN") == 0) {
|
|
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);
|
|
} 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_supplicant_drivers[i]; i++) {
|
|
struct wpa_driver_ops *drv = wpa_supplicant_drivers[i];
|
|
if (drv->get_interfaces == NULL)
|
|
continue;
|
|
tmp = drv->get_interfaces(global->drv_priv);
|
|
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) {
|
|
eloop_terminate();
|
|
} 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;
|
|
}
|