aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Kondik <shade@chemlab.org>2013-10-07 22:47:09 -0700
committerSteve Kondik <shade@chemlab.org>2013-10-07 22:47:09 -0700
commita4013bc5ccd3f368c16afd748fea4a65338b8595 (patch)
treee4946ddf61d3c4a8aa424ada1531b555955492e3
parent4370c8280d5b226caf9ddcea17b674a704e9f5e1 (diff)
parent48119a1eaaa1798aef056c7935ede5531745dd25 (diff)
downloadandroid_external_wpa_supplicant_8-a4013bc5ccd3f368c16afd748fea4a65338b8595.tar.gz
android_external_wpa_supplicant_8-a4013bc5ccd3f368c16afd748fea4a65338b8595.tar.bz2
android_external_wpa_supplicant_8-a4013bc5ccd3f368c16afd748fea4a65338b8595.zip
Merge branch 'jb_mr2' of git://codeaurora.org/platform/external/wpa_supplicant_8 into cm-10.2
Change-Id: I2b37453bc5b7022cabea29c2da432694952fbd55
-rw-r--r--hostapd/android.config2
-rw-r--r--hostapd/main.c1
-rw-r--r--src/ap/ap_drv_ops.h8
-rw-r--r--src/ap/hostapd.c70
-rw-r--r--src/ap/hostapd.h2
-rw-r--r--src/common/ieee802_11_defs.h17
-rw-r--r--src/crypto/tls_openssl.c94
-rw-r--r--src/drivers/driver.h22
-rw-r--r--src/drivers/driver_nl80211.c116
-rw-r--r--src/drivers/nl80211_copy.h59
-rw-r--r--src/eapol_supp/eapol_supp_sm.c18
-rw-r--r--src/p2p/p2p.c55
-rw-r--r--src/p2p/p2p.h19
-rw-r--r--src/p2p/p2p_go_neg.c51
-rw-r--r--src/p2p/p2p_i.h5
-rw-r--r--src/p2p/p2p_invitation.c34
-rw-r--r--src/p2p/p2p_pd.c3
-rw-r--r--src/p2p/p2p_sd.c3
-rw-r--r--src/p2p/p2p_utils.c103
-rw-r--r--src/rsn_supp/tdls.c224
-rw-r--r--src/rsn_supp/wpa.h7
-rw-r--r--src/rsn_supp/wpa_ft.c14
-rw-r--r--src/rsn_supp/wpa_i.h4
-rw-r--r--src/rsn_supp/wpa_ie.c3
-rw-r--r--src/rsn_supp/wpa_ie.h1
-rw-r--r--src/wps/wps_enrollee.c6
-rw-r--r--wpa_supplicant/android.config12
-rw-r--r--wpa_supplicant/ap.c10
-rw-r--r--wpa_supplicant/config.c1
-rw-r--r--wpa_supplicant/config.h5
-rw-r--r--wpa_supplicant/config_file.c3
-rw-r--r--wpa_supplicant/ctrl_iface.c45
-rw-r--r--wpa_supplicant/events.c111
-rw-r--r--wpa_supplicant/p2p_supplicant.c185
-rw-r--r--wpa_supplicant/scan.c63
-rw-r--r--wpa_supplicant/wnm_sta.c362
-rw-r--r--wpa_supplicant/wnm_sta.h69
-rw-r--r--wpa_supplicant/wpa_cli.c8
-rw-r--r--wpa_supplicant/wpa_supplicant.c79
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h17
-rw-r--r--wpa_supplicant/wpa_supplicant_template.conf2
-rw-r--r--wpa_supplicant/wpas_glue.c4
-rw-r--r--wpa_supplicant/wps_supplicant.c80
43 files changed, 1569 insertions, 428 deletions
diff --git a/hostapd/android.config b/hostapd/android.config
index f51a5bfe..51d6656f 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -52,7 +52,7 @@ CONFIG_LIBNL20=y
# This version is an experimental implementation based on IEEE 802.11w/D1.0
# draft and is subject to change since the standard has not yet been finalized.
# Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
+CONFIG_IEEE80211W=y
# Integrated EAP server
#CONFIG_EAP=y
diff --git a/hostapd/main.c b/hostapd/main.c
index d2ec1a50..61229d77 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -277,6 +277,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
iface->extended_capa = capa.extended_capa;
iface->extended_capa_mask = capa.extended_capa_mask;
iface->extended_capa_len = capa.extended_capa_len;
+ iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
}
return 0;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index ceb7e68e..70fab553 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -173,6 +173,14 @@ static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
}
+static inline int hostapd_drv_set_acl(struct hostapd_data *hapd,
+ struct hostapd_acl_params *params)
+{
+ if (hapd->driver == NULL || hapd->driver->set_acl == NULL)
+ return 0;
+ return hapd->driver->set_acl(hapd->drv_priv, params);
+}
+
static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index a0ac38c4..780b2e2e 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -837,6 +837,74 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
}
+static int hostapd_set_acl_list(struct hostapd_data *hapd,
+ struct mac_acl_entry *mac_acl,
+ int n_entries, u8 accept_acl)
+{
+ struct hostapd_acl_params *acl_params;
+ int i, err;
+
+ acl_params = os_zalloc(sizeof(*acl_params) +
+ (n_entries * sizeof(acl_params->mac_acl[0])));
+ if (!acl_params)
+ return -ENOMEM;
+
+ for (i = 0; i < n_entries; i++)
+ os_memcpy(acl_params->mac_acl[i].addr, mac_acl[i].addr,
+ ETH_ALEN);
+
+ acl_params->acl_policy = accept_acl;
+ acl_params->num_mac_acl = n_entries;
+
+ err = hostapd_drv_set_acl(hapd, acl_params);
+
+ os_free(acl_params);
+
+ return err;
+}
+
+
+static void hostapd_set_acl(struct hostapd_data *hapd)
+{
+ struct hostapd_config *conf = hapd->iconf;
+ int err;
+ u8 accept_acl;
+
+ if (hapd->iface->drv_max_acl_mac_addrs == 0)
+ return;
+ if (!(conf->bss->num_accept_mac || conf->bss->num_deny_mac))
+ return;
+
+ if (conf->bss->macaddr_acl == DENY_UNLESS_ACCEPTED) {
+ if (conf->bss->num_accept_mac) {
+ accept_acl = 1;
+ err = hostapd_set_acl_list(hapd, conf->bss->accept_mac,
+ conf->bss->num_accept_mac,
+ accept_acl);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "Failed to set accept acl");
+ return;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
+ }
+ } else if (conf->bss->macaddr_acl == ACCEPT_UNLESS_DENIED) {
+ if (conf->bss->num_deny_mac) {
+ accept_acl = 0;
+ err = hostapd_set_acl_list(hapd, conf->bss->deny_mac,
+ conf->bss->num_deny_mac,
+ accept_acl);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "Failed to set deny acl");
+ return;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
+ }
+ }
+}
+
+
static int setup_interface(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
@@ -962,6 +1030,8 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
ap_list_init(iface);
+ hostapd_set_acl(hapd);
+
if (hostapd_driver_commit(hapd) < 0) {
wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
"configuration", __func__);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 9a3bb686..55f6dd84 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -233,6 +233,8 @@ struct hostapd_iface {
const u8 *extended_capa, *extended_capa_mask;
unsigned int extended_capa_len;
+ unsigned int drv_max_acl_mac_addrs;
+
struct hostapd_hw_modes *hw_features;
int num_hw_features;
struct hostapd_hw_modes *current_mode;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index f782c865..08485902 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -549,6 +549,14 @@ struct ieee80211_mgmt {
* Entries (optional) */
u8 variable[0];
} STRUCT_PACKED bss_tm_resp;
+ struct {
+ u8 action; /* 6 */
+ u8 dialog_token;
+ u8 query_reason;
+ /* BSS Transition Candidate List
+ * Entries (optional) */
+ u8 variable[0];
+ } STRUCT_PACKED bss_tm_query;
} u;
} STRUCT_PACKED action;
} u;
@@ -1049,6 +1057,15 @@ enum wnm_action {
#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+#define WNM_NEIGHBOR_TSF 1
+#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2
+#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3
+#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION 4
+#define WNM_NEIGHBOR_BEARING 5
+#define WNM_NEIGHBOR_MEASUREMENT_PILOT 66
+#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70
+#define WNM_NEIGHBOR_MULTIPLE_BSSID 71
+
/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
#define WLAN_20_40_BSS_COEX_INFO_REQ BIT(0)
#define WLAN_20_40_BSS_COEX_40MHZ_INTOL BIT(1)
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 2bf47c7c..fec8e385 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -34,6 +34,10 @@
#define OPENSSL_d2i_TYPE unsigned char **
#endif
+#if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data)
+#define OPENSSL_SUPPORTS_CTX_APP_DATA
+#endif
+
#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
#ifdef SSL_OP_NO_TICKET
/*
@@ -63,17 +67,18 @@ static BIO * BIO_from_keystore(const char *key)
static int tls_openssl_ref_count = 0;
-struct tls_global {
+struct tls_context {
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
void *cb_ctx;
int cert_in_cb;
};
-static struct tls_global *tls_global = NULL;
+static struct tls_context *tls_global = NULL;
struct tls_connection {
+ struct tls_context *context;
SSL *ssl;
BIO *ssl_in, *ssl_out;
#ifndef OPENSSL_NO_ENGINE
@@ -100,6 +105,20 @@ struct tls_connection {
};
+static struct tls_context * tls_context_new(const struct tls_config *conf)
+{
+ struct tls_context *context = os_zalloc(sizeof(*context));
+ if (context == NULL)
+ return NULL;
+ if (conf) {
+ context->event_cb = conf->event_cb;
+ context->cb_ctx = conf->cb_ctx;
+ context->cert_in_cb = conf->cert_in_cb;
+ }
+ return context;
+}
+
+
#ifdef CONFIG_NO_STDOUT_DEBUG
static void _tls_show_errors(void)
@@ -525,6 +544,7 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
wpa_printf(MSG_DEBUG, "SSL: %s:%s",
str, SSL_state_string_long(ssl));
} else if (where & SSL_CB_ALERT) {
+ struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
where & SSL_CB_READ ?
"read (remote end reported an error)" :
@@ -532,21 +552,19 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
SSL_alert_type_string_long(ret),
SSL_alert_desc_string_long(ret));
if ((ret >> 8) == SSL3_AL_FATAL) {
- struct tls_connection *conn =
- SSL_get_app_data((SSL *) ssl);
if (where & SSL_CB_READ)
conn->read_alerts++;
else
conn->write_alerts++;
}
- if (tls_global->event_cb != NULL) {
+ if (conn->context->event_cb != NULL) {
union tls_event_data ev;
+ struct tls_context *context = conn->context;
os_memset(&ev, 0, sizeof(ev));
ev.alert.is_local = !(where & SSL_CB_READ);
ev.alert.type = SSL_alert_type_string_long(ret);
ev.alert.description = SSL_alert_desc_string_long(ret);
- tls_global->event_cb(tls_global->cb_ctx, TLS_ALERT,
- &ev);
+ context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
}
} else if (where & SSL_CB_EXIT && ret <= 0) {
wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
@@ -704,17 +722,12 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
void * tls_init(const struct tls_config *conf)
{
SSL_CTX *ssl;
+ struct tls_context *context;
if (tls_openssl_ref_count == 0) {
- tls_global = os_zalloc(sizeof(*tls_global));
- if (tls_global == NULL)
+ tls_global = context = tls_context_new(conf);
+ if (context == NULL)
return NULL;
- if (conf) {
- tls_global->event_cb = conf->event_cb;
- tls_global->cb_ctx = conf->cb_ctx;
- tls_global->cert_in_cb = conf->cert_in_cb;
- }
-
#ifdef CONFIG_FIPS
#ifdef OPENSSL_FIPS
if (conf && conf->fips_mode) {
@@ -760,14 +773,33 @@ void * tls_init(const struct tls_config *conf)
#endif /* OPENSSL_NO_RC2 */
PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
+ } else {
+ context = tls_global;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ /* Newer OpenSSL can store app-data per-SSL */
+ context = tls_context_new(conf);
+ if (context == NULL)
+ return NULL;
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
}
tls_openssl_ref_count++;
ssl = SSL_CTX_new(TLSv1_method());
- if (ssl == NULL)
+ if (ssl == NULL) {
+ tls_openssl_ref_count--;
+ if (tls_openssl_ref_count == 0) {
+ os_free(tls_global);
+ tls_global = NULL;
+ } else if (context != tls_global) {
+ os_free(context);
+ }
return NULL;
+ }
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ SSL_CTX_set_app_data(ssl, context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
#ifndef OPENSSL_NO_ENGINE
if (conf &&
@@ -793,6 +825,11 @@ void * tls_init(const struct tls_config *conf)
void tls_deinit(void *ssl_ctx)
{
SSL_CTX *ssl = ssl_ctx;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ struct tls_context *context = SSL_CTX_get_app_data(ssl);
+ if (context != tls_global)
+ os_free(context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
@@ -936,6 +973,10 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
SSL_CTX *ssl = ssl_ctx;
struct tls_connection *conn;
long options;
+ struct tls_context *context = tls_global;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ context = SSL_CTX_get_app_data(ssl);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
@@ -948,6 +989,7 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
return NULL;
}
+ conn->context = context;
SSL_set_app_data(conn->ssl, conn);
options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_SINGLE_DH_USE;
@@ -1148,8 +1190,9 @@ static void openssl_tls_fail_event(struct tls_connection *conn,
{
union tls_event_data ev;
struct wpabuf *cert = NULL;
+ struct tls_context *context = conn->context;
- if (tls_global->event_cb == NULL)
+ if (context->event_cb == NULL)
return;
cert = get_x509_cert(err_cert);
@@ -1160,7 +1203,7 @@ static void openssl_tls_fail_event(struct tls_connection *conn,
ev.cert_fail.subject = subject;
ev.cert_fail.reason_txt = err_str;
ev.cert_fail.cert = cert;
- tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+ context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
wpabuf_free(cert);
}
@@ -1171,15 +1214,16 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
{
struct wpabuf *cert = NULL;
union tls_event_data ev;
+ struct tls_context *context = conn->context;
#ifdef CONFIG_SHA256
u8 hash[32];
#endif /* CONFIG_SHA256 */
- if (tls_global->event_cb == NULL)
+ if (context->event_cb == NULL)
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cert_probe || tls_global->cert_in_cb) {
+ if (conn->cert_probe || context->cert_in_cb) {
cert = get_x509_cert(err_cert);
ev.peer_cert.cert = cert;
}
@@ -1197,7 +1241,7 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
#endif /* CONFIG_SHA256 */
ev.peer_cert.depth = depth;
ev.peer_cert.subject = subject;
- tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+ context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert);
}
@@ -1209,6 +1253,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
int err, depth;
SSL *ssl;
struct tls_connection *conn;
+ struct tls_context *context;
char *match, *altmatch;
const char *err_str;
@@ -1222,6 +1267,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
conn = SSL_get_app_data(ssl);
if (conn == NULL)
return 0;
+ context = conn->context;
match = conn->subject_match;
altmatch = conn->altsubject_match;
@@ -1304,9 +1350,9 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
TLS_FAIL_SERVER_CHAIN_PROBE);
}
- if (preverify_ok && tls_global->event_cb != NULL)
- tls_global->event_cb(tls_global->cb_ctx,
- TLS_CERT_CHAIN_SUCCESS, NULL);
+ if (preverify_ok && context->event_cb != NULL)
+ context->event_cb(context->cb_ctx,
+ TLS_CERT_CHAIN_SUCCESS, NULL);
return preverify_ok;
}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 14b64a6c..0091db88 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -898,6 +898,8 @@ struct wpa_driver_capa {
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
unsigned int probe_resp_offloads;
+ unsigned int max_acl_mac_addrs;
+
/**
* extended_capa - extended capabilities in driver/device
*
@@ -958,6 +960,16 @@ struct hostapd_freq_params {
int bandwidth;
};
+struct mac_address {
+ u8 addr[ETH_ALEN];
+};
+
+struct hostapd_acl_params {
+ u8 acl_policy;
+ unsigned int num_mac_acl;
+ struct mac_address mac_acl[0];
+};
+
enum wpa_driver_if_type {
/**
* WPA_IF_STATION - Station mode interface
@@ -1588,6 +1600,16 @@ struct wpa_driver_ops {
int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
/**
+ * set_acl - Set ACL in AP mode
+ * @priv: Private driver interface data
+ * @params: Parameters to configure ACL
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is used only for the drivers which support MAC address ACL.
+ */
+ int (*set_acl)(void *priv, struct hostapd_acl_params *params);
+
+ /**
* hapd_init - Initialize driver interface (hostapd only)
* @hapd: Pointer to hostapd context
* @params: Configuration for the driver wrapper
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c812d959..07cc8308 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1094,7 +1094,8 @@ static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
"associated BSS from scan results: %u MHz",
arg.assoc_freq);
- return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
+ return (drv->assoc_freq = (arg.assoc_freq ?
+ arg.assoc_freq : drv->assoc_freq ));
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -2237,6 +2238,13 @@ static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
}
+static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
+}
+
+
static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
{
@@ -2418,6 +2426,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
case NL80211_CMD_FT_EVENT:
mlme_event_ft_event(drv, tb);
break;
+ case NL80211_CMD_STOP_AP:
+ nl80211_stop_ap(drv, tb);
+ break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
@@ -2860,6 +2871,10 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
capa->max_match_sets =
nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+ if (tb[NL80211_ATTR_MAC_ACL_MAX])
+ capa->max_acl_mac_addrs =
+ nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
+
wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
@@ -4537,14 +4552,17 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
int ifindex = if_nametoindex(ifname);
struct nl_msg *msg;
int ret;
+ int tdls = 0;
wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
"set_tx=%d seq_len=%lu key_len=%lu",
__func__, ifindex, alg, addr, key_idx, set_tx,
(unsigned long) seq_len, (unsigned long) key_len);
#ifdef CONFIG_TDLS
- if (key_idx == -1)
+ if (key_idx == -1) {
key_idx = 0;
+ tdls = 1;
+ }
#endif /* CONFIG_TDLS */
msg = nlmsg_alloc();
@@ -4637,7 +4655,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
* If we failed or don't need to set the default TX key (below),
* we're done here.
*/
- if (ret || !set_tx || alg == WPA_ALG_NONE)
+ if (ret || !set_tx || alg == WPA_ALG_NONE || tdls)
return ret;
if (is_ap_interface(drv->nlmode) && addr &&
!is_broadcast_ether_addr(addr))
@@ -4850,12 +4868,20 @@ nla_put_failure:
static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
int reason_code)
{
+ int ret;
+
wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
drv->associated = 0;
- drv->ignore_next_local_disconnect = 0;
/* Disconnect command doesn't need BSSID - it uses cached value */
- return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
- reason_code, 0);
+ ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
+ reason_code, 0);
+ /*
+ * For locally generated disconnect, supplicant already generates a
+ * DEAUTH event, so ignore the event from NL80211.
+ */
+ drv->ignore_next_local_disconnect = ret == 0;
+
+ return ret;
}
@@ -5862,6 +5888,60 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
}
+static int wpa_driver_nl80211_set_acl(void *priv,
+ struct hostapd_acl_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *acl;
+ unsigned int i;
+ int ret = 0;
+
+ if (!(drv->capa.max_acl_mac_addrs))
+ return -ENOTSUP;
+
+ if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
+ return -ENOTSUP;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
+ params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
+ NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
+ NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED);
+
+ acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
+ if (acl == NULL)
+ goto nla_put_failure;
+
+ for (i = 0; i < params->num_mac_acl; i++)
+ NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr);
+
+ nla_nest_end(msg, acl);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
+ ret, strerror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ return ret;
+}
+
+
static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
@@ -6190,12 +6270,25 @@ static int wpa_driver_nl80211_sta_add(void *priv,
wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates,
params->supp_rates_len);
if (!params->set) {
- wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ if (params->aid) {
+ wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ } else {
+ /*
+ * cfg80211 validates that AID is non-zero, so we have
+ * to make this a non-zero value for the TDLS case where
+ * a dummy STA entry is used for now.
+ */
+ wpa_printf(MSG_DEBUG, " * aid=1 (TDLS workaround)");
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+ }
wpa_printf(MSG_DEBUG, " * listen_interval=%u",
params->listen_interval);
NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
params->listen_interval);
+ } else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
+ wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
+ NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid);
}
if (params->ht_capabilities) {
wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
@@ -7241,7 +7334,9 @@ static int wpa_driver_nl80211_try_connect(
if (params->freq) {
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
- }
+ drv->assoc_freq = params->freq;
+ } else
+ drv->assoc_freq = 0;
if (params->bg_scan_period >= 0) {
wpa_printf(MSG_DEBUG, " * bg scan period=%d",
params->bg_scan_period);
@@ -7452,8 +7547,6 @@ static int wpa_driver_nl80211_connect(
if (wpa_driver_nl80211_disconnect(
drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
return -1;
- /* Ignore the next local disconnect message. */
- drv->ignore_next_local_disconnect = 1;
ret = wpa_driver_nl80211_try_connect(drv, params);
}
return ret;
@@ -9974,6 +10067,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
.set_ap = wpa_driver_nl80211_set_ap,
+ .set_acl = wpa_driver_nl80211_set_acl,
.if_add = wpa_driver_nl80211_if_add,
.if_remove = driver_nl80211_if_remove,
.send_mlme = driver_nl80211_send_mlme,
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 79da8710..32b060ea 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -27,6 +27,8 @@
#include <linux/types.h>
+#define NL80211_GENL_NAME "nl80211"
+
/**
* DOC: Station handling
*
@@ -639,6 +641,13 @@
* with the relevant Information Elements. This event is used to report
* received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE).
*
+ * @NL80211_CMD_CRIT_PROTOCOL_START: Indicates user-space will start running
+ * a critical protocol that needs more reliability in the connection to
+ * complete.
+ *
+ * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
+ * return back to normal.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -798,6 +807,9 @@ enum nl80211_commands {
NL80211_CMD_UPDATE_FT_IES,
NL80211_CMD_FT_EVENT,
+ NL80211_CMD_CRIT_PROTOCOL_START,
+ NL80211_CMD_CRIT_PROTOCOL_STOP,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1414,6 +1426,16 @@ enum nl80211_commands {
* @NL80211_ATTR_IE_RIC: Resource Information Container Information
* Element
*
+ * @NL80211_ATTR_CRIT_PROT_ID: critical protocol identifier requiring increased
+ * reliability, see &enum nl80211_crit_proto_id (u16).
+ * @NL80211_ATTR_MAX_CRIT_PROT_DURATION: duration in milliseconds in which
+ * the connection should have increased reliability (u16).
+ *
+ * @NL80211_ATTR_PEER_AID: Association ID for the peer TDLS station (u16).
+ * This is similar to @NL80211_ATTR_STA_AID but with a difference of being
+ * allowed to be used with the first @NL80211_CMD_SET_STATION command to
+ * update a TDLS peer STA entry.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1709,6 +1731,11 @@ enum nl80211_attrs {
NL80211_ATTR_MDID,
NL80211_ATTR_IE_RIC,
+ NL80211_ATTR_CRIT_PROT_ID,
+ NL80211_ATTR_MAX_CRIT_PROT_DURATION,
+
+ NL80211_ATTR_PEER_AID,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1973,6 +2000,10 @@ enum nl80211_sta_bss_param {
* @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode
* @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards
* non-peer STA
+ * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU
+ * Contains a nested array of signal strength attributes (u8, dBm)
+ * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
+ * Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -2002,6 +2033,8 @@ enum nl80211_sta_info {
NL80211_STA_INFO_NONPEER_PM,
NL80211_STA_INFO_RX_BYTES64,
NL80211_STA_INFO_TX_BYTES64,
+ NL80211_STA_INFO_CHAIN_SIGNAL,
+ NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -2619,6 +2652,10 @@ enum nl80211_meshconf_params {
* @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will
* implement an MPM which handles peer allocation and state.
*
+ * @NL80211_MESH_SETUP_AUTH_PROTOCOL: Inform the kernel of the authentication
+ * method (u8, as defined in IEEE 8.4.2.100.6, e.g. 0x1 for SAE).
+ * Default is no authentication method required.
+ *
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
*
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -2632,6 +2669,7 @@ enum nl80211_mesh_setup_params {
NL80211_MESH_SETUP_USERSPACE_AMPE,
NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
NL80211_MESH_SETUP_USERSPACE_MPM,
+ NL80211_MESH_SETUP_AUTH_PROTOCOL,
/* keep last */
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
@@ -3682,4 +3720,25 @@ enum nl80211_protocol_features {
NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP = 1 << 0,
};
+/**
+ * enum nl80211_crit_proto_id - nl80211 critical protocol identifiers
+ *
+ * @NL80211_CRIT_PROTO_UNSPEC: protocol unspecified.
+ * @NL80211_CRIT_PROTO_DHCP: BOOTP or DHCPv6 protocol.
+ * @NL80211_CRIT_PROTO_EAPOL: EAPOL protocol.
+ * @NL80211_CRIT_PROTO_APIPA: APIPA protocol.
+ * @NUM_NL80211_CRIT_PROTO: must be kept last.
+ */
+enum nl80211_crit_proto_id {
+ NL80211_CRIT_PROTO_UNSPEC,
+ NL80211_CRIT_PROTO_DHCP,
+ NL80211_CRIT_PROTO_EAPOL,
+ NL80211_CRIT_PROTO_APIPA,
+ /* add other protocols before this one */
+ NUM_NL80211_CRIT_PROTO
+};
+
+/* maximum duration for critical protocol measures */
+#define NL80211_CRIT_PROTO_MAX_DURATION 5000 /* msec */
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 2e560865..898285e1 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1257,6 +1257,24 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
switch (hdr->type) {
case IEEE802_1X_TYPE_EAP_PACKET:
+ if (sm->conf.workaround) {
+ /*
+ * An AP has been reported to send out EAP message with
+ * undocumented code 10 at some point near the
+ * completion of EAP authentication. This can result in
+ * issues with the unexpected EAP message triggering
+ * restart of EAPOL authentication. Avoid this by
+ * skipping the message without advancing the state
+ * machine.
+ */
+ const struct eap_hdr *ehdr =
+ (const struct eap_hdr *) (hdr + 1);
+ if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
+ wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
+ break;
+ }
+ }
+
if (sm->cached_pmk) {
/* Trying to use PMKSA caching, but Authenticator did
* not seem to have a matching entry. Need to restart
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 2b5e5bd1..4424c92f 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -71,6 +71,8 @@ int p2p_connection_in_progress(struct p2p_data *p2p)
wpa_printf(MSG_DEBUG, "p2p_connection_in_progress state %d", p2p->state);
ret = 0;
}
+ if (p2p->pending_action_state == P2P_PENDING_PD)
+ ret = 1;
return ret;
}
@@ -268,8 +270,7 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
"P2P: Starting short listen state (state=%s)",
p2p_state_txt(p2p->state));
- freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
- p2p->cfg->channel);
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
if (freq < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unknown regulatory class/channel");
@@ -319,8 +320,7 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Going to listen(only) state");
- freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class,
- p2p->cfg->channel);
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
if (freq < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unknown regulatory class/channel");
@@ -914,7 +914,7 @@ static int p2p_get_next_prog_freq(struct p2p_data *p2p)
channel = c->reg_class[cl].channel[ch];
}
- freq = p2p_channel_to_freq(p2p->cfg->country, reg_class, channel);
+ freq = p2p_channel_to_freq(reg_class, channel);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Next progressive search "
"channel: reg_class %u channel %u -> %d MHz",
reg_class, channel, freq);
@@ -1231,6 +1231,19 @@ void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
}
+void p2p_stop_listen(struct p2p_data *p2p)
+{
+ if (p2p->state != P2P_LISTEN_ONLY) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Skip stop_listen "
+ "since not in listen_only state.");
+ return;
+ }
+
+ p2p_stop_listen_for_freq(p2p, 0);
+ p2p_set_state(p2p, P2P_IDLE);
+}
+
+
void p2p_stop_find(struct p2p_data *p2p)
{
p2p_stop_find_for_freq(p2p, 0);
@@ -1244,8 +1257,7 @@ static int p2p_prepare_channel_pref(struct p2p_data *p2p,
u8 op_class, op_channel;
unsigned int freq = force_freq ? force_freq : pref_freq;
- if (p2p_freq_to_channel(p2p->cfg->country, freq,
- &op_class, &op_channel) < 0) {
+ if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unsupported frequency %u MHz", freq);
return -1;
@@ -1281,24 +1293,24 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_overall) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
- &op_class, &op_channel) == 0) {
+ p2p_freq_to_channel(p2p->best_freq_overall, &op_class, &op_channel)
+ == 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best "
"overall channel as operating channel preference");
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_5) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
- &op_class, &op_channel) == 0) {
+ p2p_freq_to_channel(p2p->best_freq_5, &op_class, &op_channel)
+ == 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 5 GHz "
"channel as operating channel preference");
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
p2p_supported_freq(p2p, p2p->best_freq_24) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
- &op_class, &op_channel) == 0) {
+ p2p_freq_to_channel(p2p->best_freq_24, &op_class,
+ &op_channel) == 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 2.4 "
"GHz channel as operating channel preference");
p2p->op_reg_class = op_class;
@@ -1547,8 +1559,7 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
if (msg->listen_channel) {
int freq;
- freq = p2p_channel_to_freq((char *) msg->listen_channel,
- msg->listen_channel[3],
+ freq = p2p_channel_to_freq(msg->listen_channel[3],
msg->listen_channel[4]);
if (freq < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1647,8 +1658,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
if (go) {
/* Setup AP mode for WPS provisioning */
- res.freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->op_reg_class,
+ res.freq = p2p_channel_to_freq(p2p->op_reg_class,
p2p->op_channel);
os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
res.ssid_len = p2p->ssid_len;
@@ -1672,8 +1682,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
int freq;
if (freqs + 1 == P2P_MAX_CHANNELS)
break;
- freq = p2p_channel_to_freq(peer->country, c->reg_class,
- c->channel[j]);
+ freq = p2p_channel_to_freq(c->reg_class, c->channel[j]);
if (freq < 0)
continue;
res.freq_list[freqs++] = freq;
@@ -1903,8 +1912,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
if (msg.listen_channel) {
os_memcpy(dev->country, msg.listen_channel, 3);
- dev->listen_freq = p2p_channel_to_freq(dev->country,
- msg.listen_channel[3],
+ dev->listen_freq = p2p_channel_to_freq(msg.listen_channel[3],
msg.listen_channel[4]);
}
@@ -4142,7 +4150,7 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
{
- if (p2p_channel_to_freq(p2p->cfg->country, reg_class, channel) < 0)
+ if (p2p_channel_to_freq(reg_class, channel) < 0)
return -1;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set Listen channel: "
@@ -4172,8 +4180,7 @@ int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
int cfg_op_channel)
{
- if (p2p_channel_to_freq(p2p->cfg->country, op_reg_class, op_channel)
- < 0)
+ if (p2p_channel_to_freq(op_reg_class, op_channel) < 0)
return -1;
wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 28a0a1d1..f76f401d 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -693,6 +693,7 @@ struct p2p_config {
* @persistent_group: Whether this is an invitation to reinvoke a
* persistent group (instead of invitation to join an active
* group)
+ * @channels: Available operating channels for the group
* Returns: Status code (P2P_SC_*)
*
* This optional callback can be used to implement persistent reconnect
@@ -713,7 +714,8 @@ struct p2p_config {
u8 (*invitation_process)(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *go_dev_addr, const u8 *ssid,
size_t ssid_len, int *go, u8 *group_bssid,
- int *force_freq, int persistent_group);
+ int *force_freq, int persistent_group,
+ const struct p2p_channels *channels);
/**
* invitation_received - Callback on Invitation Request RX
@@ -906,6 +908,12 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq);
int p2p_listen(struct p2p_data *p2p, unsigned int timeout);
/**
+ * p2p_stop_listen - Stop P2P Listen
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_stop_listen(struct p2p_data *p2p);
+
+/**
* p2p_connect - Start P2P group formation (GO negotiation)
* @p2p: P2P module context from p2p_init()
* @peer_addr: MAC address of the peer P2P client
@@ -1648,6 +1656,15 @@ int p2p_channels_includes_freq(const struct p2p_channels *channels,
*/
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
+/**
+ * p2p_get_pref_freq - Get channel from preferred channel list
+ * @p2p: P2P module context from p2p_init()
+ * @channels: List of channels
+ * Returns: Preferred channel
+ */
+unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
+ const struct p2p_channels *channels);
+
void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
/**
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index c143ef4a..5d0b5cae 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -351,7 +351,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
unsigned int i;
if (p2p->own_freq_preference > 0 &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->own_freq_preference,
+ p2p_freq_to_channel(p2p->own_freq_preference,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick own channel "
@@ -363,7 +363,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
}
if (p2p->best_freq_overall > 0 &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
+ p2p_freq_to_channel(p2p->best_freq_overall,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best overall "
@@ -375,12 +375,11 @@ void p2p_reselect_channel(struct p2p_data *p2p,
}
/* First, try to pick the best channel from another band */
- freq = p2p_channel_to_freq(p2p->cfg->country, p2p->op_reg_class,
- p2p->op_channel);
+ freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel);
if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 &&
!p2p_channels_includes(intersection, p2p->op_reg_class,
p2p->op_channel) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
+ p2p_freq_to_channel(p2p->best_freq_5,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 5 GHz "
@@ -394,7 +393,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 &&
!p2p_channels_includes(intersection, p2p->op_reg_class,
p2p->op_channel) &&
- p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
+ p2p_freq_to_channel(p2p->best_freq_24,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 2.4 GHz "
@@ -435,6 +434,29 @@ void p2p_reselect_channel(struct p2p_data *p2p,
}
}
+ /* Prefer a 5 GHz channel */
+ for (i = 0; i < intersection->reg_classes; i++) {
+ struct p2p_reg_class *c = &intersection->reg_class[i];
+ if ((c->reg_class == 115 || c->reg_class == 124) &&
+ c->channels) {
+ unsigned int r;
+
+ /*
+ * Pick one of the available channels in the operating
+ * class at random.
+ */
+ os_get_random((u8 *) &r, sizeof(r));
+ r %= c->channels;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Pick possible 5 GHz channel (reg_class "
+ "%u channel %u) from intersection",
+ c->reg_class, c->channel[r]);
+ p2p->op_reg_class = c->reg_class;
+ p2p->op_channel = c->channel[r];
+ return;
+ }
+ }
+
/*
* Try to see if the original channel is in the intersection. If
* so, no need to change anything, as it already contains some
@@ -736,9 +758,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
goto fail;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
- dev->oper_freq = p2p_channel_to_freq((const char *)
- msg.operating_channel,
- msg.operating_channel[3],
+ dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
msg.operating_channel[4]);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
"channel preference: %d MHz", dev->oper_freq);
@@ -773,8 +793,7 @@ fail:
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1050,9 +1069,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
}
if (msg.operating_channel) {
- dev->oper_freq = p2p_channel_to_freq((const char *)
- msg.operating_channel,
- msg.operating_channel[3],
+ dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
msg.operating_channel[4]);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
"channel preference: %d MHz", dev->oper_freq);
@@ -1231,10 +1248,8 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
#ifdef ANDROID_P2P
if (msg.operating_channel) {
- dev->oper_freq = p2p_channel_to_freq((const char *)
- msg.operating_channel,
- msg.operating_channel[3],
- msg.operating_channel[4]);
+ dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3],
+ msg.operating_channel[4]);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
"channel preference: %d MHz", dev->oper_freq);
} else
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index d5ce52f8..7261ea80 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -569,9 +569,8 @@ struct p2p_group_info {
/* p2p_utils.c */
int p2p_random(char *buf, size_t len);
-int p2p_channel_to_freq(const char *country, int reg_class, int channel);
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
- u8 *channel);
+int p2p_channel_to_freq(int op_class, int channel);
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
void p2p_channels_intersect(const struct p2p_channels *a,
const struct p2p_channels *b,
struct p2p_channels *res);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 3beefd24..11a7727c 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -228,18 +228,20 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
goto fail;
}
+ p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+ &intersection);
+
if (p2p->cfg->invitation_process) {
status = p2p->cfg->invitation_process(
p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id,
msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
- &go, group_bssid, &op_freq, persistent);
+ &go, group_bssid, &op_freq, persistent, &intersection);
}
if (op_freq) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invitation "
"processing forced frequency %d MHz", op_freq);
- if (p2p_freq_to_channel(p2p->cfg->country, op_freq,
- &reg_class, &channel) < 0) {
+ if (p2p_freq_to_channel(op_freq, &reg_class, &channel) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unknown forced freq %d MHz from "
"invitation_process()", op_freq);
@@ -247,8 +249,6 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
goto fail;
}
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
- &intersection);
if (!p2p_channels_includes(&intersection, reg_class, channel))
{
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -265,8 +265,6 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
"P2P: No forced channel from invitation processing - "
"figure out best one to use");
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
- &intersection);
/* Default to own configuration as a starting point */
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
@@ -278,7 +276,6 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
if (msg.operating_channel) {
int req_freq;
req_freq = p2p_channel_to_freq(
- (const char *) msg.operating_channel,
msg.operating_channel[3],
msg.operating_channel[4]);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer "
@@ -324,10 +321,17 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
+ } else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
+ !p2p->cfg->cfg_op_channel) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Try to reselect channel selection with "
+ "peer information received; "
+ "previously selected op_class %u channel %u",
+ p2p->op_reg_class, p2p->op_channel);
+ p2p_reselect_channel(p2p, &intersection);
}
- op_freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->op_reg_class,
+ op_freq = p2p_channel_to_freq(p2p->op_reg_class,
p2p->op_channel);
if (op_freq < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -362,8 +366,7 @@ fail:
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -533,11 +536,8 @@ void p2p_invitation_req_cb(struct p2p_data *p2p, int success)
* channel.
*/
p2p_set_state(p2p, P2P_INVITE);
-#ifdef ANDROID_P2P
- p2p_set_timeout(p2p, 0, 350000);
-#else
- p2p_set_timeout(p2p, 0, 100000);
-#endif
+
+ p2p_set_timeout(p2p, 0, success ? 350000 : 100000);
}
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index a1268e44..3bbce164 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -217,8 +217,7 @@ out:
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index bf756050..d8daa59d 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -290,8 +290,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
if (rx_freq > 0)
freq = rx_freq;
else
- freq = p2p_channel_to_freq(p2p->cfg->country,
- p2p->cfg->reg_class,
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
p2p->cfg->channel);
if (freq < 0)
return;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 37b9361a..0da26827 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -46,11 +46,17 @@ int p2p_random(char *buf, size_t len)
}
-static int p2p_channel_to_freq_j4(int reg_class, int channel)
+/**
+ * p2p_channel_to_freq - Convert channel info to frequency
+ * @op_class: Operating class
+ * @channel: Channel number
+ * Returns: Frequency in MHz or -1 if the specified channel is unknown
+ */
+int p2p_channel_to_freq(int op_class, int channel)
{
- /* Table J-4 in P802.11REVmb/D4.0 - Global operating classes */
- /* TODO: more regulatory classes */
- switch (reg_class) {
+ /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
+ /* TODO: more operating classes */
+ switch (op_class) {
case 81:
/* channels 1..13 */
if (channel < 1 || channel > 13)
@@ -94,75 +100,34 @@ static int p2p_channel_to_freq_j4(int reg_class, int channel)
/**
- * p2p_channel_to_freq - Convert channel info to frequency
- * @country: Country code
- * @reg_class: Regulatory class
- * @channel: Channel number
- * Returns: Frequency in MHz or -1 if the specified channel is unknown
- */
-int p2p_channel_to_freq(const char *country, int reg_class, int channel)
-{
- if (country[2] == 0x04)
- return p2p_channel_to_freq_j4(reg_class, channel);
-
- /* These are mainly for backwards compatibility; to be removed */
- switch (reg_class) {
- case 1: /* US/1, EU/1, JP/1 = 5 GHz, channels 36,40,44,48 */
- if (channel < 36 || channel > 48)
- return -1;
- return 5000 + 5 * channel;
- case 3: /* US/3 = 5 GHz, channels 149,153,157,161 */
- case 5: /* US/5 = 5 GHz, channels 149,153,157,161 */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 4: /* EU/4 = 2.407 GHz, channels 1..13 */
- case 12: /* US/12 = 2.407 GHz, channels 1..11 */
- case 30: /* JP/30 = 2.407 GHz, channels 1..13 */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 31: /* JP/31 = 2.414 GHz, channel 14 */
- if (channel != 14)
- return -1;
- return 2414 + 5 * channel;
- }
-
- return -1;
-}
-
-
-/**
* p2p_freq_to_channel - Convert frequency into channel info
- * @country: Country code
- * @reg_class: Buffer for returning regulatory class
+ * @op_class: Buffer for returning operating class
* @channel: Buffer for returning channel number
* Returns: 0 on success, -1 if the specified frequency is unknown
*/
-int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class,
- u8 *channel)
+int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
{
/* TODO: more operating classes */
if (freq >= 2412 && freq <= 2472) {
- *reg_class = 81; /* 2.407 GHz, channels 1..13 */
+ *op_class = 81; /* 2.407 GHz, channels 1..13 */
*channel = (freq - 2407) / 5;
return 0;
}
if (freq == 2484) {
- *reg_class = 82; /* channel 14 */
+ *op_class = 82; /* channel 14 */
*channel = 14;
return 0;
}
if (freq >= 5180 && freq <= 5240) {
- *reg_class = 115; /* 5 GHz, channels 36..48 */
+ *op_class = 115; /* 5 GHz, channels 36..48 */
*channel = (freq - 5000) / 5;
return 0;
}
if (freq >= 5745 && freq <= 5805) {
- *reg_class = 124; /* 5 GHz, channels 149..161 */
+ *op_class = 124; /* 5 GHz, channels 149..161 */
*channel = (freq - 5000) / 5;
return 0;
}
@@ -261,9 +226,8 @@ int p2p_channels_includes_freq(const struct p2p_channels *channels,
for (i = 0; i < channels->reg_classes; i++) {
const struct p2p_reg_class *reg = &channels->reg_class[i];
for (j = 0; j < reg->channels; j++) {
- if (p2p_channel_to_freq_j4(reg->reg_class,
- reg->channel[j]) ==
- (int) freq)
+ if (p2p_channel_to_freq(reg->reg_class,
+ reg->channel[j]) == (int) freq)
return 1;
}
}
@@ -274,9 +238,36 @@ int p2p_channels_includes_freq(const struct p2p_channels *channels,
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
{
u8 op_reg_class, op_channel;
- if (p2p_freq_to_channel(p2p->cfg->country, freq,
- &op_reg_class, &op_channel) < 0)
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
return 0;
return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
op_channel);
}
+
+
+unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
+ const struct p2p_channels *channels)
+{
+ unsigned int i;
+ int freq = 0;
+
+ if (channels == NULL) {
+ if (p2p->cfg->num_pref_chan) {
+ freq = p2p_channel_to_freq(
+ p2p->cfg->pref_chan[0].op_class,
+ p2p->cfg->pref_chan[0].chan);
+ if (freq < 0)
+ freq = 0;
+ }
+ return freq;
+ }
+
+ for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
+ freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
+ p2p->cfg->pref_chan[i].chan);
+ if (p2p_channels_includes_freq(channels, freq))
+ return freq;
+ }
+
+ return 0;
+}
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 8ceaf6c3..53206142 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -37,8 +37,10 @@ unsigned int tdls_testing = 0;
#endif /* CONFIG_TDLS_TESTING */
#define TPK_LIFETIME 43200 /* 12 hours */
-#define TPK_RETRY_COUNT 3
-#define TPK_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M1_RETRY_COUNT 3
+#define TPK_M1_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M2_RETRY_COUNT 10
+#define TPK_M2_TIMEOUT 500 /* in milliseconds */
#define TDLS_MIC_LEN 16
@@ -79,6 +81,8 @@ struct wpa_tdls_frame {
static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs);
static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
+static void wpa_tdls_disable_peer_link(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer);
#define TDLS_MAX_IE_LEN 80
@@ -104,6 +108,7 @@ struct wpa_tdls_peer {
} tpk;
int tpk_set;
int tpk_success;
+ int tpk_in_progress;
struct tpk_timer {
u8 dest[ETH_ALEN];
@@ -126,6 +131,8 @@ struct wpa_tdls_peer {
u8 qos_info;
+ u16 aid;
+
u8 *ext_capab;
size_t ext_capab_len;
};
@@ -241,8 +248,13 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
- peer->sm_tmr.count = TPK_RETRY_COUNT;
- peer->sm_tmr.timer = TPK_TIMEOUT;
+ if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
+ peer->sm_tmr.count = TPK_M2_RETRY_COUNT;
+ peer->sm_tmr.timer = TPK_M2_TIMEOUT;
+ } else {
+ peer->sm_tmr.count = TPK_M1_RETRY_COUNT;
+ peer->sm_tmr.timer = TPK_M1_TIMEOUT;
+ }
/* Copy message to resend on timeout */
os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN);
@@ -258,28 +270,21 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
"(action_code=%u)", action_code);
- eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+ eloop_register_timeout(peer->sm_tmr.timer / 1000,
+ (peer->sm_tmr.timer % 1000) * 1000,
wpa_tdls_tpk_retry_timeout, sm, peer);
return 0;
}
static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
- u16 reason_code, int free_peer)
+ u16 reason_code)
{
int ret;
- if (sm->tdls_external_setup) {
- ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
-
- /* disable the link after teardown was sent */
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
- } else {
- ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
- }
-
- if (sm->tdls_external_setup || free_peer)
- wpa_tdls_peer_free(sm, peer);
+ ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
+ /* disable the link after teardown was sent */
+ wpa_tdls_disable_peer_link(sm, peer);
return ret;
}
@@ -293,7 +298,6 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
if (peer->sm_tmr.count) {
peer->sm_tmr.count--;
- peer->sm_tmr.timer = TPK_TIMEOUT;
wpa_printf(MSG_INFO, "TDLS: Retrying sending of message "
"(action_code=%u)",
@@ -320,14 +324,15 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
}
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
- eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+ eloop_register_timeout(peer->sm_tmr.timer / 1000,
+ (peer->sm_tmr.timer % 1000) * 1000,
wpa_tdls_tpk_retry_timeout, sm, peer);
} else {
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request");
wpa_tdls_do_teardown(sm, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
}
}
@@ -605,7 +610,7 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
" - tear down", MAC2STR(peer->addr));
wpa_tdls_do_teardown(sm, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
}
}
@@ -617,6 +622,7 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
peer->initiator = 0;
+ peer->tpk_in_progress = 0;
os_free(peer->sm_tmr.buf);
peer->sm_tmr.buf = NULL;
os_free(peer->ht_capabilities);
@@ -768,7 +774,15 @@ int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
return -1;
}
- return wpa_tdls_do_teardown(sm, peer, reason_code, 0);
+ return wpa_tdls_do_teardown(sm, peer, reason_code);
+}
+
+
+static void wpa_tdls_disable_peer_link(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer)
+{
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ wpa_tdls_peer_free(sm, peer);
}
@@ -781,10 +795,8 @@ void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
break;
}
- if (peer) {
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
- wpa_tdls_peer_free(sm, peer);
- }
+ if (peer)
+ wpa_tdls_disable_peer_link(sm, peer);
}
@@ -857,11 +869,7 @@ skip_ftie:
* Request the driver to disable the direct link and clear associated
* keys.
*/
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-
- /* clear the Peerkey statemachine */
- wpa_tdls_peer_free(sm, peer);
-
+ wpa_tdls_disable_peer_link(sm, peer);
return 0;
}
@@ -925,6 +933,7 @@ static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm,
u8 *rbuf, *pos, *count_pos;
u16 count;
struct rsn_ie_hdr *hdr;
+ int status;
if (!wpa_tdls_get_privacy(sm)) {
wpa_printf(MSG_DEBUG, "TDLS: No security used on the link");
@@ -1085,11 +1094,11 @@ skip_ies:
"Handshake Message 1 (peer " MACSTR ")",
MAC2STR(peer->addr));
- wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0,
- rbuf, pos - rbuf);
+ status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST,
+ 1, 0, rbuf, pos - rbuf);
os_free(rbuf);
- return 0;
+ return status;
}
@@ -1103,6 +1112,7 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
u32 lifetime;
struct wpa_tdls_timeoutie timeoutie;
struct wpa_tdls_ftie *ftie;
+ int status;
buf_len = 0;
if (wpa_tdls_get_privacy(sm)) {
@@ -1168,11 +1178,11 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
skip_ies:
- wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
- rbuf, pos - rbuf);
+ status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE,
+ dtoken, 0, rbuf, pos - rbuf);
os_free(rbuf);
- return 0;
+ return status;
}
@@ -1186,6 +1196,7 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
struct wpa_tdls_ftie *ftie;
struct wpa_tdls_timeoutie timeoutie;
u32 lifetime;
+ int status;
buf_len = 0;
if (wpa_tdls_get_privacy(sm)) {
@@ -1249,11 +1260,11 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
skip_ies:
- wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0,
- rbuf, pos - rbuf);
+ status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM,
+ dtoken, 0, rbuf, pos - rbuf);
os_free(rbuf);
- return 0;
+ return status;
}
@@ -1340,7 +1351,8 @@ static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
peer->supp_rates_len = merge_byte_arrays(
peer->supp_rates, sizeof(peer->supp_rates),
kde->supp_rates + 2, kde->supp_rates_len - 2,
- kde->ext_supp_rates + 2, kde->ext_supp_rates_len - 2);
+ kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL,
+ kde->ext_supp_rates_len - 2);
return 0;
}
@@ -1472,19 +1484,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
"direct link is enabled - tear down the "
"old link first");
-#if 0
- /* TODO: Disabling the link would be more proper
- * operation here, but it seems to trigger a race with
- * some drivers handling the new request frame. */
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-#else
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
- src_addr);
- else
- wpa_tdls_del_key(sm, peer);
-#endif
- wpa_tdls_peer_free(sm, peer);
+ wpa_tdls_disable_peer_link(sm, peer);
}
/*
@@ -1505,12 +1505,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
MACSTR " (terminate previously "
"initiated negotiation",
MAC2STR(src_addr));
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
- src_addr);
- else
- wpa_tdls_del_key(sm, peer);
- wpa_tdls_peer_free(sm, peer);
+ wpa_tdls_disable_peer_link(sm, peer);
}
}
}
@@ -1556,6 +1551,8 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
peer->qos_info = kde.qosinfo;
+ peer->aid = kde.aid;
+
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
peer = wpa_tdls_add_peer(sm, src_addr, NULL);
@@ -1670,16 +1667,27 @@ skip_rsn:
}
ftie = (struct wpa_tdls_ftie *) kde.ftie;
- os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
peer->rsnie_i_len = kde.rsn_ie_len;
peer->cipher = cipher;
- if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
- wpa_msg(sm->ctx->ctx, MSG_WARNING,
- "TDLS: Failed to get random data for responder nonce");
- wpa_tdls_peer_free(sm, peer);
- goto error;
+ if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
+ /*
+ * There is no point in updating the RNonce for every obtained
+ * TPK M1 frame (e.g., retransmission due to timeout) with the
+ * same INonce (SNonce in FTIE). However, if the TPK M1 is
+ * retransmitted with a different INonce, update the RNonce
+ * since this is for a new TDLS session.
+ */
+ wpa_printf(MSG_DEBUG,
+ "TDLS: New TPK M1 INonce - generate new RNonce");
+ os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
+ if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
+ "TDLS: Failed to get random data for responder nonce");
+ wpa_tdls_peer_free(sm, peer);
+ goto error;
+ }
}
#if 0
@@ -1733,12 +1741,13 @@ skip_rsn:
skip_rsn_check:
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0, NULL, NULL, 0,
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
NULL, 0);
+ peer->tpk_in_progress = 1;
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
- wpa_tdls_disable_link(sm, peer->addr);
+ wpa_tdls_disable_peer_link(sm, peer);
goto error;
}
@@ -1754,6 +1763,7 @@ error:
static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
peer->tpk_success = 1;
+ peer->tpk_in_progress = 0;
eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
if (wpa_tdls_get_privacy(sm)) {
u32 lifetime = peer->lifetime;
@@ -1775,9 +1785,11 @@ static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
}
/* add supported rates, capabilities, and qos_info to the TDLS peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->aid,
+ peer->capability,
peer->supp_rates, peer->supp_rates_len,
- peer->ht_capabilities, peer->vht_capabilities,
+ peer->ht_capabilities,
+ peer->vht_capabilities,
peer->qos_info, peer->ext_capab,
peer->ext_capab_len);
@@ -1824,8 +1836,11 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
}
wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
- if (len < 3 + 2 + 1)
+ if (len < 3 + 2 + 1) {
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
+ }
+
pos = buf;
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
status = WPA_GET_LE16(pos);
@@ -1834,8 +1849,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u",
status);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -1846,8 +1860,10 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken);
- if (len < 3 + 2 + 1 + 2)
+ if (len < 3 + 2 + 1 + 2) {
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
+ }
/* capability information */
peer->capability = WPA_GET_LE16(pos);
@@ -1896,6 +1912,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
peer->qos_info = kde.qosinfo;
+ peer->aid = kde.aid;
+
if (!wpa_tdls_get_privacy(sm)) {
peer->rsnie_p_len = 0;
peer->cipher = WPA_CIPHER_NONE;
@@ -1986,9 +2004,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
(u8 *) timeoutie, ftie) < 0) {
/* Discard the frame */
wpa_tdls_del_key(sm, peer);
- wpa_tdls_peer_free(sm, peer);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -1999,8 +2015,10 @@ skip_rsn:
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
"TPK Handshake Message 3");
- wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer);
-
+ if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) {
+ wpa_tdls_disable_peer_link(sm, peer);
+ return -1;
+ }
wpa_tdls_enable_link(sm, peer);
return 0;
@@ -2008,8 +2026,7 @@ skip_rsn:
error:
wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
status);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -2041,7 +2058,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE);
if (len < 3 + 3)
- return -1;
+ goto error;
pos = buf;
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
@@ -2050,21 +2067,19 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (status != 0) {
wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u",
status);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
- return -1;
+ goto error;
}
pos += 2 /* status code */ + 1 /* dialog token */;
ielen = len - (pos - buf); /* start of IE in buf */
if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3");
- return -1;
+ goto error;
}
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3");
- return -1;
+ goto error;
}
wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3",
(u8 *) kde.lnkid, kde.lnkid_len);
@@ -2072,7 +2087,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS");
- return -1;
+ goto error;
}
if (!wpa_tdls_get_privacy(sm))
@@ -2080,7 +2095,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3");
- return -1;
+ goto error;
}
wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3",
kde.ftie, sizeof(*ftie));
@@ -2088,7 +2103,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (kde.rsn_ie == NULL) {
wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3");
- return -1;
+ goto error;
}
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3",
kde.rsn_ie, kde.rsn_ie_len);
@@ -2096,24 +2111,24 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) {
wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match "
"with the one sent in TPK M2");
- return -1;
+ goto error;
}
if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) {
wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does "
"not match with FTIE ANonce used in TPK M2");
- return -1;
+ goto error;
}
if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not "
"match with FTIE SNonce used in TPK M1");
- return -1;
+ goto error;
}
if (kde.key_lifetime == NULL) {
wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3");
- return -1;
+ goto error;
}
timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3",
@@ -2124,16 +2139,13 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (lifetime != peer->lifetime) {
wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
"TPK M3 (expected %u)", lifetime, peer->lifetime);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
- return -1;
+ goto error;
}
if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid,
(u8 *) timeoutie, ftie) < 0) {
wpa_tdls_del_key(sm, peer);
- wpa_tdls_peer_free(sm, peer);
- return -1;
+ goto error;
}
if (wpa_tdls_set_key(sm, peer) < 0)
@@ -2143,6 +2155,9 @@ skip_rsn:
wpa_tdls_enable_link(sm, peer);
return 0;
+error:
+ wpa_tdls_disable_peer_link(sm, peer);
+ return -1;
}
@@ -2196,14 +2211,21 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
if (peer == NULL)
return -1;
+ if (peer->tpk_in_progress) {
+ wpa_printf(MSG_DEBUG, "TDLS: Setup is already in progress with the peer");
+ return 0;
+ }
+
peer->initiator = 1;
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0, NULL, NULL, 0,
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
NULL, 0);
+ peer->tpk_in_progress = 1;
+
if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
- wpa_tdls_disable_link(sm, peer->addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index dbb493e4..78dfb523 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -56,7 +56,7 @@ struct wpa_sm_ctx {
u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf, size_t len);
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
- int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+ int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid,
u16 capability, const u8 *supp_rates,
size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
@@ -315,6 +315,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len);
int wpa_ft_is_completed(struct wpa_sm *sm);
+void wpa_reset_ft_completed(struct wpa_sm *sm);
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
size_t ies_len, const u8 *src_addr);
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
@@ -346,6 +347,10 @@ static inline int wpa_ft_is_completed(struct wpa_sm *sm)
return 0;
}
+static inline void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+}
+
static inline int
wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
const u8 *src_addr)
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 4b08a624..3a40c96f 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -534,6 +534,13 @@ int wpa_ft_is_completed(struct wpa_sm *sm)
}
+void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+ if (sm != NULL)
+ sm->ft_completed = 0;
+}
+
+
static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
size_t gtk_elem_len)
{
@@ -589,6 +596,13 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
}
wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
+ if (sm->group_cipher == WPA_CIPHER_TKIP) {
+ /* Swap Tx/Rx keys for Michael MIC */
+ u8 tmp[8];
+ os_memcpy(tmp, gtk + 16, 8);
+ os_memcpy(gtk + 16, gtk + 24, 8);
+ os_memcpy(gtk + 24, tmp, 8);
+ }
if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 877e6de1..0e0d373f 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -282,7 +282,7 @@ static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
static inline int
wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
- u16 capability, const u8 *supp_rates,
+ u16 aid, u16 capability, const u8 *supp_rates,
size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
@@ -290,7 +290,7 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
{
if (sm->ctx->tdls_peer_addset)
return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
- capability, supp_rates,
+ aid, capability, supp_rates,
supp_rates_len, ht_capab,
vht_capab, qosinfo,
ext_capab, ext_capab_len);
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 652197ff..ba203e62 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -430,6 +430,9 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
} else if (*pos == WLAN_EID_HT_CAP) {
ie->ht_capabilities = pos + 2;
ie->ht_capabilities_len = pos[1];
+ } else if (*pos == WLAN_EID_VHT_AID) {
+ if (pos[1] >= 2)
+ ie->aid = WPA_GET_LE16(pos + 2);
} else if (*pos == WLAN_EID_VHT_CAP) {
ie->vht_capabilities = pos + 2;
ie->vht_capabilities_len = pos[1];
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 82a5c08c..2c788012 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -54,6 +54,7 @@ struct wpa_eapol_ie_parse {
const u8 *vht_capabilities;
size_t vht_capabilities_len;
u8 qosinfo;
+ u16 aid;
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 9c0cebb7..9a62fce8 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -855,6 +855,12 @@ static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
"ID from %u to %u", wps->dev_pw_id, id);
+ if (wps->dev_pw_id == DEV_PW_PUSHBUTTON && id == DEV_PW_DEFAULT) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Workaround - ignore PBC-to-PIN change");
+ return 0;
+ }
+
if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
os_free(wps->dev_password);
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index b86c4c7a..c22bb5cb 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -329,7 +329,7 @@ CONFIG_PEERKEY=y
# This version is an experimental implementation based on IEEE 802.11w/D1.0
# draft and is subject to change since the standard has not yet been finalized.
# Driver support is also needed for IEEE 802.11w.
-#CONFIG_IEEE80211W=y
+CONFIG_IEEE80211W=y
# Select TLS implementation
# openssl = OpenSSL (default)
@@ -407,7 +407,7 @@ CONFIG_PEERKEY=y
#CONFIG_DYNAMIC_EAP_METHODS=y
# IEEE Std 802.11r-2008 (Fast BSS Transition)
-#CONFIG_IEEE80211R=y
+CONFIG_IEEE80211R=y
# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
#CONFIG_DEBUG_FILE=y
@@ -486,14 +486,18 @@ CONFIG_ANDROID_LOG=y
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
CONFIG_IEEE80211N=y
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+CONFIG_WNM=y
+
# Interworking (IEEE 802.11u)
# This can be used to enable functionality to improve interworking with
# external networks (GAS/ANQP to learn more about the networks and network
# selection based on available credentials).
-#CONFIG_INTERWORKING=y
+CONFIG_INTERWORKING=y
# Hotspot 2.0
-#CONFIG_HS20=y
+CONFIG_HS20=y
# Disable roaming in wpa_supplicant
CONFIG_NO_ROAMING=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 3ba44964..4033492a 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -251,6 +251,16 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->rsn_pairwise = WPA_CIPHER_NONE;
}
+ if (bss->wpa_group_rekey < 86400 && (bss->wpa & 2) &&
+ (bss->wpa_group == WPA_CIPHER_CCMP ||
+ bss->wpa_group == WPA_CIPHER_GCMP)) {
+ /*
+ * Strong ciphers do not need frequent rekeying, so increase
+ * the default GTK rekeying period to 24 hours.
+ */
+ bss->wpa_group_rekey = 86400;
+ }
+
#ifdef CONFIG_WPS
/*
* Enable WPS by default for open and WPA/WPA2-Personal network, but
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 0d988840..64964db2 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -3090,6 +3090,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(beacon_int), 0 },
{ FUNC(ap_vendor_elements), 0 },
{ INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
+ { INT(sched_scan_interval), 0 },
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 4a175ce9..9b69a4b0 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -854,6 +854,11 @@ struct wpa_config {
* allowing it to update the internal BSS table.
*/
int ignore_old_scan_res;
+
+ /**
+ * sched_scan_interval - schedule scan interval
+ */
+ unsigned int sched_scan_interval;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 8604ae8a..d13af1eb 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1015,6 +1015,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->ignore_old_scan_res)
fprintf(f, "ignore_old_scan_res=%d\n",
config->ignore_old_scan_res);
+ if (config->sched_scan_interval)
+ fprintf(f, "sched_scan_interval=%u\n",
+ config->sched_scan_interval);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 22921154..b06b90cd 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -50,7 +50,7 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
static int pno_start(struct wpa_supplicant *wpa_s)
{
- int ret;
+ int ret, interval;
size_t i, num_ssid;
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
@@ -108,7 +108,10 @@ static int pno_start(struct wpa_supplicant *wpa_s)
if (wpa_s->conf->filter_rssi)
params.filter_rssi = wpa_s->conf->filter_rssi;
- ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
+ interval = wpa_s->conf->sched_scan_interval ?
+ wpa_s->conf->sched_scan_interval : 10;
+
+ ret = wpa_drv_sched_scan(wpa_s, &params, interval * 1000);
os_free(params.filter_ssids);
if (ret == 0)
wpa_s->pno = 1;
@@ -4989,6 +4992,19 @@ static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
return ret;
}
+
+static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int query_reason;
+
+ query_reason = atoi(cmd);
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: WNM_BSS_QUERY query_reason=%d",
+ query_reason);
+
+ return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason);
+}
+
#endif /* CONFIG_WNM */
@@ -5036,7 +5052,27 @@ static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
{
int ret;
- ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
+ if (os_strncasecmp(cmd, "SETBAND ", 8) == 0) {
+ int val = atoi(cmd + 8);
+ /*
+ * Use driver_cmd for drivers that support it, but ignore the
+ * return value since scan requests from wpa_supplicant will
+ * provide a list of channels to scan for based on the SETBAND
+ * setting.
+ */
+ wpa_printf(MSG_DEBUG, "SETBAND: %d", val);
+ wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
+ ret = 0;
+ if (val == 0)
+ wpa_s->setband = WPA_SETBAND_AUTO;
+ else if (val == 1)
+ wpa_s->setband = WPA_SETBAND_5G;
+ else if (val == 2)
+ wpa_s->setband = WPA_SETBAND_2G;
+ else
+ ret = -1;
+ } else
+ ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
if (ret == 0)
ret = sprintf(buf, "%s\n", "OK");
return ret;
@@ -5625,6 +5661,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
reply_len = -1;
+ } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) {
+ if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10))
+ reply_len = -1;
#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "FLUSH") == 0) {
wpa_supplicant_ctrl_iface_flush(wpa_s);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index a85bc181..184b14ef 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -333,11 +333,24 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
}
+static int has_wep_key(struct wpa_ssid *ssid)
+{
+ int i;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+
#ifndef CONFIG_NO_SCAN_PROCESSING
static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
struct wpa_ssid *ssid)
{
- int i, privacy = 0;
+ int privacy = 0;
if (ssid->mixed_cell)
return 1;
@@ -347,12 +360,9 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
return 1;
#endif /* CONFIG_WPS */
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i]) {
- privacy = 1;
- break;
- }
- }
+ if (has_wep_key(ssid))
+ privacy = 1;
+
#ifdef IEEE8021X_EAPOL
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
@@ -788,6 +798,13 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
continue;
}
+ if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
+ has_wep_key(ssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - ignore WPA/WPA2 "
+ "AP for WEP network block");
+ continue;
+ }
+
if (!wpa_supplicant_match_privacy(bss, ssid)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy "
"mismatch");
@@ -1780,6 +1797,16 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
(wpa_s->current_ssid &&
wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE)) {
+ /*
+ * Set the key after having received joined-IBSS event
+ * from the driver.
+ */
+ wpa_supplicant_set_wpa_none_key(wpa_s,
+ wpa_s->current_ssid);
+ }
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
} else if (!ft_completed) {
@@ -2219,8 +2246,12 @@ static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, data->tdls.peer);
break;
case TDLS_REQUEST_TEARDOWN:
- wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer,
- data->tdls.reason_code);
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer,
+ data->tdls.reason_code);
+ else
+ wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN,
+ data->tdls.peer);
break;
}
}
@@ -2473,6 +2504,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->deauth_info.ie,
data->deauth_info.ie_len);
}
+ wpa_reset_ft_completed(wpa_s->wpa);
}
#ifdef CONFIG_AP
if (wpa_s->ap_iface && data && data->deauth_info.addr) {
@@ -2571,72 +2603,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_assoc_reject(wpa_s, data);
else {
-#ifdef ANDROID_P2P
-#if defined(LEGACY_STA_EVENTS)
- /* If assoc reject is reported by the driver, then avoid
- * waiting for the authentication timeout. Cancel the
- * authentication timeout and retry the assoc.
- */
- if(wpa_s->assoc_retries++ < 5) {
- wpa_printf(MSG_ERROR, "Retrying assoc "
- "Iteration:%d", wpa_s->assoc_retries);
- wpa_supplicant_cancel_auth_timeout(wpa_s);
-
- /* Clear the states */
- wpa_sm_notify_disassoc(wpa_s->wpa);
- wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 1, 0);
- } else
- wpa_s->assoc_retries = 0;
-#else
- if(!wpa_s->current_ssid) {
- wpa_printf(MSG_ERROR, "current_ssid == NULL");
- break;
- }
- /* If assoc reject is reported by the driver, then avoid
- * waiting for the authentication timeout. Cancel the
- * authentication timeout and retry the assoc.
- */
- if(wpa_s->current_ssid->assoc_retry++ < 10) {
- wpa_printf(MSG_ERROR, "Retrying assoc: %d ",
- wpa_s->current_ssid->assoc_retry);
-
- wpa_supplicant_cancel_auth_timeout(wpa_s);
-
- /* Clear the states */
- wpa_sm_notify_disassoc(wpa_s->wpa);
- wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-
- wpa_s->reassociate = 1;
- if (wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE) {
- const u8 *bl_bssid = data->assoc_reject.bssid;
- if (!bl_bssid || is_zero_ether_addr(bl_bssid))
- bl_bssid = wpa_s->pending_bssid;
- wpa_blacklist_add(wpa_s, bl_bssid);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else {
- wpa_supplicant_req_scan(wpa_s, 1, 0);
- }
- } else if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
- /* If we ASSOC_REJECT's hits threshold, disable the
- * network
- */
- wpa_printf(MSG_ERROR, "Assoc retry threshold reached. "
- "Disabling the network");
- wpa_s->current_ssid->assoc_retry = 0;
- wpa_supplicant_disable_network(wpa_s, wpa_s->current_ssid);
- wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
- }
-#endif
-#else
const u8 *bssid = data->assoc_reject.bssid;
if (bssid == NULL || is_zero_ether_addr(bssid))
bssid = wpa_s->pending_bssid;
wpas_connection_failed(wpa_s, bssid);
wpa_supplicant_mark_disassoc(wpa_s);
-#endif /* ANDROID_P2P */
}
break;
case EVENT_AUTH_TIMED_OUT:
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index fc311e97..7216c3aa 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -61,6 +61,16 @@
#define P2P_MAX_INITIAL_CONN_WAIT 10
#endif /* P2P_MAX_INITIAL_CONN_WAIT */
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * WPS provisioning step on the GO. This controls the extra time the P2P
+ * operation is considered to be in progress (e.g., to delay other scans) after
+ * WPS provisioning has been completed on the GO during group formation.
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO 10
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO */
+
#ifndef P2P_CONCURRENT_SEARCH_DELAY
#define P2P_CONCURRENT_SEARCH_DELAY 500
#endif /* P2P_CONCURRENT_SEARCH_DELAY */
@@ -736,8 +746,10 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
ssid, go_dev_addr);
if (network_id < 0 && ssid)
network_id = ssid->id;
- if (!client)
+ if (!client) {
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+ os_get_time(&wpa_s->global->p2p_go_wait_client);
+ }
}
@@ -2406,10 +2418,20 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
}
+static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+{
+ if (channels == NULL)
+ return 1; /* Assume no restrictions */
+ return p2p_channels_includes_freq(channels, freq);
+
+}
+
+
static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *go_dev_addr, const u8 *ssid,
size_t ssid_len, int *go, u8 *group_bssid,
- int *force_freq, int persistent_group)
+ int *force_freq, int persistent_group,
+ const struct p2p_channels *channels)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
@@ -2507,6 +2529,25 @@ accept_inv:
wpas_p2p_set_own_freq_preference(wpa_s, res);
}
+ if (*force_freq > 0 &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ if (*go == 0) {
+ /* We are the client */
+ wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
+ "running a GO but we are capable of MCC, "
+ "figure out the best channel to use");
+ *force_freq = 0;
+ } else if (!freq_included(channels, *force_freq)) {
+ /* We are the GO, and *force_freq is not in the
+ * intersection */
+ wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+ "in intersection but we are capable of MCC, "
+ "figure out the best channel to use",
+ *force_freq);
+ *force_freq = 0;
+ }
+ }
+
return P2P_SC_SUCCESS;
}
@@ -3096,6 +3137,12 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
"%d:%d", p2p.op_reg_class, p2p.op_channel);
}
+
+ if (wpa_s->conf->p2p_pref_chan && wpa_s->conf->num_p2p_pref_chan) {
+ p2p.pref_chan = wpa_s->conf->p2p_pref_chan;
+ p2p.num_pref_chan = wpa_s->conf->num_p2p_pref_chan;
+ }
+
if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
os_memcpy(p2p.country, wpa_s->conf->country, 2);
p2p.country[2] = 0x04;
@@ -4018,6 +4065,12 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
if (wpa_s->p2p_long_listen > 0) {
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
+ } else {
+ /*
+ * When listen duration is over, stop listen & update p2p_state
+ * to IDLE.
+ */
+ p2p_stop_listen(wpa_s->global->p2p);
}
}
@@ -4059,11 +4112,57 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
}
-static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
{
- if (channels == NULL)
- return 1; /* Assume no restrictions */
- return p2p_channels_includes_freq(channels, freq);
+ unsigned int r;
+
+ if (freq == 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
+ "band");
+ if (wpa_s->best_24_freq > 0 &&
+ p2p_supported_freq(wpa_s->global->p2p,
+ wpa_s->best_24_freq)) {
+ freq = wpa_s->best_24_freq;
+ wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
+ "channel: %d MHz", freq);
+ } else {
+ os_get_random((u8 *) &r, sizeof(r));
+ freq = 2412 + (r % 3) * 25;
+ wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
+ "channel: %d MHz", freq);
+ }
+ }
+
+ if (freq == 5) {
+ wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
+ "band");
+ if (wpa_s->best_5_freq > 0 &&
+ p2p_supported_freq(wpa_s->global->p2p,
+ wpa_s->best_5_freq)) {
+ freq = wpa_s->best_5_freq;
+ wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
+ "channel: %d MHz", freq);
+ } else {
+ os_get_random((u8 *) &r, sizeof(r));
+ freq = 5180 + (r % 4) * 20;
+ if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not select "
+ "5 GHz channel for P2P group");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
+ "channel: %d MHz", freq);
+ }
+ }
+
+ if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
+ "(%u MHz) is not supported for P2P uses",
+ freq);
+ return -1;
+ }
+
+ return freq;
}
@@ -4074,6 +4173,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
{
u8 bssid[ETH_ALEN];
int res;
+ unsigned int pref_freq;
os_memset(params, 0, sizeof(*params));
params->role_go = 1;
@@ -4130,6 +4230,11 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
params->freq = wpa_s->best_5_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
"channel %d MHz", params->freq);
+ } else if ((pref_freq = p2p_get_pref_freq(wpa_s->global->p2p,
+ channels))) {
+ params->freq = pref_freq;
+ wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz from preferred "
+ "channels", params->freq);
} else {
int chan;
for (chan = 0; chan < 11; chan++) {
@@ -4255,7 +4360,6 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int ht40)
{
struct p2p_go_neg_results params;
- unsigned int r;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -4264,51 +4368,9 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
wpas_p2p_stop_find_oper(wpa_s);
- if (freq == 2) {
- wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
- "band");
- if (wpa_s->best_24_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_24_freq)) {
- freq = wpa_s->best_24_freq;
- wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
- "channel: %d MHz", freq);
- } else {
- os_get_random((u8 *) &r, sizeof(r));
- freq = 2412 + (r % 3) * 25;
- wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band "
- "channel: %d MHz", freq);
- }
- }
-
- if (freq == 5) {
- wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
- "band");
- if (wpa_s->best_5_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_5_freq)) {
- freq = wpa_s->best_5_freq;
- wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
- "channel: %d MHz", freq);
- } else {
- os_get_random((u8 *) &r, sizeof(r));
- freq = 5180 + (r % 4) * 20;
- if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: Could not select "
- "5 GHz channel for P2P group");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band "
- "channel: %d MHz", freq);
- }
- }
-
- if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
- "(%u MHz) is not supported for P2P uses",
- freq);
+ freq = wpas_p2p_select_go_freq(wpa_s, freq);
+ if (freq < 0)
return -1;
- }
if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, NULL))
return -1;
@@ -4404,6 +4466,10 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
if (ssid->mode != WPAS_MODE_P2P_GO)
return -1;
+ freq = wpas_p2p_select_go_freq(wpa_s, freq);
+ if (freq < 0)
+ return -1;
+
if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, channels))
return -1;
@@ -5160,7 +5226,7 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
"during provisioning");
return;
}
-#ifndef ANDROID_P2P
+
if (wpa_s->show_group_started) {
/*
* Use the normal group formation timeout between the end of
@@ -5173,7 +5239,6 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
"complete");
return;
}
-#endif
wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
timeout);
@@ -5695,6 +5760,19 @@ int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
}
}
+ if (!ret && wpa_s->global->p2p_go_wait_client.sec) {
+ struct os_time now;
+ os_get_time(&now);
+ if (now.sec > wpa_s->global->p2p_go_wait_client.sec +
+ P2P_MAX_INITIAL_CONN_WAIT_GO) {
+ /* Wait for the first client has expired */
+ wpa_s->global->p2p_go_wait_client.sec = 0;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Waiting for initial client connection during group formation");
+ ret = 1;
+ }
+ }
+
return ret;
}
@@ -5754,6 +5832,7 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
+ wpa_s->global->p2p_go_wait_client.sec = 0;
if (addr == NULL)
return;
wpas_p2p_add_persistent_group_client(wpa_s, addr);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index db73a186..07e3e06c 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -522,6 +522,59 @@ static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_P2P */
+static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
+ u16 num_modes,
+ enum hostapd_hw_mode mode)
+{
+ u16 i;
+
+ for (i = 0; i < num_modes; i++) {
+ if (modes[i].mode == mode)
+ return &modes[i];
+ }
+
+ return NULL;
+}
+
+static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ enum hostapd_hw_mode band,
+ struct wpa_driver_scan_params *params)
+{
+ /* Include only supported channels for the specified band */
+ struct hostapd_hw_modes *mode;
+ int count, i;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ if (mode == NULL) {
+ /* No channels supported in this band - use empty list */
+ params->freqs = os_zalloc(sizeof(int));
+ return;
+ }
+
+ params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ if (params->freqs == NULL)
+ return;
+ for (count = 0, i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ params->freqs[count++] = mode->channels[i].freq;
+ }
+}
+
+static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
+{
+ if (wpa_s->hw.modes == NULL)
+ return; /* unknown what channels the driver supports */
+ if (params->freqs)
+ return; /* already using a limited channel set */
+ if (wpa_s->setband == WPA_SETBAND_5G)
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+ params);
+ else if (wpa_s->setband == WPA_SETBAND_2G)
+ wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+ params);
+}
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
@@ -576,7 +629,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
#ifdef CONFIG_P2P
- if (wpas_p2p_in_progress(wpa_s)) {
+ if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s)) {
if (wpa_s->sta_scan_pending &&
wpas_p2p_in_progress(wpa_s) == 2 &&
wpa_s->global->p2p_cb_on_scan_complete) {
@@ -761,7 +814,7 @@ ssid_list_set:
} else
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
-
+ wpa_setband_scan_freqs(wpa_s, &params);
params.filter_ssids = wpa_supplicant_build_filter_ssids(
wpa_s->conf, &params.num_filter_ssids);
if (extra_ie) {
@@ -1028,7 +1081,9 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
if (!ssid || !wpa_s->prev_sched_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
-
+ if (wpa_s->conf->sched_scan_interval)
+ wpa_s->sched_scan_interval =
+ wpa_s->conf->sched_scan_interval;
if (wpa_s->sched_scan_interval == 0)
wpa_s->sched_scan_interval = 10;
wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
@@ -1114,7 +1169,7 @@ scan:
"Starting sched scan: interval %d (no timeout)",
wpa_s->sched_scan_interval);
}
-
+ wpa_setband_scan_freqs(wpa_s, scan_params);
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
wpa_s->sched_scan_interval);
wpabuf_free(extra_ie);
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 4d9e4533..7de96c54 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -14,8 +14,12 @@
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "scan.h"
+#include "ctrl_iface.h"
+#include "bss.h"
+#include "wnm_sta.h"
#define MAX_TFS_IE_LEN 1024
+#define WNM_MAX_NEIGHBOR_REPORT 10
/* get the TFS IE from driver */
@@ -294,6 +298,199 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
}
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
+{
+ int i;
+
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].bearing);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap);
+ os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
+ }
+
+ os_free(wpa_s->wnm_neighbor_report_elements);
+ wpa_s->wnm_neighbor_report_elements = NULL;
+}
+
+
+static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
+ u8 id, u8 elen, const u8 *pos)
+{
+ switch (id) {
+ case WNM_NEIGHBOR_TSF:
+ if (elen < 2 + 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
+ break;
+ }
+ rep->tsf_info = os_zalloc(sizeof(struct tsf_info));
+ if (rep->tsf_info == NULL)
+ break;
+ rep->tsf_info->present = 1;
+ os_memcpy(rep->tsf_info->tsf_offset, pos, 2);
+ os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2);
+ break;
+ case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
+ if (elen < 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
+ "country string");
+ break;
+ }
+ rep->con_coun_str =
+ os_zalloc(sizeof(struct condensed_country_string));
+ if (rep->con_coun_str == NULL)
+ break;
+ rep->con_coun_str->present = 1;
+ os_memcpy(rep->con_coun_str->country_string, pos, 2);
+ break;
+ case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
+ if (elen < 1) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
+ "candidate");
+ break;
+ }
+ rep->bss_tran_can =
+ os_zalloc(sizeof(struct bss_transition_candidate));
+ if (rep->bss_tran_can == NULL)
+ break;
+ rep->bss_tran_can->present = 1;
+ rep->bss_tran_can->preference = pos[0];
+ break;
+ case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
+ if (elen < 12) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination "
+ "duration");
+ break;
+ }
+ rep->bss_term_dur =
+ os_zalloc(sizeof(struct bss_termination_duration));
+ if (rep->bss_term_dur == NULL)
+ break;
+ rep->bss_term_dur->present = 1;
+ os_memcpy(rep->bss_term_dur->duration, pos, 12);
+ break;
+ case WNM_NEIGHBOR_BEARING:
+ if (elen < 8) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
+ "bearing");
+ break;
+ }
+ rep->bearing = os_zalloc(sizeof(struct bearing));
+ if (rep->bearing == NULL)
+ break;
+ rep->bearing->present = 1;
+ os_memcpy(rep->bearing->bearing, pos, 8);
+ break;
+ case WNM_NEIGHBOR_MEASUREMENT_PILOT:
+ if (elen < 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
+ "pilot");
+ break;
+ }
+ rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
+ if (rep->meas_pilot == NULL)
+ break;
+ rep->meas_pilot->present = 1;
+ rep->meas_pilot->measurement_pilot = pos[0];
+ rep->meas_pilot->num_vendor_specific = pos[1];
+ os_memcpy(rep->meas_pilot->vendor_specific, pos + 2, elen - 2);
+ break;
+ case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
+ if (elen < 4) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
+ "capabilities");
+ break;
+ }
+ rep->rrm_cap =
+ os_zalloc(sizeof(struct rrm_enabled_capabilities));
+ if (rep->rrm_cap == NULL)
+ break;
+ rep->rrm_cap->present = 1;
+ os_memcpy(rep->rrm_cap->capabilities, pos, 4);
+ break;
+ case WNM_NEIGHBOR_MULTIPLE_BSSID:
+ if (elen < 2) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
+ break;
+ }
+ rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
+ if (rep->mul_bssid == NULL)
+ break;
+ rep->mul_bssid->present = 1;
+ rep->mul_bssid->max_bssid_indicator = pos[0];
+ rep->mul_bssid->num_vendor_specific = pos[1];
+ os_memcpy(rep->mul_bssid->vendor_specific, pos + 2, elen - 2);
+ break;
+ }
+}
+
+
+static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
+ const u8 *pos, u8 len,
+ struct neighbor_report *rep)
+{
+ u8 left = len;
+
+ if (left < 13) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
+ return;
+ }
+
+ os_memcpy(rep->bssid, pos, ETH_ALEN);
+ os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4);
+ rep->regulatory_class = *(pos + 10);
+ rep->channel_number = *(pos + 11);
+ rep->phy_type = *(pos + 12);
+
+ pos += 13;
+ left -= 13;
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ wnm_parse_neighbor_report_elem(rep, id, elen, pos);
+ left -= 2 + elen;
+ pos += elen;
+ }
+}
+
+
+static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res,
+ struct neighbor_report *neigh_rep,
+ u8 num_neigh_rep, u8 *bssid_to_connect)
+{
+
+ u8 i, j;
+
+ if (scan_res == NULL || num_neigh_rep == 0)
+ return 0;
+
+ for (i = 0; i < num_neigh_rep; i++) {
+ for (j = 0; j < scan_res->num; j++) {
+ /* Check for a better RSSI AP */
+ if (os_memcmp(scan_res->res[j]->bssid,
+ neigh_rep[i].bssid, ETH_ALEN) == 0 &&
+ scan_res->res[j]->level >
+ wpa_s->current_bss->level) {
+ /* Got a BSSID with better RSSI value */
+ os_memcpy(bssid_to_connect, neigh_rep[i].bssid,
+ ETH_ALEN);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
u8 dialog_token, u8 status,
u8 delay, const u8 *target_bssid)
@@ -332,29 +529,90 @@ static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
}
+void wnm_scan_response(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ u8 bssid[ETH_ALEN];
+
+ if (scan_res == NULL) {
+ wpa_printf(MSG_ERROR, "Scan result is NULL");
+ goto send_bss_resp_fail;
+ }
+
+ /* Compare the Neighbor Report and scan results */
+ if (compare_scan_neighbor_results(wpa_s, scan_res,
+ wpa_s->wnm_neighbor_report_elements,
+ wpa_s->wnm_num_neighbor_report,
+ bssid) == 1) {
+ /* Associate to the network */
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "WNM: Target AP not found from "
+ "BSS table");
+ goto send_bss_resp_fail;
+ }
+
+ /* Send the BSS Management Response - Accept */
+ if (wpa_s->wnm_reply) {
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ 0, /* Accept */
+ 0, NULL);
+ }
+
+ wpa_s->reassociate = 1;
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ wnm_deallocate_memory(wpa_s);
+ return;
+ }
+
+ /* Send reject response for all the failures */
+send_bss_resp_fail:
+ wnm_deallocate_memory(wpa_s);
+ if (wpa_s->wnm_reply) {
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ 1 /* Reject - unspecified */,
+ 0, NULL);
+ }
+ return;
+}
+
+
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
const u8 *pos, const u8 *end,
int reply)
{
- u8 dialog_token;
- u8 mode;
- u16 disassoc_timer;
-
if (pos + 5 > end)
return;
- dialog_token = pos[0];
- mode = pos[1];
- disassoc_timer = WPA_GET_LE16(pos + 2);
+ wpa_s->wnm_dialog_token = pos[0];
+ wpa_s->wnm_mode = pos[1];
+ wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
+ wpa_s->wnm_validity_interval = pos[4];
+ wpa_s->wnm_reply = reply;
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
"dialog_token=%u request_mode=0x%x "
"disassoc_timer=%u validity_interval=%u",
- dialog_token, mode, disassoc_timer, pos[4]);
+ wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
+ wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval);
+
pos += 5;
- if (mode & 0x08)
+
+ if (wpa_s->wnm_mode & 0x08) {
+ if (pos + 12 > end) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
+ return;
+ }
+ os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
pos += 12; /* BSS Termination Duration */
- if (mode & 0x10) {
+ }
+
+ if (wpa_s->wnm_mode & 0x10) {
char url[256];
if (pos + 1 > end || pos + 1 + pos[0] > end) {
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
@@ -363,14 +621,15 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
}
os_memcpy(url, pos + 1, pos[0]);
url[pos[0]] = '\0';
+ pos += 1 + pos[0];
wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - "
"session_info_url=%s", url);
}
- if (mode & 0x04) {
+ if (wpa_s->wnm_mode & 0x04) {
wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
- "Disassociation Timer %u", disassoc_timer);
- if (disassoc_timer && !wpa_s->scanning) {
+ "Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
+ if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) {
/* TODO: mark current BSS less preferred for
* selection */
wpa_printf(MSG_DEBUG, "Trying to find another BSS");
@@ -378,15 +637,85 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
}
}
- if (reply) {
- /* TODO: add support for reporting Accept */
- wnm_send_bss_transition_mgmt_resp(wpa_s, dialog_token,
+ if (wpa_s->wnm_mode & 0x01) {
+ wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
+ wpa_s->wnm_num_neighbor_report = 0;
+ os_free(wpa_s->wnm_neighbor_report_elements);
+ wpa_s->wnm_neighbor_report_elements = os_zalloc(
+ WNM_MAX_NEIGHBOR_REPORT *
+ sizeof(struct neighbor_report));
+ if (wpa_s->wnm_neighbor_report_elements == NULL)
+ return;
+
+ while (pos + 2 <= end &&
+ wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
+ {
+ u8 tag = *pos++;
+ u8 len = *pos++;
+
+ wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
+ tag);
+ if (pos + len > end) {
+ wpa_printf(MSG_DEBUG, "WNM: Truncated request");
+ return;
+ }
+ wnm_parse_neighbor_report(
+ wpa_s, pos, len,
+ &wpa_s->wnm_neighbor_report_elements[
+ wpa_s->wnm_num_neighbor_report]);
+
+ pos += len;
+ wpa_s->wnm_num_neighbor_report++;
+ }
+
+ wpa_s->scan_res_handler = wnm_scan_response;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else if (reply) {
+ wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management "
+ "Request Mode is zero");
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
1 /* Reject - unspecified */,
0, NULL);
}
}
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+ u8 query_reason)
+{
+ u8 buf[1000], *pos;
+ struct ieee80211_mgmt *mgmt;
+ size_t len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
+ MACSTR " query_reason=%u",
+ MAC2STR(wpa_s->bssid), query_reason);
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ os_memset(&buf, 0, sizeof(buf));
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY;
+ mgmt->u.action.u.bss_tm_query.dialog_token = 0;
+ mgmt->u.action.u.bss_tm_query.query_reason = query_reason;
+ pos = mgmt->u.action.u.bss_tm_query.variable;
+
+ len = pos - (u8 *) &mgmt->u.action.category;
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ &mgmt->u.action.category, len, 0);
+
+ return ret;
+}
+
+
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
struct rx_action *action)
{
@@ -418,6 +747,7 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
break;
default:
+ wpa_printf(MSG_ERROR, "WNM: Unknown request");
break;
}
}
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index 3f9d88b7..2933926c 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -12,10 +12,79 @@
struct rx_action;
struct wpa_supplicant;
+struct tsf_info {
+ u8 present;
+ u8 tsf_offset[2];
+ u8 beacon_interval[2];
+};
+
+struct condensed_country_string {
+ u8 present;
+ u8 country_string[2];
+};
+
+struct bss_transition_candidate {
+ u8 present;
+ u8 preference;
+};
+
+struct bss_termination_duration {
+ u8 present;
+ u8 duration[12];
+};
+
+struct bearing {
+ u8 present;
+ u8 bearing[8];
+};
+
+struct measurement_pilot {
+ u8 present;
+ u8 measurement_pilot;
+ u8 num_vendor_specific;
+ u8 vendor_specific[255];
+};
+
+struct rrm_enabled_capabilities {
+ u8 present;
+ u8 capabilities[4];
+};
+
+struct multiple_bssid {
+ u8 present;
+ u8 max_bssid_indicator;
+ u8 num_vendor_specific;
+ u8 vendor_specific[255];
+};
+
+struct neighbor_report {
+ u8 bssid[ETH_ALEN];
+ u8 bssid_information[4];
+ u8 regulatory_class;
+ u8 channel_number;
+ u8 phy_type;
+ struct tsf_info *tsf_info;
+ struct condensed_country_string *con_coun_str;
+ struct bss_transition_candidate *bss_tran_can;
+ struct bss_termination_duration *bss_term_dur;
+ struct bearing *bearing;
+ struct measurement_pilot *meas_pilot;
+ struct rrm_enabled_capabilities *rrm_cap;
+ struct multiple_bssid *mul_bssid;
+};
+
+
int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
u8 action, u16 intval, struct wpabuf *tfs_req);
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
struct rx_action *action);
+void wnm_scan_response(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+ u8 query_reason);
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+
#endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6238c110..6bba4fa0 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2290,6 +2290,12 @@ static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[])
return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
}
+
+static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WNM_BSS_QUERY", 1, argc, argv);
+}
+
#endif /* CONFIG_WNM */
@@ -2773,6 +2779,8 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
#ifdef CONFIG_WNM
{ "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
"<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
+ { "wnm_bss_query", wpa_cli_cmd_wnm_bss_query, NULL, cli_cmd_flag_none,
+ "<query reason> = Send BSS Transition Management Query" },
#endif /* CONFIG_WNM */
{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
"<params..> = Sent unprocessed command" },
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d1e86566..15e35f86 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -49,6 +49,7 @@
#include "scan.h"
#include "offchannel.h"
#include "hs20_supplicant.h"
+#include "wnm_sta.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
@@ -126,8 +127,8 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
}
-static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
u8 key[32];
size_t keylen;
@@ -470,6 +471,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->disallow_aps_ssid = NULL;
wnm_bss_keep_alive_deinit(wpa_s);
+#ifdef CONFIG_WNM
+ wnm_deallocate_memory(wpa_s);
+#endif /* CONFIG_WNM */
ext_password_deinit(wpa_s->ext_pw);
wpa_s->ext_pw = NULL;
@@ -1279,8 +1283,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_driver_capa capa;
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
- u8 ext_capab[10];
- int ext_capab_len;
#ifdef CONFIG_HT_OVERRIDES
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
@@ -1493,15 +1495,27 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_HS20 */
- ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
- if (ext_capab_len > 0) {
- u8 *pos = wpa_ie;
- if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
- pos += 2 + pos[1];
- os_memmove(pos + ext_capab_len, pos,
- wpa_ie_len - (pos - wpa_ie));
- wpa_ie_len += ext_capab_len;
- os_memcpy(pos, ext_capab, ext_capab_len);
+ /*
+ * Workaround: Add Extended Capabilities element only if the AP
+ * included this element in Beacon/Probe Response frames. Some older
+ * APs seem to have interoperability issues if this element is
+ * included, so while the standard may require us to include the
+ * element in all cases, it is justifiable to skip it to avoid
+ * interoperability issues.
+ */
+ if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
+ u8 ext_capab[10];
+ int ext_capab_len;
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+ if (ext_capab_len > 0) {
+ u8 *pos = wpa_ie;
+ if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+ pos += 2 + pos[1];
+ os_memmove(pos + ext_capab_len, pos,
+ wpa_ie_len - (pos - wpa_ie));
+ wpa_ie_len += ext_capab_len;
+ os_memcpy(pos, ext_capab, ext_capab_len);
+ }
}
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
@@ -3877,3 +3891,42 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s)
if (wpa_supplicant_fast_associate(wpa_s) != 1)
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
+
+
+/**
+ * wpas_wpa_is_in_progress - Check whether a connection is in progress
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is to check if the wpa state is in beginning of the connection
+ * during 4-way handshake or group key handshake with WPA on any shared
+ * interface.
+ */
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s)
+{
+ const char *rn, *rn2;
+ struct wpa_supplicant *ifs;
+
+ if (!wpa_s->driver->get_radio_name)
+ return 0;
+
+ rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+ if (rn == NULL || rn[0] == '\0')
+ return 0;
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs == wpa_s || !ifs->driver->get_radio_name)
+ continue;
+
+ rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+ if (!rn2 || os_strcmp(rn, rn2) != 0)
+ continue;
+ if (ifs->wpa_state >= WPA_AUTHENTICATING &&
+ ifs->wpa_state != WPA_COMPLETED) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Connection is in progress "
+ "on interface %s - defer scan", ifs->ifname);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 49a87d93..c7623ac4 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -238,6 +238,7 @@ struct wpa_global {
struct wpa_supplicant *p2p_group_formation;
struct wpa_supplicant *p2p_invite_group;
u8 p2p_dev_addr[ETH_ALEN];
+ struct os_time p2p_go_wait_client;
struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
int p2p_disabled;
@@ -350,6 +351,8 @@ struct wpa_supplicant {
struct wpa_ssid_value *disallow_aps_ssid;
size_t disallow_aps_ssid_count;
+ enum { WPA_SETBAND_AUTO, WPA_SETBAND_5G, WPA_SETBAND_2G } setband;
+
/* previous scan was wildcard when interleaving between
* wildcard scans and specific SSID scan when max_ssids=1 */
int prev_scan_wildcard;
@@ -692,6 +695,17 @@ struct wpa_supplicant {
u8 last_gas_dialog_token;
unsigned int no_keep_alive:1;
+
+#ifdef CONFIG_WNM
+ u8 wnm_dialog_token;
+ u8 wnm_reply;
+ u8 wnm_num_neighbor_report;
+ u8 wnm_mode;
+ u16 wnm_dissoc_timer;
+ u8 wnm_validity_interval;
+ u8 wnm_bss_termination_duration[12];
+ struct neighbor_report *wnm_neighbor_report_elements;
+#endif /* CONFIG_WNM */
};
@@ -704,6 +718,8 @@ void wpa_supplicant_apply_vht_overrides(
struct wpa_driver_associate_params *params);
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
@@ -782,6 +798,7 @@ int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
size_t ssid_len);
void wpas_request_connection(struct wpa_supplicant *wpa_s);
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
+int wpas_wpa_is_in_progress(struct wpa_supplicant *wpa_s);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index a08eb33d..eee48a77 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -4,3 +4,5 @@ ctrl_interface=wlan0
eapol_version=1
ap_scan=1
fast_reauth=1
+### flag to avoid creating new interface for p2p
+p2p_no_group_iface=1
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index cd518738..1a64df38 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -551,7 +551,7 @@ static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer)
static int wpa_supplicant_tdls_peer_addset(
- void *ctx, const u8 *peer, int add, u16 capability,
+ void *ctx, const u8 *peer, int add, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
@@ -563,7 +563,7 @@ static int wpa_supplicant_tdls_peer_addset(
os_memset(&params, 0, sizeof(params));
params.addr = peer;
- params.aid = 1;
+ params.aid = aid;
params.capability = capability;
params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 9af60849..f37c5beb 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -219,6 +219,80 @@ static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
}
+static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *new_ssid)
+{
+ struct wpa_ssid *ssid, *next;
+
+ for (ssid = wpa_s->conf->ssid, next = ssid ? ssid->next : NULL; ssid;
+ ssid = next, next = ssid ? ssid->next : NULL) {
+ /*
+ * new_ssid has already been added to the list in
+ * wpas_wps_add_network(), so skip it.
+ */
+ if (ssid == new_ssid)
+ continue;
+
+ if (ssid->bssid_set || new_ssid->bssid_set) {
+ if (ssid->bssid_set != new_ssid->bssid_set)
+ continue;
+ if (os_memcmp(ssid->bssid, new_ssid->bssid, ETH_ALEN) !=
+ 0)
+ continue;
+ }
+
+ /* compare SSID */
+ if (ssid->ssid_len == 0 || ssid->ssid_len != new_ssid->ssid_len)
+ continue;
+
+ if (ssid->ssid && new_ssid->ssid) {
+ if (os_memcmp(ssid->ssid, new_ssid->ssid,
+ ssid->ssid_len) != 0)
+ continue;
+ } else if (ssid->ssid || new_ssid->ssid)
+ continue;
+
+ /* compare security parameters */
+ if (ssid->auth_alg != new_ssid->auth_alg ||
+ ssid->key_mgmt != new_ssid->key_mgmt ||
+ ssid->proto != new_ssid->proto ||
+ ssid->pairwise_cipher != new_ssid->pairwise_cipher ||
+ ssid->group_cipher != new_ssid->group_cipher)
+ continue;
+
+ if (ssid->passphrase && new_ssid->passphrase) {
+ if (os_strlen(ssid->passphrase) !=
+ os_strlen(new_ssid->passphrase))
+ continue;
+ if (os_strcmp(ssid->passphrase, new_ssid->passphrase) !=
+ 0)
+ continue;
+ } else if (ssid->passphrase || new_ssid->passphrase)
+ continue;
+
+ if ((ssid->psk_set || new_ssid->psk_set) &&
+ os_memcmp(ssid->psk, new_ssid->psk, sizeof(ssid->psk)) != 0)
+ continue;
+
+ if (ssid->auth_alg == WPA_ALG_WEP) {
+ if (ssid->wep_tx_keyidx != new_ssid->wep_tx_keyidx)
+ continue;
+ if (os_memcmp(ssid->wep_key, new_ssid->wep_key,
+ sizeof(ssid->wep_key)))
+ continue;
+ if (os_memcmp(ssid->wep_key_len, new_ssid->wep_key_len,
+ sizeof(ssid->wep_key_len)))
+ continue;
+ }
+
+ /* Remove the duplicated older network entry. */
+ wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ }
+}
+
+
static int wpa_supplicant_wps_cred(void *ctx,
const struct wps_credential *cred)
{
@@ -438,6 +512,8 @@ static int wpa_supplicant_wps_cred(void *ctx,
if (cred->ap_channel)
wpa_s->wps_ap_channel = cred->ap_channel;
+ wpas_wps_remove_dup_network(wpa_s, ssid);
+
#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->conf->update_config &&
wpa_config_write(wpa_s->confname, wpa_s->conf)) {
@@ -573,6 +649,10 @@ static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
wpa_s->wps_success = 1;
wpas_notify_wps_event_success(wpa_s);
+ if (wpa_s->current_ssid)
+ wpas_clear_temp_disabled(wpa_s, wpa_s->current_ssid, 1);
+ wpa_s->extra_blacklist_count = 0;
+
/*
* Enable the networks disabled during wpas_wps_reassoc after 10
* seconds. The 10 seconds timer is to allow the data connection to be