[PATCH] Add wpa_cli command to show roaming candidates
Gery Kahn
geryk
Sun Aug 7 09:49:01 PDT 2011
The wpa_supplicant collects APs for roaming during background scanning.
The patch provides new cli command to get the list of roaming
candidates by selected APs from common wpa_supplicant list. The selection rules
are AP with the same SSID, AP with the same security type as connected netwrok
and not connected AP.
The patch introduces new function wpa_bss_ssid_match_security() to check if
selected AP has the same security as chosen ESS.
To test if AP has same WPS security as ESS introduced new function
wpa_ssid_match_wps(). There is also new file ssid.c to include SSID
functionality.
Signed-off-by: Gery Kahn <geryk at ti.com>
---
wpa_supplicant/Makefile | 1 +
wpa_supplicant/bss.c | 162 +++++++++++++++++++++++++++++++++++++++
wpa_supplicant/bss.h | 3 +
wpa_supplicant/ctrl_iface.c | 37 +++++++++
wpa_supplicant/events.c | 1 -
wpa_supplicant/ssid.c | 84 ++++++++++++++++++++
wpa_supplicant/ssid.h | 21 +++++
wpa_supplicant/wpa_cli.c | 10 +++
wpa_supplicant/wps_supplicant.c | 61 +-------------
wpa_supplicant/wps_supplicant.h | 4 +
10 files changed, 327 insertions(+), 57 deletions(-)
create mode 100644 wpa_supplicant/ssid.c
create mode 100644 wpa_supplicant/ssid.h
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 4b3f5a0..866179d 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -56,6 +56,7 @@ install: all
OBJS = config.o
OBJS += notify.o
OBJS += bss.o
+OBJS += ssid.o
OBJS += eap_register.o
OBJS += ../src/utils/common.o
OBJS += ../src/utils/wpa_debug.o
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 21d6322..503bb20 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -16,13 +16,16 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "rsn_supp/wpa.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
#include "drivers/driver.h"
#include "wpa_supplicant_i.h"
#include "config.h"
#include "notify.h"
#include "scan.h"
#include "bss.h"
+#include "ssid.h"
/**
@@ -267,6 +270,165 @@ static u32 wpa_bss_compare_res(const struct wpa_bss *old,
return changes;
}
+int wpa_bss_ssid_match_wps(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct wpa_bss *bss)
+{
+ struct wpabuf *wps_ie;
+ int ret;
+
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+ return -1;
+
+ wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+
+ ret = wpa_ssid_match_wps(wpa_s, ssid, wps_ie);
+
+ if (wps_ie)
+ wpabuf_free(wps_ie);
+
+ return ret;
+}
+
+int wpa_bss_ssid_match_security(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct wpa_bss *bss)
+{
+ struct wpa_ie_data ie;
+ int proto_match = 0;
+ const u8 *rsn_ie, *wpa_ie;
+ int ret;
+ int wep_ok;
+
+ ret = wpa_bss_ssid_match_wps(wpa_s, ssid, bss);
+ if (ret >= 0)
+ return ret;
+
+ /* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */
+ wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
+ (((ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+ ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
+ (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
+
+ rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsn_ie)
+ wpa_dbg(wpa_s, MSG_DEBUG, "No RSN_IE");
+
+ while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
+ proto_match++;
+
+ if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - parse "
+ "failed");
+ break;
+ }
+
+ if (wep_ok &&
+ (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
+ {
+ wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
+ "in RSN IE");
+ return 1;
+ }
+
+ if (!(ie.proto & ssid->proto)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - proto "
+ "mismatch");
+ break;
+ }
+
+ if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - PTK "
+ "cipher mismatch");
+ break;
+ }
+
+ if (!(ie.group_cipher & ssid->group_cipher)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - GTK "
+ "cipher mismatch");
+ break;
+ }
+
+ if (!(ie.key_mgmt & ssid->key_mgmt)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - key mgmt "
+ "mismatch");
+ break;
+ }
+
+#ifdef CONFIG_IEEE80211W
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+ ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt "
+ "frame protection");
+ break;
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ wpa_dbg(wpa_s, MSG_DEBUG, " selected based on RSN IE");
+ return 1;
+ }
+
+ wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
+ proto_match++;
+
+ if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - parse "
+ "failed");
+ break;
+ }
+
+ if (wep_ok &&
+ (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
+ {
+ wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
+ "in WPA IE");
+ return 1;
+ }
+
+ if (!(ie.proto & ssid->proto)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - proto "
+ "mismatch");
+ break;
+ }
+
+ if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - PTK "
+ "cipher mismatch");
+ break;
+ }
+
+ if (!(ie.group_cipher & ssid->group_cipher)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - GTK "
+ "cipher mismatch");
+ break;
+ }
+
+ if (!(ie.key_mgmt & ssid->key_mgmt)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - key mgmt "
+ "mismatch");
+ break;
+ }
+
+ wpa_dbg(wpa_s, MSG_DEBUG, " selected based on WPA IE");
+ return 1;
+ }
+
+ if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
+ wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match");
+ return 0;
+ }
+
+ if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
+ return 1;
+ }
+
+ wpa_dbg(wpa_s, MSG_DEBUG, " reject due to mismatch with "
+ "WPA/WPA2");
+
+ return 0;
+}
static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
const struct wpa_bss *bss)
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 992b9c0..54d8a99 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -71,6 +71,9 @@ struct wpa_bss {
/* followed by beacon_ie_len octets of IEs */
};
+int wpa_bss_ssid_match_security(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct wpa_bss *bss);
void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 730e607..44e1d9a 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2103,6 +2103,39 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
return 0;
}
+static int wpa_supplicant_ctrl_iface_list_candidates(
+ struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+ struct wpa_bss *bss;
+ char *pos, *end;
+ int ret;
+
+ pos = buf;
+ end = buf + buflen;
+
+ /*
+ * Find roaming candidates from bss list. Select BSSes with the same
+ * ssid and the same security type, except BSS connected to
+ */
+ dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+ if (os_memcmp(wpa_s->bssid, bss->bssid, ETH_ALEN) == 0 ||
+ bss->ssid_len != wpa_s->current_ssid->ssid_len ||
+ os_memcmp(bss->ssid, wpa_s->current_ssid->ssid,
+ bss->ssid_len) != 0 ||
+ wpa_bss_ssid_match_security(wpa_s,
+ wpa_s->current_ssid, bss))
+ continue;
+
+ ret = os_snprintf(pos, end - pos,
+ "BSS " MACSTR " freq %d level %d\n",
+ MAC2STR(bss->bssid), bss->freq, bss->level);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
#ifdef CONFIG_P2P
static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
@@ -3270,6 +3303,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *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_strcmp(buf, "LIST_CANDIDATES") == 0) {
+ if (wpa_s->wpa_state == WPA_COMPLETED)
+ reply_len = wpa_supplicant_ctrl_iface_list_candidates(
+ wpa_s, reply, reply_size);
} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
reply_len = -1;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index a307eda..2a11770 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -460,7 +460,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
return 0;
}
-
static int freq_allowed(int *freqs, int freq)
{
int i;
diff --git a/wpa_supplicant/ssid.c b/wpa_supplicant/ssid.c
new file mode 100644
index 0000000..0655852
--- /dev/null
+++ b/wpa_supplicant/ssid.c
@@ -0,0 +1,84 @@
+/*
+ * SSID table
+ * Copyright (c) 2011, Texas Instruments
+ *
+ * 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/ieee802_11_defs.h"
+#include "eap_peer/eap.h"
+#include "drivers/driver.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "notify.h"
+#include "bss.h"
+#include "wps_supplicant.h"
+
+
+int wpa_ssid_match_wps(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct wpabuf *wps_ie)
+{
+ if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
+ if (!wps_ie) {
+ wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
+ return 0;
+ }
+
+ if (!wps_is_selected_pbc_registrar(wps_ie)) {
+ wpa_printf(MSG_DEBUG, " skip - WPS AP "
+ "without active PBC Registrar");
+ return 0;
+ }
+
+ /* TODO: overlap detection */
+ wpa_printf(MSG_DEBUG, " selected based on WPS IE "
+ "(Active PBC)");
+ return 1;
+ }
+
+ if (eap_is_wps_pin_enrollee(&ssid->eap)) {
+ if (!wps_ie) {
+ wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
+ return 0;
+ }
+
+ /*
+ * Start with WPS APs that advertise our address as an
+ * authorized MAC (v2.0) or active PIN Registrar (v1.0) and
+ * allow any WPS AP after couple of scans since some APs do not
+ * set Selected Registrar attribute properly when using
+ * external Registrar.
+ */
+ if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
+ if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
+ wpa_printf(MSG_DEBUG, " skip - WPS AP "
+ "without active PIN Registrar");
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, " selected based on WPS IE");
+ } else {
+ wpa_printf(MSG_DEBUG, " selected based on WPS IE "
+ "(Authorized MAC or Active PIN)");
+ }
+ return 1;
+ }
+
+ if (wps_ie) {
+ wpa_printf(MSG_DEBUG, " selected based on WPS IE");
+ return 1;
+ }
+
+ return -1;
+}
+
diff --git a/wpa_supplicant/ssid.h b/wpa_supplicant/ssid.h
new file mode 100644
index 0000000..8ddebae
--- /dev/null
+++ b/wpa_supplicant/ssid.h
@@ -0,0 +1,21 @@
+/*
+ * WPA Supplicant / Network configuration operations
+ * Copyright (c) 2011, Texas Instruments
+ *
+ * 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.
+ */
+
+#ifndef SSID_H
+#define SSID_H
+
+int wpa_ssid_match_wps(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct wpabuf *wps_ie);
+
+#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 9439856..7b84b7d 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1678,6 +1678,13 @@ static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_list_candidates(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "LIST_CANDIDATES");
+}
+
+
#ifdef CONFIG_P2P
static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -2540,6 +2547,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "roam", wpa_cli_cmd_roam,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
+ { "list_candidates", wpa_cli_cmd_list_candidates,
+ cli_cmd_flag_none,
+ "= list candidates for roaming" },
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, cli_cmd_flag_none,
"[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 6f70cad..b750ef1 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -33,16 +33,13 @@
#include "blacklist.h"
#include "bss.h"
#include "scan.h"
+#include "ssid.h"
#include "ap.h"
#include "p2p/p2p.h"
#include "p2p_supplicant.h"
#include "wps_supplicant.h"
-#ifndef WPS_PIN_SCAN_IGNORE_SEL_REG
-#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
-#endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */
-
static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
@@ -1201,67 +1198,19 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, struct wpa_scan_res *bss)
{
struct wpabuf *wps_ie;
+ int ret;
if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
return -1;
wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
- if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
- if (!wps_ie) {
- wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
- return 0;
- }
-
- if (!wps_is_selected_pbc_registrar(wps_ie)) {
- wpa_printf(MSG_DEBUG, " skip - WPS AP "
- "without active PBC Registrar");
- wpabuf_free(wps_ie);
- return 0;
- }
-
- /* TODO: overlap detection */
- wpa_printf(MSG_DEBUG, " selected based on WPS IE "
- "(Active PBC)");
- wpabuf_free(wps_ie);
- return 1;
- }
-
- if (eap_is_wps_pin_enrollee(&ssid->eap)) {
- if (!wps_ie) {
- wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
- return 0;
- }
- /*
- * Start with WPS APs that advertise our address as an
- * authorized MAC (v2.0) or active PIN Registrar (v1.0) and
- * allow any WPS AP after couple of scans since some APs do not
- * set Selected Registrar attribute properly when using
- * external Registrar.
- */
- if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
- if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
- wpa_printf(MSG_DEBUG, " skip - WPS AP "
- "without active PIN Registrar");
- wpabuf_free(wps_ie);
- return 0;
- }
- wpa_printf(MSG_DEBUG, " selected based on WPS IE");
- } else {
- wpa_printf(MSG_DEBUG, " selected based on WPS IE "
- "(Authorized MAC or Active PIN)");
- }
- wpabuf_free(wps_ie);
- return 1;
- }
+ ret = wpa_ssid_match_wps(wpa_s, ssid, wps_ie);
- if (wps_ie) {
- wpa_printf(MSG_DEBUG, " selected based on WPS IE");
+ if (wps_ie)
wpabuf_free(wps_ie);
- return 1;
- }
- return -1;
+ return ret;
}
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index b38c091..c42b2b2 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -22,6 +22,10 @@ struct wpa_scan_res;
#include "wps/wps.h"
#include "wps/wps_defs.h"
+#ifndef WPS_PIN_SCAN_IGNORE_SEL_REG
+#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
+#endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */
+
struct wpa_bss;
struct wps_new_ap_settings {
--
1.7.0.4
More information about the Hostap
mailing list