aboutsummaryrefslogtreecommitdiffstats
path: root/src/ap
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2013-01-15 13:53:35 -0800
committerDmitry Shmidt <dimitrysh@google.com>2013-01-15 14:44:44 -0800
commita54fa5fb807eaeff45464139b5a7759f060cec68 (patch)
tree4075cdcbf5dfca04f2593a53a3b43bb65aaef62b /src/ap
parentd27fcf69aa1b0e5400526626b3ffdeacc21660b6 (diff)
downloadandroid_external_wpa_supplicant_8-a54fa5fb807eaeff45464139b5a7759f060cec68.tar.gz
android_external_wpa_supplicant_8-a54fa5fb807eaeff45464139b5a7759f060cec68.tar.bz2
android_external_wpa_supplicant_8-a54fa5fb807eaeff45464139b5a7759f060cec68.zip
Accumulative patch from commit dc013f1e37df3462085cf01a13f0c432f146ad7a
Author: Jouni Malinen <jouni@qca.qualcomm.com> Date: Tue Jan 15 12:03:29 2013 +0200 eapol_test: Remove unnecessary header file inclusion - P2P: Send P2P-FIND-STOPPED event in the new continue-search states - P2P: Add some more details on Service Query TLV format - P2P: Use the same Dialog Token value for every GO Negotiation retry - P2P: Publish more connected clients info in Probe Response frames - P2P: Fix some memory leaks in p2p_add_device() - P2P: Use the same Dialog Token value for every PD retry - P2P: Document operating channel selection functions - P2P: Always re-select operating channel if not hard coded - P2P: Do not allow re-selection of GO channel if forced_freq in use - P2P: Set FORCE_FREQ flag as part of p2p_prepare_channel() - P2P: Share a single function for GO channel selection - P2P: Prefer operating channels where HT40 is possible - P2P: Be more careful with wpa_config_update_psk() call - P2P: Allow PSK to be used instead of passphrase for persistent GO - P2P: Consider age for the P2P scan results - Move some P2P offchannel operations to offchannel.c - P2P: Add more complete description of p2p_cancel - P2P: Allow p2p_cancel to be used to stop p2p_connect-join operation - Interworking changes - WNM changes - WPS changes - SAE changes Change-Id: I38b847d3460066cc58aecbcf67266bfcff1d344e Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'src/ap')
-rw-r--r--src/ap/accounting.c5
-rw-r--r--src/ap/accounting.h6
-rw-r--r--src/ap/ap_config.c7
-rw-r--r--src/ap/ap_config.h8
-rw-r--r--src/ap/ap_drv_ops.c69
-rw-r--r--src/ap/ap_drv_ops.h6
-rw-r--r--src/ap/beacon.c61
-rw-r--r--src/ap/ctrl_iface_ap.c20
-rw-r--r--src/ap/drv_callbacks.c4
-rw-r--r--src/ap/hostapd.c6
-rw-r--r--src/ap/hostapd.h6
-rw-r--r--src/ap/hw_features.c4
-rw-r--r--src/ap/ieee802_11.c242
-rw-r--r--src/ap/ieee802_11.h3
-rw-r--r--src/ap/ieee802_11_shared.c33
-rw-r--r--src/ap/ieee802_11_vht.c11
-rw-r--r--src/ap/ieee802_1x.c17
-rw-r--r--src/ap/pmksa_cache_auth.c2
-rw-r--r--src/ap/sta_info.c7
-rw-r--r--src/ap/sta_info.h3
-rw-r--r--src/ap/wnm_ap.c85
-rw-r--r--src/ap/wnm_ap.h4
-rw-r--r--src/ap/wpa_auth.c128
-rw-r--r--src/ap/wpa_auth.h4
-rw-r--r--src/ap/wpa_auth_ft.c2
-rw-r--r--src/ap/wpa_auth_glue.c15
-rw-r--r--src/ap/wpa_auth_i.h2
-rw-r--r--src/ap/wpa_auth_ie.c9
-rw-r--r--src/ap/wps_hostapd.c3
29 files changed, 533 insertions, 239 deletions
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 7563b52e..95405313 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -26,8 +26,6 @@
* input/output octets and updates Acct-{Input,Output}-Gigawords. */
#define ACCT_DEFAULT_UPDATE_INTERVAL 300
-static void accounting_sta_get_id(struct hostapd_data *hapd,
- struct sta_info *sta);
static void accounting_sta_interim(struct hostapd_data *hapd,
struct sta_info *sta);
@@ -210,7 +208,6 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->acct_session_started)
return;
- accounting_sta_get_id(hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"starting accounting session %08X-%08X",
@@ -377,7 +374,7 @@ void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
}
-static void accounting_sta_get_id(struct hostapd_data *hapd,
+void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta)
{
sta->acct_session_id_lo = hapd->acct_session_id_lo++;
diff --git a/src/ap/accounting.h b/src/ap/accounting.h
index 9d13d011..dcc54ee9 100644
--- a/src/ap/accounting.h
+++ b/src/ap/accounting.h
@@ -10,6 +10,11 @@
#define ACCOUNTING_H
#ifdef CONFIG_NO_ACCOUNTING
+static inline void accounting_sta_get_id(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+}
+
static inline void accounting_sta_start(struct hostapd_data *hapd,
struct sta_info *sta)
{
@@ -29,6 +34,7 @@ static inline void accounting_deinit(struct hostapd_data *hapd)
{
}
#else /* CONFIG_NO_ACCOUNTING */
+void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
int accounting_init(struct hostapd_data *hapd);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 3c699f71..922f5646 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -89,6 +89,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
#endif /* CONFIG_IEEE80211R */
bss->radius_das_time_window = 300;
+
+ bss->sae_anti_clogging_threshold = 5;
}
@@ -158,6 +160,9 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
+ conf->ap_table_max_size = 255;
+ conf->ap_table_expiration_time = 60;
+
return conf;
}
@@ -516,6 +521,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
+
+ os_free(conf->sae_groups);
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 71313c02..4742107d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -51,7 +51,8 @@ typedef enum hostap_security_policy {
struct hostapd_ssid {
u8 ssid[HOSTAPD_MAX_SSID_LEN];
size_t ssid_len;
- int ssid_set;
+ unsigned int ssid_set:1;
+ unsigned int utf8_ssid:1;
char vlan[IFNAMSIZ + 1];
secpolicy security_policy;
@@ -390,6 +391,8 @@ struct hostapd_bss_config {
/* IEEE 802.11v */
int time_advertisement;
char *time_zone;
+ int wnm_sleep_mode;
+ int bss_transition;
/* IEEE 802.11u - Interworking */
int interworking;
@@ -452,6 +455,9 @@ struct hostapd_bss_config {
#endif /* CONFIG_RADIUS_TEST */
struct wpabuf *vendor_elements;
+
+ unsigned int sae_anti_clogging_threshold;
+ int *sae_groups;
};
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 02da25b7..b71d51d8 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -338,6 +338,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
u32 flags, u8 qosinfo)
{
struct hostapd_sta_add_params params;
@@ -355,6 +356,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.supp_rates_len = supp_rates_len;
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
+ params.vht_capabilities = vht_capab;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
return hapd->driver->sta_add(hapd->drv_priv, &params);
@@ -454,19 +456,76 @@ int hostapd_flush(struct hostapd_data *hapd)
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
- int channel, int ht_enabled, int sec_channel_offset)
+ int channel, int ht_enabled, int vht_enabled,
+ int sec_channel_offset, int vht_oper_chwidth,
+ int center_segment0, int center_segment1)
{
struct hostapd_freq_params data;
- if (hapd->driver == NULL)
- return 0;
- if (hapd->driver->set_freq == NULL)
- return 0;
+ int tmp;
+
os_memset(&data, 0, sizeof(data));
data.mode = mode;
data.freq = freq;
data.channel = channel;
data.ht_enabled = ht_enabled;
+ data.vht_enabled = vht_enabled;
data.sec_channel_offset = sec_channel_offset;
+ data.center_freq1 = freq + sec_channel_offset * 10;
+ data.center_freq2 = 0;
+ data.bandwidth = sec_channel_offset ? 40 : 20;
+
+ /*
+ * This validation code is probably misplaced, maybe it should be
+ * in src/ap/hw_features.c and check the hardware support as well.
+ */
+ if (data.vht_enabled) switch (vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ if (center_segment1)
+ return -1;
+ if (5000 + center_segment0 * 5 != data.center_freq1)
+ return -1;
+ break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ if (center_segment1 == center_segment0 + 4 ||
+ center_segment1 == center_segment0 - 4)
+ return -1;
+ data.center_freq2 = 5000 + center_segment1 * 5;
+ /* fall through */
+ case VHT_CHANWIDTH_80MHZ:
+ data.bandwidth = 80;
+ if (vht_oper_chwidth == 1 && center_segment1)
+ return -1;
+ if (vht_oper_chwidth == 3 && !center_segment1)
+ return -1;
+ if (!sec_channel_offset)
+ return -1;
+ /* primary 40 part must match the HT configuration */
+ tmp = (30 + freq - 5000 - center_segment0 * 5)/20;
+ tmp /= 2;
+ if (data.center_freq1 != 5000 +
+ center_segment0 * 5 - 20 + 40 * tmp)
+ return -1;
+ data.center_freq1 = 5000 + center_segment0 * 5;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ data.bandwidth = 160;
+ if (center_segment1)
+ return -1;
+ if (!sec_channel_offset)
+ return -1;
+ /* primary 40 part must match the HT configuration */
+ tmp = (70 + freq - 5000 - center_segment0 * 5)/20;
+ tmp /= 2;
+ if (data.center_freq1 != 5000 +
+ center_segment0 * 5 - 60 + 40 * tmp)
+ return -1;
+ data.center_freq1 = 5000 + center_segment0 * 5;
+ break;
+ }
+ if (hapd->driver == NULL)
+ return 0;
+ if (hapd->driver->set_freq == NULL)
+ return 0;
return hapd->driver->set_freq(hapd->drv_priv, &data);
}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 9c53b99d..ceb7e68e 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -13,6 +13,7 @@ enum wpa_driver_if_type;
struct wpa_bss_params;
struct wpa_driver_scan_params;
struct ieee80211_ht_capabilities;
+struct ieee80211_vht_capabilities;
u32 hostapd_sta_flags_to_drv(u32 flags);
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
@@ -37,6 +38,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
u32 flags, u8 qosinfo);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
@@ -55,7 +57,9 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
- int channel, int ht_enabled, int sec_channel_offset);
+ int channel, int ht_enabled, int vht_enabled,
+ int sec_channel_offset, int vht_oper_chwidth,
+ int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index f761bf55..4c47c758 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -2,7 +2,7 @@
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -310,6 +310,46 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
}
+enum ssid_match_result {
+ NO_SSID_MATCH,
+ EXACT_SSID_MATCH,
+ WILDCARD_SSID_MATCH
+};
+
+static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *ssid_list,
+ size_t ssid_list_len)
+{
+ const u8 *pos, *end;
+ int wildcard = 0;
+
+ if (ssid_len == 0)
+ wildcard = 1;
+ if (ssid_len == hapd->conf->ssid.ssid_len &&
+ os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
+ return EXACT_SSID_MATCH;
+
+ if (ssid_list == NULL)
+ return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+
+ pos = ssid_list;
+ end = ssid_list + ssid_list_len;
+ while (pos + 1 <= end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[1] == 0)
+ wildcard = 1;
+ if (pos[1] == hapd->conf->ssid.ssid_len &&
+ os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
+ return EXACT_SSID_MATCH;
+ pos += 2 + pos[1];
+ }
+
+ return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+}
+
+
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal)
@@ -321,6 +361,7 @@ void handle_probe_req(struct hostapd_data *hapd,
struct sta_info *sta = NULL;
size_t i, resp_len;
int noack;
+ enum ssid_match_result res;
ie = mgmt->u.probe_req.variable;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
@@ -376,7 +417,8 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P */
- if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
+ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
+ elems.ssid_list_len == 0) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
@@ -394,10 +436,9 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P */
- if (elems.ssid_len == 0 ||
- (elems.ssid_len == hapd->conf->ssid.ssid_len &&
- os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
- 0)) {
+ res = ssid_match(hapd, elems.ssid, elems.ssid_len,
+ elems.ssid_list, elems.ssid_list_len);
+ if (res != NO_SSID_MATCH) {
if (sta)
sta->ssid_probe = &hapd->conf->ssid;
} else {
@@ -406,9 +447,10 @@ void handle_probe_req(struct hostapd_data *hapd,
ieee802_11_print_ssid(ssid_txt, elems.ssid,
elems.ssid_len);
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
- " for foreign SSID '%s' (DA " MACSTR ")",
+ " for foreign SSID '%s' (DA " MACSTR ")%s",
MAC2STR(mgmt->sa), ssid_txt,
- MAC2STR(mgmt->da));
+ MAC2STR(mgmt->da),
+ elems.ssid_list ? " (SSID list)" : "");
}
return;
}
@@ -455,7 +497,8 @@ void handle_probe_req(struct hostapd_data *hapd,
* If this is a broadcast probe request, apply no ack policy to avoid
* excessive retries.
*/
- noack = !!(elems.ssid_len == 0 && is_broadcast_ether_addr(mgmt->da));
+ noack = !!(res == WILDCARD_SSID_MATCH &&
+ is_broadcast_ether_addr(mgmt->da));
if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
perror("handle_probe_req: send");
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index c55d3fe3..1cb7e73c 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -189,6 +189,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
+ u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
txtaddr);
@@ -228,11 +229,14 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = os_strstr(txtaddr, " reason=");
+ if (pos)
+ reason = atoi(pos + 8);
+
+ hostapd_drv_sta_deauth(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
- ap_sta_deauthenticate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ ap_sta_deauthenticate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
@@ -246,6 +250,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
+ u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
txtaddr);
@@ -285,11 +290,14 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = os_strstr(txtaddr, " reason=");
+ if (pos)
+ reason = atoi(pos + 8);
+
+ hostapd_drv_sta_disassoc(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
- ap_sta_disassociate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ ap_sta_disassociate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 86139752..8980bec0 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -512,13 +512,13 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
action->data + 2);
}
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211V
+#ifdef CONFIG_WNM
if (action->category == WLAN_ACTION_WNM) {
wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
__func__, (int) action->len);
ieee802_11_rx_wnm_action_ap(hapd, action);
}
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index cef9dafc..92fda569 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -894,7 +894,11 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
hapd->iconf->ieee80211n,
- hapd->iconf->secondary_channel)) {
+ hapd->iconf->ieee80211ac,
+ hapd->iconf->secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ hapd->iconf->vht_oper_centr_freq_seg0_idx,
+ hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
wpa_printf(MSG_ERROR, "Could not set channel for "
"kernel driver");
return -1;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index f1e7d9ff..c9087b31 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -192,6 +192,12 @@ struct hostapd_data {
#ifdef CONFIG_SQLITE
struct hostapd_eap_user tmp_eap_user;
#endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_SAE
+ /** Key used for generating SAE anti-clogging tokens */
+ u8 sae_token_key[8];
+ os_time_t last_sae_token_key_update;
+#endif /* CONFIG_SAE */
};
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 97e1238e..923b6982 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -122,6 +122,8 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
case HOSTAPD_MODE_IEEE80211G:
basic_rates = basic_rates_g;
break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ return 0; /* No basic rates for 11ad */
default:
return -1;
}
@@ -756,6 +758,8 @@ const char * hostapd_hw_mode_txt(int mode)
return "IEEE 802.11b";
case HOSTAPD_MODE_IEEE80211G:
return "IEEE 802.11g";
+ case HOSTAPD_MODE_IEEE80211AD:
+ return "IEEE 802.11ad";
default:
return "UNKNOWN";
}
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index a13a135e..79235dfd 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -13,10 +13,13 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "crypto/crypto.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/sae.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -34,6 +37,7 @@
#include "ap_mlme.h"
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
+#include "wnm_ap.h"
#include "ieee802_11.h"
@@ -316,19 +320,33 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
#ifdef CONFIG_SAE
-static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta)
+static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta)
{
struct wpabuf *buf;
- buf = wpabuf_alloc(2);
- if (buf == NULL)
+ if (hapd->conf->ssid.wpa_passphrase == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: No password available");
+ return NULL;
+ }
+
+ if (sae_prepare_commit(hapd->own_addr, sta->addr,
+ (u8 *) hapd->conf->ssid.wpa_passphrase,
+ os_strlen(hapd->conf->ssid.wpa_passphrase),
+ sta->sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
+ return NULL;
+ }
+
+ if (sae_process_commit(sta->sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
return NULL;
+ }
- wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
- /* TODO: Anti-Clogging Token (if requested) */
- /* TODO: Scalar */
- /* TODO: Element */
+ buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
+ if (buf == NULL)
+ return NULL;
+ sae_write_commit(sta->sae, buf, NULL);
return buf;
}
@@ -339,49 +357,82 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
{
struct wpabuf *buf;
- buf = wpabuf_alloc(2);
+ buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
if (buf == NULL)
return NULL;
- wpabuf_put_le16(buf, sta->sae_send_confirm);
- sta->sae_send_confirm++;
- /* TODO: Confirm */
+ sae_write_confirm(sta->sae, buf);
return buf;
}
-static u16 handle_sae_commit(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *data, size_t len)
+static int use_sae_anti_clogging(struct hostapd_data *hapd)
{
- wpa_hexdump(MSG_DEBUG, "SAE commit fields", data, len);
+ struct sta_info *sta;
+ unsigned int open = 0;
- /* 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;
+ if (hapd->conf->sae_anti_clogging_threshold == 0)
+ return 1;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->sae)
+ continue;
+ if (sta->sae->state != SAE_COMMITTED &&
+ sta->sae->state != SAE_CONFIRMED)
+ continue;
+ open++;
+ if (open >= hapd->conf->sae_anti_clogging_threshold)
+ return 1;
}
- return WLAN_STATUS_SUCCESS;
+ return 0;
}
-static u16 handle_sae_confirm(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *data, size_t len)
+static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *token, size_t token_len)
{
- u16 rc;
+ u8 mac[SHA256_MAC_LEN];
- wpa_hexdump(MSG_DEBUG, "SAE confirm fields", data, len);
+ if (token_len != SHA256_MAC_LEN)
+ return -1;
+ if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, mac) < 0 ||
+ os_memcmp(token, mac, SHA256_MAC_LEN) != 0)
+ return -1;
- if (len < 2)
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- rc = WPA_GET_LE16(data);
- wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+ return 0;
+}
- return WLAN_STATUS_SUCCESS;
+
+static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
+ const u8 *addr)
+{
+ struct wpabuf *buf;
+ u8 *token;
+ struct os_time t;
+
+ os_get_time(&t);
+ if (hapd->last_sae_token_key_update == 0 ||
+ t.sec > hapd->last_sae_token_key_update + 60) {
+ if (random_get_bytes(hapd->sae_token_key,
+ sizeof(hapd->sae_token_key)) < 0)
+ return NULL;
+ wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
+ hapd->sae_token_key, sizeof(hapd->sae_token_key));
+ hapd->last_sae_token_key_update = t.sec;
+ }
+
+ buf = wpabuf_alloc(SHA256_MAC_LEN);
+ if (buf == NULL)
+ return NULL;
+
+ token = wpabuf_put(buf, SHA256_MAC_LEN);
+ hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, token);
+
+ return buf;
}
@@ -390,19 +441,52 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
u8 auth_transaction)
{
u16 resp = WLAN_STATUS_SUCCESS;
- struct wpabuf *data;
+ struct wpabuf *data = NULL;
+
+ if (!sta->sae) {
+ if (auth_transaction != 1)
+ return;
+ sta->sae = os_zalloc(sizeof(*sta->sae));
+ if (sta->sae == NULL)
+ return;
+ sta->sae->state = SAE_NOTHING;
+ }
if (auth_transaction == 1) {
+ const u8 *token = NULL;
+ size_t token_len = 0;
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;
+ resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
+ ((const u8 *) mgmt) + len -
+ mgmt->u.auth.variable, &token,
+ &token_len, hapd->conf->sae_groups);
+ if (token && check_sae_token(hapd, sta->addr, token, token_len)
+ < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
+ "incorrect token from " MACSTR,
+ MAC2STR(sta->addr));
+ return;
+ }
+
+ if (resp == WLAN_STATUS_SUCCESS) {
+ if (!token && use_sae_anti_clogging(hapd)) {
+ wpa_printf(MSG_DEBUG, "SAE: Request anti-"
+ "clogging token from " MACSTR,
+ MAC2STR(sta->addr));
+ data = auth_build_token_req(hapd, sta->addr);
+ resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
+ } else {
+ data = auth_process_sae_commit(hapd, sta);
+ if (data == NULL)
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ else
+ sta->sae->state = SAE_COMMITTED;
+ }
+ }
} else if (auth_transaction == 2) {
- if (sta->sae_state != SAE_COMMIT) {
+ if (sta->sae->state != SAE_COMMITTED) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -412,14 +496,24 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
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) {
+ if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
+ ((u8 *) mgmt) + len -
+ mgmt->u.auth.variable) < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ } else {
+ 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);
+
+ data = auth_build_sae_confirm(hapd, sta);
+ if (data == NULL)
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ else {
+ sta->sae->state = SAE_ACCEPTED;
+ sae_clear_temp_data(sta->sae);
+ }
}
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -431,16 +525,6 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
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 *) "",
@@ -1434,13 +1518,32 @@ static int robust_action_frame(u8 category)
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct rx_action action;
+ if (len < IEEE80211_HDRLEN + 2)
+ return;
+ os_memset(&action, 0, sizeof(action));
+ action.da = mgmt->da;
+ action.sa = mgmt->sa;
+ action.bssid = mgmt->bssid;
+ action.category = mgmt->u.action.category;
+ action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action;
+ action.len = len - IEEE80211_HDRLEN - 1;
+ action.freq = hapd->iface->freq;
+ ieee802_11_rx_wnm_action_ap(hapd, &action);
+}
+#endif /* CONFIG_WNM */
+
+
static void handle_action(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
struct sta_info *sta;
sta = ap_get_sta(hapd, mgmt->sa);
-#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
if (len < IEEE80211_HDRLEN + 1) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1450,6 +1553,14 @@ static void handle_action(struct hostapd_data *hapd,
return;
}
+ if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
+ (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
+ "frame (category=%u) from unassociated STA " MACSTR,
+ MAC2STR(mgmt->sa), mgmt->u.action.category);
+ return;
+ }
+
#ifdef CONFIG_IEEE80211W
if (sta && (sta->flags & WLAN_STA_MFP) &&
!(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
@@ -1465,20 +1576,10 @@ static void handle_action(struct hostapd_data *hapd,
switch (mgmt->u.action.category) {
#ifdef CONFIG_IEEE80211R
case WLAN_ACTION_FT:
- {
- if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action "
- "frame from unassociated STA " MACSTR,
- MAC2STR(mgmt->sa));
- return;
- }
-
if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
len - IEEE80211_HDRLEN))
break;
-
return;
- }
#endif /* CONFIG_IEEE80211R */
case WLAN_ACTION_WMM:
hostapd_wmm_action(hapd, mgmt, len);
@@ -1488,6 +1589,11 @@ static void handle_action(struct hostapd_data *hapd,
hostapd_sa_query_action(hapd, mgmt, len);
return;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+ case WLAN_ACTION_WNM:
+ hostapd_wnm_action(hapd, sta, mgmt, len);
+ return;
+#endif /* CONFIG_WNM */
case WLAN_ACTION_PUBLIC:
if (hapd->public_action_cb) {
hapd->public_action_cb(hapd->public_action_cb_ctx,
@@ -1685,6 +1791,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
struct sta_info *sta;
int new_assoc = 1;
struct ieee80211_ht_capabilities ht_cap;
+ struct ieee80211_vht_capabilities vht_cap;
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
sizeof(mgmt->u.assoc_resp))) {
@@ -1757,11 +1864,16 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
if (sta->flags & WLAN_STA_HT)
hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (sta->flags & WLAN_STA_VHT)
+ hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
+#endif /* CONFIG_IEEE80211AC */
if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
sta->supported_rates, sta->supported_rates_len,
sta->listen_interval,
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+ sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
sta->flags, sta->qosinfo)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 1e5800d0..2aab56de 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -53,6 +53,9 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
void hostapd_get_ht_capab(struct hostapd_data *hapd,
struct ieee80211_ht_capabilities *ht_cap,
struct ieee80211_ht_capabilities *neg_ht_cap);
+void hostapd_get_vht_capab(struct hostapd_data *hapd,
+ struct ieee80211_vht_capabilities *vht_cap,
+ struct ieee80211_vht_capabilities *neg_vht_cap);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index b3fdf3d6..76f78a7d 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -173,6 +173,14 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
len = 5;
if (len < 4 && hapd->conf->interworking)
len = 4;
+ if (len < 3 && hapd->conf->wnm_sleep_mode)
+ len = 3;
+ if (len < 7 && hapd->conf->ssid.utf8_ssid)
+ len = 7;
+#ifdef CONFIG_WNM
+ if (len < 4)
+ len = 4;
+#endif /* CONFIG_WNM */
if (len == 0)
return eid;
@@ -180,9 +188,20 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
*pos++ = len;
*pos++ = 0x00;
*pos++ = 0x00;
- *pos++ = 0x00;
*pos = 0x00;
+ if (hapd->conf->wnm_sleep_mode)
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ if (hapd->conf->bss_transition)
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+ pos++;
+
+ if (len < 4)
+ return pos;
+ *pos = 0x00;
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
if (hapd->conf->time_advertisement == 2)
*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
if (hapd->conf->interworking)
@@ -198,6 +217,18 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
pos++;
+ if (len < 6)
+ return pos;
+ *pos = 0x00;
+ pos++;
+
+ if (len < 7)
+ return pos;
+ *pos = 0x00;
+ if (hapd->conf->ssid.utf8_ssid)
+ *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+ pos++;
+
return pos;
}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index b21c2b7f..f6cc5d6c 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -108,3 +108,14 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
}
+
+void hostapd_get_vht_capab(struct hostapd_data *hapd,
+ struct ieee80211_vht_capabilities *vht_cap,
+ struct ieee80211_vht_capabilities *neg_vht_cap)
+{
+ if (vht_cap == NULL)
+ return;
+ os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
+
+ /* TODO: mask own capabilities, like get_ht_capab() */
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index e1b11ba1..a832a732 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -66,8 +66,9 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->flags & WLAN_STA_PREAUTH) {
rsn_preauth_send(hapd, sta, buf, len);
} else {
- hostapd_drv_hapd_send_eapol(hapd, sta->addr, buf, len,
- encrypt, sta->flags);
+ hostapd_drv_hapd_send_eapol(
+ hapd, sta->addr, buf, len,
+ encrypt, hostapd_sta_flags_to_drv(sta->flags));
}
os_free(buf);
@@ -354,6 +355,8 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
const char *radius_mode_txt(struct hostapd_data *hapd)
{
switch (hapd->iface->conf->hw_mode) {
+ case HOSTAPD_MODE_IEEE80211AD:
+ return "802.11ad";
case HOSTAPD_MODE_IEEE80211A:
return "802.11a";
case HOSTAPD_MODE_IEEE80211G:
@@ -452,6 +455,16 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
return -1;
}
+ if (sta->acct_session_id_hi || sta->acct_session_id_lo) {
+ os_snprintf(buf, sizeof(buf), "%08X-%08X",
+ sta->acct_session_id_hi, sta->acct_session_id_lo);
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
+ return -1;
+ }
+ }
+
return 0;
}
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 3a9cc7b4..d27fd302 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -209,6 +209,8 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
pmksa->pmksa_count++;
+ if (prev == NULL)
+ pmksa_cache_set_expiration(pmksa);
wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
MAC2STR(entry->spa));
wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 6bc43d2d..8ada1218 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/sae.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "drivers/driver.h"
@@ -240,6 +241,11 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->identity);
os_free(sta->radius_cui);
+#ifdef CONFIG_SAE
+ sae_clear_data(sta->sae);
+ os_free(sta->sae);
+#endif /* CONFIG_SAE */
+
os_free(sta);
}
@@ -493,6 +499,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
return NULL;
}
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
+ accounting_sta_get_id(hapd, sta);
/* initialize STA info data */
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index d5e92faa..32ea46e0 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -127,8 +127,7 @@ struct sta_info {
struct os_time connected_time;
#ifdef CONFIG_SAE
- enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
- u16 sae_send_confirm;
+ struct sae_data *sae;
#endif /* CONFIG_SAE */
};
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 25944045..54a6b857 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -19,7 +19,6 @@
#define MAX_TFS_IE_LEN 1024
-#ifdef CONFIG_IEEE80211V
/* get the TFS IE from driver */
static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
@@ -57,8 +56,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
u16 wnmtfs_ie_len;
u8 *pos;
struct sta_info *sta;
- enum wnm_oper tfs_oper = action_type == 0 ? WNM_SLEEP_TFS_RESP_IE_ADD :
- WNM_SLEEP_TFS_RESP_IE_NONE;
+ enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ?
+ WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE;
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
@@ -105,7 +104,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token;
pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
/* add key data if MFP is enabled */
- if (wpa_auth_uses_mfp(sta->wpa_sm) || action_type != 1){
+ if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+ action_type != WNM_SLEEP_MODE_EXIT) {
mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
} else {
gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos);
@@ -132,7 +132,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
pos += wnmsleep_ie_len;
- os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+ if (wnmtfs_ie)
+ os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
@@ -152,7 +153,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
* WNM Sleep
*/
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
- wnmsleep_ie.action_type == 0) {
+ wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
addr, NULL, NULL);
wpa_set_wnmsleep(sta->wpa_sm, 1);
@@ -162,12 +163,14 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
* 2. start GTK/IGTK update if MFP is not used
* 3. unpause the node in driver
*/
- if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
- wnmsleep_ie.action_type == 1) {
+ if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
+ wnmsleep_ie.status ==
+ WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) &&
+ wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) {
wpa_set_wnmsleep(sta->wpa_sm, 0);
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
addr, NULL, NULL);
- if (wpa_auth_uses_mfp(sta->wpa_sm) && action_type == 1)
+ if (!wpa_auth_uses_mfp(sta->wpa_sm))
wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
}
} else
@@ -184,29 +187,29 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *frm, int len)
{
- /*
- * Action [1] | Dialog Token [1] | WNM-Sleep Mode IE |
- * TFS Response IE
- */
- u8 *pos = (u8 *) frm; /* point to action field */
- u8 dialog_token = pos[1];
+ /* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
+ const u8 *pos = frm;
+ u8 dialog_token;
struct wnm_sleep_element *wnmsleep_ie = NULL;
/* multiple TFS Req IE (assuming consecutive) */
u8 *tfsreq_ie_start = NULL;
u8 *tfsreq_ie_end = NULL;
u16 tfsreq_ie_len = 0;
- pos += 1 + 1;
- while (pos - frm < len - 1) {
- u8 ie_len = *(pos+1);
+ dialog_token = *pos++;
+ while (pos + 1 < frm + len) {
+ u8 ie_len = pos[1];
+ if (pos + 2 + ie_len > frm + len)
+ break;
if (*pos == WLAN_EID_WNMSLEEP)
- wnmsleep_ie = (struct wnm_sleep_element *)pos;
+ wnmsleep_ie = (struct wnm_sleep_element *) pos;
else if (*pos == WLAN_EID_TFS_REQ) {
if (!tfsreq_ie_start)
- tfsreq_ie_start = pos;
- tfsreq_ie_end = pos;
+ tfsreq_ie_start = (u8 *) pos;
+ tfsreq_ie_end = (u8 *) pos;
} else
- wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
+ wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
+ *pos);
pos += ie_len + 2;
}
@@ -215,8 +218,9 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
return;
}
- if (wnmsleep_ie->action_type == 0 && tfsreq_ie_start &&
- tfsreq_ie_end && tfsreq_ie_end - tfsreq_ie_start >= 0) {
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
+ tfsreq_ie_start && tfsreq_ie_end &&
+ tfsreq_ie_end - tfsreq_ie_start >= 0) {
tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) -
tfsreq_ie_start;
wpa_printf(MSG_DEBUG, "TFS Req IE(s) found");
@@ -231,7 +235,7 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
wnmsleep_ie->action_type,
wnmsleep_ie->intval);
- if (wnmsleep_ie->action_type == 1) {
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
/* clear the tfs after sending the resp frame */
ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
&tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL);
@@ -239,20 +243,29 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
}
-void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
- struct rx_action *action)
+int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+ struct rx_action *action)
{
- u8 *pos = (u8 *) action->data + 1; /* point to the action field */
- u8 act = *pos;
+ if (action->len < 1 || action->data == NULL)
+ return -1;
- switch (act) {
+ switch (action->data[0]) {
+ case WNM_BSS_TRANS_MGMT_QUERY:
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
+ /* TODO */
+ return -1;
+ case WNM_BSS_TRANS_MGMT_RESP:
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
+ "Response");
+ /* TODO */
+ return -1;
case WNM_SLEEP_MODE_REQ:
ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
- action->len);
- break;
- default:
- break;
+ action->len - 1);
+ return 0;
}
-}
-#endif /* CONFIG_IEEE80211V */
+ wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
+ action->data[0], MAC2STR(action->sa));
+ return -1;
+}
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
index ab7c4f1c..f05726ee 100644
--- a/src/ap/wnm_ap.h
+++ b/src/ap/wnm_ap.h
@@ -11,7 +11,7 @@
struct rx_action;
-void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
- struct rx_action *action);
+int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+ struct rx_action *action);
#endif /* WNM_AP_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0816b25b..fa4b1cb3 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -282,8 +282,9 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- u8 buf[ETH_ALEN + 8 + sizeof(group)];
+ u8 buf[ETH_ALEN + 8 + sizeof(unsigned long)];
u8 rkey[32];
+ unsigned long ptr;
if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
return -1;
@@ -295,7 +296,8 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
*/
os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
wpa_get_ntp_timestamp(buf + ETH_ALEN);
- os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+ ptr = (unsigned long) group;
+ os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
if (random_get_bytes(rkey, sizeof(rkey)) < 0)
return -1;
@@ -2413,11 +2415,9 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
"marking station for GTK rekeying");
}
-#ifdef CONFIG_IEEE80211V
- /* Do not rekey GTK/IGTK when STA is in wnmsleep */
+ /* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
if (sm->is_wnmsleep)
return 0;
-#endif /* CONFIG_IEEE80211V */
sm->group->GKeyDoneStations++;
sm->GUpdateStationKeys = TRUE;
@@ -2427,8 +2427,8 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
}
-#ifdef CONFIG_IEEE80211V
-/* update GTK when exiting wnmsleep mode */
+#ifdef CONFIG_WNM
+/* update GTK when exiting WNM-Sleep Mode */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
{
if (sm->is_wnmsleep)
@@ -2446,111 +2446,65 @@ void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
- u8 *subelem;
struct wpa_group *gsm = sm->group;
- size_t subelem_len, pad_len;
- const u8 *key;
- size_t key_len;
- u8 keybuf[32];
-
- /* GTK subslement */
- key_len = gsm->GTK_len;
- if (key_len > sizeof(keybuf))
- return 0;
-
- /*
- * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
- * than 16 bytes.
- */
- pad_len = key_len % 8;
- if (pad_len)
- pad_len = 8 - pad_len;
- if (key_len + pad_len < 16)
- pad_len += 8;
- if (pad_len) {
- os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
- os_memset(keybuf + key_len, 0, pad_len);
- keybuf[key_len] = 0xdd;
- key_len += pad_len;
- key = keybuf;
- } else
- key = gsm->GTK[gsm->GN - 1];
+ u8 *start = pos;
/*
+ * GTK subelement:
* Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
- * Key[5..32] | 8 padding.
+ * Key[5..32]
*/
- subelem_len = 13 + key_len + 8;
- subelem = os_zalloc(subelem_len);
- if (subelem == NULL)
- return 0;
-
- subelem[0] = WNM_SLEEP_SUBELEM_GTK;
- subelem[1] = 11 + key_len + 8;
+ *pos++ = WNM_SLEEP_SUBELEM_GTK;
+ *pos++ = 11 + gsm->GTK_len;
/* Key ID in B0-B1 of Key Info */
- WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
- subelem[4] = gsm->GTK_len;
- if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5) != 0)
- {
- os_free(subelem);
- return 0;
- }
- if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
- os_free(subelem);
+ WPA_PUT_LE16(pos, gsm->GN & 0x03);
+ pos += 2;
+ *pos++ = gsm->GTK_len;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0)
return 0;
- }
-
- os_memcpy(pos, subelem, subelem_len);
+ pos += 8;
+ os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ pos += gsm->GTK_len;
- wpa_hexdump_key(MSG_DEBUG, "Plaintext GTK",
+ wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit",
gsm->GTK[gsm->GN - 1], gsm->GTK_len);
- os_free(subelem);
- return subelem_len;
+ return pos - start;
}
#ifdef CONFIG_IEEE80211W
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
- u8 *subelem, *ptr;
struct wpa_group *gsm = sm->group;
- size_t subelem_len;
-
- /* IGTK subelement
- * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] |
- * Key[16] | 8 padding */
- subelem_len = 1 + 1 + 2 + 6 + WPA_IGTK_LEN + 8;
- subelem = os_zalloc(subelem_len);
- if (subelem == NULL)
- return 0;
+ u8 *start = pos;
- ptr = subelem;
- *ptr++ = WNM_SLEEP_SUBELEM_IGTK;
- *ptr++ = subelem_len - 2;
- WPA_PUT_LE16(ptr, gsm->GN_igtk);
- ptr += 2;
- if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, ptr) != 0) {
- os_free(subelem);
+ /*
+ * IGTK subelement:
+ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+ */
+ *pos++ = WNM_SLEEP_SUBELEM_IGTK;
+ *pos++ = 2 + 6 + WPA_IGTK_LEN;
+ WPA_PUT_LE16(pos, gsm->GN_igtk);
+ pos += 2;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
return 0;
- }
- ptr += 6;
- if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
- gsm->IGTK[gsm->GN_igtk - 4], ptr)) {
- os_free(subelem);
- return -1;
- }
+ pos += 6;
- os_memcpy(pos, subelem, subelem_len);
+ os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+ pos += WPA_IGTK_LEN;
- wpa_hexdump_key(MSG_DEBUG, "Plaintext IGTK",
+ wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN_igtk);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
- os_free(subelem);
- return subelem_len;
+ return pos - start;
}
#endif /* CONFIG_IEEE80211W */
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 6ab170d1..465eec6a 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -282,14 +282,10 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211V
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
-#ifdef CONFIG_IEEE80211W
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);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 48bf79b9..ccb3f823 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -416,7 +416,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
pad_len = 8 - pad_len;
if (key_len + pad_len < 16)
pad_len += 8;
- if (pad_len) {
+ if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 76c61ea1..fdaaaff5 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1,6 +1,6 @@
/*
* hostapd / WPA authenticator glue code
- * 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.
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
@@ -184,7 +185,17 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
- const u8 *psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
+ const u8 *psk;
+
+#ifdef CONFIG_SAE
+ if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
+ if (!sta->sae || prev_psk)
+ return NULL;
+ return sta->sae->pmk;
+ }
+#endif /* CONFIG_SAE */
+
+ psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
/*
* This is about to iterate over all psks, prev_psk gives the last
* returned psk which should not be returned again.
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index d5cf2c50..97489d34 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -87,9 +87,7 @@ struct wpa_state_machine {
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211V
unsigned int is_wnmsleep:1;
-#endif /* CONFIG_IEEE80211V */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 4fd0135f..cdfcca19 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -564,12 +564,9 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#endif /* CONFIG_IEEE80211R */
- if (ciphers & WPA_CIPHER_CCMP)
- sm->pairwise = WPA_CIPHER_CCMP;
- else if (ciphers & WPA_CIPHER_GCMP)
- sm->pairwise = WPA_CIPHER_GCMP;
- else
- sm->pairwise = WPA_CIPHER_TKIP;
+ sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
+ if (sm->pairwise < 0)
+ return WPA_INVALID_PAIRWISE;
/* TODO: clear WPA/WPA2 state if STA changes from one to another */
if (wpa_ie[0] == WLAN_EID_RSN)
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 85633ec5..5ce4f1be 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -957,6 +957,9 @@ int hostapd_init_wps(struct hostapd_data *hapd,
if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
cfg.static_wep_only = 1;
cfg.dualband = interface_count(hapd->iface) > 1;
+ if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
+ (WPS_RF_50GHZ | WPS_RF_24GHZ))
+ cfg.dualband = 1;
if (cfg.dualband)
wpa_printf(MSG_DEBUG, "WPS: Dualband AP");