aboutsummaryrefslogtreecommitdiffstats
path: root/src/ap
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2012-12-03 15:08:10 -0800
committerDmitry Shmidt <dimitrysh@google.com>2012-12-20 10:35:12 -0800
commitd5e4923d04122f81300fa68fb07d64ede28fd44d (patch)
tree29f99bf419804daf82e32e67911628df0c2e5f39 /src/ap
parent90f44d5ff88189e0972bcd376b662d898e4c3c2e (diff)
downloadandroid_external_wpa_supplicant_8-d5e4923d04122f81300fa68fb07d64ede28fd44d.tar.gz
android_external_wpa_supplicant_8-d5e4923d04122f81300fa68fb07d64ede28fd44d.tar.bz2
android_external_wpa_supplicant_8-d5e4923d04122f81300fa68fb07d64ede28fd44d.zip
Accumulative patch from commit f5f37d3a4fc2df2a24676b4f95afca15ed793cba
Author: Jouni Malinen <j@w1.fi> Date: Sun Nov 25 22:05:32 2012 +0200 Fix REAUTHENTICATE command after PMKSA caching The current PMKSA cache entry needs to be clear to allow EAPOL reauthentication to be started in case this association used PMKSA caching. - Remove old WPS_OOB NCF - WPS: Add preliminary NFC connection handover support for Enrollee - WPS: Reenable the networks disabled during wpa_wpas_reassoc - P2P: Avoid multi-channel scans when they are not needed - P2P: Allow discoverable interval for p2p_find to be configured - P2P: Allow all channels with multi-channel concurrency - Bonjour changes - Remove disassociate - HS 2.0 changes - Add preliminary support for using SQLite for eap_user database - Add SAE support - Add disallow_aps parameter to disallow BSSIDs/SSIDs Change-Id: I85358a05b39d46b8db49acdad667e771c580b05c Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'src/ap')
-rw-r--r--src/ap/ap_config.c55
-rw-r--r--src/ap/ap_config.h10
-rw-r--r--src/ap/authsrv.c2
-rw-r--r--src/ap/ctrl_iface_ap.c26
-rw-r--r--src/ap/drv_callbacks.c18
-rw-r--r--src/ap/eap_user_db.c270
-rw-r--r--src/ap/hostapd.c12
-rw-r--r--src/ap/hostapd.h9
-rw-r--r--src/ap/ieee802_11.c210
-rw-r--r--src/ap/ieee802_11_auth.c135
-rw-r--r--src/ap/ieee802_11_auth.h5
-rw-r--r--src/ap/ieee802_11_vht.c2
-rw-r--r--src/ap/ieee802_1x.c7
-rw-r--r--src/ap/pmksa_cache_auth.c6
-rw-r--r--src/ap/sta_info.c4
-rw-r--r--src/ap/sta_info.h11
-rw-r--r--src/ap/tkip_countermeasures.c11
-rw-r--r--src/ap/tkip_countermeasures.h4
-rw-r--r--src/ap/wpa_auth.c28
-rw-r--r--src/ap/wpa_auth.h4
-rw-r--r--src/ap/wpa_auth_glue.c18
-rw-r--r--src/ap/wpa_auth_ie.c24
-rw-r--r--src/ap/wps_hostapd.c58
-rw-r--r--src/ap/wps_hostapd.h2
24 files changed, 723 insertions, 208 deletions
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 31e1c19c..3c699f71 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -408,6 +408,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
user = user->next;
hostapd_config_free_eap_user(prev_user);
}
+ os_free(conf->eap_user_sqlite);
os_free(conf->dump_log_name);
os_free(conf->eap_req_id_text);
@@ -619,57 +620,3 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
return NULL;
}
-
-
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
- size_t identity_len, int phase2)
-{
- struct hostapd_eap_user *user = conf->eap_user;
-
-#ifdef CONFIG_WPS
- if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
- os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
- static struct hostapd_eap_user wsc_enrollee;
- os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
- wsc_enrollee.methods[0].method = eap_server_get_type(
- "WSC", &wsc_enrollee.methods[0].vendor);
- return &wsc_enrollee;
- }
-
- if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
- os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
- static struct hostapd_eap_user wsc_registrar;
- os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
- wsc_registrar.methods[0].method = eap_server_get_type(
- "WSC", &wsc_registrar.methods[0].vendor);
- wsc_registrar.password = (u8 *) conf->ap_pin;
- wsc_registrar.password_len = conf->ap_pin ?
- os_strlen(conf->ap_pin) : 0;
- return &wsc_registrar;
- }
-#endif /* CONFIG_WPS */
-
- while (user) {
- if (!phase2 && user->identity == NULL) {
- /* Wildcard match */
- break;
- }
-
- if (user->phase2 == !!phase2 && user->wildcard_prefix &&
- identity_len >= user->identity_len &&
- os_memcmp(user->identity, identity, user->identity_len) ==
- 0) {
- /* Wildcard prefix match */
- break;
- }
-
- if (user->phase2 == !!phase2 &&
- user->identity_len == identity_len &&
- os_memcmp(user->identity, identity, identity_len) == 0)
- break;
- user = user->next;
- }
-
- return user;
-}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index f5e4a6a5..71313c02 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -96,6 +96,11 @@ struct hostapd_vlan {
};
#define PMK_LEN 32
+struct hostapd_sta_wpa_psk_short {
+ struct hostapd_sta_wpa_psk_short *next;
+ u8 psk[PMK_LEN];
+};
+
struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
@@ -192,6 +197,7 @@ struct hostapd_bss_config {
int eap_server; /* Use internal EAP server instead of external
* RADIUS server */
struct hostapd_eap_user *eap_user;
+ char *eap_user_sqlite;
char *eap_sim_db;
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
@@ -505,6 +511,7 @@ struct hostapd_config {
int require_vht;
u8 vht_oper_chwidth;
u8 vht_oper_centr_freq_seg0_idx;
+ u8 vht_oper_centr_freq_seg1_idx;
};
@@ -523,9 +530,6 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
- size_t identity_len, int phase2);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 5c03f45c..d66d97e4 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -92,7 +92,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
srv.auth_port = conf->radius_server_auth_port;
- srv.conf_ctx = conf;
+ srv.conf_ctx = hapd;
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
srv.ssl_ctx = hapd->ssl_ctx;
srv.msg_ctx = hapd->msg_ctx;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index ab9c83eb..c55d3fe3 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -21,6 +21,28 @@
#include "ap_drv_ops.h"
+static int hostapd_get_sta_conn_time(struct sta_info *sta,
+ char *buf, size_t buflen)
+{
+ struct os_time now, age;
+ int len = 0, ret;
+
+ if (!sta->connected_time.sec)
+ return 0;
+
+ os_get_time(&now);
+ os_time_sub(&now, &sta->connected_time, &age);
+
+ ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
+ (unsigned int) age.sec);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ return len;
+}
+
+
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
@@ -58,6 +80,10 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (res >= 0)
len += res;
+ res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+
return len;
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 23fa241a..86139752 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -109,6 +109,15 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_HS20
+ wpabuf_free(sta->hs20_ie);
+ if (elems.hs20 && elems.hs20_len > 4) {
+ sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+ elems.hs20_len - 4);
+ } else
+ sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
if (hapd->conf->wpa) {
if (ie == NULL || ielen == 0) {
#ifdef CONFIG_WPS
@@ -672,12 +681,15 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
const u8 *data, size_t data_len)
{
struct hostapd_iface *iface = hapd->iface;
+ struct sta_info *sta;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
- if (ap_get_sta(iface->bss[j], src)) {
- hapd = iface->bss[j];
- break;
+ if ((sta = ap_get_sta(iface->bss[j], src))) {
+ if (sta->flags & WLAN_STA_ASSOC) {
+ hapd = iface->bss[j];
+ break;
+ }
}
}
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
new file mode 100644
index 00000000..79d50e51
--- /dev/null
+++ b/src/ap/eap_user_db.c
@@ -0,0 +1,270 @@
+/*
+ * hostapd / EAP user database
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
+#include "common.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_server/eap_methods.h"
+#include "eap_server/eap.h"
+#include "ap_config.h"
+#include "hostapd.h"
+
+#ifdef CONFIG_SQLITE
+
+static void set_user_methods(struct hostapd_eap_user *user, const char *methods)
+{
+ char *buf, *start;
+ int num_methods;
+
+ buf = os_strdup(methods);
+ if (buf == NULL)
+ return;
+
+ os_memset(&user->methods, 0, sizeof(user->methods));
+ num_methods = 0;
+ start = buf;
+ while (*start) {
+ char *pos3 = os_strchr(start, ',');
+ if (pos3)
+ *pos3++ = '\0';
+ user->methods[num_methods].method =
+ eap_server_get_type(start,
+ &user->methods[num_methods].vendor);
+ if (user->methods[num_methods].vendor == EAP_VENDOR_IETF &&
+ user->methods[num_methods].method == EAP_TYPE_NONE) {
+ if (os_strcmp(start, "TTLS-PAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-CHAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+ goto skip_eap;
+ }
+ wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'",
+ start);
+ os_free(buf);
+ return;
+ }
+
+ num_methods++;
+ if (num_methods >= EAP_MAX_METHODS)
+ break;
+ skip_eap:
+ if (pos3 == NULL)
+ break;
+ start = pos3;
+ }
+
+ os_free(buf);
+}
+
+
+static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct hostapd_eap_user *user = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "password") == 0 && argv[i]) {
+ os_free(user->password);
+ user->password_len = os_strlen(argv[i]);
+ user->password = (u8 *) os_strdup(argv[i]);
+ user->next = (void *) 1;
+ } else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
+ set_user_methods(user, argv[i]);
+ }
+ }
+
+ return 0;
+}
+
+
+static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct hostapd_eap_user *user = ctx;
+ int i, id = -1, methods = -1;
+ size_t len;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "identity") == 0 && argv[i])
+ id = i;
+ else if (os_strcmp(col[i], "methods") == 0 && argv[i])
+ methods = i;
+ }
+
+ if (id < 0 || methods < 0)
+ return 0;
+
+ len = os_strlen(argv[id]);
+ if (len <= user->identity_len &&
+ os_memcmp(argv[id], user->identity, len) == 0 &&
+ (user->password == NULL || len > user->password_len)) {
+ os_free(user->password);
+ user->password_len = os_strlen(argv[id]);
+ user->password = (u8 *) os_strdup(argv[id]);
+ user->next = (void *) 1;
+ set_user_methods(user, argv[methods]);
+ }
+
+ return 0;
+}
+
+
+static const struct hostapd_eap_user *
+eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
+ size_t identity_len, int phase2)
+{
+ sqlite3 *db;
+ struct hostapd_eap_user *user = NULL;
+ char id_str[256], cmd[300];
+ size_t i;
+
+ if (identity_len >= sizeof(id_str))
+ return NULL;
+ os_memcpy(id_str, identity, identity_len);
+ id_str[identity_len] = '\0';
+ for (i = 0; i < identity_len; i++) {
+ if (id_str[i] >= 'a' && id_str[i] <= 'z')
+ continue;
+ if (id_str[i] >= 'A' && id_str[i] <= 'Z')
+ continue;
+ if (id_str[i] >= '0' && id_str[i] <= '9')
+ continue;
+ if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' ||
+ id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' ||
+ id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' ||
+ id_str[i] == '=' || id_str[i] == ' ')
+ continue;
+ wpa_printf(MSG_INFO, "DB: Unsupported character in identity");
+ return NULL;
+ }
+
+ os_free(hapd->tmp_eap_user.identity);
+ os_free(hapd->tmp_eap_user.password);
+ os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
+ hapd->tmp_eap_user.phase2 = phase2;
+ hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
+ if (hapd->tmp_eap_user.identity == NULL)
+ return NULL;
+ os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
+
+ if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
+ wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
+ hapd->conf->eap_user_sqlite, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT password,methods FROM users WHERE "
+ "identity='%s' AND phase2=%d;", id_str, phase2);
+ wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+ if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
+ SQLITE_OK) {
+ wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
+ } else if (hapd->tmp_eap_user.next)
+ user = &hapd->tmp_eap_user;
+
+ if (user == NULL && !phase2) {
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT identity,methods FROM wildcards;");
+ wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+ if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
+ NULL) != SQLITE_OK) {
+ wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
+ "operation");
+ } else if (hapd->tmp_eap_user.next) {
+ user = &hapd->tmp_eap_user;
+ os_free(user->identity);
+ user->identity = user->password;
+ user->identity_len = user->password_len;
+ user->password = NULL;
+ user->password_len = 0;
+ }
+ }
+
+ sqlite3_close(db);
+
+ return user;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+ size_t identity_len, int phase2)
+{
+ const struct hostapd_bss_config *conf = hapd->conf;
+ struct hostapd_eap_user *user = conf->eap_user;
+
+#ifdef CONFIG_WPS
+ if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
+ os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
+ static struct hostapd_eap_user wsc_enrollee;
+ os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
+ wsc_enrollee.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_enrollee.methods[0].vendor);
+ return &wsc_enrollee;
+ }
+
+ if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
+ os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
+ static struct hostapd_eap_user wsc_registrar;
+ os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
+ wsc_registrar.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_registrar.methods[0].vendor);
+ wsc_registrar.password = (u8 *) conf->ap_pin;
+ wsc_registrar.password_len = conf->ap_pin ?
+ os_strlen(conf->ap_pin) : 0;
+ return &wsc_registrar;
+ }
+#endif /* CONFIG_WPS */
+
+ while (user) {
+ if (!phase2 && user->identity == NULL) {
+ /* Wildcard match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 && user->wildcard_prefix &&
+ identity_len >= user->identity_len &&
+ os_memcmp(user->identity, identity, user->identity_len) ==
+ 0) {
+ /* Wildcard prefix match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 &&
+ user->identity_len == identity_len &&
+ os_memcmp(user->identity, identity, identity_len) == 0)
+ break;
+ user = user->next;
+ }
+
+#ifdef CONFIG_SQLITE
+ if (user == NULL && conf->eap_user_sqlite) {
+ return eap_user_sqlite_get(hapd, identity, identity_len,
+ phase2);
+ }
+#endif /* CONFIG_SQLITE */
+
+ return user;
+}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 34292587..cef9dafc 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -273,6 +273,11 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_INTERWORKING
gas_serv_deinit(hapd);
#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+ os_free(hapd->tmp_eap_user.identity);
+ os_free(hapd->tmp_eap_user.password);
+#endif /* CONFIG_SQLITE */
}
@@ -1113,12 +1118,13 @@ int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
{
size_t j;
- struct hostapd_bss_config *bss = hapd_iface->bss[0]->conf;
+ struct hostapd_bss_config *bss;
const struct wpa_driver_ops *driver;
void *drv_priv;
if (hapd_iface == NULL)
return -1;
+ bss = hapd_iface->bss[0]->conf;
driver = hapd_iface->bss[0]->driver;
drv_priv = hapd_iface->bss[0]->drv_priv;
@@ -1373,8 +1379,10 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
/* Start accounting here, if IEEE 802.1X and WPA are not used.
* IEEE 802.1X/WPA code will start accounting after the station has
* been authorized. */
- if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
+ os_get_time(&sta->connected_time);
accounting_sta_start(hapd, sta);
+ }
/* Start IEEE 802.1X authentication process for new stations */
ieee802_1x_new_station(hapd, sta);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 71f476c0..f1e7d9ff 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -10,6 +10,7 @@
#define HOSTAPD_H
#include "common/defs.h"
+#include "ap_config.h"
struct wpa_driver_ops;
struct wpa_ctrl_dst;
@@ -187,6 +188,10 @@ struct hostapd_data {
#ifdef CONFIG_INTERWORKING
size_t gas_frag_limit;
#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+ struct hostapd_eap_user tmp_eap_user;
+#endif /* CONFIG_SQLITE */
};
@@ -297,4 +302,8 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset);
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+ size_t identity_len, int phase2);
+
#endif /* HOSTAPD_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index ce20e5f8..a13a135e 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -49,6 +49,8 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
num = hapd->iface->num_rates;
if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
num++;
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+ num++;
if (num > 8) {
/* rest of the rates are encoded in Extended supported
* rates element */
@@ -66,9 +68,15 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
pos++;
}
- if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
- hapd->iface->num_rates < 8)
+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
+ count++;
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+ }
+
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
+ count++;
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+ }
return pos;
}
@@ -85,6 +93,8 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
num = hapd->iface->num_rates;
if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
num++;
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+ num++;
if (num <= 8)
return eid;
num -= 8;
@@ -103,9 +113,17 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
pos++;
}
- if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
- hapd->iface->num_rates >= 8)
- *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
+ count++;
+ if (count > 8)
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+ }
+
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
+ count++;
+ if (count > 8)
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+ }
return pos;
}
@@ -296,6 +314,142 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+
+static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(2);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
+ /* TODO: Anti-Clogging Token (if requested) */
+ /* TODO: Scalar */
+ /* TODO: Element */
+
+ return buf;
+}
+
+
+static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(2);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_le16(buf, sta->sae_send_confirm);
+ sta->sae_send_confirm++;
+ /* TODO: Confirm */
+
+ return buf;
+}
+
+
+static u16 handle_sae_commit(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *data, size_t len)
+{
+ wpa_hexdump(MSG_DEBUG, "SAE commit fields", data, len);
+
+ /* Check Finite Cyclic Group */
+ if (len < 2)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ if (WPA_GET_LE16(data) != 19) {
+ wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+ WPA_GET_LE16(data));
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 handle_sae_confirm(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *data, size_t len)
+{
+ u16 rc;
+
+ wpa_hexdump(MSG_DEBUG, "SAE confirm fields", data, len);
+
+ if (len < 2)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ rc = WPA_GET_LE16(data);
+ wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ u8 auth_transaction)
+{
+ u16 resp = WLAN_STATUS_SUCCESS;
+ struct wpabuf *data;
+
+ if (auth_transaction == 1) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "start SAE authentication (RX commit)");
+ resp = handle_sae_commit(hapd, sta, mgmt->u.auth.variable,
+ ((u8 *) mgmt) + len -
+ mgmt->u.auth.variable);
+ if (resp == WLAN_STATUS_SUCCESS)
+ sta->sae_state = SAE_COMMIT;
+ } else if (auth_transaction == 2) {
+ if (sta->sae_state != SAE_COMMIT) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "SAE confirm before commit");
+ resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+ }
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "SAE authentication (RX confirm)");
+ resp = handle_sae_confirm(hapd, sta, mgmt->u.auth.variable,
+ ((u8 *) mgmt) + len -
+ mgmt->u.auth.variable);
+ if (resp == WLAN_STATUS_SUCCESS) {
+ sta->flags |= WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->auth_alg = WLAN_AUTH_SAE;
+ mlme_authenticate_indication(hapd, sta);
+ }
+ } else {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "unexpected SAE authentication transaction %u",
+ auth_transaction);
+ resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+ }
+
+ sta->auth_alg = WLAN_AUTH_SAE;
+
+ if (resp == WLAN_STATUS_SUCCESS) {
+ if (auth_transaction == 1)
+ data = auth_build_sae_commit(hapd, sta);
+ else
+ data = auth_build_sae_confirm(hapd, sta);
+ if (data == NULL)
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ } else
+ data = NULL;
+
+ send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ auth_transaction, resp,
+ data ? wpabuf_head(data) : (u8 *) "",
+ data ? wpabuf_len(data) : 0);
+ wpabuf_free(data);
+}
+#endif /* CONFIG_SAE */
+
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -307,8 +461,7 @@ static void handle_auth(struct hostapd_data *hapd,
const u8 *challenge = NULL;
u32 session_timeout, acct_interim_interval;
int vlan_id = 0;
- u8 psk[PMK_LEN];
- int has_psk = 0;
+ struct hostapd_sta_wpa_psk_short *psk = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
char *identity = NULL;
@@ -348,6 +501,10 @@ static void handle_auth(struct hostapd_data *hapd,
(hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
auth_alg == WLAN_AUTH_FT) ||
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ auth_alg == WLAN_AUTH_SAE) ||
+#endif /* CONFIG_SAE */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
printf("Unsupported authentication algorithm (%d)\n",
@@ -356,7 +513,7 @@ static void handle_auth(struct hostapd_data *hapd,
goto fail;
}
- if (!(auth_transaction == 1 ||
+ if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
printf("Unknown authentication transaction number (%d)\n",
auth_transaction);
@@ -374,7 +531,7 @@ static void handle_auth(struct hostapd_data *hapd,
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
&session_timeout,
&acct_interim_interval, &vlan_id,
- psk, &has_psk, &identity, &radius_cui);
+ &psk, &identity, &radius_cui);
if (res == HOSTAPD_ACL_REJECT) {
printf("Station " MACSTR " not allowed to authenticate.\n",
@@ -413,13 +570,11 @@ static void handle_auth(struct hostapd_data *hapd,
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
}
- if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
- os_free(sta->psk);
- sta->psk = os_malloc(PMK_LEN);
- if (sta->psk)
- os_memcpy(sta->psk, psk, PMK_LEN);
+ hostapd_free_psk_list(sta->psk);
+ if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+ sta->psk = psk;
+ psk = NULL;
} else {
- os_free(sta->psk);
sta->psk = NULL;
}
@@ -486,11 +641,17 @@ static void handle_auth(struct hostapd_data *hapd,
/* handle_auth_ft_finish() callback will complete auth. */
return;
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ case WLAN_AUTH_SAE:
+ handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
+ return;
+#endif /* CONFIG_SAE */
}
fail:
os_free(identity);
os_free(radius_cui);
+ hostapd_free_psk_list(psk);
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
auth_transaction + 1, resp, resp_ies, resp_ies_len);
@@ -779,6 +940,16 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ if (wpa_auth_uses_sae(sta->wpa_sm) &&
+ sta->auth_alg != WLAN_AUTH_SAE) {
+ wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
+ "SAE AKM after non-SAE auth_alg %u",
+ MAC2STR(sta->addr), sta->auth_alg);
+ return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+ }
+#endif /* CONFIG_SAE */
+
#ifdef CONFIG_IEEE80211N
if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
@@ -807,6 +978,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_HS20
+ wpabuf_free(sta->hs20_ie);
+ if (elems.hs20 && elems.hs20_len > 4) {
+ sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+ elems.hs20_len - 4);
+ } else
+ sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
return WLAN_STATUS_SUCCESS;
}
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 63ae3452..c311e559 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -36,8 +36,7 @@ struct hostapd_cached_radius_acl {
u32 session_timeout;
u32 acct_interim_interval;
int vlan_id;
- int has_psk;
- u8 psk[PMK_LEN];
+ struct hostapd_sta_wpa_psk_short *psk;
char *identity;
char *radius_cui;
};
@@ -58,6 +57,7 @@ static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
{
os_free(e->identity);
os_free(e->radius_cui);
+ hostapd_free_psk_list(e->psk);
os_free(e);
}
@@ -74,11 +74,34 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
}
+static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src)
+{
+ struct hostapd_sta_wpa_psk_short **copy_to;
+ struct hostapd_sta_wpa_psk_short *copy_from;
+
+ /* Copy PSK linked list */
+ copy_to = psk;
+ copy_from = src;
+ while (copy_from && copy_to) {
+ *copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+ if (*copy_to == NULL)
+ break;
+ os_memcpy(*copy_to, copy_from,
+ sizeof(struct hostapd_sta_wpa_psk_short));
+ copy_from = copy_from->next;
+ copy_to = &((*copy_to)->next);
+ }
+ if (copy_to)
+ *copy_to = NULL;
+}
+
+
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk, char **identity,
- char **radius_cui)
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui)
{
struct hostapd_cached_radius_acl *entry;
struct os_time now;
@@ -99,10 +122,7 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
entry->acct_interim_interval;
if (vlan_id)
*vlan_id = entry->vlan_id;
- if (psk)
- os_memcpy(psk, entry->psk, PMK_LEN);
- if (has_psk)
- *has_psk = entry->has_psk;
+ copy_psk_list(psk, entry->psk);
if (identity) {
if (entry->identity)
*identity = os_strdup(entry->identity);
@@ -200,8 +220,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
* @session_timeout: Buffer for returning session timeout (from RADIUS)
* @acct_interim_interval: Buffer for returning account interval (from RADIUS)
* @vlan_id: Buffer for returning VLAN ID
- * @psk: Buffer for returning WPA PSK
- * @has_psk: Buffer for indicating whether psk was filled
+ * @psk: Linked list buffer for returning WPA PSK
* @identity: Buffer for returning identity (from RADIUS)
* @radius_cui: Buffer for returning CUI (from RADIUS)
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
@@ -212,8 +231,8 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk, char **identity,
- char **radius_cui)
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui)
{
if (session_timeout)
*session_timeout = 0;
@@ -221,10 +240,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
*acct_interim_interval = 0;
if (vlan_id)
*vlan_id = 0;
- if (has_psk)
- *has_psk = 0;
if (psk)
- os_memset(psk, 0, PMK_LEN);
+ *psk = NULL;
if (identity)
*identity = NULL;
if (radius_cui)
@@ -253,7 +270,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval,
- vlan_id, psk, has_psk,
+ vlan_id, psk,
identity, radius_cui);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
@@ -396,6 +413,54 @@ static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
}
+static void decode_tunnel_passwords(struct hostapd_data *hapd,
+ const u8 *shared_secret,
+ size_t shared_secret_len,
+ struct radius_msg *msg,
+ struct radius_msg *req,
+ struct hostapd_cached_radius_acl *cache)
+{
+ int passphraselen;
+ char *passphrase, *strpassphrase;
+ size_t i;
+ struct hostapd_sta_wpa_psk_short *psk;
+
+ /*
+ * Decode all tunnel passwords as PSK and save them into a linked list.
+ */
+ for (i = 0; ; i++) {
+ passphrase = radius_msg_get_tunnel_password(
+ msg, &passphraselen, shared_secret, shared_secret_len,
+ req, i);
+ /*
+ * Passphrase is NULL iff there is no i-th Tunnel-Password
+ * attribute in msg.
+ */
+ if (passphrase == NULL)
+ break;
+ /*
+ * passphrase does not contain the NULL termination.
+ * Add it here as pbkdf2_sha1() requires it.
+ */
+ strpassphrase = os_zalloc(passphraselen + 1);
+ psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+ if (strpassphrase && psk) {
+ os_memcpy(strpassphrase, passphrase, passphraselen);
+ pbkdf2_sha1(strpassphrase,
+ hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len, 4096,
+ psk->psk, PMK_LEN);
+ psk->next = cache->psk;
+ cache->psk = psk;
+ psk = NULL;
+ }
+ os_free(strpassphrase);
+ os_free(psk);
+ os_free(passphrase);
+ }
+}
+
+
/**
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
* @msg: RADIUS response message
@@ -454,8 +519,6 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
cache->timestamp = t.sec;
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
- int passphraselen;
- char *passphrase;
u8 *buf;
size_t len;
@@ -478,27 +541,9 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
cache->vlan_id = radius_msg_get_vlanid(msg);
- passphrase = radius_msg_get_tunnel_password(
- msg, &passphraselen,
- hapd->conf->radius->auth_server->shared_secret,
- hapd->conf->radius->auth_server->shared_secret_len,
- req);
- cache->has_psk = passphrase != NULL;
- if (passphrase != NULL) {
- /* passphrase does not contain the NULL termination.
- * Add it here as pbkdf2_sha1 requires it. */
- char *strpassphrase = os_zalloc(passphraselen + 1);
- if (strpassphrase) {
- os_memcpy(strpassphrase, passphrase,
- passphraselen);
- pbkdf2_sha1(strpassphrase,
- hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len, 4096,
- cache->psk, PMK_LEN);
- os_free(strpassphrase);
- }
- os_free(passphrase);
- }
+ decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
+ msg, req, cache);
+
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
&buf, &len, NULL) == 0) {
cache->identity = os_zalloc(len + 1);
@@ -514,7 +559,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
- !cache->has_psk)
+ !cache->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
@@ -586,3 +631,13 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
hostapd_acl_query_free(prev);
}
}
+
+
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
+{
+ while (psk) {
+ struct hostapd_sta_wpa_psk_short *prev = psk;
+ psk = psk->next;
+ os_free(prev);
+ }
+}
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 0e8d1cb1..2bc1065a 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -19,9 +19,10 @@ enum {
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk, char **identity,
- char **radius_cui);
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
#endif /* IEEE802_11_AUTH_H */
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 7599ef8d..b21c2b7f 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -68,6 +68,8 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
*/
oper->vht_op_info_chan_center_freq_seg0_idx =
hapd->iconf->vht_oper_centr_freq_seg0_idx;
+ oper->vht_op_info_chan_center_freq_seg1_idx =
+ hapd->iconf->vht_oper_centr_freq_seg1_idx;
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index c4d3da82..e1b11ba1 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -99,8 +99,10 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
"driver (errno=%d).\n", MAC2STR(sta->addr), errno);
}
- if (authorized)
+ if (authorized) {
+ os_get_time(&sta->connected_time);
accounting_sta_start(hapd, sta);
+ }
}
@@ -1684,8 +1686,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
const struct hostapd_eap_user *eap_user;
int i;
- eap_user = hostapd_get_eap_user(hapd->conf, identity,
- identity_len, phase2);
+ eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
if (eap_user == NULL)
return -1;
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index ba2c033a..3a9cc7b4 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -95,11 +95,9 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
os_get_time(&now);
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
- struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
- pmksa->pmksa = entry->next;
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
- MACSTR, MAC2STR(entry->spa));
- pmksa_cache_free_entry(pmksa, entry);
+ MACSTR, MAC2STR(pmksa->pmksa->spa));
+ pmksa_cache_free_entry(pmksa, pmksa->pmksa);
}
pmksa_cache_set_expiration(pmksa);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index d61177fd..6bc43d2d 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -20,6 +20,7 @@
#include "accounting.h"
#include "ieee802_1x.h"
#include "ieee802_11.h"
+#include "ieee802_11_auth.h"
#include "wpa_auth.h"
#include "preauth_auth.h"
#include "ap_config.h"
@@ -232,9 +233,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
+ wpabuf_free(sta->hs20_ie);
os_free(sta->ht_capabilities);
- os_free(sta->psk);
+ hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index b3c57b43..d5e92faa 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -95,7 +95,8 @@ struct sta_info {
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
int vlan_id;
- u8 *psk; /* PSK from RADIUS authentication server */
+ /* PSKs from RADIUS authentication server */
+ struct hostapd_sta_wpa_psk_short *psk;
char *identity; /* User-Name from RADIUS */
char *radius_cui; /* Chargeable-User-Identity from RADIUS */
@@ -121,6 +122,14 @@ struct sta_info {
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
+ struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+
+ struct os_time connected_time;
+
+#ifdef CONFIG_SAE
+ enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
+ u16 sae_send_confirm;
+#endif /* CONFIG_SAE */
};
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index dd5aa687..4a2ea066 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -66,9 +66,10 @@ void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
}
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
{
struct os_time now;
+ int ret = 0;
if (addr && local) {
struct sta_info *sta = ap_get_sta(hapd, addr);
@@ -84,7 +85,7 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
"MLME-MICHAELMICFAILURE.indication "
"for not associated STA (" MACSTR
") ignored", MAC2STR(addr));
- return;
+ return ret;
}
}
@@ -93,8 +94,12 @@ void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
hapd->michael_mic_failures = 1;
} else {
hapd->michael_mic_failures++;
- if (hapd->michael_mic_failures > 1)
+ if (hapd->michael_mic_failures > 1) {
ieee80211_tkip_countermeasures_start(hapd);
+ ret = 1;
+ }
}
hapd->michael_mic_failure = now.sec;
+
+ return ret;
}
diff --git a/src/ap/tkip_countermeasures.h b/src/ap/tkip_countermeasures.h
index f7a66246..d3eaed3c 100644
--- a/src/ap/tkip_countermeasures.h
+++ b/src/ap/tkip_countermeasures.h
@@ -1,6 +1,6 @@
/*
* hostapd / TKIP countermeasures
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,7 +9,7 @@
#ifndef TKIP_COUNTERMEASURES_H
#define TKIP_COUNTERMEASURES_H
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd);
#endif /* TKIP_COUNTERMEASURES_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 49d81757..0816b25b 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -54,11 +54,12 @@ static const int dot11RSNAConfigPMKReauthThreshold = 70;
static const int dot11RSNAConfigSATimeout = 60;
-static inline void wpa_auth_mic_failure_report(
+static inline int wpa_auth_mic_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
if (wpa_auth->cb.mic_failure_report)
- wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+ return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+ return 0;
}
@@ -700,8 +701,8 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_IEEE80211R */
-static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, int group)
+static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int group)
{
/* Supplicant reported a Michael MIC error */
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -718,7 +719,8 @@ static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
"ignore Michael MIC failure report since "
"pairwise cipher is not TKIP");
} else {
- wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+ if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
+ return 1; /* STA entry was removed */
sm->dot11RSNAStatsTKIPRemoteMICFailures++;
wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
}
@@ -728,6 +730,7 @@ static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
* Authenticator may do it, let's change the keys now anyway.
*/
wpa_request_new_ptk(sm);
+ return 0;
}
@@ -1081,9 +1084,10 @@ continue_processing:
#endif /* CONFIG_PEERKEY */
return;
} else if (key_info & WPA_KEY_INFO_ERROR) {
- wpa_receive_error_report(
- wpa_auth, sm,
- !(key_info & WPA_KEY_INFO_KEY_TYPE));
+ if (wpa_receive_error_report(
+ wpa_auth, sm,
+ !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
+ return; /* STA entry was removed */
} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key Request for new "
@@ -3056,3 +3060,11 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
wpa_send_eapol_timeout, wpa_auth, sm);
}
}
+
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return 0;
+ return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 91ba4991..6ab170d1 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -177,7 +177,7 @@ struct wpa_auth_callbacks {
void (*logger)(void *ctx, const u8 *addr, logger_level level,
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
- void (*mic_failure_report)(void *ctx, const u8 *addr);
+ int (*mic_failure_report)(void *ctx, const u8 *addr);
void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
@@ -291,4 +291,6 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_IEEE80211V */
+int wpa_auth_uses_sae(struct wpa_state_machine *sm);
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index bdc89e4f..76c61ea1 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -112,10 +112,10 @@ static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
}
-static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
+static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
{
struct hostapd_data *hapd = ctx;
- michael_mic_failure(hapd, addr, 0);
+ return michael_mic_failure(hapd, addr, 0);
}
@@ -188,10 +188,18 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
/*
* This is about to iterate over all psks, prev_psk gives the last
* returned psk which should not be returned again.
- * logic list (all hostapd_get_psk; sta->psk)
+ * logic list (all hostapd_get_psk; all sta->psk)
*/
- if (sta && sta->psk && !psk && sta->psk != prev_psk)
- psk = sta->psk;
+ if (sta && sta->psk && !psk) {
+ struct hostapd_sta_wpa_psk_short *pos;
+ psk = sta->psk->psk;
+ for (pos = sta->psk; pos; pos = pos->next) {
+ if (pos->psk == prev_psk) {
+ psk = pos->next ? pos->next->psk : NULL;
+ break;
+ }
+ }
+ }
return psk;
}
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 17862305..4fd0135f 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -188,6 +188,18 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
num_suites++;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_SAE */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -407,6 +419,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
+ selector = RSN_AUTH_KEY_MGMT_SAE;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
+ selector = RSN_AUTH_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
@@ -479,6 +497,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ else if (key_mgmt & WPA_KEY_MGMT_SAE)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+ else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
else
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 5e44c72c..85633ec5 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -11,8 +11,6 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
-#include "crypto/dh_groups.h"
-#include "crypto/dh_group5.h"
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -1036,8 +1034,6 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
wps_device_data_free(&hapd->wps->dev);
wpabuf_free(hapd->wps->dh_pubkey);
wpabuf_free(hapd->wps->dh_privkey);
- wpabuf_free(hapd->wps->oob_conf.pubkey_hash);
- wpabuf_free(hapd->wps->oob_conf.dev_password);
wps_free_pending_msgs(hapd->wps->upnp_msgs);
hostapd_wps_nfc_clear(hapd->wps);
os_free(hapd->wps);
@@ -1155,60 +1151,6 @@ int hostapd_wps_cancel(struct hostapd_data *hapd)
}
-#ifdef CONFIG_WPS_OOB
-int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
- char *path, char *method, char *name)
-{
- struct wps_context *wps = hapd->wps;
- struct oob_device_data *oob_dev;
-
- oob_dev = wps_get_oob_device(device_type);
- if (oob_dev == NULL)
- return -1;
- oob_dev->device_path = path;
- oob_dev->device_name = name;
- wps->oob_conf.oob_method = wps_get_oob_method(method);
-
- if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) {
- /*
- * Use pre-configured DH keys in order to be able to write the
- * key hash into the OOB file.
- */
- wpabuf_free(wps->dh_pubkey);
- wpabuf_free(wps->dh_privkey);
- wps->dh_privkey = NULL;
- wps->dh_pubkey = dh_init(dh_groups_get(WPS_DH_GROUP),
- &wps->dh_privkey);
- wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
- if (wps->dh_pubkey == NULL) {
- wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
- "Diffie-Hellman handshake");
- return -1;
- }
- }
-
- if (wps_process_oob(wps, oob_dev, 1) < 0)
- goto error;
-
- if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
- wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
- hostapd_wps_add_pin(hapd, NULL, "any",
- wpabuf_head(wps->oob_conf.dev_password), 0) <
- 0)
- goto error;
-
- return 0;
-
-error:
- wpabuf_free(wps->dh_pubkey);
- wps->dh_pubkey = NULL;
- wpabuf_free(wps->dh_privkey);
- wps->dh_privkey = NULL;
- return -1;
-}
-#endif /* CONFIG_WPS_OOB */
-
-
static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
const u8 *bssid,
const u8 *ie, size_t ie_len,
diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h
index f968e151..4e5026b4 100644
--- a/src/ap/wps_hostapd.h
+++ b/src/ap/wps_hostapd.h
@@ -21,8 +21,6 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr);
int hostapd_wps_cancel(struct hostapd_data *hapd);
-int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
- char *path, char *method, char *name);
int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
char *buf, size_t buflen);
void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);