[wpa_supplicant] Cumulative patch from b8491ae5a
Also revert local solution for encrypted IMSI and use the upstream version.
Bug: 134177972
Test: Device boots up and connects to WPA3/OWE wifi networks, run traffic.
Test: Able to turn on/off softap, associate wifi STA, run traffic.
Test: Regression test passed (Bug: 137653009)
Change-Id: Ibf6b6ef3495287156c397daa89d02923f981889b
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 9b07ee1..48f8f23 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -20,6 +20,7 @@
CFLAGS += -DCONFIG_PROXYARP
CFLAGS += -DCONFIG_IPV6
CFLAGS += -DCONFIG_IAPP
+CFLAGS += -DCONFIG_AIRTIME_POLICY
LIB_OBJS= \
accounting.o \
@@ -27,6 +28,7 @@
ap_drv_ops.o \
ap_list.o \
ap_mlme.o \
+ airtime_policy.o \
authsrv.o \
beacon.o \
bss_load.o \
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 3b45075..11178a1 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -594,12 +594,12 @@
iface->conf->secondary_channel)
n_chans = 2;
- if (iface->conf->ieee80211ac) {
- switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_80MHZ:
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_80MHZ:
n_chans = 4;
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
n_chans = 8;
break;
}
@@ -607,7 +607,7 @@
bw = num_chan_to_bw(n_chans);
- /* TODO: VHT80+80. Update acs_adjust_vht_center_freq() too. */
+ /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
wpa_printf(MSG_DEBUG,
"ACS: Survey analysis for selected bandwidth %d MHz", bw);
@@ -647,9 +647,9 @@
}
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
- iface->conf->ieee80211ac) {
- if (iface->conf->vht_oper_chwidth ==
- VHT_CHANWIDTH_80MHZ &&
+ (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
+ if (hostapd_get_oper_chwidth(iface->conf) ==
+ CHANWIDTH_80MHZ &&
!acs_usable_vht80_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for VHT80",
@@ -657,8 +657,8 @@
continue;
}
- if (iface->conf->vht_oper_chwidth ==
- VHT_CHANWIDTH_160MHZ &&
+ if (hostapd_get_oper_chwidth(iface->conf) ==
+ CHANWIDTH_160MHZ &&
!acs_usable_vht160_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for VHT160",
@@ -783,20 +783,20 @@
}
-static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
+static void acs_adjust_center_freq(struct hostapd_iface *iface)
{
int offset;
wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
- switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_USE_HT:
offset = 2 * iface->conf->secondary_channel;
break;
- case VHT_CHANWIDTH_80MHZ:
+ case CHANWIDTH_80MHZ:
offset = 6;
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
offset = 14;
break;
default:
@@ -807,8 +807,8 @@
return;
}
- iface->conf->vht_oper_centr_freq_seg0_idx =
- iface->conf->channel + offset;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ iface->conf->channel + offset);
}
@@ -863,8 +863,8 @@
iface->conf->channel = ideal_chan->chan;
- if (iface->conf->ieee80211ac)
- acs_adjust_vht_center_freq(iface);
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
+ acs_adjust_center_freq(iface);
err = 0;
fail:
diff --git a/src/ap/airtime_policy.c b/src/ap/airtime_policy.c
new file mode 100644
index 0000000..f56ca5b
--- /dev/null
+++ b/src/ap/airtime_policy.c
@@ -0,0 +1,269 @@
+/*
+ * Airtime policy configuration
+ * Copyright (c) 2018-2019, Toke Høiland-Jørgensen <toke@toke.dk>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "airtime_policy.h"
+
+/* Idea:
+ * Two modes of airtime enforcement:
+ * 1. Static weights: specify weights per MAC address with a per-BSS default
+ * 2. Per-BSS limits: Dynamically calculate weights of backlogged stations to
+ * enforce relative total shares between BSSes.
+ *
+ * - Periodic per-station callback to update queue status.
+ *
+ * Copy accounting_sta_update_stats() to get TXQ info and airtime weights and
+ * keep them updated in sta_info.
+ *
+ * - Separate periodic per-bss (or per-iface?) callback to update weights.
+ *
+ * Just need to loop through all interfaces, count sum the active stations (or
+ * should the per-STA callback just adjust that for the BSS?) and calculate new
+ * weights.
+ */
+
+static int get_airtime_policy_update_timeout(struct hostapd_iface *iface,
+ unsigned int *sec,
+ unsigned int *usec)
+{
+ unsigned int update_int = iface->conf->airtime_update_interval;
+
+ if (!update_int) {
+ wpa_printf(MSG_ERROR,
+ "Airtime policy: Invalid airtime policy update interval %u",
+ update_int);
+ return -1;
+ }
+
+ *sec = update_int / 1000;
+ *usec = (update_int % 1000) * 1000;
+
+ return 0;
+}
+
+
+static void set_new_backlog_time(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct os_reltime *now)
+{
+ sta->backlogged_until = *now;
+ sta->backlogged_until.usec += hapd->iconf->airtime_update_interval *
+ AIRTIME_BACKLOG_EXPIRY_FACTOR;
+ while (sta->backlogged_until.usec >= 1000000) {
+ sta->backlogged_until.sec++;
+ sta->backlogged_until.usec -= 1000000;
+ }
+}
+
+
+static void count_backlogged_sta(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data = {};
+ unsigned int num_backlogged = 0;
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr))
+ continue;
+
+ if (data.backlog_bytes > 0)
+ set_new_backlog_time(hapd, sta, &now);
+ if (os_reltime_before(&now, &sta->backlogged_until))
+ num_backlogged++;
+ }
+ hapd->num_backlogged_sta = num_backlogged;
+}
+
+
+static int sta_set_airtime_weight(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ unsigned int weight)
+{
+ int ret = 0;
+
+ if (weight != sta->airtime_weight &&
+ (ret = hostapd_sta_set_airtime_weight(hapd, sta->addr, weight)))
+ return ret;
+
+ sta->airtime_weight = weight;
+ return ret;
+}
+
+
+static void set_sta_weights(struct hostapd_data *hapd, unsigned int weight)
+{
+ struct sta_info *sta;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next)
+ sta_set_airtime_weight(hapd, sta, weight);
+}
+
+
+static unsigned int get_airtime_quantum(unsigned int max_wt)
+{
+ unsigned int quantum = AIRTIME_QUANTUM_TARGET / max_wt;
+
+ if (quantum < AIRTIME_QUANTUM_MIN)
+ quantum = AIRTIME_QUANTUM_MIN;
+ else if (quantum > AIRTIME_QUANTUM_MAX)
+ quantum = AIRTIME_QUANTUM_MAX;
+
+ return quantum;
+}
+
+
+static void update_airtime_weights(void *eloop_data, void *user_data)
+{
+ struct hostapd_iface *iface = eloop_data;
+ struct hostapd_data *bss;
+ unsigned int sec, usec;
+ unsigned int num_sta_min = 0, num_sta_prod = 1, num_sta_sum = 0,
+ wt_sum = 0;
+ unsigned int quantum;
+ Boolean all_div_min = TRUE;
+ Boolean apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC;
+ int wt, num_bss = 0, max_wt = 0;
+ size_t i;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ bss = iface->bss[i];
+ if (!bss->started || !bss->conf->airtime_weight)
+ continue;
+
+ count_backlogged_sta(bss);
+ if (!bss->num_backlogged_sta)
+ continue;
+
+ if (!num_sta_min || bss->num_backlogged_sta < num_sta_min)
+ num_sta_min = bss->num_backlogged_sta;
+
+ num_sta_prod *= bss->num_backlogged_sta;
+ num_sta_sum += bss->num_backlogged_sta;
+ wt_sum += bss->conf->airtime_weight;
+ num_bss++;
+ }
+
+ if (num_sta_min) {
+ for (i = 0; i < iface->num_bss; i++) {
+ bss = iface->bss[i];
+ if (!bss->started || !bss->conf->airtime_weight)
+ continue;
+
+ /* Check if we can divide all sta numbers by the
+ * smallest number to keep weights as small as possible.
+ * This is a lazy way to avoid having to factor
+ * integers. */
+ if (bss->num_backlogged_sta &&
+ bss->num_backlogged_sta % num_sta_min > 0)
+ all_div_min = FALSE;
+
+ /* If we're in LIMIT mode, we only apply the weight
+ * scaling when the BSS(es) marked as limited would a
+ * larger share than the relative BSS weights indicates
+ * it should. */
+ if (!apply_limit && bss->conf->airtime_limit) {
+ if (bss->num_backlogged_sta * wt_sum >
+ bss->conf->airtime_weight * num_sta_sum)
+ apply_limit = TRUE;
+ }
+ }
+ if (all_div_min)
+ num_sta_prod /= num_sta_min;
+ }
+
+ for (i = 0; i < iface->num_bss; i++) {
+ bss = iface->bss[i];
+ if (!bss->started || !bss->conf->airtime_weight)
+ continue;
+
+ /* We only set the calculated weight if the BSS has active
+ * stations and there are other active interfaces as well -
+ * otherwise we just set a unit weight. This ensures that
+ * the weights are set reasonably when stations transition from
+ * inactive to active. */
+ if (apply_limit && bss->num_backlogged_sta && num_bss > 1)
+ wt = bss->conf->airtime_weight * num_sta_prod /
+ bss->num_backlogged_sta;
+ else
+ wt = 1;
+
+ bss->airtime_weight = wt;
+ if (wt > max_wt)
+ max_wt = wt;
+ }
+
+ quantum = get_airtime_quantum(max_wt);
+
+ for (i = 0; i < iface->num_bss; i++) {
+ bss = iface->bss[i];
+ if (!bss->started || !bss->conf->airtime_weight)
+ continue;
+ set_sta_weights(bss, bss->airtime_weight * quantum);
+ }
+
+ if (get_airtime_policy_update_timeout(iface, &sec, &usec) < 0)
+ return;
+
+ eloop_register_timeout(sec, usec, update_airtime_weights, iface,
+ NULL);
+}
+
+
+static int get_weight_for_sta(struct hostapd_data *hapd, const u8 *sta)
+{
+ struct airtime_sta_weight *wt;
+
+ wt = hapd->conf->airtime_weight_list;
+ while (wt && os_memcmp(wt->addr, sta, ETH_ALEN) != 0)
+ wt = wt->next;
+
+ return wt ? wt->weight : hapd->conf->airtime_weight;
+}
+
+
+int airtime_policy_new_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ unsigned int weight;
+
+ if (hapd->iconf->airtime_mode == AIRTIME_MODE_STATIC) {
+ weight = get_weight_for_sta(hapd, sta->addr);
+ if (weight)
+ return sta_set_airtime_weight(hapd, sta, weight);
+ }
+ return 0;
+}
+
+
+int airtime_policy_update_init(struct hostapd_iface *iface)
+{
+ unsigned int sec, usec;
+
+ if (iface->conf->airtime_mode < AIRTIME_MODE_DYNAMIC)
+ return 0;
+
+ if (get_airtime_policy_update_timeout(iface, &sec, &usec) < 0)
+ return -1;
+
+ eloop_register_timeout(sec, usec, update_airtime_weights, iface, NULL);
+ return 0;
+}
+
+
+void airtime_policy_update_deinit(struct hostapd_iface *iface)
+{
+ eloop_cancel_timeout(update_airtime_weights, iface, NULL);
+}
diff --git a/src/ap/airtime_policy.h b/src/ap/airtime_policy.h
new file mode 100644
index 0000000..c2a9b00
--- /dev/null
+++ b/src/ap/airtime_policy.h
@@ -0,0 +1,48 @@
+/*
+ * Airtime policy configuration
+ * Copyright (c) 2018-2019, Toke Høiland-Jørgensen <toke@toke.dk>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AIRTIME_POLICY_H
+#define AIRTIME_POLICY_H
+
+struct hostapd_iface;
+
+#ifdef CONFIG_AIRTIME_POLICY
+
+#define AIRTIME_DEFAULT_UPDATE_INTERVAL 200 /* ms */
+#define AIRTIME_BACKLOG_EXPIRY_FACTOR 2500 /* 2.5 intervals + convert to usec */
+
+/* scale quantum so this becomes the effective quantum after applying the max
+ * weight, but never go below min or above max */
+#define AIRTIME_QUANTUM_MIN 8 /* usec */
+#define AIRTIME_QUANTUM_MAX 256 /* usec */
+#define AIRTIME_QUANTUM_TARGET 1024 /* usec */
+
+int airtime_policy_new_sta(struct hostapd_data *hapd, struct sta_info *sta);
+int airtime_policy_update_init(struct hostapd_iface *iface);
+void airtime_policy_update_deinit(struct hostapd_iface *iface);
+
+#else /* CONFIG_AIRTIME_POLICY */
+
+static inline int airtime_policy_new_sta(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return -1;
+}
+
+static inline int airtime_policy_update_init(struct hostapd_iface *iface)
+{
+ return -1;
+}
+
+static inline void airtime_policy_update_deinit(struct hostapd_iface *iface)
+{
+}
+
+#endif /* CONFIG_AIRTIME_POLICY */
+
+#endif /* AIRTIME_POLICY_H */
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index e640e99..a061bd8 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -13,12 +13,14 @@
#include "crypto/tls.h"
#include "radius/radius_client.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_1x_defs.h"
#include "common/eapol_common.h"
#include "common/dhcp.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
#include "sta_info.h"
+#include "airtime_policy.h"
#include "ap_config.h"
@@ -138,6 +140,11 @@
bss->hs20_release = (HS20_VERSION >> 4) + 1;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MACSEC
+ bss->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
+ bss->macsec_port = 1;
+#endif /* CONFIG_MACSEC */
+
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
}
@@ -236,6 +243,13 @@
conf->acs_num_scans = 5;
#endif /* CONFIG_ACS */
+#ifdef CONFIG_IEEE80211AX
+ conf->he_op.he_rts_threshold = HE_OPERATION_RTS_THRESHOLD_MASK >>
+ HE_OPERATION_RTS_THRESHOLD_OFFSET;
+ /* Set default basic MCS/NSS set to single stream MCS 0-7 */
+ conf->he_op.he_basic_mcs_nss_set = 0xfffc;
+#endif /* CONFIG_IEEE80211AX */
+
/* The third octet of the country string uses an ASCII space character
* by default to indicate that the regulations encompass all
* environments for the current frequency band in the country. */
@@ -244,6 +258,10 @@
conf->rssi_reject_assoc_rssi = 0;
conf->rssi_reject_assoc_timeout = 30;
+#ifdef CONFIG_AIRTIME_POLICY
+ conf->airtime_update_interval = AIRTIME_DEFAULT_UPDATE_INTERVAL;
+#endif /* CONFIG_AIRTIME_POLICY */
+
return conf;
}
@@ -559,8 +577,26 @@
}
+#ifdef CONFIG_DPP2
+static void hostapd_dpp_controller_conf_free(struct dpp_controller_conf *conf)
+{
+ struct dpp_controller_conf *prev;
+
+ while (conf) {
+ prev = conf;
+ conf = conf->next;
+ os_free(prev);
+ }
+}
+#endif /* CONFIG_DPP2 */
+
+
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
+#if defined(CONFIG_WPS) || defined(CONFIG_HS20)
+ size_t i;
+#endif
+
if (conf == NULL)
return;
@@ -593,8 +629,11 @@
os_free(conf->ctrl_interface);
os_free(conf->ca_cert);
os_free(conf->server_cert);
+ os_free(conf->server_cert2);
os_free(conf->private_key);
+ os_free(conf->private_key2);
os_free(conf->private_key_passwd);
+ os_free(conf->private_key_passwd2);
os_free(conf->check_cert_subject);
os_free(conf->ocsp_stapling_response);
os_free(conf->ocsp_stapling_response_multi);
@@ -653,12 +692,8 @@
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
- {
- unsigned int i;
-
- for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
- wpabuf_free(conf->wps_vendor_ext[i]);
- }
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+ wpabuf_free(conf->wps_vendor_ext[i]);
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@@ -684,7 +719,6 @@
os_free(conf->hs20_operating_class);
os_free(conf->hs20_icons);
if (conf->hs20_osu_providers) {
- size_t i;
for (i = 0; i < conf->hs20_osu_providers_count; i++) {
struct hs20_osu_provider *p;
size_t j;
@@ -702,8 +736,6 @@
os_free(conf->hs20_osu_providers);
}
if (conf->hs20_operator_icon) {
- size_t i;
-
for (i = 0; i < conf->hs20_operator_icon_count; i++)
os_free(conf->hs20_operator_icon[i]);
os_free(conf->hs20_operator_icon);
@@ -740,10 +772,27 @@
os_free(conf->dpp_connector);
wpabuf_free(conf->dpp_netaccesskey);
wpabuf_free(conf->dpp_csign);
+#ifdef CONFIG_DPP2
+ hostapd_dpp_controller_conf_free(conf->dpp_controller);
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
hostapd_config_free_sae_passwords(conf);
+#ifdef CONFIG_AIRTIME_POLICY
+ {
+ struct airtime_sta_weight *wt, *wt_prev;
+
+ wt = conf->airtime_weight_list;
+ conf->airtime_weight_list = NULL;
+ while (wt) {
+ wt_prev = wt;
+ wt = wt->next;
+ os_free(wt_prev);
+ }
+ }
+#endif /* CONFIG_AIRTIME_POLICY */
+
os_free(conf);
}
@@ -1140,6 +1189,13 @@
return -1;
}
+#ifdef CONFIG_AIRTIME_POLICY
+ if (full_config && conf->airtime_mode > AIRTIME_MODE_STATIC &&
+ !conf->airtime_update_interval) {
+ wpa_printf(MSG_ERROR, "Airtime update interval cannot be zero");
+ return -1;
+ }
+#endif /* CONFIG_AIRTIME_POLICY */
for (i = 0; i < NUM_TX_QUEUES; i++) {
if (hostapd_config_check_cw(conf, i))
return -1;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 509677a..eebf898 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -15,6 +15,7 @@
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "crypto/sha256.h"
#include "wps/wps.h"
#include "fst/fst.h"
#include "vlan.h"
@@ -252,6 +253,18 @@
int vlan_id;
};
+struct dpp_controller_conf {
+ struct dpp_controller_conf *next;
+ u8 pkhash[SHA256_MAC_LEN];
+ struct hostapd_ip_addr ipaddr;
+};
+
+struct airtime_sta_weight {
+ struct airtime_sta_weight *next;
+ unsigned int weight;
+ u8 addr[ETH_ALEN];
+};
+
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@@ -390,8 +403,11 @@
char *ca_cert;
char *server_cert;
+ char *server_cert2;
char *private_key;
+ char *private_key2;
char *private_key_passwd;
+ char *private_key_passwd2;
char *check_cert_subject;
int check_crl;
int check_crl_strict;
@@ -410,6 +426,8 @@
int eap_fast_prov;
int pac_key_lifetime;
int pac_key_refresh_time;
+ int eap_teap_auth;
+ int eap_teap_pac_no_inner;
int eap_sim_aka_result_ind;
int tnc;
int fragment_size;
@@ -570,6 +588,7 @@
int osen;
int proxy_arp;
int na_mcast_to_ucast;
+
#ifdef CONFIG_HS20
int hs20;
int hs20_release;
@@ -692,6 +711,9 @@
struct wpabuf *dpp_netaccesskey;
unsigned int dpp_netaccesskey_expiry;
struct wpabuf *dpp_csign;
+#ifdef CONFIG_DPP2
+ struct dpp_controller_conf *dpp_controller;
+#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_OWE
@@ -709,6 +731,100 @@
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
+
+#ifdef CONFIG_AIRTIME_POLICY
+ unsigned int airtime_weight;
+ int airtime_limit;
+ struct airtime_sta_weight *airtime_weight_list;
+#endif /* CONFIG_AIRTIME_POLICY */
+
+#ifdef CONFIG_MACSEC
+ /**
+ * macsec_policy - Determines the policy for MACsec secure session
+ *
+ * 0: MACsec not in use (default)
+ * 1: MACsec enabled - Should secure, accept key server's advice to
+ * determine whether to use a secure session or not.
+ */
+ int macsec_policy;
+
+ /**
+ * macsec_integ_only - Determines how MACsec are transmitted
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: Encrypt traffic (default)
+ * 1: Integrity only
+ */
+ int macsec_integ_only;
+
+ /**
+ * macsec_replay_protect - Enable MACsec replay protection
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: Replay protection disabled (default)
+ * 1: Replay protection enabled
+ */
+ int macsec_replay_protect;
+
+ /**
+ * macsec_replay_window - MACsec replay protection window
+ *
+ * A window in which replay is tolerated, to allow receipt of frames
+ * that have been misordered by the network.
+ *
+ * This setting applies only when MACsec replay protection active, i.e.,
+ * - macsec_replay_protect is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: No replay window, strict check (default)
+ * 1..2^32-1: number of packets that could be misordered
+ */
+ u32 macsec_replay_window;
+
+ /**
+ * macsec_port - MACsec port (in SCI)
+ *
+ * Port component of the SCI.
+ *
+ * Range: 1-65534 (default: 1)
+ */
+ int macsec_port;
+
+ /**
+ * mka_priority - Priority of MKA Actor
+ *
+ * Range: 0-255 (default: 255)
+ */
+ int mka_priority;
+
+ /**
+ * mka_ckn - MKA pre-shared CKN
+ */
+#define MACSEC_CKN_MAX_LEN 32
+ size_t mka_ckn_len;
+ u8 mka_ckn[MACSEC_CKN_MAX_LEN];
+
+ /**
+ * mka_cak - MKA pre-shared CAK
+ */
+#define MACSEC_CAK_MAX_LEN 32
+ size_t mka_cak_len;
+ u8 mka_cak[MACSEC_CAK_MAX_LEN];
+
+#define MKA_PSK_SET_CKN BIT(0)
+#define MKA_PSK_SET_CAK BIT(1)
+#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK)
+ /**
+ * mka_psk_set - Whether mka_ckn and mka_cak are set
+ */
+ u8 mka_psk_set;
+#endif /* CONFIG_MACSEC */
};
/**
@@ -727,7 +843,20 @@
u8 he_bss_color;
u8 he_default_pe_duration;
u8 he_twt_required;
- u8 he_rts_threshold;
+ u16 he_rts_threshold;
+ u16 he_basic_mcs_nss_set;
+};
+
+/**
+ * struct spatial_reuse - Spatial reuse
+ */
+struct spatial_reuse {
+ u8 sr_control;
+ u8 non_srg_obss_pd_max_offset;
+ u8 srg_obss_pd_min_offset;
+ u8 srg_obss_pd_max_offset;
+ u8 srg_obss_color_bitmap;
+ u8 srg_obss_color_partial_bitmap;
};
/**
@@ -852,6 +981,10 @@
struct he_phy_capabilities_info he_phy_capab;
struct he_operation he_op;
struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
+ struct spatial_reuse spr;
+ u8 he_oper_chwidth;
+ u8 he_oper_centr_freq_seg0_idx;
+ u8 he_oper_centr_freq_seg1_idx;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@@ -861,9 +994,83 @@
int rssi_reject_assoc_rssi;
int rssi_reject_assoc_timeout;
+
+#ifdef CONFIG_AIRTIME_POLICY
+ enum {
+ AIRTIME_MODE_OFF = 0,
+ AIRTIME_MODE_STATIC = 1,
+ AIRTIME_MODE_DYNAMIC = 2,
+ AIRTIME_MODE_LIMIT = 3,
+ __AIRTIME_MODE_MAX,
+ } airtime_mode;
+ unsigned int airtime_update_interval;
+#define AIRTIME_MODE_MAX (__AIRTIME_MODE_MAX - 1)
+#endif /* CONFIG_AIRTIME_POLICY */
};
+static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ return conf->he_oper_chwidth;
+#endif /* CONFIG_IEEE80211AX */
+ return conf->vht_oper_chwidth;
+}
+
+static inline void
+hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ conf->he_oper_chwidth = oper_chwidth;
+#endif /* CONFIG_IEEE80211AX */
+ conf->vht_oper_chwidth = oper_chwidth;
+}
+
+static inline u8
+hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ return conf->he_oper_centr_freq_seg0_idx;
+#endif /* CONFIG_IEEE80211AX */
+ return conf->vht_oper_centr_freq_seg0_idx;
+}
+
+static inline void
+hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
+ u8 oper_centr_freq_seg0_idx)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+#endif /* CONFIG_IEEE80211AX */
+ conf->vht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+}
+
+static inline u8
+hostapd_get_oper_centr_freq_seg1_idx(struct hostapd_config *conf)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ return conf->he_oper_centr_freq_seg1_idx;
+#endif /* CONFIG_IEEE80211AX */
+ return conf->vht_oper_centr_freq_seg1_idx;
+}
+
+static inline void
+hostapd_set_oper_centr_freq_seg1_idx(struct hostapd_config *conf,
+ u8 oper_centr_freq_seg1_idx)
+{
+#ifdef CONFIG_IEEE80211AX
+ if (conf->ieee80211ax)
+ conf->he_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
+#endif /* CONFIG_IEEE80211AX */
+ conf->vht_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
+}
+
+
int hostapd_mac_comp(const void *a, const void *b);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 067cf86..c0ededa 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -413,6 +413,8 @@
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
+ const struct ieee80211_he_capabilities *he_capab,
+ size_t he_capab_len,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set)
{
@@ -432,6 +434,8 @@
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
params.vht_capabilities = vht_capab;
+ params.he_capab = he_capab;
+ params.he_capab_len = he_capab_len;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
@@ -537,17 +541,20 @@
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int ht_enabled, int vht_enabled,
- int sec_channel_offset, int vht_oper_chwidth,
+ int he_enabled,
+ int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
{
struct hostapd_freq_params data;
+ struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
- vht_enabled, sec_channel_offset,
- vht_oper_chwidth,
+ vht_enabled, he_enabled, sec_channel_offset,
+ oper_chwidth,
center_segment0, center_segment1,
- hapd->iface->current_mode ?
- hapd->iface->current_mode->vht_capab : 0))
+ cmode ? cmode->vht_capab : 0,
+ cmode ?
+ &cmode->he_capab[IEEE80211_MODE_AP] : NULL))
return -1;
if (hapd->driver == NULL)
@@ -583,6 +590,16 @@
}
+int hostapd_sta_set_airtime_weight(struct hostapd_data *hapd, const u8 *addr,
+ unsigned int weight)
+{
+ if (!hapd->driver || !hapd->driver->sta_set_airtime_weight)
+ return 0;
+ return hapd->driver->sta_set_airtime_weight(hapd->drv_priv, addr,
+ weight);
+}
+
+
int hostapd_set_country(struct hostapd_data *hapd, const char *country)
{
if (hapd->driver == NULL ||
@@ -775,14 +792,16 @@
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
- int sec_channel_offset, int vht_oper_chwidth,
+ int he_enabled,
+ int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_freq_params data;
int res;
+ struct hostapd_hw_modes *cmode = iface->current_mode;
- if (!hapd->driver || !hapd->driver->start_dfs_cac)
+ if (!hapd->driver || !hapd->driver->start_dfs_cac || !cmode)
return 0;
if (!iface->conf->ieee80211h) {
@@ -792,10 +811,11 @@
}
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
- vht_enabled, sec_channel_offset,
- vht_oper_chwidth, center_segment0,
+ vht_enabled, he_enabled, sec_channel_offset,
+ oper_chwidth, center_segment0,
center_segment1,
- iface->current_mode->vht_capab)) {
+ cmode->vht_capab,
+ &cmode->he_capab[IEEE80211_MODE_AP])) {
wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
}
@@ -919,15 +939,17 @@
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
params.ch_width = 40;
- /* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
+ /* Note: VHT20 is defined by combination of ht_capab & oper_chwidth
*/
- if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
- if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ if ((hapd->iface->conf->ieee80211ax ||
+ hapd->iface->conf->ieee80211ac) &&
+ params.ht40_enabled) {
+ u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
+
+ if (oper_chwidth == CHANWIDTH_80MHZ)
params.ch_width = 80;
- else if (hapd->iface->conf->vht_oper_chwidth ==
- VHT_CHANWIDTH_160MHZ ||
- hapd->iface->conf->vht_oper_chwidth ==
- VHT_CHANWIDTH_80P80MHZ)
+ else if (oper_chwidth == CHANWIDTH_160MHZ ||
+ oper_chwidth == CHANWIDTH_80P80MHZ)
params.ch_width = 160;
}
@@ -936,3 +958,13 @@
return ret;
}
+
+
+int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
+ u16 reason_code, const u8 *ie, size_t ielen)
+{
+ if (!hapd->driver || !hapd->driver->update_dh_ie || !hapd->drv_priv)
+ return 0;
+ return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
+ ie, ielen);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index de40171..ca7f7ab 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -41,6 +41,8 @@
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
+ const struct ieee80211_he_capabilities *he_capab,
+ size_t he_capab_len,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
@@ -61,12 +63,14 @@
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int ht_enabled, int vht_enabled,
- int sec_channel_offset, int vht_oper_chwidth,
+ int he_enabled, int sec_channel_offset, int 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,
int total_flags, int flags_or, int flags_and);
+int hostapd_sta_set_airtime_weight(struct hostapd_data *hapd, const u8 *addr,
+ unsigned int weight);
int hostapd_set_country(struct hostapd_data *hapd, const char *country);
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time);
@@ -122,9 +126,12 @@
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
- int sec_channel_offset, int vht_oper_chwidth,
+ int he_enabled,
+ int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_drv_do_acs(struct hostapd_data *hapd);
+int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
+ u16 reason_code, const u8 *ie, size_t ielen);
#include "drivers/driver.h"
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index eced6c7..b3d9107 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -120,6 +120,8 @@
srv.eap_fast_prov = conf->eap_fast_prov;
srv.pac_key_lifetime = conf->pac_key_lifetime;
srv.pac_key_refresh_time = conf->pac_key_refresh_time;
+ srv.eap_teap_auth = conf->eap_teap_auth;
+ srv.eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
srv.tnc = conf->tnc;
srv.wps = hapd->wps;
@@ -195,7 +197,8 @@
#ifdef EAP_TLS_FUNCS
if (hapd->conf->eap_server &&
(hapd->conf->ca_cert || hapd->conf->server_cert ||
- hapd->conf->private_key || hapd->conf->dh_file)) {
+ hapd->conf->private_key || hapd->conf->dh_file ||
+ hapd->conf->server_cert2 || hapd->conf->private_key2)) {
struct tls_config conf;
struct tls_connection_params params;
@@ -224,8 +227,11 @@
os_memset(¶ms, 0, sizeof(params));
params.ca_cert = hapd->conf->ca_cert;
params.client_cert = hapd->conf->server_cert;
+ params.client_cert2 = hapd->conf->server_cert2;
params.private_key = hapd->conf->private_key;
+ params.private_key2 = hapd->conf->private_key2;
params.private_key_passwd = hapd->conf->private_key_passwd;
+ params.private_key_passwd2 = hapd->conf->private_key_passwd2;
params.dh_file = hapd->conf->dh_file;
params.openssl_ciphers = hapd->conf->openssl_ciphers;
params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 3e62991..a51b949 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -347,7 +347,7 @@
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
hapd->iconf->secondary_channel,
- hapd->iconf->vht_oper_chwidth,
+ hostapd_get_oper_chwidth(hapd->iconf),
&op_class, &channel) ==
NUM_HOSTAPD_MODES)
return eid;
@@ -398,7 +398,8 @@
if (hapd->iconf->ieee80211ax) {
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
- 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
+ 3 + sizeof(struct ieee80211_spatial_reuse);
}
#endif /* CONFIG_IEEE80211AX */
@@ -509,9 +510,10 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
- pos = hostapd_eid_he_capab(hapd, pos);
+ pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_he_operation(hapd, pos);
pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
+ pos = hostapd_eid_spatial_reuse(hapd, pos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -593,7 +595,7 @@
pos = ssid_list;
end = ssid_list + ssid_list_len;
- while (end - pos >= 1) {
+ while (end - pos >= 2) {
if (2 + pos[1] > end - pos)
break;
if (pos[1] == 0)
@@ -1088,7 +1090,8 @@
if (hapd->iconf->ieee80211ax) {
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
- 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
+ 3 + sizeof(struct ieee80211_spatial_reuse);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1223,9 +1226,11 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
- tailpos = hostapd_eid_he_capab(hapd, tailpos);
+ tailpos = hostapd_eid_he_capab(hapd, tailpos,
+ IEEE80211_MODE_AP);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
+ tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1394,6 +1399,7 @@
struct hostapd_freq_params freq;
struct hostapd_iface *iface = hapd->iface;
struct hostapd_config *iconf = iface->conf;
+ struct hostapd_hw_modes *cmode = iface->current_mode;
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
@@ -1417,15 +1423,16 @@
params.reenable = hapd->reenable_beacon;
hapd->reenable_beacon = 0;
- if (iface->current_mode &&
+ if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
iconf->channel, iconf->ieee80211n,
- iconf->ieee80211ac,
+ iconf->ieee80211ac, iconf->ieee80211ax,
iconf->secondary_channel,
- iconf->vht_oper_chwidth,
- iconf->vht_oper_centr_freq_seg0_idx,
- iconf->vht_oper_centr_freq_seg1_idx,
- iface->current_mode->vht_capab) == 0)
+ hostapd_get_oper_chwidth(iconf),
+ hostapd_get_oper_centr_freq_seg0_idx(iconf),
+ hostapd_get_oper_centr_freq_seg1_idx(iconf),
+ cmode->vht_capab,
+ &cmode->he_capab[IEEE80211_MODE_AP]) == 0)
params.freq = &freq;
res = hostapd_drv_set_ap(hapd, ¶ms);
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index c693715..2c4953d 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -712,6 +712,7 @@
"secondary_channel=%d\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
+ "ieee80211ax=%d\n"
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
@@ -720,6 +721,7 @@
iface->conf->ieee80211n && !hapd->conf->disable_11n,
iface->conf->ieee80211ac &&
!hapd->conf->disable_11ac,
+ iface->conf->ieee80211ax,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 79cd00f..ac23c2b 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -28,17 +28,17 @@
if (iface->conf->ieee80211n && iface->conf->secondary_channel)
n_chans = 2;
- if (iface->conf->ieee80211ac) {
- switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_USE_HT:
break;
- case VHT_CHANWIDTH_80MHZ:
+ case CHANWIDTH_80MHZ:
n_chans = 4;
break;
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_160MHZ:
n_chans = 8;
break;
- case VHT_CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_80P80MHZ:
n_chans = 4;
*seg1 = 4;
break;
@@ -188,8 +188,8 @@
* The function assumes HT40+ operation.
* Make sure to adjust the following variables after calling this:
* - hapd->secondary_channel
- * - hapd->vht_oper_centr_freq_seg0_idx
- * - hapd->vht_oper_centr_freq_seg1_idx
+ * - hapd->vht/he_oper_centr_freq_seg0_idx
+ * - hapd->vht/he_oper_centr_freq_seg1_idx
*/
static int dfs_find_channel(struct hostapd_iface *iface,
struct hostapd_channel_data **ret_chan,
@@ -232,44 +232,44 @@
}
-static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
- struct hostapd_channel_data *chan,
- int secondary_channel,
- u8 *vht_oper_centr_freq_seg0_idx,
- u8 *vht_oper_centr_freq_seg1_idx)
+static void dfs_adjust_center_freq(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan,
+ int secondary_channel,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx)
{
- if (!iface->conf->ieee80211ac)
+ if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
return;
if (!chan)
return;
- *vht_oper_centr_freq_seg1_idx = 0;
+ *oper_centr_freq_seg1_idx = 0;
- switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_USE_HT:
if (secondary_channel == 1)
- *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
+ *oper_centr_freq_seg0_idx = chan->chan + 2;
else if (secondary_channel == -1)
- *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
+ *oper_centr_freq_seg0_idx = chan->chan - 2;
else
- *vht_oper_centr_freq_seg0_idx = chan->chan;
+ *oper_centr_freq_seg0_idx = chan->chan;
break;
- case VHT_CHANWIDTH_80MHZ:
- *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
+ case CHANWIDTH_80MHZ:
+ *oper_centr_freq_seg0_idx = chan->chan + 6;
break;
- case VHT_CHANWIDTH_160MHZ:
- *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
+ case CHANWIDTH_160MHZ:
+ *oper_centr_freq_seg0_idx = chan->chan + 14;
break;
default:
wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
- *vht_oper_centr_freq_seg0_idx = 0;
+ *oper_centr_freq_seg0_idx = 0;
break;
}
wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
- *vht_oper_centr_freq_seg0_idx,
- *vht_oper_centr_freq_seg1_idx);
+ *oper_centr_freq_seg0_idx,
+ *oper_centr_freq_seg1_idx);
}
@@ -288,24 +288,24 @@
if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
channel_no -= 4;
- /* VHT */
- if (iface->conf->ieee80211ac) {
- switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ /* VHT/HE */
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_USE_HT:
break;
- case VHT_CHANWIDTH_80MHZ:
- channel_no =
- iface->conf->vht_oper_centr_freq_seg0_idx - 6;
+ case CHANWIDTH_80MHZ:
+ channel_no = hostapd_get_oper_centr_freq_seg0_idx(
+ iface->conf) - 6;
break;
- case VHT_CHANWIDTH_160MHZ:
- channel_no =
- iface->conf->vht_oper_centr_freq_seg0_idx - 14;
+ case CHANWIDTH_160MHZ:
+ channel_no = hostapd_get_oper_centr_freq_seg0_idx(
+ iface->conf) - 14;
break;
- case VHT_CHANWIDTH_80P80MHZ:
- channel_no =
- iface->conf->vht_oper_centr_freq_seg0_idx - 6;
- chan_seg1 =
- iface->conf->vht_oper_centr_freq_seg1_idx - 6;
+ case CHANWIDTH_80P80MHZ:
+ channel_no = hostapd_get_oper_centr_freq_seg0_idx(
+ iface->conf) - 6;
+ chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
+ iface->conf) - 6;
break;
default:
wpa_printf(MSG_INFO,
@@ -348,7 +348,7 @@
mode->num_channels, channel_no, iface->conf->channel,
iface->conf->ieee80211n,
iface->conf->secondary_channel,
- iface->conf->vht_oper_chwidth);
+ hostapd_get_oper_chwidth(iface->conf));
for (i = 0; i < mode->num_channels; i++) {
wpa_printf(MSG_DEBUG, "Available channel: %d",
@@ -435,8 +435,8 @@
static struct hostapd_channel_data *
dfs_get_valid_channel(struct hostapd_iface *iface,
int *secondary_channel,
- u8 *vht_oper_centr_freq_seg0_idx,
- u8 *vht_oper_centr_freq_seg1_idx,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx,
int skip_radar)
{
struct hostapd_hw_modes *mode;
@@ -447,8 +447,8 @@
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
*secondary_channel = 0;
- *vht_oper_centr_freq_seg0_idx = 0;
- *vht_oper_centr_freq_seg1_idx = 0;
+ *oper_centr_freq_seg0_idx = 0;
+ *oper_centr_freq_seg1_idx = 0;
if (iface->current_mode == NULL)
return NULL;
@@ -473,10 +473,10 @@
else
*secondary_channel = 0;
- dfs_adjust_vht_center_freq(iface, chan,
- *secondary_channel,
- vht_oper_centr_freq_seg0_idx,
- vht_oper_centr_freq_seg1_idx);
+ dfs_adjust_center_freq(iface, chan,
+ *secondary_channel,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx);
return chan;
}
@@ -724,8 +724,8 @@
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = sec;
- iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
- iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
}
} while (res);
@@ -736,20 +736,19 @@
"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
iface->freq,
iface->conf->channel, iface->conf->secondary_channel,
- iface->conf->vht_oper_chwidth,
- iface->conf->vht_oper_centr_freq_seg0_idx,
- iface->conf->vht_oper_centr_freq_seg1_idx,
+ hostapd_get_oper_chwidth(iface->conf),
+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
iface->dfs_cac_ms / 1000);
- res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
- iface->freq,
- iface->conf->channel,
- iface->conf->ieee80211n,
- iface->conf->ieee80211ac,
- iface->conf->secondary_channel,
- iface->conf->vht_oper_chwidth,
- iface->conf->vht_oper_centr_freq_seg0_idx,
- iface->conf->vht_oper_centr_freq_seg1_idx);
+ res = hostapd_start_dfs_cac(
+ iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
+ iface->conf->ieee80211n, iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
+ iface->conf->secondary_channel,
+ hostapd_get_oper_chwidth(iface->conf),
+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
if (res) {
wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
@@ -842,16 +841,16 @@
{
struct hostapd_channel_data *channel;
int secondary_channel;
- u8 vht_oper_centr_freq_seg0_idx = 0;
- u8 vht_oper_centr_freq_seg1_idx = 0;
+ u8 oper_centr_freq_seg0_idx = 0;
+ u8 oper_centr_freq_seg1_idx = 0;
int skip_radar = 0;
int err = 1;
/* Radar detected during active CAC */
iface->cac_started = 0;
channel = dfs_get_valid_channel(iface, &secondary_channel,
- &vht_oper_centr_freq_seg0_idx,
- &vht_oper_centr_freq_seg1_idx,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
@@ -868,10 +867,10 @@
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
- iface->conf->vht_oper_centr_freq_seg0_idx =
- vht_oper_centr_freq_seg0_idx;
- iface->conf->vht_oper_centr_freq_seg1_idx =
- vht_oper_centr_freq_seg1_idx;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ oper_centr_freq_seg1_idx);
err = 0;
hostapd_setup_interface_complete(iface, err);
@@ -883,12 +882,13 @@
{
struct hostapd_channel_data *channel;
int secondary_channel;
- u8 vht_oper_centr_freq_seg0_idx;
- u8 vht_oper_centr_freq_seg1_idx;
+ u8 oper_centr_freq_seg0_idx;
+ u8 oper_centr_freq_seg1_idx;
int skip_radar = 1;
struct csa_settings csa_settings;
unsigned int i;
int err = 1;
+ struct hostapd_hw_modes *cmode = iface->current_mode;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -911,8 +911,8 @@
/* Perform channel switch/CSA */
channel = dfs_get_valid_channel(iface, &secondary_channel,
- &vht_oper_centr_freq_seg0_idx,
- &vht_oper_centr_freq_seg1_idx,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
@@ -923,8 +923,8 @@
*/
skip_radar = 0;
channel = dfs_get_valid_channel(iface, &secondary_channel,
- &vht_oper_centr_freq_seg0_idx,
- &vht_oper_centr_freq_seg1_idx,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
wpa_printf(MSG_INFO,
@@ -936,10 +936,10 @@
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
- iface->conf->vht_oper_centr_freq_seg0_idx =
- vht_oper_centr_freq_seg0_idx;
- iface->conf->vht_oper_centr_freq_seg1_idx =
- vht_oper_centr_freq_seg1_idx;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ oper_centr_freq_seg1_idx);
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
@@ -962,11 +962,13 @@
channel->chan,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
secondary_channel,
- iface->conf->vht_oper_chwidth,
- vht_oper_centr_freq_seg0_idx,
- vht_oper_centr_freq_seg1_idx,
- iface->current_mode->vht_capab);
+ hostapd_get_oper_chwidth(iface->conf),
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx,
+ cmode->vht_capab,
+ &cmode->he_capab[IEEE80211_MODE_AP]);
if (err) {
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
@@ -986,10 +988,10 @@
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
- iface->conf->vht_oper_centr_freq_seg0_idx =
- vht_oper_centr_freq_seg0_idx;
- iface->conf->vht_oper_centr_freq_seg1_idx =
- vht_oper_centr_freq_seg1_idx;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ oper_centr_freq_seg1_idx);
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 75edbc9..697c3ba 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -16,6 +16,7 @@
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "gas_query_ap.h"
+#include "gas_serv.h"
#include "wpa_auth.h"
#include "dpp_hostapd.h"
@@ -557,6 +558,14 @@
* received hash values */
dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
r_bootstrap, &own_bi, &peer_bi);
+#ifdef CONFIG_DPP2
+ if (!own_bi) {
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, i_bootstrap,
+ r_bootstrap) == 0)
+ return;
+ }
+#endif /* CONFIG_DPP2 */
if (!own_bi) {
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"No matching own bootstrapping key found - ignore message");
@@ -1357,6 +1366,12 @@
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
" freq=%u type=%d", MAC2STR(src), freq, type);
+#ifdef CONFIG_DPP2
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, NULL, NULL) == 0)
+ return;
+#endif /* CONFIG_DPP2 */
+
switch (type) {
case DPP_PA_AUTHENTICATION_REQ:
hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
@@ -1410,7 +1425,8 @@
struct wpabuf *
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
- const u8 *query, size_t query_len)
+ const u8 *query, size_t query_len,
+ const u8 *data, size_t data_len)
{
struct dpp_authentication *auth = hapd->dpp_auth;
struct wpabuf *resp;
@@ -1418,6 +1434,13 @@
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
if (!auth || !auth->auth_success ||
os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
+#ifdef CONFIG_DPP2
+ if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data,
+ data_len) == 0) {
+ /* Response will be forwarded once received over TCP */
+ return NULL;
+ }
+#endif /* CONFIG_DPP2 */
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
}
@@ -1609,11 +1632,67 @@
}
+#ifdef CONFIG_DPP2
+
+static void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq,
+ const u8 *msg, size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ u8 *buf;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u",
+ MAC2STR(addr), freq);
+ buf = os_malloc(2 + len);
+ if (!buf)
+ return;
+ buf[0] = WLAN_ACTION_PUBLIC;
+ buf[1] = WLAN_PA_VENDOR_SPECIFIC;
+ os_memcpy(buf + 2, msg, len);
+ hostapd_drv_send_action(hapd, freq, 0, addr, buf, 2 + len);
+ os_free(buf);
+}
+
+
+static void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr,
+ u8 dialog_token, int prot,
+ struct wpabuf *buf)
+{
+ struct hostapd_data *hapd = ctx;
+
+ gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
+static int hostapd_dpp_add_controllers(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_DPP2
+ struct dpp_controller_conf *ctrl;
+ struct dpp_relay_config config;
+
+ os_memset(&config, 0, sizeof(config));
+ config.cb_ctx = hapd;
+ config.tx = hostapd_dpp_relay_tx;
+ config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx;
+ for (ctrl = hapd->conf->dpp_controller; ctrl; ctrl = ctrl->next) {
+ config.ipaddr = &ctrl->ipaddr;
+ config.pkhash = ctrl->pkhash;
+ if (dpp_relay_add_controller(hapd->iface->interfaces->dpp,
+ &config) < 0)
+ return -1;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
+}
+
+
int hostapd_dpp_init(struct hostapd_data *hapd)
{
hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
hapd->dpp_init_done = 1;
- return 0;
+ return hostapd_dpp_add_controllers(hapd);
}
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index 449ca16..c1ec5d7 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -19,7 +19,8 @@
const u8 *data, size_t data_len, int ok);
struct wpabuf *
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
- const u8 *query, size_t query_len);
+ const u8 *query, size_t query_len,
+ const u8 *data, size_t data_len);
void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok);
int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 952a3d5..3158768 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -772,7 +772,8 @@
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset, int width, int cf1, int cf2)
+ int offset, int width, int cf1, int cf2,
+ int finished)
{
/* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
@@ -783,7 +784,8 @@
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ finished ? "had" : "starting",
freq, ht, hapd->iconf->ch_switch_vht_config, offset,
width, channel_width_to_string(width), cf1, cf2);
@@ -806,19 +808,19 @@
switch (width) {
case CHAN_WIDTH_80:
- chwidth = VHT_CHANWIDTH_80MHZ;
+ chwidth = CHANWIDTH_80MHZ;
break;
case CHAN_WIDTH_80P80:
- chwidth = VHT_CHANWIDTH_80P80MHZ;
+ chwidth = CHANWIDTH_80P80MHZ;
break;
case CHAN_WIDTH_160:
- chwidth = VHT_CHANWIDTH_160MHZ;
+ chwidth = CHANWIDTH_160MHZ;
break;
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
case CHAN_WIDTH_40:
default:
- chwidth = VHT_CHANWIDTH_USE_HT;
+ chwidth = CHANWIDTH_USE_HT;
break;
}
@@ -851,13 +853,22 @@
hapd->iconf->ch_switch_vht_config = 0;
hapd->iconf->secondary_channel = offset;
- hapd->iconf->vht_oper_chwidth = chwidth;
- hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
- hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
+ hostapd_set_oper_chwidth(hapd->iconf, chwidth);
+ hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
hapd->iface->num_hw_features);
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d",
+ finished ? WPA_EVENT_CHANNEL_SWITCH :
+ WPA_EVENT_CHANNEL_SWITCH_STARTED,
+ freq, ht, offset, channel_width_to_string(width),
+ cf1, cf2, is_dfs);
+ if (!finished)
+ return;
+
if (hapd->csa_in_progress &&
freq == hapd->cs_freq_params.freq) {
hostapd_cleanup_cs_params(hapd);
@@ -949,28 +960,31 @@
goto out;
}
- if (hapd->iface->conf->ieee80211ac) {
+ if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
/* set defaults for backwards compatibility */
- hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
- hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
- hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
+ hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
+ hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
if (acs_res->ch_width == 80) {
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- acs_res->vht_seg0_center_ch;
- hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg0_center_ch);
+ hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ);
} else if (acs_res->ch_width == 160) {
if (acs_res->vht_seg1_center_ch == 0) {
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- acs_res->vht_seg0_center_ch;
- hapd->iconf->vht_oper_chwidth =
- VHT_CHANWIDTH_160MHZ;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf,
+ acs_res->vht_seg0_center_ch);
+ hostapd_set_oper_chwidth(hapd->iconf,
+ CHANWIDTH_160MHZ);
} else {
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- acs_res->vht_seg0_center_ch;
- hapd->iconf->vht_oper_centr_freq_seg1_idx =
- acs_res->vht_seg1_center_ch;
- hapd->iconf->vht_oper_chwidth =
- VHT_CHANWIDTH_80P80MHZ;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf,
+ acs_res->vht_seg0_center_ch);
+ hostapd_set_oper_centr_freq_seg1_idx(
+ hapd->iconf,
+ acs_res->vht_seg1_center_ch);
+ hostapd_set_oper_chwidth(hapd->iconf,
+ CHANWIDTH_80P80MHZ);
}
}
}
@@ -1575,6 +1589,73 @@
}
+#ifdef CONFIG_OWE
+static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd,
+ const u8 *peer, const u8 *ie,
+ size_t ie_len)
+{
+ u16 status;
+ struct sta_info *sta;
+ struct ieee802_11_elems elems;
+
+ if (!hapd || !hapd->wpa_auth) {
+ wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context");
+ return -1;
+ }
+ if (!peer) {
+ wpa_printf(MSG_DEBUG, "OWE: Peer unknown");
+ return -1;
+ }
+ if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) {
+ wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured");
+ status = WLAN_STATUS_AKMP_NOT_VALID;
+ goto err;
+ }
+ if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for "
+ MACSTR, MAC2STR(peer));
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto err;
+ }
+ status = owe_validate_request(hapd, peer, elems.rsn_ie,
+ elems.rsn_ie_len,
+ elems.owe_dh, elems.owe_dh_len);
+ if (status != WLAN_STATUS_SUCCESS)
+ goto err;
+
+ sta = ap_get_sta(hapd, peer);
+ if (sta) {
+ ap_sta_no_session_timeout(hapd, sta);
+ accounting_sta_stop(hapd, sta);
+
+ /*
+ * Make sure that the previously registered inactivity timer
+ * will not remove the STA immediately.
+ */
+ sta->timeout_next = STA_NULLFUNC;
+ } else {
+ sta = ap_sta_add(hapd, peer);
+ if (!sta) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto err;
+ }
+ }
+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+
+ status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie,
+ elems.rsn_ie_len, elems.owe_dh,
+ elems.owe_dh_len);
+ if (status != WLAN_STATUS_SUCCESS)
+ ap_free_sta(hapd, sta);
+
+ return 0;
+err:
+ hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0);
+ return 0;
+}
+#endif /* CONFIG_OWE */
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -1680,6 +1761,15 @@
data->assoc_info.req_ies_len,
data->assoc_info.reassoc);
break;
+#ifdef CONFIG_OWE
+ case EVENT_UPDATE_DH:
+ if (!data)
+ return;
+ hostapd_notif_update_dh_ie(hapd, data->update_dh.peer,
+ data->update_dh.ie,
+ data->update_dh.ie_len);
+ break;
+#endif /* CONFIG_OWE */
case EVENT_DISASSOC:
if (data)
hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
@@ -1696,6 +1786,7 @@
case EVENT_AUTH:
hostapd_notif_auth(hapd, &data->auth);
break;
+ case EVENT_CH_SWITCH_STARTED:
case EVENT_CH_SWITCH:
if (!data)
break;
@@ -1704,7 +1795,8 @@
data->ch_switch.ch_offset,
data->ch_switch.ch_width,
data->ch_switch.cf1,
- data->ch_switch.cf2);
+ data->ch_switch.cf2,
+ event == EVENT_CH_SWITCH);
break;
case EVENT_CONNECT_FAILED_REASON:
if (!data)
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index a7df810..9567e20 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1522,9 +1522,9 @@
#ifdef CONFIG_DPP
-static void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
- const u8 *sa, u8 dialog_token,
- int prot, struct wpabuf *buf)
+void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
+ const u8 *sa, u8 dialog_token,
+ int prot, struct wpabuf *buf)
{
struct wpabuf *tx_buf;
@@ -1681,7 +1681,8 @@
if (dpp) {
struct wpabuf *msg;
- msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen);
+ msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen,
+ data, len);
if (!msg)
return;
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 2cf1817..1528af4 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -88,4 +88,8 @@
int gas_serv_init(struct hostapd_data *hapd);
void gas_serv_deinit(struct hostapd_data *hapd);
+void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
+ const u8 *sa, u8 dialog_token,
+ int prot, struct wpabuf *buf);
+
#endif /* GAS_SERV_H */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 0bd6892..cc75a77 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -50,6 +50,8 @@
#include "fils_hlp.h"
#include "acs.h"
#include "hs20.h"
+#include "airtime_policy.h"
+#include "wpa_auth_kay.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -260,11 +262,14 @@
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
hapd->iconf->ht_capab = oldconf->ht_capab;
hapd->iconf->vht_capab = oldconf->vht_capab;
- hapd->iconf->vht_oper_chwidth = oldconf->vht_oper_chwidth;
- hapd->iconf->vht_oper_centr_freq_seg0_idx =
- oldconf->vht_oper_centr_freq_seg0_idx;
- hapd->iconf->vht_oper_centr_freq_seg1_idx =
- oldconf->vht_oper_centr_freq_seg1_idx;
+ hostapd_set_oper_chwidth(hapd->iconf,
+ hostapd_get_oper_chwidth(oldconf));
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf,
+ hostapd_get_oper_centr_freq_seg0_idx(oldconf));
+ hostapd_set_oper_centr_freq_seg1_idx(
+ hapd->iconf,
+ hostapd_get_oper_centr_freq_seg1_idx(oldconf));
hapd->conf = newconf->bss[j];
hostapd_reload_bss(hapd);
}
@@ -369,6 +374,7 @@
#endif /* CONFIG_NO_RADIUS */
hostapd_deinit_wps(hapd);
+ ieee802_1x_dealloc_kay_sm_hapd(hapd);
#ifdef CONFIG_DPP
hostapd_dpp_deinit(hapd);
gas_query_ap_deinit(hapd->gas);
@@ -491,6 +497,7 @@
iface->basic_rates = NULL;
ap_list_deinit(iface);
sta_track_deinit(iface);
+ airtime_policy_update_deinit(iface);
}
@@ -1863,10 +1870,13 @@
hapd->iconf->channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
+ hapd->iconf->ieee80211ax,
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)) {
+ hostapd_get_oper_chwidth(hapd->iconf),
+ hostapd_get_oper_centr_freq_seg0_idx(
+ hapd->iconf),
+ hostapd_get_oper_centr_freq_seg1_idx(
+ hapd->iconf))) {
wpa_printf(MSG_ERROR, "Could not set channel for "
"kernel driver");
goto fail;
@@ -1976,6 +1986,7 @@
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
hostapd_owe_update_trans(iface);
+ airtime_policy_update_init(iface);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
@@ -2996,6 +3007,8 @@
}
#endif /* CONFIG_P2P */
+ airtime_policy_new_sta(hapd, 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. */
@@ -3036,6 +3049,14 @@
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
}
+
+#ifdef CONFIG_MACSEC
+ if (hapd->conf->wpa_key_mgmt == WPA_KEY_MGMT_NONE &&
+ hapd->conf->mka_psk_set)
+ ieee802_1x_create_preshared_mka_hapd(hapd, sta);
+ else
+ ieee802_1x_alloc_kay_sm_hapd(hapd, sta);
+#endif /* CONFIG_MACSEC */
}
@@ -3195,6 +3216,8 @@
struct hostapd_freq_params *old_params)
{
int channel;
+ u8 seg0, seg1;
+ struct hostapd_hw_modes *mode;
if (!params->channel) {
/* check if the new channel is supported by hw */
@@ -3205,33 +3228,37 @@
if (!channel)
return -1;
+ mode = hapd->iface->current_mode;
+
/* if a pointer to old_params is provided we save previous state */
if (old_params &&
hostapd_set_freq_params(old_params, conf->hw_mode,
hostapd_hw_get_freq(hapd, conf->channel),
conf->channel, conf->ieee80211n,
- conf->ieee80211ac,
+ conf->ieee80211ac, conf->ieee80211ax,
conf->secondary_channel,
- conf->vht_oper_chwidth,
- conf->vht_oper_centr_freq_seg0_idx,
- conf->vht_oper_centr_freq_seg1_idx,
- conf->vht_capab))
+ hostapd_get_oper_chwidth(conf),
+ hostapd_get_oper_centr_freq_seg0_idx(conf),
+ hostapd_get_oper_centr_freq_seg1_idx(conf),
+ conf->vht_capab,
+ mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+ NULL))
return -1;
switch (params->bandwidth) {
case 0:
case 20:
case 40:
- conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
break;
case 80:
if (params->center_freq2)
- conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_80P80MHZ);
else
- conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
break;
case 160:
- conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
+ hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
break;
default:
return -1;
@@ -3241,9 +3268,11 @@
conf->ieee80211n = params->ht_enabled;
conf->secondary_channel = params->sec_channel_offset;
ieee80211_freq_to_chan(params->center_freq1,
- &conf->vht_oper_centr_freq_seg0_idx);
+ &seg0);
ieee80211_freq_to_chan(params->center_freq2,
- &conf->vht_oper_centr_freq_seg1_idx);
+ &seg1);
+ hostapd_set_oper_centr_freq_seg0_idx(conf, seg0);
+ hostapd_set_oper_centr_freq_seg1_idx(conf, seg1);
/* TODO: maybe call here hostapd_config_check here? */
@@ -3257,7 +3286,7 @@
struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
- u8 chan, vht_bandwidth;
+ u8 chan, bandwidth;
os_memset(&old_freq, 0, sizeof(old_freq));
if (!iface || !iface->freq || hapd->csa_in_progress)
@@ -3266,29 +3295,30 @@
switch (settings->freq_params.bandwidth) {
case 80:
if (settings->freq_params.center_freq2)
- vht_bandwidth = VHT_CHANWIDTH_80P80MHZ;
+ bandwidth = CHANWIDTH_80P80MHZ;
else
- vht_bandwidth = VHT_CHANWIDTH_80MHZ;
+ bandwidth = CHANWIDTH_80MHZ;
break;
case 160:
- vht_bandwidth = VHT_CHANWIDTH_160MHZ;
+ bandwidth = CHANWIDTH_160MHZ;
break;
default:
- vht_bandwidth = VHT_CHANWIDTH_USE_HT;
+ bandwidth = CHANWIDTH_USE_HT;
break;
}
if (ieee80211_freq_to_channel_ext(
settings->freq_params.freq,
settings->freq_params.sec_channel_offset,
- vht_bandwidth,
+ bandwidth,
&hapd->iface->cs_oper_class,
&chan) == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_DEBUG,
- "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)",
+ "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)",
settings->freq_params.freq,
settings->freq_params.sec_channel_offset,
- settings->freq_params.vht_enabled);
+ settings->freq_params.vht_enabled,
+ settings->freq_params.he_enabled);
return -1;
}
@@ -3388,29 +3418,29 @@
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params)
{
- int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
+ int seg0_idx = 0, seg1_idx = 0, bw = CHANWIDTH_USE_HT;
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
if (freq_params->center_freq1)
- vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
+ seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
if (freq_params->center_freq2)
- vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
+ seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
switch (freq_params->bandwidth) {
case 0:
case 20:
case 40:
- vht_bw = VHT_CHANWIDTH_USE_HT;
+ bw = CHANWIDTH_USE_HT;
break;
case 80:
if (freq_params->center_freq2)
- vht_bw = VHT_CHANWIDTH_80P80MHZ;
+ bw = CHANWIDTH_80P80MHZ;
else
- vht_bw = VHT_CHANWIDTH_80MHZ;
+ bw = CHANWIDTH_80MHZ;
break;
case 160:
- vht_bw = VHT_CHANWIDTH_160MHZ;
+ bw = CHANWIDTH_160MHZ;
break;
default:
wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
@@ -3421,11 +3451,12 @@
iface->freq = freq_params->freq;
iface->conf->channel = freq_params->channel;
iface->conf->secondary_channel = freq_params->sec_channel_offset;
- iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
- iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
- iface->conf->vht_oper_chwidth = vht_bw;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf, seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf, seg1_idx);
+ hostapd_set_oper_chwidth(iface->conf, bw);
iface->conf->ieee80211n = freq_params->ht_enabled;
iface->conf->ieee80211ac = freq_params->vht_enabled;
+ iface->conf->ieee80211ax = freq_params->he_enabled;
/*
* cs_params must not be cleared earlier because the freq_params
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 607bb95..44ef753 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -232,6 +232,10 @@
struct wps_stat wps_stats;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_MACSEC
+ struct ieee802_1x_kay *kay;
+#endif /* CONFIG_MACSEC */
+
struct hostapd_probereq_cb *probereq_cb;
size_t num_probereq_cb;
@@ -379,6 +383,13 @@
unsigned int dpp_ignore_netaccesskey_mismatch:1;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_AIRTIME_POLICY
+ unsigned int num_backlogged_sta;
+ unsigned int airtime_weight;
+#endif /* CONFIG_AIRTIME_POLICY */
+
+ u8 last_1x_eapol_key_replay_counter[8];
};
@@ -542,6 +553,12 @@
unsigned int num_sta_seen;
u8 dfs_domain;
+#ifdef CONFIG_AIRTIME_POLICY
+ unsigned int airtime_quantum;
+#endif /* CONFIG_AIRTIME_POLICY */
+
+ /* Previous WMM element information */
+ struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
};
/* hostapd.c */
@@ -608,7 +625,8 @@
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
- int offset, int width, int cf1, int cf2);
+ int offset, int width, int cf1, int cf2,
+ int finished);
struct survey_results;
void hostapd_event_get_survey(struct hostapd_iface *iface,
struct survey_results *survey_results);
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 8ac33bb..c1f19e2 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -329,9 +329,9 @@
res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
- iface->conf->vht_oper_centr_freq_seg0_idx = 0;
- iface->conf->vht_oper_centr_freq_seg1_idx = 0;
- iface->conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 0);
+ hostapd_set_oper_chwidth(iface->conf, CHANWIDTH_USE_HT);
res = 1;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
@@ -655,6 +655,14 @@
}
#endif /* CONFIG_IEEE80211AC */
+
+#ifdef CONFIG_IEEE80211AX
+static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface)
+{
+ return 1;
+}
+#endif /* CONFIG_IEEE80211AX */
+
#endif /* CONFIG_IEEE80211N */
@@ -675,6 +683,11 @@
if (!ieee80211n_supported_ht_capab(iface))
return -1;
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->ieee80211ax &&
+ !ieee80211ax_supported_he_capab(iface))
+ return -1;
+#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_IEEE80211AC
if (iface->conf->ieee80211ac &&
!ieee80211ac_supported_vht_capab(iface))
@@ -863,12 +876,14 @@
return -1;
if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
- iface->conf->ieee80211n || iface->conf->ieee80211ac) &&
+ iface->conf->ieee80211n || iface->conf->ieee80211ac ||
+ iface->conf->ieee80211ax) &&
iface->conf->channel == 14) {
- wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
+ wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14");
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
iface->conf->ieee80211n = 0;
iface->conf->ieee80211ac = 0;
+ iface->conf->ieee80211ax = 0;
}
iface->current_mode = NULL;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 5cd2562..fff35b7 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -23,6 +23,7 @@
#include "common/sae.h"
#include "common/dpp.h"
#include "common/ocv.h"
+#include "common/wpa_common.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -709,7 +710,8 @@
os_memset(¶ms, 0, sizeof(params));
params.status = status;
params.bssid = sta->addr;
- if (status == WLAN_STATUS_SUCCESS && sta->sae)
+ if (status == WLAN_STATUS_SUCCESS && sta->sae &&
+ !hapd->conf->disable_pmksa_caching)
params.pmkid = sta->sae->pmkid;
hostapd_drv_send_external_auth_status(hapd, ¶ms);
@@ -1038,8 +1040,8 @@
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "start SAE authentication (RX commit, status=%u)",
- status_code);
+ "start SAE authentication (RX commit, status=%u (%s))",
+ status_code, status2str(status_code));
if ((hapd->conf->mesh & MESH_ENABLED) &&
status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
@@ -1182,8 +1184,8 @@
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "SAE authentication (RX confirm, status=%u)",
- status_code);
+ "SAE authentication (RX confirm, status=%u (%s))",
+ status_code, status2str(status_code));
if (status_code != WLAN_STATUS_SUCCESS)
goto remove_sta;
if (sta->sae->state >= SAE_CONFIRMED ||
@@ -1224,8 +1226,9 @@
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "unexpected SAE authentication transaction %u (status=%u)",
- auth_transaction, status_code);
+ "unexpected SAE authentication transaction %u (status=%u (%s))",
+ auth_transaction, status_code,
+ status2str(status_code));
if (status_code != WLAN_STATUS_SUCCESS)
goto remove_sta;
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
@@ -1821,6 +1824,8 @@
}
sta->fils_erp_pmkid_set = 0;
+ wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len,
+ sta->fils_erp_pmkid);
if (!hapd->conf->disable_pmksa_caching &&
wpa_auth_pmksa_add2(
hapd->wpa_auth, sta->addr,
@@ -2321,8 +2326,11 @@
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
WLAN_STA_AUTHORIZED);
- if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
- NULL, NULL, sta->flags, 0, 0, 0, 0)) {
+ if (hostapd_sta_add(hapd, sta->addr, 0, 0,
+ sta->supported_rates,
+ sta->supported_rates_len,
+ 0, NULL, NULL, NULL, 0,
+ sta->flags, 0, 0, 0, 0)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
@@ -2788,6 +2796,123 @@
return WLAN_STATUS_SUCCESS;
}
+
+u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
+{
+ struct wpa_ie_data data;
+ int res;
+
+ if (!rsn_ie || rsn_ie_len < 2) {
+ wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
+ MAC2STR(peer));
+ return WLAN_STATUS_INVALID_IE;
+ }
+ rsn_ie -= 2;
+ rsn_ie_len += 2;
+
+ res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
+ " (res=%d)", MAC2STR(peer), res);
+ wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
+ return wpa_res_to_status_code(res);
+ }
+ if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Unexpected key mgmt 0x%x from " MACSTR,
+ (unsigned int) data.key_mgmt, MAC2STR(peer));
+ return WLAN_STATUS_AKMP_NOT_VALID;
+ }
+ if (!owe_dh) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: No Diffie-Hellman Parameter element from "
+ MACSTR, MAC2STR(peer));
+ return WLAN_STATUS_AKMP_NOT_VALID;
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+u16 owe_process_rsn_ie(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
+{
+ u16 status;
+ u8 *owe_buf, ie[256 * 2];
+ size_t ie_len = 0;
+ int res;
+
+ if (!rsn_ie || rsn_ie_len < 2) {
+ wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
+ status = WLAN_STATUS_INVALID_IE;
+ goto end;
+ }
+
+ if (!sta->wpa_sm)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
+ NULL);
+ if (!sta->wpa_sm) {
+ wpa_printf(MSG_WARNING,
+ "OWE: Failed to initialize WPA state machine");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto end;
+ }
+ rsn_ie -= 2;
+ rsn_ie_len += 2;
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ hapd->iface->freq, rsn_ie, rsn_ie_len,
+ NULL, 0, owe_dh, owe_dh_len);
+ status = wpa_res_to_status_code(res);
+ if (status != WLAN_STATUS_SUCCESS)
+ goto end;
+ status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+ if (status != WLAN_STATUS_SUCCESS)
+ goto end;
+ owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
+ NULL, 0);
+ if (!owe_buf) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto end;
+ }
+
+ if (sta->owe_ecdh) {
+ struct wpabuf *pub;
+
+ pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+ if (!pub) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto end;
+ }
+
+ /* OWE Diffie-Hellman Parameter element */
+ *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
+ *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
+ *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
+ */
+ WPA_PUT_LE16(owe_buf, sta->owe_group);
+ owe_buf += 2;
+ os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
+ owe_buf += wpabuf_len(pub);
+ wpabuf_free(pub);
+ sta->external_dh_updated = 1;
+ }
+ ie_len = owe_buf - ie;
+
+end:
+ wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
+ MACSTR, status, (unsigned int) ie_len,
+ MAC2STR(sta->addr));
+ hostapd_drv_update_dh_ie(hapd, sta->addr, status,
+ status == WLAN_STATUS_SUCCESS ? ie : NULL,
+ ie_len);
+
+ return status;
+}
+
#endif /* CONFIG_OWE */
@@ -2843,10 +2968,6 @@
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- resp = copy_sta_vht_oper(hapd, sta, elems.vht_operation);
- if (resp != WLAN_STATUS_SUCCESS)
- return resp;
-
resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -2867,6 +2988,15 @@
return resp;
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
+ elems.he_capabilities,
+ elems.he_capabilities_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
+#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_P2P
if (elems.p2p) {
@@ -3229,6 +3359,7 @@
{
struct ieee80211_ht_capabilities ht_cap;
struct ieee80211_vht_capabilities vht_cap;
+ struct ieee80211_he_capabilities he_cap;
int set = 1;
/*
@@ -3281,6 +3412,12 @@
if (sta->flags & WLAN_STA_VHT)
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (sta->flags & WLAN_STA_HE) {
+ hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
+ sta->he_capab_len);
+ }
+#endif /* CONFIG_IEEE80211AX */
/*
* Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
@@ -3292,6 +3429,8 @@
sta->listen_interval,
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
+ sta->flags & WLAN_STA_HE ? &he_cap : NULL,
+ sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
set)) {
@@ -3329,6 +3468,8 @@
#ifdef CONFIG_FILS
if (sta && sta->fils_hlp_resp)
buflen += wpabuf_len(sta->fils_hlp_resp);
+ if (sta)
+ buflen += 150;
#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
@@ -3390,6 +3531,15 @@
}
}
#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_FILS
+ if (sta && status_code == WLAN_STATUS_SUCCESS &&
+ (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK))
+ p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
+ buf + buflen - p,
+ ies, ies_len);
+#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
if (sta && status_code == WLAN_STATUS_SUCCESS &&
@@ -3432,6 +3582,15 @@
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
+ p = hostapd_eid_he_operation(hapd, p);
+ p = hostapd_eid_spatial_reuse(hapd, p);
+ p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
p = hostapd_eid_ext_capab(hapd, p);
p = hostapd_eid_bss_max_idle_period(hapd, p);
if (sta && sta->qos_map_enabled)
@@ -3608,6 +3767,12 @@
return owe_buf;
}
+ if (sta->owe_pmk && sta->external_dh_updated) {
+ wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
+ *reason = WLAN_STATUS_SUCCESS;
+ return owe_buf;
+ }
+
*reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
if (*reason != WLAN_STATUS_SUCCESS)
return NULL;
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index db7badc..b8453c9 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -18,6 +18,7 @@
struct ieee80211_mgmt;
struct vlan_description;
struct hostapd_sta_wpa_psk_short;
+enum ieee80211_op_mode;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
@@ -57,9 +58,11 @@
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode);
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
@@ -70,6 +73,10 @@
void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap);
+void hostapd_get_he_capab(struct hostapd_data *hapd,
+ const struct ieee80211_he_capabilities *he_cap,
+ struct ieee80211_he_capabilities *neg_he_cap,
+ size_t he_capab_len);
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab);
@@ -85,6 +92,9 @@
const u8 *vht_oper);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_opmode);
+u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode, const u8 *he_capab,
+ size_t he_capab_len);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -153,6 +163,12 @@
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *owe_dh, u8 owe_dh_len,
u8 *owe_buf, size_t owe_buf_len, u16 *reason);
+u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
+u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 0721358..a51f3fc 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -1,6 +1,7 @@
/*
* hostapd / IEEE 802.11ax HE
* Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2019 John Crispin <john@phrozen.org>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,37 +14,113 @@
#include "hostapd.h"
#include "ap_config.h"
#include "beacon.h"
+#include "sta_info.h"
#include "ieee802_11.h"
#include "dfs.h"
-u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
+static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
+{
+ u8 sz = 0, ru;
+
+ if ((phy_cap_info[HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] &
+ HE_PHYCAP_PPE_THRESHOLD_PRESENT) == 0)
+ return 0;
+
+ ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) &
+ HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
+ while (ru) {
+ if (ru & 0x1)
+ sz++;
+ ru >>= 1;
+ }
+
+ sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
+ sz = (sz * 6) + 7;
+ if (sz % 8)
+ sz += 8;
+ sz /= 8;
+
+ return sz;
+}
+
+
+u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode)
{
struct ieee80211_he_capabilities *cap;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
u8 *pos = eid;
+ u8 ie_size = 0, mcs_nss_size = 0, ppet_size = 0;
- if (!hapd->iface->current_mode)
+ if (!mode)
return eid;
+ ie_size = sizeof(struct ieee80211_he_capabilities);
+ ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
+ mode->he_capab[opmode].phy_cap);
+
+ switch (hapd->iface->conf->he_oper_chwidth) {
+ case CHANWIDTH_80P80MHZ:
+ he_oper_chwidth |=
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
+ mcs_nss_size += 4;
+ /* fall through */
+ case CHANWIDTH_160MHZ:
+ he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+ mcs_nss_size += 4;
+ /* fall through */
+ case CHANWIDTH_80MHZ:
+ case CHANWIDTH_USE_HT:
+ he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
+ mcs_nss_size += 4;
+ break;
+ }
+
+ ie_size += mcs_nss_size + ppet_size;
+
*pos++ = WLAN_EID_EXTENSION;
- *pos++ = 1 + sizeof(struct ieee80211_he_capabilities);
+ *pos++ = 1 + ie_size;
*pos++ = WLAN_EID_EXT_HE_CAPABILITIES;
cap = (struct ieee80211_he_capabilities *) pos;
os_memset(cap, 0, sizeof(*cap));
+ os_memcpy(cap->he_mac_capab_info, mode->he_capab[opmode].mac_cap,
+ HE_MAX_MAC_CAPAB_SIZE);
+ os_memcpy(cap->he_phy_capab_info, mode->he_capab[opmode].phy_cap,
+ HE_MAX_PHY_CAPAB_SIZE);
+ os_memcpy(cap->optional, mode->he_capab[opmode].mcs, mcs_nss_size);
+ if (ppet_size)
+ os_memcpy(&cap->optional[mcs_nss_size],
+ mode->he_capab[opmode].ppet, ppet_size);
+
if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
HE_PHYCAP_SU_BEAMFORMER_CAPAB;
+ else
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] &=
+ ~HE_PHYCAP_SU_BEAMFORMER_CAPAB;
if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
+ else
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] &=
+ ~HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
HE_PHYCAP_MU_BEAMFORMER_CAPAB;
+ else
+ cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] &=
+ ~HE_PHYCAP_MU_BEAMFORMER_CAPAB;
- pos += sizeof(*cap);
+ cap->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &=
+ he_oper_chwidth;
+
+ pos += ie_size;
return pos;
}
@@ -53,36 +130,43 @@
{
struct ieee80211_he_operation *oper;
u8 *pos = eid;
+ int oper_size = 6;
+ u32 params = 0;
if (!hapd->iface->current_mode)
return eid;
*pos++ = WLAN_EID_EXTENSION;
- *pos++ = 1 + sizeof(struct ieee80211_he_operation);
+ *pos++ = 1 + oper_size;
*pos++ = WLAN_EID_EXT_HE_OPERATION;
oper = (struct ieee80211_he_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
- if (hapd->iface->conf->he_op.he_bss_color)
- oper->he_oper_params |= hapd->iface->conf->he_op.he_bss_color;
-
if (hapd->iface->conf->he_op.he_default_pe_duration)
- oper->he_oper_params |=
- (hapd->iface->conf->he_op.he_default_pe_duration <<
- HE_OPERATION_DFLT_PE_DURATION_OFFSET);
+ params |= (hapd->iface->conf->he_op.he_default_pe_duration <<
+ HE_OPERATION_DFLT_PE_DURATION_OFFSET);
if (hapd->iface->conf->he_op.he_twt_required)
- oper->he_oper_params |= HE_OPERATION_TWT_REQUIRED;
+ params |= HE_OPERATION_TWT_REQUIRED;
if (hapd->iface->conf->he_op.he_rts_threshold)
- oper->he_oper_params |=
- (hapd->iface->conf->he_op.he_rts_threshold <<
- HE_OPERATION_RTS_THRESHOLD_OFFSET);
+ params |= (hapd->iface->conf->he_op.he_rts_threshold <<
+ HE_OPERATION_RTS_THRESHOLD_OFFSET);
+
+ if (hapd->iface->conf->he_op.he_bss_color)
+ params |= (hapd->iface->conf->he_op.he_bss_color <<
+ HE_OPERATION_BSS_COLOR_OFFSET);
+
+ /* HE minimum required basic MCS and NSS for STAs */
+ oper->he_mcs_nss_set =
+ host_to_le16(hapd->iface->conf->he_op.he_basic_mcs_nss_set);
/* TODO: conditional MaxBSSID Indicator subfield */
- pos += sizeof(*oper);
+ oper->he_oper_params = host_to_le32(params);
+
+ pos += oper_size;
return pos;
}
@@ -117,3 +201,148 @@
return pos;
}
+
+
+u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_spatial_reuse *spr;
+ u8 *pos = eid, *spr_param;
+ u8 sz = 1;
+
+ if (!hapd->iface->conf->spr.sr_control)
+ return eid;
+
+ if (hapd->iface->conf->spr.sr_control &
+ SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT)
+ sz++;
+
+ if (hapd->iface->conf->spr.sr_control &
+ SPATIAL_REUSE_SRG_INFORMATION_PRESENT)
+ sz += 18;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sz;
+ *pos++ = WLAN_EID_EXT_SPATIAL_REUSE;
+
+ spr = (struct ieee80211_spatial_reuse *) pos;
+ os_memset(spr, 0, sizeof(*spr));
+
+ spr->sr_ctrl = hapd->iface->conf->spr.sr_control;
+ pos++;
+ spr_param = spr->params;
+ if (spr->sr_ctrl & SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) {
+ *spr_param++ =
+ hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
+ pos++;
+ }
+ if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
+ *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
+ *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ pos += 18;
+ }
+
+ return pos;
+}
+
+
+void hostapd_get_he_capab(struct hostapd_data *hapd,
+ const struct ieee80211_he_capabilities *he_cap,
+ struct ieee80211_he_capabilities *neg_he_cap,
+ size_t he_capab_len)
+{
+ if (!he_cap)
+ return;
+
+ if (he_capab_len > sizeof(*neg_he_cap))
+ he_capab_len = sizeof(*neg_he_cap);
+ /* TODO: mask out unsupported features */
+
+ os_memcpy(neg_he_cap, he_cap, he_capab_len);
+}
+
+
+static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
+ enum ieee80211_op_mode opmode)
+{
+ u16 sta_rx_mcs_set, ap_tx_mcs_set;
+ u8 mcs_count = 0;
+ const u16 *ap_mcs_set, *sta_mcs_set;
+ int i;
+
+ if (!hapd->iface->current_mode)
+ return 1;
+ ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs;
+ sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *)
+ sta_he_capab)->optional;
+
+ /*
+ * Disable HE capabilities for STAs for which there is not even a single
+ * allowed MCS in any supported number of streams, i.e., STA is
+ * advertising 3 (not supported) as HE MCS rates for all supported
+ * band/stream cases.
+ */
+ switch (hapd->iface->conf->he_oper_chwidth) {
+ case CHANWIDTH_80P80MHZ:
+ mcs_count = 3;
+ break;
+ case CHANWIDTH_160MHZ:
+ mcs_count = 2;
+ break;
+ default:
+ mcs_count = 1;
+ break;
+ }
+
+ for (i = 0; i < mcs_count; i++) {
+ int j;
+
+ /* AP Tx MCS map vs. STA Rx MCS map */
+ sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]);
+ ap_tx_mcs_set = WPA_GET_LE16((const u8 *)
+ &ap_mcs_set[(i * 2) + 1]);
+
+ for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
+ if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3)
+ continue;
+
+ if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3)
+ continue;
+
+ return 1;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "No matching HE MCS found between AP TX and STA RX");
+
+ return 0;
+}
+
+
+u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode, const u8 *he_capab,
+ size_t he_capab_len)
+{
+ if (!he_capab || !hapd->iconf->ieee80211ax ||
+ !check_valid_he_mcs(hapd, he_capab, opmode) ||
+ he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
+ sta->flags &= ~WLAN_STA_HE;
+ os_free(sta->he_capab);
+ sta->he_capab = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (!sta->he_capab) {
+ sta->he_capab =
+ os_zalloc(sizeof(struct ieee80211_he_capabilities));
+ if (!sta->he_capab)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_HE;
+ os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities));
+ os_memcpy(sta->he_capab, he_capab, he_capab_len);
+ sta->he_capab_len = he_capab_len;
+
+ return WLAN_STATUS_SUCCESS;
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 54ee080..269345f 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -242,7 +242,7 @@
return eid;
switch (iface->conf->vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
+ case CHANWIDTH_USE_HT:
if (iconf->secondary_channel == 0) {
/* Max Transmit Power count = 0 (20 MHz) */
tx_pwr_count = 0;
@@ -251,12 +251,12 @@
tx_pwr_count = 1;
}
break;
- case VHT_CHANWIDTH_80MHZ:
+ case CHANWIDTH_80MHZ:
/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
tx_pwr_count = 2;
break;
- case VHT_CHANWIDTH_80P80MHZ:
- case VHT_CHANWIDTH_160MHZ:
+ case CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_160MHZ:
/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
tx_pwr_count = 3;
break;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 870329a..d628641 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -34,6 +34,7 @@
/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */
#include "ieee802_11.h"
#include "ieee802_1x.h"
+#include "wpa_auth_kay.h"
#ifdef CONFIG_HS20
@@ -63,6 +64,10 @@
xhdr = (struct ieee802_1x_hdr *) buf;
xhdr->version = hapd->conf->eapol_version;
+#ifdef CONFIG_MACSEC
+ if (xhdr->version > 2 && hapd->conf->macsec_policy == 0)
+ xhdr->version = 2;
+#endif /* CONFIG_MACSEC */
xhdr->type = type;
xhdr->length = host_to_be16(datalen);
@@ -157,6 +162,21 @@
key->type = EAPOL_KEY_TYPE_RC4;
WPA_PUT_BE16(key->key_length, key_len);
wpa_get_ntp_timestamp(key->replay_counter);
+ if (os_memcmp(key->replay_counter,
+ hapd->last_1x_eapol_key_replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN) <= 0) {
+ /* NTP timestamp did not increment from last EAPOL-Key frame;
+ * use previously used value + 1 instead. */
+ inc_byte_array(hapd->last_1x_eapol_key_replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN);
+ os_memcpy(key->replay_counter,
+ hapd->last_1x_eapol_key_replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN);
+ } else {
+ os_memcpy(hapd->last_1x_eapol_key_replay_counter,
+ key->replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN);
+ }
if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
wpa_printf(MSG_ERROR, "Could not get random numbers");
@@ -197,6 +217,10 @@
/* This header is needed here for HMAC-MD5, but it will be regenerated
* in ieee802_1x_send() */
hdr->version = hapd->conf->eapol_version;
+#ifdef CONFIG_MACSEC
+ if (hdr->version > 2)
+ hdr->version = 2;
+#endif /* CONFIG_MACSEC */
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len);
hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
@@ -1104,6 +1128,13 @@
/* TODO: implement support for this; show data */
break;
+#ifdef CONFIG_MACSEC
+ case IEEE802_1X_TYPE_EAPOL_MKA:
+ wpa_printf(MSG_EXCESSIVE,
+ "EAPOL type %d will be handled by MKA", hdr->type);
+ break;
+#endif /* CONFIG_MACSEC */
+
default:
wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type");
sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
@@ -1236,6 +1267,7 @@
sta->eapol_sm->portValid = TRUE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
+ wpa_auth_set_ptk_rekey_timer(sta->wpa_sm);
return;
}
#endif /* CONFIG_FILS */
@@ -1384,6 +1416,8 @@
size_t shared_secret_len)
{
struct radius_ms_mppe_keys *keys;
+ u8 *buf;
+ size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
if (sm == NULL)
return;
@@ -1392,7 +1426,7 @@
shared_secret_len);
if (keys && keys->send && keys->recv) {
- size_t len = keys->send_len + keys->recv_len;
+ len = keys->send_len + keys->recv_len;
wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
keys->send, keys->send_len);
wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
@@ -1420,6 +1454,20 @@
os_free(keys->recv);
os_free(keys);
}
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len,
+ NULL) == 0) {
+ os_free(sm->eap_if->eapSessionId);
+ sm->eap_if->eapSessionId = os_memdup(buf, len);
+ if (sm->eap_if->eapSessionId) {
+ sm->eap_if->eapSessionIdLen = len;
+ wpa_hexdump(MSG_DEBUG, "EAP-Key Name",
+ sm->eap_if->eapSessionId,
+ sm->eap_if->eapSessionIdLen);
+ }
+ } else {
+ sm->eap_if->eapSessionIdLen = 0;
+ }
}
@@ -2323,6 +2371,8 @@
conf.eap_fast_prov = hapd->conf->eap_fast_prov;
conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
+ conf.eap_teap_auth = hapd->conf->eap_teap_auth;
+ conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
conf.tnc = hapd->conf->tnc;
conf.wps = hapd->wps;
@@ -2542,6 +2592,20 @@
}
+#ifdef CONFIG_MACSEC
+const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
+ size_t *len)
+{
+ *len = 0;
+ if (!sm || !sm->eap_if)
+ return NULL;
+
+ *len = sm->eap_if->eapSessionIdLen;
+ return sm->eap_if->eapSessionId;
+}
+#endif /* CONFIG_MACSEC */
+
+
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled)
{
@@ -2832,6 +2896,10 @@
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_MACSEC
+ ieee802_1x_notify_create_actor_hapd(hapd, sta);
+#endif /* CONFIG_MACSEC */
+
key = ieee802_1x_get_key(sta->eapol_sm, &len);
if (sta->session_timeout_set) {
os_get_reltime(&now);
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 9594661..d771ba5 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -39,6 +39,8 @@
int idx);
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
+const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
+ size_t *len);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled);
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 2b6f727..5415443 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -139,19 +139,21 @@
#ifdef NEED_AP_MLME
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
- int ht, int vht)
+ int ht, int vht, int he)
{
- if (!ht && !vht)
+ u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
+
+ if (!ht && !vht && !he)
return NR_CHAN_WIDTH_20;
if (!hapd->iconf->secondary_channel)
return NR_CHAN_WIDTH_20;
- if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
+ if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT)
return NR_CHAN_WIDTH_40;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ if (oper_chwidth == CHANWIDTH_80MHZ)
return NR_CHAN_WIDTH_80;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
+ if (oper_chwidth == CHANWIDTH_160MHZ)
return NR_CHAN_WIDTH_160;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
+ if (oper_chwidth == CHANWIDTH_80P80MHZ)
return NR_CHAN_WIDTH_80P80;
return NR_CHAN_WIDTH_20;
}
@@ -164,6 +166,7 @@
u16 capab = hostapd_own_capab_info(hapd);
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
+ int he = hapd->iconf->ieee80211ax;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
@@ -205,16 +208,18 @@
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
hapd->iconf->secondary_channel,
- hapd->iconf->vht_oper_chwidth,
+ hostapd_get_oper_chwidth(hapd->iconf),
&op_class, &channel) ==
NUM_HOSTAPD_MODES)
return;
- width = hostapd_get_nr_chan_width(hapd, ht, vht);
+ width = hostapd_get_nr_chan_width(hapd, ht, vht, he);
if (vht) {
- center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
+ center_freq1_idx = hostapd_get_oper_centr_freq_seg0_idx(
+ hapd->iconf);
if (width == NR_CHAN_WIDTH_80P80)
center_freq2_idx =
- hapd->iconf->vht_oper_centr_freq_seg1_idx;
+ hostapd_get_oper_centr_freq_seg1_idx(
+ hapd->iconf);
} else if (ht) {
ieee80211_freq_to_chan(hapd->iface->freq +
10 * hapd->iconf->secondary_channel,
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 71f9f21..51d7884 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -330,6 +330,7 @@
os_free(sta->ht_capabilities);
os_free(sta->vht_capabilities);
os_free(sta->vht_operation);
+ os_free(sta->he_capab);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@@ -670,6 +671,7 @@
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
+ int i;
sta = ap_get_sta(hapd, addr);
if (sta)
@@ -694,6 +696,15 @@
return NULL;
}
+ for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
+ if (!hapd->iface->basic_rates)
+ break;
+ if (hapd->iface->basic_rates[i] < 0)
+ break;
+ sta->supported_rates[i] = hapd->iface->basic_rates[i] / 5;
+ }
+ sta->supported_rates_len = i;
+
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - ap_max_inactivity)",
@@ -812,6 +823,8 @@
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(hapd, sta);
+ wpa_auth_sta_deinit(sta->wpa_sm);
+ sta->wpa_sm = NULL;
sta->disassoc_reason = reason;
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index ece0c60..5456a63 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -37,6 +37,7 @@
#define WLAN_STA_VENDOR_VHT BIT(21)
#define WLAN_STA_PENDING_FILS_ERP BIT(22)
#define WLAN_STA_MULTI_AP BIT(23)
+#define WLAN_STA_HE BIT(24)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -119,6 +120,7 @@
unsigned int agreed_to_steer:1;
unsigned int hs20_t_c_filtering:1;
unsigned int ft_over_ds:1;
+ unsigned int external_dh_updated:1;
u16 auth_alg;
@@ -166,6 +168,8 @@
struct ieee80211_vht_capabilities *vht_capabilities;
struct ieee80211_vht_operation *vht_operation;
u8 vht_opmode;
+ struct ieee80211_he_capabilities *he_capab;
+ size_t he_capab_len;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
@@ -275,6 +279,10 @@
u8 last_tk[WPA_TK_MAX_LEN];
size_t last_tk_len;
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_AIRTIME_POLICY
+ unsigned int airtime_weight;
+ struct os_reltime backlogged_until;
+#endif /* CONFIG_AIRTIME_POLICY */
};
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index 8054c5d..dc73493 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -20,6 +20,13 @@
#include "ap_drv_ops.h"
#include "wmm.h"
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
{
@@ -39,6 +46,62 @@
}
+static void
+wmm_set_regulatory_limit(const struct hostapd_wmm_ac_params *wmm_conf,
+ struct hostapd_wmm_ac_params *wmm,
+ const struct hostapd_wmm_rule *wmm_reg)
+{
+ int ac;
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ wmm[ac].cwmin = MAX(wmm_conf[ac].cwmin, wmm_reg[ac].min_cwmin);
+ wmm[ac].cwmax = MAX(wmm_conf[ac].cwmax, wmm_reg[ac].min_cwmax);
+ wmm[ac].aifs = MAX(wmm_conf[ac].aifs, wmm_reg[ac].min_aifs);
+ wmm[ac].txop_limit =
+ MIN(wmm_conf[ac].txop_limit, wmm_reg[ac].max_txop);
+ wmm[ac].admission_control_mandatory =
+ wmm_conf[ac].admission_control_mandatory;
+ }
+}
+
+
+/*
+ * Calculate WMM regulatory limit if any.
+ */
+static void wmm_calc_regulatory_limit(struct hostapd_data *hapd,
+ struct hostapd_wmm_ac_params *acp)
+{
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ int c;
+
+ os_memcpy(acp, hapd->iconf->wmm_ac_params,
+ sizeof(hapd->iconf->wmm_ac_params));
+
+ for (c = 0; mode && c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->freq != hapd->iface->freq)
+ continue;
+
+ if (chan->wmm_rules_valid)
+ wmm_set_regulatory_limit(hapd->iconf->wmm_ac_params,
+ acp, chan->wmm_rules);
+ break;
+ }
+
+ /*
+ * Check if we need to update set count. Since both were initialized to
+ * zero we can compare the whole array in one shot.
+ */
+ if (os_memcmp(acp, hapd->iface->prev_wmm,
+ sizeof(hapd->iconf->wmm_ac_params)) != 0) {
+ os_memcpy(hapd->iface->prev_wmm, acp,
+ sizeof(hapd->iconf->wmm_ac_params));
+ hapd->parameter_set_count++;
+ }
+}
+
+
/*
* Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
* Response frames.
@@ -48,10 +111,12 @@
u8 *pos = eid;
struct wmm_parameter_element *wmm =
(struct wmm_parameter_element *) (pos + 2);
+ struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM] = { 0 };
int e;
if (!hapd->conf->wmm_enabled)
return eid;
+ wmm_calc_regulatory_limit(hapd, wmmp);
eid[0] = WLAN_EID_VENDOR_SPECIFIC;
wmm->oui[0] = 0x00;
wmm->oui[1] = 0x50;
@@ -70,8 +135,7 @@
/* fill in a parameter set record for each AC */
for (e = 0; e < 4; e++) {
struct wmm_ac_parameter *ac = &wmm->ac[e];
- struct hostapd_wmm_ac_params *acp =
- &hapd->iconf->wmm_ac_params[e];
+ struct hostapd_wmm_ac_params *acp = &wmmp[e];
ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
acp->admission_control_mandatory,
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index e89a716..e1c0c2c 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -320,6 +320,19 @@
}
+void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm)
+{
+ if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) {
+ wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for "
+ MACSTR " (%d seconds)", MAC2STR(sm->addr),
+ sm->wpa_auth->conf.wpa_ptk_rekey);
+ eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+ eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0,
+ wpa_rekey_ptk, sm->wpa_auth, sm);
+ }
+}
+
+
static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
{
if (sm->pmksa == ctx)
@@ -921,6 +934,7 @@
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+ forced_memzero(&PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
return 0;
@@ -1394,6 +1408,8 @@
#endif /* CONFIG_SHA256 */
#endif /* CONFIG_SHA384 */
+ forced_memzero(data, sizeof(data));
+
return ret;
}
@@ -1735,6 +1751,8 @@
sm->pmk_len = 0;
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
sm->xxkey_len = 0;
+ os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+ sm->pmk_r1_len = 0;
#endif /* CONFIG_IEEE80211R_AP */
break;
case WPA_REAUTH:
@@ -1776,6 +1794,7 @@
/* Using FT protocol, not WPA auth state machine */
sm->ft_completed = 1;
+ wpa_auth_set_ptk_rekey_timer(sm);
return 0;
#else /* CONFIG_IEEE80211R_AP */
break;
@@ -2030,7 +2049,7 @@
sm->Disconnect = TRUE;
return;
}
- os_memset(msk, 0, sizeof(msk));
+ forced_memzero(msk, sizeof(msk));
sm->req_replay_counter_used = 0;
/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
@@ -2130,6 +2149,29 @@
wpa_printf(MSG_DEBUG,
"RSN: No KCK available to derive PMKID for message 1/4");
pmkid = NULL;
+#ifdef CONFIG_FILS
+ } else if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ if (sm->pmkid_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Message 1/4 PMKID from FILS/ERP",
+ sm->pmkid, PMKID_LEN);
+ os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
+ sm->pmkid, PMKID_LEN);
+ } else {
+ /* No PMKID available */
+ wpa_printf(MSG_DEBUG,
+ "RSN: No FILS/ERP PMKID available for message 1/4");
+ pmkid = NULL;
+ }
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R_AP
+ } else if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+ sm->ft_completed) {
+ wpa_printf(MSG_DEBUG,
+ "FT: No PMKID in message 1/4 when using FT protocol");
+ pmkid = NULL;
+ pmkid_len = 0;
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
} else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
if (sm->pmkid_set) {
@@ -2172,8 +2214,20 @@
size_t z_len = 0;
#ifdef CONFIG_IEEE80211R_AP
- if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+ if (sm->ft_completed) {
+ u8 ptk_name[WPA_PMK_NAME_LEN];
+
+ return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len,
+ sm->SNonce, sm->ANonce,
+ sm->addr, sm->wpa_auth->addr,
+ sm->pmk_r1_name,
+ ptk, ptk_name,
+ sm->wpa_key_mgmt,
+ sm->pairwise);
+ }
+ return wpa_auth_derive_ptk_ft(sm, ptk);
+ }
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_DPP2
@@ -2234,12 +2288,12 @@
wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
- os_memset(fils_ft, 0, sizeof(fils_ft));
+ forced_memzero(fils_ft, sizeof(fils_ft));
res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
sm->addr, sm->pmk_r1_name,
use_sha384);
- os_memset(pmk_r0, 0, PMK_LEN_MAX);
+ forced_memzero(pmk_r0, PMK_LEN_MAX);
if (res < 0)
return -1;
wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
@@ -2257,7 +2311,7 @@
sm->wpa_key_mgmt, sm->fils_key_auth_sta,
sm->fils_key_auth_ap,
&sm->fils_key_auth_len);
- os_memset(ick, 0, sizeof(ick));
+ forced_memzero(ick, sizeof(ick));
/* Store nonces for (Re)Association Request/Response frame processing */
os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
@@ -2559,7 +2613,7 @@
if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
wpa_printf(MSG_DEBUG,
"FILS: Not enough room for FILS elements");
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return -1;
}
@@ -2569,7 +2623,7 @@
if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
wpabuf_head(plain), wpabuf_len(plain),
5, aad, aad_len, pos) < 0) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return -1;
}
@@ -2577,7 +2631,7 @@
"FILS: Encrypted Association Response elements",
pos, AES_BLOCK_SIZE + wpabuf_len(plain));
current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
sm->fils_completed = 1;
@@ -2631,7 +2685,7 @@
* of GTK in the BSS.
*/
if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return NULL;
}
gtk = dummy_gtk;
@@ -2658,13 +2712,13 @@
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
wpa_printf(MSG_WARNING,
"FILS: Failed to get channel info for OCI element");
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return NULL;
}
pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return NULL;
}
}
@@ -2727,7 +2781,7 @@
wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
(unsigned int) wpabuf_len(plain));
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
sm->fils_completed = 1;
return pos;
}
@@ -2796,6 +2850,12 @@
pmk_len = sm->pmk_len;
}
+ if ((!pmk || !pmk_len) && sm->pmksa) {
+ wpa_printf(MSG_DEBUG, "WPA: Use PMK from PMKSA cache");
+ pmk = sm->pmksa->pmk;
+ pmk_len = sm->pmksa->pmk_len;
+ }
+
if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
break;
@@ -2973,6 +3033,7 @@
sm->MICVerified = TRUE;
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+ forced_memzero(&PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
}
@@ -3293,12 +3354,7 @@
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
sm->pairwise_set = TRUE;
- if (sm->wpa_auth->conf.wpa_ptk_rekey) {
- eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
- eloop_register_timeout(sm->wpa_auth->conf.
- wpa_ptk_rekey, 0, wpa_rekey_ptk,
- sm->wpa_auth, sm);
- }
+ wpa_auth_set_ptk_rekey_timer(sm);
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
@@ -4307,6 +4363,15 @@
sm->wpa_auth->conf.disable_pmksa_caching)
return -1;
+#ifdef CONFIG_IEEE80211R_AP
+ if (pmk_len >= 2 * PMK_LEN && wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+ wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
+ !wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
+ /* Cache MPMK/XXKey instead of initial part from MSK */
+ pmk = pmk + PMK_LEN;
+ pmk_len = PMK_LEN;
+ } else
+#endif /* CONFIG_IEEE80211R_AP */
if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
if (pmk_len > PMK_LEN_SUITE_B_192)
pmk_len = PMK_LEN_SUITE_B_192;
@@ -4314,6 +4379,7 @@
pmk_len = PMK_LEN;
}
+ wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len);
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
sm->PTK.kck, sm->PTK.kck_len,
sm->wpa_auth->addr, sm->addr, session_timeout,
@@ -4332,6 +4398,7 @@
if (wpa_auth == NULL)
return -1;
+ wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
NULL, 0,
wpa_auth->addr,
@@ -4349,6 +4416,7 @@
if (wpa_auth->conf.disable_pmksa_caching)
return -1;
+ wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, PMK_LEN);
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
NULL, 0,
wpa_auth->addr, addr, 0, NULL,
@@ -4373,6 +4441,7 @@
if (wpa_auth->conf.disable_pmksa_caching)
return -1;
+ wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN);
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
NULL, 0, wpa_auth->addr, addr, session_timeout,
NULL, akmp))
@@ -4846,6 +4915,16 @@
*fils_kek_len = sm->PTK.kek_len;
}
+
+void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *pmkid)
+{
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
+ sm->pmkid_set = 1;
+}
+
#endif /* CONFIG_FILS */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 484e1e5..a348bc2 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -470,9 +470,14 @@
void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
u8 *fils_anonce, u8 *fils_snonce,
u8 *fils_kek, size_t *fils_kek_len);
+void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *pmkid);
u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len);
+u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
+ u8 *pos, size_t max_len,
+ const u8 *req_ies, size_t req_ies_len);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
@@ -486,5 +491,6 @@
void (*cb)(void *ctx1, void *ctx2),
void *ctx1, void *ctx2);
int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
+void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm);
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index fdb7eba..696f8d5 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -25,6 +25,7 @@
#include "wmm.h"
#include "wpa_auth.h"
#include "wpa_auth_i.h"
+#include "pmksa_cache_auth.h"
#ifdef CONFIG_IEEE80211R_AP
@@ -2074,8 +2075,7 @@
}
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk)
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
{
u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
@@ -2095,8 +2095,16 @@
const u8 *identity, *radius_cui;
size_t identity_len, radius_cui_len;
int session_timeout;
+ const u8 *mpmk;
+ size_t mpmk_len;
- if (sm->xxkey_len == 0) {
+ if (sm->xxkey_len > 0) {
+ mpmk = sm->xxkey;
+ mpmk_len = sm->xxkey_len;
+ } else if (sm->pmksa) {
+ mpmk = sm->pmksa->pmk;
+ mpmk_len = sm->pmksa->pmk_len;
+ } else {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
"derivation");
return -1;
@@ -2113,7 +2121,7 @@
&radius_cui);
session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
- if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
+ if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
r0kh, r0kh_len, sm->addr,
pmk_r0, pmk_r0_name,
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
@@ -2218,6 +2226,7 @@
return NULL;
}
+ forced_memzero(keybuf, sizeof(keybuf));
*len = subelem_len;
return subelem;
}
@@ -2984,6 +2993,8 @@
wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, pmk_r1_len);
sm->pmk_r1_name_valid = 1;
os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
+ os_memcpy(sm->pmk_r1, pmk_r1, pmk_r1_len);
+ sm->pmk_r1_len = pmk_r1_len;
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -3089,8 +3100,9 @@
status = res;
wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
- " auth_transaction=%d status=%d",
- MAC2STR(sm->addr), auth_transaction + 1, status);
+ " auth_transaction=%d status=%u (%s)",
+ MAC2STR(sm->addr), auth_transaction + 1, status,
+ status2str(status));
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
resp_ies, resp_ies_len);
@@ -3448,8 +3460,9 @@
u8 *pos;
wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
- " CurrentAP=" MACSTR " status=%d",
- MAC2STR(sm->addr), MAC2STR(current_ap), status);
+ " CurrentAP=" MACSTR " status=%u (%s)",
+ MAC2STR(sm->addr), MAC2STR(current_ap), status,
+ status2str(status));
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
/* RRB - Forward action frame response to the Current AP */
@@ -3555,7 +3568,7 @@
pmk_r0->vlan, src_addr, type,
packet, packet_len);
- os_memset(pmk_r1, 0, sizeof(pmk_r1));
+ forced_memzero(pmk_r1, sizeof(pmk_r1));
return ret;
}
@@ -3881,10 +3894,7 @@
ret = 0;
out:
- if (plain) {
- os_memset(plain, 0, plain_len);
- os_free(plain);
- }
+ bin_clear_free(plain, plain_len);
return ret;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 45172c6..0800a87 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -53,6 +53,10 @@
wconf->rsn_pairwise = conf->rsn_pairwise;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
+#ifdef CONFIG_MACSEC
+ if (wconf->eapol_version > 2)
+ wconf->eapol_version = 2;
+#endif /* CONFIG_MACSEC */
wconf->wmm_enabled = conf->wmm_enabled;
wconf->wmm_uapsd = conf->wmm_uapsd;
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 3dcf77a..4babd0c 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -119,6 +119,8 @@
u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
* first 384 bits of MSK */
size_t xxkey_len;
+ u8 pmk_r1[PMK_LEN_MAX];
+ unsigned int pmk_r1_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
* Request */
u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
@@ -290,8 +292,7 @@
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len);
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk);
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 8580a5a..2e5c916 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1176,3 +1176,23 @@
return pos + res;
}
#endif /* CONFIG_OWE */
+
+
+#ifdef CONFIG_FILS
+u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
+ u8 *pos, size_t max_len,
+ const u8 *req_ies, size_t req_ies_len)
+{
+ int res;
+
+ if (!sm ||
+ sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA384))
+ return pos;
+
+ res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len, NULL);
+ if (res < 0)
+ return pos;
+ return pos + res;
+}
+#endif /* CONFIG_FILS */
diff --git a/src/ap/wpa_auth_kay.c b/src/ap/wpa_auth_kay.c
new file mode 100644
index 0000000..b6e4797
--- /dev/null
+++ b/src/ap/wpa_auth_kay.c
@@ -0,0 +1,523 @@
+/*
+ * IEEE 802.1X-2010 KaY Interface
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "pae/ieee802_1x_key.h"
+#include "pae/ieee802_1x_kay.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "wpa_auth_kay.h"
+#include "ieee802_1x.h"
+
+
+#define DEFAULT_KEY_LEN 16
+/* secure Connectivity Association Key Name (CKN) */
+#define DEFAULT_CKN_LEN 16
+
+
+static int hapd_macsec_init(void *priv, struct macsec_init_params *params)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->macsec_init)
+ return -1;
+ return hapd->driver->macsec_init(hapd->drv_priv, params);
+}
+
+
+static int hapd_macsec_deinit(void *priv)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->macsec_deinit)
+ return -1;
+ return hapd->driver->macsec_deinit(hapd->drv_priv);
+}
+
+
+static int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->macsec_get_capability)
+ return -1;
+ return hapd->driver->macsec_get_capability(hapd->drv_priv, cap);
+}
+
+
+static int hapd_enable_protect_frames(void *priv, Boolean enabled)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_protect_frames)
+ return -1;
+ return hapd->driver->enable_protect_frames(hapd->drv_priv, enabled);
+}
+
+
+static int hapd_enable_encrypt(void *priv, Boolean enabled)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_encrypt)
+ return -1;
+ return hapd->driver->enable_encrypt(hapd->drv_priv, enabled);
+}
+
+
+static int hapd_set_replay_protect(void *priv, Boolean enabled, u32 window)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->set_replay_protect)
+ return -1;
+ return hapd->driver->set_replay_protect(hapd->drv_priv, enabled,
+ window);
+}
+
+
+static int hapd_set_current_cipher_suite(void *priv, u64 cs)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->set_current_cipher_suite)
+ return -1;
+ return hapd->driver->set_current_cipher_suite(hapd->drv_priv, cs);
+}
+
+
+static int hapd_enable_controlled_port(void *priv, Boolean enabled)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_controlled_port)
+ return -1;
+ return hapd->driver->enable_controlled_port(hapd->drv_priv, enabled);
+}
+
+
+static int hapd_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->get_receive_lowest_pn)
+ return -1;
+ return hapd->driver->get_receive_lowest_pn(hapd->drv_priv, sa);
+}
+
+
+static int hapd_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->get_transmit_next_pn)
+ return -1;
+ return hapd->driver->get_transmit_next_pn(hapd->drv_priv, sa);
+}
+
+
+static int hapd_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->set_transmit_next_pn)
+ return -1;
+ return hapd->driver->set_transmit_next_pn(hapd->drv_priv, sa);
+}
+
+
+static unsigned int conf_offset_val(enum confidentiality_offset co)
+{
+ switch (co) {
+ case CONFIDENTIALITY_OFFSET_30:
+ return 30;
+ break;
+ case CONFIDENTIALITY_OFFSET_50:
+ return 50;
+ default:
+ return 0;
+ }
+}
+
+
+static int hapd_create_receive_sc(void *priv, struct receive_sc *sc,
+ enum validate_frames vf,
+ enum confidentiality_offset co)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->create_receive_sc)
+ return -1;
+ return hapd->driver->create_receive_sc(hapd->drv_priv, sc,
+ conf_offset_val(co), vf);
+}
+
+
+static int hapd_delete_receive_sc(void *priv, struct receive_sc *sc)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->delete_receive_sc)
+ return -1;
+ return hapd->driver->delete_receive_sc(hapd->drv_priv, sc);
+}
+
+
+static int hapd_create_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->create_receive_sa)
+ return -1;
+ return hapd->driver->create_receive_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_delete_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->delete_receive_sa)
+ return -1;
+ return hapd->driver->delete_receive_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_enable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_receive_sa)
+ return -1;
+ return hapd->driver->enable_receive_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_disable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->disable_receive_sa)
+ return -1;
+ return hapd->driver->disable_receive_sa(hapd->drv_priv, sa);
+}
+
+
+static int
+hapd_create_transmit_sc(void *priv, struct transmit_sc *sc,
+ enum confidentiality_offset co)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->create_transmit_sc)
+ return -1;
+ return hapd->driver->create_transmit_sc(hapd->drv_priv, sc,
+ conf_offset_val(co));
+}
+
+
+static int hapd_delete_transmit_sc(void *priv, struct transmit_sc *sc)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->delete_transmit_sc)
+ return -1;
+ return hapd->driver->delete_transmit_sc(hapd->drv_priv, sc);
+}
+
+
+static int hapd_create_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->create_transmit_sa)
+ return -1;
+ return hapd->driver->create_transmit_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_delete_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->delete_transmit_sa)
+ return -1;
+ return hapd->driver->delete_transmit_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_enable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->enable_transmit_sa)
+ return -1;
+ return hapd->driver->enable_transmit_sa(hapd->drv_priv, sa);
+}
+
+
+static int hapd_disable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct hostapd_data *hapd = priv;
+
+ if (!hapd->driver->disable_transmit_sa)
+ return -1;
+ return hapd->driver->disable_transmit_sa(hapd->drv_priv, sa);
+}
+
+
+int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct ieee802_1x_kay_ctx *kay_ctx;
+ struct ieee802_1x_kay *res = NULL;
+ enum macsec_policy policy;
+
+ ieee802_1x_dealloc_kay_sm_hapd(hapd);
+
+ if (!hapd->conf || hapd->conf->macsec_policy == 0)
+ return 0;
+
+ if (hapd->conf->macsec_policy == 1) {
+ if (hapd->conf->macsec_integ_only == 1)
+ policy = SHOULD_SECURE;
+ else
+ policy = SHOULD_ENCRYPT;
+ } else {
+ policy = DO_NOT_SECURE;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: if_name=%s", __func__, hapd->conf->iface);
+ kay_ctx = os_zalloc(sizeof(*kay_ctx));
+ if (!kay_ctx)
+ return -1;
+
+ kay_ctx->ctx = hapd;
+
+ kay_ctx->macsec_init = hapd_macsec_init;
+ kay_ctx->macsec_deinit = hapd_macsec_deinit;
+ kay_ctx->macsec_get_capability = hapd_macsec_get_capability;
+ kay_ctx->enable_protect_frames = hapd_enable_protect_frames;
+ kay_ctx->enable_encrypt = hapd_enable_encrypt;
+ kay_ctx->set_replay_protect = hapd_set_replay_protect;
+ kay_ctx->set_current_cipher_suite = hapd_set_current_cipher_suite;
+ kay_ctx->enable_controlled_port = hapd_enable_controlled_port;
+ kay_ctx->get_receive_lowest_pn = hapd_get_receive_lowest_pn;
+ kay_ctx->get_transmit_next_pn = hapd_get_transmit_next_pn;
+ kay_ctx->set_transmit_next_pn = hapd_set_transmit_next_pn;
+ kay_ctx->create_receive_sc = hapd_create_receive_sc;
+ kay_ctx->delete_receive_sc = hapd_delete_receive_sc;
+ kay_ctx->create_receive_sa = hapd_create_receive_sa;
+ kay_ctx->delete_receive_sa = hapd_delete_receive_sa;
+ kay_ctx->enable_receive_sa = hapd_enable_receive_sa;
+ kay_ctx->disable_receive_sa = hapd_disable_receive_sa;
+ kay_ctx->create_transmit_sc = hapd_create_transmit_sc;
+ kay_ctx->delete_transmit_sc = hapd_delete_transmit_sc;
+ kay_ctx->create_transmit_sa = hapd_create_transmit_sa;
+ kay_ctx->delete_transmit_sa = hapd_delete_transmit_sa;
+ kay_ctx->enable_transmit_sa = hapd_enable_transmit_sa;
+ kay_ctx->disable_transmit_sa = hapd_disable_transmit_sa;
+
+ res = ieee802_1x_kay_init(kay_ctx, policy,
+ hapd->conf->macsec_replay_protect,
+ hapd->conf->macsec_replay_window,
+ hapd->conf->macsec_port,
+ hapd->conf->mka_priority, hapd->conf->iface,
+ hapd->own_addr);
+ /* ieee802_1x_kay_init() frees kay_ctx on failure */
+ if (!res)
+ return -1;
+
+ hapd->kay = res;
+
+ return 0;
+}
+
+
+void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
+{
+ if (!hapd->kay)
+ return;
+
+ ieee802_1x_kay_deinit(hapd->kay);
+ hapd->kay = NULL;
+}
+
+
+static int ieee802_1x_auth_get_session_id(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *sid,
+ size_t *len)
+{
+ const u8 *session_id;
+ size_t id_len, need_len;
+
+ session_id = ieee802_1x_get_session_id(sta->eapol_sm, &id_len);
+ if (!session_id) {
+ wpa_printf(MSG_DEBUG,
+ "MACsec: Failed to get SessionID from EAPOL state machines");
+ return -1;
+ }
+
+ need_len = 1 + 2 * 32 /* random size */;
+ if (need_len > id_len) {
+ wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
+ return -1;
+ }
+
+ os_memcpy(sid, session_id, need_len);
+ *len = need_len;
+
+ return 0;
+}
+
+
+static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *msk, size_t *len)
+{
+ const u8 *key;
+ size_t keylen;
+
+ if (!sta->eapol_sm)
+ return -1;
+
+ key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
+ if (key == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MACsec: Failed to get MSK from EAPOL state machines");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "MACsec: Successfully fetched key (len=%lu)",
+ (unsigned long) keylen);
+ wpa_hexdump_key(MSG_DEBUG, "MSK: ", key, keylen);
+
+ if (keylen > *len)
+ keylen = *len;
+ os_memcpy(msk, key, keylen);
+ *len = keylen;
+
+ return 0;
+}
+
+
+void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ u8 *sid;
+ size_t sid_len = 128;
+ struct mka_key_name *ckn;
+ struct mka_key *cak;
+ struct mka_key *msk;
+ void *res = NULL;
+
+ if (!hapd->kay || hapd->kay->policy == DO_NOT_SECURE)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: External notification - Create MKA for "
+ MACSTR, MAC2STR(sta->addr));
+
+ msk = os_zalloc(sizeof(*msk));
+ sid = os_zalloc(sid_len);
+ ckn = os_zalloc(sizeof(*ckn));
+ cak = os_zalloc(sizeof(*cak));
+ if (!msk || !sid || !ckn || !cak)
+ goto fail;
+
+ msk->len = DEFAULT_KEY_LEN;
+ if (ieee802_1x_auth_get_msk(hapd, sta, msk->key, &msk->len)) {
+ wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK");
+ goto fail;
+ }
+
+ if (ieee802_1x_auth_get_session_id(hapd, sta, sid, &sid_len))
+ {
+ wpa_printf(MSG_ERROR,
+ "IEEE 802.1X: Could not get EAP Session Id");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "own_addr", hapd->own_addr, ETH_ALEN);
+ wpa_hexdump(MSG_DEBUG, "sta_addr", sta->addr, ETH_ALEN);
+
+ /* Derive CAK from MSK */
+ cak->len = DEFAULT_KEY_LEN;
+ if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, hapd->own_addr,
+ sta->addr, cak->key, cak->len)) {
+ wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CAK failed");
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len);
+
+ /* Derive CKN from MSK */
+ ckn->len = DEFAULT_CKN_LEN;
+ if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, hapd->own_addr,
+ sta->addr, sid, sid_len, ckn->name)) {
+ wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CKN failed");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
+
+ res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
+ TRUE);
+
+fail:
+ bin_clear_free(msk, sizeof(*msk));
+ os_free(sid);
+ os_free(ckn);
+ bin_clear_free(cak, sizeof(*cak));
+
+ return res;
+}
+
+
+void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct mka_key *cak;
+ struct mka_key_name *ckn;
+ void *res = NULL;
+
+ if ((hapd->conf->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
+ goto end;
+
+ ckn = os_zalloc(sizeof(*ckn));
+ if (!ckn)
+ goto end;
+
+ cak = os_zalloc(sizeof(*cak));
+ if (!cak)
+ goto free_ckn;
+
+ if (ieee802_1x_alloc_kay_sm_hapd(hapd, sta) < 0 || !hapd->kay)
+ goto free_cak;
+
+ if (hapd->kay->policy == DO_NOT_SECURE)
+ goto dealloc;
+
+ cak->len = hapd->conf->mka_cak_len;
+ os_memcpy(cak->key, hapd->conf->mka_cak, cak->len);
+
+ ckn->len = hapd->conf->mka_ckn_len;;
+ os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len);
+
+ res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, TRUE);
+ if (res)
+ goto free_cak;
+
+dealloc:
+ /* Failed to create MKA */
+ ieee802_1x_dealloc_kay_sm_hapd(hapd);
+free_cak:
+ os_free(cak);
+free_ckn:
+ os_free(ckn);
+end:
+ return res;
+}
diff --git a/src/ap/wpa_auth_kay.h b/src/ap/wpa_auth_kay.h
new file mode 100644
index 0000000..0dd7e41
--- /dev/null
+++ b/src/ap/wpa_auth_kay.h
@@ -0,0 +1,51 @@
+/*
+ * IEEE 802.1X-2010 KaY Interface
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_KAY_H
+#define WPA_AUTH_KAY_H
+
+#ifdef CONFIG_MACSEC
+
+int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta);
+void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta);
+void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd);
+
+void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta);
+
+#else /* CONFIG_MACSEC */
+
+static inline int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return 0;
+}
+
+static inline void *
+ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return NULL;
+}
+
+static inline void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
+{
+}
+
+static inline void *
+ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_MACSEC */
+
+#endif /* WPA_AUTH_KAY_H */