aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile4
-rw-r--r--src/ap/Makefile15
-rw-r--r--src/ap/acs.c299
-rw-r--r--src/ap/airtime_policy.c8
-rw-r--r--src/ap/ap_config.c153
-rw-r--r--src/ap/ap_config.h61
-rw-r--r--src/ap/ap_drv_ops.c135
-rw-r--r--src/ap/ap_drv_ops.h21
-rw-r--r--src/ap/ap_list.c4
-rw-r--r--src/ap/beacon.c289
-rw-r--r--src/ap/ctrl_iface_ap.c77
-rw-r--r--src/ap/dfs.c277
-rw-r--r--src/ap/dfs.h3
-rw-r--r--src/ap/dhcp_snoop.c8
-rw-r--r--src/ap/dpp_hostapd.c843
-rw-r--r--src/ap/dpp_hostapd.h11
-rw-r--r--src/ap/drv_callbacks.c302
-rw-r--r--src/ap/fils_hlp.c36
-rw-r--r--src/ap/gas_serv.c10
-rw-r--r--src/ap/hostapd.c181
-rw-r--r--src/ap/hostapd.h33
-rw-r--r--src/ap/hw_features.c222
-rw-r--r--src/ap/hw_features.h10
-rw-r--r--src/ap/ieee802_11.c707
-rw-r--r--src/ap/ieee802_11.h23
-rw-r--r--src/ap/ieee802_11_auth.c172
-rw-r--r--src/ap/ieee802_11_auth.h17
-rw-r--r--src/ap/ieee802_11_he.c95
-rw-r--r--src/ap/ieee802_11_ht.c26
-rw-r--r--src/ap/ieee802_11_shared.c128
-rw-r--r--src/ap/ieee802_11_vht.c57
-rw-r--r--src/ap/ieee802_1x.c114
-rw-r--r--src/ap/ieee802_1x.h7
-rw-r--r--src/ap/neighbor_db.c56
-rw-r--r--src/ap/neighbor_db.h1
-rw-r--r--src/ap/pmksa_cache_auth.c5
-rw-r--r--src/ap/preauth_auth.c2
-rw-r--r--src/ap/sta_info.c68
-rw-r--r--src/ap/sta_info.h6
-rw-r--r--src/ap/utils.c4
-rw-r--r--src/ap/vlan_init.c5
-rw-r--r--src/ap/wmm.c14
-rw-r--r--src/ap/wnm_ap.c78
-rw-r--r--src/ap/wpa_auth.c1258
-rw-r--r--src/ap/wpa_auth.h72
-rw-r--r--src/ap/wpa_auth_ft.c346
-rw-r--r--src/ap/wpa_auth_glue.c272
-rw-r--r--src/ap/wpa_auth_i.h66
-rw-r--r--src/ap/wpa_auth_ie.c87
-rw-r--r--src/ap/wpa_auth_kay.c12
-rw-r--r--src/ap/wps_hostapd.c119
-rw-r--r--src/build.rules109
-rw-r--r--src/common/Makefile15
-rw-r--r--src/common/common_module_tests.c209
-rw-r--r--src/common/defs.h74
-rw-r--r--src/common/dhcp.h2
-rw-r--r--src/common/dpp.c8420
-rw-r--r--src/common/dpp.h195
-rw-r--r--src/common/dpp_auth.c1976
-rw-r--r--src/common/dpp_backup.c1292
-rw-r--r--src/common/dpp_crypto.c3328
-rw-r--r--src/common/dpp_i.h160
-rw-r--r--src/common/dpp_pkex.c1324
-rw-r--r--src/common/dpp_reconfig.c958
-rw-r--r--src/common/dpp_tcp.c1794
-rw-r--r--src/common/gas_server.c125
-rw-r--r--src/common/gas_server.h8
-rw-r--r--src/common/hw_features_common.c332
-rw-r--r--src/common/hw_features_common.h20
-rw-r--r--src/common/ieee802_11_common.c586
-rw-r--r--src/common/ieee802_11_common.h50
-rw-r--r--src/common/ieee802_11_defs.h110
-rw-r--r--src/common/ocv.c39
-rw-r--r--src/common/ocv.h13
-rw-r--r--src/common/privsep_commands.h1
-rw-r--r--src/common/qca-vendor.h2187
-rw-r--r--src/common/sae.c273
-rw-r--r--src/common/sae.h72
-rw-r--r--src/common/sae_pk.c884
-rw-r--r--src/common/wpa_common.c138
-rw-r--r--src/common/wpa_common.h47
-rw-r--r--src/common/wpa_ctrl.c5
-rw-r--r--src/common/wpa_ctrl.h32
-rw-r--r--src/crypto/.gitignore1
-rw-r--r--src/crypto/Makefile19
-rw-r--r--src/crypto/crypto.h26
-rw-r--r--src/crypto/crypto_module_tests.c150
-rw-r--r--src/crypto/crypto_openssl.c196
-rw-r--r--src/crypto/crypto_wolfssl.c27
-rw-r--r--src/crypto/sha256.c6
-rw-r--r--src/crypto/sha384.c6
-rw-r--r--src/crypto/sha512.c6
-rw-r--r--src/crypto/tls.h14
-rw-r--r--src/crypto/tls_openssl.c213
-rw-r--r--src/crypto/tls_wolfssl.c51
-rw-r--r--src/drivers/.gitignore2
-rw-r--r--src/drivers/driver.h508
-rw-r--r--src/drivers/driver_atheros.c15
-rw-r--r--src/drivers/driver_bsd.c482
-rw-r--r--src/drivers/driver_common.c21
-rw-r--r--src/drivers/driver_hostap.c24
-rw-r--r--src/drivers/driver_macsec_linux.c87
-rw-r--r--src/drivers/driver_macsec_qca.c34
-rw-r--r--src/drivers/driver_ndis.c20
-rw-r--r--src/drivers/driver_nl80211.c1500
-rw-r--r--src/drivers/driver_nl80211.h46
-rw-r--r--src/drivers/driver_nl80211_android.c4
-rw-r--r--src/drivers/driver_nl80211_capa.c513
-rw-r--r--src/drivers/driver_nl80211_event.c274
-rw-r--r--src/drivers/driver_nl80211_monitor.c3
-rw-r--r--src/drivers/driver_nl80211_scan.c51
-rw-r--r--src/drivers/driver_none.c8
-rw-r--r--src/drivers/driver_openbsd.c10
-rw-r--r--src/drivers/driver_privsep.c18
-rw-r--r--src/drivers/driver_wext.c91
-rw-r--r--src/drivers/driver_wext.h4
-rw-r--r--src/drivers/drivers.mak18
-rw-r--r--src/drivers/drivers.mk21
-rw-r--r--src/drivers/nl80211_copy.h409
-rw-r--r--src/eap_common/Makefile15
-rw-r--r--src/eap_common/eap_sim_common.c4
-rw-r--r--src/eap_peer/.gitignore1
-rw-r--r--src/eap_peer/Makefile22
-rw-r--r--src/eap_peer/eap.c108
-rw-r--r--src/eap_peer/eap.h13
-rw-r--r--src/eap_peer/eap_aka.c14
-rw-r--r--src/eap_peer/eap_eke.c16
-rw-r--r--src/eap_peer/eap_fast.c4
-rw-r--r--src/eap_peer/eap_gpsk.c14
-rw-r--r--src/eap_peer/eap_gtc.c8
-rw-r--r--src/eap_peer/eap_i.h34
-rw-r--r--src/eap_peer/eap_ikev2.c28
-rw-r--r--src/eap_peer/eap_leap.c44
-rw-r--r--src/eap_peer/eap_md5.c12
-rw-r--r--src/eap_peer/eap_mschapv2.c32
-rw-r--r--src/eap_peer/eap_otp.c8
-rw-r--r--src/eap_peer/eap_pax.c50
-rw-r--r--src/eap_peer/eap_peap.c16
-rw-r--r--src/eap_peer/eap_psk.c22
-rw-r--r--src/eap_peer/eap_pwd.c22
-rw-r--r--src/eap_peer/eap_sake.c26
-rw-r--r--src/eap_peer/eap_sim.c44
-rw-r--r--src/eap_peer/eap_teap.c13
-rw-r--r--src/eap_peer/eap_tls.c8
-rw-r--r--src/eap_peer/eap_tls_common.c18
-rw-r--r--src/eap_peer/eap_tnc.c32
-rw-r--r--src/eap_peer/eap_ttls.c6
-rw-r--r--src/eap_peer/eap_vendor_test.c16
-rw-r--r--src/eap_peer/eap_wsc.c24
-rw-r--r--src/eap_peer/tncc.c5
-rw-r--r--src/eap_server/Makefile15
-rw-r--r--src/eap_server/eap.h34
-rw-r--r--src/eap_server/eap_i.h23
-rw-r--r--src/eap_server/eap_server.c130
-rw-r--r--src/eap_server/eap_server_aka.c28
-rw-r--r--src/eap_server/eap_server_eke.c20
-rw-r--r--src/eap_server/eap_server_fast.c12
-rw-r--r--src/eap_server/eap_server_gpsk.c16
-rw-r--r--src/eap_server/eap_server_gtc.c12
-rw-r--r--src/eap_server/eap_server_identity.c14
-rw-r--r--src/eap_server/eap_server_ikev2.c12
-rw-r--r--src/eap_server/eap_server_md5.c14
-rw-r--r--src/eap_server/eap_server_mschapv2.c18
-rw-r--r--src/eap_server/eap_server_pax.c32
-rw-r--r--src/eap_server/eap_server_peap.c12
-rw-r--r--src/eap_server/eap_server_psk.c18
-rw-r--r--src/eap_server/eap_server_pwd.c18
-rw-r--r--src/eap_server/eap_server_sake.c24
-rw-r--r--src/eap_server/eap_server_sim.c30
-rw-r--r--src/eap_server/eap_server_teap.c36
-rw-r--r--src/eap_server/eap_server_tls.c12
-rw-r--r--src/eap_server/eap_server_tnc.c20
-rw-r--r--src/eap_server/eap_server_ttls.c12
-rw-r--r--src/eap_server/eap_server_vendor_test.c12
-rw-r--r--src/eap_server/eap_server_wsc.c14
-rw-r--r--src/eap_server/tncs.c5
-rw-r--r--src/eapol_auth/Makefile16
-rw-r--r--src/eapol_auth/eapol_auth_sm.c117
-rw-r--r--src/eapol_auth/eapol_auth_sm_i.h40
-rw-r--r--src/eapol_supp/Makefile15
-rw-r--r--src/eapol_supp/eapol_supp_sm.c218
-rw-r--r--src/eapol_supp/eapol_supp_sm.h29
-rw-r--r--src/fst/fst.c16
-rw-r--r--src/fst/fst.h16
-rw-r--r--src/fst/fst_ctrl_aux.h4
-rw-r--r--src/fst/fst_ctrl_iface.c48
-rw-r--r--src/fst/fst_ctrl_iface.h2
-rw-r--r--src/fst/fst_group.c10
-rw-r--r--src/fst/fst_group.h4
-rw-r--r--src/fst/fst_iface.c8
-rw-r--r--src/fst/fst_iface.h8
-rw-r--r--src/fst/fst_session.c96
-rw-r--r--src/fst/fst_session.h12
-rw-r--r--src/l2_packet/Makefile15
-rw-r--r--src/l2_packet/l2_packet.h4
-rw-r--r--src/l2_packet/l2_packet_freebsd.c2
-rw-r--r--src/l2_packet/l2_packet_linux.c11
-rw-r--r--src/l2_packet/l2_packet_ndis.c3
-rw-r--r--src/l2_packet/l2_packet_none.c4
-rw-r--r--src/l2_packet/l2_packet_pcap.c4
-rw-r--r--src/l2_packet/l2_packet_privsep.c3
-rw-r--r--src/l2_packet/l2_packet_winpcap.c3
-rw-r--r--src/lib.rules38
-rw-r--r--src/objs.mk3
-rw-r--r--src/p2p/Makefile15
-rw-r--r--src/p2p/p2p.c18
-rw-r--r--src/p2p/p2p.h4
-rw-r--r--src/p2p/p2p_go_neg.c9
-rw-r--r--src/pae/ieee802_1x_cp.c144
-rw-r--r--src/pae/ieee802_1x_cp.h10
-rw-r--r--src/pae/ieee802_1x_kay.c389
-rw-r--r--src/pae/ieee802_1x_kay.h68
-rw-r--r--src/pae/ieee802_1x_kay_i.h40
-rw-r--r--src/pae/ieee802_1x_secy_ops.c22
-rw-r--r--src/pae/ieee802_1x_secy_ops.h8
-rw-r--r--src/radius/.gitignore1
-rw-r--r--src/radius/Makefile16
-rw-r--r--src/radius/radius.c2
-rw-r--r--src/radius/radius_client.c6
-rw-r--r--src/radius/radius_server.c14
-rw-r--r--src/rsn_supp/Makefile15
-rw-r--r--src/rsn_supp/pmksa_cache.c43
-rw-r--r--src/rsn_supp/pmksa_cache.h1
-rw-r--r--src/rsn_supp/preauth.c24
-rw-r--r--src/rsn_supp/tdls.c12
-rw-r--r--src/rsn_supp/wpa.c437
-rw-r--r--src/rsn_supp/wpa.h33
-rw-r--r--src/rsn_supp/wpa_ft.c248
-rw-r--r--src/rsn_supp/wpa_i.h39
-rw-r--r--src/rsn_supp/wpa_ie.c36
-rw-r--r--src/rsn_supp/wpa_ie.h1
-rw-r--r--src/tls/.gitignore1
-rw-r--r--src/tls/Makefile17
-rw-r--r--src/tls/asn1.c313
-rw-r--r--src/tls/asn1.h39
-rw-r--r--src/tls/pkcs1.c4
-rw-r--r--src/tls/rsa.c2
-rw-r--r--src/tls/tlsv1_client_read.c10
-rw-r--r--src/tls/tlsv1_cred.c8
-rw-r--r--src/tls/x509v3.c136
-rw-r--r--src/tls/x509v3.h7
-rw-r--r--src/utils/.gitignore1
-rw-r--r--src/utils/Makefile16
-rw-r--r--src/utils/base64.c59
-rw-r--r--src/utils/base64.h13
-rw-r--r--src/utils/browser-android.c2
-rw-r--r--src/utils/browser-system.c2
-rw-r--r--src/utils/browser-wpadebug.c2
-rw-r--r--src/utils/browser.c210
-rw-r--r--src/utils/browser.h4
-rw-r--r--src/utils/common.c38
-rw-r--r--src/utils/common.h5
-rw-r--r--src/utils/eloop.c47
-rw-r--r--src/utils/eloop_win.c8
-rw-r--r--src/utils/http-utils.h6
-rw-r--r--src/utils/includes.h1
-rw-r--r--src/utils/json.c122
-rw-r--r--src/utils/json.h15
-rw-r--r--src/utils/os_unix.c5
-rw-r--r--src/utils/state_machine.h8
-rw-r--r--src/utils/trace.c11
-rw-r--r--src/utils/utils_module_tests.c39
-rw-r--r--src/utils/wpa_debug.c147
-rw-r--r--src/utils/wpa_debug.h2
-rw-r--r--src/utils/wpabuf.h15
-rw-r--r--src/utils/xml_libxml2.c2
-rw-r--r--src/wps/Makefile15
-rw-r--r--src/wps/upnp_xml.c2
-rw-r--r--src/wps/wps.h14
-rw-r--r--src/wps/wps_attr_build.c6
-rw-r--r--src/wps/wps_dev_attr.c17
-rw-r--r--src/wps/wps_dev_attr.h1
-rw-r--r--src/wps/wps_enrollee.c11
-rw-r--r--src/wps/wps_er.c6
-rw-r--r--src/wps/wps_registrar.c68
-rw-r--r--src/wps/wps_upnp.c70
-rw-r--r--src/wps/wps_upnp_ap.c4
-rw-r--r--src/wps/wps_upnp_event.c34
-rw-r--r--src/wps/wps_upnp_i.h12
-rw-r--r--src/wps/wps_upnp_web.c4
280 files changed, 28760 insertions, 12972 deletions
diff --git a/src/Makefile b/src/Makefile
index c9e84c1..6eb7f2a 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,8 +5,8 @@ all:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
clean:
- for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
- rm -f *~
+ $(Q)for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
+ $(Q)rm -f *~
install:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 54e48a0..a1e9b7c 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -1,13 +1,3 @@
-all: libap.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libap.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DHOSTAPD
CFLAGS += -DNEED_AP_MLME
CFLAGS += -DCONFIG_ETH_P_OUI
@@ -67,7 +57,4 @@ LIB_OBJS= \
wps_hostapd.o \
x_snoop.o
-libap.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/ap/acs.c b/src/ap/acs.c
index f12539f..aa2ceb0 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -261,13 +261,13 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
}
-void acs_cleanup(struct hostapd_iface *iface)
+static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
acs_clean_chan_surveys(chan);
@@ -276,6 +276,15 @@ void acs_cleanup(struct hostapd_iface *iface)
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
chan->min_nf = 0;
}
+}
+
+
+void acs_cleanup(struct hostapd_iface *iface)
+{
+ int i;
+
+ for (i = 0; i < iface->num_hw_features; i++)
+ acs_cleanup_mode(&iface->hw_features[i]);
iface->chans_surveyed = 0;
iface->acs_num_completed_scans = 0;
@@ -453,21 +462,35 @@ static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
}
-static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+static int acs_surveys_are_sufficient_mode(struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- int valid = 0;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
acs_survey_list_is_sufficient(chan))
- valid++;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode) &&
+ acs_surveys_are_sufficient_mode(mode))
+ return 1;
}
- /* We need at least survey data for one channel */
- return !!valid;
+ return 0;
}
@@ -489,14 +512,25 @@ static int is_in_chanlist(struct hostapd_iface *iface,
}
-static void acs_survey_all_chans_intereference_factor(
- struct hostapd_iface *iface)
+static int is_in_freqlist(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan)
+{
+ if (!iface->conf->acs_freq_list.num)
+ return 1;
+
+ return freq_range_list_includes(&iface->conf->acs_freq_list,
+ chan->freq);
+}
+
+
+static void acs_survey_mode_interference_factor(
+ struct hostapd_iface *iface, struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (!acs_usable_chan(chan))
continue;
@@ -504,6 +538,9 @@ static void acs_survey_all_chans_intereference_factor(
if (!is_in_chanlist(iface, chan))
continue;
+ if (!is_in_freqlist(iface, chan))
+ continue;
+
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
chan->chan, chan->freq);
@@ -515,14 +552,28 @@ static void acs_survey_all_chans_intereference_factor(
}
-static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
- int freq)
+static void acs_survey_all_chans_interference_factor(
+ struct hostapd_iface *iface)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ acs_survey_mode_interference_factor(iface, mode);
+ }
+}
+
+
+static struct hostapd_channel_data *
+acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq)
{
struct hostapd_channel_data *chan;
int i;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
@@ -535,6 +586,26 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
}
+static struct hostapd_channel_data *
+acs_find_chan(struct hostapd_iface *iface, int freq)
+{
+ int i;
+ struct hostapd_hw_modes *mode;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode)) {
+ chan = acs_find_chan_mode(mode, freq);
+ if (chan)
+ return chan;
+ }
+ }
+
+ return NULL;
+}
+
+
static int is_24ghz_mode(enum hostapd_hw_mode mode)
{
return mode == HOSTAPD_MODE_IEEE80211B ||
@@ -565,58 +636,24 @@ static int is_common_24ghz_chan(int chan)
#define ACS_24GHZ_PREFER_1_6_11 0.8
#endif /* ACS_24GHZ_PREFER_1_6_11 */
-/*
- * At this point it's assumed chan->interface_factor has been computed.
- * This function should be reusable regardless of interference computation
- * option (survey, BSS, spectral, ...). chan->interference factor must be
- * summable (i.e., must be always greater than zero).
- */
-static struct hostapd_channel_data *
-acs_find_ideal_chan(struct hostapd_iface *iface)
+static void
+acs_find_ideal_chan_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode,
+ int n_chans, u32 bw,
+ struct hostapd_channel_data **rand_chan,
+ struct hostapd_channel_data **ideal_chan,
+ long double *ideal_factor)
{
- struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
- *rand_chan = NULL;
- long double factor, ideal_factor = 0;
+ struct hostapd_channel_data *chan, *adj_chan = NULL;
+ long double factor;
int i, j;
- int n_chans = 1;
- u32 bw;
unsigned int k;
- /* TODO: HT40- support */
-
- if (iface->conf->ieee80211n &&
- iface->conf->secondary_channel == -1) {
- wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
- return NULL;
- }
-
- if (iface->conf->ieee80211n &&
- iface->conf->secondary_channel)
- n_chans = 2;
-
- if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
- switch (hostapd_get_oper_chwidth(iface->conf)) {
- case CHANWIDTH_80MHZ:
- n_chans = 4;
- break;
- case CHANWIDTH_160MHZ:
- n_chans = 8;
- break;
- }
- }
-
- bw = num_chan_to_bw(n_chans);
-
- /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
-
- wpa_printf(MSG_DEBUG,
- "ACS: Survey analysis for selected bandwidth %d MHz", bw);
-
- for (i = 0; i < iface->current_mode->num_channels; i++) {
+ for (i = 0; i < mode->num_channels; i++) {
double total_weight;
struct acs_bias *bias, tmp_bias;
- chan = &iface->current_mode->channels[i];
+ chan = &mode->channels[i];
/* Since in the current ACS implementation the first channel is
* always a primary channel, skip channels not available as
@@ -628,6 +665,9 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
if (!is_in_chanlist(iface, chan))
continue;
+ if (!is_in_freqlist(iface, chan))
+ continue;
+
if (!chan_bw_allowed(chan, bw, 1, 1)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: BW %u is not supported",
@@ -637,7 +677,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
!acs_usable_ht40_chan(chan)) {
@@ -646,7 +686,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
continue;
}
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_80MHZ &&
@@ -698,7 +738,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
* channel interference factor. */
- if (is_24ghz_mode(iface->current_mode->mode)) {
+ if (is_24ghz_mode(mode->mode)) {
for (j = 0; j < n_chans; j++) {
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 5);
@@ -744,7 +784,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
break;
bias = NULL;
}
- } else if (is_24ghz_mode(iface->current_mode->mode) &&
+ } else if (is_24ghz_mode(mode->mode) &&
is_common_24ghz_chan(chan->chan)) {
tmp_bias.channel = chan->chan;
tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
@@ -763,14 +803,71 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
}
if (acs_usable_chan(chan) &&
- (!ideal_chan || factor < ideal_factor)) {
- ideal_factor = factor;
- ideal_chan = chan;
+ (!*ideal_chan || factor < *ideal_factor)) {
+ *ideal_factor = factor;
+ *ideal_chan = chan;
}
/* This channel would at least be usable */
- if (!rand_chan)
- rand_chan = chan;
+ if (!(*rand_chan))
+ *rand_chan = chan;
+ }
+}
+
+
+/*
+ * At this point it's assumed chan->interference_factor has been computed.
+ * This function should be reusable regardless of interference computation
+ * option (survey, BSS, spectral, ...). chan->interference factor must be
+ * summable (i.e., must be always greater than zero).
+ */
+static struct hostapd_channel_data *
+acs_find_ideal_chan(struct hostapd_iface *iface)
+{
+ struct hostapd_channel_data *ideal_chan = NULL,
+ *rand_chan = NULL;
+ long double ideal_factor = 0;
+ int i;
+ int n_chans = 1;
+ u32 bw;
+ struct hostapd_hw_modes *mode;
+
+ /* TODO: HT40- support */
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel == -1) {
+ wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
+ return NULL;
+ }
+
+ if (iface->conf->ieee80211n &&
+ iface->conf->secondary_channel)
+ n_chans = 2;
+
+ if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+ switch (hostapd_get_oper_chwidth(iface->conf)) {
+ case CHANWIDTH_80MHZ:
+ n_chans = 4;
+ break;
+ case CHANWIDTH_160MHZ:
+ n_chans = 8;
+ break;
+ }
+ }
+
+ bw = num_chan_to_bw(n_chans);
+
+ /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
+
+ wpa_printf(MSG_DEBUG,
+ "ACS: Survey analysis for selected bandwidth %d MHz", bw);
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ acs_find_ideal_chan_mode(iface, mode, n_chans, bw,
+ &rand_chan, &ideal_chan,
+ &ideal_factor);
}
if (ideal_chan) {
@@ -826,7 +923,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface)
return -1;
}
- acs_survey_all_chans_intereference_factor(iface);
+ acs_survey_all_chans_interference_factor(iface);
return 0;
}
@@ -862,6 +959,7 @@ static void acs_study(struct hostapd_iface *iface)
}
iface->conf->channel = ideal_chan->chan;
+ iface->freq = ideal_chan->freq;
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
acs_adjust_center_freq(iface);
@@ -917,29 +1015,59 @@ fail:
}
+static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode,
+ int *freq)
+{
+ struct hostapd_channel_data *chan;
+ int i;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
+ if (!is_in_freqlist(iface, chan))
+ continue;
+
+ *freq++ = chan->freq;
+ }
+
+ return freq;
+}
+
+
static int acs_request_scan(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
- struct hostapd_channel_data *chan;
int i, *freq;
+ int num_channels;
+ struct hostapd_hw_modes *mode;
os_memset(&params, 0, sizeof(params));
- params.freqs = os_calloc(iface->current_mode->num_channels + 1,
- sizeof(params.freqs[0]));
+
+ num_channels = 0;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ num_channels += mode->num_channels;
+ }
+
+ params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0]));
if (params.freqs == NULL)
return -1;
freq = params.freqs;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
- continue;
- if (!is_in_chanlist(iface, chan))
- continue;
-
- *freq++ = chan->freq;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ mode = &iface->hw_features[i];
+ if (!hostapd_hw_skip_mode(iface, mode))
+ freq = acs_request_scan_add_freqs(iface, mode, freq);
}
+
*freq = 0;
if (params.freqs == freq) {
@@ -977,7 +1105,8 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
return HOSTAPD_CHAN_ACS;
}
- if (!iface->current_mode)
+ if (!iface->current_mode &&
+ iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
return HOSTAPD_CHAN_INVALID;
acs_cleanup(iface);
diff --git a/src/ap/airtime_policy.c b/src/ap/airtime_policy.c
index f56ca5b..1e67f0d 100644
--- a/src/ap/airtime_policy.c
+++ b/src/ap/airtime_policy.c
@@ -134,8 +134,8 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
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;
+ bool all_div_min = true;
+ bool apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC;
int wt, num_bss = 0, max_wt = 0;
size_t i;
@@ -169,7 +169,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
* integers. */
if (bss->num_backlogged_sta &&
bss->num_backlogged_sta % num_sta_min > 0)
- all_div_min = FALSE;
+ 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
@@ -178,7 +178,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
if (!apply_limit && bss->conf->airtime_limit) {
if (bss->num_backlogged_sta * wt_sum >
bss->conf->airtime_weight * num_sta_sum)
- apply_limit = TRUE;
+ apply_limit = true;
}
}
if (all_div_min)
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 58fc3e9..04535a1 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -54,23 +54,33 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->logger_syslog = (unsigned int) -1;
bss->logger_stdout = (unsigned int) -1;
+#ifdef CONFIG_WEP
bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
bss->wep_rekeying_period = 300;
/* use key0 in individual key and key1 in broadcast key */
bss->broadcast_key_idx_min = 1;
bss->broadcast_key_idx_max = 2;
+#else /* CONFIG_WEP */
+ bss->auth_algs = WPA_AUTH_ALG_OPEN;
+#endif /* CONFIG_WEP */
bss->eap_reauth_period = 3600;
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
+ bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
bss->wpa_group_update_count = 4;
bss->wpa_pairwise_update_count = 4;
bss->wpa_disable_eapol_key_retries =
DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+#ifdef CONFIG_NO_TKIP
+ bss->wpa_pairwise = WPA_CIPHER_CCMP;
+ bss->wpa_group = WPA_CIPHER_CCMP;
+#else /* CONFIG_NO_TKIP */
bss->wpa_pairwise = WPA_CIPHER_TKIP;
bss->wpa_group = WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
bss->rsn_pairwise = 0;
bss->max_num_sta = MAX_STA_COUNT;
@@ -150,6 +160,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ bss->sae_commit_status = -1;
+#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -251,6 +265,9 @@ struct hostapd_config * hostapd_config_defaults(void)
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;
+ conf->he_op.he_bss_color_disabled = 1;
+ conf->he_op.he_bss_color_partial = 0;
+ conf->he_op.he_bss_color = 1;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
@@ -301,6 +318,7 @@ static int hostapd_config_read_wpa_psk(const char *fname,
while (fgets(buf, sizeof(buf), f)) {
int vlan_id = 0;
+ int wps = 0;
line++;
@@ -331,6 +349,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
value = "";
if (!os_strcmp(name, "keyid")) {
keyid = value;
+ } else if (!os_strcmp(name, "wps")) {
+ wps = atoi(value);
} else if (!os_strcmp(name, "vlanid")) {
vlan_id = atoi(value);
} else {
@@ -348,8 +368,9 @@ static int hostapd_config_read_wpa_psk(const char *fname,
if (!token)
token = "";
if (hwaddr_aton(token, addr)) {
- wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
- "line %d in '%s'", token, line, fname);
+ wpa_printf(MSG_ERROR,
+ "Invalid MAC address '%s' on line %d in '%s'",
+ token, line, fname);
ret = -1;
break;
}
@@ -377,16 +398,17 @@ static int hostapd_config_read_wpa_psk(const char *fname,
ok = 0;
len = os_strlen(pos);
- if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+ if (len == 2 * PMK_LEN &&
+ hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
ok = 1;
- else if (len >= 8 && len < 64) {
- pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
- 4096, psk->psk, PMK_LEN);
+ else if (len >= 8 && len < 64 &&
+ pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
+ 4096, psk->psk, PMK_LEN) == 0)
ok = 1;
- }
if (!ok) {
- wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
- "'%s'", pos, line, fname);
+ wpa_printf(MSG_ERROR,
+ "Invalid PSK '%s' on line %d in '%s'",
+ pos, line, fname);
os_free(psk);
ret = -1;
break;
@@ -404,6 +426,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
}
}
+ psk->wps = wps;
+
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
@@ -441,7 +465,10 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
struct hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw;
- if (conf->sae_pwe == 0)
+ if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
+ !hostapd_sae_pk_in_use(conf)) ||
+ conf->sae_pwe == 3 ||
+ !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
return 0; /* PT not needed */
sae_deinit_pt(ssid->pt);
@@ -623,6 +650,7 @@ void hostapd_config_free_eap_users(struct hostapd_eap_user *user)
}
+#ifdef CONFIG_WEP
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
@@ -631,6 +659,7 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
keys->key[i] = NULL;
}
}
+#endif /* CONFIG_WEP */
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
@@ -687,6 +716,9 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
#ifdef CONFIG_SAE
sae_deinit_pt(tmp->pt);
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SAE_PK
+ sae_deinit_pk(tmp->pk);
+#endif /* CONFIG_SAE_PK */
os_free(tmp);
}
}
@@ -719,7 +751,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
str_clear_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file);
+#ifdef CONFIG_WEP
hostapd_config_free_wep(&conf->ssid.wep);
+#endif /* CONFIG_WEP */
#ifdef CONFIG_FULL_DYNAMIC_VLAN
os_free(conf->ssid.vlan_tagged_interface);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -813,6 +847,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->upc);
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
wpabuf_free(conf->wps_vendor_ext[i]);
+ wpabuf_free(conf->wps_application_ext);
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@@ -880,6 +915,12 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override);
wpabuf_free(conf->sae_commit_override);
+ wpabuf_free(conf->rsne_override_eapol);
+ wpabuf_free(conf->rsnxe_override_eapol);
+ wpabuf_free(conf->rsne_override_ft);
+ wpabuf_free(conf->rsnxe_override_ft);
+ wpabuf_free(conf->gtk_rsc_override);
+ wpabuf_free(conf->igtk_rsc_override);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(conf->no_probe_resp_if_seen_on);
@@ -935,6 +976,7 @@ void hostapd_config_free(struct hostapd_config *conf)
os_free(conf->supported_rates);
os_free(conf->basic_rates);
os_free(conf->acs_ch_list.range);
+ os_free(conf->acs_freq_list.range);
os_free(conf->driver_params);
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
@@ -1077,6 +1119,37 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
}
+#ifdef CONFIG_SAE_PK
+static bool hostapd_sae_pk_password_without_pk(struct hostapd_bss_config *bss)
+{
+ struct sae_password_entry *pw;
+ bool res = false;
+
+ if (bss->ssid.wpa_passphrase &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ sae_pk_valid_password(bss->ssid.wpa_passphrase))
+ res = true;
+
+ for (pw = bss->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk &&
+#ifdef CONFIG_TESTING_OPTIONS
+ !bss->sae_pk_password_check_skip &&
+#endif /* CONFIG_TESTING_OPTIONS */
+ sae_pk_valid_password(pw->password))
+ return true;
+
+ if (bss->ssid.wpa_passphrase && res && pw->pk &&
+ os_strcmp(bss->ssid.wpa_passphrase, pw->password) == 0)
+ res = false;
+ }
+
+ return res;
+}
+#endif /* CONFIG_SAE_PK */
+
+
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf,
int full_config)
@@ -1088,6 +1161,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1;
}
+#ifdef CONFIG_WEP
if (bss->wpa) {
int wep, i;
@@ -1105,6 +1179,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1;
}
}
+#endif /* CONFIG_WEP */
if (full_config && bss->wpa &&
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
@@ -1152,7 +1227,6 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_IEEE80211N
if (full_config && conf->ieee80211n &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
bss->disable_11n = 1;
@@ -1160,12 +1234,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
"allowed, disabling HT capabilities");
}
+#ifdef CONFIG_WEP
if (full_config && conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
"allowed, disabling HT capabilities");
}
+#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211n && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
@@ -1177,15 +1253,16 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
"requires CCMP/GCMP to be enabled, disabling HT "
"capabilities");
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
+#ifdef CONFIG_WEP
if (full_config && conf->ieee80211ac &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11ac = 1;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
}
+#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211ac && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
@@ -1205,12 +1282,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
bss->wps_state = 0;
}
+#ifdef CONFIG_WEP
if (full_config && bss->wps_state &&
bss->ssid.wep.keys_set && bss->wpa == 0) {
wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
"disabled");
bss->wps_state = 0;
}
+#endif /* CONFIG_WEP */
if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) ||
@@ -1254,6 +1333,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_OCV */
+#ifdef CONFIG_SAE_PK
+ if (full_config && hostapd_sae_pk_in_use(bss) &&
+ hostapd_sae_pk_password_without_pk(bss)) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: SAE password uses SAE-PK style, but does not have PK configured");
+ return -1;
+ }
+#endif /* CONFIG_SAE_PK */
+
return 0;
}
@@ -1334,11 +1422,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config)
{
+#ifdef CONFIG_WEP
if (bss->individual_wep_key_len == 0) {
/* individual keys are not use; can use key idx0 for
* broadcast keys */
bss->broadcast_key_idx_min = 0;
}
+#endif /* CONFIG_WEP */
if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
bss->rsn_pairwise = bss->wpa_pairwise;
@@ -1364,6 +1454,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
} else if (bss->ieee802_1x) {
int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+#ifdef CONFIG_WEP
bss->ssid.wep.default_len = bss->default_wep_key_len;
if (full_config && bss->default_wep_key_len) {
cipher = bss->default_wep_key_len >= 13 ?
@@ -1374,11 +1465,13 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
else
cipher = WPA_CIPHER_WEP40;
}
+#endif /* CONFIG_WEP */
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+#ifdef CONFIG_WEP
} else if (bss->ssid.wep.keys_set) {
int cipher = WPA_CIPHER_WEP40;
if (bss->ssid.wep.len[0] >= 13)
@@ -1389,6 +1482,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
bss->rsn_pairwise = cipher;
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
+#endif /* CONFIG_WEP */
} else if (bss->osen) {
bss->ssid.security_policy = SECURITY_OSEN;
bss->wpa_group = WPA_CIPHER_CCMP;
@@ -1427,3 +1521,38 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
return 2;
return with_id;
}
+
+
+bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_SAE_PK
+ struct sae_password_entry *pw;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->pk)
+ return true;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ return false;
+}
+
+
+#ifdef CONFIG_SAE_PK
+bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
+{
+ bool with_pk = false;
+ struct sae_password_entry *pw;
+
+ if (conf->ssid.wpa_passphrase)
+ return false;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (!pw->pk)
+ return false;
+ with_pk = true;
+ }
+
+ return with_pk;
+}
+#endif /* CONFIG_SAE_PK */
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 2a0c984..bada04c 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -67,6 +67,7 @@ struct hostapd_radius_servers;
struct ft_remote_r0kh;
struct ft_remote_r1kh;
+#ifdef CONFIG_WEP
#define NUM_WEP_KEYS 4
struct hostapd_wep_keys {
u8 idx;
@@ -75,10 +76,13 @@ struct hostapd_wep_keys {
int keys_set;
size_t default_len; /* key length used for dynamic key generation */
};
+#endif /* CONFIG_WEP */
typedef enum hostap_security_policy {
SECURITY_PLAINTEXT = 0,
+#ifdef CONFIG_WEP
SECURITY_STATIC_WEP = 1,
+#endif /* CONFIG_WEP */
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4,
@@ -88,6 +92,7 @@ typedef enum hostap_security_policy {
struct hostapd_ssid {
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
+ u32 short_ssid;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
unsigned int wpa_passphrase_set:1;
@@ -101,7 +106,9 @@ struct hostapd_ssid {
char *wpa_psk_file;
struct sae_pt *pt;
+#ifdef CONFIG_WEP
struct hostapd_wep_keys wep;
+#endif /* CONFIG_WEP */
#define DYNAMIC_VLAN_DISABLED 0
#define DYNAMIC_VLAN_OPTIONAL 1
@@ -151,6 +158,7 @@ struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
char keyid[KEYID_LEN];
+ int wps;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
@@ -189,15 +197,6 @@ struct hostapd_radius_attr {
#define NUM_TX_QUEUES 4
-
-struct hostapd_tx_queue_params {
- int aifs;
- int cwmin;
- int cwmax;
- int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
-};
-
-
#define MAX_ROAMING_CONSORTIUM_LEN 15
struct hostapd_roaming_consortium {
@@ -253,6 +252,7 @@ struct sae_password_entry {
u8 peer_addr[ETH_ALEN];
int vlan_id;
struct sae_pt *pt;
+ struct sae_pk *pk;
};
struct dpp_controller_conf {
@@ -319,10 +319,12 @@ struct hostapd_bss_config {
size_t eap_req_id_text_len;
int eapol_key_index_workaround;
+#ifdef CONFIG_WEP
size_t default_wep_key_len;
int individual_wep_key_len;
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
+#endif /* CONFIG_WEP */
int eap_reauth_period;
int erp_send_reauth_start;
char *erp_domain;
@@ -344,9 +346,11 @@ struct hostapd_bss_config {
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+ int extended_key_id;
int wpa_key_mgmt;
enum mfp_options ieee80211w;
int group_mgmt_cipher;
+ int beacon_prot;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
@@ -367,6 +371,7 @@ struct hostapd_bss_config {
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
@@ -497,6 +502,7 @@ struct hostapd_bss_config {
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ struct wpabuf *wps_application_ext;
int wps_nfc_pw_from_config;
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
@@ -663,7 +669,26 @@ struct hostapd_bss_config {
u8 bss_load_test_set;
struct wpabuf *own_ie_override;
int sae_reflection_attack;
+ int sae_commit_status;
+ int sae_pk_omit;
+ int sae_pk_password_check_skip;
struct wpabuf *sae_commit_override;
+ struct wpabuf *rsne_override_eapol;
+ struct wpabuf *rsnxe_override_eapol;
+ struct wpabuf *rsne_override_ft;
+ struct wpabuf *rsnxe_override_ft;
+ struct wpabuf *gtk_rsc_override;
+ struct wpabuf *igtk_rsc_override;
+ int no_beacon_rsnxe;
+ int skip_prune_assoc;
+ int ft_rsnxe_used;
+ unsigned int oci_freq_override_eapol_m3;
+ unsigned int oci_freq_override_eapol_g1;
+ unsigned int oci_freq_override_saquery_req;
+ unsigned int oci_freq_override_saquery_resp;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
+ unsigned int oci_freq_override_wnm_sleep;
#endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0)
@@ -719,6 +744,8 @@ struct hostapd_bss_config {
struct wpabuf *dpp_csign;
#ifdef CONFIG_DPP2
struct dpp_controller_conf *dpp_controller;
+ int dpp_configurator_connectivity;
+ int dpp_pfs;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
@@ -728,12 +755,15 @@ struct hostapd_bss_config {
size_t owe_transition_ssid_len;
char owe_transition_ifname[IFNAMSIZ + 1];
int *owe_groups;
+ int owe_ptk_workaround;
#endif /* CONFIG_OWE */
int coloc_intf_reporting;
u8 send_probe_response;
+ u8 transition_disable;
+
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
@@ -837,9 +867,9 @@ struct hostapd_bss_config {
* struct he_phy_capabilities_info - HE PHY capabilities
*/
struct he_phy_capabilities_info {
- Boolean he_su_beamformer;
- Boolean he_su_beamformee;
- Boolean he_mu_beamformer;
+ bool he_su_beamformer;
+ bool he_su_beamformee;
+ bool he_mu_beamformer;
};
/**
@@ -847,6 +877,8 @@ struct he_phy_capabilities_info {
*/
struct he_operation {
u8 he_bss_color;
+ u8 he_bss_color_disabled;
+ u8 he_bss_color_partial;
u8 he_default_pe_duration;
u8 he_twt_required;
u16 he_rts_threshold;
@@ -881,8 +913,11 @@ struct hostapd_config {
u8 edmg_channel;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
+ struct wpa_freq_range_list acs_freq_list;
+ u8 acs_freq_list_present;
int acs_exclude_dfs;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+ int acs_exclude_6ghz_non_psc;
enum {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
@@ -1107,6 +1142,8 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
+bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
+bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index de60c79..f157659 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/hw_features_common.h"
#include "wps/wps.h"
#include "p2p/p2p.h"
@@ -350,7 +351,7 @@ int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg)
{
if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
- return 0;
+ return -EOPNOTSUPP;
return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
}
@@ -417,6 +418,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set)
{
@@ -438,6 +440,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.vht_capabilities = vht_capab;
params.he_capab = he_capab;
params.he_capab_len = he_capab_len;
+ params.he_6ghz_capab = he_6ghz_capab;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
@@ -587,7 +590,7 @@ 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)
{
- if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->sta_set_flags)
return 0;
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
flags_or, flags_and);
@@ -649,6 +652,12 @@ int hostapd_drv_none(struct hostapd_data *hapd)
}
+bool hostapd_drv_nl80211(struct hostapd_data *hapd)
+{
+ return hapd->driver && os_strcmp(hapd->driver->name, "nl80211") == 0;
+}
+
+
int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params)
{
@@ -679,36 +688,41 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
+ int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+ const u8 *key, size_t key_len, enum key_flag key_flag)
{
+ struct wpa_driver_set_key_params params;
+
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
return 0;
- return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
- key_idx, set_tx, seq, seq_len, key,
- key_len);
-}
+ os_memset(&params, 0, sizeof(params));
+ params.ifname = ifname;
+ params.alg = alg;
+ params.addr = addr;
+ params.key_idx = key_idx;
+ params.set_tx = set_tx;
+ params.seq = seq;
+ params.seq_len = seq_len;
+ params.key = key;
+ params.key_len = key_len;
+ params.vlan_id = vlan_id;
+ params.key_flag = key_flag;
-int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack)
-{
- if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
- return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
- NULL, 0);
+ return hapd->driver->set_key(hapd->drv_priv, &params);
}
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack,
- const u16 *csa_offs, size_t csa_offs_len)
+int hostapd_drv_send_mlme(struct hostapd_data *hapd,
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt)
{
- if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
+ if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
- csa_offs, csa_offs_len);
+ csa_offs, csa_offs_len, no_encrypt, 0);
}
@@ -855,10 +869,24 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
- if ((acs_ch_list_all ||
- freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
- chan->chan)) &&
- !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ if (!acs_ch_list_all &&
+ (hapd->iface->conf->acs_freq_list.num &&
+ !freq_range_list_includes(
+ &hapd->iface->conf->acs_freq_list,
+ chan->freq)))
+ continue;
+ if (!acs_ch_list_all &&
+ (!hapd->iface->conf->acs_freq_list_present &&
+ hapd->iface->conf->acs_ch_list.num &&
+ !freq_range_list_includes(
+ &hapd->iface->conf->acs_ch_list,
+ chan->chan)))
+ continue;
+ if (is_6ghz_freq(chan->freq) &&
+ hapd->iface->conf->acs_exclude_6ghz_non_psc &&
+ !is_6ghz_psc_frequency(chan->freq))
+ continue;
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
!(hapd->iface->conf->acs_exclude_dfs &&
(chan->flag & HOSTAPD_CHAN_RADAR)))
int_array_add_unique(freq_list, chan->freq);
@@ -884,10 +912,9 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
int ret, i, acs_ch_list_all = 0;
- u8 *channels = NULL;
- unsigned int num_channels = 0;
struct hostapd_hw_modes *mode;
int *freq_list = NULL;
+ enum hostapd_hw_mode selected_mode;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0;
@@ -899,42 +926,27 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
* If no chanlist config parameter is provided, include all enabled
* channels of the selected hw_mode.
*/
- if (!hapd->iface->conf->acs_ch_list.num)
- acs_ch_list_all = 1;
-
- mode = hapd->iface->current_mode;
- if (mode) {
- channels = os_malloc(mode->num_channels);
- if (channels == NULL)
- return -1;
-
- for (i = 0; i < mode->num_channels; i++) {
- struct hostapd_channel_data *chan = &mode->channels[i];
- if (!acs_ch_list_all &&
- !freq_range_list_includes(
- &hapd->iface->conf->acs_ch_list,
- chan->chan))
- continue;
- if (hapd->iface->conf->acs_exclude_dfs &&
- (chan->flag & HOSTAPD_CHAN_RADAR))
- continue;
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
- channels[num_channels++] = chan->chan;
- int_array_add_unique(&freq_list, chan->freq);
- }
- }
- } else {
- for (i = 0; i < hapd->iface->num_hw_features; i++) {
- mode = &hapd->iface->hw_features[i];
- hostapd_get_hw_mode_any_channels(hapd, mode,
- acs_ch_list_all,
- &freq_list);
- }
+ if (hapd->iface->conf->acs_freq_list_present)
+ acs_ch_list_all = !hapd->iface->conf->acs_freq_list.num;
+ else
+ acs_ch_list_all = !hapd->iface->conf->acs_ch_list.num;
+
+ if (hapd->iface->current_mode)
+ selected_mode = hapd->iface->current_mode->mode;
+ else
+ selected_mode = HOSTAPD_MODE_IEEE80211ANY;
+
+ for (i = 0; i < hapd->iface->num_hw_features; i++) {
+ mode = &hapd->iface->hw_features[i];
+ if (selected_mode != HOSTAPD_MODE_IEEE80211ANY &&
+ selected_mode != mode->mode)
+ continue;
+ hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all,
+ &freq_list);
}
- params.ch_list = channels;
- params.ch_list_len = num_channels;
params.freq_list = freq_list;
+ params.edmg_enabled = hapd->iface->conf->enable_edmg;
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
@@ -958,8 +970,11 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
params.ch_width = 160;
}
+ if (hapd->iface->conf->op_class)
+ params.ch_width = op_class_to_bandwidth(
+ hapd->iface->conf->op_class);
ret = hapd->driver->do_acs(hapd->drv_priv, &params);
- os_free(channels);
+ os_free(freq_list);
return ret;
}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 79b1302..5738c1c 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -43,6 +43,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
@@ -80,6 +81,7 @@ hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags, u8 *dfs_domain);
int hostapd_driver_commit(struct hostapd_data *hapd);
int hostapd_drv_none(struct hostapd_data *hapd);
+bool hostapd_drv_nl80211(struct hostapd_data *hapd);
int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params);
struct wpa_scan_results * hostapd_driver_get_scan_results(
@@ -89,14 +91,13 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int hostapd_drv_set_key(const char *ifname,
struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
+ int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len);
+ const u8 *key, size_t key_len, enum key_flag key_flag);
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack);
-int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
- const void *msg, size_t len, int noack,
- const u16 *csa_offs, size_t csa_offs_len);
+ const void *msg, size_t len, int noack,
+ const u16 *csa_offs, size_t csa_offs_len,
+ int no_encrypt);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
@@ -382,4 +383,12 @@ hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
return hapd->driver->send_external_auth_status(hapd->drv_priv, params);
}
+static inline int
+hostapd_drv_set_band(struct hostapd_data *hapd, enum set_band band)
+{
+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
+ return -1;
+ return hapd->driver->set_band(hapd->drv_priv, band);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 8bf6dde..20be7f8 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -228,7 +228,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
set_beacon++;
}
-#ifdef CONFIG_IEEE80211N
if (!iface->olbc_ht && !ap->ht_support &&
(ap->channel == 0 ||
ap->channel == iface->conf->channel ||
@@ -241,7 +240,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
-#endif /* CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_update_beacons(iface);
@@ -285,14 +283,12 @@ void ap_list_timer(struct hostapd_iface *iface)
iface->olbc = 0;
set_beacon++;
}
-#ifdef CONFIG_IEEE80211N
if (!olbc_ht && iface->olbc_ht) {
wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
iface->olbc_ht = 0;
hostapd_ht_operation_update(iface);
set_beacon++;
}
-#endif /* CONFIG_IEEE80211N */
}
if (set_beacon)
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 331c09b..b3b33b7 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -36,27 +36,6 @@
#ifdef NEED_AP_MLME
-static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
- size_t len)
-{
- size_t i;
-
- for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
- if (hapd->conf->radio_measurements[i])
- break;
- }
-
- if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
- return eid;
-
- *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
- *eid++ = RRM_CAPABILITIES_IE_LEN;
- os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
-
- return eid + RRM_CAPABILITIES_IE_LEN;
-}
-
-
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
{
if (len < 2 + 5)
@@ -287,17 +266,101 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
}
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
+static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+{
+ const u8 *ies;
+ size_t ies_len;
+
+ ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+ if (!ies)
+ return NULL;
+
+ return get_ie(ies, ies_len, eid);
+}
+
+
+static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd,
+ u32 vendor_type)
+{
+ const u8 *ies;
+ size_t ies_len;
+
+ ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
+ if (!ies)
+ return NULL;
+
+ return get_vendor_ie(ies, ies_len, vendor_type);
+}
+
+
+static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len)
{
const u8 *ie;
- size_t ielen;
- ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
- if (ie == NULL || ielen > len)
- return eid;
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->no_beacon_rsnxe) {
+ wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon");
+ return pos;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
- os_memcpy(eid, ie, ielen);
- return eid + ielen;
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
}
@@ -400,11 +463,15 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ buflen += sizeof(struct ieee80211_he_6ghz_oper_info) +
+ 3 + sizeof(struct ieee80211_he_6ghz_band_cap);
}
#endif /* CONFIG_IEEE80211AX */
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
+ buflen += hostapd_eid_dpp_cc_len(hapd);
resp = os_zalloc(buflen);
if (resp == NULL)
@@ -455,14 +522,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* Extended supported rates */
pos = hostapd_eid_ext_supp_rates(hapd, pos);
- /* RSN, MDIE */
- if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
- (hapd->conf->osen && !hapd->conf->wpa)))
- pos = hostapd_eid_wpa(hapd, pos, epos - pos);
-
+ pos = hostapd_get_rsne(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
-
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+ pos = hostapd_get_mde(hapd, pos, epos - pos);
/* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, pos);
@@ -471,15 +534,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = csa_pos;
pos = hostapd_eid_supported_op_classes(hapd, pos);
-
-#ifdef CONFIG_IEEE80211N
- /* Secondary Channel Offset element */
- /* TODO: The standard doesn't specify a position for this element. */
- pos = hostapd_eid_secondary_channel(hapd, pos);
-
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
pos = hostapd_eid_ext_capab(hapd, pos);
@@ -504,18 +560,23 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
- pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
}
#endif /* CONFIG_IEEE80211AC */
+ if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
+ hapd->iconf->ieee80211ax)
+ pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
+
pos = hostapd_eid_fils_indic(hapd, pos, 0);
+ pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
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);
+ pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
+ pos = hostapd_eid_he_6ghz_band_cap(hapd, pos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -524,10 +585,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
- /* WPA */
- if (hapd->conf->wpa == WPA_PROTO_WPA ||
- (hapd->conf->osen && !hapd->conf->wpa))
- pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+ /* WPA / OSEN */
+ pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
+ pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -560,6 +620,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
+ pos = hostapd_eid_dpp_cc(hapd, pos, (u8 *) resp + buflen - pos);
if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
@@ -581,7 +642,9 @@ enum ssid_match_result {
static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
const u8 *ssid, size_t ssid_len,
const u8 *ssid_list,
- size_t ssid_list_len)
+ size_t ssid_list_len,
+ const u8 *short_ssid_list,
+ size_t short_ssid_list_len)
{
const u8 *pos, *end;
int wildcard = 0;
@@ -592,20 +655,30 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
return EXACT_SSID_MATCH;
- if (ssid_list == NULL)
- return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+ if (ssid_list) {
+ pos = ssid_list;
+ end = ssid_list + ssid_list_len;
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos)
+ break;
+ if (pos[1] == 0)
+ wildcard = 1;
+ if (pos[1] == hapd->conf->ssid.ssid_len &&
+ os_memcmp(pos + 2, hapd->conf->ssid.ssid,
+ pos[1]) == 0)
+ return EXACT_SSID_MATCH;
+ pos += 2 + pos[1];
+ }
+ }
- pos = ssid_list;
- end = ssid_list + ssid_list_len;
- while (end - pos >= 2) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[1] == 0)
- wildcard = 1;
- if (pos[1] == hapd->conf->ssid.ssid_len &&
- os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
- return EXACT_SSID_MATCH;
- pos += 2 + pos[1];
+ if (short_ssid_list) {
+ pos = short_ssid_list;
+ end = short_ssid_list + short_ssid_list_len;
+ while (end - pos >= 4) {
+ if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos))
+ return EXACT_SSID_MATCH;
+ pos += 4;
+ }
}
return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
@@ -743,11 +816,7 @@ void handle_probe_req(struct hostapd_data *hapd,
int ret;
u16 csa_offs[2];
size_t csa_offs_len;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
- char *identity = NULL;
- char *radius_cui = NULL;
+ struct radius_sta rad_info;
if (len < IEEE80211_HDRLEN)
return;
@@ -756,10 +825,8 @@ void handle_probe_req(struct hostapd_data *hapd,
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
ie_len = len - IEEE80211_HDRLEN;
- ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
- &session_timeout,
- &acct_interim_interval, &vlan_id,
- &psk, &identity, &radius_cui, 1);
+ ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &rad_info, 1);
if (ret == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Probe Request frame from " MACSTR
@@ -838,7 +905,7 @@ void handle_probe_req(struct hostapd_data *hapd,
#endif /* CONFIG_P2P */
if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
- elems.ssid_list_len == 0) {
+ elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
@@ -870,7 +937,8 @@ void handle_probe_req(struct hostapd_data *hapd,
#endif /* CONFIG_TAXONOMY */
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
- elems.ssid_list, elems.ssid_list_len);
+ elems.ssid_list, elems.ssid_list_len,
+ elems.short_ssid_list, elems.short_ssid_list_len);
if (res == NO_SSID_MATCH) {
if (!(mgmt->da[0] & 0x01)) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
@@ -883,6 +951,12 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
+ if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) {
+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+ "broadcast SSID ignored", MAC2STR(mgmt->sa));
+ return;
+ }
+
#ifdef CONFIG_INTERWORKING
if (hapd->conf->interworking &&
elems.interworking && elems.interworking_len >= 1) {
@@ -987,9 +1061,9 @@ void handle_probe_req(struct hostapd_data *hapd,
hapd->cs_c_off_ecsa_proberesp;
}
- ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
- csa_offs_len ? csa_offs : NULL,
- csa_offs_len);
+ ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack,
+ csa_offs_len ? csa_offs : NULL,
+ csa_offs_len, 0);
if (ret < 0)
wpa_printf(MSG_INFO, "handle_probe_req: send failed");
@@ -1060,7 +1134,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
size_t resp_len = 0;
#ifdef NEED_AP_MLME
u16 capab_info;
- u8 *pos, *tailpos, *csa_pos;
+ u8 *pos, *tailpos, *tailend, *csa_pos;
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
@@ -1094,11 +1168,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ tail_len += sizeof(struct ieee80211_he_6ghz_oper_info) +
+ 3 + sizeof(struct ieee80211_he_6ghz_band_cap);
}
#endif /* CONFIG_IEEE80211AX */
tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
+ tail_len += hostapd_eid_dpp_cc_len(hapd);
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
@@ -1107,6 +1185,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
os_free(tail);
return -1;
}
+ tailend = tail + tail_len;
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_BEACON);
@@ -1147,8 +1226,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
head_len = pos - (u8 *) head;
- tailpos = hostapd_eid_country(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
/* Power Constraint element */
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
@@ -1165,19 +1243,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
/* Extended supported rates */
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
- /* RSN, MDIE */
- if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
- (hapd->conf->osen && !hapd->conf->wpa)))
- tailpos = hostapd_eid_wpa(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
-
+ tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
+ tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
-
- tailpos = hostapd_eid_bss_load(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE - tailpos);
+ tailend - tailpos);
+ tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
/* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, tailpos);
@@ -1186,15 +1256,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = csa_pos;
tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
-
-#ifdef CONFIG_IEEE80211N
- /* Secondary Channel Offset element */
- /* TODO: The standard doesn't specify a position for this element. */
- tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
-
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
-#endif /* CONFIG_IEEE80211N */
tailpos = hostapd_eid_ext_capab(hapd, tailpos);
@@ -1221,19 +1284,24 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
- tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AC */
+ if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
+ hapd->iconf->ieee80211ax)
+ tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
+
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
+ tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
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);
+ tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
+ tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1242,12 +1310,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
- /* WPA */
- if (hapd->conf->wpa == WPA_PROTO_WPA ||
- (hapd->conf->osen && !hapd->conf->wpa))
- tailpos = hostapd_eid_wpa(hapd, tailpos,
- tail + BEACON_TAIL_BUF_SIZE -
- tailpos);
+ /* WPA / OSEN */
+ tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
+ tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -1280,6 +1345,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
tailpos = hostapd_eid_owe_trans(hapd, tailpos,
tail + tail_len - tailpos);
+ tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
@@ -1318,10 +1384,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->auth_algs = hapd->conf->auth_algs;
params->wpa_version = hapd->conf->wpa;
- params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+ params->privacy = hapd->conf->wpa;
+#ifdef CONFIG_WEP
+ params->privacy |= hapd->conf->ssid.wep.keys_set ||
(hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len));
+#endif /* CONFIG_WEP */
switch (hapd->conf->ignore_broadcast_ssid) {
case 0:
params->hide_ssid = NO_SSID_HIDING;
@@ -1334,7 +1403,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
break;
}
params->isolate = hapd->conf->isolate;
- params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
#ifdef NEED_AP_MLME
params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION);
@@ -1430,6 +1498,13 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
hapd->iface->conf->spr.srg_obss_pd_min_offset;
params.he_spr_srg_obss_pd_max_offset =
hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ params.he_bss_color_disabled =
+ hapd->iface->conf->he_op.he_bss_color_disabled;
+ params.he_bss_color_partial =
+ hapd->iface->conf->he_op.he_bss_color_partial;
+ params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
+ params.twt_responder = hostapd_get_he_twt_responder(hapd,
+ IEEE80211_MODE_AP);
#endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 676a4c7..ef53a82 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -273,6 +273,36 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (!os_snprintf_error(buflen - len, res))
len += res;
}
+
+ if (sta->sae && sta->sae->tmp) {
+ const u8 *pos;
+ unsigned int j, count;
+ struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
+
+ res = os_snprintf(buf + len, buflen - len,
+ "sae_rejected_groups=");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+
+ if (groups) {
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ } else {
+ pos = NULL;
+ count = 0;
+ }
+ for (j = 0; pos && j < count; j++) {
+ res = os_snprintf(buf + len, buflen - len, "%s%d",
+ j == 0 ? "" : " ", WPA_GET_LE16(pos));
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ pos += 2;
+ }
+
+ res = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
#endif /* CONFIG_SAE */
if (sta->vlan_id > 0) {
@@ -315,7 +345,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AC */
-#ifdef CONFIG_IEEE80211N
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
res = os_snprintf(buf + len, buflen - len,
"ht_caps_info=0x%04x\n",
@@ -324,7 +353,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (!os_snprintf_error(buflen - len, res))
len += res;
}
-#endif /* CONFIG_IEEE80211N */
if (sta->ext_capability &&
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
@@ -432,9 +460,6 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
int ret;
u8 *pos;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
-
mgmt = os_zalloc(sizeof(*mgmt) + 100);
if (mgmt == NULL)
return -1;
@@ -468,8 +493,8 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
pos += 2;
*pos++ = minor_reason_code;
- ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
- pos - (u8 *) mgmt, 1);
+ ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
+ 0);
os_free(mgmt);
return ret < 0 ? -1 : 0;
@@ -499,8 +524,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
+
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@@ -510,10 +534,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
+ if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ 0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
@@ -562,8 +586,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (!hapd->drv_priv || !hapd->driver->send_frame)
- return -1;
+
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@@ -573,10 +596,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
- if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
- IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth),
- encrypt) < 0)
+ if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
+ IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth),
+ 0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
@@ -731,6 +754,22 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->ieee80211ax) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "he_oper_chwidth=%d\n"
+ "he_oper_centr_freq_seg0_idx=%d\n"
+ "he_oper_centr_freq_seg1_idx=%d\n",
+ iface->conf->he_oper_chwidth,
+ iface->conf->he_oper_centr_freq_seg0_idx,
+ iface->conf->he_oper_centr_freq_seg1_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
ret = os_snprintf(buf + len, buflen - len,
"vht_oper_chwidth=%d\n"
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index c4c00fc..f04a00a 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -144,30 +144,44 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int i;
u32 bw = num_chan_to_bw(num_chans);
- if (first_chan_idx + num_chans > mode->num_channels)
+ if (first_chan_idx + num_chans > mode->num_channels) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: some channels in range not defined");
return 0;
+ }
first_chan = &mode->channels[first_chan_idx];
/* hostapd DFS implementation assumes the first channel as primary.
* If it's not allowed to use the first channel as primary, decline the
* whole channel range. */
- if (!chan_pri_allowed(first_chan))
+ if (!chan_pri_allowed(first_chan)) {
+ wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed");
return 0;
+ }
for (i = 0; i < num_chans; i++) {
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
first_chan_idx);
- if (!chan)
+ if (!chan) {
+ wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
+ first_chan->freq + i * 20);
return 0;
+ }
/* HT 40 MHz secondary channel availability checked only for
* primary channel */
- if (!chan_bw_allowed(chan, bw, 1, !i))
+ if (!chan_bw_allowed(chan, bw, 1, !i)) {
+ wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
+ first_chan->freq + i * 20);
return 0;
+ }
- if (!dfs_channel_available(chan, skip_radar))
+ if (!dfs_channel_available(chan, skip_radar)) {
+ wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
+ first_chan->freq + i * 20);
return 0;
+ }
}
return 1;
@@ -210,22 +224,36 @@ static int dfs_find_channel(struct hostapd_iface *iface,
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
(!dfs_is_chan_allowed(chan, n_chans) ||
- !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
+ !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: channel %d (%d) is incompatible",
+ chan->freq, chan->chan);
continue;
+ }
/* Skip incompatible chandefs */
- if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
+ if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: range not available for %d (%d)",
+ chan->freq, chan->chan);
continue;
+ }
- if (!is_in_chanlist(iface, chan))
+ if (!is_in_chanlist(iface, chan)) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: channel %d (%d) not in chanlist",
+ chan->freq, chan->chan);
continue;
+ }
if (ret_chan && idx == channel_idx) {
- wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
+ wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
+ chan->freq, chan->chan);
*ret_chan = chan;
return idx;
}
- wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
+ wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
+ chan->freq, chan->chan);
channel_idx++;
}
return channel_idx;
@@ -235,6 +263,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
static void dfs_adjust_center_freq(struct hostapd_iface *iface,
struct hostapd_channel_data *chan,
int secondary_channel,
+ int sec_chan_idx_80p80,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx)
{
@@ -261,8 +290,14 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
case CHANWIDTH_160MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 14;
break;
+ case CHANWIDTH_80P80MHZ:
+ *oper_centr_freq_seg0_idx = chan->chan + 6;
+ *oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
+ break;
+
default:
- wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
+ wpa_printf(MSG_INFO,
+ "DFS: Unsupported channel width configuration");
*oper_centr_freq_seg0_idx = 0;
break;
}
@@ -441,8 +476,11 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
+ struct hostapd_channel_data *chan2 = NULL;
int num_available_chandefs;
- int chan_idx;
+ int chan_idx, chan_idx2;
+ int sec_chan_idx_80p80 = -1;
+ int i;
u32 _rand;
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
@@ -459,6 +497,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
/* Get the count first */
num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
+ wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
+ num_available_chandefs);
if (num_available_chandefs == 0)
return NULL;
@@ -466,6 +506,12 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
return NULL;
chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+ if (!chan) {
+ wpa_printf(MSG_DEBUG, "DFS: no random channel found");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
+ chan->freq, chan->chan);
/* dfs_find_channel() calculations assume HT40+ */
if (iface->conf->secondary_channel)
@@ -473,8 +519,45 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
else
*secondary_channel = 0;
+ /* Get secondary channel for HT80P80 */
+ if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
+ if (num_available_chandefs <= 1) {
+ wpa_printf(MSG_ERROR,
+ "only 1 valid chan, can't support 80+80");
+ return NULL;
+ }
+
+ /*
+ * Loop all channels except channel1 to find a valid channel2
+ * that is not adjacent to channel1.
+ */
+ for (i = 0; i < num_available_chandefs - 1; i++) {
+ /* start from chan_idx + 1, end when chan_idx - 1 */
+ chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
+ dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
+ if (chan2 && abs(chan2->chan - chan->chan) > 12) {
+ /* two channels are not adjacent */
+ sec_chan_idx_80p80 = chan2->chan;
+ wpa_printf(MSG_DEBUG,
+ "DFS: got second chan: %d (%d)",
+ chan2->freq, chan2->chan);
+ break;
+ }
+ }
+
+ /* Check if we got a valid secondary channel which is not
+ * adjacent to the first channel.
+ */
+ if (sec_chan_idx_80p80 == -1) {
+ wpa_printf(MSG_INFO,
+ "DFS: failed to get chan2 for 80+80");
+ return NULL;
+ }
+ }
+
dfs_adjust_center_freq(iface, chan,
*secondary_channel,
+ sec_chan_idx_80p80,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx);
@@ -515,6 +598,7 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
int n_chans = 1, i;
struct hostapd_hw_modes *mode;
int frequency = freq;
+ int frequency2 = 0;
int ret = 0;
mode = iface->current_mode;
@@ -542,6 +626,11 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
n_chans = 4;
frequency = cf1 - 30;
break;
+ case CHAN_WIDTH_80P80:
+ n_chans = 4;
+ frequency = cf1 - 30;
+ frequency2 = cf2 - 30;
+ break;
case CHAN_WIDTH_160:
n_chans = 8;
frequency = cf1 - 70;
@@ -557,6 +646,11 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
for (i = 0; i < n_chans; i++) {
ret += set_dfs_state_freq(iface, frequency, state);
frequency = frequency + 20;
+
+ if (chan_width == CHAN_WIDTH_80P80) {
+ ret += set_dfs_state_freq(iface, frequency2, state);
+ frequency2 = frequency2 + 20;
+ }
}
return ret;
@@ -662,6 +756,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
int skip_radar = 0;
+ if (is_6ghz_freq(iface->freq))
+ return 1;
+
if (!iface->current_mode) {
/*
* This can happen with drivers that do not provide mode
@@ -759,7 +856,7 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
}
-static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
{
int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
@@ -807,7 +904,7 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
* another radio.
*/
if (iface->state != HAPD_IFACE_ENABLED &&
- hostapd_config_dfs_chan_available(iface)) {
+ hostapd_is_dfs_chan_available(iface)) {
hostapd_setup_interface_complete(iface, 0);
iface->cac_started = 0;
}
@@ -837,6 +934,44 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
}
+static struct hostapd_channel_data *
+dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx, int *skip_radar)
+{
+ struct hostapd_channel_data *channel;
+
+ for (;;) {
+ channel = dfs_get_valid_channel(iface, secondary_channel,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx,
+ *skip_radar);
+ if (channel) {
+ wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
+ channel->chan);
+ return channel;
+ }
+
+ if (*skip_radar) {
+ *skip_radar = 0;
+ } else {
+ int oper_chwidth;
+
+ oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ if (oper_chwidth == CHANWIDTH_USE_HT)
+ break;
+ *skip_radar = 1;
+ hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
+ }
+ }
+
+ wpa_printf(MSG_INFO,
+ "%s: no DFS channels left, waiting for NOP to finish",
+ __func__);
+ return NULL;
+}
+
+
static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
@@ -854,8 +989,14 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
skip_radar);
if (!channel) {
- wpa_printf(MSG_ERROR, "No valid channel available");
- return err;
+ channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &skip_radar);
+ if (!channel) {
+ wpa_printf(MSG_ERROR, "No valid channel available");
+ return err;
+ }
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -884,11 +1025,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
int secondary_channel;
u8 oper_centr_freq_seg0_idx;
u8 oper_centr_freq_seg1_idx;
+ u8 new_vht_oper_chwidth;
int skip_radar = 1;
struct csa_settings csa_settings;
unsigned int i;
int err = 1;
struct hostapd_hw_modes *cmode = iface->current_mode;
+ u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -922,28 +1065,25 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
* requires to perform a CAC first.
*/
skip_radar = 0;
- channel = dfs_get_valid_channel(iface, &secondary_channel,
- &oper_centr_freq_seg0_idx,
- &oper_centr_freq_seg1_idx,
- skip_radar);
- if (!channel) {
- wpa_printf(MSG_INFO,
- "%s: no DFS channels left, waiting for NOP to finish",
- __func__);
+ channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &skip_radar);
+ if (!channel)
return err;
+ if (!skip_radar) {
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = secondary_channel;
+ 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);
+ return 0;
}
-
- iface->freq = channel->freq;
- iface->conf->channel = channel->chan;
- iface->conf->secondary_channel = secondary_channel;
- 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);
- return 0;
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@@ -952,6 +1092,9 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
"freq=%d chan=%d sec_chan=%d", channel->freq,
channel->chan, secondary_channel);
+ new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
+
/* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings));
csa_settings.cs_count = 5;
@@ -966,7 +1109,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
secondary_channel,
- hostapd_get_oper_chwidth(iface->conf),
+ new_vht_oper_chwidth,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
cmode->vht_capab,
@@ -990,6 +1133,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
+ hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
@@ -1026,8 +1170,10 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
return 0;
/* mark radar frequency as invalid */
- set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
- cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+ res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
+ if (!res)
+ return 0;
/* Skip if reported radar event not overlapped our channels */
res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
@@ -1147,3 +1293,56 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
__func__, iface->freq);
return 2;
}
+
+
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+ int center_freq)
+{
+ struct hostapd_channel_data *chan;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ int half_width;
+ int res = 0;
+ int i;
+
+ if (!iface->conf->ieee80211h || !mode ||
+ mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ half_width = 10;
+ break;
+ case CHAN_WIDTH_40:
+ half_width = 20;
+ break;
+ case CHAN_WIDTH_80:
+ case CHAN_WIDTH_80P80:
+ half_width = 40;
+ break;
+ case CHAN_WIDTH_160:
+ half_width = 80;
+ break;
+ default:
+ wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported",
+ width);
+ return 0;
+ }
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+
+ if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+ continue;
+
+ if (center_freq - chan->freq < half_width &&
+ chan->freq - center_freq < half_width)
+ res++;
+ }
+
+ wpa_printf(MSG_DEBUG, "DFS: (%d, %d): in range: %s",
+ center_freq - half_width, center_freq + half_width,
+ res ? "yes" : "no");
+
+ return res;
+}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index f0fa6f6..606c1b3 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -25,9 +25,12 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
int ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2);
int hostapd_is_dfs_required(struct hostapd_iface *iface);
+int hostapd_is_dfs_chan_available(struct hostapd_iface *iface);
int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2);
int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
+int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+ int center_freq);
#endif /* DFS_H */
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index ed37fc8..edc77da 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -39,22 +39,22 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
const u8 *end, *pos;
int res, msgtype = 0, prefixlen = 32;
u32 subnet_mask = 0;
- u16 tot_len;
+ u16 ip_len;
exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
if (exten_len < 4)
return;
b = (const struct bootp_pkt *) &buf[ETH_HLEN];
- tot_len = ntohs(b->iph.tot_len);
- if (tot_len > (unsigned int) (len - ETH_HLEN))
+ ip_len = ntohs(b->iph.ip_len);
+ if (ip_len > (unsigned int) (len - ETH_HLEN))
return;
if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
return;
/* Parse DHCP options */
- end = (const u8 *) b + tot_len;
+ end = (const u8 *) b + ip_len;
pos = &b->exten[4];
while (pos < end && *pos != DHCP_OPT_END) {
const u8 *opt = pos++;
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 085d423..6772a87 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -1,6 +1,7 @@
/*
* hostapd / DPP integration
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -25,6 +26,13 @@ static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
+#ifdef CONFIG_DPP2
+static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf);
+#endif /* CONFIG_DPP2 */
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -58,10 +66,97 @@ int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
wpabuf_len(hapd->dpp_auth->resp_msg));
}
+#ifdef CONFIG_DPP2
+ dpp_controller_new_qr_code(hapd->iface->interfaces->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
+ return bi->id;
+}
+
+
+/**
+ * hostapd_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
+ * @hapd: Pointer to hostapd_data
+ * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_bootstrap_info *bi;
+
+ bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, cmd);
+ if (!bi)
+ return -1;
+
return bi->id;
}
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Request");
+ return -1;
+ }
+
+ if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+ return -1;
+
+ return peer_bi->id;
+}
+
+
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
+
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Select");
+ return -1;
+ }
+
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer (NFC Handover Selector) used different curve");
+ return -1;
+ }
+
+ return peer_bi->id;
+}
+
+
static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx,
void *timeout_ctx)
{
@@ -153,6 +248,10 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
+#endif /* CONFIG_DPP2 */
hostapd_drv_send_action_cancel_wait(hapd);
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -394,12 +493,35 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
}
+#ifdef CONFIG_DPP2
+static int hostapd_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth)
+{
+ struct hostapd_data *hapd = ctx;
+ unsigned int i;
+
+ for (i = 0; i < auth->num_conf_obj; i++)
+ hostapd_dpp_handle_config_obj(hapd, auth,
+ &auth->conf_obj[i]);
+
+ return 0;
+}
+#endif /* CONFIG_DPP2 */
+
+
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
{
const char *pos;
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
+ struct dpp_authentication *auth;
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
unsigned int neg_freq = 0;
+ int tcp = 0;
+#ifdef CONFIG_DPP2
+ int tcp_port = DPP_TCP_PORT;
+ struct hostapd_ip_addr ipaddr;
+ char *addr;
+#endif /* CONFIG_DPP2 */
pos = os_strstr(cmd, " peer=");
if (!pos)
@@ -412,6 +534,25 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
return -1;
}
+#ifdef CONFIG_DPP2
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ tcp_port = atoi(pos);
+ }
+
+ addr = get_param(cmd, " tcp_addr=");
+ if (addr) {
+ int res;
+
+ res = hostapd_parse_ip_addr(addr, &ipaddr);
+ os_free(addr);
+ if (res)
+ return -1;
+ tcp = 1;
+ }
+#endif /* CONFIG_DPP2 */
+
pos = os_strstr(cmd, " own=");
if (pos) {
pos += 5;
@@ -449,36 +590,46 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
if (pos)
neg_freq = atoi(pos + 10);
- if (hapd->dpp_auth) {
+ if (!tcp && hapd->dpp_auth) {
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL);
+#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
+#endif /* CONFIG_DPP2 */
hostapd_drv_send_action_cancel_wait(hapd);
dpp_auth_deinit(hapd->dpp_auth);
}
- hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
- allowed_roles, neg_freq,
- hapd->iface->hw_features,
- hapd->iface->num_hw_features);
- if (!hapd->dpp_auth)
+ auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ peer_bi, own_bi, allowed_roles, neg_freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
+ if (!auth)
goto fail;
- hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- hapd->dpp_auth, cmd) < 0) {
- dpp_auth_deinit(hapd->dpp_auth);
- hapd->dpp_auth = NULL;
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth, cmd) < 0) {
+ dpp_auth_deinit(auth);
goto fail;
}
- hapd->dpp_auth->neg_freq = neg_freq;
+ auth->neg_freq = neg_freq;
if (!is_zero_ether_addr(peer_bi->mac_addr))
- os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
- ETH_ALEN);
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+#ifdef CONFIG_DPP2
+ if (tcp)
+ return dpp_tcp_init(hapd->iface->interfaces->dpp, auth,
+ &ipaddr, tcp_port, hapd->conf->dpp_name,
+ DPP_NETROLE_AP, hapd->msg_ctx, hapd,
+ hostapd_dpp_process_conf_obj);
+#endif /* CONFIG_DPP2 */
+ hapd->dpp_auth = auth;
return hostapd_dpp_auth_init_next(hapd);
fail:
return -1;
@@ -534,6 +685,10 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
MAC2STR(src));
+#ifdef CONFIG_DPP2
+ hostapd_dpp_chirp_stop(hapd);
+#endif /* CONFIG_DPP2 */
+
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
@@ -579,7 +734,8 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
}
hapd->dpp_auth_ok_on_ack = 0;
- hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
+ hapd->dpp_auth = dpp_auth_req_rx(hapd->iface->interfaces->dpp,
+ hapd->msg_ctx, hapd->dpp_allowed_roles,
hapd->dpp_qr_mutual,
peer_bi, own_bi, freq, hdr, buf, len);
if (!hapd->dpp_auth) {
@@ -587,8 +743,7 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
return;
}
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- hapd->dpp_auth,
+ if (dpp_set_configurator(hapd->dpp_auth,
hapd->dpp_configurator_params) < 0) {
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -624,7 +779,8 @@ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
* message. */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
conf->connector);
- } else if (conf->passphrase[0]) {
+ }
+ if (conf->passphrase[0]) {
char hex[64 * 2 + 1];
wpa_snprintf_hex(hex, sizeof(hex),
@@ -678,6 +834,33 @@ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
}
+static int hostapd_dpp_handle_key_pkg(struct hostapd_data *hapd,
+ struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+ int res;
+
+ if (!key)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+
+ while (key) {
+ res = dpp_configurator_from_backup(
+ hapd->iface->interfaces->dpp, key);
+ if (res < 0)
+ return -1;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+ res);
+ key = key->next;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
+}
+
+
static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_ap_result result,
const struct wpabuf *adv_proto,
@@ -722,6 +905,9 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
}
hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
+ if (hostapd_dpp_handle_key_pkg(hapd, auth->conf_key_pkg) < 0)
+ goto fail;
+
status = DPP_STATUS_OK;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_REJECT_CONFIG) {
@@ -768,7 +954,8 @@ static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd)
struct wpabuf *buf;
int res;
- buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name, 1,
+ buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name,
+ DPP_NETROLE_AP,
hapd->conf->dpp_mud_url, NULL);
if (!buf) {
wpa_printf(MSG_DEBUG,
@@ -1017,6 +1204,227 @@ static void hostapd_dpp_rx_conn_status_result(struct hostapd_data *hapd,
}
+static void
+hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(hapd->iface->interfaces->dpp,
+ r_bootstrap);
+ dpp_notify_chirp_received(hapd->msg_ctx,
+ peer_bi ? (int) peer_bi->id : -1,
+ src, freq, r_bootstrap);
+ if (!peer_bi) {
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, NULL,
+ r_bootstrap) == 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
+ return;
+ }
+
+ if (hapd->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
+ return;
+ }
+
+ auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ peer_bi, NULL, DPP_CAPAB_CONFIGURATOR, freq, NULL,
+ 0);
+ if (!auth)
+ return;
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth,
+ hapd->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ auth->neg_freq = freq;
+
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+ hapd->dpp_auth = auth;
+ if (hostapd_dpp_auth_init_next(hapd) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ }
+}
+
+
+static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout");
+ hostapd_dpp_listen_stop(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
+static void
+hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+ u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
+ struct dpp_configurator *conf;
+ struct dpp_authentication *auth;
+ unsigned int wait_time, max_wait_time;
+ u16 group;
+
+ if (hapd->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore Reconfig Announcement during ongoing Authentication");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement from " MACSTR,
+ MAC2STR(src));
+
+ csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
+ &csign_hash_len);
+ if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Configurator C-sign key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)",
+ csign_hash, csign_hash_len);
+ conf = dpp_configurator_find_kid(hapd->iface->interfaces->dpp,
+ csign_hash);
+ if (!conf) {
+ if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, NULL,
+ NULL) == 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching Configurator information found");
+ return;
+ }
+
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return;
+ }
+ group = WPA_GET_LE16(fcgroup);
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+ a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+ e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
+ auth = dpp_reconfig_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+ conf, freq, group, a_nonce, a_nonce_len,
+ e_id, e_id_len);
+ if (!auth)
+ return;
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (dpp_set_configurator(auth, hapd->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
+ return;
+ }
+
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ hapd->dpp_auth = auth;
+
+ hapd->dpp_in_response_listen = 0;
+ hapd->dpp_auth_ok_on_ack = 0;
+ wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
+ max_wait_time = hapd->dpp_resp_wait_time ?
+ hapd->dpp_resp_wait_time : 2000;
+ if (wait_time > max_wait_time)
+ wait_time = max_wait_time;
+ wait_time += 10; /* give the driver some extra time to complete */
+ eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
+ hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
+ wait_time -= 10;
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ);
+ if (hostapd_drv_send_action(hapd, freq, wait_time, src,
+ wpabuf_head(auth->reconfig_req_msg),
+ wpabuf_len(auth->reconfig_req_msg)) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ }
+}
+
+
+static void
+hostapd_dpp_rx_reconfig_auth_resp(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct dpp_authentication *auth = hapd->dpp_auth;
+ struct wpabuf *conf;
+
+ wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response from "
+ MACSTR, MAC2STR(src));
+
+ if (!auth || !auth->reconfig || !auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Reconfig Authentication in progress - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len);
+ if (!conf)
+ return;
+
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_CONF);
+ if (hostapd_drv_send_action(hapd, freq, 500, src,
+ wpabuf_head(conf), wpabuf_len(conf)) < 0) {
+ wpabuf_free(conf);
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
+ wpabuf_free(conf);
+}
+
#endif /* CONFIG_DPP2 */
@@ -1026,9 +1434,13 @@ static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
enum dpp_status_error status)
{
struct wpabuf *msg;
+ size_t len;
- msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
- 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector));
+ len = 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector);
+#ifdef CONFIG_DPP2
+ len += 5;
+#endif /* CONFIG_DPP2 */
+ msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP, len);
if (!msg)
return;
@@ -1101,6 +1513,15 @@ skip_status:
skip_connector:
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1) {
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, DPP_VERSION);
+ }
+#endif /* CONFIG_DPP2 */
+
wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
" status=%d", MAC2STR(src), status);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
@@ -1466,6 +1887,18 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
case DPP_PA_CONNECTION_STATUS_RESULT:
hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len);
break;
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ hostapd_dpp_rx_presence_announcement(hapd, src, hdr, buf, len,
+ freq);
+ break;
+ case DPP_PA_RECONFIG_ANNOUNCEMENT:
+ hostapd_dpp_rx_reconfig_announcement(hapd, src, hdr, buf, len,
+ freq);
+ break;
+ case DPP_PA_RECONFIG_AUTH_RESP:
+ hostapd_dpp_rx_reconfig_auth_resp(hapd, src, hdr, buf, len,
+ freq);
+ break;
#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
@@ -1495,7 +1928,7 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
struct wpabuf *resp;
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
- if (!auth || !auth->auth_success ||
+ if (!auth || (!auth->auth_success && !auth->reconfig_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,
@@ -1531,6 +1964,8 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
if (ok && auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
@@ -1560,14 +1995,13 @@ int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
int ret = -1;
char *curve = NULL;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(hapd->iface->interfaces->dpp, hapd->msg_ctx);
if (!auth)
return -1;
curve = get_param(cmd, " curve=");
hostapd_dpp_set_testing_options(hapd, auth);
- if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
- auth, cmd) == 0 &&
+ if (dpp_set_configurator(auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 1) == 0) {
hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
ret = 0;
@@ -1776,10 +2210,13 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
+ eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
+ hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL);
eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
NULL);
+ hostapd_dpp_chirp_stop(hapd);
#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -1788,3 +2225,359 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
os_free(hapd->dpp_configurator_params);
hapd->dpp_configurator_params = NULL;
}
+
+
+#ifdef CONFIG_DPP2
+
+int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_controller_config config;
+ const char *pos;
+
+ os_memset(&config, 0, sizeof(config));
+ config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
+ config.netrole = DPP_NETROLE_AP;
+ config.msg_ctx = hapd->msg_ctx;
+ config.cb_ctx = hapd;
+ config.process_conf_obj = hostapd_dpp_process_conf_obj;
+ if (cmd) {
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ config.tcp_port = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " role=");
+ if (pos) {
+ pos += 6;
+ if (os_strncmp(pos, "configurator", 12) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR;
+ else if (os_strncmp(pos, "enrollee", 8) == 0)
+ config.allowed_roles = DPP_CAPAB_ENROLLEE;
+ else if (os_strncmp(pos, "either", 6) == 0)
+ config.allowed_roles = DPP_CAPAB_CONFIGURATOR |
+ DPP_CAPAB_ENROLLEE;
+ else
+ return -1;
+ }
+
+ config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
+ }
+ config.configurator_params = hapd->dpp_configurator_params;
+ return dpp_controller_start(hapd->iface->interfaces->dpp, &config);
+}
+
+
+static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
+
+static void hostapd_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
+ hostapd_drv_send_action_cancel_wait(hapd);
+ hostapd_dpp_chirp_next(hapd, NULL);
+}
+
+
+static void hostapd_dpp_chirp_start(struct hostapd_data *hapd)
+{
+ struct wpabuf *msg;
+ int type;
+
+ msg = hapd->dpp_presence_announcement;
+ type = DPP_PA_PRESENCE_ANNOUNCEMENT;
+ wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", hapd->dpp_chirp_freq);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d",
+ MAC2STR(broadcast), hapd->dpp_chirp_freq, type);
+ if (hostapd_drv_send_action(
+ hapd, hapd->dpp_chirp_freq, 2000, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg)) < 0 ||
+ eloop_register_timeout(2, 0, hostapd_dpp_chirp_timeout,
+ hapd, NULL) < 0)
+ hostapd_dpp_chirp_stop(hapd);
+}
+
+
+static struct hostapd_hw_modes *
+dpp_get_mode(struct hostapd_data *hapd,
+ enum hostapd_hw_mode mode)
+{
+ struct hostapd_hw_modes *modes = hapd->iface->hw_features;
+ u16 num_modes = hapd->iface->num_hw_features;
+ u16 i;
+
+ for (i = 0; i < num_modes; i++) {
+ if (modes[i].mode != mode ||
+ !modes[i].num_channels || !modes[i].channels)
+ continue;
+ return &modes[i];
+ }
+
+ return NULL;
+}
+
+
+static void
+hostapd_dpp_chirp_scan_res_handler(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ struct wpa_scan_results *scan_res;
+ struct dpp_bootstrap_info *bi = hapd->dpp_chirp_bi;
+ unsigned int i;
+ struct hostapd_hw_modes *mode;
+ int c;
+
+ if (!bi)
+ return;
+
+ hapd->dpp_chirp_scan_done = 1;
+
+ scan_res = hostapd_driver_get_scan_results(hapd);
+
+ os_free(hapd->dpp_chirp_freqs);
+ hapd->dpp_chirp_freqs = NULL;
+
+ /* Channels from own bootstrapping info */
+ if (bi) {
+ for (i = 0; i < bi->num_freq; i++)
+ int_array_add_unique(&hapd->dpp_chirp_freqs,
+ bi->freq[i]);
+ }
+
+ /* Preferred chirping channels */
+ int_array_add_unique(&hapd->dpp_chirp_freqs, 2437);
+
+ mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211A);
+ if (mode) {
+ int chan44 = 0, chan149 = 0;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+ if (chan->freq == 5220)
+ chan44 = 1;
+ if (chan->freq == 5745)
+ chan149 = 1;
+ }
+ if (chan149)
+ int_array_add_unique(&hapd->dpp_chirp_freqs, 5745);
+ else if (chan44)
+ int_array_add_unique(&hapd->dpp_chirp_freqs, 5220);
+ }
+
+ mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211AD);
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR)) ||
+ chan->freq != 60480)
+ continue;
+ int_array_add_unique(&hapd->dpp_chirp_freqs, 60480);
+ break;
+ }
+ }
+
+ /* Add channels from scan results for APs that advertise Configurator
+ * Connectivity element */
+ for (i = 0; scan_res && i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ size_t ie_len = bss->ie_len;
+
+ if (!ie_len)
+ ie_len = bss->beacon_ie_len;
+ if (get_vendor_ie((const u8 *) (bss + 1), ie_len,
+ DPP_CC_IE_VENDOR_TYPE))
+ int_array_add_unique(&hapd->dpp_chirp_freqs,
+ bss->freq);
+ }
+
+ if (!hapd->dpp_chirp_freqs ||
+ eloop_register_timeout(0, 0, hostapd_dpp_chirp_next,
+ hapd, NULL) < 0)
+ hostapd_dpp_chirp_stop(hapd);
+
+ wpa_scan_results_free(scan_res);
+}
+
+
+static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ int i;
+
+ if (hapd->dpp_chirp_listen)
+ hostapd_dpp_listen_stop(hapd);
+
+ if (hapd->dpp_chirp_freq == 0) {
+ if (hapd->dpp_chirp_round % 4 == 0 &&
+ !hapd->dpp_chirp_scan_done) {
+ struct wpa_driver_scan_params params;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update channel list for chirping");
+ os_memset(&params, 0, sizeof(params));
+ ret = hostapd_driver_scan(hapd, &params);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to request a scan ret=%d (%s)",
+ ret, strerror(-ret));
+ hostapd_dpp_chirp_scan_res_handler(hapd->iface);
+ } else {
+ hapd->iface->scan_cb =
+ hostapd_dpp_chirp_scan_res_handler;
+ }
+ return;
+ }
+ hapd->dpp_chirp_freq = hapd->dpp_chirp_freqs[0];
+ hapd->dpp_chirp_round++;
+ wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
+ hapd->dpp_chirp_round);
+ } else {
+ for (i = 0; hapd->dpp_chirp_freqs[i]; i++)
+ if (hapd->dpp_chirp_freqs[i] == hapd->dpp_chirp_freq)
+ break;
+ if (!hapd->dpp_chirp_freqs[i]) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Previous chirp freq %d not found",
+ hapd->dpp_chirp_freq);
+ return;
+ }
+ i++;
+ if (hapd->dpp_chirp_freqs[i]) {
+ hapd->dpp_chirp_freq = hapd->dpp_chirp_freqs[i];
+ } else {
+ hapd->dpp_chirp_iter--;
+ if (hapd->dpp_chirp_iter <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Chirping iterations completed");
+ hostapd_dpp_chirp_stop(hapd);
+ return;
+ }
+ hapd->dpp_chirp_freq = 0;
+ hapd->dpp_chirp_scan_done = 0;
+ if (eloop_register_timeout(30, 0,
+ hostapd_dpp_chirp_next,
+ hapd, NULL) < 0) {
+ hostapd_dpp_chirp_stop(hapd);
+ return;
+ }
+ if (hapd->dpp_chirp_listen) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Listen on %d MHz during chirp 30 second wait",
+ hapd->dpp_chirp_listen);
+ /* TODO: start listen on the channel */
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait 30 seconds before starting the next chirping round");
+ }
+ return;
+ }
+ }
+
+ hostapd_dpp_chirp_start(hapd);
+}
+
+
+int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd)
+{
+ const char *pos;
+ int iter = 1, listen_freq = 0;
+ struct dpp_bootstrap_info *bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos));
+ if (!bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not found");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " listen=");
+ if (pos) {
+ listen_freq = atoi(pos + 8);
+ if (listen_freq <= 0)
+ return -1;
+ }
+
+ hostapd_dpp_chirp_stop(hapd);
+ hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ hapd->dpp_qr_mutual = 0;
+ hapd->dpp_chirp_bi = bi;
+ hapd->dpp_presence_announcement = dpp_build_presence_announcement(bi);
+ if (!hapd->dpp_presence_announcement)
+ return -1;
+ hapd->dpp_chirp_iter = iter;
+ hapd->dpp_chirp_round = 0;
+ hapd->dpp_chirp_scan_done = 0;
+ hapd->dpp_chirp_listen = listen_freq;
+
+ return eloop_register_timeout(0, 0, hostapd_dpp_chirp_next, hapd, NULL);
+}
+
+
+void hostapd_dpp_chirp_stop(struct hostapd_data *hapd)
+{
+ if (hapd->dpp_presence_announcement) {
+ hostapd_drv_send_action_cancel_wait(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
+ }
+ hapd->dpp_chirp_bi = NULL;
+ wpabuf_free(hapd->dpp_presence_announcement);
+ hapd->dpp_presence_announcement = NULL;
+ if (hapd->dpp_chirp_listen)
+ hostapd_dpp_listen_stop(hapd);
+ hapd->dpp_chirp_listen = 0;
+ hapd->dpp_chirp_freq = 0;
+ os_free(hapd->dpp_chirp_freqs);
+ hapd->dpp_chirp_freqs = NULL;
+ eloop_cancel_timeout(hostapd_dpp_chirp_next, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_chirp_timeout, hapd, NULL);
+ if (hapd->iface->scan_cb == hostapd_dpp_chirp_scan_res_handler) {
+ /* TODO: abort ongoing scan */
+ hapd->iface->scan_cb = NULL;
+ }
+}
+
+
+static int handle_dpp_remove_bi(struct hostapd_iface *iface, void *ctx)
+{
+ struct dpp_bootstrap_info *bi = ctx;
+ size_t i;
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+
+ if (bi == hapd->dpp_chirp_bi)
+ hostapd_dpp_chirp_stop(hapd);
+ }
+
+ return 0;
+}
+
+
+void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
+{
+ struct hapd_interfaces *interfaces = ctx;
+
+ hostapd_for_each_interface(interfaces, handle_dpp_remove_bi, bi);
+}
+
+#endif /* CONFIG_DPP2 */
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index c1ec5d7..264d3e4 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -1,6 +1,7 @@
/*
* hostapd / DPP integration
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,7 +10,12 @@
#ifndef DPP_HOSTAPD_H
#define DPP_HOSTAPD_H
+struct dpp_bootstrap_info;
+
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
@@ -35,4 +41,9 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd);
void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
+int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd);
+int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
+void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
+void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
+
#endif /* DPP_HOSTAPD_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 3198bd5..9af5445 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -17,6 +17,7 @@
#include "common/wpa_ctrl.h"
#include "common/dpp.h"
#include "common/sae.h"
+#include "common/hw_features_common.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -104,18 +105,45 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
+static bool check_sa_query_need(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if ((sta->flags &
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
+ return false;
+
+ if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+
+ if (!sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA Query timeout
+ * has not been reached. Reject the association attempt
+ * temporarily and start SA Query, if one is not pending.
+ */
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+ return true;
+ }
+
+ return false;
+}
+
+
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *req_ies, size_t req_ies_len, int reassoc)
{
struct sta_info *sta;
- int new_assoc, res;
+ int new_assoc;
+ enum wpa_validate_result res;
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
u16 reason = WLAN_REASON_UNSPECIFIED;
- u16 status = WLAN_STATUS_SUCCESS;
+ int status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
if (addr == NULL) {
@@ -219,7 +247,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#endif /* CONFIG_P2P */
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
if (elems.ht_capabilities &&
(hapd->iface->conf->ht_capab &
@@ -233,7 +260,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
ht40_intolerant_add(hapd->iface, sta);
}
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_INTERWORKING
if (elems.ext_capab && elems.ext_capab_len > 4) {
@@ -293,6 +319,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
struct wpabuf *wps;
+ if (check_sa_query_need(hapd, sta)) {
+ status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
+ p = hostapd_eid_assoc_comeback_time(hapd, sta,
+ p);
+
+ hostapd_sta_assoc(hapd, addr, reassoc, status,
+ buf, p - buf);
+ return 0;
+ }
+
sta->flags |= WLAN_STA_WPS;
wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE);
@@ -324,52 +361,71 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
- if (res != WPA_IE_OK) {
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ switch (res) {
+ case WPA_IE_OK:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_SUCCESS;
+ break;
+ case WPA_INVALID_IE:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_GROUP:
+ reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ break;
+ case WPA_INVALID_PAIRWISE:
+ reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ break;
+ case WPA_INVALID_AKMP:
+ reason = WLAN_REASON_AKMP_NOT_VALID;
+ status = WLAN_STATUS_AKMP_NOT_VALID;
+ break;
+ case WPA_NOT_ENABLED:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_ALLOC_FAIL:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ break;
+ case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_MGMT_GROUP_CIPHER:
+ reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
+ status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+ break;
+ case WPA_INVALID_MDIE:
+ reason = WLAN_REASON_INVALID_MDE;
+ status = WLAN_STATUS_INVALID_MDIE;
+ break;
+ case WPA_INVALID_PROTO:
+ reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ break;
+ case WPA_INVALID_PMKID:
+ reason = WLAN_REASON_INVALID_PMKID;
+ status = WLAN_STATUS_INVALID_PMKID;
+ break;
+ case WPA_DENIED_OTHER_REASON:
+ reason = WLAN_REASON_UNSPECIFIED;
+ status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ break;
+ }
+ if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG,
"WPA/RSN information element rejected? (res %u)",
res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
- if (res == WPA_INVALID_GROUP) {
- reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
- status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- } else if (res == WPA_INVALID_PAIRWISE) {
- reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
- status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- } else if (res == WPA_INVALID_AKMP) {
- reason = WLAN_REASON_AKMP_NOT_VALID;
- status = WLAN_STATUS_AKMP_NOT_VALID;
- } else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
- reason = WLAN_REASON_INVALID_IE;
- status = WLAN_STATUS_INVALID_IE;
- } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
- reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
- status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
- } else {
- reason = WLAN_REASON_INVALID_IE;
- status = WLAN_STATUS_INVALID_IE;
- }
goto fail;
}
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- sta->sa_query_count > 0)
- ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- (sta->auth_alg != WLAN_AUTH_FT)) {
- /*
- * STA has already been associated with MFP and SA
- * Query timeout has not been reached. Reject the
- * association attempt temporarily and start SA Query,
- * if one is not pending.
- */
-
- if (sta->sa_query_count == 0)
- ap_sta_start_sa_query(hapd, sta);
-
+ if (check_sa_query_need(hapd, sta)) {
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
@@ -402,7 +458,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
#ifdef CONFIG_SAE
if (hapd->conf->sae_pwe == 2 &&
sta->auth_alg == WLAN_AUTH_SAE &&
- sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ sta->sae && !sta->sae->h2e &&
elems.rsnxe && elems.rsnxe_len >= 1 &&
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
wpa_printf(MSG_INFO, "SAE: " MACSTR
@@ -465,6 +521,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
}
+#ifdef CONFIG_WPS
+skip_wpa_check:
+#endif /* CONFIG_WPS */
#ifdef CONFIG_MBO
if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
@@ -476,13 +535,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#endif /* CONFIG_MBO */
-#ifdef CONFIG_WPS
-skip_wpa_check:
-#endif /* CONFIG_WPS */
-
#ifdef CONFIG_IEEE80211R_AP
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
- sta->auth_alg, req_ies, req_ies_len);
+ sta->auth_alg, req_ies, req_ies_len,
+ !elems.rsnxe);
if (!p) {
wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -569,22 +625,24 @@ skip_wpa_check:
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
elems.owe_dh) {
u8 *npos;
+ u16 ret_status;
npos = owe_assoc_req_process(hapd, sta,
elems.owe_dh, elems.owe_dh_len,
p, sizeof(buf) - (p - buf),
- &reason);
+ &ret_status);
+ status = ret_status;
if (npos)
p = npos;
+
if (!npos &&
- reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
- status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
- hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
+ status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
+ hostapd_sta_assoc(hapd, addr, reassoc, ret_status, buf,
p - buf);
return 0;
}
- if (!npos || reason != WLAN_STATUS_SUCCESS)
+ if (!npos || status != WLAN_STATUS_SUCCESS)
goto fail;
}
#endif /* CONFIG_OWE */
@@ -621,6 +679,11 @@ skip_wpa_check:
pfs_fail:
#endif /* CONFIG_DPP2 */
+ if (elems.rrm_enabled &&
+ elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+ os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+ sizeof(sta->rrm_enabled_capa));
+
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
@@ -667,7 +730,8 @@ skip_wpa_check:
fail:
#ifdef CONFIG_IEEE80211R_AP
- hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+ if (status >= 0)
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#endif /* CONFIG_IEEE80211R_AP */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta);
@@ -705,6 +769,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -798,8 +863,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2,
int finished)
{
- /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
-
#ifdef NEED_AP_MLME
int channel, chwidth, is_dfs;
u8 seg0_idx = 0, seg1_idx = 0;
@@ -849,9 +912,18 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
switch (hapd->iface->current_mode->mode) {
case HOSTAPD_MODE_IEEE80211A:
- if (cf1 > 5000)
+ if (cf1 == 5935)
+ seg0_idx = (cf1 - 5925) / 5;
+ else if (cf1 > 5950)
+ seg0_idx = (cf1 - 5950) / 5;
+ else if (cf1 > 5000)
seg0_idx = (cf1 - 5000) / 5;
- if (cf2 > 5000)
+
+ if (cf2 == 5935)
+ seg1_idx = (cf2 - 5925) / 5;
+ else if (cf2 > 5950)
+ seg1_idx = (cf2 - 5950) / 5;
+ else if (cf2 > 5000)
seg1_idx = (cf2 - 5000) / 5;
break;
default:
@@ -902,10 +974,39 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
+ } else if (is_dfs &&
+ hostapd_is_dfs_required(hapd->iface) &&
+ !hostapd_is_dfs_chan_available(hapd->iface) &&
+ !hapd->iface->cac_started) {
+ hostapd_disable_iface(hapd->iface);
+ hostapd_enable_iface(hapd->iface);
}
for (i = 0; i < hapd->iface->num_bss; i++)
hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
+
+#ifdef CONFIG_OCV
+ if (hapd->conf->ocv) {
+ struct sta_info *sta;
+ bool check_sa_query = false;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (wpa_auth_uses_ocv(sta->wpa_sm) &&
+ !(sta->flags & WLAN_STA_WNM_SLEEP_MODE)) {
+ sta->post_csa_sa_query = 1;
+ check_sa_query = true;
+ }
+ }
+
+ if (check_sa_query) {
+ wpa_printf(MSG_DEBUG,
+ "OCV: Check post-CSA SA Query initiation in 15 seconds");
+ eloop_register_timeout(15, 0,
+ hostapd_ocv_check_csa_sa_query,
+ hapd, NULL);
+ }
+ }
+#endif /* CONFIG_OCV */
#endif /* NEED_AP_MLME */
}
@@ -932,6 +1033,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
{
int ret, i;
int err = 0;
+ struct hostapd_channel_data *pri_chan;
if (hapd->iconf->channel) {
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@@ -939,12 +1041,20 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
return;
}
+ hapd->iface->freq = acs_res->pri_freq;
+
if (!hapd->iface->current_mode) {
for (i = 0; i < hapd->iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode =
&hapd->iface->hw_features[i];
if (mode->mode == acs_res->hw_mode) {
+ if (hapd->iface->freq > 0 &&
+ !hw_get_chan(mode->mode,
+ hapd->iface->freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features))
+ continue;
hapd->iface->current_mode = mode;
break;
}
@@ -958,24 +1068,33 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
}
}
- hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
-
- if (!acs_res->pri_channel) {
+ if (!acs_res->pri_freq) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
err = 1;
goto out;
}
+ pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode,
+ acs_res->pri_freq, NULL,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
+ if (!pri_chan) {
+ wpa_printf(MSG_ERROR,
+ "ACS: Could not determine primary channel number from pri_freq %u",
+ acs_res->pri_freq);
+ err = 1;
+ goto out;
+ }
- hapd->iconf->channel = acs_res->pri_channel;
+ hapd->iconf->channel = pri_chan->chan;
hapd->iconf->acs = 1;
- if (acs_res->sec_channel == 0)
+ if (acs_res->sec_freq == 0)
hapd->iconf->secondary_channel = 0;
- else if (acs_res->sec_channel < acs_res->pri_channel)
+ else if (acs_res->sec_freq < acs_res->pri_freq)
hapd->iconf->secondary_channel = -1;
- else if (acs_res->sec_channel > acs_res->pri_channel)
+ else if (acs_res->sec_freq > acs_res->pri_freq)
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
@@ -983,32 +1102,35 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
goto out;
}
+ hapd->iconf->edmg_channel = acs_res->edmg_channel;
+
if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
/* set defaults for backwards compatibility */
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) {
- 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) {
+ if (acs_res->ch_width == 40) {
+ if (is_6ghz_freq(acs_res->pri_freq))
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf,
acs_res->vht_seg0_center_ch);
+ } else if (acs_res->ch_width == 80) {
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg0_center_ch);
+ if (acs_res->vht_seg1_center_ch == 0) {
hostapd_set_oper_chwidth(hapd->iconf,
- CHANWIDTH_160MHZ);
+ CHANWIDTH_80MHZ);
} else {
- hostapd_set_oper_centr_freq_seg0_idx(
- hapd->iconf,
- acs_res->vht_seg0_center_ch);
+ hostapd_set_oper_chwidth(hapd->iconf,
+ CHANWIDTH_80P80MHZ);
hostapd_set_oper_centr_freq_seg1_idx(
hapd->iconf,
acs_res->vht_seg1_center_ch);
- hostapd_set_oper_chwidth(hapd->iconf,
- CHANWIDTH_80P80MHZ);
}
+ } else if (acs_res->ch_width == 160) {
+ hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ);
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg1_center_ch);
}
}
@@ -1404,15 +1526,33 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
#endif /* HOSTAPD */
+static struct hostapd_channel_data *
+hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq)
+{
+ int i;
+ struct hostapd_channel_data *chan;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+ if ((unsigned int) chan->freq == freq)
+ return chan;
+ }
+
+ return NULL;
+}
+
+
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
{
int i;
struct hostapd_channel_data *chan;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if ((unsigned int) chan->freq == freq)
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
+ continue;
+ chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
+ if (chan)
return chan;
}
diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c
index 6da514a..0310aab 100644
--- a/src/ap/fils_hlp.c
+++ b/src/ap/fils_hlp.c
@@ -158,7 +158,7 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
ssize_t res;
u8 msgtype = 0;
int rapid_commit = 0;
- struct iphdr *iph;
+ struct ip *iph;
struct udphdr *udph;
struct wpabuf *resp;
const u8 *rpos;
@@ -259,14 +259,14 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
wpabuf_put_be16(resp, ETH_P_IP);
iph = wpabuf_put(resp, sizeof(*iph));
- iph->version = 4;
- iph->ihl = sizeof(*iph) / 4;
- iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
- iph->ttl = 1;
- iph->protocol = 17; /* UDP */
- iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
- iph->daddr = dhcp->client_ip;
- iph->check = ip_checksum(iph, sizeof(*iph));
+ iph->ip_v = 4;
+ iph->ip_hl = sizeof(*iph) / 4;
+ iph->ip_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
+ iph->ip_ttl = 1;
+ iph->ip_p = 17; /* UDP */
+ iph->ip_src.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ iph->ip_dst.s_addr = dhcp->client_ip;
+ iph->ip_sum = ip_checksum(iph, sizeof(*iph));
udph = wpabuf_put(resp, sizeof(*udph));
udph->uh_sport = htons(DHCP_SERVER_PORT);
udph->uh_dport = htons(DHCP_CLIENT_PORT);
@@ -479,13 +479,13 @@ static int fils_process_hlp_udp(struct hostapd_data *hapd,
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
- const struct iphdr *iph;
+ const struct ip *iph;
const struct udphdr *udph;
u16 sport, dport, ulen;
if (len < sizeof(*iph) + sizeof(*udph))
return 0;
- iph = (const struct iphdr *) pos;
+ iph = (const struct ip *) pos;
udph = (const struct udphdr *) (iph + 1);
sport = ntohs(udph->uh_sport);
dport = ntohs(udph->uh_dport);
@@ -510,24 +510,24 @@ static int fils_process_hlp_ip(struct hostapd_data *hapd,
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
- const struct iphdr *iph;
- u16 tot_len;
+ const struct ip *iph;
+ uint16_t ip_len;
if (len < sizeof(*iph))
return 0;
- iph = (const struct iphdr *) pos;
+ iph = (const struct ip *) pos;
if (ip_checksum(iph, sizeof(*iph)) != 0) {
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4 packet had invalid header checksum - dropped");
return 0;
}
- tot_len = ntohs(iph->tot_len);
- if (tot_len > len)
+ ip_len = ntohs(iph->ip_len);
+ if (ip_len > len)
return 0;
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
- iph->saddr, iph->daddr, iph->protocol);
- switch (iph->protocol) {
+ iph->ip_src.s_addr, iph->ip_dst.s_addr, iph->ip_p);
+ switch (iph->ip_p) {
case 17:
return fils_process_hlp_udp(hapd, sta, dst, pos, len);
}
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 9567e20..90f1577 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1555,11 +1555,14 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
di->prot = prot;
di->sd_resp = buf;
di->sd_resp_pos = 0;
+ di->dpp = 1;
tx_buf = gas_build_initial_resp(
dialog_token, WLAN_STATUS_SUCCESS,
- comeback_delay, 10);
- if (tx_buf)
+ comeback_delay, 10 + 2);
+ if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_le16(tx_buf, 0);
+ }
}
} else {
wpa_printf(MSG_DEBUG,
@@ -1782,9 +1785,10 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
tx_buf = gas_build_comeback_resp(dialog_token,
WLAN_STATUS_SUCCESS,
dialog->sd_frag_id, more, 0,
- 10 + frag_len);
+ 10 + 2 + frag_len);
if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf);
+ wpabuf_put_le16(tx_buf, frag_len);
wpabuf_put_buf(tx_buf, buf);
}
} else
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3686438..b37f49f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/crc32.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/hw_features_common.h"
@@ -57,8 +58,10 @@
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
+#ifdef CONFIG_WEP
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+#endif /* CONFIG_WEP */
static int setup_interface2(struct hostapd_iface *iface);
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
@@ -73,6 +76,8 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
int ret;
for (i = 0; i < interfaces->count; i++) {
+ if (!interfaces->iface[i])
+ continue;
ret = cb(interfaces->iface[i], ctx);
if (ret)
return ret;
@@ -88,7 +93,9 @@ void hostapd_reconfig_encryption(struct hostapd_data *hapd)
return;
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
}
@@ -141,7 +148,9 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
wpa_deinit(hapd->wpa_auth);
hapd->wpa_auth = NULL;
hostapd_set_privacy(hapd, 0);
+#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd);
+#endif /* CONFIG_WEP */
hostapd_set_generic_elem(hapd, (u8 *) "", 0);
}
@@ -169,7 +178,9 @@ static void hostapd_clear_old(struct hostapd_iface *iface)
for (j = 0; j < iface->num_bss; j++) {
hostapd_flush_old_stations(iface->bss[j],
WLAN_REASON_PREV_AUTH_NOT_VALID);
+#ifdef CONFIG_WEP
hostapd_broadcast_wep_clear(iface->bss[j]);
+#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_RADIUS
/* TODO: update dynamic data based on changed configuration
@@ -283,6 +294,8 @@ int hostapd_reload_config(struct hostapd_iface *iface)
}
+#ifdef CONFIG_WEP
+
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
const char *ifname)
{
@@ -291,8 +304,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
if (!ifname || !hapd->drv_priv)
return;
for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
- 0, NULL, 0, NULL, 0)) {
+ if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0,
+ 0, NULL, 0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear default "
"encryption keys (ifname=%s keyidx=%d)",
ifname, i);
@@ -301,8 +314,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
if (hapd->conf->ieee80211w) {
for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
- NULL, i, 0, NULL,
- 0, NULL, 0)) {
+ NULL, i, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear "
"default mgmt encryption keys "
"(ifname=%s keyidx=%d)", ifname, i);
@@ -325,11 +338,12 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
struct hostapd_ssid *ssid = &hapd->conf->ssid;
idx = ssid->wep.idx;
- if (ssid->wep.default_len &&
+ if (ssid->wep.default_len && ssid->wep.key[idx] &&
hostapd_drv_set_key(hapd->conf->iface,
- hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
+ hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0,
1, NULL, 0, ssid->wep.key[idx],
- ssid->wep.len[idx])) {
+ ssid->wep.len[idx],
+ KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
errors++;
}
@@ -337,6 +351,8 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
return errors;
}
+#endif /* CONFIG_WEP */
+
static void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
@@ -423,6 +439,10 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
hostapd_clean_rrm(hapd);
fils_hlp_deinit(hapd);
+#ifdef CONFIG_OCV
+ eloop_cancel_timeout(hostapd_ocv_check_csa_sa_query, hapd, NULL);
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_SAE
{
struct hostapd_sae_commit_queue *q;
@@ -479,11 +499,9 @@ static void sta_track_deinit(struct hostapd_iface *iface)
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface);
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
if (iface->current_mode)
acs_cleanup(iface);
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
@@ -524,6 +542,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
}
+#ifdef CONFIG_WEP
+
static void hostapd_clear_wep(struct hostapd_data *hapd)
{
if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
@@ -552,10 +572,13 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
for (i = 0; i < 4; i++) {
if (hapd->conf->ssid.wep.key[i] &&
- hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
+ hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 0,
i == hapd->conf->ssid.wep.idx, NULL, 0,
hapd->conf->ssid.wep.key[i],
- hapd->conf->ssid.wep.len[i])) {
+ hapd->conf->ssid.wep.len[i],
+ i == hapd->conf->ssid.wep.idx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX)) {
wpa_printf(MSG_WARNING, "Could not set WEP "
"encryption.");
return -1;
@@ -568,6 +591,8 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
return 0;
}
+#endif /* CONFIG_WEP */
+
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
{
@@ -603,7 +628,9 @@ static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
{
hostapd_free_stas(hapd);
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+#ifdef CONFIG_WEP
hostapd_clear_wep(hapd);
+#endif /* CONFIG_WEP */
}
@@ -1154,13 +1181,15 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
#endif /* CONFIG_MESH */
if (flush_old_stations)
- hostapd_flush_old_stations(hapd,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ hostapd_flush(hapd);
hostapd_set_privacy(hapd, 0);
- hostapd_broadcast_wep_clear(hapd);
+#ifdef CONFIG_WEP
+ if (!hostapd_drv_nl80211(hapd))
+ hostapd_broadcast_wep_clear(hapd);
if (hostapd_setup_encryption(conf->iface, hapd))
return -1;
+#endif /* CONFIG_WEP */
/*
* Fetch the SSID from the system and use it or,
@@ -1190,8 +1219,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
}
+ /*
+ * Short SSID calculation is identical to FCS and it is defined in
+ * IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID).
+ */
+ conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len);
+
if (!hostapd_drv_none(hapd)) {
- wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
+ wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR
" and ssid \"%s\"",
conf->iface, MAC2STR(hapd->own_addr),
wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
@@ -1340,6 +1375,21 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
return -1;
+ if (flush_old_stations && !conf->start_disabled &&
+ conf->broadcast_deauth) {
+ u8 addr[ETH_ALEN];
+
+ /* Should any previously associated STA not have noticed that
+ * the AP had stopped and restarted, send one more
+ * deauthentication notification now that the AP is ready to
+ * operate. */
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "Deauthenticate all stations at BSS start");
+ os_memset(addr, 0xff, ETH_ALEN);
+ hostapd_drv_sta_deauth(hapd, addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ }
+
if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
return -1;
@@ -1572,6 +1622,51 @@ static int setup_interface(struct hostapd_iface *iface)
}
+static int configured_fixed_chan_to_freq(struct hostapd_iface *iface)
+{
+ int freq, i, j;
+
+ if (!iface->conf->channel)
+ return 0;
+ if (iface->conf->op_class) {
+ freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
+ iface->conf->channel);
+ if (freq < 0) {
+ wpa_printf(MSG_INFO,
+ "Could not convert op_class %u channel %u to operating frequency",
+ iface->conf->op_class, iface->conf->channel);
+ return -1;
+ }
+ iface->freq = freq;
+ return 0;
+ }
+
+ /* Old configurations using only 2.4/5/60 GHz bands may not specify the
+ * op_class parameter. Select a matching channel from the configured
+ * mode using the channel parameter for these cases.
+ */
+ for (j = 0; j < iface->num_hw_features; j++) {
+ struct hostapd_hw_modes *mode = &iface->hw_features[j];
+
+ if (iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
+ iface->conf->hw_mode != mode->mode)
+ continue;
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+
+ if (chan->chan == iface->conf->channel &&
+ !is_6ghz_freq(chan->freq)) {
+ iface->freq = chan->freq;
+ return 0;
+ }
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Could not determine operating frequency");
+ return -1;
+}
+
+
static int setup_interface2(struct hostapd_iface *iface)
{
iface->wait_channel_update = 0;
@@ -1580,7 +1675,20 @@ static int setup_interface2(struct hostapd_iface *iface)
/* Not all drivers support this yet, so continue without hw
* feature data. */
} else {
- int ret = hostapd_select_hw_mode(iface);
+ int ret;
+
+ ret = configured_fixed_chan_to_freq(iface);
+ if (ret < 0)
+ goto fail;
+
+ if (iface->conf->op_class) {
+ int ch_width;
+
+ ch_width = op_class_to_ch_width(iface->conf->op_class);
+ hostapd_set_oper_chwidth(iface->conf, ch_width);
+ }
+
+ ret = hostapd_select_hw_mode(iface);
if (ret < 0) {
wpa_printf(MSG_ERROR, "Could not select hw_mode and "
"channel. (%d)", ret);
@@ -1685,7 +1793,7 @@ static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr,
static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct sta_info *s = (struct sta_info *) *get_ctx;
@@ -1707,7 +1815,7 @@ static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
static const u8 * fst_hostapd_get_peer_first(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
struct hostapd_data *hapd = ctx;
@@ -1719,7 +1827,7 @@ static const u8 * fst_hostapd_get_peer_first(void *ctx,
static const u8 * fst_hostapd_get_peer_next(void *ctx,
struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+ bool mb_only)
{
return fst_hostapd_get_sta(get_ctx, mb_only);
}
@@ -1807,6 +1915,13 @@ static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
if (!bss->conf->owe_transition_ifname[0])
continue;
+ if (bss->iface->state != HAPD_IFACE_ENABLED) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Interface %s state %s - defer beacon update",
+ bss->conf->iface,
+ hostapd_state_text(bss->iface->state));
+ continue;
+ }
res = hostapd_owe_trans_get_info(bss);
if (res == 0)
continue;
@@ -1864,12 +1979,11 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
goto fail;
wpa_printf(MSG_DEBUG, "Completing interface initialization");
- if (iface->conf->channel) {
+ if (iface->freq) {
#ifdef NEED_AP_MLME
int res;
#endif /* NEED_AP_MLME */
- iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
"Frequency: %d MHz",
hostapd_hw_mode_txt(iface->conf->hw_mode),
@@ -2281,12 +2395,10 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
hostapd_bss_deinit(iface->bss[j]);
}
-#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface);
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
#endif /* NEED_AP_MLME */
-#endif /* CONFIG_IEEE80211N */
}
@@ -3050,6 +3162,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
hostapd_prune_associations(hapd, sta->addr);
ap_sta_clear_disconnect_timeouts(hapd, sta);
+ sta->post_csa_sa_query = 0;
#ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
@@ -3561,3 +3674,25 @@ void hostapd_periodic_iface(struct hostapd_iface *iface)
#endif /* CONFIG_NO_RADIUS */
}
}
+
+
+#ifdef CONFIG_OCV
+void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG, "OCV: Post-CSA SA Query initiation check");
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->post_csa_sa_query)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "OCV: OCVC STA " MACSTR
+ " did not start SA Query after CSA - disconnect",
+ MAC2STR(sta->addr));
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ }
+}
+#endif /* CONFIG_OCV */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 2358d16..b70d13f 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -38,6 +38,10 @@ union wps_event_data;
struct mesh_conf;
#endif /* CONFIG_MESH */
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define CTRL_IFACE_COOKIE_LEN 8
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
struct hostapd_iface;
struct hapd_interfaces {
@@ -72,6 +76,11 @@ struct hapd_interfaces {
#ifdef CONFIG_DPP
struct dpp_global *dpp;
#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
};
enum hostapd_chan_status {
@@ -340,6 +349,11 @@ struct hostapd_data {
int last_igtk_key_idx;
u8 last_igtk[WPA_IGTK_MAX_LEN];
size_t last_igtk_len;
+
+ enum wpa_alg last_bigtk_alg;
+ int last_bigtk_key_idx;
+ u8 last_bigtk[WPA_BIGTK_MAX_LEN];
+ size_t last_bigtk_len;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO
@@ -377,6 +391,16 @@ struct hostapd_data {
unsigned int dpp_resp_wait_time;
unsigned int dpp_resp_max_tries;
unsigned int dpp_resp_retry_time;
+#ifdef CONFIG_DPP2
+ struct wpabuf *dpp_presence_announcement;
+ struct dpp_bootstrap_info *dpp_chirp_bi;
+ int dpp_chirp_freq;
+ int *dpp_chirp_freqs;
+ int dpp_chirp_iter;
+ int dpp_chirp_round;
+ int dpp_chirp_scan_done;
+ int dpp_chirp_listen;
+#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
char *dpp_discovery_override;
@@ -395,6 +419,10 @@ struct hostapd_data {
#ifdef CONFIG_SQLITE
sqlite3 *rad_attr_db;
#endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+ unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
};
@@ -462,9 +490,7 @@ struct hostapd_iface {
struct ap_info *ap_hash[STA_HASH_SIZE];
u64 drv_flags;
-
- /* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
- unsigned int smps_modes;
+ u64 drv_flags2;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -606,6 +632,7 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
+void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 2fefaf8..f6e6903 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -224,16 +224,27 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
}
-#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
- int pri_chan, sec_chan;
+ int pri_freq, sec_freq;
+ struct hostapd_channel_data *p_chan, *s_chan;
- pri_chan = iface->conf->channel;
- sec_chan = pri_chan + iface->conf->secondary_channel * 4;
+ pri_freq = iface->freq;
+ sec_freq = pri_freq + iface->conf->secondary_channel * 20;
+
+ if (!iface->current_mode)
+ return 0;
+
+ p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
- return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
- sec_chan);
+ s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
+
+ return allowed_ht40_channel_pair(iface->current_mode->mode,
+ p_chan, s_chan);
}
@@ -241,9 +252,11 @@ static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
{
if (iface->conf->secondary_channel > 0) {
iface->conf->channel += 4;
+ iface->freq += 20;
iface->conf->secondary_channel = -1;
} else {
iface->conf->channel -= 4;
+ iface->freq -= 20;
iface->conf->secondary_channel = 1;
}
}
@@ -252,13 +265,23 @@ static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
- int pri_chan, sec_chan;
+ unsigned int pri_freq, sec_freq;
int res;
+ struct hostapd_channel_data *pri_chan, *sec_chan;
- pri_chan = iface->conf->channel;
- sec_chan = pri_chan + iface->conf->secondary_channel * 4;
+ pri_freq = iface->freq;
+ sec_freq = pri_freq + iface->conf->secondary_channel * 20;
+
+ if (!iface->current_mode)
+ return 0;
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq,
+ NULL, iface->hw_features,
+ iface->num_hw_features);
+ sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq,
+ NULL, iface->hw_features,
+ iface->num_hw_features);
- res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
+ res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
if (res == 2) {
if (iface->conf->no_pri_sec_switch) {
@@ -352,7 +375,7 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
if (iface->current_mode == NULL)
return;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ pri_freq = iface->freq;
if (iface->conf->secondary_channel > 0)
sec_freq = pri_freq + 20;
else
@@ -397,7 +420,7 @@ static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
if (iface->current_mode == NULL)
return;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+ pri_freq = iface->freq;
if (iface->conf->secondary_channel > 0) {
affected_start = pri_freq - 10;
affected_end = pri_freq + 30;
@@ -537,26 +560,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
- switch (conf & HT_CAP_INFO_SMPS_MASK) {
- case HT_CAP_INFO_SMPS_STATIC:
- if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
- wpa_printf(MSG_ERROR,
- "Driver does not support configured HT capability [SMPS-STATIC]");
- return 0;
- }
- break;
- case HT_CAP_INFO_SMPS_DYNAMIC:
- if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
- wpa_printf(MSG_ERROR,
- "Driver does not support configured HT capability [SMPS-DYNAMIC]");
- return 0;
- }
- break;
- case HT_CAP_INFO_SMPS_DISABLED:
- default:
- break;
- }
-
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
!(hw & HT_CAP_INFO_GREEN_FIELD)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
@@ -663,13 +666,13 @@ static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface)
}
#endif /* CONFIG_IEEE80211AX */
-#endif /* CONFIG_IEEE80211N */
-
int hostapd_check_ht_capab(struct hostapd_iface *iface)
{
-#ifdef CONFIG_IEEE80211N
int ret;
+
+ if (is_6ghz_freq(iface->freq))
+ return 0;
if (!iface->conf->ieee80211n)
return 0;
@@ -698,7 +701,6 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
return ret;
if (!ieee80211n_allowed_ht40_channel_pair(iface))
return -1;
-#endif /* CONFIG_IEEE80211N */
return 0;
}
@@ -731,14 +733,15 @@ int hostapd_check_edmg_capab(struct hostapd_iface *iface)
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
- int channel, int primary)
+ int frequency, int primary)
{
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
- chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
+ chan = hw_get_channel_freq(iface->current_mode->mode, frequency, NULL,
+ iface->hw_features, iface->num_hw_features);
if (!chan)
return 0;
@@ -747,8 +750,8 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
return 1;
wpa_printf(MSG_INFO,
- "Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
- channel, primary ? "primary" : "secondary",
+ "Frequency %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
+ frequency, primary ? "primary" : "secondary",
chan->flag,
chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
@@ -762,19 +765,28 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
int num_of_enabled = 0;
int max_contiguous = 0;
struct ieee80211_edmg_config edmg;
+ struct hostapd_channel_data *pri_chan;
if (!iface->conf->enable_edmg)
return 1;
+ if (!iface->current_mode)
+ return 0;
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode,
+ iface->freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
hostapd_encode_edmg_chan(iface->conf->enable_edmg,
iface->conf->edmg_channel,
- iface->conf->channel,
+ pri_chan->chan,
&edmg);
- if (!(edmg.channels & BIT(iface->conf->channel - 1)))
+ if (!(edmg.channels & BIT(pri_chan->chan - 1)))
return 0;
/* 60 GHz channels 1..6 */
for (i = 0; i < 6; i++) {
+ int freq = 56160 + 2160 * (i + 1);
+
if (edmg.channels & BIT(i)) {
contiguous++;
num_of_enabled++;
@@ -789,7 +801,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
if (num_of_enabled > 4)
return 0;
- if (!hostapd_is_usable_chan(iface, i + 1, 1))
+ if (!hostapd_is_usable_chan(iface, freq, 1))
return 0;
if (contiguous > max_contiguous)
@@ -819,38 +831,45 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
- int secondary_chan;
+ int secondary_freq;
struct hostapd_channel_data *pri_chan;
- pri_chan = hw_get_channel_chan(iface->current_mode,
- iface->conf->channel, NULL);
- if (!pri_chan)
+ if (!iface->current_mode)
return 0;
-
- if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
+ pri_chan = hw_get_channel_freq(iface->current_mode->mode,
+ iface->freq, NULL,
+ iface->hw_features,
+ iface->num_hw_features);
+ if (!pri_chan) {
+ wpa_printf(MSG_ERROR, "Primary frequency not present");
return 0;
-
+ }
+ if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) {
+ wpa_printf(MSG_ERROR, "Primary frequency not allowed");
+ return 0;
+ }
if (!hostapd_is_usable_edmg(iface))
return 0;
if (!iface->conf->secondary_channel)
return 1;
+ if (hostapd_is_usable_chan(iface, iface->freq +
+ iface->conf->secondary_channel * 20, 0))
+ return 1;
if (!iface->conf->ht40_plus_minus_allowed)
- return hostapd_is_usable_chan(
- iface, iface->conf->channel +
- iface->conf->secondary_channel * 4, 0);
+ return 0;
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
- secondary_chan = iface->conf->channel + 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ secondary_freq = iface->freq + 20;
+ if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
iface->conf->secondary_channel = 1;
return 1;
}
- secondary_chan = iface->conf->channel - 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ secondary_freq = iface->freq - 20;
+ if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
iface->conf->secondary_channel = -1;
return 1;
@@ -860,10 +879,43 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
}
+static void hostapd_determine_mode(struct hostapd_iface *iface)
+{
+ int i;
+ enum hostapd_hw_mode target_mode;
+
+ if (iface->current_mode ||
+ iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
+ return;
+
+ if (iface->freq < 4000)
+ target_mode = HOSTAPD_MODE_IEEE80211G;
+ else if (iface->freq > 50000)
+ target_mode = HOSTAPD_MODE_IEEE80211AD;
+ else
+ target_mode = HOSTAPD_MODE_IEEE80211A;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ struct hostapd_hw_modes *mode;
+
+ mode = &iface->hw_features[i];
+ if (mode->mode == target_mode) {
+ iface->current_mode = mode;
+ iface->conf->hw_mode = mode->mode;
+ break;
+ }
+ }
+
+ if (!iface->current_mode)
+ wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
+}
+
+
static enum hostapd_chan_status
hostapd_check_chans(struct hostapd_iface *iface)
{
- if (iface->conf->channel) {
+ if (iface->freq) {
+ hostapd_determine_mode(iface);
if (hostapd_is_usable_chans(iface))
return HOSTAPD_CHAN_VALID;
else
@@ -897,9 +949,9 @@ static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
- "Configured channel (%d) not found from the "
- "channel list of current mode (%d) %s",
+ "Configured channel (%d) or frequency (%d) not found from the channel list of the current mode (%d) %s",
iface->conf->channel,
+ iface->freq,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
@@ -919,9 +971,7 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err)
case HOSTAPD_CHAN_VALID:
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
ACS_EVENT_COMPLETED "freq=%d channel=%d",
- hostapd_hw_get_freq(iface->bss[0],
- iface->conf->channel),
- iface->conf->channel);
+ iface->freq, iface->conf->channel);
break;
case HOSTAPD_CHAN_ACS:
wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
@@ -961,7 +1011,6 @@ out:
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
int i;
- int freq = -1;
if (iface->num_hw_features < 1)
return -1;
@@ -978,13 +1027,13 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
}
iface->current_mode = NULL;
- if (iface->conf->channel && iface->conf->op_class)
- freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
- iface->conf->channel);
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
if (mode->mode == iface->conf->hw_mode) {
- if (freq > 0 && !hw_get_chan(mode, freq))
+ if (iface->freq > 0 &&
+ !hw_get_chan(mode->mode, iface->freq,
+ iface->hw_features,
+ iface->num_hw_features))
continue;
iface->current_mode = mode;
break;
@@ -992,9 +1041,15 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
}
if (iface->current_mode == NULL) {
- if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
- !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
- {
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) {
+ wpa_printf(MSG_DEBUG,
+ "Using offloaded hw_mode=any ACS");
+ } else if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
+ iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211ANY) {
+ wpa_printf(MSG_DEBUG,
+ "Using internal ACS for hw_mode=any");
+ } else {
wpa_printf(MSG_ERROR,
"Hardware does not support configured mode");
hostapd_logger(iface->bss[0], NULL,
@@ -1048,7 +1103,9 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
struct hostapd_hw_modes *mode;
if (hapd->iface->current_mode) {
- channel = hw_get_chan(hapd->iface->current_mode, freq);
+ channel = hw_get_chan(hapd->iface->current_mode->mode, freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
if (channel)
return channel;
}
@@ -1059,9 +1116,28 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
return 0;
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
- channel = hw_get_chan(mode, freq);
+ channel = hw_get_chan(mode->mode, freq,
+ hapd->iface->hw_features,
+ hapd->iface->num_hw_features);
if (channel)
return channel;
}
return 0;
}
+
+
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode)
+{
+ int i;
+
+ if (iface->current_mode)
+ return mode != iface->current_mode;
+ if (mode->mode != HOSTAPD_MODE_IEEE80211B)
+ return 0;
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (iface->hw_features[i].mode == HOSTAPD_MODE_IEEE80211G)
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 902a19f..dd24f95 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -25,6 +25,8 @@ int hostapd_check_edmg_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
+int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -49,7 +51,7 @@ static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
static inline const char * hostapd_hw_mode_txt(int mode)
{
- return NULL;
+ return "UNKNOWN";
}
static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
@@ -77,6 +79,12 @@ static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
{
}
+static inline int hostapd_hw_skip_mode(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode)
+{
+ return 0;
+}
+
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 306e989..de715a0 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -24,6 +24,7 @@
#include "common/dpp.h"
#include "common/ocv.h"
#include "common/wpa_common.h"
+#include "common/wpa_ctrl.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -88,6 +89,7 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
int i, num, count;
+ int h2e_required;
if (hapd->iface->current_rates == NULL)
return eid;
@@ -98,7 +100,11 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
- if (hapd->conf->sae_pwe == 1)
+ h2e_required = (hapd->conf->sae_pwe == 1 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+ hapd->conf->sae_pwe != 3 &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+ if (h2e_required)
num++;
if (num > 8) {
/* rest of the rates are encoded in Extended supported
@@ -126,7 +132,7 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
- if (hapd->conf->sae_pwe == 1 && count < 8) {
+ if (h2e_required && count < 8) {
count++;
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
}
@@ -139,6 +145,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
int i, num, count;
+ int h2e_required;
if (hapd->iface->current_rates == NULL)
return eid;
@@ -148,7 +155,11 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
- if (hapd->conf->sae_pwe == 1)
+ h2e_required = (hapd->conf->sae_pwe == 1 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+ hapd->conf->sae_pwe != 3 &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
+ if (h2e_required)
num++;
if (num <= 8)
return eid;
@@ -179,7 +190,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
- if (hapd->conf->sae_pwe == 1) {
+ if (h2e_required) {
count++;
if (count > 8)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
@@ -189,10 +200,31 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
}
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i])
+ break;
+ }
+
+ if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
+ return eid;
+
+ *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+ *eid++ = RRM_CAPABILITIES_IE_LEN;
+ os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
+
+ return eid + RRM_CAPABILITIES_IE_LEN;
+}
+
+
u16 hostapd_own_capab_info(struct hostapd_data *hapd)
{
int capab = WLAN_CAPABILITY_ESS;
- int privacy;
+ int privacy = 0;
int dfs;
int i;
@@ -208,12 +240,14 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
hapd->iconf->preamble == SHORT_PREAMBLE)
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+#ifdef CONFIG_WEP
privacy = hapd->conf->ssid.wep.keys_set;
if (hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len))
privacy = 1;
+#endif /* CONFIG_WEP */
if (hapd->conf->wpa)
privacy = 1;
@@ -253,6 +287,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
}
+#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
u16 auth_transaction, const u8 *challenge,
@@ -309,9 +344,10 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
return 0;
}
#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
-static int send_auth_reply(struct hostapd_data *hapd,
+static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *dst, const u8 *bssid,
u16 auth_alg, u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len, const char *dbg)
@@ -344,7 +380,38 @@ static int send_auth_reply(struct hostapd_data *hapd,
" auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)",
MAC2STR(dst), auth_alg, auth_transaction,
resp, (unsigned long) ies_len, dbg);
- if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_SAE
+ if (hapd->conf->sae_confirm_immediate == 2 &&
+ auth_alg == WLAN_AUTH_SAE) {
+ if (auth_transaction == 1 && sta &&
+ (resp == WLAN_STATUS_SUCCESS ||
+ resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ resp == WLAN_STATUS_SAE_PK)) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Postpone SAE Commit transmission until Confirm is ready");
+ os_free(sta->sae_postponed_commit);
+ sta->sae_postponed_commit = buf;
+ sta->sae_postponed_commit_len = rlen;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (auth_transaction == 2 && sta && sta->sae_postponed_commit) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm");
+ if (hostapd_drv_send_mlme(hapd,
+ sta->sae_postponed_commit,
+ sta->sae_postponed_commit_len,
+ 0, NULL, 0, 0) < 0)
+ wpa_printf(MSG_INFO, "send_auth_reply: send failed");
+ os_free(sta->sae_postponed_commit);
+ sta->sae_postponed_commit = NULL;
+ sta->sae_postponed_commit_len = 0;
+ }
+ }
+#endif /* CONFIG_SAE */
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "send_auth_reply: send failed");
else
reply_res = WLAN_STATUS_SUCCESS;
@@ -364,7 +431,7 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
struct sta_info *sta;
int reply_res;
- reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
+ reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
auth_transaction, status, ies, ies_len,
"auth-ft-finish");
@@ -403,7 +470,8 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state,
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta, int update)
+ struct sta_info *sta, int update,
+ int status_code)
{
struct wpabuf *buf;
const char *password = NULL;
@@ -411,12 +479,25 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
const char *rx_id = NULL;
int use_pt = 0;
struct sae_pt *pt = NULL;
+ const struct sae_pk *pk = NULL;
if (sta->sae->tmp) {
rx_id = sta->sae->tmp->pw_id;
- use_pt = sta->sae->tmp->h2e;
+ use_pt = sta->sae->h2e;
+#ifdef CONFIG_SAE_PK
+ os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
+ os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
+#endif /* CONFIG_SAE_PK */
}
+ if (rx_id && hapd->conf->sae_pwe != 3)
+ use_pt = 1;
+ else if (status_code == WLAN_STATUS_SUCCESS)
+ use_pt = 0;
+ else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
+ use_pt = 1;
+
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
@@ -428,6 +509,8 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
continue;
password = pw->password;
pt = pw->pt;
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ pk = pw->pk;
break;
}
if (!password) {
@@ -441,7 +524,7 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
if (update && use_pt &&
sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
- NULL) < 0)
+ NULL, pk) < 0)
return NULL;
if (update && !use_pt &&
@@ -463,10 +546,13 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
(rx_id ? 3 + os_strlen(rx_id) : 0));
- if (buf == NULL)
- return NULL;
- sae_write_commit(sta->sae, buf, sta->sae->tmp ?
- sta->sae->tmp->anti_clogging_token : NULL, rx_id);
+ if (buf &&
+ sae_write_commit(sta->sae, buf, sta->sae->tmp ?
+ sta->sae->tmp->anti_clogging_token : NULL,
+ rx_id) < 0) {
+ wpabuf_free(buf);
+ buf = NULL;
+ }
return buf;
}
@@ -481,7 +567,17 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
if (buf == NULL)
return NULL;
- sae_write_confirm(sta->sae, buf);
+#ifdef CONFIG_SAE_PK
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sta->sae->tmp)
+ sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_SAE_PK */
+
+ if (sae_write_confirm(sta->sae, buf) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
return buf;
}
@@ -489,21 +585,35 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
static int auth_sae_send_commit(struct hostapd_data *hapd,
struct sta_info *sta,
- const u8 *bssid, int update)
+ const u8 *bssid, int update, int status_code)
{
struct wpabuf *data;
int reply_res;
u16 status;
- data = auth_build_sae_commit(hapd, sta, update);
+ data = auth_build_sae_commit(hapd, sta, update, status_code);
if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
- WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
- reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
+ if (sta->sae->tmp && sta->sae->pk)
+ status = WLAN_STATUS_SAE_PK;
+ else if (sta->sae->tmp && sta->sae->h2e)
+ status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ else
+ status = WLAN_STATUS_SUCCESS;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->sae_commit_status >= 0 &&
+ hapd->conf->sae_commit_status != status) {
+ wpa_printf(MSG_INFO,
+ "TESTING: Override SAE commit status code %u --> %d",
+ status, hapd->conf->sae_commit_status);
+ status = hapd->conf->sae_commit_status;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ WLAN_AUTH_SAE, 1,
status, wpabuf_head(data),
wpabuf_len(data), "sae-send-commit");
@@ -524,7 +634,8 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
+ reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ WLAN_AUTH_SAE, 2,
WLAN_STATUS_SUCCESS, wpabuf_head(data),
wpabuf_len(data), "sae-send-confirm");
@@ -564,13 +675,15 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
}
-static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
+static int sae_token_hash(struct hostapd_data *hapd, const u8 *addr, u8 *idx)
{
u8 hash[SHA256_MAC_LEN];
- hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
- addr, ETH_ALEN, hash);
- return hash[0];
+ if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, hash) < 0)
+ return -1;
+ *idx = hash[0];
+ return 0;
}
@@ -583,9 +696,8 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
u16 token_idx;
u8 idx;
- if (token_len != SHA256_MAC_LEN)
+ if (token_len != SHA256_MAC_LEN || sae_token_hash(hapd, addr, &idx) < 0)
return -1;
- idx = sae_token_hash(hapd, addr);
token_idx = hapd->sae_pending_token_idx[idx];
if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
@@ -610,7 +722,7 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
- int group, const u8 *addr)
+ int group, const u8 *addr, int h2e)
{
struct wpabuf *buf;
u8 *token;
@@ -636,13 +748,23 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
sizeof(hapd->sae_pending_token_idx));
}
- buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
+ buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
if (buf == NULL)
return NULL;
wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
- p_idx = sae_token_hash(hapd, addr);
+ if (h2e) {
+ /* Encapsulate Anti-clogging Token field in a container IE */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
+ }
+
+ if (sae_token_hash(hapd, addr, &p_idx) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
token_idx = hapd->sae_pending_token_idx[p_idx];
if (!token_idx) {
hapd->sae_token_idx++;
@@ -693,7 +815,7 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
switch (sta->sae->state) {
case SAE_COMMITTED:
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
eloop_register_timeout(0,
hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
@@ -784,6 +906,9 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
mlme_authenticate_indication(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm");
+ crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0);
+ sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
+ sta->sae->peer_commit_scalar = NULL;
wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
sta->sae->pmk, sta->sae->pmkid);
sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
@@ -807,11 +932,16 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
- if (sta->sae->tmp)
- sta->sae->tmp->h2e = status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT;
+ if (sta->sae->tmp) {
+ sta->sae->h2e =
+ (status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
+ sta->sae->pk =
+ status_code == WLAN_STATUS_SAE_PK;
+ }
ret = auth_sae_send_commit(hapd, sta, bssid,
- !allow_reuse);
+ !allow_reuse, status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -881,7 +1011,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 0);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 0,
+ status_code);
if (ret)
return ret;
@@ -914,7 +1045,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+ status_code);
if (ret)
return ret;
@@ -942,7 +1074,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
*sta_removed = 1;
} else if (auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+ status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -1014,13 +1147,30 @@ static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
{
- return (hapd->conf->sae_pwe == 0 &&
+ int sae_pwe = hapd->conf->sae_pwe;
+ int id_in_use;
+ bool sae_pk = false;
+
+ id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
+ if (id_in_use == 2 && sae_pwe != 3)
+ sae_pwe = 1;
+ else if (id_in_use == 1 && sae_pwe == 0)
+ sae_pwe = 2;
+#ifdef CONFIG_SAE_PK
+ sae_pk = hostapd_sae_pk_in_use(hapd->conf);
+ if (sae_pwe == 0 && sae_pk)
+ sae_pwe = 2;
+#endif /* CONFIG_SAE_PK */
+
+ return ((sae_pwe == 0 || sae_pwe == 3) &&
status_code == WLAN_STATUS_SUCCESS) ||
- (hapd->conf->sae_pwe == 1 &&
- status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
- (hapd->conf->sae_pwe == 2 &&
+ (sae_pwe == 1 &&
+ (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ (sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
+ (sae_pwe == 2 &&
(status_code == WLAN_STATUS_SUCCESS ||
- status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ (sae_pk && status_code == WLAN_STATUS_SAE_PK)));
}
@@ -1043,11 +1193,15 @@ static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
static int check_sae_rejected_groups(struct hostapd_data *hapd,
- const struct wpabuf *groups)
+ struct sae_data *sae)
{
+ const struct wpabuf *groups;
size_t i, count;
const u8 *pos;
+ if (!sae->tmp)
+ return 0;
+ groups = sae->tmp->peer_rejected_groups;
if (!groups)
return 0;
@@ -1089,7 +1243,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len;
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ resp = status_code;
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp, pos, end - pos,
"auth-sae-reflection-attack");
goto remove_sta;
@@ -1097,7 +1252,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->sae_commit_override && auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
wpabuf_head(hapd->conf->sae_commit_override),
wpabuf_len(hapd->conf->sae_commit_override),
@@ -1108,8 +1263,10 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (!sta->sae) {
if (auth_transaction != 1 ||
!sae_status_success(hapd, status_code)) {
- resp = -1;
- goto remove_sta;
+ wpa_printf(MSG_DEBUG, "SAE: Unexpected Status Code %u",
+ status_code);
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
}
sta->sae = os_zalloc(sizeof(*sta->sae));
if (!sta->sae) {
@@ -1174,7 +1331,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
* Authentication frame, and the commit-scalar and
* COMMIT-ELEMENT previously sent.
*/
- resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+ resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
+ status_code);
if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
"SAE: Failed to send commit message");
@@ -1231,7 +1389,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
&token_len, groups, status_code ==
- WLAN_STATUS_SAE_HASH_TO_ELEMENT);
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1261,19 +1420,24 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
- if (sta->sae->tmp &&
- check_sae_rejected_groups(
- hapd, sta->sae->tmp->peer_rejected_groups) < 0) {
+ if (check_sae_rejected_groups(hapd, sta->sae)) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto remove_sta;
+ goto reply;
}
if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
+ int h2e = 0;
+
wpa_printf(MSG_DEBUG,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
+ if (sta->sae->tmp)
+ h2e = sta->sae->h2e;
+ if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
+ status_code == WLAN_STATUS_SAE_PK)
+ h2e = 1;
data = auth_build_token_req(hapd, sta->sae->group,
- sta->addr);
+ sta->addr, h2e);
resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
if (hapd->conf->mesh & MESH_ENABLED)
sae_set_state(sta, SAE_NOTHING,
@@ -1348,7 +1512,7 @@ reply:
data = wpabuf_alloc_copy(pos, 2);
sae_sme_send_external_auth_status(hapd, sta, resp);
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-sae");
@@ -1385,7 +1549,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->sae->state != SAE_NOTHING)
return -1;
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
if (ret)
return -1;
@@ -1498,27 +1662,37 @@ static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
#endif /* CONFIG_SAE */
-static u16 wpa_res_to_status_code(int res)
+static u16 wpa_res_to_status_code(enum wpa_validate_result res)
{
- if (res == WPA_INVALID_GROUP)
+ switch (res) {
+ case WPA_IE_OK:
+ return WLAN_STATUS_SUCCESS;
+ case WPA_INVALID_IE:
+ return WLAN_STATUS_INVALID_IE;
+ case WPA_INVALID_GROUP:
return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- if (res == WPA_INVALID_PAIRWISE)
+ case WPA_INVALID_PAIRWISE:
return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- if (res == WPA_INVALID_AKMP)
+ case WPA_INVALID_AKMP:
return WLAN_STATUS_AKMP_NOT_VALID;
- if (res == WPA_ALLOC_FAIL)
+ case WPA_NOT_ENABLED:
+ return WLAN_STATUS_INVALID_IE;
+ case WPA_ALLOC_FAIL:
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+ case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
- if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+ case WPA_INVALID_MGMT_GROUP_CIPHER:
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
- if (res == WPA_INVALID_MDIE)
+ case WPA_INVALID_MDIE:
return WLAN_STATUS_INVALID_MDIE;
- if (res == WPA_INVALID_PMKID)
- return WLAN_STATUS_INVALID_PMKID;
- if (res != WPA_IE_OK)
+ case WPA_INVALID_PROTO:
return WLAN_STATUS_INVALID_IE;
- return WLAN_STATUS_SUCCESS;
+ case WPA_INVALID_PMKID:
+ return WLAN_STATUS_INVALID_PMKID;
+ case WPA_DENIED_OTHER_REASON:
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ }
+ return WLAN_STATUS_INVALID_IE;
}
@@ -1538,7 +1712,7 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
u16 resp = WLAN_STATUS_SUCCESS;
const u8 *end;
struct ieee802_11_elems elems;
- int res;
+ enum wpa_validate_result res;
struct wpa_ie_data rsn;
struct rsn_pmksa_cache_entry *pmksa = NULL;
@@ -1714,11 +1888,11 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
FILS_SESSION_LEN);
os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
- if (elems.fils_wrapped_data) {
+ /* Wrapped Data */
+ if (elems.wrapped_data) {
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ elems.wrapped_data,
+ elems.wrapped_data_len);
if (!pmksa) {
#ifndef CONFIG_NO_RADIUS
if (!sta->eapol_sm) {
@@ -1728,8 +1902,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG,
"FILS: Forward EAP-Initiate/Re-auth to authentication server");
ieee802_1x_encapsulate_radius(
- hapd, sta, elems.fils_wrapped_data,
- elems.fils_wrapped_data_len);
+ hapd, sta, elems.wrapped_data,
+ elems.wrapped_data_len);
sta->fils_pending_cb = cb;
wpa_printf(MSG_DEBUG,
"FILS: Will send Authentication frame once the response from authentication server is available");
@@ -1738,8 +1912,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
* to maintain a copy of the EAP-Initiate/Reauth
* message. */
if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
- elems.fils_wrapped_data,
- elems.fils_wrapped_data_len,
+ elems.wrapped_data,
+ elems.wrapped_data_len,
sta->fils_erp_pmkid) == 0)
sta->fils_erp_pmkid_set = 1;
return;
@@ -1882,12 +2056,12 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
- /* FILS Wrapped Data */
+ /* Wrapped Data */
if (!pmksa && erp_resp) {
wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
/* Element ID Extension */
- wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
wpabuf_put_buf(data, erp_resp);
if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
@@ -1989,7 +2163,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
auth_alg = (pub ||
resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
- send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
+ send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-fils-finish");
wpabuf_free(data);
@@ -2033,28 +2207,18 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
-int
-ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui, int is_probe_req)
+static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *msg, size_t len,
+ struct radius_sta *info)
{
int res;
- os_memset(vlan_id, 0, sizeof(*vlan_id));
- res = hostapd_allowed_address(hapd, addr, msg, len,
- session_timeout, acct_interim_interval,
- vlan_id, psk, identity, radius_cui,
- is_probe_req);
+ res = hostapd_allowed_address(hapd, addr, msg, len, info, 0);
if (res == HOSTAPD_ACL_REJECT) {
- if (!is_probe_req)
- wpa_printf(MSG_DEBUG,
- "Station " MACSTR
- " not allowed to authenticate",
- MAC2STR(addr));
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not allowed to authenticate",
+ MAC2STR(addr));
return HOSTAPD_ACL_REJECT;
}
@@ -2074,12 +2238,15 @@ ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
static int
ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
- int res, u32 session_timeout,
- u32 acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ int res, struct radius_sta *info)
{
+ u32 session_timeout = info->session_timeout;
+ u32 acct_interim_interval = info->acct_interim_interval;
+ struct vlan_description *vlan_id = &info->vlan_id;
+ struct hostapd_sta_wpa_psk_short *psk = info->psk;
+ char *identity = info->identity;
+ char *radius_cui = info->radius_cui;
+
if (vlan_id->notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
@@ -2096,20 +2263,22 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
hostapd_free_psk_list(sta->psk);
- if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
- sta->psk = *psk;
- *psk = NULL;
- } else {
+ if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED)
+ hostapd_copy_psk_list(&sta->psk, psk);
+ else
sta->psk = NULL;
- }
os_free(sta->identity);
- sta->identity = *identity;
- *identity = NULL;
+ if (identity)
+ sta->identity = os_strdup(identity);
+ else
+ sta->identity = NULL;
os_free(sta->radius_cui);
- sta->radius_cui = *radius_cui;
- *radius_cui = NULL;
+ if (radius_cui)
+ sta->radius_cui = os_strdup(radius_cui);
+ else
+ sta->radius_cui = NULL;
if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
sta->acct_interim_interval = acct_interim_interval;
@@ -2137,14 +2306,10 @@ static void handle_auth(struct hostapd_data *hapd,
int res, reply_res;
u16 fc;
const u8 *challenge = NULL;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
- char *identity = NULL;
- char *radius_cui = NULL;
u16 seq_ctrl;
+ struct radius_sta rad_info;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -2295,10 +2460,8 @@ static void handle_auth(struct hostapd_data *hapd,
}
}
- res = ieee802_11_allowed_address(
- hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
- &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui,
- 0);
+ res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &rad_info);
if (res == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Authentication frame from " MACSTR
@@ -2381,9 +2544,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_rssi = rssi;
#endif /* CONFIG_MBO */
- res = ieee802_11_set_radius_info(
- hapd, sta, res, session_timeout, acct_interim_interval,
- &vlan_id, &psk, &identity, &radius_cui);
+ res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info);
if (res) {
wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2416,32 +2577,10 @@ static void handle_auth(struct hostapd_data *hapd,
(!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
!(hapd->conf->mesh & MESH_ENABLED) &&
!(sta->added_unassoc)) {
- /*
- * If a station that is already associated to the AP, is trying
- * to authenticate again, remove the STA entry, in order to make
- * sure the STA PS state gets cleared and configuration gets
- * updated. To handle this, station's added_unassoc flag is
- * cleared once the station has completed association.
- */
- ap_sta_set_authorized(hapd, sta, 0);
- hostapd_drv_sta_remove(hapd, sta->addr);
- sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
- WLAN_STA_AUTHORIZED);
-
- 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,
- "Could not add STA to kernel driver");
+ if (ap_sta_re_add(hapd, sta) < 0) {
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
}
-
- sta->added_unassoc = 1;
}
switch (auth_alg) {
@@ -2454,6 +2593,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_alg = WLAN_AUTH_OPEN;
mlme_authenticate_indication(hapd, sta);
break;
+#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4
case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
@@ -2472,6 +2612,7 @@ static void handle_auth(struct hostapd_data *hapd,
}
break;
#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_WEP */
#ifdef CONFIG_IEEE80211R_AP
case WLAN_AUTH_FT:
sta->auth_alg = WLAN_AUTH_FT;
@@ -2525,11 +2666,7 @@ static void handle_auth(struct hostapd_data *hapd,
}
fail:
- os_free(identity);
- os_free(radius_cui);
- hostapd_free_psk_list(psk);
-
- reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+ reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg,
auth_transaction + 1, resp, resp_ies,
resp_ies_len, "handle-auth");
@@ -2946,7 +3083,7 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd,
u16 status;
u8 *owe_buf, ie[256 * 2];
size_t ie_len = 0;
- int res;
+ enum wpa_validate_result res;
if (!rsn_ie || rsn_ie_len < 2) {
wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
@@ -3018,11 +3155,39 @@ end:
#endif /* CONFIG_OWE */
-static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
+static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
+ int reassoc)
+{
+ if ((sta->flags &
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
+ return false;
+
+ if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+
+ if (!sta->sa_query_timed_out &&
+ (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA Query timeout
+ * has not been reached. Reject the association attempt
+ * temporarily and start SA Query, if one is not pending.
+ */
+ if (sta->sa_query_count == 0)
+ ap_sta_start_sa_query(hapd, sta);
+
+ return true;
+ }
+
+ return false;
+}
+
+
+static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ies, size_t ies_len, int reassoc)
{
struct ieee802_11_elems elems;
- u16 resp;
+ int resp;
const u8 *wpa_ie;
size_t wpa_ie_len;
const u8 *p2p_dev_addr = NULL;
@@ -3051,7 +3216,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
return resp;
-#ifdef CONFIG_IEEE80211N
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -3062,7 +3226,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"mandatory HT PHY - reject association");
return WLAN_STATUS_ASSOC_DENIED_NO_HT;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac) {
@@ -3097,6 +3260,19 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
elems.he_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ if (!(sta->flags & WLAN_STA_HE)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station does not support mandatory HE PHY - reject association");
+ return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
+ }
+ resp = copy_sta_he_6ghz_capab(hapd, sta,
+ elems.he_6ghz_band_cap);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
}
#endif /* CONFIG_IEEE80211AX */
@@ -3130,6 +3306,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->wps_state && elems.wps_ie) {
wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
"Request - assume WPS is used");
+ if (check_sa_query(hapd, sta, reassoc))
+ return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
sta->flags |= WLAN_STA_WPS;
wpabuf_free(sta->wps_ie);
sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
@@ -3159,7 +3337,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
if (hapd->conf->wpa && wpa_ie) {
- int res;
+ enum wpa_validate_result res;
+
wpa_ie -= 2;
wpa_ie_len += 2;
if (sta->wpa_sm == NULL)
@@ -3182,27 +3361,9 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- sta->sa_query_count > 0)
- ap_check_sa_query_timeout(hapd, sta);
- if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
- (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
- !sta->sa_query_timed_out &&
- (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
- /*
- * STA has already been associated with MFP and SA
- * Query timeout has not been reached. Reject the
- * association attempt temporarily and start SA Query,
- * if one is not pending.
- */
-
- if (sta->sa_query_count == 0)
- ap_sta_start_sa_query(hapd, sta);
+ if (check_sa_query(hapd, sta, reassoc))
return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
- }
if (wpa_auth_uses_mfp(sta->wpa_sm))
sta->flags |= WLAN_STA_MFP;
@@ -3255,7 +3416,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->sae_pwe == 2 &&
sta->auth_alg == WLAN_AUTH_SAE &&
- sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ sta->sae && !sta->sae->h2e &&
elems.rsnxe && elems.rsnxe_len >= 1 &&
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
wpa_printf(MSG_INFO, "SAE: " MACSTR
@@ -3280,7 +3441,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
dpp_pfs_free(sta->dpp_pfs);
sta->dpp_pfs = NULL;
- if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ if (DPP_VERSION > 1 &&
+ (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
elems.owe_dh) {
@@ -3307,7 +3469,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
pfs_fail:
#endif /* CONFIG_DPP2 */
-#ifdef CONFIG_IEEE80211N
if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
hostapd_logger(hapd, sta->addr,
@@ -3317,7 +3478,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"association");
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_HS20
} else if (hapd->conf->osen) {
if (elems.osen == NULL) {
@@ -3404,6 +3564,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
wpa_printf(MSG_WARNING,
@@ -3417,9 +3578,20 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
&tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
+ res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_printf(MSG_INFO,
+ "FILS: Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sta->wpa_sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
+ ocv_errorstr);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
+ MACSTR " frame=fils-reassoc-req error=%s",
+ MAC2STR(sta->addr), ocv_errorstr);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
}
@@ -3462,7 +3634,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
reply.u.deauth.reason_code = host_to_le16(reason_code);
- if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "Failed to send deauth: %s",
strerror(errno));
}
@@ -3518,10 +3690,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
sta->ft_over_ds = 0;
}
-#ifdef CONFIG_IEEE80211N
if (sta->flags & WLAN_STA_HT)
hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (sta->flags & WLAN_STA_VHT)
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
@@ -3545,6 +3715,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
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->he_6ghz_capab,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
set)) {
@@ -3569,7 +3740,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 status_code, int reassoc,
- const u8 *ies, size_t ies_len, int rssi)
+ const u8 *ies, size_t ies_len, int rssi,
+ int omit_rsnxe)
{
int send_len;
u8 *buf;
@@ -3620,6 +3792,9 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
+ /* Radio measurement capabilities */
+ p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p);
+
#ifdef CONFIG_MBO
if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
rssi != 0) {
@@ -3636,7 +3811,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
* Transition Information, RSN, [RIC Response] */
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
buf + buflen - p,
- sta->auth_alg, ies, ies_len);
+ sta->auth_alg, ies, ies_len,
+ omit_rsnxe);
if (!p) {
wpa_printf(MSG_DEBUG,
"FT: Failed to write AssocResp IEs");
@@ -3666,10 +3842,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-#ifdef CONFIG_IEEE80211N
p = hostapd_eid_ht_capabilities(hapd, p);
p = hostapd_eid_ht_operation(hapd, p);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
@@ -3701,6 +3875,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
p = hostapd_eid_he_operation(hapd, p);
p = hostapd_eid_spatial_reuse(hapd, p);
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
+ p = hostapd_eid_he_6ghz_band_cap(hapd, p);
}
#endif /* CONFIG_IEEE80211AX */
@@ -3717,12 +3892,29 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_FST */
- p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->rsnxe_override_ft &&
+ buf + buflen - p >=
+ (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
+ sta && sta->auth_alg == WLAN_AUTH_FT) {
+ wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
+ os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
+ wpabuf_len(hapd->conf->rsnxe_override_ft));
+ p += wpabuf_len(hapd->conf->rsnxe_override_ft);
+ goto rsnxe_done;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (!omit_rsnxe)
+ p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+#ifdef CONFIG_TESTING_OPTIONS
+rsnxe_done:
+#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
- wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
+ wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
+ !wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
struct wpabuf *pub;
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
@@ -3743,7 +3935,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP2
- if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
+ if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
@@ -3848,7 +4040,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_FILS */
- if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3863,12 +4055,12 @@ done:
#ifdef CONFIG_OWE
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)
+ u8 *owe_buf, size_t owe_buf_len, u16 *status)
{
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->own_ie_override) {
wpa_printf(MSG_DEBUG, "OWE: Using IE override");
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
owe_buf_len, NULL, 0);
}
@@ -3878,18 +4070,18 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching");
owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
owe_buf_len, NULL, 0);
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return owe_buf;
}
if (sta->owe_pmk && sta->external_dh_updated) {
wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
- *reason = WLAN_STATUS_SUCCESS;
+ *status = WLAN_STATUS_SUCCESS;
return owe_buf;
}
- *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
- if (*reason != WLAN_STATUS_SUCCESS)
+ *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+ if (*status != WLAN_STATUS_SUCCESS)
return NULL;
owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf,
@@ -3900,7 +4092,7 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
if (!pub) {
- *reason = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ *status = WLAN_STATUS_UNSPECIFIED_FAILURE;
return owe_buf;
}
@@ -3935,7 +4127,7 @@ void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
sta->fils_pending_assoc_is_reassoc,
sta->fils_pending_assoc_req,
- sta->fils_pending_assoc_req_len, 0);
+ sta->fils_pending_assoc_req_len, 0, 0);
os_free(sta->fils_pending_assoc_req);
sta->fils_pending_assoc_req = NULL;
sta->fils_pending_assoc_req_len = 0;
@@ -3975,17 +4167,16 @@ static void handle_assoc(struct hostapd_data *hapd,
int reassoc, int rssi)
{
u16 capab_info, listen_interval, seq_ctrl, fc;
- u16 resp = WLAN_STATUS_SUCCESS, reply_res;
+ int resp = WLAN_STATUS_SUCCESS;
+ u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
const u8 *pos;
int left, i;
struct sta_info *sta;
u8 *tmp = NULL;
- struct hostapd_sta_wpa_psk_short *psk = NULL;
- char *identity = NULL;
- char *radius_cui = NULL;
#ifdef CONFIG_FILS
int delay_assoc = 0;
#endif /* CONFIG_FILS */
+ int omit_rsnxe = 0;
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
@@ -4062,13 +4253,11 @@ static void handle_assoc(struct hostapd_data *hapd,
hapd->iface->current_mode->mode ==
HOSTAPD_MODE_IEEE80211AD) {
int acl_res;
- u32 session_timeout, acct_interim_interval;
- struct vlan_description vlan_id;
+ struct radius_sta info;
- acl_res = ieee802_11_allowed_address(
- hapd, mgmt->sa, (const u8 *) mgmt, len,
- &session_timeout, &acct_interim_interval,
- &vlan_id, &psk, &identity, &radius_cui, 0);
+ acl_res = ieee802_11_allowed_address(hapd, mgmt->sa,
+ (const u8 *) mgmt,
+ len, &info);
if (acl_res == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Association Request frame from "
@@ -4093,9 +4282,7 @@ static void handle_assoc(struct hostapd_data *hapd,
}
acl_res = ieee802_11_set_radius_info(
- hapd, sta, acl_res, session_timeout,
- acct_interim_interval, &vlan_id, &psk,
- &identity, &radius_cui);
+ hapd, sta, acl_res, &info);
if (acl_res) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
@@ -4202,6 +4389,7 @@ static void handle_assoc(struct hostapd_data *hapd,
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
+ omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
if (hostapd_get_aid(hapd, sta) < 0) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -4254,9 +4442,7 @@ static void handle_assoc(struct hostapd_data *hapd,
ieee802_11_set_beacons(hapd->iface);
}
-#ifdef CONFIG_IEEE80211N
update_ht_state(hapd, sta);
-#endif /* CONFIG_IEEE80211N */
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -4296,9 +4482,6 @@ static void handle_assoc(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
fail:
- os_free(identity);
- os_free(radius_cui);
- hostapd_free_psk_list(psk);
/*
* In case of a successful response, add the station to the driver.
@@ -4359,12 +4542,13 @@ static void handle_assoc(struct hostapd_data *hapd,
}
#endif /* CONFIG_FILS */
- reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
- left, rssi);
+ if (resp >= 0)
+ reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
+ pos, left, rssi, omit_rsnxe);
os_free(tmp);
/*
- * Remove the station in case tranmission of a success response fails
+ * Remove the station in case transmission of a success response fails
* (the STA was added associated to the driver) or if the station was
* previously added unassociated.
*/
@@ -4401,6 +4585,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
ap_sta_set_authorized(hapd, sta, 0);
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated");
@@ -4467,6 +4652,7 @@ static void handle_deauth(struct hostapd_data *hapd,
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_ASSOC_REQ_OK);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -4598,14 +4784,12 @@ static int handle_action(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
case WLAN_ACTION_PUBLIC:
case WLAN_ACTION_PROTECTED_DUAL:
-#ifdef CONFIG_IEEE80211N
if (len >= IEEE80211_HDRLEN + 2 &&
mgmt->u.action.u.public_action.action ==
WLAN_PA_20_40_BSS_COEX) {
hostapd_2040_coex_action(hapd, mgmt, len);
return 1;
}
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_DPP
if (len >= IEEE80211_HDRLEN + 6 &&
mgmt->u.action.u.vs_public_action.action ==
@@ -4688,7 +4872,7 @@ static int handle_action(struct hostapd_data *hapd,
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
resp->u.action.category |= 0x80;
- if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
"Action frame");
}
@@ -4765,6 +4949,11 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
return 0;
}
+ if (hapd->iface->state != HAPD_IFACE_ENABLED) {
+ wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
+ return 1;
+ }
if (stype == WLAN_FC_STYPE_PROBE_REQ) {
handle_probe_req(hapd, mgmt, len, ssi_signal);
@@ -4880,6 +5069,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
struct sta_info *sta,
char *ifname_wds)
{
+#ifdef CONFIG_WEP
int i;
struct hostapd_ssid *ssid = &hapd->conf->ssid;
@@ -4889,14 +5079,18 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
for (i = 0; i < 4; i++) {
if (ssid->wep.key[i] &&
hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
- i == ssid->wep.idx, NULL, 0,
- ssid->wep.key[i], ssid->wep.len[i])) {
+ 0, i == ssid->wep.idx, NULL, 0,
+ ssid->wep.key[i], ssid->wep.len[i],
+ i == ssid->wep.idx ?
+ KEY_FLAG_GROUP_RX_TX_DEFAULT :
+ KEY_FLAG_GROUP_RX_TX)) {
wpa_printf(MSG_WARNING,
"Could not set WEP keys for WDS interface; %s",
ifname_wds);
break;
}
}
+#endif /* CONFIG_WEP */
}
@@ -5394,4 +5588,57 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
}
+u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 bw, chan1, chan2 = 0;
+ int freq1;
+
+ if (!hapd->cs_freq_params.channel ||
+ (!hapd->cs_freq_params.vht_enabled &&
+ !hapd->cs_freq_params.he_enabled))
+ return eid;
+
+ /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
+ switch (hapd->cs_freq_params.bandwidth) {
+ case 40:
+ bw = 0;
+ break;
+ case 80:
+ /* check if it's 80+80 */
+ if (!hapd->cs_freq_params.center_freq2)
+ bw = 1;
+ else
+ bw = 3;
+ break;
+ case 160:
+ bw = 2;
+ break;
+ default:
+ /* not valid VHT bandwidth or not in CSA */
+ return eid;
+ }
+
+ freq1 = hapd->cs_freq_params.center_freq1 ?
+ hapd->cs_freq_params.center_freq1 :
+ hapd->cs_freq_params.freq;
+ if (ieee80211_freq_to_chan(freq1, &chan1) !=
+ HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ if (hapd->cs_freq_params.center_freq2 &&
+ ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
+ &chan2) != HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
+ *eid++ = 5; /* Length of Channel Switch Wrapper */
+ *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
+ *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
+ *eid++ = bw; /* New Channel Width */
+ *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
+ *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
+
+ return eid;
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index f592da5..ea8c608 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -16,8 +16,7 @@ struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
-struct vlan_description;
-struct hostapd_sta_wpa_psk_short;
+struct radius_sta;
enum ieee80211_op_mode;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
@@ -50,9 +49,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
@@ -63,6 +63,7 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
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);
+u8 * hostapd_eid_he_6ghz_band_cap(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,
@@ -95,6 +96,10 @@ u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
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);
+u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *he_6ghz_capab);
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+ enum ieee80211_op_mode mode);
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,
@@ -162,7 +167,7 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
const u8 *msk, size_t msk_len);
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);
+ u8 *owe_buf, size_t owe_buf_len, u16 *status);
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);
@@ -180,13 +185,9 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
-int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui,
- int is_probe_req);
+
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len);
int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 931d4d0..783ee6d 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -32,12 +32,7 @@ struct hostapd_cached_radius_acl {
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
- u32 session_timeout;
- u32 acct_interim_interval;
- struct vlan_description vlan_id;
- struct hostapd_sta_wpa_psk_short *psk;
- char *identity;
- char *radius_cui;
+ struct radius_sta info;
};
@@ -54,9 +49,9 @@ struct hostapd_acl_query_data {
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
{
- os_free(e->identity);
- os_free(e->radius_cui);
- hostapd_free_psk_list(e->psk);
+ os_free(e->info.identity);
+ os_free(e->info.radius_cui);
+ hostapd_free_psk_list(e->info.psk);
os_free(e);
}
@@ -73,25 +68,8 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
}
-static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
- struct hostapd_sta_wpa_psk_short *src)
-{
- if (!psk)
- return;
-
- if (src)
- src->ref++;
-
- *psk = src;
-}
-
-
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
- u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui)
+ struct radius_sta *out)
{
struct hostapd_cached_radius_acl *entry;
struct os_reltime now;
@@ -105,27 +83,8 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
if (os_reltime_expired(&now, &entry->timestamp,
RADIUS_ACL_TIMEOUT))
return -1; /* entry has expired */
- if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
- if (session_timeout)
- *session_timeout = entry->session_timeout;
- if (acct_interim_interval)
- *acct_interim_interval =
- entry->acct_interim_interval;
- if (vlan_id)
- *vlan_id = entry->vlan_id;
- copy_psk_list(psk, entry->psk);
- if (identity) {
- if (entry->identity)
- *identity = os_strdup(entry->identity);
- else
- *identity = NULL;
- }
- if (radius_cui) {
- if (entry->radius_cui)
- *radius_cui = os_strdup(entry->radius_cui);
- else
- *radius_cui = NULL;
- }
+ *out = entry->info;
+
return entry->accepted;
}
@@ -238,42 +197,28 @@ int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
* @addr: MAC address of the STA
* @msg: Authentication message
* @len: Length of msg in octets
- * @session_timeout: Buffer for returning session timeout (from RADIUS)
- * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
- * @vlan_id: Buffer for returning VLAN ID
- * @psk: Linked list buffer for returning WPA PSK
- * @identity: Buffer for returning identity (from RADIUS)
- * @radius_cui: Buffer for returning CUI (from RADIUS)
+ * @out.session_timeout: Buffer for returning session timeout (from RADIUS)
+ * @out.acct_interim_interval: Buffer for returning account interval (from
+ * RADIUS)
+ * @out.vlan_id: Buffer for returning VLAN ID
+ * @out.psk: Linked list buffer for returning WPA PSK
+ * @out.identity: Buffer for returning identity (from RADIUS)
+ * @out.radius_cui: Buffer for returning CUI (from RADIUS)
* @is_probe_req: Whether this query for a Probe Request frame
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*
- * The caller is responsible for freeing the returned *identity and *radius_cui
- * values with os_free().
+ * The caller is responsible for properly cloning the returned out->identity and
+ * out->radius_cui and out->psk values.
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui,
+ const u8 *msg, size_t len, struct radius_sta *out,
int is_probe_req)
{
int res;
- if (session_timeout)
- *session_timeout = 0;
- if (acct_interim_interval)
- *acct_interim_interval = 0;
- if (vlan_id)
- os_memset(vlan_id, 0, sizeof(*vlan_id));
- if (psk)
- *psk = NULL;
- if (identity)
- *identity = NULL;
- if (radius_cui)
- *radius_cui = NULL;
-
- res = hostapd_check_acl(hapd, addr, vlan_id);
+ os_memset(out, 0, sizeof(*out));
+
+ res = hostapd_check_acl(hapd, addr, &out->vlan_id);
if (res != HOSTAPD_ACL_PENDING)
return res;
@@ -290,12 +235,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
};
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- vlan_id = NULL;
+ os_memset(&out->vlan_id, 0, sizeof(out->vlan_id));
/* Check whether ACL cache has an entry for this station */
- res = hostapd_acl_cache_get(hapd, addr, session_timeout,
- acct_interim_interval, vlan_id, psk,
- identity, radius_cui);
+ res = hostapd_acl_cache_get(hapd, addr, out);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@@ -307,14 +250,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
- if (identity) {
- os_free(*identity);
- *identity = NULL;
- }
- if (radius_cui) {
- os_free(*radius_cui);
- *radius_cui = NULL;
- }
return HOSTAPD_ACL_PENDING;
}
query = query->next;
@@ -488,8 +423,8 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
passphraselen);
psk->is_passphrase = 1;
}
- psk->next = cache->psk;
- cache->psk = psk;
+ psk->next = cache->info.psk;
+ cache->info.psk = psk;
psk = NULL;
}
skip:
@@ -518,6 +453,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_data *hapd = data;
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
+ struct radius_sta *info;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
query = hapd->acl_queries;
@@ -555,65 +491,66 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
+ info = &cache->info;
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
size_t len;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
- &cache->session_timeout) == 0)
+ &info->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
else
cache->accepted = HOSTAPD_ACL_ACCEPT;
if (radius_msg_get_attr_int32(
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
- &cache->acct_interim_interval) == 0 &&
- cache->acct_interim_interval < 60) {
+ &info->acct_interim_interval) == 0 &&
+ info->acct_interim_interval < 60) {
wpa_printf(MSG_DEBUG, "Ignored too small "
"Acct-Interim-Interval %d for STA " MACSTR,
- cache->acct_interim_interval,
+ info->acct_interim_interval,
MAC2STR(query->addr));
- cache->acct_interim_interval = 0;
+ info->acct_interim_interval = 0;
}
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
- cache->vlan_id.notempty = !!radius_msg_get_vlanid(
- msg, &cache->vlan_id.untagged,
- MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
+ info->vlan_id.notempty = !!radius_msg_get_vlanid(
+ msg, &info->vlan_id.untagged,
+ MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
&buf, &len, NULL) == 0) {
- cache->identity = os_zalloc(len + 1);
- if (cache->identity)
- os_memcpy(cache->identity, buf, len);
+ info->identity = os_zalloc(len + 1);
+ if (info->identity)
+ os_memcpy(info->identity, buf, len);
}
if (radius_msg_get_attr_ptr(
msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
- cache->radius_cui = os_zalloc(len + 1);
- if (cache->radius_cui)
- os_memcpy(cache->radius_cui, buf, len);
+ info->radius_cui = os_zalloc(len + 1);
+ if (info->radius_cui)
+ os_memcpy(info->radius_cui, buf, len);
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
- !cache->psk)
+ !info->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
- if (cache->vlan_id.notempty &&
- !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
+ if (info->vlan_id.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) {
hostapd_logger(hapd, query->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN %d%s received from RADIUS server",
- cache->vlan_id.untagged,
- cache->vlan_id.tagged[0] ? "+" : "");
- os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
+ info->vlan_id.untagged,
+ info->vlan_id.tagged[0] ? "+" : "");
+ os_memset(&info->vlan_id, 0, sizeof(info->vlan_id));
}
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
- !cache->vlan_id.notempty)
+ !info->vlan_id.notempty)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
@@ -622,7 +559,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
#ifdef CONFIG_DRIVER_RADIUS_ACL
hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
- cache->session_timeout);
+ info->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
/* Re-send original authentication frame for 802.11 processing */
@@ -685,6 +622,19 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
}
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src)
+{
+ if (!psk)
+ return;
+
+ if (src)
+ src->ref++;
+
+ *psk = src;
+}
+
+
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
{
if (psk && psk->ref) {
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 5aece51..9410f55 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -16,18 +16,25 @@ enum {
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
+struct radius_sta {
+ u32 session_timeout;
+ u32 acct_interim_interval;
+ struct vlan_description vlan_id;
+ struct hostapd_sta_wpa_psk_short *psk;
+ char *identity;
+ char *radius_cui;
+};
+
int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
struct vlan_description *vlan_id);
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
- const u8 *msg, size_t len, u32 *session_timeout,
- u32 *acct_interim_interval,
- struct vlan_description *vlan_id,
- struct hostapd_sta_wpa_psk_short **psk,
- char **identity, char **radius_cui,
+ const u8 *msg, size_t len, struct radius_sta *out,
int is_probe_req);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
void hostapd_acl_expire(struct hostapd_data *hapd);
+void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src);
#endif /* IEEE802_11_AUTH_H */
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index abd3940..85b7140 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -192,9 +192,12 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
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);
+ if (hapd->iface->conf->he_op.he_bss_color_disabled)
+ params |= HE_OPERATION_BSS_COLOR_DISABLED;
+ if (hapd->iface->conf->he_op.he_bss_color_partial)
+ params |= HE_OPERATION_BSS_COLOR_PARTIAL;
+ 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 =
@@ -206,17 +209,25 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
if (is_6ghz_op_class(hapd->iconf->op_class)) {
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
+ u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
if (!seg0)
seg0 = hapd->iconf->channel;
params |= HE_OPERATION_6GHZ_OPER_INFO;
+
+ /* 6 GHz Operation Information field */
*pos++ = hapd->iconf->channel; /* Primary Channel */
- *pos++ = center_idx_to_bw_6ghz(seg0); /* Control: Channel Width
- */
- /* Channel Center Freq Seg0/Seg0 */
+
+ /* Control: Channel Width */
+ if (seg1)
+ *pos++ = 3;
+ else
+ *pos++ = center_idx_to_bw_6ghz(seg0);
+
+ /* Channel Center Freq Seg0/Seg1 */
*pos++ = seg0;
- *pos++ = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
+ *pos++ = seg1;
/* Minimum Rate */
*pos++ = 6; /* TODO: what should be set here? */
}
@@ -300,6 +311,35 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
}
+u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
+{
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+ struct he_capabilities *he_cap;
+ struct ieee80211_he_6ghz_band_cap *cap;
+ u16 capab;
+ u8 *pos;
+
+ if (!mode || !is_6ghz_op_class(hapd->iconf->op_class) ||
+ !is_6ghz_freq(hapd->iface->freq))
+ return eid;
+
+ he_cap = &mode->he_capab[IEEE80211_MODE_AP];
+ capab = he_cap->he_6ghz_capa;
+ capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
+
+ pos = eid;
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sizeof(*cap);
+ *pos++ = WLAN_EID_EXT_HE_6GHZ_BAND_CAP;
+
+ cap = (struct ieee80211_he_6ghz_band_cap *) pos;
+ cap->capab = host_to_le16(capab);
+ pos += sizeof(*cap);
+
+ 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,
@@ -402,3 +442,44 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
}
+
+
+u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *he_6ghz_capab)
+{
+ if (!he_6ghz_capab || !hapd->iconf->ieee80211ax ||
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
+ sta->flags &= ~WLAN_STA_6GHZ;
+ os_free(sta->he_6ghz_capab);
+ sta->he_6ghz_capab = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (!sta->he_6ghz_capab) {
+ sta->he_6ghz_capab =
+ os_zalloc(sizeof(struct ieee80211_he_6ghz_band_cap));
+ if (!sta->he_6ghz_capab)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_6GHZ;
+ os_memcpy(sta->he_6ghz_capab, he_6ghz_capab,
+ sizeof(struct ieee80211_he_6ghz_band_cap));
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
+ enum ieee80211_op_mode mode)
+{
+ u8 *mac_cap;
+
+ if (!hapd->iface->current_mode ||
+ !hapd->iface->current_mode->he_capab[mode].he_supported)
+ return 0;
+
+ mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
+
+ return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER);
+}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 6db9365..59ecbdc 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -109,33 +109,9 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
}
-u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
-{
- u8 sec_ch;
-
- if (!hapd->cs_freq_params.channel ||
- !hapd->cs_freq_params.sec_channel_offset ||
- is_6ghz_op_class(hapd->iconf->op_class))
- return eid;
-
- if (hapd->cs_freq_params.sec_channel_offset == -1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
- else if (hapd->cs_freq_params.sec_channel_offset == 1)
- sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
- else
- return eid;
-
- *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
- *eid++ = 1;
- *eid++ = sec_ch;
-
- return eid;
-}
-
-
/*
op_mode
-Set to 0 (HT pure) under the followign conditions
+Set to 0 (HT pure) under the following conditions
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
Set to 1 (HT non-member protection) if there may be non-HT STAs
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index f24963e..17003d5 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_config.h"
@@ -72,6 +73,16 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
"Failed to get channel info for OCI element in SA Query Request");
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_saquery_req) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_saquery_req);
+ ci.frequency =
+ hapd->conf->oci_freq_override_saquery_req;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -112,7 +123,8 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
- if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0, NULL, 0, 0)
+ < 0)
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
os_free(mgmt);
@@ -150,6 +162,16 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
"Failed to get channel info for OCI element in SA Query Response");
return;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_saquery_resp) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_saquery_resp);
+ ci.frequency =
+ hapd->conf->oci_freq_override_saquery_resp;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -193,7 +215,8 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
- if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0, NULL, 0, 0)
+ < 0)
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
os_free(resp);
@@ -252,14 +275,21 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
return;
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ tx_chanwidth, tx_seg1_idx) !=
+ OCI_SUCCESS) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
+ MACSTR " frame=saquery%s error=%s",
+ MAC2STR(sa),
+ action_type == WLAN_SA_QUERY_REQUEST ?
+ "req" : "resp", ocv_errorstr);
return;
}
}
#endif /* CONFIG_OCV */
if (action_type == WLAN_SA_QUERY_REQUEST) {
+ if (sta)
+ sta->post_csa_sa_query = 0;
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
return;
}
@@ -375,6 +405,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
*pos |= 0x01;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax &&
+ hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+ *pos |= 0x40; /* Bit 78 - TWT responder */
+#endif /* CONFIG_IEEE80211AX */
break;
case 10: /* Bits 80-87 */
#ifdef CONFIG_SAE
@@ -390,6 +425,16 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
* Identifiers Used Exclusively */
}
#endif /* CONFIG_SAE */
+ if (hapd->conf->beacon_prot)
+ *pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
+ break;
+ case 11: /* Bits 88-95 */
+#ifdef CONFIG_SAE_PK
+ if (hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pk_exclusively(hapd->conf))
+ *pos |= 0x01; /* Bit 88 - SAE PK Exclusively */
+#endif /* CONFIG_SAE_PK */
break;
}
}
@@ -400,14 +445,22 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
u8 *pos = eid;
u8 len = 0, i;
- if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+ if (hapd->conf->qos_map_set_len ||
+ (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)))
len = 5;
- if (len < 4 && hapd->conf->interworking)
+ if (len < 4 &&
+ (hapd->conf->time_advertisement == 2 || hapd->conf->interworking))
len = 4;
- if (len < 3 && hapd->conf->wnm_sleep_mode)
+ if (len < 3 &&
+ (hapd->conf->wnm_sleep_mode || hapd->conf->bss_transition))
len = 3;
- if (len < 1 && hapd->iconf->obss_interval)
+ if (len < 1 &&
+ (hapd->iconf->obss_interval ||
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)))
len = 1;
+ if (len < 2 &&
+ (hapd->conf->proxy_arp || hapd->conf->coloc_intf_reporting))
+ len = 2;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
if (len < 9 &&
@@ -430,12 +483,25 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
len = 10;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ if (len < 10 && hapd->iconf->ieee80211ax &&
+ hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+ len = 10;
+#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_SAE
if (len < 11 && hapd->conf->wpa &&
wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
hostapd_sae_pw_id_in_use(hapd->conf))
len = 11;
#endif /* CONFIG_SAE */
+ if (len < 11 && hapd->conf->beacon_prot)
+ len = 11;
+#ifdef CONFIG_SAE_PK
+ if (len < 12 && hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pk_exclusively(hapd->conf))
+ len = 12;
+#endif /* CONFIG_SAE_PK */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -850,6 +916,35 @@ u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
}
+size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_DPP2
+ if (hapd->conf->dpp_configurator_connectivity)
+ return 6;
+#endif /* CONFIG_DPP2 */
+ return 0;
+}
+
+
+u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ u8 *pos = eid;
+
+#ifdef CONFIG_DPP2
+ if (!hapd->conf->dpp_configurator_connectivity || len < 6)
+ return pos;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = DPP_CC_OUI_TYPE;
+#endif /* CONFIG_DPP2 */
+
+ return pos;
+}
+
+
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
const u8 *supp_op_classes,
size_t supp_op_classes_len)
@@ -1001,9 +1096,17 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
{
u8 *pos = eid;
+ bool sae_pk = false;
+
+#ifdef CONFIG_SAE_PK
+ sae_pk = hostapd_sae_pk_in_use(hapd->conf);
+#endif /* CONFIG_SAE_PK */
if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
- (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2) ||
+ !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
+ (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
+ !hostapd_sae_pw_id_in_use(hapd->conf) && !sae_pk) ||
+ hapd->conf->sae_pwe == 3 ||
len < 3)
return pos;
@@ -1011,7 +1114,12 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
*pos++ = 1;
/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
* used for now */
- *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ *pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (sae_pk)
+ *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ pos++;
return pos;
}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index f50f142..c925bf1 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -167,59 +167,6 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
}
-u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
-{
- u8 bw, chan1, chan2 = 0;
- int freq1;
-
- if (!hapd->cs_freq_params.channel ||
- !hapd->cs_freq_params.vht_enabled)
- return eid;
-
- /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
- switch (hapd->cs_freq_params.bandwidth) {
- case 40:
- bw = 0;
- break;
- case 80:
- /* check if it's 80+80 */
- if (!hapd->cs_freq_params.center_freq2)
- bw = 1;
- else
- bw = 3;
- break;
- case 160:
- bw = 2;
- break;
- default:
- /* not valid VHT bandwidth or not in CSA */
- return eid;
- }
-
- freq1 = hapd->cs_freq_params.center_freq1 ?
- hapd->cs_freq_params.center_freq1 :
- hapd->cs_freq_params.freq;
- if (ieee80211_freq_to_chan(freq1, &chan1) !=
- HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- if (hapd->cs_freq_params.center_freq2 &&
- ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
- &chan2) != HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
- *eid++ = 5; /* Length of Channel Switch Wrapper */
- *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
- *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
- *eid++ = bw; /* New Channel Width */
- *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
- *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
-
- return eid;
-}
-
-
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
{
struct hostapd_iface *iface = hapd->iface;
@@ -425,7 +372,9 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- if (!hapd->iface->current_mode)
+ /* Vendor VHT is applicable only to 2.4 GHz */
+ if (!hapd->iface->current_mode ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return eid;
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index d081031..ee095f6 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -137,6 +137,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
}
+#ifdef CONFIG_WEP
#ifndef CONFIG_FIPS
#ifndef CONFIG_NO_RC4
@@ -284,8 +285,9 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
/* TODO: set encryption in TX callback, i.e., only after STA
* has ACKed EAPOL-Key frame */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
- sta->addr, 0, 1, NULL, 0, ikey,
- hapd->conf->individual_wep_key_len)) {
+ sta->addr, 0, 0, 1, NULL, 0, ikey,
+ hapd->conf->individual_wep_key_len,
+ KEY_FLAG_PAIRWISE_RX_TX)) {
wpa_printf(MSG_ERROR,
"Could not set individual WEP encryption");
}
@@ -296,6 +298,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
+#endif /* CONFIG_WEP */
const char *radius_mode_txt(struct hostapd_data *hapd)
@@ -875,7 +878,7 @@ static void handle_eap_response(struct hostapd_data *hapd,
wpabuf_free(sm->eap_if->eapRespData);
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
- sm->eapolEap = TRUE;
+ sm->eapolEap = true;
}
@@ -906,7 +909,7 @@ static void handle_eap_initiate(struct hostapd_data *hapd,
wpabuf_free(sm->eap_if->eapRespData);
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
- sm->eapolEap = TRUE;
+ sm->eapolEap = true;
#endif /* CONFIG_ERP */
}
@@ -1137,7 +1140,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
}
#endif /* CONFIG_WPS */
- sta->eapol_sm->eap_if->portEnabled = TRUE;
+ sta->eapol_sm->eap_if->portEnabled = true;
}
/* since we support version 1, we can ignore version field and proceed
@@ -1164,7 +1167,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
"cached PMKSA available - ignore it since STA sent EAPOL-Start");
wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
}
- sta->eapol_sm->eapolStart = TRUE;
+ sta->eapol_sm->eapolStart = true;
sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap);
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
@@ -1177,7 +1180,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
accounting_sta_stop(hapd, sta);
- sta->eapol_sm->eapolLogoff = TRUE;
+ sta->eapol_sm->eapolLogoff = true;
sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap);
break;
@@ -1294,7 +1297,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
}
#endif /* CONFIG_WPS */
- sta->eapol_sm->eap_if->portEnabled = TRUE;
+ sta->eapol_sm->eap_if->portEnabled = true;
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@@ -1303,13 +1306,13 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
"PMK from FT - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing FT information from R0KH. */
- sta->eapol_sm->keyRun = TRUE;
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->keyRun = true;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
- sta->eapol_sm->authSuccess = TRUE;
- sta->eapol_sm->authFail = FALSE;
- sta->eapol_sm->portValid = TRUE;
+ sta->eapol_sm->authSuccess = true;
+ sta->eapol_sm->authFail = false;
+ sta->eapol_sm->portValid = true;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
ap_sta_bind_vlan(hapd, sta);
@@ -1326,13 +1329,13 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
"PMK from FILS - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing FILS information. */
- sta->eapol_sm->keyRun = TRUE;
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->keyRun = true;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
- sta->eapol_sm->authSuccess = TRUE;
- sta->eapol_sm->authFail = FALSE;
- sta->eapol_sm->portValid = TRUE;
+ sta->eapol_sm->authSuccess = true;
+ sta->eapol_sm->authFail = false;
+ 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);
@@ -1347,12 +1350,12 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
"PMK from PMKSA cache - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state
* because of existing PMKSA information in the cache. */
- sta->eapol_sm->keyRun = TRUE;
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->keyRun = true;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
- sta->eapol_sm->authSuccess = TRUE;
- sta->eapol_sm->authFail = FALSE;
+ sta->eapol_sm->authSuccess = true;
+ sta->eapol_sm->authFail = false;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
@@ -1364,7 +1367,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
* re-authentication without having to wait for the
* Supplicant to send EAPOL-Start.
*/
- sta->eapol_sm->reAuthenticate = TRUE;
+ sta->eapol_sm->reAuthenticate = true;
}
eapol_auth_step(sta->eapol_sm);
}
@@ -1412,7 +1415,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
if (!sm || !sm->last_recv_radius) {
if (sm)
- sm->eap_if->aaaEapNoReq = TRUE;
+ sm->eap_if->aaaEapNoReq = true;
return;
}
@@ -1426,7 +1429,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING,
"could not extract EAP-Message from RADIUS message");
- sm->eap_if->aaaEapNoReq = TRUE;
+ sm->eap_if->aaaEapNoReq = true;
return;
}
@@ -1435,7 +1438,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
HOSTAPD_LEVEL_WARNING,
"too short EAP packet received from authentication server");
wpabuf_free(eap);
- sm->eap_if->aaaEapNoReq = TRUE;
+ sm->eap_if->aaaEapNoReq = true;
return;
}
@@ -1470,7 +1473,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
"decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s",
hdr->code, hdr->identifier, be_to_host16(hdr->length),
buf);
- sm->eap_if->aaaEapReq = TRUE;
+ sm->eap_if->aaaEapReq = true;
wpabuf_free(sm->eap_if->aaaEapReqData);
sm->eap_if->aaaEapReqData = eap;
@@ -1509,7 +1512,7 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
keys->send, keys->send_len);
sm->eap_if->aaaEapKeyDataLen = len;
- sm->eap_if->aaaEapKeyAvailable = TRUE;
+ sm->eap_if->aaaEapKeyAvailable = true;
}
} else {
wpa_printf(MSG_DEBUG,
@@ -1877,7 +1880,7 @@ static int ieee802_1x_update_vlan(struct radius_msg *msg,
if (vlan_desc.notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
- sta->eapol_sm->authFail = TRUE;
+ sta->eapol_sm->authFail = true;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN %d%s received from RADIUS server",
@@ -1890,7 +1893,7 @@ static int ieee802_1x_update_vlan(struct radius_msg *msg,
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
!vlan_desc.notempty) {
- sta->eapol_sm->authFail = TRUE;
+ sta->eapol_sm->authFail = true;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
"authentication server did not include required VLAN ID in Access-Accept");
@@ -2016,7 +2019,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
else
ap_sta_no_session_timeout(hapd, sta);
- sm->eap_if->aaaSuccess = TRUE;
+ sm->eap_if->aaaSuccess = true;
override_eapReq = 1;
ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
shared_secret_len);
@@ -2028,7 +2031,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
(int) session_timeout : -1);
break;
case RADIUS_CODE_ACCESS_REJECT:
- sm->eap_if->aaaFail = TRUE;
+ sm->eap_if->aaaFail = true;
override_eapReq = 1;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
&reason_code) == 0) {
@@ -2039,7 +2042,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
}
break;
case RADIUS_CODE_ACCESS_CHALLENGE:
- sm->eap_if->aaaEapReq = TRUE;
+ sm->eap_if->aaaEapReq = true;
if (session_timeout_set) {
/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
sm->eap_if->aaaMethodTimeout = session_timeout;
@@ -2060,7 +2063,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
ieee802_1x_decapsulate_radius(hapd, sta);
if (override_eapReq)
- sm->eap_if->aaaEapReq = FALSE;
+ sm->eap_if->aaaEapReq = false;
#ifdef CONFIG_FILS
#ifdef NEED_AP_MLME
@@ -2106,13 +2109,15 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
MAC2STR(sta->addr));
- sm->eap_if->portEnabled = FALSE;
+ sm->eap_if->portEnabled = false;
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
}
}
+#ifdef CONFIG_WEP
+
static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
{
struct eapol_authenticator *eapol = hapd->eapol_auth;
@@ -2143,7 +2148,7 @@ static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx)
{
if (sta->eapol_sm) {
- sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->eap_if->eapKeyAvailable = true;
eapol_auth_step(sta->eapol_sm);
}
return 0;
@@ -2177,9 +2182,10 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
* after new broadcast key has been sent to all stations. */
if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
broadcast_ether_addr,
- eapol->default_wep_key_idx, 1, NULL, 0,
+ eapol->default_wep_key_idx, 0, 1, NULL, 0,
eapol->default_wep_key,
- hapd->conf->default_wep_key_len)) {
+ hapd->conf->default_wep_key_len,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING,
"failed to configure a new broadcast key");
@@ -2196,6 +2202,8 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
}
}
+#endif /* CONFIG_WEP */
+
static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
const u8 *data, size_t datalen)
@@ -2359,6 +2367,7 @@ static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
}
+#ifdef CONFIG_WEP
static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
{
#ifndef CONFIG_FIPS
@@ -2370,6 +2379,7 @@ static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
}
+#endif /* CONFIG_WEP */
static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
@@ -2420,7 +2430,6 @@ static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
int ieee802_1x_init(struct hostapd_data *hapd)
{
- int i;
struct eapol_auth_config conf;
struct eapol_auth_cb cb;
@@ -2431,7 +2440,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.ctx = hapd;
conf.eap_reauth_period = hapd->conf->eap_reauth_period;
conf.wpa = hapd->conf->wpa;
+#ifdef CONFIG_WEP
conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
+#endif /* CONFIG_WEP */
conf.eap_req_id_text = hapd->conf->eap_req_id_text;
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
@@ -2446,7 +2457,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
cb.logger = ieee802_1x_logger;
cb.set_port_authorized = ieee802_1x_set_port_authorized;
cb.abort_auth = _ieee802_1x_abort_auth;
+#ifdef CONFIG_WEP
cb.tx_key = _ieee802_1x_tx_key;
+#endif /* CONFIG_WEP */
cb.eapol_event = ieee802_1x_eapol_event;
#ifdef CONFIG_ERP
cb.erp_get_key = ieee802_1x_erp_get_key;
@@ -2467,17 +2480,21 @@ int ieee802_1x_init(struct hostapd_data *hapd)
return -1;
#endif /* CONFIG_NO_RADIUS */
+#ifdef CONFIG_WEP
if (hapd->conf->default_wep_key_len) {
+ int i;
+
for (i = 0; i < 4; i++)
hostapd_drv_set_key(hapd->conf->iface, hapd,
- WPA_ALG_NONE, NULL, i, 0, NULL, 0,
- NULL, 0);
+ WPA_ALG_NONE, NULL, i, 0, 0, NULL,
+ 0, NULL, 0, KEY_FLAG_GROUP);
ieee802_1x_rekey(hapd, NULL);
if (!hapd->eapol_auth->default_wep_key)
return -1;
}
+#endif /* CONFIG_WEP */
return 0;
}
@@ -2497,7 +2514,9 @@ void ieee802_1x_erp_flush(struct hostapd_data *hapd)
void ieee802_1x_deinit(struct hostapd_data *hapd)
{
+#ifdef CONFIG_WEP
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
+#endif /* CONFIG_WEP */
if (hapd->driver && hapd->drv_priv &&
(hapd->conf->ieee802_1x || hapd->conf->wpa))
@@ -2658,26 +2677,25 @@ const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
- int enabled)
+ bool enabled)
{
if (!sm)
return;
- sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
+ sm->eap_if->portEnabled = enabled;
eapol_auth_step(sm);
}
-void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
- int valid)
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid)
{
if (!sm)
return;
- sm->portValid = valid ? TRUE : FALSE;
+ sm->portValid = valid;
eapol_auth_step(sm);
}
-void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth)
{
if (!sm)
return;
@@ -2688,7 +2706,7 @@ void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
}
-static const char * bool_txt(Boolean val)
+static const char * bool_txt(bool val)
{
return val ? "TRUE" : "FALSE";
}
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index bb85b93..70dc11a 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -42,10 +42,9 @@ 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,
- int valid);
-void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
+ bool enabled);
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid);
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth);
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 5415443..01bf886 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -34,6 +34,60 @@ hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
}
+int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+ struct hostapd_neighbor_entry *nr;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ int ret;
+ char nrie[2 * 255 + 1];
+ char lci[2 * 255 + 1];
+ char civic[2 * 255 + 1];
+ char ssid[SSID_MAX_LEN * 2 + 1];
+
+ ssid[0] = '\0';
+ wpa_snprintf_hex(ssid, sizeof(ssid), nr->ssid.ssid,
+ nr->ssid.ssid_len);
+
+ nrie[0] = '\0';
+ if (nr->nr)
+ wpa_snprintf_hex(nrie, sizeof(nrie),
+ wpabuf_head(nr->nr),
+ wpabuf_len(nr->nr));
+
+ lci[0] = '\0';
+ if (nr->lci)
+ wpa_snprintf_hex(lci, sizeof(lci),
+ wpabuf_head(nr->lci),
+ wpabuf_len(nr->lci));
+
+ civic[0] = '\0';
+ if (nr->civic)
+ wpa_snprintf_hex(civic, sizeof(civic),
+ wpabuf_head(nr->civic),
+ wpabuf_len(nr->civic));
+
+ ret = os_snprintf(pos, end - pos, MACSTR
+ " ssid=%s%s%s%s%s%s%s%s\n",
+ MAC2STR(nr->bssid), ssid,
+ nr->nr ? " nr=" : "", nrie,
+ nr->lci ? " lci=" : "", lci,
+ nr->civic ? " civic=" : "", civic,
+ nr->stationary ? " stat" : "");
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
{
wpabuf_free(nr->nr);
@@ -202,6 +256,8 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
if (vht)
bssid_info |= NEI_REP_BSSID_INFO_VHT;
+ if (he)
+ bssid_info |= NEI_REP_BSSID_INFO_HE;
}
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
index 9c8f4f2..bed0a2f 100644
--- a/src/ap/neighbor_db.h
+++ b/src/ap/neighbor_db.h
@@ -13,6 +13,7 @@
struct hostapd_neighbor_entry *
hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid);
+int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen);
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid,
const struct wpabuf *nr, const struct wpabuf *lci,
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 15e2c49..fe5f817 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -516,6 +516,11 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
+ if (wpa_key_mgmt_sae(entry->akmp)) {
+ if (os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
+ return entry;
+ continue;
+ }
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
entry->akmp);
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
diff --git a/src/ap/preauth_auth.c b/src/ap/preauth_auth.c
index 3e0c800..2ff1861 100644
--- a/src/ap/preauth_auth.c
+++ b/src/ap/preauth_auth.c
@@ -82,7 +82,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
sta = NULL;
} else {
sta->eapol_sm->radius_identifier = -1;
- sta->eapol_sm->portValid = TRUE;
+ sta->eapol_sm->portValid = true;
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
}
}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index d7734ee..67b5e98 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -164,6 +164,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
/* just in case */
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
@@ -233,9 +234,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
sta->assoc_ie_taxonomy = NULL;
#endif /* CONFIG_TAXONOMY */
-#ifdef CONFIG_IEEE80211N
ht40_intolerant_remove(hapd->iface, sta);
-#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
@@ -246,10 +245,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
}
#endif /* CONFIG_P2P */
-#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
+#ifdef NEED_AP_MLME
if (hostapd_ht_operation_update(hapd->iface) > 0)
set_beacon++;
-#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
+#endif /* NEED_AP_MLME */
#ifdef CONFIG_MESH
if (hapd->mesh_sta_free_cb)
@@ -327,6 +326,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->vht_capabilities);
os_free(sta->vht_operation);
os_free(sta->he_capab);
+ os_free(sta->he_6ghz_capab);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@@ -373,6 +373,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->ifname_wds);
+#ifdef CONFIG_TESTING_OPTIONS
+ os_free(sta->sae_postponed_commit);
+#endif /* CONFIG_TESTING_OPTIONS */
+
os_free(sta);
}
@@ -542,6 +546,7 @@ skip_poll:
case STA_DISASSOC_FROM_CLI:
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~WLAN_STA_ASSOC;
+ hostapd_set_sta_flags(hapd, sta);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
@@ -586,7 +591,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
- if (!(sta->flags & WLAN_STA_AUTH)) {
+ if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC |
+ WLAN_STA_AUTHORIZED))) {
if (sta->flags & WLAN_STA_GAS) {
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
"entry " MACSTR, MAC2STR(sta->addr));
@@ -809,6 +815,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
sta->timeout_next = STA_DEAUTH;
}
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
@@ -859,6 +866,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_set_sta_flags(hapd, sta);
sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
@@ -1024,6 +1032,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
int ret;
int old_vlanid = sta->vlan_id_bound;
+ if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
+ wpa_printf(MSG_DEBUG,
+ "Do not override WDS VLAN assignment for STA "
+ MACSTR, MAC2STR(sta->addr));
+ return 0;
+ }
+
iface = hapd->conf->iface;
if (hapd->conf->ssid.vlan[0])
iface = hapd->conf->ssid.vlan;
@@ -1045,7 +1060,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->vlan_id == old_vlanid)
goto skip_counting;
- if (sta->vlan_id > 0 && vlan == NULL) {
+ if (sta->vlan_id > 0 && !vlan &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
"binding station to (vlan_id=%d)",
@@ -1129,6 +1145,8 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
if (sta->sa_query_count > 0 &&
ap_check_sa_query_timeout(hapd, sta))
return;
+ if (sta->sa_query_count >= 1000)
+ return;
nbuf = os_realloc_array(sta->sa_query_trans_id,
sta->sa_query_count + 1,
@@ -1316,9 +1334,10 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
if (sta == NULL)
return;
ap_sta_set_authorized(hapd, sta, 0);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
@@ -1406,7 +1425,8 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
int res;
buf[0] = '\0';
- res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ res = os_snprintf(buf, buflen,
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1425,6 +1445,8 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
(flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
+ (flags & WLAN_STA_HE ? "[HE]" : ""),
+ (flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
@@ -1478,3 +1500,33 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
hapd, sta);
}
+
+
+int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ /*
+ * If a station that is already associated to the AP, is trying to
+ * authenticate again, remove the STA entry, in order to make sure the
+ * STA PS state gets cleared and configuration gets updated. To handle
+ * this, station's added_unassoc flag is cleared once the station has
+ * completed association.
+ */
+ ap_sta_set_authorized(hapd, sta, 0);
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED);
+
+ if (hostapd_sta_add(hapd, sta->addr, 0, 0,
+ sta->supported_rates,
+ sta->supported_rates_len,
+ 0, NULL, NULL, NULL, 0, NULL,
+ sta->flags, 0, 0, 0, 0)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_NOTICE,
+ "Could not add STA to kernel driver");
+ return -1;
+ }
+
+ sta->added_unassoc = 1;
+ return 0;
+}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index de806b4..ef48561 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -38,6 +38,7 @@
#define WLAN_STA_PENDING_FILS_ERP BIT(22)
#define WLAN_STA_MULTI_AP BIT(23)
#define WLAN_STA_HE BIT(24)
+#define WLAN_STA_6GHZ BIT(25)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -121,6 +122,7 @@ struct sta_info {
unsigned int hs20_t_c_filtering:1;
unsigned int ft_over_ds:1;
unsigned int external_dh_updated:1;
+ unsigned int post_csa_sa_query:1;
u16 auth_alg;
@@ -170,6 +172,7 @@ struct sta_info {
u8 vht_opmode;
struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
+ struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
@@ -276,6 +279,8 @@ struct sta_info {
int last_tk_key_idx;
u8 last_tk[WPA_TK_MAX_LEN];
size_t last_tk_len;
+ u8 *sae_postponed_commit;
+ size_t sae_postponed_commit_len;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
@@ -356,5 +361,6 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta);
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta);
+int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* STA_INFO_H */
diff --git a/src/ap/utils.c b/src/ap/utils.c
index fcb371b..bedad6e 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -56,6 +56,10 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
ohapd = iface->bss[j];
if (ohapd == data->hapd)
continue;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (ohapd->conf->skip_prune_assoc)
+ continue;
+#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FST
/* Don't prune STAs belong to same FST */
if (ohapd->iface->fst &&
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index e293a00..53eacfb 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -22,7 +22,9 @@
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
{
- int ret, i;
+ int ret;
+#ifdef CONFIG_WEP
+ int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (!hapd->conf->ssid.wep.key[i])
@@ -32,6 +34,7 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
vlan->ifname);
return -1;
}
+#endif /* CONFIG_WEP */
if (!iface_exists(vlan->ifname))
ret = hostapd_vlan_if_add(hapd, vlan->ifname);
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index dc73493..9ebb01e 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -111,9 +111,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
u8 *pos = eid;
struct wmm_parameter_element *wmm =
(struct wmm_parameter_element *) (pos + 2);
- struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM] = { 0 };
+ struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM];
int e;
+ os_memset(wmmp, 0, sizeof(wmmp));
+
if (!hapd->conf->wmm_enabled)
return eid;
wmm_calc_regulatory_limit(hapd, wmmp);
@@ -209,7 +211,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
len = ((u8 *) (t + 1)) - buf;
- if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
+ if (hostapd_drv_send_mlme(hapd, m, len, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "wmm_send_action: send failed");
}
@@ -291,10 +293,11 @@ int wmm_process_tspec(struct wmm_tspec_element *tspec)
static void wmm_addts_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
- struct wmm_tspec_element *tspec, size_t len)
+ const struct wmm_tspec_element *tspec, size_t len)
{
const u8 *end = ((const u8 *) mgmt) + len;
int res;
+ struct wmm_tspec_element tspec_resp;
if ((const u8 *) (tspec + 1) > end) {
wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
@@ -306,10 +309,11 @@ static void wmm_addts_req(struct hostapd_data *hapd,
mgmt->u.action.u.wmm_action.dialog_token,
MAC2STR(mgmt->sa));
- res = wmm_process_tspec(tspec);
+ os_memcpy(&tspec_resp, tspec, sizeof(struct wmm_tspec_element));
+ res = wmm_process_tspec(&tspec_resp);
wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
- wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
+ wmm_send_action(hapd, mgmt->sa, &tspec_resp, WMM_ACTION_CODE_ADDTS_RESP,
mgmt->u.action.u.wmm_action.dialog_token, res);
}
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index e4dcfe9..be81797 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -54,6 +54,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
size_t len;
size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0;
+ size_t bigtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie;
u8 *wnmtfs_ie, *oci_ie;
u8 wnmsleep_ie_len, oci_ie_len;
@@ -102,6 +103,15 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
os_free(wnmtfs_ie);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->oci_freq_override_wnm_sleep) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ hapd->conf->oci_freq_override_wnm_sleep);
+ ci.frequency = hapd->conf->oci_freq_override_wnm_sleep;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@@ -122,8 +132,10 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#define MAX_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26
+#define MAX_BIGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+ MAX_BIGTK_SUBELEM_LEN +
oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
@@ -157,10 +169,19 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len);
+ if (hapd->conf->beacon_prot) {
+ res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
+ if (res < 0)
+ goto fail;
+ bigtk_elem_len = res;
+ pos += bigtk_elem_len;
+ wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d",
+ (int) bigtk_elem_len);
+ }
WPA_PUT_LE16((u8 *)
&mgmt->u.action.u.wnm_sleep_resp.keydata_len,
- gtk_elem_len + igtk_elem_len);
+ gtk_elem_len + igtk_elem_len + bigtk_elem_len);
}
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
@@ -176,7 +197,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#endif /* CONFIG_OCV */
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
- igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
+ igtk_elem_len + bigtk_elem_len +
+ wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
/* In driver, response frame should be forced to sent when STA is in
* PS mode */
@@ -189,8 +211,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
/* when entering wnmsleep
* 1. pause the node in driver
- * 2. mark the node so that AP won't update GTK/IGTK during
- * WNM Sleep
+ * 2. mark the node so that AP won't update GTK/IGTK/BIGTK
+ * during WNM Sleep
*/
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
@@ -201,7 +223,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
}
/* when exiting wnmsleep
* 1. unmark the node
- * 2. start GTK/IGTK update if MFP is not used
+ * 2. start GTK/IGTK/BIGTK update if MFP is not used
* 3. unpause the node in driver
*/
if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
@@ -221,6 +243,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#undef MAX_GTK_SUBELEM_LEN
#undef MAX_IGTK_SUBELEM_LEN
+#undef MAX_BIGTK_SUBELEM_LEN
fail:
os_free(wnmtfs_ie);
os_free(oci_ie);
@@ -303,8 +326,9 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
channel_width_to_int(ci.chanwidth),
- ci.seg1_idx) != 0) {
- wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ ci.seg1_idx) != OCI_SUCCESS) {
+ wpa_msg(hapd, MSG_WARNING, "WNM: OCV failed: %s",
+ ocv_errorstr);
return;
}
}
@@ -508,6 +532,30 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
}
+static void wnm_beacon_protection_failure(struct hostapd_data *hapd,
+ const u8 *addr)
+{
+ struct sta_info *sta;
+
+ if (!hapd->conf->beacon_prot)
+ return;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for received WNM-Notification Request",
+ MAC2STR(addr));
+ return;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Beacon protection failure reported");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_UNPROT_BEACON "reporter="
+ MACSTR, MAC2STR(addr));
+}
+
+
static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *buf,
size_t len)
@@ -526,8 +574,14 @@ static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
MAC2STR(addr), dialog_token, type);
wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
buf, len);
- if (type == WLAN_EID_VENDOR_SPECIFIC)
+ switch (type) {
+ case WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE:
+ wnm_beacon_protection_failure(hapd, addr);
+ break;
+ case WNM_NOTIF_TYPE_VENDOR_SPECIFIC:
mbo_ap_wnm_notification_req(hapd, addr, buf, len);
+ break;
+ }
}
@@ -641,7 +695,7 @@ int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
MACSTR, disassoc_timer, MAC2STR(sta->addr));
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@@ -714,7 +768,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
os_memcpy(pos, url, url_len);
pos += url_len;
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@@ -790,7 +844,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
mbo_len);
}
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"Failed to send BSS Transition Management Request frame");
os_free(buf);
@@ -834,7 +888,7 @@ int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
MAC2STR(sta->addr), dialog_token, auto_report, timeout);
- if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"WNM: Failed to send Collocated Interference Request frame");
return -1;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 7b690d7..9d74bfc 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -14,6 +14,8 @@
#include "utils/bitfield.h"
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
+#include "common/dpp.h"
+#include "common/wpa_ctrl.h"
#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes_siv.h"
@@ -56,13 +58,14 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk);
+ struct wpa_ptk *ptk, int force_sha256);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
+static int ieee80211w_kde_len(struct wpa_state_machine *sm);
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
static const u32 eapol_key_timeout_first = 100; /* ms */
@@ -105,7 +108,7 @@ static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var)
{
- if (wpa_auth->cb->get_eapol == NULL)
+ if (!wpa_auth->cb->get_eapol)
return -1;
return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var);
}
@@ -117,7 +120,7 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
const u8 *prev_psk, size_t *psk_len,
int *vlan_id)
{
- if (wpa_auth->cb->get_psk == NULL)
+ if (!wpa_auth->cb->get_psk)
return NULL;
return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
prev_psk, psk_len, vlan_id);
@@ -127,7 +130,7 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
const u8 *addr, u8 *msk, size_t *len)
{
- if (wpa_auth->cb->get_msk == NULL)
+ if (!wpa_auth->cb->get_msk)
return -1;
return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len);
}
@@ -136,21 +139,46 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
- if (wpa_auth->cb->set_key == NULL)
+ if (!wpa_auth->cb->set_key)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
}
static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
const u8 *addr, int idx, u8 *seq)
{
- if (wpa_auth->cb->get_seqnum == NULL)
+ int res;
+
+ if (!wpa_auth->cb->get_seqnum)
return -1;
- return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+ res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Override GTK RSC %016llx --> %016llx",
+ (long long unsigned) WPA_GET_LE64(seq),
+ (long long unsigned)
+ WPA_GET_LE64(wpa_auth->conf.gtk_rsc_override));
+ os_memcpy(seq, wpa_auth->conf.gtk_rsc_override,
+ WPA_KEY_RSC_LEN);
+ }
+ if (!addr && idx >= 4 && idx <= 5 &&
+ wpa_auth->conf.igtk_rsc_override_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Override IGTK RSC %016llx --> %016llx",
+ (long long unsigned) WPA_GET_LE64(seq),
+ (long long unsigned)
+ WPA_GET_LE64(wpa_auth->conf.igtk_rsc_override));
+ os_memcpy(seq, wpa_auth->conf.igtk_rsc_override,
+ WPA_KEY_RSC_LEN);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ return res;
}
@@ -158,7 +186,7 @@ static inline int
wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *data, size_t data_len, int encrypt)
{
- if (wpa_auth->cb->send_eapol == NULL)
+ if (!wpa_auth->cb->send_eapol)
return -1;
return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
encrypt);
@@ -169,7 +197,7 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
const u8 *addr)
{
- if (wpa_auth->cb->start_ampe == NULL)
+ if (!wpa_auth->cb->start_ampe)
return -1;
return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr);
}
@@ -180,7 +208,7 @@ int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb->for_each_sta == NULL)
+ if (!wpa_auth->cb->for_each_sta)
return 0;
return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx);
}
@@ -190,7 +218,7 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb->for_each_auth == NULL)
+ if (!wpa_auth->cb->for_each_auth)
return 0;
return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx);
}
@@ -199,7 +227,7 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt)
{
- if (wpa_auth->cb->logger == NULL)
+ if (!wpa_auth->cb->logger)
return;
wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt);
}
@@ -212,7 +240,7 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
int maxlen;
va_list ap;
- if (wpa_auth->cb->logger == NULL)
+ if (!wpa_auth->cb->logger)
return;
maxlen = os_strlen(fmt) + 100;
@@ -233,7 +261,7 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
const u8 *addr, u16 reason)
{
- if (wpa_auth->cb->disconnect == NULL)
+ if (!wpa_auth->cb->disconnect)
return;
wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR " (reason %u)",
MAC2STR(addr), reason);
@@ -266,8 +294,8 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
struct wpa_authenticator *wpa_auth = eloop_ctx;
if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
- wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
- "initialization.");
+ wpa_printf(MSG_ERROR,
+ "Failed to get random data for WPA initialization.");
} else {
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
wpa_hexdump_key(MSG_DEBUG, "GMK",
@@ -291,9 +319,9 @@ static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
while (group) {
wpa_group_get(wpa_auth, group);
- group->GTKReKey = TRUE;
+ group->GTKReKey = true;
do {
- group->changed = FALSE;
+ group->changed = false;
wpa_group_sm_step(wpa_auth, group);
} while (group->changed);
@@ -391,17 +419,16 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
struct wpa_group *group;
group = os_zalloc(sizeof(struct wpa_group));
- if (group == NULL)
+ if (!group)
return NULL;
- group->GTKAuthenticator = TRUE;
+ group->GTKAuthenticator = true;
group->vlan_id = vlan_id;
group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
if (random_pool_ready() != 1) {
- wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
- "for secure operations - update keys later when "
- "the first station connects");
+ wpa_printf(MSG_INFO,
+ "WPA: Not enough entropy in random pool for secure operations - update keys later when the first station connects");
}
/*
@@ -411,20 +438,20 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
* on embedded devices.
*/
if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
- wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
- "initialization.");
+ wpa_printf(MSG_ERROR,
+ "Failed to get random data for WPA initialization.");
os_free(group);
return NULL;
}
- group->GInit = TRUE;
+ group->GInit = true;
if (delay_init) {
- wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
- "until Beacon frames have been configured");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Delay group state machine start until Beacon frames have been configured");
/* Initialization is completed in wpa_init_keys(). */
} else {
wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
+ group->GInit = false;
wpa_group_sm_step(wpa_auth, group);
}
@@ -447,7 +474,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_authenticator *wpa_auth;
wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return NULL;
os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -461,7 +488,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
}
wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
- if (wpa_auth->group == NULL) {
+ if (!wpa_auth->group) {
os_free(wpa_auth->wpa_ie);
os_free(wpa_auth);
return NULL;
@@ -469,7 +496,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
wpa_auth);
- if (wpa_auth->pmksa == NULL) {
+ if (!wpa_auth->pmksa) {
wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
@@ -479,7 +506,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
#ifdef CONFIG_IEEE80211R_AP
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
- if (wpa_auth->ft_pmk_cache == NULL) {
+ if (!wpa_auth->ft_pmk_cache) {
wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
@@ -518,10 +545,10 @@ int wpa_init_keys(struct wpa_authenticator *wpa_auth)
{
struct wpa_group *group = wpa_auth->group;
- wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
- "keys");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Start group state machine to set initial keys");
wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
+ group->GInit = false;
wpa_group_sm_step(wpa_auth, group);
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
return -1;
@@ -575,7 +602,8 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf)
{
struct wpa_group *group;
- if (wpa_auth == NULL)
+
+ if (!wpa_auth)
return 0;
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
@@ -590,9 +618,9 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
*/
group = wpa_auth->group;
group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
- group->GInit = TRUE;
+ group->GInit = true;
wpa_group_sm_step(wpa_auth, group);
- group->GInit = FALSE;
+ group->GInit = false;
wpa_group_sm_step(wpa_auth, group);
return 0;
@@ -609,7 +637,7 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
return NULL;
sm = os_zalloc(sizeof(struct wpa_state_machine));
- if (sm == NULL)
+ if (!sm)
return NULL;
os_memcpy(sm->addr, addr, ETH_ALEN);
if (p2p_dev_addr)
@@ -626,17 +654,16 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm)
{
- if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
return -1;
#ifdef CONFIG_IEEE80211R_AP
if (sm->ft_completed) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "FT authentication already completed - do not "
- "start 4-way handshake");
+ "FT authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
- sm->Pair = TRUE;
+ sm->Pair = true;
return 0;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -647,14 +674,14 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
"FILS authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
- sm->Pair = TRUE;
+ sm->Pair = true;
return 0;
}
#endif /* CONFIG_FILS */
if (sm->started) {
os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
- sm->ReAuthenticationRequest = TRUE;
+ sm->ReAuthenticationRequest = true;
return wpa_sm_step(sm);
}
@@ -662,11 +689,11 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
"start authentication");
sm->started = 1;
- sm->Init = TRUE;
+ sm->Init = true;
if (wpa_sm_step(sm) == 1)
return 1; /* should not really happen */
- sm->Init = FALSE;
- sm->AuthenticationRequest = TRUE;
+ sm->Init = false;
+ sm->AuthenticationRequest = true;
return wpa_sm_step(sm);
}
@@ -676,7 +703,7 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
/* WPA/RSN was not used - clear WPA state. This is needed if the STA
* reassociates back to the same AP while the previous entry for the
* STA has not yet been removed. */
- if (sm == NULL)
+ if (!sm)
return;
sm->wpa_key_mgmt = 0;
@@ -688,8 +715,9 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr)) {
u32 start;
- wpa_printf(MSG_DEBUG, "P2P: Free assigned IP "
- "address %u.%u.%u.%u from " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "P2P: Free assigned IP address %u.%u.%u.%u from "
+ MACSTR,
sm->ip_addr[0], sm->ip_addr[1],
sm->ip_addr[2], sm->ip_addr[3],
MAC2STR(sm->addr));
@@ -700,7 +728,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
#endif /* CONFIG_P2P */
if (sm->GUpdateStationKeys) {
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
}
#ifdef CONFIG_IEEE80211R_AP
os_free(sm->assoc_resp_ftie);
@@ -719,31 +747,34 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ struct wpa_authenticator *wpa_auth;
+
+ if (!sm)
return;
- if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "strict rekeying - force GTK rekey since STA "
- "is leaving");
+ wpa_auth = sm->wpa_auth;
+ if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "strict rekeying - force GTK rekey since STA is leaving");
if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
- sm->wpa_auth, NULL) == -1)
- eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
- NULL);
+ wpa_auth, NULL) == -1)
+ eloop_register_timeout(0, 500000, wpa_rekey_gtk,
+ wpa_auth, NULL);
}
- eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+ eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
- eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+ eloop_cancel_timeout(wpa_rekey_ptk, wpa_auth, sm);
#ifdef CONFIG_IEEE80211R_AP
wpa_ft_sta_deinit(sm);
#endif /* CONFIG_IEEE80211R_AP */
if (sm->in_step_loop) {
/* Must not free state machine while wpa_sm_step() is running.
* Freeing will be completed in the end of wpa_sm_step(). */
- wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
- "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ wpa_printf(MSG_DEBUG,
+ "WPA: Registering pending STA state machine deinit for "
+ MACSTR, MAC2STR(sm->addr));
sm->pending_deinit = 1;
} else
wpa_free_sta_sm(sm);
@@ -752,11 +783,23 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
static void wpa_request_new_ptk(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return;
- sm->PTKRequest = TRUE;
- sm->PTK_valid = 0;
+ if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
+ MAC2STR(sm->addr));
+ sm->Disconnect = true;
+ /* Try to encourage the STA to reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+ } else {
+ if (sm->use_ext_key_id)
+ sm->keyidx_active ^= 1; /* flip Key ID */
+ sm->PTKRequest = true;
+ sm->PTK_valid = 0;
+ }
}
@@ -781,10 +824,10 @@ static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
int i;
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
if (ctr[i].valid &&
- (replay_counter == NULL ||
+ (!replay_counter ||
os_memcmp(replay_counter, ctr[i].counter,
WPA_REPLAY_COUNTER_LEN) == 0))
- ctr[i].valid = FALSE;
+ ctr[i].valid = false;
}
}
@@ -798,9 +841,9 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
struct rsn_mdie *mdie;
if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
- ie.num_pmkid != 1 || ie.pmkid == NULL) {
- wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
- "FT 4-way handshake message 2/4");
+ ie.num_pmkid != 1 || !ie.pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "FT: No PMKR1Name in FT 4-way handshake message 2/4");
return -1;
}
@@ -809,8 +852,9 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
sm->sup_pmk_r1_name, PMKID_LEN);
if (!kde->mdie || !kde->ftie) {
- wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
- "message 2/4", kde->mdie ? "FTIE" : "MDIE");
+ wpa_printf(MSG_DEBUG,
+ "FT: No %s in FT 4-way handshake message 2/4",
+ kde->mdie ? "FTIE" : "MDIE");
return -1;
}
@@ -844,18 +888,15 @@ static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
{
/* Supplicant reported a Michael MIC error */
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Error Request "
- "(STA detected Michael MIC failure (group=%d))",
+ "received EAPOL-Key Error Request (STA detected Michael MIC failure (group=%d))",
group);
if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "ignore Michael MIC failure report since "
- "group cipher is not TKIP");
+ "ignore Michael MIC failure report since group cipher is not TKIP");
} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "ignore Michael MIC failure report since "
- "pairwise cipher is not TKIP");
+ "ignore Michael MIC failure report since pairwise cipher is not TKIP");
} else {
if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
return 1; /* STA entry was removed */
@@ -888,7 +929,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk, &pmk_len,
&vlan_id);
- if (pmk == NULL)
+ if (!pmk)
break;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@@ -901,7 +942,8 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
pmk_len = sm->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+ if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) <
+ 0)
break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
@@ -936,7 +978,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
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;
+ sm->PTK_valid = true;
return 0;
}
@@ -956,7 +998,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
size_t keyhdrlen, mic_len;
u8 *mic;
- if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+ if (!wpa_auth || !wpa_auth->conf.wpa || !sm)
return;
wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len);
@@ -975,20 +1017,19 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
key_data = mic + mic_len + 2;
key_data_length = WPA_GET_BE16(mic + mic_len);
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
- " key_info=0x%x type=%u mic_len=%u key_data_length=%u",
+ " key_info=0x%x type=%u mic_len=%zu key_data_length=%u",
MAC2STR(sm->addr), key_info, key->type,
- (unsigned int) mic_len, key_data_length);
+ mic_len, key_data_length);
wpa_hexdump(MSG_MSGDUMP,
"WPA: EAPOL-Key header (ending before Key MIC)",
key, sizeof(*key));
wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC",
mic, mic_len);
if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
- wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
- "key_data overflow (%d > %lu)",
+ wpa_printf(MSG_INFO,
+ "WPA: Invalid EAPOL-Key frame - key_data overflow (%d > %zu)",
key_data_length,
- (unsigned long) (data_len - sizeof(*hdr) -
- keyhdrlen));
+ data_len - sizeof(*hdr) - keyhdrlen);
return;
}
@@ -998,18 +1039,18 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
* Some deployed station implementations seem to send
* msg 4/4 with incorrect type value in WPA2 mode.
*/
- wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key "
- "with unexpected WPA type in RSN mode");
+ wpa_printf(MSG_DEBUG,
+ "Workaround: Allow EAPOL-Key with unexpected WPA type in RSN mode");
} else if (key->type != EAPOL_KEY_TYPE_RSN) {
- wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
- "unexpected type %d in RSN mode",
+ wpa_printf(MSG_DEBUG,
+ "Ignore EAPOL-Key with unexpected type %d in RSN mode",
key->type);
return;
}
} else {
if (key->type != EAPOL_KEY_TYPE_WPA) {
- wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
- "unexpected type %d in WPA mode",
+ wpa_printf(MSG_DEBUG,
+ "Ignore EAPOL-Key with unexpected type %d in WPA mode",
key->type);
return;
}
@@ -1054,9 +1095,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
- "advertised support for "
- "AES-128-CMAC, but did not "
- "use it");
+ "advertised support for AES-128-CMAC, but did not use it");
return;
}
@@ -1065,8 +1104,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
- "did not use HMAC-SHA1-AES "
- "with CCMP/GCMP");
+ "did not use HMAC-SHA1-AES with CCMP/GCMP");
return;
}
}
@@ -1084,8 +1122,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
os_memcmp(key->replay_counter, sm->req_replay_counter,
WPA_REPLAY_COUNTER_LEN) <= 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
- "received EAPOL-Key request with "
- "replayed counter");
+ "received EAPOL-Key request with replayed counter");
return;
}
}
@@ -1108,12 +1145,10 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
* even if we have already sent out EAPOL-Key 3/4.
*/
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "Process SNonce update from STA "
- "based on retransmitted EAPOL-Key "
- "1/4");
+ "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4");
sm->update_snonce = 1;
os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
- sm->alt_snonce_valid = TRUE;
+ sm->alt_snonce_valid = true;
os_memcpy(sm->alt_replay_counter,
sm->key_replay[0].counter,
WPA_REPLAY_COUNTER_LEN);
@@ -1139,12 +1174,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
key->replay_counter) &&
sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "ignore retransmitted EAPOL-Key %s - "
- "SNonce did not change", msgtxt);
+ "ignore retransmitted EAPOL-Key %s - SNonce did not change",
+ msgtxt);
} else {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "received EAPOL-Key %s with "
- "unexpected replay counter", msgtxt);
+ "received EAPOL-Key %s with unexpected replay counter",
+ msgtxt);
}
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
if (!sm->key_replay[i].valid)
@@ -1175,8 +1210,7 @@ continue_processing:
(!sm->update_snonce ||
sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 2/4 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 2/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
}
@@ -1191,9 +1225,8 @@ continue_processing:
* Counter update and the station will be allowed to
* continue.
*/
- wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
- "collect more entropy for random number "
- "generation");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Reject 4-way handshake to collect more entropy for random number generation");
random_mark_pool_ready();
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -1204,8 +1237,7 @@ continue_processing:
if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
!sm->PTK_valid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 4/4 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 4/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
}
@@ -1214,8 +1246,7 @@ continue_processing:
if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
|| !sm->PTK_valid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key msg 2/2 in "
- "invalid state (%d) - dropped",
+ "received EAPOL-Key msg 2/2 in invalid state (%d) - dropped",
sm->wpa_ptk_group_state);
return;
}
@@ -1249,7 +1280,7 @@ continue_processing:
}
#endif /* CONFIG_FILS */
- sm->MICVerified = FALSE;
+ sm->MICVerified = false;
if (sm->PTK_valid && !sm->update_snonce) {
if (mic_len &&
wpa_verify_key_mic(sm->wpa_key_mgmt, sm->pmk_len, &sm->PTK,
@@ -1282,7 +1313,7 @@ continue_processing:
#ifdef TEST_FUZZ
continue_fuzz:
#endif /* TEST_FUZZ */
- sm->MICVerified = TRUE;
+ sm->MICVerified = true;
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
}
@@ -1294,8 +1325,7 @@ continue_processing:
WPA_REPLAY_COUNTER_LEN);
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key request with "
- "invalid MIC");
+ "received EAPOL-Key request with invalid MIC");
return;
}
@@ -1311,8 +1341,7 @@ continue_processing:
return; /* STA entry was removed */
} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Request for new "
- "4-Way Handshake");
+ "received EAPOL-Key Request for new 4-Way Handshake");
wpa_request_new_ptk(sm);
} else if (key_data_length > 0 &&
wpa_parse_kde_ies(key_data, key_data_length,
@@ -1320,8 +1349,7 @@ continue_processing:
kde.mac_addr) {
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "received EAPOL-Key Request for GTK "
- "rekeying");
+ "received EAPOL-Key Request for GTK rekeying");
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
wpa_rekey_gtk(wpa_auth, NULL);
}
@@ -1354,12 +1382,12 @@ continue_processing:
os_free(sm->last_rx_eapol_key);
sm->last_rx_eapol_key = os_memdup(data, data_len);
- if (sm->last_rx_eapol_key == NULL)
+ if (!sm->last_rx_eapol_key)
return;
sm->last_rx_eapol_key_len = data_len;
sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
- sm->EAPOLKeyReceived = TRUE;
+ sm->EAPOLKeyReceived = true;
sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
@@ -1422,7 +1450,7 @@ static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
sm->pending_1_of_4_timeout = 0;
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
- sm->TimeoutEvt = TRUE;
+ sm->TimeoutEvt = true;
wpa_sm_step(sm);
}
@@ -1433,6 +1461,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
const u8 *kde, size_t kde_len,
int keyidx, int encr, int force_version)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
size_t len, mic_len, keyhdrlen;
@@ -1461,15 +1490,14 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
- wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
- "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
- "encr=%d)",
+ wpa_printf(MSG_DEBUG,
+ "WPA: Send EAPOL(version=%d secure=%d mic=%d ack=%d install=%d pairwise=%d kde_len=%zu keyidx=%d encr=%d)",
version,
(key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
(key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
(key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
(key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
- pairwise, (unsigned long) kde_len, keyidx, encr);
+ pairwise, kde_len, keyidx, encr);
key_data_len = kde_len;
@@ -1487,9 +1515,9 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
len += AES_BLOCK_SIZE;
hdr = os_zalloc(len);
- if (hdr == NULL)
+ if (!hdr)
return;
- hdr->version = wpa_auth->conf.eapol_version;
+ hdr->version = conf->eapol_version;
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len - sizeof(*hdr));
key = (struct wpa_eapol_key *) (hdr + 1);
@@ -1505,7 +1533,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
WPA_PUT_BE16(key->key_info, key_info);
- alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
+ alg = pairwise ? sm->pairwise : conf->wpa_group;
if (sm->wpa == WPA_VERSION_WPA2 && !pairwise)
WPA_PUT_BE16(key->key_length, 0);
else
@@ -1522,7 +1550,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
WPA_REPLAY_COUNTER_LEN);
wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter",
key->replay_counter, WPA_REPLAY_COUNTER_LEN);
- sm->key_replay[0].valid = TRUE;
+ sm->key_replay[0].valid = true;
if (nonce)
os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
@@ -1559,7 +1587,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_FILS */
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
- if (buf == NULL) {
+ if (!buf) {
os_free(hdr);
return;
}
@@ -1576,8 +1604,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_printf(MSG_DEBUG,
- "WPA: Encrypt Key Data using AES-WRAP (KEK length %u)",
- (unsigned int) sm->PTK.kek_len);
+ "WPA: Encrypt Key Data using AES-WRAP (KEK length %zu)",
+ sm->PTK.kek_len);
if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
(key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
@@ -1611,8 +1639,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
if (key_info & WPA_KEY_INFO_MIC) {
if (!sm->PTK_valid || !mic_len) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTK not valid when sending EAPOL-Key "
- "frame");
+ "PTK not valid when sending EAPOL-Key frame");
os_free(hdr);
return;
}
@@ -1625,9 +1652,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
}
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
- drand48() <
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
+ conf->corrupt_gtk_rekey_mic_probability > 0.0 &&
+ drand48() < conf->corrupt_gtk_rekey_mic_probability) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"Corrupting group EAPOL-Key Key MIC");
key_mic[0]++;
@@ -1635,8 +1661,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_TESTING_OPTIONS */
}
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
- 1);
+ wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1);
wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
sm->pairwise_set);
os_free(hdr);
@@ -1653,7 +1678,7 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
u32 ctr;
- if (sm == NULL)
+ if (!sm)
return;
__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
@@ -1673,8 +1698,9 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
#ifdef TEST_FUZZ
timeout_ms = 1;
#endif /* TEST_FUZZ */
- wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
- "counter %u)", timeout_ms, ctr);
+ wpa_printf(MSG_DEBUG,
+ "WPA: Use EAPOL-Key timeout of %u ms (retry counter %u)",
+ timeout_ms, ctr);
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
wpa_send_eapol_timeout, wpa_auth, sm);
}
@@ -1711,13 +1737,18 @@ static int wpa_verify_key_mic(int akmp, size_t pmk_len, struct wpa_ptk *PTK,
void wpa_remove_ptk(struct wpa_state_machine *sm)
{
- sm->PTK_valid = FALSE;
+ sm->PTK_valid = false;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
- 0))
+ 0, KEY_FLAG_PAIRWISE))
wpa_printf(MSG_DEBUG,
"RSN: PTK removal from the driver failed");
- sm->pairwise_set = FALSE;
+ if (sm->use_ext_key_id &&
+ wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 1, NULL,
+ 0, KEY_FLAG_PAIRWISE))
+ wpa_printf(MSG_DEBUG,
+ "RSN: PTK Key ID 1 removal from the driver failed");
+ sm->pairwise_set = false;
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
}
@@ -1726,7 +1757,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
{
int remove_ptk = 1;
- if (sm == NULL)
+ if (!sm)
return -1;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -1746,7 +1777,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
break;
case WPA_DEAUTH:
case WPA_DISASSOC:
- sm->DeauthenticationRequest = TRUE;
+ sm->DeauthenticationRequest = true;
#ifdef CONFIG_IEEE80211R_AP
os_memset(sm->PMK, 0, sizeof(sm->PMK));
sm->pmk_len = 0;
@@ -1766,32 +1797,48 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
* sure that the WPA state machines gets initialized
* properly at this point.
*/
- wpa_printf(MSG_DEBUG, "WPA state machine had not been "
- "started - initialize now");
+ wpa_printf(MSG_DEBUG,
+ "WPA state machine had not been started - initialize now");
sm->started = 1;
- sm->Init = TRUE;
+ sm->Init = true;
if (wpa_sm_step(sm) == 1)
return 1; /* should not really happen */
- sm->Init = FALSE;
- sm->AuthenticationRequest = TRUE;
+ sm->Init = false;
+ sm->AuthenticationRequest = true;
+ break;
+ }
+
+ if (!sm->use_ext_key_id &&
+ sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect "
+ MACSTR, MAC2STR(sm->addr));
+ sm->Disconnect = true;
+ /* Try to encourage the STA to reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
break;
}
+
+ if (sm->use_ext_key_id)
+ sm->keyidx_active ^= 1; /* flip Key ID */
+
if (sm->GUpdateStationKeys) {
/*
* Reauthentication cancels the pending group key
* update for this STA.
*/
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
- sm->PtkGroupInit = TRUE;
+ sm->GUpdateStationKeys = false;
+ sm->PtkGroupInit = true;
}
- sm->ReAuthenticationRequest = TRUE;
+ sm->ReAuthenticationRequest = true;
break;
case WPA_ASSOC_FT:
#ifdef CONFIG_IEEE80211R_AP
- wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
- "after association");
- wpa_ft_install_ptk(sm);
+ wpa_printf(MSG_DEBUG,
+ "FT: Retry PTK configuration after association");
+ wpa_ft_install_ptk(sm, 1);
/* Using FT protocol, not WPA auth state machine */
sm->ft_completed = 1;
@@ -1811,7 +1858,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
break;
#endif /* CONFIG_FILS */
case WPA_DRV_STA_REMOVED:
- sm->tk_already_set = FALSE;
+ sm->tk_already_set = false;
return 0;
}
@@ -1828,7 +1875,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
#endif /* CONFIG_FILS */
if (remove_ptk) {
- sm->PTK_valid = FALSE;
+ sm->PTK_valid = false;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
if (event != WPA_REAUTH_EAPOL)
@@ -1840,7 +1887,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
* wpa_sm_step() is already running - avoid recursive call to
* it by making the existing loop process the new update.
*/
- sm->changed = TRUE;
+ sm->changed = true;
return 0;
}
return wpa_sm_step(sm);
@@ -1853,18 +1900,18 @@ SM_STATE(WPA_PTK, INITIALIZE)
if (sm->Init) {
/* Init flag is not cleared here, so avoid busy
* loop by claiming nothing changed. */
- sm->changed = FALSE;
+ sm->changed = false;
}
sm->keycount = 0;
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
if (sm->wpa == WPA_VERSION_WPA)
- sm->PInitAKeys = FALSE;
+ sm->PInitAKeys = false;
if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
* Local AA > Remote AA)) */) {
- sm->Pair = TRUE;
+ sm->Pair = true;
}
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
wpa_remove_ptk(sm);
@@ -1884,7 +1931,7 @@ SM_STATE(WPA_PTK, DISCONNECT)
u16 reason = sm->disconnect_reason;
SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
- sm->Disconnect = FALSE;
+ sm->Disconnect = false;
sm->disconnect_reason = 0;
if (!reason)
reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
@@ -1895,7 +1942,7 @@ SM_STATE(WPA_PTK, DISCONNECT)
SM_STATE(WPA_PTK, DISCONNECTED)
{
SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
- sm->DeauthenticationRequest = FALSE;
+ sm->DeauthenticationRequest = false;
}
@@ -1903,11 +1950,11 @@ SM_STATE(WPA_PTK, AUTHENTICATION)
{
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
- sm->PTK_valid = FALSE;
+ sm->PTK_valid = false;
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
1);
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
- sm->AuthenticationRequest = FALSE;
+ sm->AuthenticationRequest = false;
}
@@ -1923,23 +1970,23 @@ static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
* GMK and Counter here to improve their strength if there was not
* enough entropy available immediately after system startup.
*/
- wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
- "station");
+ wpa_printf(MSG_DEBUG,
+ "WPA: Re-initialize GMK/Counter on first station");
if (random_pool_ready() != 1) {
- wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
- "to proceed - reject first 4-way handshake");
- group->reject_4way_hs_for_entropy = TRUE;
+ wpa_printf(MSG_INFO,
+ "WPA: Not enough entropy in random pool to proceed - reject first 4-way handshake");
+ group->reject_4way_hs_for_entropy = true;
} else {
- group->first_sta_seen = TRUE;
- group->reject_4way_hs_for_entropy = FALSE;
+ group->first_sta_seen = true;
+ group->reject_4way_hs_for_entropy = false;
}
if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0 ||
wpa_gtk_update(wpa_auth, group) < 0 ||
wpa_group_config_group_keys(wpa_auth, group) < 0) {
wpa_printf(MSG_INFO, "WPA: GMK/GTK setup failed");
- group->first_sta_seen = FALSE;
- group->reject_4way_hs_for_entropy = TRUE;
+ group->first_sta_seen = false;
+ group->reject_4way_hs_for_entropy = true;
}
}
@@ -1949,7 +1996,7 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
wpa_group_ensure_init(sm->wpa_auth, sm->group);
- sm->ReAuthenticationRequest = FALSE;
+ sm->ReAuthenticationRequest = false;
/*
* Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
@@ -1961,9 +2008,9 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
* stronger protection against potential precomputation attacks.
*/
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
- wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
- "ANonce.");
- sm->Disconnect = TRUE;
+ wpa_printf(MSG_ERROR,
+ "WPA: Failed to get random data for ANonce.");
+ sm->Disconnect = true;
return;
}
wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
@@ -1981,7 +2028,7 @@ static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_ERROR,
"WPA: Failed to get random data for ANonce");
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
return -1;
}
wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
@@ -2008,7 +2055,7 @@ SM_STATE(WPA_PTK, INITPMK)
} else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP) {
wpa_printf(MSG_DEBUG,
"DPP: No PMKSA cache entry for STA - reject connection");
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
sm->disconnect_reason = WLAN_REASON_INVALID_PMKID;
return;
#endif /* CONFIG_DPP */
@@ -2019,14 +2066,14 @@ SM_STATE(WPA_PTK, INITPMK)
pmk_len = PMK_LEN_SUITE_B_192;
else
pmk_len = PMK_LEN;
- wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
- "(MSK len=%lu PMK len=%u)", (unsigned long) len,
- pmk_len);
+ wpa_printf(MSG_DEBUG,
+ "WPA: PMK from EAPOL state machine (MSK len=%zu PMK len=%u)",
+ len, pmk_len);
if (len < pmk_len) {
wpa_printf(MSG_DEBUG,
- "WPA: MSK not long enough (%u) to create PMK (%u)",
- (unsigned int) len, (unsigned int) pmk_len);
- sm->Disconnect = TRUE;
+ "WPA: MSK not long enough (%zu) to create PMK (%u)",
+ len, pmk_len);
+ sm->Disconnect = true;
return;
}
os_memcpy(sm->PMK, msk, pmk_len);
@@ -2045,21 +2092,21 @@ SM_STATE(WPA_PTK, INITPMK)
} else {
wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
sm->wpa_auth->cb->get_msk);
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
return;
}
forced_memzero(msk, sizeof(msk));
sm->req_replay_counter_used = 0;
- /* IEEE 802.11i does not set keyRun to FALSE, but not doing this
+ /* IEEE 802.11i does not set keyRun to false, but not doing this
* will break reauthentication since EAPOL state machines may not be
* get into AUTHENTICATING state that clears keyRun before WPA state
* machine enters AUTHENTICATION2 state and goes immediately to INITPMK
* state and takes PMK from the previously used AAA Key. This will
* eventually fail in 4-Way Handshake because Supplicant uses PMK
- * derived from the new AAA Key. Setting keyRun = FALSE here seems to
+ * derived from the new AAA Key. Setting keyRun = false here seems to
* be good workaround for this issue. */
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, false);
}
@@ -2100,9 +2147,9 @@ SM_STATE(WPA_PTK, PTKSTART)
size_t pmkid_len = 0;
SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
- sm->PTKRequest = FALSE;
- sm->TimeoutEvt = FALSE;
- sm->alt_snonce_valid = FALSE;
+ sm->PTKRequest = false;
+ sm->TimeoutEvt = false;
+ sm->alt_snonce_valid = false;
sm->TimeoutCtr++;
if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
@@ -2169,7 +2216,6 @@ SM_STATE(WPA_PTK, PTKSTART)
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)) {
@@ -2199,6 +2245,8 @@ SM_STATE(WPA_PTK, PTKSTART)
&pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
}
}
+ if (!pmkid)
+ pmkid_len = 0;
wpa_send_eapol(sm->wpa_auth, sm,
WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
sm->ANonce, pmkid, pmkid_len, 0, 0);
@@ -2207,10 +2255,11 @@ SM_STATE(WPA_PTK, PTKSTART)
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk)
+ struct wpa_ptk *ptk, int force_sha256)
{
const u8 *z = NULL;
size_t z_len = 0;
+ int akmp;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -2236,9 +2285,12 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
}
#endif /* CONFIG_DPP2 */
+ akmp = sm->wpa_key_mgmt;
+ if (force_sha256)
+ akmp |= WPA_KEY_MGMT_PSK_SHA256;
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
+ ptk, akmp, sm->pairwise, z, z_len);
}
@@ -2262,8 +2314,8 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
fils_ft, &fils_ft_len);
if (res < 0)
return res;
- sm->PTK_valid = TRUE;
- sm->tk_already_set = FALSE;
+ sm->PTK_valid = true;
+ sm->tk_already_set = false;
#ifdef CONFIG_IEEE80211R_AP
if (fils_ft_len) {
@@ -2271,7 +2323,6 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_auth_config *conf = &wpa_auth->conf;
u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
- size_t pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
if (wpa_derive_pmk_r0(fils_ft, fils_ft_len,
conf->ssid, conf->ssid_len,
@@ -2282,10 +2333,6 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
use_sha384) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
- pmk_r0, pmk_r0_len);
- 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);
forced_memzero(fils_ft, sizeof(fils_ft));
@@ -2452,9 +2499,9 @@ int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
wpa_printf(MSG_DEBUG,
- "FILS: Unexpected Key-Auth length %d (expected %d)",
+ "FILS: Unexpected Key-Auth length %d (expected %zu)",
elems.fils_key_confirm_len,
- (int) sm->fils_key_auth_len);
+ sm->fils_key_auth_len);
return -1;
}
@@ -2647,8 +2694,13 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
u8 *gtk, dummy_gtk[32];
size_t gtk_len;
struct wpa_group *gsm;
+ size_t plain_len;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
- plain = wpabuf_alloc(1000);
+ plain_len = 1000 + ieee80211w_kde_len(sm);
+ if (conf->transition_disable)
+ plain_len += 2 + RSN_SELECTOR_LEN + 1;
+ plain = wpabuf_alloc(plain_len);
if (!plain)
return NULL;
@@ -2677,8 +2729,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
/* GTK KDE */
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -2696,11 +2747,18 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
gtk, gtk_len);
wpabuf_put(plain, tmp2 - tmp);
- /* IGTK KDE */
+ /* IGTK KDE and BIGTK KDE */
tmp = wpabuf_put(plain, 0);
tmp2 = ieee80211w_kde_add(sm, tmp);
wpabuf_put(plain, tmp2 - tmp);
+ if (conf->transition_disable) {
+ tmp = wpabuf_put(plain, 0);
+ tmp2 = wpa_add_kde(tmp, WFA_KEY_DATA_TRANSITION_DISABLE,
+ &conf->transition_disable, 1, NULL, 0);
+ wpabuf_put(plain, tmp2 - tmp);
+ }
+
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
#ifdef CONFIG_OCV
@@ -2714,6 +2772,15 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
wpabuf_clear_free(plain);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->oci_freq_override_fils_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ conf->oci_freq_override_fils_assoc);
+ ci.frequency = conf->oci_freq_override_fils_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
@@ -2746,11 +2813,11 @@ int fils_set_tk(struct wpa_state_machine *sm)
wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen)) {
+ sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) {
wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
return -1;
}
- sm->tk_already_set = TRUE;
+ sm->tk_already_set = true;
return 0;
}
@@ -2778,8 +2845,8 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain));
pos += wpabuf_len(plain);
- wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
- (unsigned int) wpabuf_len(plain));
+ wpa_printf(MSG_DEBUG, "%s: plain buf_len: %zu", __func__,
+ wpabuf_len(plain));
wpabuf_clear_free(plain);
sm->fils_completed = 1;
return pos;
@@ -2818,10 +2885,11 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
struct wpa_eapol_key *key;
struct wpa_eapol_ie_parse kde;
int vlan_id = 0;
+ int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
- sm->EAPOLKeyReceived = FALSE;
- sm->update_snonce = FALSE;
+ sm->EAPOLKeyReceived = false;
+ sm->update_snonce = false;
os_memset(&PTK, 0, sizeof(PTK));
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
@@ -2835,7 +2903,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
sm->p2p_dev_addr, pmk, &pmk_len,
&vlan_id);
- if (pmk == NULL)
+ if (!pmk)
break;
psk_found = 1;
#ifdef CONFIG_IEEE80211R_AP
@@ -2855,7 +2923,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
pmk_len = sm->pmksa->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+ if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
+ owe_ptk_workaround == 2) < 0)
break;
if (mic_len &&
@@ -2879,6 +2948,16 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
}
#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 &&
+ owe_ptk_workaround == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Try PTK derivation workaround with SHA256");
+ owe_ptk_workaround = 2;
+ continue;
+ }
+#endif /* CONFIG_OWE */
+
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
@@ -2921,7 +3000,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
eapol_key_ie_len = kde.wpa_ie_len;
}
ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt);
- if (sm->wpa_ie == NULL ||
+ if (!sm->wpa_ie ||
wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
eapol_key_ie, eapol_key_ie_len)) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -2958,6 +3037,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (wpa_channel_info(wpa_auth, &ci) != 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -2971,10 +3051,21 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
&tx_seg1_idx) < 0)
return;
- if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- ocv_errorstr);
+ res = ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "OCV failed: %s", ocv_errorstr);
+ if (wpa_auth->conf.msg_ctx)
+ wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=eapol-key-m2 error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
return;
}
}
@@ -3006,6 +3097,24 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1 && kde.dpp_kde) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: peer Protocol Version %u Flags 0x%x",
+ kde.dpp_kde[0], kde.dpp_kde[1]);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
+ wpa_auth->conf.dpp_pfs != 2 &&
+ (kde.dpp_kde[1] & DPP_KDE_PFS_ALLOWED) &&
+ !sm->dpp_z) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer indicated it supports PFS and local configuration allows this, but PFS was not negotiated for the association");
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+ }
+#endif /* CONFIG_DPP2 */
+
#ifdef CONFIG_IEEE80211R_AP
if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
/*
@@ -3015,10 +3124,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
WPA_PMK_NAME_LEN) != 0) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PMKR1Name mismatch in FT 4-way "
- "handshake");
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
- "Supplicant",
+ "PMKR1Name mismatch in FT 4-way handshake");
+ wpa_hexdump(MSG_DEBUG,
+ "FT: PMKR1Name from Supplicant",
sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
@@ -3045,11 +3153,11 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
sm->pmk_len = PMK_LEN;
}
- sm->MICVerified = TRUE;
+ sm->MICVerified = true;
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
forced_memzero(&PTK, sizeof(PTK));
- sm->PTK_valid = TRUE;
+ sm->PTK_valid = true;
}
@@ -3062,22 +3170,29 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
static int ieee80211w_kde_len(struct wpa_state_machine *sm)
{
+ size_t len = 0;
+
if (sm->mgmt_frame_prot) {
- size_t len;
- len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
- return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
+ len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ }
+ if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
+ len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
}
- return 0;
+ return len;
}
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_igtk_kde igtk;
+ struct wpa_bigtk_kde bigtk;
struct wpa_group *gsm = sm->group;
u8 rsc[WPA_KEY_RSC_LEN];
- size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+ size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher);
if (!sm->mgmt_frame_prot)
return pos;
@@ -3090,8 +3205,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
else
os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS.
@@ -3103,6 +3217,29 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
(const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
NULL, 0);
+ if (!conf->beacon_prot)
+ return pos;
+
+ bigtk.keyid[0] = gsm->GN_bigtk;
+ bigtk.keyid[1] = 0;
+ if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
+ os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
+ else
+ os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
+ os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each OSEN STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(bigtk.bigtk, len) < 0)
+ return pos;
+ }
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
+ (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
+ NULL, 0);
+
return pos;
}
@@ -3116,7 +3253,9 @@ static int ocv_oci_len(struct wpa_state_machine *sm)
return 0;
}
-static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
+
+static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos,
+ unsigned int freq)
{
#ifdef CONFIG_OCV
struct wpa_channel_info ci;
@@ -3129,6 +3268,14 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
"Failed to get channel info for OCI element");
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (freq) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %u MHz",
+ ci.frequency, freq);
+ ci.frequency = freq;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
return ocv_insert_oci_kde(&ci, argpos);
#else /* CONFIG_OCV */
@@ -3137,61 +3284,126 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
}
+#ifdef CONFIG_TESTING_OPTIONS
+static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
+ const u8 *ie, size_t ie_len)
+{
+ const u8 *elem;
+ u8 *buf;
+
+ wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name);
+ wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override",
+ old_buf, *len);
+ buf = os_malloc(*len + ie_len);
+ if (!buf)
+ return NULL;
+ os_memcpy(buf, old_buf, *len);
+ elem = get_ie(buf, *len, eid);
+ if (elem) {
+ u8 elem_len = 2 + elem[1];
+
+ os_memmove((void *) elem, elem + elem_len,
+ *len - (elem - buf) - elem_len);
+ *len -= elem_len;
+ }
+ os_memcpy(buf + *len, ie, ie_len);
+ *len += ie_len;
+ wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override",
+ buf, *len);
+
+ return buf;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
- u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
- size_t gtk_len, kde_len;
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32];
+ size_t gtk_len, kde_len, wpa_ie_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, gtkidx, encr = 0;
+ int secure, gtkidx, encr = 0;
+ u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
+ u8 hdr[2];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
- sm->TimeoutEvt = FALSE;
+ sm->TimeoutEvt = false;
sm->TimeoutCtr++;
- if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
- sm->TimeoutCtr > 1) {
+ if (conf->wpa_disable_eapol_key_retries && sm->TimeoutCtr > 1) {
/* Do not allow retransmission of EAPOL-Key msg 3/4 */
return;
}
- if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
+ if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
}
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
wpa_ie = sm->wpa_auth->wpa_ie;
wpa_ie_len = sm->wpa_auth->wpa_ie_len;
- if (sm->wpa == WPA_VERSION_WPA &&
- (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
- wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+ if (sm->wpa == WPA_VERSION_WPA && (conf->wpa & WPA_PROTO_RSN) &&
+ wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
/* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->rsne_override_eapol_set) {
+ wpa_ie_buf2 = replace_ie(
+ "RSNE", wpa_ie, &wpa_ie_len, WLAN_EID_RSN,
+ conf->rsne_override_eapol,
+ conf->rsne_override_eapol_len);
+ if (!wpa_ie_buf2)
+ goto done;
+ wpa_ie = wpa_ie_buf2;
+ }
+ if (conf->rsnxe_override_eapol_set) {
+ wpa_ie_buf = replace_ie(
+ "RSNXE", wpa_ie, &wpa_ie_len, WLAN_EID_RSNX,
+ conf->rsnxe_override_eapol,
+ conf->rsnxe_override_eapol_len);
+ if (!wpa_ie_buf)
+ goto done;
+ wpa_ie = wpa_ie_buf;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"sending 3/4 msg of 4-Way Handshake");
if (sm->wpa == WPA_VERSION_WPA2) {
+ if (sm->use_ext_key_id && sm->TimeoutCtr == 1 &&
+ wpa_auth_set_key(sm->wpa_auth, 0,
+ wpa_cipher_to_alg(sm->pairwise),
+ sm->addr,
+ sm->keyidx_active, sm->PTK.tk,
+ wpa_cipher_key_len(sm->pairwise),
+ KEY_FLAG_PAIRWISE_RX)) {
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+
/* WPA2 send GTK in the 4-way handshake */
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (sm->wpa_auth->conf.disable_gtk ||
+ if (conf->disable_gtk ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
*/
if (random_get_bytes(dummy_gtk, gtk_len) < 0)
- return;
+ goto done;
gtk = dummy_gtk;
}
gtkidx = gsm->GN;
@@ -3213,13 +3425,16 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
* WPA if the supplicant used it first.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "STA used Secure bit in WPA msg 2/4 - "
- "set Secure for 3/4 as workaround");
+ "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+ if (sm->use_ext_key_id)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -3232,9 +3447,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
if (WPA_GET_BE32(sm->ip_addr) > 0)
kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
#endif /* CONFIG_P2P */
+
+ if (conf->transition_disable)
+ kde_len += 2 + RSN_SELECTOR_LEN + 1;
+
+#ifdef CONFIG_DPP2
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+#endif /* CONFIG_DPP2 */
+
kde = os_malloc(kde_len);
- if (kde == NULL)
- return;
+ if (!kde)
+ goto done;
pos = kde;
os_memcpy(pos, wpa_ie, wpa_ie_len);
@@ -3247,34 +3471,34 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
elen = pos - kde;
res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert "
- "PMKR1Name into RSN IE in EAPOL-Key data");
- os_free(kde);
- return;
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
+ goto done;
}
pos -= wpa_ie_len;
pos += elen;
}
#endif /* CONFIG_IEEE80211R_AP */
+ hdr[1] = 0;
+
+ if (sm->use_ext_key_id) {
+ hdr[0] = sm->keyidx_active & 0x01;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+ }
+
if (gtk) {
- u8 hdr[2];
hdr[0] = gtkidx & 0x03;
- hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
pos = ieee80211w_kde_add(sm, pos);
- if (ocv_oci_add(sm, &pos) < 0) {
- os_free(kde);
- return;
- }
+ if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0)
+ goto done;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
- struct wpa_auth_config *conf;
- conf = &sm->wpa_auth->conf;
if (sm->assoc_resp_ftie &&
kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
os_memcpy(pos, sm->assoc_resp_ftie,
@@ -3288,13 +3512,12 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
- NULL, 0);
+ NULL, 0, 0);
}
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
- "into EAPOL-Key Key Data");
- os_free(kde);
- return;
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert FTIE into EAPOL-Key Key Data");
+ goto done;
}
pos += res;
@@ -3317,13 +3540,33 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
if (WPA_GET_BE32(sm->ip_addr) > 0) {
u8 addr[3 * 4];
os_memcpy(addr, sm->ip_addr, 4);
- os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
- os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
+ os_memcpy(addr + 4, conf->ip_addr_mask, 4);
+ os_memcpy(addr + 8, conf->ip_addr_go, 4);
pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
addr, sizeof(addr), NULL, 0);
}
#endif /* CONFIG_P2P */
+ if (conf->transition_disable)
+ pos = wpa_add_kde(pos, WFA_KEY_DATA_TRANSITION_DISABLE,
+ &conf->transition_disable, 1, NULL, 0);
+
+#ifdef CONFIG_DPP2
+ if (DPP_VERSION > 1 && sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP) {
+ u8 payload[2];
+
+ payload[0] = DPP_VERSION; /* Protocol Version */
+ payload[1] = 0; /* Flags */
+ if (conf->dpp_pfs == 0)
+ payload[1] |= DPP_KDE_PFS_ALLOWED;
+ else if (conf->dpp_pfs == 1)
+ payload[1] |= DPP_KDE_PFS_ALLOWED |
+ DPP_KDE_PFS_REQUIRED;
+ pos = wpa_add_kde(pos, WFA_KEY_DATA_DPP,
+ payload, sizeof(payload), NULL, 0);
+ }
+#endif /* CONFIG_DPP2 */
+
wpa_send_eapol(sm->wpa_auth, sm,
(secure ? WPA_KEY_INFO_SECURE : 0) |
(wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
@@ -3331,25 +3574,37 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
_rsc, sm->ANonce, kde, pos - kde, 0, encr);
+done:
os_free(kde);
+ os_free(wpa_ie_buf);
+ os_free(wpa_ie_buf2);
}
SM_STATE(WPA_PTK, PTKINITDONE)
{
SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
- sm->EAPOLKeyReceived = FALSE;
+ sm->EAPOLKeyReceived = false;
if (sm->Pair) {
enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
int klen = wpa_cipher_key_len(sm->pairwise);
- if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen)) {
+ int res;
+
+ if (sm->use_ext_key_id)
+ res = wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr,
+ sm->keyidx_active, NULL, 0,
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY);
+ else
+ res = wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr,
+ 0, sm->PTK.tk, klen,
+ KEY_FLAG_PAIRWISE_RX_TX);
+ if (res) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
- sm->pairwise_set = TRUE;
+ sm->pairwise_set = true;
wpa_auth_set_ptk_rekey_timer(sm);
@@ -3371,12 +3626,13 @@ SM_STATE(WPA_PTK, PTKINITDONE)
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
1);
}
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0);
- wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable,
+ false);
+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, true);
if (sm->wpa == WPA_VERSION_WPA)
- sm->PInitAKeys = TRUE;
+ sm->PInitAKeys = true;
else
- sm->has_GTK = TRUE;
+ sm->has_GTK = true;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
"pairwise key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
@@ -3390,6 +3646,7 @@ SM_STATE(WPA_PTK, PTKINITDONE)
SM_STEP(WPA_PTK)
{
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ struct wpa_auth_config *conf = &wpa_auth->conf;
if (sm->Init)
SM_ENTER(WPA_PTK, INITIALIZE);
@@ -3424,8 +3681,8 @@ SM_STEP(WPA_PTK)
break;
case WPA_PTK_AUTHENTICATION2:
if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
- wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
- WPA_EAPOL_keyRun) > 0)
+ wpa_auth_get_eapol(wpa_auth, sm->addr,
+ WPA_EAPOL_keyRun))
SM_ENTER(WPA_PTK, INITPMK);
else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE
@@ -3435,8 +3692,8 @@ SM_STEP(WPA_PTK)
SM_ENTER(WPA_PTK, INITPMK);
break;
case WPA_PTK_INITPMK:
- if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
- WPA_EAPOL_keyAvailable) > 0) {
+ if (wpa_auth_get_eapol(wpa_auth, sm->addr,
+ WPA_EAPOL_keyAvailable)) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_DPP
} else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->pmksa) {
@@ -3444,13 +3701,13 @@ SM_STEP(WPA_PTK)
#endif /* CONFIG_DPP */
} else {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"INITPMK - keyAvailable = false");
SM_ENTER(WPA_PTK, DISCONNECT);
}
break;
case WPA_PTK_INITPSK:
- if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
+ if (wpa_auth_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr,
NULL, NULL, NULL)) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_SAE
@@ -3458,7 +3715,7 @@ SM_STEP(WPA_PTK)
SM_ENTER(WPA_PTK, PTKSTART);
#endif /* CONFIG_SAE */
} else {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"no PSK configured for the STA");
wpa_auth->dot11RSNA4WayHandshakeFailures++;
SM_ENTER(WPA_PTK, DISCONNECT);
@@ -3468,13 +3725,13 @@ SM_STEP(WPA_PTK)
if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
sm->EAPOLKeyPairwise)
SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
- else if (sm->TimeoutCtr >
- sm->wpa_auth->conf.wpa_pairwise_update_count) {
+ else if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(
- sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKSTART: Retry limit %u reached",
- sm->wpa_auth->conf.wpa_pairwise_update_count);
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKSTART: Retry limit %u reached",
+ conf->wpa_pairwise_update_count);
+ sm->disconnect_reason =
+ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT;
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKSTART);
@@ -3498,14 +3755,15 @@ SM_STEP(WPA_PTK)
sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK, PTKINITDONE);
else if (sm->TimeoutCtr >
- sm->wpa_auth->conf.wpa_pairwise_update_count ||
- (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+ conf->wpa_pairwise_update_count ||
+ (conf->wpa_disable_eapol_key_retries &&
sm->TimeoutCtr > 1)) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(
- sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKINITNEGOTIATING: Retry limit %u reached",
- sm->wpa_auth->conf.wpa_pairwise_update_count);
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKINITNEGOTIATING: Retry limit %u reached",
+ conf->wpa_pairwise_update_count);
+ sm->disconnect_reason =
+ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT;
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -3522,7 +3780,7 @@ SM_STATE(WPA_PTK_GROUP, IDLE)
if (sm->Init) {
/* Init flag is not cleared here, so avoid busy
* loop by claiming nothing changed. */
- sm->changed = FALSE;
+ sm->changed = false;
}
sm->GTimeoutCtr = 0;
}
@@ -3536,24 +3794,24 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
u8 *kde_buf = NULL, *pos, hdr[2];
size_t kde_len;
u8 *gtk, dummy_gtk[32];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
sm->GTimeoutCtr++;
- if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
- sm->GTimeoutCtr > 1) {
+ if (conf->wpa_disable_eapol_key_retries && sm->GTimeoutCtr > 1) {
/* Do not allow retransmission of EAPOL-Key group msg 1/2 */
return;
}
- if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
+ if (sm->GTimeoutCtr > conf->wpa_group_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
}
if (sm->wpa == WPA_VERSION_WPA)
- sm->PInitAKeys = FALSE;
- sm->TimeoutEvt = FALSE;
+ sm->PInitAKeys = false;
+ sm->TimeoutEvt = false;
/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
@@ -3562,8 +3820,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
"sending 1/2 msg of Group Key Handshake");
gtk = gsm->GTK[gsm->GN - 1];
- if (sm->wpa_auth->conf.disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -3576,7 +3833,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
- if (kde_buf == NULL)
+ if (!kde_buf)
return;
kde = pos = kde_buf;
@@ -3585,7 +3842,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos,
+ conf->oci_freq_override_eapol_g1) < 0) {
os_free(kde_buf);
return;
}
@@ -3609,8 +3867,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
{
-#ifdef CONFIG_OCV
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+#ifdef CONFIG_OCV
const u8 *key_data, *mic;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
@@ -3620,7 +3878,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
#endif /* CONFIG_OCV */
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
- sm->EAPOLKeyReceived = FALSE;
+ sm->EAPOLKeyReceived = false;
#ifdef CONFIG_OCV
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
@@ -3651,7 +3909,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
if (wpa_channel_info(wpa_auth, &ci) != 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
+ "Failed to get channel info to validate received OCI in EAPOL-Key group 2/2");
return;
}
@@ -3662,9 +3920,15 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
return;
if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- ocv_errorstr);
+ tx_chanwidth, tx_seg1_idx) !=
+ OCI_SUCCESS) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "OCV failed: %s", ocv_errorstr);
+ if (wpa_auth->conf.msg_ctx)
+ wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=eapol-key-g2 error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
return;
}
}
@@ -3672,13 +3936,13 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
sm->GTimeoutCtr = 0;
/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"group key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
- sm->has_GTK = TRUE;
+ sm->has_GTK = true;
}
@@ -3687,8 +3951,9 @@ SM_STATE(WPA_PTK_GROUP, KEYERROR)
SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = FALSE;
- sm->Disconnect = TRUE;
+ sm->GUpdateStationKeys = false;
+ sm->Disconnect = true;
+ sm->disconnect_reason = WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT;
wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
"group key handshake failed (%s) after %u tries",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
@@ -3700,7 +3965,7 @@ SM_STEP(WPA_PTK_GROUP)
{
if (sm->Init || sm->PtkGroupInit) {
SM_ENTER(WPA_PTK_GROUP, IDLE);
- sm->PtkGroupInit = FALSE;
+ sm->PtkGroupInit = false;
} else switch (sm->wpa_ptk_group_state) {
case WPA_PTK_GROUP_IDLE:
if (sm->GUpdateStationKeys ||
@@ -3732,7 +3997,9 @@ SM_STEP(WPA_PTK_GROUP)
static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
int ret = 0;
+ size_t len;
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
@@ -3743,9 +4010,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
wpa_hexdump_key(MSG_DEBUG, "GTK",
group->GTK[group->GN - 1], group->GTK_len);
- if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- size_t len;
- len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
@@ -3756,6 +4022,19 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
group->IGTK[group->GN_igtk - 4], len);
}
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+ conf->beacon_prot) {
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
+ os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+ inc_byte_array(group->Counter, WPA_NONCE_LEN);
+ if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
+ wpa_auth->addr, group->GNonce,
+ group->BIGTK[group->GN_bigtk - 6], len) < 0)
+ ret = -1;
+ wpa_hexdump_key(MSG_DEBUG, "BIGTK",
+ group->BIGTK[group->GN_bigtk - 6], len);
+ }
+
return ret;
}
@@ -3763,9 +4042,10 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "GTK_INIT (VLAN-ID %d)", group->vlan_id);
- group->changed = FALSE; /* GInit is not cleared here; avoid loop */
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state GTK_INIT (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = false; /* GInit is not cleared here; avoid loop */
group->wpa_group_state = WPA_GROUP_GTK_INIT;
/* GTK[0..N] = 0 */
@@ -3774,6 +4054,8 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
group->GM = 2;
group->GN_igtk = 4;
group->GM_igtk = 5;
+ group->GN_bigtk = 6;
+ group->GM_bigtk = 7;
/* GTK[GN] = CalcGTK() */
wpa_gtk_update(wpa_auth, group);
}
@@ -3787,7 +4069,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
- sm->GUpdateStationKeys = FALSE;
+ sm->GUpdateStationKeys = false;
return 0;
}
if (sm->GUpdateStationKeys) {
@@ -3797,8 +4079,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
* station needs to be counted here anyway.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "GUpdateStationKeys was already set when "
- "marking station for GTK rekeying");
+ "GUpdateStationKeys was already set when marking station for GTK rekeying");
}
/* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
@@ -3806,7 +4087,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
return 0;
sm->group->GKeyDoneStations++;
- sm->GUpdateStationKeys = TRUE;
+ sm->GUpdateStationKeys = true;
wpa_sm_step(sm);
return 0;
@@ -3817,7 +4098,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
/* update GTK when exiting WNM-Sleep Mode */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
{
- if (sm == NULL || sm->is_wnmsleep)
+ if (!sm || sm->is_wnmsleep)
return;
wpa_group_update_sta(sm, NULL);
@@ -3833,6 +4114,7 @@ void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *start = pos;
@@ -3851,6 +4133,14 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
return 0;
pos += 8;
os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(pos, gsm->GTK_len) < 0)
+ return 0;
+ }
pos += gsm->GTK_len;
wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
@@ -3864,6 +4154,7 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *start = pos;
size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
@@ -3881,6 +4172,14 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
pos += 6;
os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use
+ * of IGTK in the BSS.
+ */
+ if (random_get_bytes(pos, len) < 0)
+ return 0;
+ }
pos += len;
wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
@@ -3891,6 +4190,44 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
return pos - start;
}
+
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ struct wpa_group *gsm = sm->group;
+ u8 *start = pos;
+ size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+ /*
+ * BIGTK subelement:
+ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+ */
+ *pos++ = WNM_SLEEP_SUBELEM_BIGTK;
+ *pos++ = 2 + 6 + len;
+ WPA_PUT_LE16(pos, gsm->GN_bigtk);
+ pos += 2;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
+ return 0;
+ pos += 6;
+
+ os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(pos, len) < 0)
+ return 0;
+ }
+ pos += len;
+
+ wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN_bigtk);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit",
+ gsm->IGTK[gsm->GN_bigtk - 6], len);
+
+ return pos - start;
+}
+
#endif /* CONFIG_WNM_AP */
@@ -3899,25 +4236,29 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
{
int tmp;
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "SETKEYS (VLAN-ID %d)", group->vlan_id);
- group->changed = TRUE;
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = true;
group->wpa_group_state = WPA_GROUP_SETKEYS;
- group->GTKReKey = FALSE;
+ group->GTKReKey = false;
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
/* "GKeyDoneStations = GNoStations" is done in more robust way by
* counting the STAs that are marked with GUpdateStationKeys instead of
* including all STAs that could be in not-yet-completed state. */
wpa_gtk_update(wpa_auth, group);
if (group->GKeyDoneStations) {
- wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected "
- "GKeyDoneStations=%d when starting new GTK rekey",
+ wpa_printf(MSG_DEBUG,
+ "wpa_group_setkeys: Unexpected GKeyDoneStations=%d when starting new GTK rekey",
group->GKeyDoneStations);
group->GKeyDoneStations = 0;
}
@@ -3930,25 +4271,35 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
int ret = 0;
if (wpa_auth_set_key(wpa_auth, group->vlan_id,
- wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
+ wpa_cipher_to_alg(conf->wpa_group),
broadcast_ether_addr, group->GN,
- group->GTK[group->GN - 1], group->GTK_len) < 0)
+ group->GTK[group->GN - 1], group->GTK_len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
- if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
enum wpa_alg alg;
size_t len;
- alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
- len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ alg = wpa_cipher_to_alg(conf->group_mgmt_cipher);
+ len = wpa_cipher_key_len(conf->group_mgmt_cipher);
if (ret == 0 &&
wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
broadcast_ether_addr, group->GN_igtk,
- group->IGTK[group->GN_igtk - 4], len) < 0)
+ group->IGTK[group->GN_igtk - 4], len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
+ ret = -1;
+
+ if (ret == 0 && conf->beacon_prot &&
+ wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+ broadcast_ether_addr, group->GN_bigtk,
+ group->BIGTK[group->GN_bigtk - 6], len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
}
@@ -3960,9 +4311,9 @@ static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
{
if (sm->group == ctx) {
wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
- " for discconnection due to fatal failure",
+ " for disconnection due to fatal failure",
MAC2STR(sm->addr));
- sm->Disconnect = TRUE;
+ sm->Disconnect = true;
}
return 0;
@@ -3972,8 +4323,9 @@ static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE");
- group->changed = TRUE;
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state FATAL_FAILURE");
+ group->changed = true;
group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
}
@@ -3982,9 +4334,10 @@ static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
- "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
- group->changed = TRUE;
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYSDONE (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = true;
group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
if (wpa_group_config_group_keys(wpa_auth, group) < 0) {
@@ -4020,7 +4373,7 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
static int wpa_sm_step(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
if (sm->in_step_loop) {
@@ -4036,8 +4389,8 @@ static int wpa_sm_step(struct wpa_state_machine *sm)
if (sm->pending_deinit)
break;
- sm->changed = FALSE;
- sm->wpa_auth->group->changed = FALSE;
+ sm->changed = false;
+ sm->wpa_auth->group->changed = false;
SM_STEP_RUN(WPA_PTK);
if (sm->pending_deinit)
@@ -4050,8 +4403,9 @@ static int wpa_sm_step(struct wpa_state_machine *sm)
sm->in_step_loop = 0;
if (sm->pending_deinit) {
- wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
- "machine deinit for " MACSTR, MAC2STR(sm->addr));
+ wpa_printf(MSG_DEBUG,
+ "WPA: Completing pending STA state machine deinit for "
+ MACSTR, MAC2STR(sm->addr));
wpa_free_sta_sm(sm);
return 1;
}
@@ -4068,7 +4422,7 @@ static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
void wpa_auth_sm_notify(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return;
eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
}
@@ -4079,7 +4433,7 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
int tmp, i;
struct wpa_group *group;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return;
group = wpa_auth->group;
@@ -4091,6 +4445,9 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
}
@@ -4109,6 +4466,7 @@ static const char * wpa_bool_txt(int val)
int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
{
+ struct wpa_auth_config *conf;
int len = 0, ret;
char pmkid_txt[PMKID_LEN * 2 + 1];
#ifdef CONFIG_RSN_PREAUTH
@@ -4117,8 +4475,9 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
const int preauth = 0;
#endif /* CONFIG_RSN_PREAUTH */
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return len;
+ conf = &wpa_auth->conf;
ret = os_snprintf(buf + len, buflen - len,
"dot11RSNAOptionImplemented=TRUE\n"
@@ -4126,8 +4485,8 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
"dot11RSNAEnabled=%s\n"
"dot11RSNAPreauthenticationEnabled=%s\n",
wpa_bool_txt(preauth),
- wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
- wpa_bool_txt(wpa_auth->conf.rsn_preauth));
+ wpa_bool_txt(conf->wpa & WPA_PROTO_RSN),
+ wpa_bool_txt(conf->rsn_preauth));
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -4162,10 +4521,10 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
"dot11RSNA4WayHandshakeFailures=%u\n"
"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
RSN_VERSION,
- !!wpa_auth->conf.wpa_strict_rekey,
- wpa_auth->conf.wpa_group_update_count,
- wpa_auth->conf.wpa_pairwise_update_count,
- wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
+ !!conf->wpa_strict_rekey,
+ conf->wpa_group_update_count,
+ conf->wpa_pairwise_update_count,
+ wpa_cipher_key_len(conf->wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
dot11RSNAConfigSATimeout,
@@ -4201,7 +4560,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
int len = 0, ret;
u32 pairwise = 0;
- if (sm == NULL)
+ if (!sm)
return 0;
/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
@@ -4282,7 +4641,7 @@ const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return -1;
return sm->wpa_key_mgmt;
}
@@ -4290,7 +4649,7 @@ int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return sm->wpa;
}
@@ -4315,7 +4674,7 @@ int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm)
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
struct rsn_pmksa_cache_entry *entry)
{
- if (sm == NULL || sm->pmksa != entry)
+ if (!sm || sm->pmksa != entry)
return -1;
sm->pmksa = NULL;
return 0;
@@ -4338,7 +4697,7 @@ void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
{
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return NULL;
*len = wpa_auth->wpa_ie_len;
return wpa_auth->wpa_ie;
@@ -4349,7 +4708,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
unsigned int pmk_len,
int session_timeout, struct eapol_state_machine *eapol)
{
- if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
+ if (!sm || sm->wpa != WPA_VERSION_WPA2 ||
sm->wpa_auth->conf.disable_pmksa_caching)
return -1;
@@ -4385,7 +4744,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
int session_timeout,
struct eapol_state_machine *eapol)
{
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
@@ -4446,7 +4805,7 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
{
struct rsn_pmksa_cache_entry *pmksa;
- if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+ if (!wpa_auth || !wpa_auth->pmksa)
return;
pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
if (pmksa) {
@@ -4612,13 +4971,13 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
struct wpa_group *group;
- if (wpa_auth == NULL || wpa_auth->group == NULL)
+ if (!wpa_auth || !wpa_auth->group)
return NULL;
wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
vlan_id);
group = wpa_group_init(wpa_auth, vlan_id, 0);
- if (group == NULL)
+ if (!group)
return NULL;
group->next = wpa_auth->group->next;
@@ -4638,7 +4997,7 @@ int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
struct wpa_group *group;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return 0;
group = wpa_auth->group;
@@ -4648,9 +5007,9 @@ int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
group = group->next;
}
- if (group == NULL) {
+ if (!group) {
group = wpa_auth_add_group(wpa_auth, vlan_id);
- if (group == NULL)
+ if (!group)
return -1;
}
@@ -4679,7 +5038,7 @@ int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
struct wpa_group *group;
int ret = 0;
- if (wpa_auth == NULL)
+ if (!wpa_auth)
return 0;
group = wpa_auth->group;
@@ -4689,7 +5048,7 @@ int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
group = group->next;
}
- if (group == NULL)
+ if (!group)
return -1;
wpa_printf(MSG_DEBUG,
@@ -4724,7 +5083,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
{
struct wpa_group *group;
- if (sm == NULL || sm->wpa_auth == NULL)
+ if (!sm || !sm->wpa_auth)
return 0;
group = sm->wpa_auth->group;
@@ -4734,9 +5093,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
group = group->next;
}
- if (group == NULL) {
+ if (!group) {
group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
- if (group == NULL)
+ if (!group)
return -1;
}
@@ -4746,8 +5105,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
return -1;
- wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
- "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+ wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR
+ " to use group state machine for VLAN ID %d",
+ MAC2STR(sm->addr), vlan_id);
wpa_group_get(sm->wpa_auth, group);
wpa_group_put(sm->wpa_auth, sm->group);
@@ -4760,7 +5120,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack)
{
- if (wpa_auth == NULL || sm == NULL)
+ if (!wpa_auth || !sm)
return;
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
" ack=%d", MAC2STR(sm->addr), ack);
@@ -4776,8 +5136,8 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
* the station has received the frame.
*/
int timeout_ms = eapol_key_timeout_subseq;
- wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
- "timeout by %u ms because of acknowledged frame",
+ wpa_printf(MSG_DEBUG,
+ "WPA: Increase initial EAPOL-Key 1/4 timeout by %u ms because of acknowledged frame",
timeout_ms);
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
eloop_register_timeout(timeout_ms / 1000,
@@ -4797,7 +5157,7 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
int wpa_auth_uses_sae(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
}
@@ -4805,7 +5165,7 @@ int wpa_auth_uses_sae(struct wpa_state_machine *sm)
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
{
- if (sm == NULL)
+ if (!sm)
return 0;
return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
}
@@ -4814,7 +5174,7 @@ int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
#ifdef CONFIG_P2P
int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
{
- if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
+ if (!sm || WPA_GET_BE32(sm->ip_addr) == 0)
return -1;
os_memcpy(addr, sm->ip_addr, 4);
return 0;
@@ -4890,7 +5250,7 @@ int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder,
conf->r0_key_holder_len,
- NULL, NULL, buf, len, NULL, 0);
+ NULL, NULL, buf, len, NULL, 0, 0);
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -4936,6 +5296,14 @@ void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
#endif /* CONFIG_DPP2 */
+void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
+ u8 val)
+{
+ if (wpa_auth)
+ wpa_auth->conf.transition_disable = val;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
@@ -4967,12 +5335,14 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
u8 *opos;
size_t gtk_len, kde_len;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
int wpa_ie_len, secure, gtkidx, encr = 0;
+ u8 hdr[2];
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
/* Use 0 RSC */
@@ -5015,13 +5385,16 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
* WPA if the supplicant used it first.
*/
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "STA used Secure bit in WPA msg 2/4 - "
- "set Secure for 3/4 as workaround");
+ "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+ if (sm->use_ext_key_id)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -5031,7 +5404,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
}
#endif /* CONFIG_IEEE80211R_AP */
kde = os_malloc(kde_len);
- if (kde == NULL)
+ if (!kde)
return -1;
pos = kde;
@@ -5045,8 +5418,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
elen = pos - kde;
res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert "
- "PMKR1Name into RSN IE in EAPOL-Key data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data");
os_free(kde);
return -1;
}
@@ -5054,10 +5427,15 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
pos += elen;
}
#endif /* CONFIG_IEEE80211R_AP */
+ hdr[1] = 0;
+
+ if (sm->use_ext_key_id) {
+ hdr[0] = sm->keyidx_active & 0x01;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+ }
+
if (gtk) {
- u8 hdr[2];
hdr[0] = gtkidx & 0x03;
- hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
@@ -5068,7 +5446,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0) {
os_free(kde);
return -1;
}
@@ -5076,9 +5454,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
- struct wpa_auth_config *conf;
- conf = &sm->wpa_auth->conf;
if (sm->assoc_resp_ftie &&
kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
os_memcpy(pos, sm->assoc_resp_ftie,
@@ -5092,11 +5468,11 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
conf->r0_key_holder_len,
NULL, NULL, pos,
kde + kde_len - pos,
- NULL, 0);
+ NULL, 0, 0);
}
if (res < 0) {
- wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
- "into EAPOL-Key Key Data");
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to insert FTIE into EAPOL-Key Key Data");
os_free(kde);
return -1;
}
@@ -5135,6 +5511,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
void *ctx1, void *ctx2)
{
u8 rsc[WPA_KEY_RSC_LEN];
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
@@ -5153,7 +5530,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
- if (kde_buf == NULL)
+ if (!kde_buf)
return -1;
kde = pos = kde_buf;
@@ -5169,7 +5546,8 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
opos += 2 + RSN_SELECTOR_LEN + 2;
os_memset(opos, 0, 6); /* clear PN */
}
- if (ocv_oci_add(sm, &pos) < 0) {
+ if (ocv_oci_add(sm, &pos,
+ conf->oci_freq_override_eapol_g1) < 0) {
os_free(kde_buf);
return -1;
}
@@ -5204,4 +5582,34 @@ int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth)
return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
}
+
+void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val)
+{
+ if (wpa_auth)
+ wpa_auth->conf.ft_rsnxe_used = val;
+}
+
+
+void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
+ enum wpa_auth_ocv_override_frame frame,
+ unsigned int freq)
+{
+ if (!wpa_auth)
+ return;
+ switch (frame) {
+ case WPA_AUTH_OCV_OVERRIDE_EAPOL_M3:
+ wpa_auth->conf.oci_freq_override_eapol_m3 = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_EAPOL_G1:
+ wpa_auth->conf.oci_freq_override_eapol_g1 = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_FT_ASSOC:
+ wpa_auth->conf.oci_freq_override_ft_assoc = freq;
+ break;
+ case WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC:
+ wpa_auth->conf.oci_freq_override_fils_assoc = freq;
+ break;
+ }
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index f627838..5f9df9c 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -168,7 +168,9 @@ struct ft_remote_r1kh {
struct wpa_auth_config {
+ void *msg_ctx;
int wpa;
+ int extended_key_id;
int wpa_key_mgmt;
int wpa_pairwise;
int wpa_group;
@@ -176,6 +178,7 @@ struct wpa_auth_config {
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ int wpa_deny_ptk0_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
@@ -188,6 +191,7 @@ struct wpa_auth_config {
int okc;
int tx_status;
enum mfp_options ieee80211w;
+ int beacon_prot;
int group_mgmt_cipher;
int sae_require_mfp;
#ifdef CONFIG_OCV
@@ -219,7 +223,28 @@ struct wpa_auth_config {
double corrupt_gtk_rekey_mic_probability;
u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
size_t own_ie_override_len;
+ u8 rsne_override_eapol[MAX_OWN_IE_OVERRIDE];
+ size_t rsne_override_eapol_len;
+ u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
+ size_t rsnxe_override_eapol_len;
+ u8 rsne_override_ft[MAX_OWN_IE_OVERRIDE];
+ size_t rsne_override_ft_len;
+ u8 rsnxe_override_ft[MAX_OWN_IE_OVERRIDE];
+ size_t rsnxe_override_ft_len;
+ u8 gtk_rsc_override[WPA_KEY_RSC_LEN];
+ u8 igtk_rsc_override[WPA_KEY_RSC_LEN];
+ unsigned int rsne_override_eapol_set:1;
+ unsigned int rsnxe_override_eapol_set:1;
+ unsigned int rsne_override_ft_set:1;
+ unsigned int rsnxe_override_ft_set:1;
+ unsigned int gtk_rsc_override_set:1;
+ unsigned int igtk_rsc_override_set:1;
+ int ft_rsnxe_used;
#endif /* CONFIG_TESTING_OPTIONS */
+ unsigned int oci_freq_override_eapol_m3;
+ unsigned int oci_freq_override_eapol_g1;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
u8 ip_addr_mask[4];
@@ -231,6 +256,12 @@ struct wpa_auth_config {
u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */
int sae_pwe;
+ bool sae_pk;
+ int owe_ptk_workaround;
+ u8 transition_disable;
+#ifdef CONFIG_DPP2
+ int dpp_pfs;
+#endif /* CONFIG_DPP2 */
};
typedef enum {
@@ -257,7 +288,8 @@ struct wpa_auth_callbacks {
int *vlan_id);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
- const u8 *addr, int idx, u8 *key, size_t key_len);
+ const u8 *addr, int idx, u8 *key, size_t key_len,
+ enum key_flag key_flag);
int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
size_t data_len, int encrypt);
@@ -276,6 +308,7 @@ struct wpa_auth_callbacks {
int *bandwidth, int *seg1_idx);
#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+ int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
int (*set_vlan)(void *ctx, const u8 *sta_addr,
struct vlan_description *vlan);
int (*get_vlan)(void *ctx, const u8 *sta_addr,
@@ -309,19 +342,21 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf);
-enum {
+enum wpa_validate_result {
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
- WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID
+ WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID,
+ WPA_DENIED_OTHER_REASON
};
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, int freq,
- const u8 *wpa_ie, size_t wpa_ie_len,
- const u8 *rsnxe, size_t rsnxe_len,
- const u8 *mdie, size_t mdie_len,
- const u8 *owe_dh, size_t owe_dh_len);
+enum wpa_validate_result
+wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int freq,
+ const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ const u8 *mdie, size_t mdie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
@@ -405,14 +440,15 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
#ifdef CONFIG_IEEE80211R_AP
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
- const u8 *req_ies, size_t req_ies_len);
+ const u8 *req_ies, size_t req_ies_len,
+ int omit_rsnxe);
void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
u16 auth_transaction, const u8 *ies, size_t ies_len,
void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len),
void *ctx);
-u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len);
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
@@ -429,6 +465,7 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_auth_uses_sae(struct wpa_state_machine *sm);
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
@@ -480,6 +517,8 @@ u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
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);
+void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
+ u8 val);
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
void (*cb)(void *ctx1, void *ctx2),
@@ -492,5 +531,16 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
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);
+void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val);
+
+enum wpa_auth_ocv_override_frame {
+ WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
+ WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
+ WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
+ WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC,
+};
+void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
+ enum wpa_auth_ocv_override_frame frame,
+ unsigned int freq);
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index a599be2..5aa363e 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -14,6 +14,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
+#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
@@ -808,7 +809,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
- size_t subelem_len)
+ size_t subelem_len, int rsnxe_used)
{
u8 *pos = buf, *ielen;
size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
@@ -826,7 +827,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
+ WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce)
@@ -836,7 +837,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr);
- WPA_PUT_LE16(hdr->mic_control, 0);
+ WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce)
@@ -951,8 +952,9 @@ wpa_ft_rrb_seq_req(struct wpa_authenticator *wpa_auth,
goto err;
}
- wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR,
- MAC2STR(src_addr));
+ wpa_printf(MSG_DEBUG, "FT: Send sequence number request from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
item = os_zalloc(sizeof(*item));
if (!item)
goto err;
@@ -1896,7 +1898,7 @@ static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth,
return;
}
- wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID",
+ wpa_hexdump(MSG_DEBUG, "FT: Temporarily block R0KH-ID",
f_r0kh_id, f_r0kh_id_len);
if (r0kh) {
@@ -1984,7 +1986,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
return -1;
}
if (is_zero_ether_addr(r0kh->addr)) {
- wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is blacklisted",
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is temporarily blocked",
sm->r0kh_id, sm->r0kh_id_len);
return -1;
}
@@ -1997,9 +1999,6 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
key = r0kh->key;
key_len = sizeof(r0kh->key);
- wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
- "address " MACSTR, MAC2STR(r0kh->addr));
-
if (r0kh->seq->rx.num_last == 0) {
/* A sequence request will be sent out anyway when pull
* response is received. Send it out now to avoid one RTT. */
@@ -2008,6 +2007,10 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
key_len, NULL, 0, NULL, 0, NULL);
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request from " MACSTR
+ " to remote R0KH address " MACSTR,
+ MAC2STR(sm->wpa_auth->addr), MAC2STR(r0kh->addr));
+
if (first &&
random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
@@ -2126,8 +2129,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
pmk_r0, pmk_r0_name,
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
pmk_r0_name,
@@ -2138,9 +2139,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
pmk_r1, sm->pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
sm->pmk_r1_name, sm->pairwise, &vlan,
@@ -2165,11 +2163,12 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
size_t subelem_len, pad_len;
const u8 *key;
size_t key_len;
- u8 keybuf[32];
+ u8 keybuf[WPA_GTK_MAX_LEN];
const u8 *kek;
size_t kek_len;
@@ -2196,12 +2195,30 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
pad_len += 8;
if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+ if (conf->disable_gtk ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(keybuf, key_len) < 0)
+ return NULL;
+ }
os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd;
key_len += pad_len;
key = keybuf;
- } else
+ } else if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random GTK to each STA to prevent use of GTK
+ * in the BSS.
+ */
+ if (random_get_bytes(keybuf, key_len) < 0)
+ return NULL;
+ key = keybuf;
+ } else {
key = gsm->GTK[gsm->GN - 1];
+ }
/*
* Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
@@ -2235,11 +2252,13 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
{
u8 *subelem, *pos;
+ struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group;
size_t subelem_len;
- const u8 *kek;
+ const u8 *kek, *igtk;
size_t kek_len;
size_t igtk_len;
+ u8 dummy_igtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2;
@@ -2266,8 +2285,19 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = igtk_len;
- if (aes_wrap(kek, kek_len, igtk_len / 8,
- gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+ igtk = gsm->IGTK[gsm->GN_igtk - 4];
+ if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use of
+ * IGTK in the BSS.
+ */
+ if (random_get_bytes(dummy_igtk, igtk_len / 8) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ igtk = dummy_igtk;
+ }
+ if (aes_wrap(kek, kek_len, igtk_len / 8, igtk, pos)) {
wpa_printf(MSG_DEBUG,
"FT: IGTK subelem encryption failed: kek_len=%d",
(int) kek_len);
@@ -2280,6 +2310,66 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
}
+static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+ u8 *subelem, *pos;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len;
+ const u8 *kek, *bigtk;
+ size_t kek_len;
+ size_t bigtk_len;
+ u8 dummy_bigtk[WPA_IGTK_MAX_LEN];
+
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kek = sm->PTK.kek2;
+ kek_len = sm->PTK.kek2_len;
+ } else {
+ kek = sm->PTK.kek;
+ kek_len = sm->PTK.kek_len;
+ }
+
+ bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+ /* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] |
+ * Key[16+8] */
+ subelem_len = 1 + 1 + 2 + 6 + 1 + bigtk_len + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return NULL;
+
+ pos = subelem;
+ *pos++ = FTIE_SUBELEM_BIGTK;
+ *pos++ = subelem_len - 2;
+ WPA_PUT_LE16(pos, gsm->GN_bigtk);
+ pos += 2;
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
+ pos += 6;
+ *pos++ = bigtk_len;
+ bigtk = gsm->IGTK[gsm->GN_bigtk - 6];
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ /*
+ * Provide unique random BIGTK to each OSEN STA to prevent use
+ * of BIGTK in the BSS.
+ */
+ if (random_get_bytes(dummy_bigtk, bigtk_len / 8) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ bigtk = dummy_bigtk;
+ }
+ if (aes_wrap(kek, kek_len, bigtk_len / 8, bigtk, pos)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: BIGTK subelem encryption failed: kek_len=%d",
+ (int) kek_len);
+ os_free(subelem);
+ return NULL;
+ }
+
+ *len = subelem_len;
+ return subelem;
+}
+
+
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
u8 *pos, u8 *end, u8 id, u8 descr_count,
const u8 *ies, size_t ies_len)
@@ -2413,13 +2503,15 @@ static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
- const u8 *req_ies, size_t req_ies_len)
+ const u8 *req_ies, size_t req_ies_len,
+ int omit_rsnxe)
{
u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
u8 *fte_mic, *elem_count;
size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
- u8 rsnxe[10];
+ u8 rsnxe_buf[10], *rsnxe = rsnxe_buf;
size_t rsnxe_len;
+ int rsnxe_used;
int res;
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
@@ -2440,6 +2532,32 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
end = pos + max_len;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth_alg == WLAN_AUTH_FT &&
+ sm->wpa_auth->conf.rsne_override_ft_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNE FT override for MIC calculation");
+ rsnie = sm->wpa_auth->conf.rsne_override_ft;
+ rsnie_len = sm->wpa_auth->conf.rsne_override_ft_len;
+ if (end - pos < (long int) rsnie_len)
+ return pos;
+ os_memcpy(pos, rsnie, rsnie_len);
+ rsnie = pos;
+ pos += rsnie_len;
+ if (rsnie_len > PMKID_LEN && sm->pmk_r1_name_valid) {
+ int idx;
+
+ /* Replace all 0xff PMKID with the valid PMKR1Name */
+ for (idx = 0; idx < PMKID_LEN; idx++) {
+ if (rsnie[rsnie_len - 1 - idx] != 0xff)
+ break;
+ }
+ if (idx == PMKID_LEN)
+ os_memcpy(&rsnie[rsnie_len - PMKID_LEN],
+ sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+ }
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
if (auth_alg == WLAN_AUTH_FT ||
((auth_alg == WLAN_AUTH_FILS_SK ||
auth_alg == WLAN_AUTH_FILS_SK_PFS ||
@@ -2509,6 +2627,29 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
subelem_len += igtk_len;
os_free(igtk);
}
+ if (sm->mgmt_frame_prot && conf->beacon_prot) {
+ u8 *bigtk;
+ size_t bigtk_len;
+ u8 *nbuf;
+
+ bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
+ if (!bigtk) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add BIGTK subelement");
+ os_free(subelem);
+ return NULL;
+ }
+ nbuf = os_realloc(subelem, subelem_len + bigtk_len);
+ if (!nbuf) {
+ os_free(subelem);
+ os_free(bigtk);
+ return NULL;
+ }
+ subelem = nbuf;
+ os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
+ subelem_len += bigtk_len;
+ os_free(bigtk);
+ }
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
@@ -2520,6 +2661,15 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
os_free(subelem);
return NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->oci_freq_override_ft_assoc) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI frequency %d -> %u MHz",
+ ci.frequency,
+ conf->oci_freq_override_ft_assoc);
+ ci.frequency = conf->oci_freq_override_ft_assoc;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
subelem_len += 2 + OCV_OCI_LEN;
nbuf = os_realloc(subelem, subelem_len);
@@ -2544,9 +2694,18 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
anonce = NULL;
snonce = NULL;
}
+ rsnxe_used = (auth_alg == WLAN_AUTH_FT) &&
+ (conf->sae_pwe == 1 || conf->sae_pwe == 2);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->wpa_auth->conf.ft_rsnxe_used) {
+ rsnxe_used = sm->wpa_auth->conf.ft_rsnxe_used == 1;
+ wpa_printf(MSG_DEBUG, "TESTING: FT: Force RSNXE Used %d",
+ rsnxe_used);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
anonce, snonce, pos, end - pos,
- subelem, subelem_len);
+ subelem, subelem_len, rsnxe_used);
os_free(subelem);
if (res < 0)
return NULL;
@@ -2582,10 +2741,24 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
if (ric_start == pos)
ric_start = NULL;
- res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, sizeof(rsnxe));
- if (res < 0)
- return NULL;
- rsnxe_len = res;
+ if (omit_rsnxe) {
+ rsnxe_len = 0;
+ } else {
+ res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe,
+ sizeof(rsnxe_buf));
+ if (res < 0)
+ return NULL;
+ rsnxe_len = res;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+ if (auth_alg == WLAN_AUTH_FT &&
+ sm->wpa_auth->conf.rsnxe_override_ft_set) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: RSNXE FT override for MIC calculation");
+ rsnxe = sm->wpa_auth->conf.rsnxe_override_ft;
+ rsnxe_len = sm->wpa_auth->conf.rsnxe_override_ft_len;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
*elem_count += 1;
@@ -2620,16 +2793,26 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len,
+ enum key_flag key_flag)
{
if (wpa_auth->cb->set_key == NULL)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
+}
+
+
+static inline int wpa_auth_add_sta_ft(struct wpa_authenticator *wpa_auth,
+ const u8 *addr)
+{
+ if (!wpa_auth->cb->add_sta_ft)
+ return -1;
+ return wpa_auth->cb->add_sta_ft(wpa_auth->cb_ctx, addr);
}
-void wpa_ft_install_ptk(struct wpa_state_machine *sm)
+void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry)
{
enum wpa_alg alg;
int klen;
@@ -2651,19 +2834,22 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
return;
}
+ if (!retry)
+ wpa_auth_add_sta_ft(sm->wpa_auth, sm->addr);
+
/* FIX: add STA entry to kernel/driver here? The set_key will fail
* most likely without this.. At the moment, STA entry is added only
* after association has been completed. This function will be called
* again after association to get the PTK configured, but that could be
* optimized by adding the STA entry earlier.
*/
- if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen))
+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active,
+ sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
- sm->pairwise_set = TRUE;
- sm->tk_already_set = TRUE;
+ sm->pairwise_set = true;
+ sm->tk_already_set = true;
}
@@ -2824,8 +3010,6 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth,
conf->r1_key_holder,
sm->addr, out_pmk_r1, pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, r0->pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
os_get_reltime(&now);
if (r0->expiration)
@@ -2954,8 +3138,6 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
sm->wpa_auth->conf.r1_key_holder, sm->addr,
pmk_r1_name, use_sha384) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
- pmk_r1_name, WPA_PMK_NAME_LEN);
if (conf->ft_psk_generate_local &&
wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@@ -3020,9 +3202,9 @@ pmk_r1_derived:
return WLAN_STATUS_UNSPECIFIED_FAILURE;
sm->pairwise = pairwise;
- sm->PTK_valid = TRUE;
- sm->tk_already_set = FALSE;
- wpa_ft_install_ptk(sm);
+ sm->PTK_valid = true;
+ sm->tk_already_set = false;
+ wpa_ft_install_ptk(sm, 0);
if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
@@ -3057,7 +3239,8 @@ pmk_r1_derived:
pos += ret;
ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
- sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
+ sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0,
+ 0);
if (ret < 0)
goto fail;
pos += ret;
@@ -3116,7 +3299,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
}
-u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len)
{
struct wpa_ft_ies parse;
@@ -3129,10 +3312,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
int use_sha384;
const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count;
+ int rsnxe_used;
+ struct wpa_auth_config *conf;
if (sm == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ conf = &sm->wpa_auth->conf;
use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
@@ -3161,8 +3347,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
mdie = (struct rsn_mdie *) parse.mdie;
if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
- os_memcmp(mdie->mobility_domain,
- sm->wpa_auth->conf.mobility_domain,
+ os_memcmp(mdie->mobility_domain, conf->mobility_domain,
MOBILITY_DOMAIN_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
return WLAN_STATUS_INVALID_MDIE;
@@ -3179,6 +3364,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
} else {
@@ -3192,6 +3378,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
anonce = ftie->anonce;
snonce = ftie->snonce;
+ rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic;
}
@@ -3237,14 +3424,14 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_FTIE;
}
- if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
+ if (os_memcmp_const(parse.r1kh_id, conf->r1_key_holder,
FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocReq");
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
- sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+ conf->r1_key_holder, FT_R1KH_ID_LEN);
return WLAN_STATUS_INVALID_FTIE;
}
@@ -3306,11 +3493,19 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
return WLAN_STATUS_INVALID_FTIE;
}
+ if (rsnxe_used && (conf->sae_pwe == 1 || conf->sae_pwe == 2) &&
+ !parse.rsnxe) {
+ wpa_printf(MSG_INFO,
+ "FT: FTE indicated that STA uses RSNXE, but RSNXE was not included");
+ return -1; /* discard request */
+ }
+
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
int tx_chanwidth;
int tx_seg1_idx;
+ enum oci_verify_result res;
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
wpa_printf(MSG_WARNING,
@@ -3324,10 +3519,21 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
&tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
- tx_chanwidth, tx_seg1_idx) != 0) {
- wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ res = ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx);
+ if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+ /* Work around misbehaving STAs */
+ wpa_printf(MSG_INFO,
+ "Disable OCV with a STA that does not send OCI");
+ wpa_auth_set_ocv(sm, 0);
+ } else if (res != OCI_SUCCESS) {
+ wpa_printf(MSG_WARNING, "OCV failed: %s", ocv_errorstr);
+ if (sm->wpa_auth->conf.msg_ctx)
+ wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO,
+ OCV_FAILURE "addr=" MACSTR
+ " frame=ft-reassoc-req error=%s",
+ MAC2STR(sm->addr), ocv_errorstr);
+ return WLAN_STATUS_INVALID_FTIE;
}
}
#endif /* CONFIG_OCV */
@@ -3550,14 +3756,11 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
};
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 for peer AP");
if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_len,
pmk_r0->pmk_r0_name, r1kh_id,
s1kh_id, pmk_r1, pmk_r1_name) < 0)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 (for peer AP)",
- pmk_r1, pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name (for peer AP)",
- pmk_r1_name, WPA_PMK_NAME_LEN);
WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
os_get_reltime(&now);
@@ -3687,6 +3890,10 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
goto out;
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull response from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
resp[0].type = FT_RRB_S1KH_ID;
resp[0].len = f_s1kh_id_len;
resp[0].data = f_s1kh_id;
@@ -4193,6 +4400,10 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth,
goto out;
}
+ wpa_printf(MSG_DEBUG, "FT: Send sequence number response from " MACSTR
+ " to " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr));
+
seq_resp_auth[0].type = FT_RRB_NONCE;
seq_resp_auth[0].len = f_nonce_len;
seq_resp_auth[0].data = f_nonce;
@@ -4422,7 +4633,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return -1;
}
status_code = WPA_GET_LE16(pos);
- pos += 2;
wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
"(status_code=%d)", status_code);
@@ -4435,11 +4645,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return -1;
}
- if (end > pos) {
- wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
- pos, end - pos);
- }
-
return 0;
}
@@ -4452,9 +4657,11 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
size_t alen, elen;
int no_defer = 0;
- wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP "
- MACSTR, MAC2STR(src_addr));
- wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix);
+ wpa_printf(MSG_DEBUG, "FT: RRB-OUI(" MACSTR
+ ") received frame from remote AP "
+ MACSTR " oui_suffix=%u dst=" MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(src_addr), oui_suffix,
+ MAC2STR(dst_addr));
wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len);
if (is_multicast_ether_addr(src_addr)) {
@@ -4464,13 +4671,8 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return;
}
- if (is_multicast_ether_addr(dst_addr)) {
- wpa_printf(MSG_DEBUG,
- "FT: RRB-OUI received frame from remote AP " MACSTR
- " to multicast address " MACSTR,
- MAC2STR(src_addr), MAC2STR(dst_addr));
+ if (is_multicast_ether_addr(dst_addr))
no_defer = 1;
- }
if (data_len < sizeof(u16)) {
wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short");
@@ -4545,6 +4747,10 @@ static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
return -1;
}
+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 push from " MACSTR
+ " to remote R0KH address " MACSTR,
+ MAC2STR(wpa_auth->addr), MAC2STR(r1kh->addr));
+
if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0,
r1kh->id, s1kh_id, push_auth, wpa_auth->addr,
FT_PACKET_R0KH_R1KH_PUSH,
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 76f86d9..c01654f 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -37,8 +37,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
struct hostapd_config *iconf,
struct wpa_auth_config *wconf)
{
+ int sae_pw_id;
+
os_memset(wconf, 0, sizeof(*wconf));
wconf->wpa = conf->wpa;
+ wconf->extended_key_id = conf->extended_key_id;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise;
wconf->wpa_group = conf->wpa_group;
@@ -65,6 +68,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
wconf->ieee80211w = conf->ieee80211w;
+ wconf->beacon_prot = conf->beacon_prot;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
wconf->sae_require_mfp = conf->sae_require_mfp;
#ifdef CONFIG_IEEE80211R_AP
@@ -118,6 +122,64 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wpabuf_head(conf->own_ie_override),
wconf->own_ie_override_len);
}
+ if (conf->rsne_override_eapol &&
+ wpabuf_len(conf->rsne_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsne_override_eapol_set = 1;
+ wconf->rsne_override_eapol_len =
+ wpabuf_len(conf->rsne_override_eapol);
+ os_memcpy(wconf->rsne_override_eapol,
+ wpabuf_head(conf->rsne_override_eapol),
+ wconf->rsne_override_eapol_len);
+ }
+ if (conf->rsnxe_override_eapol &&
+ wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxe_override_eapol_set = 1;
+ wconf->rsnxe_override_eapol_len =
+ wpabuf_len(conf->rsnxe_override_eapol);
+ os_memcpy(wconf->rsnxe_override_eapol,
+ wpabuf_head(conf->rsnxe_override_eapol),
+ wconf->rsnxe_override_eapol_len);
+ }
+ if (conf->rsne_override_ft &&
+ wpabuf_len(conf->rsne_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsne_override_ft_set = 1;
+ wconf->rsne_override_ft_len =
+ wpabuf_len(conf->rsne_override_ft);
+ os_memcpy(wconf->rsne_override_ft,
+ wpabuf_head(conf->rsne_override_ft),
+ wconf->rsne_override_ft_len);
+ }
+ if (conf->rsnxe_override_ft &&
+ wpabuf_len(conf->rsnxe_override_ft) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxe_override_ft_set = 1;
+ wconf->rsnxe_override_ft_len =
+ wpabuf_len(conf->rsnxe_override_ft);
+ os_memcpy(wconf->rsnxe_override_ft,
+ wpabuf_head(conf->rsnxe_override_ft),
+ wconf->rsnxe_override_ft_len);
+ }
+ if (conf->gtk_rsc_override &&
+ wpabuf_len(conf->gtk_rsc_override) > 0 &&
+ wpabuf_len(conf->gtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+ os_memcpy(wconf->gtk_rsc_override,
+ wpabuf_head(conf->gtk_rsc_override),
+ wpabuf_len(conf->gtk_rsc_override));
+ wconf->gtk_rsc_override_set = 1;
+ }
+ if (conf->igtk_rsc_override &&
+ wpabuf_len(conf->igtk_rsc_override) > 0 &&
+ wpabuf_len(conf->igtk_rsc_override) <= WPA_KEY_RSC_LEN) {
+ os_memcpy(wconf->igtk_rsc_override,
+ wpabuf_head(conf->igtk_rsc_override),
+ wpabuf_len(conf->igtk_rsc_override));
+ wconf->igtk_rsc_override_set = 1;
+ }
+ wconf->ft_rsnxe_used = conf->ft_rsnxe_used;
+ wconf->oci_freq_override_eapol_m3 = conf->oci_freq_override_eapol_m3;
+ wconf->oci_freq_override_eapol_g1 = conf->oci_freq_override_eapol_g1;
+ wconf->oci_freq_override_ft_assoc = conf->oci_freq_override_ft_assoc;
+ wconf->oci_freq_override_fils_assoc =
+ conf->oci_freq_override_fils_assoc;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@@ -131,6 +193,21 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
FILS_CACHE_ID_LEN);
#endif /* CONFIG_FILS */
wconf->sae_pwe = conf->sae_pwe;
+ sae_pw_id = hostapd_sae_pw_id_in_use(conf);
+ if (sae_pw_id == 2 && wconf->sae_pwe != 3)
+ wconf->sae_pwe = 1;
+ else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
+ wconf->sae_pwe = 2;
+#ifdef CONFIG_SAE_PK
+ wconf->sae_pk = hostapd_sae_pk_in_use(conf);
+#endif /* CONFIG_SAE_PK */
+#ifdef CONFIG_OWE
+ wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
+#endif /* CONFIG_OWE */
+ wconf->transition_disable = conf->transition_disable;
+#ifdef CONFIG_DPP2
+ wconf->dpp_pfs = conf->dpp_pfs;
+#endif /* CONFIG_DPP2 */
}
@@ -208,16 +285,15 @@ static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
break;
case WPA_EAPOL_keyRun:
if (sta->eapol_sm)
- sta->eapol_sm->keyRun = value ? TRUE : FALSE;
+ sta->eapol_sm->keyRun = value;
break;
case WPA_EAPOL_keyAvailable:
if (sta->eapol_sm)
- sta->eapol_sm->eap_if->eapKeyAvailable =
- value ? TRUE : FALSE;
+ sta->eapol_sm->eap_if->eapKeyAvailable = value;
break;
case WPA_EAPOL_keyDone:
if (sta->eapol_sm)
- sta->eapol_sm->keyDone = value ? TRUE : FALSE;
+ sta->eapol_sm->keyDone = value;
break;
case WPA_EAPOL_inc_EapolFramesTx:
if (sta->eapol_sm)
@@ -354,19 +430,27 @@ static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key,
- size_t key_len)
+ size_t key_len, enum key_flag key_flag)
{
struct hostapd_data *hapd = ctx;
const char *ifname = hapd->conf->iface;
if (vlan_id > 0) {
ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
- if (ifname == NULL)
- return -1;
+ if (!ifname) {
+ if (!(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_VLAN_OFFLOAD))
+ return -1;
+ ifname = hapd->conf->iface;
+ }
}
#ifdef CONFIG_TESTING_OPTIONS
- if (addr && !is_broadcast_ether_addr(addr)) {
+ if (key_flag & KEY_FLAG_MODIFY) {
+ /* We are updating an already installed key. Don't overwrite
+ * the already stored key information with zeros.
+ */
+ } else if (addr && !is_broadcast_ether_addr(addr)) {
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
@@ -377,15 +461,23 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
os_memcpy(sta->last_tk, key, key_len);
sta->last_tk_len = key_len;
}
- } else if (alg == WPA_ALG_IGTK ||
+ } else if (alg == WPA_ALG_BIP_CMAC_128 ||
alg == WPA_ALG_BIP_GMAC_128 ||
alg == WPA_ALG_BIP_GMAC_256 ||
alg == WPA_ALG_BIP_CMAC_256) {
- hapd->last_igtk_alg = alg;
- hapd->last_igtk_key_idx = idx;
- if (key)
- os_memcpy(hapd->last_igtk, key, key_len);
- hapd->last_igtk_len = key_len;
+ if (idx == 4 || idx == 5) {
+ hapd->last_igtk_alg = alg;
+ hapd->last_igtk_key_idx = idx;
+ if (key)
+ os_memcpy(hapd->last_igtk, key, key_len);
+ hapd->last_igtk_len = key_len;
+ } else if (idx == 6 || idx == 7) {
+ hapd->last_bigtk_alg = alg;
+ hapd->last_bigtk_key_idx = idx;
+ if (key)
+ os_memcpy(hapd->last_bigtk, key, key_len);
+ hapd->last_bigtk_len = key_len;
+ }
} else {
hapd->last_gtk_alg = alg;
hapd->last_gtk_key_idx = idx;
@@ -394,8 +486,8 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
hapd->last_gtk_len = key_len;
}
#endif /* CONFIG_TESTING_OPTIONS */
- return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
- key, key_len);
+ return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, vlan_id, 1,
+ NULL, 0, key, key_len, key_flag);
}
@@ -615,10 +707,6 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
}
#endif /* CONFIG_IEEE80211R_AP */
- if (hapd->driver && hapd->driver->send_ether)
- return hapd->driver->send_ether(hapd->drv_priv, dst,
- hapd->own_addr, proto,
- data, data_len);
if (hapd->l2 == NULL)
return -1;
@@ -680,6 +768,12 @@ static void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx)
dl_list_for_each_safe(data, n, &hapd->l2_oui_queue,
struct oui_deliver_later_data, list) {
oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix);
+ wpa_printf(MSG_DEBUG, "RRB(%s): %s src=" MACSTR " dst=" MACSTR
+ " oui_suffix=%u data_len=%u data=%p",
+ hapd->conf->iface, __func__,
+ MAC2STR(data->src_addr), MAC2STR(data->dst_addr),
+ data->oui_suffix, (unsigned int) data->data_len,
+ data);
if (hapd->wpa_auth && oui_ctx) {
eth_p_oui_deliver(oui_ctx, data->src_addr,
data->dst_addr,
@@ -704,16 +798,26 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
{
struct wpa_auth_oui_iface_iter_data *idata = ctx;
struct oui_deliver_later_data *data;
- struct hostapd_data *hapd;
+ struct hostapd_data *hapd, *src_hapd = idata->src_hapd;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
- if (hapd == idata->src_hapd)
- continue;
+ if (hapd == src_hapd)
+ continue; /* don't deliver back to same interface */
+ if (!wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) ||
+ hapd->conf->ssid.ssid_len !=
+ src_hapd->conf->ssid.ssid_len ||
+ os_memcmp(hapd->conf->ssid.ssid,
+ src_hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len) != 0 ||
+ os_memcmp(hapd->conf->mobility_domain,
+ src_hapd->conf->mobility_domain,
+ MOBILITY_DOMAIN_ID_LEN) != 0)
+ continue; /* no matching FT SSID/mobility domain */
if (!is_multicast_ether_addr(idata->dst_addr) &&
os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0)
- continue;
+ continue; /* destination address does not match */
/* defer eth_p_oui_deliver until next eloop step as this is
* when it would be triggerd from reading from sock
@@ -725,14 +829,20 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
data = os_zalloc(sizeof(*data) + idata->data_len);
if (!data)
return 1;
+ wpa_printf(MSG_DEBUG,
+ "RRB(%s): local delivery to %s dst=" MACSTR
+ " oui_suffix=%u data_len=%u data=%p",
+ src_hapd->conf->iface, hapd->conf->iface,
+ MAC2STR(idata->dst_addr), idata->oui_suffix,
+ (unsigned int) idata->data_len, data);
- os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN);
+ os_memcpy(data->src_addr, src_hapd->own_addr, ETH_ALEN);
os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN);
os_memcpy(data + 1, idata->data, idata->data_len);
data->data_len = idata->data_len;
data->oui_suffix = idata->oui_suffix;
- dl_list_add(&hapd->l2_oui_queue, &data->list);
+ dl_list_add_tail(&hapd->l2_oui_queue, &data->list);
if (!eloop_is_timeout_registered(hostapd_oui_deliver_later,
hapd, NULL))
@@ -740,7 +850,11 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx)
hostapd_oui_deliver_later,
hapd, NULL);
- return 1;
+ /* If dst_addr is a multicast address, do not return any
+ * non-zero value here. Otherwise, the iteration of
+ * for_each_interface() will be stopped. */
+ if (!is_multicast_ether_addr(idata->dst_addr))
+ return 1;
}
return 0;
@@ -756,6 +870,10 @@ static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix,
struct hostapd_data *hapd = ctx;
struct eth_p_oui_ctx *oui_ctx;
+ wpa_printf(MSG_DEBUG, "RRB(%s): send to dst=" MACSTR
+ " oui_suffix=%u data_len=%u",
+ hapd->conf->iface, MAC2STR(dst), oui_suffix,
+ (unsigned int) data_len);
#ifdef CONFIG_IEEE80211R_AP
if (hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
@@ -799,26 +917,32 @@ static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
#ifndef CONFIG_NO_VLAN
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
- struct vlan_description vlan_desc;
sta = ap_get_sta(hapd, addr);
if (!sta)
return -1;
- os_memset(&vlan_desc, 0, sizeof(vlan_desc));
- vlan_desc.notempty = 1;
- vlan_desc.untagged = vlan_id;
- if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
- wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file",
- vlan_id);
- return -1;
- }
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
+ struct vlan_description vlan_desc;
- if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
- wpa_printf(MSG_INFO,
- "Failed to assign VLAN ID %d from wpa_psk_file to "
- MACSTR, vlan_id, MAC2STR(sta->addr));
- return -1;
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = 1;
+ vlan_desc.untagged = vlan_id;
+ if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ wpa_printf(MSG_INFO,
+ "Invalid VLAN ID %d in wpa_psk_file",
+ vlan_id);
+ return -1;
+ }
+
+ if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) {
+ wpa_printf(MSG_INFO,
+ "Failed to assign VLAN ID %d from wpa_psk_file to "
+ MACSTR, vlan_id, MAC2STR(sta->addr));
+ return -1;
+ }
+ } else {
+ sta->vlan_id = vlan_id;
}
wpa_printf(MSG_INFO,
@@ -880,7 +1004,7 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
os_memcpy(&m->u, data, data_len);
- res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
+ res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0, NULL, 0, 0);
os_free(m);
return res;
}
@@ -891,18 +1015,28 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int ret;
wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR
" based on WPA authenticator callback",
MAC2STR(sta_addr));
- if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
+ ret = hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT);
+
+ /*
+ * The expected return values from hostapd_add_sta_node() are
+ * 0: successfully added STA entry
+ * -EOPNOTSUPP: driver or driver wrapper does not support/need this
+ * operations
+ * any other negative value: error in adding the STA entry */
+ if (ret < 0 && ret != -EOPNOTSUPP)
return NULL;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
- if (hapd->driver && hapd->driver->add_sta_node)
+ if (ret == 0)
sta->added_unassoc = 1;
+
sta->ft_over_ds = 1;
if (sta->wpa_sm) {
sta->auth_alg = WLAN_AUTH_FT;
@@ -920,6 +1054,34 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
}
+static int hostapd_wpa_auth_add_sta_ft(void *ctx, const u8 *sta_addr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, sta_addr);
+ if (!sta)
+ return -1;
+
+ if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+ (sta->flags & WLAN_STA_MFP) && ap_sta_is_authorized(sta) &&
+ !(hapd->conf->mesh & MESH_ENABLED) && !(sta->added_unassoc)) {
+ /* We could not do this in handle_auth() since there was a
+ * PMF-enabled association for the STA and the new
+ * authentication attempt was not yet fully processed. Now that
+ * we are ready to configure the TK to the driver,
+ * authentication has succeeded and we can clean up the driver
+ * STA entry to avoid issues with any maintained state from the
+ * previous association. */
+ wpa_printf(MSG_DEBUG,
+ "FT: Remove and re-add driver STA entry after successful FT authentication");
+ return ap_sta_re_add(hapd, sta);
+ }
+
+ return 0;
+}
+
+
static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
struct vlan_description *vlan)
{
@@ -1281,6 +1443,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211R_AP
.send_ft_action = hostapd_wpa_auth_send_ft_action,
.add_sta = hostapd_wpa_auth_add_sta,
+ .add_sta_ft = hostapd_wpa_auth_add_sta_ft,
.add_tspec = hostapd_wpa_auth_add_tspec,
.set_vlan = hostapd_wpa_auth_set_vlan,
.get_vlan = hostapd_wpa_auth_get_vlan,
@@ -1296,10 +1459,27 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
size_t wpa_ie_len;
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
+ _conf.msg_ctx = hapd->msg_ctx;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
_conf.ap_mlme = 1;
+
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+ (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+ (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ "Disable PTK0 rekey support - replaced with disconnect");
+ _conf.wpa_deny_ptk0_rekey = 1;
+ }
+
+ if (_conf.extended_key_id &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID))
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Extended Key ID supported");
+ else
+ _conf.extended_key_id = 0;
+
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
@@ -1334,9 +1514,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
hapd->conf->iface;
hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB,
hostapd_rrb_receive, hapd, 1);
- if (hapd->l2 == NULL &&
- (hapd->driver == NULL ||
- hapd->driver->send_ether == NULL)) {
+ if (!hapd->l2) {
wpa_printf(MSG_ERROR, "Failed to open l2_packet "
"interface");
return -1;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index a993f50..a6dc1a5 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -39,20 +39,20 @@ struct wpa_state_machine {
WPA_PTK_GROUP_KEYERROR
} wpa_ptk_group_state;
- Boolean Init;
- Boolean DeauthenticationRequest;
- Boolean AuthenticationRequest;
- Boolean ReAuthenticationRequest;
- Boolean Disconnect;
+ bool Init;
+ bool DeauthenticationRequest;
+ bool AuthenticationRequest;
+ bool ReAuthenticationRequest;
+ bool Disconnect;
u16 disconnect_reason; /* specific reason code to use with Disconnect */
u32 TimeoutCtr;
u32 GTimeoutCtr;
- Boolean TimeoutEvt;
- Boolean EAPOLKeyReceived;
- Boolean EAPOLKeyPairwise;
- Boolean EAPOLKeyRequest;
- Boolean MICVerified;
- Boolean GUpdateStationKeys;
+ bool TimeoutEvt;
+ bool EAPOLKeyReceived;
+ bool EAPOLKeyPairwise;
+ bool EAPOLKeyRequest;
+ bool MICVerified;
+ bool GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
u8 SNonce[WPA_NONCE_LEN];
u8 alt_SNonce[WPA_NONCE_LEN];
@@ -61,20 +61,22 @@ struct wpa_state_machine {
unsigned int pmk_len;
u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
struct wpa_ptk PTK;
- Boolean PTK_valid;
- Boolean pairwise_set;
- Boolean tk_already_set;
+ u8 keyidx_active;
+ bool use_ext_key_id;
+ bool PTK_valid;
+ bool pairwise_set;
+ bool tk_already_set;
int keycount;
- Boolean Pair;
+ bool Pair;
struct wpa_key_replay_counter {
u8 counter[WPA_REPLAY_COUNTER_LEN];
- Boolean valid;
+ bool valid;
} key_replay[RSNA_MAX_EAPOL_RETRIES],
prev_key_replay[RSNA_MAX_EAPOL_RETRIES];
- Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
- Boolean PTKRequest; /* not in IEEE 802.11i state machine */
- Boolean has_GTK;
- Boolean PtkGroupInit; /* init request for PTK Group state machine */
+ bool PInitAKeys; /* WPA only, not in IEEE 802.11i */
+ bool PTKRequest; /* not in IEEE 802.11i state machine */
+ bool has_GTK;
+ bool PtkGroupInit; /* init request for PTK Group state machine */
u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
size_t last_rx_eapol_key_len;
@@ -93,8 +95,9 @@ struct wpa_state_machine {
#endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1;
+
#ifdef CONFIG_OCV
- unsigned int ocv_enabled:1;
+ int ocv_enabled;
#endif /* CONFIG_OCV */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
@@ -172,12 +175,12 @@ struct wpa_group {
struct wpa_group *next;
int vlan_id;
- Boolean GInit;
+ bool GInit;
int GKeyDoneStations;
- Boolean GTKReKey;
+ bool GTKReKey;
int GTK_len;
int GN, GM;
- Boolean GTKAuthenticator;
+ bool GTKAuthenticator;
u8 Counter[WPA_NONCE_LEN];
enum {
@@ -189,11 +192,13 @@ struct wpa_group {
u8 GMK[WPA_GMK_LEN];
u8 GTK[2][WPA_GTK_MAX_LEN];
u8 GNonce[WPA_NONCE_LEN];
- Boolean changed;
- Boolean first_sta_seen;
- Boolean reject_4way_hs_for_entropy;
+ bool changed;
+ bool first_sta_seen;
+ bool reject_4way_hs_for_entropy;
u8 IGTK[2][WPA_IGTK_MAX_LEN];
+ u8 BIGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
+ int GN_bigtk, GM_bigtk;
/* Number of references except those in struct wpa_group->next */
unsigned int references;
unsigned int num_setup_iface;
@@ -273,7 +278,8 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len);
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt);
void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
- logger_level level, const char *fmt, ...);
+ logger_level level, const char *fmt, ...)
+ PRINTF_FORMAT(4, 5);
void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int key_info,
const u8 *key_rsc, const u8 *nonce,
@@ -292,11 +298,11 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
- size_t subelem_len);
+ size_t subelem_len, int rsnxe_used);
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);
+void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry);
int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
const u8 *pmk_r0_name);
#endif /* CONFIG_IEEE80211R_AP */
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 2e6d059..3704fc0 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -297,6 +297,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
if (rsn_testing)
capab |= BIT(8) | BIT(15);
#endif /* CONFIG_RSN_TESTING */
+ if (conf->extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -376,7 +378,7 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
u8 *pos = buf;
- if (conf->sae_pwe != 1 && conf->sae_pwe != 2)
+ if (conf->sae_pwe != 1 && conf->sae_pwe != 2 && !conf->sae_pk)
return 0; /* no supported extended RSN capabilities */
if (len < 3)
@@ -386,7 +388,12 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
*pos++ = 1;
/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
* used for now */
- *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ *pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (conf->sae_pk)
+ *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ pos++;
return pos - buf;
}
@@ -546,13 +553,15 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
}
-int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, int freq,
- const u8 *wpa_ie, size_t wpa_ie_len,
- const u8 *rsnxe, size_t rsnxe_len,
- const u8 *mdie, size_t mdie_len,
- const u8 *owe_dh, size_t owe_dh_len)
+enum wpa_validate_result
+wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int freq,
+ const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ const u8 *mdie, size_t mdie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
{
+ struct wpa_auth_config *conf = &wpa_auth->conf;
struct wpa_ie_data data;
int ciphers, key_mgmt, res, version;
u32 selector;
@@ -799,14 +808,26 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_SAE */
#ifdef CONFIG_OCV
- if ((data.capabilities & WPA_CAPABILITY_OCVC) &&
+ if (wpa_auth->conf.ocv && (data.capabilities & WPA_CAPABILITY_OCVC) &&
!(data.capabilities & WPA_CAPABILITY_MFPC)) {
- wpa_printf(MSG_DEBUG,
- "Management frame protection required with OCV, but client did not enable it");
- return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ /* Some legacy MFP incapable STAs wrongly copy OCVC bit from
+ * AP RSN capabilities. To improve interoperability with such
+ * legacy STAs allow connection without enabling OCV when the
+ * workaround mode (ocv=2) is enabled.
+ */
+ if (wpa_auth->conf.ocv == 2) {
+ wpa_printf(MSG_DEBUG,
+ "Allow connecting MFP incapable and OCV capable STA without enabling OCV");
+ wpa_auth_set_ocv(sm, 0);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection required with OCV, but client did not enable it");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+ } else {
+ wpa_auth_set_ocv(sm, (data.capabilities & WPA_CAPABILITY_OCVC) ?
+ wpa_auth->conf.ocv : 0);
}
- wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
- (data.capabilities & WPA_CAPABILITY_OCVC));
#endif /* CONFIG_OCV */
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
@@ -847,19 +868,18 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
"OWE: No Diffie-Hellman Parameter element");
return WPA_INVALID_AKMP;
}
-#ifdef CONFIG_DPP
- if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && owe_dh) {
- /* Diffie-Hellman Parameter element can be used with DPP as
- * well, so allow this to proceed. */
- } else
-#endif /* CONFIG_DPP */
- if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) {
- wpa_printf(MSG_DEBUG,
- "OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM");
- return WPA_INVALID_AKMP;
- }
#endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
+ ((conf->dpp_pfs == 1 && !owe_dh) ||
+ (conf->dpp_pfs == 2 && owe_dh))) {
+ wpa_printf(MSG_DEBUG, "DPP: PFS %s",
+ conf->dpp_pfs == 1 ? "required" : "not allowed");
+ return WPA_DENIED_OTHER_REASON;
+ }
+#endif /* CONFIG_DPP2 */
+
sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
if (sm->pairwise < 0)
return WPA_INVALID_PAIRWISE;
@@ -944,6 +964,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#endif /* CONFIG_DPP */
+ if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 &&
+ sm->pairwise != WPA_CIPHER_TKIP &&
+ (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+ sm->use_ext_key_id = true;
+ if (conf->extended_key_id == 2 &&
+ !wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+ !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
+ sm->keyidx_active = 1;
+ else
+ sm->keyidx_active = 0;
+ wpa_printf(MSG_DEBUG,
+ "RSN: Extended Key ID supported (start with %d)",
+ sm->keyidx_active);
+ } else {
+ sm->use_ext_key_id = false;
+ }
+
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
os_free(sm->wpa_ie);
sm->wpa_ie = os_malloc(wpa_ie_len);
diff --git a/src/ap/wpa_auth_kay.c b/src/ap/wpa_auth_kay.c
index b6e4797..46d94b4 100644
--- a/src/ap/wpa_auth_kay.c
+++ b/src/ap/wpa_auth_kay.c
@@ -52,7 +52,7 @@ static int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap)
}
-static int hapd_enable_protect_frames(void *priv, Boolean enabled)
+static int hapd_enable_protect_frames(void *priv, bool enabled)
{
struct hostapd_data *hapd = priv;
@@ -62,7 +62,7 @@ static int hapd_enable_protect_frames(void *priv, Boolean enabled)
}
-static int hapd_enable_encrypt(void *priv, Boolean enabled)
+static int hapd_enable_encrypt(void *priv, bool enabled)
{
struct hostapd_data *hapd = priv;
@@ -72,7 +72,7 @@ static int hapd_enable_encrypt(void *priv, Boolean enabled)
}
-static int hapd_set_replay_protect(void *priv, Boolean enabled, u32 window)
+static int hapd_set_replay_protect(void *priv, bool enabled, u32 window)
{
struct hostapd_data *hapd = priv;
@@ -93,7 +93,7 @@ static int hapd_set_current_cipher_suite(void *priv, u64 cs)
}
-static int hapd_enable_controlled_port(void *priv, Boolean enabled)
+static int hapd_enable_controlled_port(void *priv, bool enabled)
{
struct hostapd_data *hapd = priv;
@@ -465,7 +465,7 @@ void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
- TRUE);
+ true);
fail:
bin_clear_free(msk, sizeof(*msk));
@@ -507,7 +507,7 @@ void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
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);
+ res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, true);
if (res)
goto free_cak;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 33caeaf..dc8aa8f 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -125,6 +125,7 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
os_memcpy(p->addr, mac_addr, ETH_ALEN);
os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
os_memcpy(p->psk, psk, PMK_LEN);
+ p->wps = 1;
if (hapd->new_psk_cb) {
hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
@@ -137,16 +138,17 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
if (ssid->wpa_psk_file) {
FILE *f;
char hex[PMK_LEN * 2 + 1];
+
/* Add the new PSK to PSK list file */
f = fopen(ssid->wpa_psk_file, "a");
- if (f == NULL) {
- wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
- "'%s'", ssid->wpa_psk_file);
+ if (!f) {
+ wpa_printf(MSG_DEBUG, "Failed to add the PSK to '%s'",
+ ssid->wpa_psk_file);
return -1;
}
wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
- fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
+ fprintf(f, "wps=1 " MACSTR " %s\n", MAC2STR(mac_addr), hex);
fclose(f);
}
@@ -269,6 +271,44 @@ static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
}
+static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr,
+ const u8 **psk)
+{
+ const struct hostapd_data *hapd = ctx;
+ const struct hostapd_wpa_psk *wpa_psk;
+ const u8 *any_psk = NULL;
+ const u8 *dev_psk = NULL;
+
+ for (wpa_psk = hapd->conf->ssid.wpa_psk; wpa_psk;
+ wpa_psk = wpa_psk->next) {
+ if (!wpa_psk->wps)
+ continue;
+
+ if (!any_psk && is_zero_ether_addr(wpa_psk->addr))
+ any_psk = wpa_psk->psk;
+
+ if (mac_addr && !dev_psk &&
+ os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) {
+ dev_psk = wpa_psk->psk;
+ break;
+ }
+ }
+
+ if (dev_psk) {
+ *psk = dev_psk;
+ } else if (any_psk) {
+ *psk = any_psk;
+ } else {
+ *psk = NULL;
+ wpa_printf(MSG_DEBUG,
+ "WPS: No appropriate PSK in wpa_psk_file");
+ return 0;
+ }
+
+ return 1;
+}
+
+
static void wps_reload_config(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
@@ -324,6 +364,13 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
bss->ssid.ssid_set = 1;
}
+#ifdef CONFIG_NO_TKIP
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK |
+ WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ bss->wpa = 2;
+ else
+ bss->wpa = 0;
+#else /* CONFIG_NO_TKIP */
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
bss->wpa = 3;
@@ -333,6 +380,7 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
bss->wpa = 1;
else
bss->wpa = 0;
+#endif /* CONFIG_NO_TKIP */
if (bss->wpa) {
if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
@@ -347,8 +395,10 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
else
bss->wpa_pairwise |= WPA_CIPHER_CCMP;
}
+#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP)
bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+#endif /* CONFIG_NO_TKIP */
bss->rsn_pairwise = bss->wpa_pairwise;
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
bss->wpa_pairwise,
@@ -519,6 +569,13 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
fprintf(nconf, "\n");
}
+#ifdef CONFIG_NO_TKIP
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK |
+ WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ wpa = 2;
+ else
+ wpa = 0;
+#else /* CONFIG_NO_TKIP */
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
wpa = 3;
@@ -528,6 +585,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
wpa = 1;
else
wpa = 0;
+#endif /* CONFIG_NO_TKIP */
if (wpa) {
char *prefix;
@@ -571,9 +629,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
prefix = " ";
}
+#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP) {
fprintf(nconf, "%sTKIP", prefix);
}
+#endif /* CONFIG_NO_TKIP */
fprintf(nconf, "\n");
if (cred->key_len >= 8 && cred->key_len < 64) {
@@ -611,8 +671,10 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
(str_starts(buf, "ssid=") ||
str_starts(buf, "ssid2=") ||
str_starts(buf, "auth_algs=") ||
+#ifdef CONFIG_WEP
str_starts(buf, "wep_default_key=") ||
str_starts(buf, "wep_key") ||
+#endif /* CONFIG_WEP */
str_starts(buf, "wps_state=") ||
(pmf_changed && str_starts(buf, "ieee80211w=")) ||
str_starts(buf, "wpa=") ||
@@ -985,6 +1047,21 @@ static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
}
+static int hostapd_wps_set_application_ext(struct hostapd_data *hapd,
+ struct wps_context *wps)
+{
+ wpabuf_free(wps->dev.application_ext);
+
+ if (!hapd->conf->wps_application_ext) {
+ wps->dev.application_ext = NULL;
+ return 0;
+ }
+
+ wps->dev.application_ext = wpabuf_dup(hapd->conf->wps_application_ext);
+ return wps->dev.application_ext ? 0 : -1;
+}
+
+
static void hostapd_free_wps(struct wps_context *wps)
{
int i;
@@ -1074,7 +1151,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
WPS_DEV_TYPE_LEN);
- if (hostapd_wps_set_vendor_ext(hapd, wps) < 0)
+ if (hostapd_wps_set_vendor_ext(hapd, wps) < 0 ||
+ hostapd_wps_set_application_ext(hapd, wps) < 0)
goto fail;
wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
@@ -1102,12 +1180,24 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->encr_types_rsn |= WPS_ENCR_AES;
}
if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
+#ifdef CONFIG_NO_TKIP
+ wpa_printf(MSG_INFO, "WPS: TKIP not supported");
+ goto fail;
+#else /* CONFIG_NO_TKIP */
wps->encr_types |= WPS_ENCR_TKIP;
wps->encr_types_rsn |= WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
}
}
if (conf->wpa & WPA_PROTO_WPA) {
+#ifdef CONFIG_NO_TKIP
+ if (!(conf->wpa & WPA_PROTO_RSN)) {
+ wpa_printf(MSG_INFO, "WPS: WPA(v1) not supported");
+ goto fail;
+ }
+ conf->wpa &= ~WPA_PROTO_WPA;
+#else /* CONFIG_NO_TKIP */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
wps->auth_types |= WPS_AUTH_WPAPSK;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
@@ -1121,6 +1211,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->encr_types |= WPS_ENCR_TKIP;
wps->encr_types_wpa |= WPS_ENCR_TKIP;
}
+#endif /* CONFIG_NO_TKIP */
}
if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
@@ -1140,6 +1231,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
conf->ssid.wpa_psk->psk, PMK_LEN);
wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
wps->network_key = os_malloc(conf->ssid.wep.len[0]);
if (wps->network_key == NULL)
@@ -1147,6 +1239,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
os_memcpy(wps->network_key, conf->ssid.wep.key[0],
conf->ssid.wep.len[0]);
wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
}
if (conf->ssid.wpa_psk) {
@@ -1158,10 +1251,17 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->ap_encr_type = wps->encr_types;
if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
/* Override parameters to enable security by default */
+#ifdef CONFIG_NO_TKIP
+ wps->auth_types = WPS_AUTH_WPA2PSK;
+ wps->encr_types = WPS_ENCR_AES;
+ wps->encr_types_rsn = WPS_ENCR_AES;
+ wps->encr_types_wpa = WPS_ENCR_AES;
+#else /* CONFIG_NO_TKIP */
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
wps->encr_types_rsn = WPS_ENCR_AES | WPS_ENCR_TKIP;
wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
}
if ((hapd->conf->multi_ap & FRONTHAUL_BSS) &&
@@ -1197,14 +1297,13 @@ int hostapd_init_wps(struct hostapd_data *hapd,
cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
cfg.reg_success_cb = hostapd_wps_reg_success_cb;
cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
+ cfg.lookup_pskfile_cb = hostapd_wps_lookup_pskfile_cb;
cfg.cb_ctx = hapd;
cfg.skip_cred_build = conf->skip_cred_build;
cfg.extra_cred = conf->extra_cred;
cfg.extra_cred_len = conf->extra_cred_len;
cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
conf->skip_cred_build;
- if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
- cfg.static_wep_only = 1;
cfg.dualband = interface_count(hapd->iface) > 1;
if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
(WPS_RF_50GHZ | WPS_RF_24GHZ))
@@ -1311,6 +1410,7 @@ void hostapd_update_wps(struct hostapd_data *hapd)
#endif /* CONFIG_WPS_UPNP */
hostapd_wps_set_vendor_ext(hapd, hapd->wps);
+ hostapd_wps_set_application_ext(hapd, hapd->wps);
if (hapd->conf->wps_state)
wps_registrar_update_ie(hapd->wps->registrar);
@@ -1417,6 +1517,7 @@ static int wps_cancel(struct hostapd_data *hapd, void *ctx)
data->count++;
wps_registrar_wps_cancel(hapd->wps->registrar);
ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_CANCEL);
}
return 0;
@@ -1740,8 +1841,10 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
if (os_strncmp(auth, "OPEN", 4) == 0)
cred.auth_type = WPS_AUTH_OPEN;
+#ifndef CONFIG_NO_TKIP
else if (os_strncmp(auth, "WPAPSK", 6) == 0)
cred.auth_type = WPS_AUTH_WPAPSK;
+#endif /* CONFIG_NO_TKIP */
else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
cred.auth_type = WPS_AUTH_WPA2PSK;
else
@@ -1750,8 +1853,10 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
if (encr) {
if (os_strncmp(encr, "NONE", 4) == 0)
cred.encr_type = WPS_ENCR_NONE;
+#ifndef CONFIG_NO_TKIP
else if (os_strncmp(encr, "TKIP", 4) == 0)
cred.encr_type = WPS_ENCR_TKIP;
+#endif /* CONFIG_NO_TKIP */
else if (os_strncmp(encr, "CCMP", 4) == 0)
cred.encr_type = WPS_ENCR_AES;
else
diff --git a/src/build.rules b/src/build.rules
new file mode 100644
index 0000000..acda884
--- /dev/null
+++ b/src/build.rules
@@ -0,0 +1,109 @@
+.PHONY: all
+all: _all
+
+# disable built-in rules
+.SUFFIXES:
+
+# setup some variables
+ROOTDIR := $(dir $(lastword $(MAKEFILE_LIST)))
+ROOTDIR := $(dir $(ROOTDIR:%../src/=%))../
+BUILDDIR ?= $(abspath $(ROOTDIR)build)
+BUILDDIR := $(BUILDDIR:%/=%)
+ABSROOT := $(abspath $(ROOTDIR))
+ifeq ($(origin OUT),command line)
+_PROJ := $(OUT:%/=%)
+_PROJ := $(_PROJ:$(BUILDDIR)/%=%)
+else
+_PROJ := $(abspath $(dir $(firstword $(MAKEFILE_LIST))))
+_PROJ := $(_PROJ:$(ABSROOT)/%=%)
+endif
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef RANLIB
+RANLIB=ranlib
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+ifneq ($(CONFIG_FILE),)
+-include $(CONFIG_FILE)
+
+# export for sub-makefiles
+export CONFIG_CODE_COVERAGE
+
+.PHONY: verify_config
+verify_config:
+ @if [ ! -r $(CONFIG_FILE) ]; then \
+ echo 'Building $(firstword $(ALL)) requires a configuration file'; \
+ echo '(.config). See README for more instructions. You can'; \
+ echo 'run "cp defconfig .config" to create an example'; \
+ echo 'configuration.'; \
+ exit 1; \
+ fi
+VERIFY := verify_config
+else
+VERIFY :=
+endif
+
+# default target
+.PHONY: _all
+_all: $(VERIFY) $(ALL) $(EXTRA_TARGETS)
+
+# continue setup
+COVSUFFIX := $(if $(CONFIG_CODE_COVERAGE),-cov,)
+PROJ := $(_PROJ)$(COVSUFFIX)
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
+
+ifeq ($(Q),@)
+MAKEFLAGS += --no-print-directory
+endif
+
+_DIRS := $(BUILDDIR)/$(PROJ)
+.PHONY: _make_dirs
+_make_dirs:
+ @mkdir -p $(_DIRS)
+
+$(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+$(BUILDDIR)/$(PROJ)/%.o: %.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+# for the fuzzing tests
+$(BUILDDIR)/$(PROJ)/wpa_supplicant/%.o: $(ROOTDIR)wpa_supplicant/%.c $(CONFIG_FILE) | _make_dirs
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+
+# libraries - they know how to build themselves
+# (lib_phony so we recurse all the time)
+.PHONY: lib_phony
+lib_phony:
+# nothing
+
+$(BUILDDIR)/$(PROJ)/%.a: $(CONFIG_FILE) lib_phony
+ $(Q)$(MAKE) -C $(ROOTDIR)$(dir $(@:$(BUILDDIR)/$(PROJ)/%=%)) OUT=$(abspath $(dir $@))/
+
+BUILDOBJ = $(patsubst %,$(BUILDDIR)/$(PROJ)/%,$(patsubst $(ROOTDIR)%,%,$(1)))
+
+.PHONY: common-clean
+common-clean:
+ $(Q)rm -rf $(ALL) $(BUILDDIR)/$(PROJ)
diff --git a/src/common/Makefile b/src/common/Makefile
index ccb280e..59ba6c5 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -1,13 +1,3 @@
-all: libcommon.a
-
-clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcommon.a
-
-install:
- @echo Nothing to be made.
-
-include ../lib.rules
-
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_SAE
@@ -21,7 +11,4 @@ LIB_OBJS= \
sae.o \
wpa_common.o
-libcommon.a: $(LIB_OBJS)
- $(AR) crT $@ $?
-
--include $(OBJS:%.o=%.d)
+include ../lib.rules
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index fb0cf43..00308d4 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -341,71 +341,71 @@ static int sae_tests(void)
struct wpabuf *buf = NULL;
struct crypto_bignum *mask = NULL;
const u8 pwe_19_x[32] = {
- 0x19, 0xd3, 0x37, 0xc9, 0x30, 0x79, 0x2b, 0x47,
- 0x2b, 0x14, 0x5f, 0xc1, 0x5b, 0x98, 0x64, 0x0a,
- 0x0e, 0x7d, 0x3b, 0xb0, 0x7d, 0xc0, 0xad, 0xee,
- 0x6f, 0xc9, 0xdf, 0x75, 0xde, 0xc2, 0xd6, 0x94
+ 0xc9, 0x30, 0x49, 0xb9, 0xe6, 0x40, 0x00, 0xf8,
+ 0x48, 0x20, 0x16, 0x49, 0xe9, 0x99, 0xf2, 0xb5,
+ 0xc2, 0x2d, 0xea, 0x69, 0xb5, 0x63, 0x2c, 0x9d,
+ 0xf4, 0xd6, 0x33, 0xb8, 0xaa, 0x1f, 0x6c, 0x1e
};
const u8 pwe_19_y[32] = {
- 0xb7, 0x8a, 0x02, 0x39, 0x20, 0x29, 0xe7, 0xf4,
- 0x52, 0x41, 0x3d, 0x35, 0x8c, 0x88, 0xd9, 0x16,
- 0xc8, 0x90, 0xba, 0x40, 0xd9, 0x93, 0xe3, 0x2d,
- 0xd0, 0x0f, 0xfb, 0x58, 0xee, 0x62, 0x74, 0x98
+ 0x73, 0x63, 0x4e, 0x94, 0xb5, 0x3d, 0x82, 0xe7,
+ 0x38, 0x3a, 0x8d, 0x25, 0x81, 0x99, 0xd9, 0xdc,
+ 0x1a, 0x5e, 0xe8, 0x26, 0x9d, 0x06, 0x03, 0x82,
+ 0xcc, 0xbf, 0x33, 0xe6, 0x14, 0xff, 0x59, 0xa0
};
const u8 pwe_15[384] = {
- 0x59, 0x00, 0x9a, 0x32, 0xbb, 0x37, 0x84, 0x60,
- 0x27, 0xeb, 0x70, 0x20, 0x57, 0x34, 0xf1, 0xb4,
- 0xde, 0x1b, 0x48, 0xfc, 0x0e, 0xa5, 0xb8, 0x65,
- 0xb1, 0xa0, 0xd4, 0xb9, 0x42, 0x1d, 0x6d, 0xdf,
- 0x8b, 0x86, 0xeb, 0x4a, 0x2c, 0x2e, 0x38, 0x06,
- 0x52, 0xae, 0x67, 0x39, 0xed, 0x7d, 0x0c, 0xd0,
- 0xea, 0x30, 0x6e, 0x50, 0xe7, 0xb1, 0x8d, 0x91,
- 0xf0, 0x05, 0x1f, 0x16, 0xf5, 0x45, 0xa7, 0x37,
- 0x21, 0x0d, 0x8a, 0x69, 0x9a, 0xd1, 0xf1, 0x8c,
- 0x2b, 0xbb, 0xd8, 0x21, 0xa2, 0x8f, 0xcc, 0xd1,
- 0x35, 0x98, 0x66, 0xf3, 0x3c, 0x03, 0xba, 0x70,
- 0x72, 0x4e, 0xe4, 0x23, 0xb5, 0x2e, 0x96, 0x5f,
- 0xdd, 0xd1, 0xae, 0x71, 0xb1, 0xc1, 0x4b, 0x69,
- 0x4e, 0x60, 0x0a, 0x08, 0x02, 0xa1, 0x6e, 0x80,
- 0x68, 0x0a, 0xe7, 0x97, 0x9f, 0x5b, 0xbf, 0xa8,
- 0x77, 0xda, 0x5b, 0x26, 0x13, 0x0a, 0xab, 0x92,
- 0x79, 0x87, 0xa3, 0x85, 0x78, 0x74, 0xae, 0xae,
- 0x01, 0xf0, 0x31, 0x8a, 0xc3, 0x96, 0xce, 0xaa,
- 0x57, 0xbf, 0xb3, 0x57, 0xce, 0x2d, 0x2d, 0x36,
- 0xda, 0x02, 0x5b, 0x12, 0xeb, 0xff, 0x13, 0x00,
- 0x9e, 0xf7, 0xae, 0xe0, 0x47, 0xa4, 0x5d, 0x0a,
- 0x88, 0x65, 0xbc, 0x66, 0x23, 0x3e, 0xf2, 0xf1,
- 0xa0, 0x64, 0x5c, 0x6b, 0xdc, 0x81, 0xe9, 0x3c,
- 0x46, 0x4f, 0x83, 0xcf, 0x9f, 0x55, 0x33, 0x8f,
- 0xaa, 0x60, 0x4b, 0xd7, 0x21, 0x73, 0x6b, 0xdb,
- 0x26, 0xad, 0x2f, 0xb7, 0xe2, 0x42, 0x56, 0x33,
- 0xdb, 0xd6, 0xb2, 0x3a, 0x7d, 0x75, 0x87, 0xda,
- 0x86, 0xc4, 0xe9, 0x41, 0x8d, 0x63, 0x19, 0x8e,
- 0x8b, 0x17, 0x95, 0xfe, 0x2b, 0x96, 0xa0, 0x38,
- 0xf1, 0xe2, 0x1d, 0x42, 0xa9, 0xe3, 0x8a, 0xa1,
- 0x61, 0x62, 0x10, 0xf8, 0xb3, 0xb2, 0x2c, 0x7b,
- 0xdf, 0xba, 0x74, 0xb2, 0x5b, 0xf6, 0xa9, 0xae,
- 0x1d, 0x21, 0x0d, 0xc0, 0x48, 0x20, 0xfc, 0x28,
- 0xf6, 0x22, 0xd2, 0xf6, 0x9c, 0x71, 0x3f, 0x9f,
- 0x32, 0xd6, 0xbb, 0x9b, 0xd3, 0x87, 0x25, 0xcf,
- 0x62, 0xd1, 0x68, 0xba, 0x55, 0x3b, 0x74, 0x2b,
- 0x1d, 0x5a, 0xe4, 0x94, 0x59, 0x3b, 0x13, 0x21,
- 0x15, 0x87, 0x3b, 0x09, 0x0e, 0xcf, 0x35, 0x60,
- 0x04, 0xa8, 0xde, 0xa1, 0x09, 0xca, 0xb8, 0x35,
- 0x1e, 0x16, 0x61, 0xed, 0xa1, 0x1f, 0x8c, 0x92,
- 0x83, 0xa5, 0x27, 0x92, 0xf2, 0x80, 0xc3, 0xcb,
- 0xdd, 0x3c, 0x0c, 0xf5, 0x8d, 0x69, 0xb3, 0xe4,
- 0xd5, 0x49, 0x4d, 0x62, 0xcb, 0xb8, 0xe3, 0x9f,
- 0x89, 0xb5, 0x57, 0xff, 0xef, 0x12, 0x37, 0x05,
- 0xb6, 0x35, 0xe5, 0xc6, 0xd9, 0x23, 0xe2, 0xeb,
- 0xe4, 0x0d, 0x1a, 0x30, 0x8f, 0x73, 0x70, 0x3a,
- 0xef, 0x5a, 0xd1, 0x8c, 0x18, 0x34, 0x1e, 0xf0,
- 0xb9, 0x08, 0x57, 0xab, 0xcb, 0x5c, 0x87, 0x10
+ 0x69, 0x68, 0x73, 0x65, 0x8f, 0x65, 0x31, 0x42,
+ 0x9f, 0x97, 0x39, 0x6f, 0xb8, 0x5f, 0x89, 0xe1,
+ 0xfc, 0xd2, 0xf6, 0x92, 0x19, 0xa9, 0x0e, 0x82,
+ 0x2f, 0xf7, 0xf4, 0xbc, 0x0b, 0xd8, 0xa7, 0x9f,
+ 0xf0, 0x80, 0x35, 0x31, 0x6f, 0xca, 0xe1, 0xa5,
+ 0x39, 0x77, 0xdc, 0x11, 0x2b, 0x0b, 0xfe, 0x2e,
+ 0x6f, 0x65, 0x6d, 0xc7, 0xd4, 0xa4, 0x5b, 0x08,
+ 0x1f, 0xd9, 0xbb, 0xe2, 0x22, 0x85, 0x31, 0x81,
+ 0x79, 0x70, 0xbe, 0xa1, 0x66, 0x58, 0x4a, 0x09,
+ 0x3c, 0x57, 0x34, 0x3c, 0x9d, 0x57, 0x8f, 0x42,
+ 0x58, 0xd0, 0x39, 0x81, 0xdb, 0x8f, 0x79, 0xa2,
+ 0x1b, 0x01, 0xcd, 0x27, 0xc9, 0xae, 0xcf, 0xcb,
+ 0x9c, 0xdb, 0x1f, 0x84, 0xb8, 0x88, 0x4e, 0x8f,
+ 0x50, 0x66, 0xb4, 0x29, 0x83, 0x1e, 0xb9, 0x89,
+ 0x0c, 0xa5, 0x47, 0x21, 0xba, 0x10, 0xd5, 0xaa,
+ 0x1a, 0x80, 0xce, 0xf1, 0x4c, 0xad, 0x16, 0xda,
+ 0x57, 0xb2, 0x41, 0x8a, 0xbe, 0x4b, 0x8c, 0xb0,
+ 0xb2, 0xeb, 0xf7, 0xa8, 0x0e, 0x3e, 0xcf, 0x22,
+ 0x8f, 0xd8, 0xb6, 0xdb, 0x79, 0x9c, 0x9b, 0x80,
+ 0xaf, 0xd7, 0x14, 0xad, 0x51, 0x82, 0xf4, 0x64,
+ 0xb6, 0x3f, 0x4c, 0x6c, 0xe5, 0x3f, 0xaa, 0x6f,
+ 0xbf, 0x3d, 0xc2, 0x3f, 0x77, 0xfd, 0xcb, 0xe1,
+ 0x9c, 0xe3, 0x1e, 0x8a, 0x0e, 0x97, 0xe2, 0x2b,
+ 0xe2, 0xdd, 0x37, 0x39, 0x88, 0xc2, 0x8e, 0xbe,
+ 0xfa, 0xac, 0x3d, 0x5b, 0x62, 0x2e, 0x1e, 0x74,
+ 0xa0, 0x9a, 0xf8, 0xed, 0xfa, 0xe1, 0xce, 0x9c,
+ 0xab, 0xbb, 0xdc, 0x36, 0xb1, 0x28, 0x46, 0x3c,
+ 0x7e, 0xa8, 0xbd, 0xb9, 0x36, 0x4c, 0x26, 0x75,
+ 0xe0, 0x17, 0x73, 0x1f, 0xe0, 0xfe, 0xf6, 0x49,
+ 0xfa, 0xa0, 0x45, 0xf4, 0x44, 0x05, 0x20, 0x27,
+ 0x25, 0xc2, 0x99, 0xde, 0x27, 0x8b, 0x70, 0xdc,
+ 0x54, 0x60, 0x90, 0x02, 0x1e, 0x29, 0x97, 0x9a,
+ 0xc4, 0xe7, 0xb6, 0xf5, 0x8b, 0xae, 0x7c, 0x34,
+ 0xaa, 0xef, 0x9b, 0xc6, 0x30, 0xf2, 0x80, 0x8d,
+ 0x80, 0x78, 0xc2, 0x55, 0x63, 0xa0, 0xa1, 0x38,
+ 0x70, 0xfb, 0xf4, 0x74, 0x8d, 0xcd, 0x87, 0x90,
+ 0xb4, 0x54, 0xc3, 0x75, 0xdf, 0x10, 0xc5, 0xb6,
+ 0xb2, 0x08, 0x59, 0x61, 0xe6, 0x68, 0xa5, 0x82,
+ 0xf8, 0x8f, 0x47, 0x30, 0x43, 0xb4, 0xdc, 0x31,
+ 0xfc, 0xbc, 0x69, 0xe7, 0xb4, 0x94, 0xb0, 0x6a,
+ 0x60, 0x59, 0x80, 0x2e, 0xd3, 0xa4, 0xe8, 0x97,
+ 0xa2, 0xa3, 0xc9, 0x08, 0x4b, 0x27, 0x6c, 0xc1,
+ 0x37, 0xe8, 0xfc, 0x5c, 0xe2, 0x54, 0x30, 0x3e,
+ 0xf8, 0xfe, 0xa2, 0xfc, 0xbb, 0xbd, 0x88, 0x6c,
+ 0x92, 0xa3, 0x2a, 0x40, 0x7a, 0x2c, 0x22, 0x38,
+ 0x8c, 0x86, 0x86, 0xfe, 0xb9, 0xd4, 0x6b, 0xd6,
+ 0x47, 0x88, 0xa7, 0xf6, 0x8e, 0x0f, 0x14, 0xad,
+ 0x1e, 0xac, 0xcf, 0x33, 0x01, 0x99, 0xc1, 0x62
};
int pt_groups[] = { 19, 20, 21, 25, 26, 28, 29, 30, 15, 0 };
struct sae_pt *pt_info, *pt;
- u8 addr1b[ETH_ALEN] = { 0x3b, 0x36, 0xc2, 0x8b, 0x83, 0x03 };
- u8 addr2b[ETH_ALEN] = { 0x58, 0x36, 0xc0, 0x64, 0x2d, 0x31 };
+ const u8 addr1b[ETH_ALEN] = { 0x00, 0x09, 0x5b, 0x66, 0xec, 0x1e };
+ const u8 addr2b[ETH_ALEN] = { 0x00, 0x0b, 0x6b, 0xd9, 0x02, 0x46 };
os_memset(&sae, 0, sizeof(sae));
buf = wpabuf_alloc(1000);
@@ -434,7 +434,8 @@ static int sae_tests(void)
goto fail;
/* Check that output matches the test vector */
- sae_write_commit(&sae, buf, NULL, pwid);
+ if (sae_write_commit(&sae, buf, NULL, pwid) < 0)
+ goto fail;
wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
if (wpabuf_len(buf) != sizeof(local_commit) ||
@@ -547,6 +548,95 @@ fail:
}
+static int sae_pk_tests(void)
+{
+#ifdef CONFIG_SAE_PK
+ const char *invalid[] = { "a2bc-de3f-ghim-", "a2bcde3fghim", "", NULL };
+ struct {
+ const char *pw;
+ const u8 *val;
+ } valid[] = {
+ { "a2bc-de3f-ghim", (u8 *) "\x06\x82\x21\x93\x65\x31\xd0\xc0" },
+ { "aaaa-aaaa-aaaj", (u8 *) "\x00\x00\x00\x00\x00\x00\x00\x90" },
+ { "7777-7777-777f", (u8 *) "\xff\xff\xff\xff\xff\xff\xfe\x50" },
+ { NULL, NULL }
+ };
+ int i;
+ bool failed;
+
+ for (i = 0; invalid[i]; i++) {
+ if (sae_pk_valid_password(invalid[i])) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Invalid password '%s' not recognized",
+ invalid[i]);
+ return -1;
+ }
+ }
+
+ failed = false;
+ for (i = 0; valid[i].pw; i++) {
+ u8 *res;
+ size_t res_len;
+ char *b32;
+ const char *pw = valid[i].pw;
+ const u8 *val = valid[i].val;
+ size_t pw_len = os_strlen(pw);
+ size_t bits = (pw_len - pw_len / 5) * 5;
+ size_t bytes = (bits + 7) / 8;
+
+ if (!sae_pk_valid_password(pw)) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Valid password '%s' not recognized",
+ pw);
+ failed = true;
+ continue;
+ }
+
+ res = sae_pk_base32_decode(pw, pw_len, &res_len);
+ if (!res) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Failed to decode password '%s'",
+ valid[i].pw);
+ failed = true;
+ continue;
+ }
+ if (res_len != bytes || os_memcmp(val, res, res_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Mismatch for decoded password '%s'",
+ valid[i].pw);
+ wpa_hexdump(MSG_INFO, "SAE-PK: Decoded value",
+ res, res_len);
+ wpa_hexdump(MSG_INFO, "SAE-PK: Expected value",
+ val, bytes);
+ failed = true;
+ }
+ os_free(res);
+
+ b32 = sae_pk_base32_encode(val, bits - 5);
+ if (!b32) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Failed to encode password '%s'",
+ pw);
+ failed = true;
+ continue;
+ }
+ if (os_strcmp(b32, pw) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE-PK: Mismatch for password '%s'", pw);
+ wpa_printf(MSG_INFO, "SAE-PK: Encoded value: '%s'",
+ b32);
+ failed = true;
+ }
+ os_free(b32);
+ }
+
+ return failed ? -1 : 0;
+#else /* CONFIG_SAE_PK */
+ return 0;
+#endif /* CONFIG_SAE_PK */
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -556,6 +646,7 @@ int common_module_tests(void)
if (ieee802_11_parse_tests() < 0 ||
gas_tests() < 0 ||
sae_tests() < 0 ||
+ sae_pk_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/src/common/defs.h b/src/common/defs.h
index 4faf1c8..bbe3120 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -9,15 +9,6 @@
#ifndef DEFS_H
#define DEFS_H
-#ifdef FALSE
-#undef FALSE
-#endif
-#ifdef TRUE
-#undef TRUE
-#endif
-typedef enum { FALSE = 0, TRUE = 1 } Boolean;
-
-
#define WPA_CIPHER_NONE BIT(0)
#define WPA_CIPHER_WEP40 BIT(1)
#define WPA_CIPHER_WEP104 BIT(2)
@@ -82,6 +73,13 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
WPA_KEY_MGMT_FT_FILS_SHA384));
}
+static inline int wpa_key_mgmt_wpa_psk_no_sae(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256));
+}
+
static inline int wpa_key_mgmt_wpa_psk(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK |
@@ -192,8 +190,7 @@ enum wpa_alg {
WPA_ALG_WEP,
WPA_ALG_TKIP,
WPA_ALG_CCMP,
- WPA_ALG_IGTK,
- WPA_ALG_PMK,
+ WPA_ALG_BIP_CMAC_128,
WPA_ALG_GCMP,
WPA_ALG_SMS4,
WPA_ALG_KRK,
@@ -204,6 +201,14 @@ enum wpa_alg {
WPA_ALG_BIP_CMAC_256
};
+static inline int wpa_alg_bip(enum wpa_alg alg)
+{
+ return alg == WPA_ALG_BIP_CMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_256 ||
+ alg == WPA_ALG_BIP_CMAC_256;
+}
+
/**
* enum wpa_states - wpa_supplicant state
*
@@ -416,7 +421,54 @@ enum chan_width {
CHAN_WIDTH_80,
CHAN_WIDTH_80P80,
CHAN_WIDTH_160,
+ CHAN_WIDTH_2160,
+ CHAN_WIDTH_4320,
+ CHAN_WIDTH_6480,
+ CHAN_WIDTH_8640,
CHAN_WIDTH_UNKNOWN
};
+enum key_flag {
+ KEY_FLAG_MODIFY = BIT(0),
+ KEY_FLAG_DEFAULT = BIT(1),
+ KEY_FLAG_RX = BIT(2),
+ KEY_FLAG_TX = BIT(3),
+ KEY_FLAG_GROUP = BIT(4),
+ KEY_FLAG_PAIRWISE = BIT(5),
+ KEY_FLAG_PMK = BIT(6),
+ /* Used flag combinations */
+ KEY_FLAG_RX_TX = KEY_FLAG_RX | KEY_FLAG_TX,
+ KEY_FLAG_GROUP_RX_TX = KEY_FLAG_GROUP | KEY_FLAG_RX_TX,
+ KEY_FLAG_GROUP_RX_TX_DEFAULT = KEY_FLAG_GROUP_RX_TX |
+ KEY_FLAG_DEFAULT,
+ KEY_FLAG_GROUP_RX = KEY_FLAG_GROUP | KEY_FLAG_RX,
+ KEY_FLAG_GROUP_TX_DEFAULT = KEY_FLAG_GROUP | KEY_FLAG_TX |
+ KEY_FLAG_DEFAULT,
+ KEY_FLAG_PAIRWISE_RX_TX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX_TX,
+ KEY_FLAG_PAIRWISE_RX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX,
+ KEY_FLAG_PAIRWISE_RX_TX_MODIFY = KEY_FLAG_PAIRWISE_RX_TX |
+ KEY_FLAG_MODIFY,
+ /* Max allowed flags for each key type */
+ KEY_FLAG_PAIRWISE_MASK = KEY_FLAG_PAIRWISE_RX_TX_MODIFY,
+ KEY_FLAG_GROUP_MASK = KEY_FLAG_GROUP_RX_TX_DEFAULT,
+ KEY_FLAG_PMK_MASK = KEY_FLAG_PMK,
+};
+
+static inline int check_key_flag(enum key_flag key_flag)
+{
+ return !!(!key_flag ||
+ ((key_flag & (KEY_FLAG_PAIRWISE | KEY_FLAG_MODIFY)) &&
+ (key_flag & ~KEY_FLAG_PAIRWISE_MASK)) ||
+ ((key_flag & KEY_FLAG_GROUP) &&
+ (key_flag & ~KEY_FLAG_GROUP_MASK)) ||
+ ((key_flag & KEY_FLAG_PMK) &&
+ (key_flag & ~KEY_FLAG_PMK_MASK)));
+}
+
+enum ptk0_rekey_handling {
+ PTK0_REKEY_ALLOW_ALWAYS,
+ PTK0_REKEY_ALLOW_LOCAL_OK,
+ PTK0_REKEY_ALLOW_NEVER
+};
+
#endif /* DEFS_H */
diff --git a/src/common/dhcp.h b/src/common/dhcp.h
index e38512c..7dc67d5 100644
--- a/src/common/dhcp.h
+++ b/src/common/dhcp.h
@@ -39,7 +39,7 @@ struct dhcp_data {
} STRUCT_PACKED;
struct bootp_pkt {
- struct iphdr iph;
+ struct ip iph;
struct udphdr udph;
u8 op;
u8 htype;
diff --git a/src/common/dpp.c b/src/common/dpp.c
index ab7072c..0bda85f 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -1,51 +1,41 @@
/*
* DPP functionality shared between hostapd and wpa_supplicant
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018-2019, The Linux Foundation
+ * Copyright (c) 2018-2020, 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 <fcntl.h>
#include <openssl/opensslv.h>
#include <openssl/err.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
#include "utils/common.h"
#include "utils/base64.h"
#include "utils/json.h"
-#include "utils/ip_addr.h"
-#include "utils/eloop.h"
#include "common/ieee802_11_common.h"
-#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/gas.h"
+#include "eap_common/eap_defs.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
-#include "crypto/sha384.h"
-#include "crypto/sha512.h"
#include "drivers/driver.h"
#include "dpp.h"
+#include "dpp_i.h"
+static const char * dpp_netrole_str(enum dpp_netrole netrole);
+
#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_DPP2
+int dpp_version_override = 2;
+#else
+int dpp_version_override = 1;
+#endif
enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
-u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-u8 dpp_pkex_ephemeral_key_override[600];
-size_t dpp_pkex_ephemeral_key_override_len = 0;
-u8 dpp_protocol_key_override[600];
-size_t dpp_protocol_key_override_len = 0;
-u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
-size_t dpp_nonce_override_len = 0;
-
-static int dpp_test_gen_invalid_key(struct wpabuf *msg,
- const struct dpp_curve_params *curve);
#endif /* CONFIG_TESTING_OPTIONS */
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
@@ -53,649 +43,19 @@ static int dpp_test_gen_invalid_key(struct wpabuf *msg,
LIBRESSL_VERSION_NUMBER < 0x20700000L)
/* Compatibility wrappers for older versions. */
-static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
-{
- sig->r = r;
- sig->s = s;
- return 1;
-}
-
-
-static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
- const BIGNUM **ps)
-{
- if (pr)
- *pr = sig->r;
- if (ps)
- *ps = sig->s;
-}
-
-#endif
-
-
-struct dpp_connection {
- struct dl_list list;
- struct dpp_controller *ctrl;
- struct dpp_relay_controller *relay;
- struct dpp_global *global;
- struct dpp_authentication *auth;
- int sock;
- u8 mac_addr[ETH_ALEN];
- unsigned int freq;
- u8 msg_len[4];
- size_t msg_len_octets;
- struct wpabuf *msg;
- struct wpabuf *msg_out;
- size_t msg_out_pos;
- unsigned int read_eloop:1;
- unsigned int write_eloop:1;
- unsigned int on_tcp_tx_complete_gas_done:1;
- unsigned int on_tcp_tx_complete_remove:1;
- unsigned int on_tcp_tx_complete_auth_ok:1;
-};
-
-/* Remote Controller */
-struct dpp_relay_controller {
- struct dl_list list;
- struct dpp_global *global;
- u8 pkhash[SHA256_MAC_LEN];
- struct hostapd_ip_addr ipaddr;
- void *cb_ctx;
- void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
- size_t len);
- void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
- int prot, struct wpabuf *buf);
- struct dl_list conn; /* struct dpp_connection */
-};
-
-/* Local Controller */
-struct dpp_controller {
- struct dpp_global *global;
- u8 allowed_roles;
- int qr_mutual;
- int sock;
- struct dl_list conn; /* struct dpp_connection */
- char *configurator_params;
-};
-
-struct dpp_global {
- void *msg_ctx;
- struct dl_list bootstrap; /* struct dpp_bootstrap_info */
- struct dl_list configurator; /* struct dpp_configurator */
#ifdef CONFIG_DPP2
- struct dl_list controllers; /* struct dpp_relay_controller */
- struct dpp_controller *controller;
- struct dl_list tcp_init; /* struct dpp_connection */
- void *cb_ctx;
- int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
-#endif /* CONFIG_DPP2 */
-};
-
-static const struct dpp_curve_params dpp_curves[] = {
- /* The mandatory to support and the default NIST P-256 curve needs to
- * be the first entry on this list. */
- { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
- { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
- { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
- { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
- { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
- { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
- { NULL, 0, 0, 0, 0, NULL, 0, NULL }
-};
-
-
-/* Role-specific elements for PKEX */
-
-/* NIST P-256 */
-static const u8 pkex_init_x_p256[32] = {
- 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
- 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
- 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
- 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
- };
-static const u8 pkex_init_y_p256[32] = {
- 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
- 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
- 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
- 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
- };
-static const u8 pkex_resp_x_p256[32] = {
- 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
- 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
- 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
- 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
-};
-static const u8 pkex_resp_y_p256[32] = {
- 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
- 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
- 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
- 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
-};
-
-/* NIST P-384 */
-static const u8 pkex_init_x_p384[48] = {
- 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
- 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
- 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
- 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
- 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
- 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
-};
-static const u8 pkex_init_y_p384[48] = {
- 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
- 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
- 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
- 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
- 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
- 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
-};
-static const u8 pkex_resp_x_p384[48] = {
- 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
- 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
- 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
- 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
- 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
- 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
-};
-static const u8 pkex_resp_y_p384[48] = {
- 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
- 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
- 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
- 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
- 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
- 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
-};
-
-/* NIST P-521 */
-static const u8 pkex_init_x_p521[66] = {
- 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
- 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
- 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
- 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
- 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
- 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
- 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
- 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
- 0x97, 0x76
-};
-static const u8 pkex_init_y_p521[66] = {
- 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
- 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
- 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
- 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
- 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
- 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
- 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
- 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
- 0x03, 0xa8
-};
-static const u8 pkex_resp_x_p521[66] = {
- 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
- 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
- 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
- 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
- 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
- 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
- 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
- 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
- 0x84, 0xb4
-};
-static const u8 pkex_resp_y_p521[66] = {
- 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
- 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
- 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
- 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
- 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
- 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
- 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
- 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
- 0xce, 0xe1
-};
-
-/* Brainpool P-256r1 */
-static const u8 pkex_init_x_bp_p256r1[32] = {
- 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
- 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
- 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
- 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
-};
-static const u8 pkex_init_y_bp_p256r1[32] = {
- 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
- 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
- 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
- 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
-};
-static const u8 pkex_resp_x_bp_p256r1[32] = {
- 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
- 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
- 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
- 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
-};
-static const u8 pkex_resp_y_bp_p256r1[32] = {
- 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
- 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
- 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
- 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
-};
-
-/* Brainpool P-384r1 */
-static const u8 pkex_init_x_bp_p384r1[48] = {
- 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
- 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
- 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
- 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
- 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
- 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
-};
-static const u8 pkex_init_y_bp_p384r1[48] = {
- 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
- 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
- 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
- 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
- 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
- 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
-};
-static const u8 pkex_resp_x_bp_p384r1[48] = {
- 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
- 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
- 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
- 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
- 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
- 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
-};
-static const u8 pkex_resp_y_bp_p384r1[48] = {
- 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
- 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
- 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
- 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
- 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
- 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
-};
-
-/* Brainpool P-512r1 */
-static const u8 pkex_init_x_bp_p512r1[64] = {
- 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
- 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
- 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
- 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
- 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
- 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
- 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
- 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
-};
-static const u8 pkex_init_y_bp_p512r1[64] = {
- 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
- 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
- 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
- 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
- 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
- 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
- 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
- 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
-};
-static const u8 pkex_resp_x_bp_p512r1[64] = {
- 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
- 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
- 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
- 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
- 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
- 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
- 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
- 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
-};
-static const u8 pkex_resp_y_bp_p512r1[64] = {
- 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
- 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
- 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
- 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
- 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
- 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
- 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
- 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
-};
-
-
-static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
- const EC_POINT *point)
-{
- BIGNUM *x, *y;
- BN_CTX *ctx;
- char *x_str = NULL, *y_str = NULL;
-
- if (!wpa_debug_show_keys)
- return;
-
- ctx = BN_CTX_new();
- x = BN_new();
- y = BN_new();
- if (!ctx || !x || !y ||
- EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
- goto fail;
-
- x_str = BN_bn2hex(x);
- y_str = BN_bn2hex(y);
- if (!x_str || !y_str)
- goto fail;
-
- wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
-
-fail:
- OPENSSL_free(x_str);
- OPENSSL_free(y_str);
- BN_free(x);
- BN_free(y);
- BN_CTX_free(ctx);
-}
-
-
-static int dpp_hash_vector(const struct dpp_curve_params *curve,
- size_t num_elem, const u8 *addr[], const size_t *len,
- u8 *mac)
-{
- if (curve->hash_len == 32)
- return sha256_vector(num_elem, addr, len, mac);
- if (curve->hash_len == 48)
- return sha384_vector(num_elem, addr, len, mac);
- if (curve->hash_len == 64)
- return sha512_vector(num_elem, addr, len, mac);
- return -1;
-}
-
-
-static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
- const char *label, u8 *out, size_t outlen)
-{
- if (hash_len == 32)
- return hmac_sha256_kdf(secret, secret_len, NULL,
- (const u8 *) label, os_strlen(label),
- out, outlen);
- if (hash_len == 48)
- return hmac_sha384_kdf(secret, secret_len, NULL,
- (const u8 *) label, os_strlen(label),
- out, outlen);
- if (hash_len == 64)
- return hmac_sha512_kdf(secret, secret_len, NULL,
- (const u8 *) label, os_strlen(label),
- out, outlen);
- return -1;
-}
-
-
-static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
- size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac)
-{
- if (hash_len == 32)
- return hmac_sha256_vector(key, key_len, num_elem, addr, len,
- mac);
- if (hash_len == 48)
- return hmac_sha384_vector(key, key_len, num_elem, addr, len,
- mac);
- if (hash_len == 64)
- return hmac_sha512_vector(key, key_len, num_elem, addr, len,
- mac);
- return -1;
-}
-
-
-static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
- const u8 *data, size_t data_len, u8 *mac)
-{
- if (hash_len == 32)
- return hmac_sha256(key, key_len, data, data_len, mac);
- if (hash_len == 48)
- return hmac_sha384(key, key_len, data, data_len, mac);
- if (hash_len == 64)
- return hmac_sha512(key, key_len, data, data_len, mac);
- return -1;
-}
-
-
-static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
-{
- int num_bytes, offset;
-
- num_bytes = BN_num_bytes(bn);
- if ((size_t) num_bytes > len)
- return -1;
- offset = len - num_bytes;
- os_memset(pos, 0, offset);
- BN_bn2bin(bn, pos + offset);
- return 0;
-}
-
-
-static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
-{
- int len, res;
- EC_KEY *eckey;
- struct wpabuf *buf;
- unsigned char *pos;
-
- eckey = EVP_PKEY_get1_EC_KEY(pkey);
- if (!eckey)
- return NULL;
- EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
- len = i2o_ECPublicKey(eckey, NULL);
- if (len <= 0) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to determine public key encoding length");
- EC_KEY_free(eckey);
- return NULL;
- }
-
- buf = wpabuf_alloc(len);
- if (!buf) {
- EC_KEY_free(eckey);
- return NULL;
- }
-
- pos = wpabuf_put(buf, len);
- res = i2o_ECPublicKey(eckey, &pos);
- EC_KEY_free(eckey);
- if (res != len) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to encode public key (res=%d/%d)",
- res, len);
- wpabuf_free(buf);
- return NULL;
- }
-
- if (!prefix) {
- /* Remove 0x04 prefix to match DPP definition */
- pos = wpabuf_mhead(buf);
- os_memmove(pos, pos + 1, len - 1);
- buf->used--;
- }
-
- return buf;
-}
-
-
-static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
- const u8 *buf_x, const u8 *buf_y,
- size_t len)
-{
- EC_KEY *eckey = NULL;
- BN_CTX *ctx;
- EC_POINT *point = NULL;
- BIGNUM *x = NULL, *y = NULL;
- EVP_PKEY *pkey = NULL;
-
- ctx = BN_CTX_new();
- if (!ctx) {
- wpa_printf(MSG_ERROR, "DPP: Out of memory");
- return NULL;
- }
-
- point = EC_POINT_new(group);
- x = BN_bin2bn(buf_x, len, NULL);
- y = BN_bin2bn(buf_y, len, NULL);
- if (!point || !x || !y) {
- wpa_printf(MSG_ERROR, "DPP: Out of memory");
- goto fail;
- }
-
- if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
- wpa_printf(MSG_ERROR,
- "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (!EC_POINT_is_on_curve(group, point, ctx) ||
- EC_POINT_is_at_infinity(group, point)) {
- wpa_printf(MSG_ERROR, "DPP: Invalid point");
- goto fail;
- }
- dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
-
- eckey = EC_KEY_new();
- if (!eckey ||
- EC_KEY_set_group(eckey, group) != 1 ||
- EC_KEY_set_public_key(eckey, point) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to set EC_KEY: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
-
- pkey = EVP_PKEY_new();
- if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
- wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
- goto fail;
- }
-
-out:
- BN_free(x);
- BN_free(y);
- EC_KEY_free(eckey);
- EC_POINT_free(point);
- BN_CTX_free(ctx);
- return pkey;
-fail:
- EVP_PKEY_free(pkey);
- pkey = NULL;
- goto out;
-}
-
-
-static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
- const u8 *buf, size_t len)
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
{
- EC_KEY *eckey;
- const EC_GROUP *group;
- EVP_PKEY *pkey = NULL;
-
- if (len & 1)
+ if (pkey->type != EVP_PKEY_EC)
return NULL;
-
- eckey = EVP_PKEY_get1_EC_KEY(group_key);
- if (!eckey) {
- wpa_printf(MSG_ERROR,
- "DPP: Could not get EC_KEY from group_key");
- return NULL;
- }
-
- group = EC_KEY_get0_group(eckey);
- if (group)
- pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
- len / 2);
- else
- wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
-
- EC_KEY_free(eckey);
- return pkey;
+ return pkey->pkey.ec;
}
+#endif /* CONFIG_DPP2 */
-
-static int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
- u8 *secret, size_t *secret_len)
-{
- EVP_PKEY_CTX *ctx;
- int ret = -1;
-
- ERR_clear_error();
- *secret_len = 0;
-
- ctx = EVP_PKEY_CTX_new(own, NULL);
- if (!ctx) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
-
- if (EVP_PKEY_derive_init(ctx) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: EVP_PKEY_derive_set_peet failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
- u8 buf[200];
- int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
-
- /* It looks like OpenSSL can return unexpectedly large buffer
- * need for shared secret from EVP_PKEY_derive(NULL) in some
- * cases. For example, group 19 has shown cases where secret_len
- * is set to 72 even though the actual length ends up being
- * updated to 32 when EVP_PKEY_derive() is called with a buffer
- * for the value. Work around this by trying to fetch the value
- * and continue if it is within supported range even when the
- * initial buffer need is claimed to be larger. */
- wpa_printf(level,
- "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
- (int) *secret_len);
- if (*secret_len > 200)
- goto fail;
- if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
- wpa_printf(MSG_ERROR,
- "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
- (int) *secret_len);
- goto fail;
- }
- wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
- buf, *secret_len);
- os_memcpy(secret, buf, *secret_len);
- forced_memzero(buf, sizeof(buf));
- goto done;
- }
-
- if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
-done:
- ret = 0;
-
-fail:
- EVP_PKEY_CTX_free(ctx);
- return ret;
-}
+#endif
-static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
+void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
{
wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
}
@@ -818,7 +178,10 @@ void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
return;
os_free(info->uri);
os_free(info->info);
+ os_free(info->chan);
+ os_free(info->pk);
EVP_PKEY_free(info->pubkey);
+ str_clear_free(info->configurator_params);
os_free(info);
}
@@ -830,6 +193,8 @@ const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
return "QRCODE";
case DPP_BOOTSTRAP_PKEX:
return "PKEX";
+ case DPP_BOOTSTRAP_NFC_URI:
+ return "NFC-URI";
}
return "??";
}
@@ -880,6 +245,7 @@ int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
wpa_printf(MSG_DEBUG,
"DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
opclass, channel, freq);
+ bi->channels_listed = true;
if (freq < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
@@ -948,67 +314,38 @@ int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
}
-static const struct dpp_curve_params *
-dpp_get_curve_oid(const ASN1_OBJECT *poid)
+int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
{
- ASN1_OBJECT *oid;
- int i;
-
- for (i = 0; dpp_curves[i].name; i++) {
- oid = OBJ_txt2obj(dpp_curves[i].name, 0);
- if (oid && OBJ_cmp(poid, oid) == 0)
- return &dpp_curves[i];
- }
- return NULL;
-}
+#ifdef CONFIG_DPP2
+ if (!version || DPP_VERSION < 2)
+ return 0;
+ if (*version == '1')
+ bi->version = 1;
+ else if (*version == '2')
+ bi->version = 2;
+ else
+ wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
-static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
-{
- int i, tmp;
+ wpa_printf(MSG_DEBUG, "DPP: URI version: %d", bi->version);
+#endif /* CONFIG_DPP2 */
- if (!nid)
- return NULL;
- for (i = 0; dpp_curves[i].name; i++) {
- tmp = OBJ_txt2nid(dpp_curves[i].name);
- if (tmp == nid)
- return &dpp_curves[i];
- }
- return NULL;
+ return 0;
}
static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
{
- const char *end;
u8 *data;
size_t data_len;
- EVP_PKEY *pkey;
- const unsigned char *p;
int res;
- X509_PUBKEY *pub = NULL;
- ASN1_OBJECT *ppkalg;
- const unsigned char *pk;
- int ppklen;
- X509_ALGOR *pa;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20800000L)
- ASN1_OBJECT *pa_oid;
-#else
- const ASN1_OBJECT *pa_oid;
-#endif
- const void *pval;
- int ptype;
- const ASN1_OBJECT *poid;
- char buf[100];
+ const char *end;
end = os_strchr(info, ';');
if (!end)
return -1;
- data = base64_decode((const unsigned char *) info, end - info,
- &data_len);
+ data = base64_decode(info, end - info, &data_len);
if (!data) {
wpa_printf(MSG_DEBUG,
"DPP: Invalid base64 encoding on URI public-key");
@@ -1017,104 +354,9 @@ static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
data, data_len);
- if (sha256_vector(1, (const u8 **) &data, &data_len,
- bi->pubkey_hash) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
- os_free(data);
- return -1;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
- bi->pubkey_hash, SHA256_MAC_LEN);
-
- /* DER encoded ASN.1 SubjectPublicKeyInfo
- *
- * SubjectPublicKeyInfo ::= SEQUENCE {
- * algorithm AlgorithmIdentifier,
- * subjectPublicKey BIT STRING }
- *
- * AlgorithmIdentifier ::= SEQUENCE {
- * algorithm OBJECT IDENTIFIER,
- * parameters ANY DEFINED BY algorithm OPTIONAL }
- *
- * subjectPublicKey = compressed format public key per ANSI X9.63
- * algorithm = ecPublicKey (1.2.840.10045.2.1)
- * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
- * prime256v1 (1.2.840.10045.3.1.7)
- */
-
- p = data;
- pkey = d2i_PUBKEY(NULL, &p, data_len);
+ res = dpp_get_subject_public_key(bi, data, data_len);
os_free(data);
-
- if (!pkey) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
- return -1;
- }
-
- if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
- wpa_printf(MSG_DEBUG,
- "DPP: SubjectPublicKeyInfo does not describe an EC key");
- EVP_PKEY_free(pkey);
- return -1;
- }
-
- res = X509_PUBKEY_set(&pub, pkey);
- if (res != 1) {
- wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
- goto fail;
- }
-
- res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
- if (res != 1) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not extract SubjectPublicKeyInfo parameters");
- goto fail;
- }
- res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
- if (res < 0 || (size_t) res >= sizeof(buf)) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not extract SubjectPublicKeyInfo algorithm");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
- if (os_strcmp(buf, "id-ecPublicKey") != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unsupported SubjectPublicKeyInfo algorithm");
- goto fail;
- }
-
- X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
- if (ptype != V_ASN1_OBJECT) {
- wpa_printf(MSG_DEBUG,
- "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
- goto fail;
- }
- poid = pval;
- res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
- if (res < 0 || (size_t) res >= sizeof(buf)) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
- bi->curve = dpp_get_curve_oid(poid);
- if (!bi->curve) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
- buf);
- goto fail;
- }
-
- wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
-
- X509_PUBKEY_free(pub);
- bi->pubkey = pkey;
- return 0;
-fail:
- X509_PUBKEY_free(pub);
- EVP_PKEY_free(pkey);
- return -1;
+ return res;
}
@@ -1123,6 +365,7 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
const char *pos = uri;
const char *end;
const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
+ const char *version = NULL;
struct dpp_bootstrap_info *bi;
wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
@@ -1153,6 +396,8 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
info = pos + 2;
else if (pos[0] == 'K' && pos[1] == ':' && !pk)
pk = pos + 2;
+ else if (pos[0] == 'V' && pos[1] == ':' && !version)
+ version = pos + 2;
else
wpa_hexdump_ascii(MSG_DEBUG,
"DPP: Ignore unrecognized URI parameter",
@@ -1173,6 +418,7 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
dpp_parse_uri_mac(bi, mac) < 0 ||
dpp_parse_uri_info(bi, info) < 0 ||
+ dpp_parse_uri_version(bi, version) < 0 ||
dpp_parse_uri_pk(bi, pk) < 0) {
dpp_bootstrap_info_free(bi);
bi = NULL;
@@ -1182,486 +428,7 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
}
-struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
-{
- struct dpp_bootstrap_info *bi;
-
- bi = dpp_parse_uri(uri);
- if (bi)
- bi->type = DPP_BOOTSTRAP_QR_CODE;
- return bi;
-}
-
-
-static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
-{
- EC_KEY *eckey;
- BIO *out;
- size_t rlen;
- char *txt;
- int res;
- unsigned char *der = NULL;
- int der_len;
- const EC_GROUP *group;
- const EC_POINT *point;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return;
-
- EVP_PKEY_print_private(out, key, 0, NULL);
- rlen = BIO_ctrl_pending(out);
- txt = os_malloc(rlen + 1);
- if (txt) {
- res = BIO_read(out, txt, rlen);
- if (res > 0) {
- txt[res] = '\0';
- wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
- }
- os_free(txt);
- }
- BIO_free(out);
-
- eckey = EVP_PKEY_get1_EC_KEY(key);
- if (!eckey)
- return;
-
- group = EC_KEY_get0_group(eckey);
- point = EC_KEY_get0_public_key(eckey);
- if (group && point)
- dpp_debug_print_point(title, group, point);
-
- der_len = i2d_ECPrivateKey(eckey, &der);
- if (der_len > 0)
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
- OPENSSL_free(der);
- if (der_len <= 0) {
- der = NULL;
- der_len = i2d_EC_PUBKEY(eckey, &der);
- if (der_len > 0)
- wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
- OPENSSL_free(der);
- }
-
- EC_KEY_free(eckey);
-}
-
-
-static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
-{
- EVP_PKEY_CTX *kctx = NULL;
- EC_KEY *ec_params = NULL;
- EVP_PKEY *params = NULL, *key = NULL;
- int nid;
-
- wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
-
- nid = OBJ_txt2nid(curve->name);
- if (nid == NID_undef) {
- wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
- return NULL;
- }
-
- ec_params = EC_KEY_new_by_curve_name(nid);
- if (!ec_params) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate EC_KEY parameters");
- goto fail;
- }
- EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
- params = EVP_PKEY_new();
- if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate EVP_PKEY parameters");
- goto fail;
- }
-
- kctx = EVP_PKEY_CTX_new(params, NULL);
- if (!kctx ||
- EVP_PKEY_keygen_init(kctx) != 1 ||
- EVP_PKEY_keygen(kctx, &key) != 1) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
- key = NULL;
- goto fail;
- }
-
- if (wpa_debug_show_keys)
- dpp_debug_print_key("Own generated key", key);
-
-fail:
- EC_KEY_free(ec_params);
- EVP_PKEY_free(params);
- EVP_PKEY_CTX_free(kctx);
- return key;
-}
-
-
-static const struct dpp_curve_params *
-dpp_get_curve_name(const char *name)
-{
- int i;
-
- for (i = 0; dpp_curves[i].name; i++) {
- if (os_strcmp(name, dpp_curves[i].name) == 0 ||
- (dpp_curves[i].jwk_crv &&
- os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
- return &dpp_curves[i];
- }
- return NULL;
-}
-
-
-static const struct dpp_curve_params *
-dpp_get_curve_jwk_crv(const char *name)
-{
- int i;
-
- for (i = 0; dpp_curves[i].name; i++) {
- if (dpp_curves[i].jwk_crv &&
- os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
- return &dpp_curves[i];
- }
- return NULL;
-}
-
-
-static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
- const u8 *privkey, size_t privkey_len)
-{
- EVP_PKEY *pkey;
- EC_KEY *eckey;
- const EC_GROUP *group;
- int nid;
-
- pkey = EVP_PKEY_new();
- if (!pkey)
- return NULL;
- eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
- if (!eckey) {
- wpa_printf(MSG_INFO,
- "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- EVP_PKEY_free(pkey);
- return NULL;
- }
- group = EC_KEY_get0_group(eckey);
- if (!group) {
- EC_KEY_free(eckey);
- EVP_PKEY_free(pkey);
- return NULL;
- }
- nid = EC_GROUP_get_curve_name(group);
- *curve = dpp_get_curve_nid(nid);
- if (!*curve) {
- wpa_printf(MSG_INFO,
- "DPP: Unsupported curve (nid=%d) in pre-assigned key",
- nid);
- EC_KEY_free(eckey);
- EVP_PKEY_free(pkey);
- return NULL;
- }
-
- if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
- EC_KEY_free(eckey);
- EVP_PKEY_free(pkey);
- return NULL;
- }
- return pkey;
-}
-
-
-typedef struct {
- /* AlgorithmIdentifier ecPublicKey with optional parameters present
- * as an OID identifying the curve */
- X509_ALGOR *alg;
- /* Compressed format public key per ANSI X9.63 */
- ASN1_BIT_STRING *pub_key;
-} DPP_BOOTSTRAPPING_KEY;
-
-ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
- ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
- ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
-} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
-
-IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
-
-
-static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
-{
- unsigned char *der = NULL;
- int der_len;
- EC_KEY *eckey;
- struct wpabuf *ret = NULL;
- size_t len;
- const EC_GROUP *group;
- const EC_POINT *point;
- BN_CTX *ctx;
- DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
- int nid;
-
- ctx = BN_CTX_new();
- eckey = EVP_PKEY_get1_EC_KEY(key);
- if (!ctx || !eckey)
- goto fail;
-
- group = EC_KEY_get0_group(eckey);
- point = EC_KEY_get0_public_key(eckey);
- if (!group || !point)
- goto fail;
- dpp_debug_print_point("DPP: bootstrap public key", group, point);
- nid = EC_GROUP_get_curve_name(group);
-
- bootstrap = DPP_BOOTSTRAPPING_KEY_new();
- if (!bootstrap ||
- X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
- V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
- goto fail;
-
- len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
- NULL, 0, ctx);
- if (len == 0)
- goto fail;
-
- der = OPENSSL_malloc(len);
- if (!der)
- goto fail;
- len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
- der, len, ctx);
-
- OPENSSL_free(bootstrap->pub_key->data);
- bootstrap->pub_key->data = der;
- der = NULL;
- bootstrap->pub_key->length = len;
- /* No unused bits */
- bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
- bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
-
- der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
- if (der_len <= 0) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to build DER encoded public key");
- goto fail;
- }
-
- ret = wpabuf_alloc_copy(der, der_len);
-fail:
- DPP_BOOTSTRAPPING_KEY_free(bootstrap);
- OPENSSL_free(der);
- EC_KEY_free(eckey);
- BN_CTX_free(ctx);
- return ret;
-}
-
-
-int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
-{
- struct wpabuf *der;
- int res;
- const u8 *addr[1];
- size_t len[1];
-
- der = dpp_bootstrap_key_der(bi->pubkey);
- if (!der)
- return -1;
- wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
- der);
-
- addr[0] = wpabuf_head(der);
- len[0] = wpabuf_len(der);
- res = sha256_vector(1, addr, len, bi->pubkey_hash);
- if (res < 0)
- wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
- else
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
- SHA256_MAC_LEN);
- wpabuf_free(der);
- return res;
-}
-
-
-char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
- const u8 *privkey, size_t privkey_len)
-{
- unsigned char *base64 = NULL;
- char *pos, *end;
- size_t len;
- struct wpabuf *der = NULL;
- const u8 *addr[1];
- int res;
-
- if (!curve) {
- bi->curve = &dpp_curves[0];
- } else {
- bi->curve = dpp_get_curve_name(curve);
- if (!bi->curve) {
- wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
- curve);
- return NULL;
- }
- }
- if (privkey)
- bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
- else
- bi->pubkey = dpp_gen_keypair(bi->curve);
- if (!bi->pubkey)
- goto fail;
- bi->own = 1;
-
- der = dpp_bootstrap_key_der(bi->pubkey);
- if (!der)
- goto fail;
- wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
- der);
-
- addr[0] = wpabuf_head(der);
- len = wpabuf_len(der);
- res = sha256_vector(1, addr, &len, bi->pubkey_hash);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
- SHA256_MAC_LEN);
-
- base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
- wpabuf_free(der);
- der = NULL;
- if (!base64)
- goto fail;
- pos = (char *) base64;
- end = pos + len;
- for (;;) {
- pos = os_strchr(pos, '\n');
- if (!pos)
- break;
- os_memmove(pos, pos + 1, end - pos);
- }
- return (char *) base64;
-fail:
- os_free(base64);
- wpabuf_free(der);
- return NULL;
-}
-
-
-static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
- unsigned int hash_len)
-{
- u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
- const char *info = "first intermediate key";
- int res;
-
- /* k1 = HKDF(<>, "first intermediate key", M.x) */
-
- /* HKDF-Extract(<>, M.x) */
- os_memset(salt, 0, hash_len);
- if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
- prk, hash_len);
-
- /* HKDF-Expand(PRK, info, L) */
- res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
- os_memset(prk, 0, hash_len);
- if (res < 0)
- return -1;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
- k1, hash_len);
- return 0;
-}
-
-
-static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
- unsigned int hash_len)
-{
- u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
- const char *info = "second intermediate key";
- int res;
-
- /* k2 = HKDF(<>, "second intermediate key", N.x) */
-
- /* HKDF-Extract(<>, N.x) */
- os_memset(salt, 0, hash_len);
- res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
- if (res < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
- prk, hash_len);
-
- /* HKDF-Expand(PRK, info, L) */
- res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
- os_memset(prk, 0, hash_len);
- if (res < 0)
- return -1;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
- k2, hash_len);
- return 0;
-}
-
-
-static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
- unsigned int hash_len)
-{
- size_t nonce_len;
- u8 nonces[2 * DPP_MAX_NONCE_LEN];
- const char *info_ke = "DPP Key";
- u8 prk[DPP_MAX_HASH_LEN];
- int res;
- const u8 *addr[3];
- size_t len[3];
- size_t num_elem = 0;
-
- if (!auth->Mx_len || !auth->Nx_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: Mx/Nx not available - cannot derive ke");
- return -1;
- }
-
- /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
-
- /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
- nonce_len = auth->curve->nonce_len;
- os_memcpy(nonces, auth->i_nonce, nonce_len);
- os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
- addr[num_elem] = auth->Mx;
- len[num_elem] = auth->Mx_len;
- num_elem++;
- addr[num_elem] = auth->Nx;
- len[num_elem] = auth->Nx_len;
- num_elem++;
- if (auth->peer_bi && auth->own_bi) {
- if (!auth->Lx_len) {
- wpa_printf(MSG_DEBUG,
- "DPP: Lx not available - cannot derive ke");
- return -1;
- }
- addr[num_elem] = auth->Lx;
- len[num_elem] = auth->secret_len;
- num_elem++;
- }
- res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
- num_elem, addr, len, prk);
- if (res < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
- prk, hash_len);
-
- /* HKDF-Expand(PRK, info, L) */
- res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
- os_memset(prk, 0, hash_len);
- if (res < 0)
- return -1;
-
- wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
- ke, hash_len);
- return 0;
-}
-
-
-static void dpp_build_attr_status(struct wpabuf *msg,
- enum dpp_status_error status)
+void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status)
{
wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
wpabuf_put_le16(msg, DPP_ATTR_STATUS);
@@ -1670,8 +437,7 @@ static void dpp_build_attr_status(struct wpabuf *msg,
}
-static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
- const u8 *hash)
+void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash)
{
if (hash) {
wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
@@ -1682,372 +448,6 @@ static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
}
-static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
- const u8 *hash)
-{
- if (hash) {
- wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
- wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
- wpabuf_put_le16(msg, SHA256_MAC_LEN);
- wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
- }
-}
-
-
-static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
- const struct wpabuf *pi,
- size_t nonce_len,
- const u8 *r_pubkey_hash,
- const u8 *i_pubkey_hash,
- unsigned int neg_freq)
-{
- struct wpabuf *msg;
- u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
- u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
- u8 *pos;
- const u8 *addr[2];
- size_t len[2], siv_len, attr_len;
- u8 *attr_start, *attr_end;
-
- /* Build DPP Authentication Request frame attributes */
- attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
- 4 + sizeof(wrapped_data);
- if (neg_freq > 0)
- attr_len += 4 + 2;
-#ifdef CONFIG_DPP2
- attr_len += 5;
-#endif /* CONFIG_DPP2 */
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
- attr_len += 5;
-#endif /* CONFIG_TESTING_OPTIONS */
- msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
- if (!msg)
- return NULL;
-
- attr_start = wpabuf_put(msg, 0);
-
- /* Responder Bootstrapping Key Hash */
- dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
-
- /* Initiator Bootstrapping Key Hash */
- dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
-
- /* Initiator Protocol Key */
- if (pi) {
- wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
- wpabuf_put_le16(msg, wpabuf_len(pi));
- wpabuf_put_buf(msg, pi);
- }
-
- /* Channel */
- if (neg_freq > 0) {
- u8 op_class, channel;
-
- if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
- &channel) ==
- NUM_HOSTAPD_MODES) {
- wpa_printf(MSG_INFO,
- "DPP: Unsupported negotiation frequency request: %d",
- neg_freq);
- wpabuf_free(msg);
- return NULL;
- }
- wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
- wpabuf_put_le16(msg, 2);
- wpabuf_put_u8(msg, op_class);
- wpabuf_put_u8(msg, channel);
- }
-
-#ifdef CONFIG_DPP2
- /* Protocol Version */
- wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, 2);
-#endif /* CONFIG_DPP2 */
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
- goto skip_wrapped_data;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* Wrapped data ({I-nonce, I-capabilities}k1) */
- pos = clear;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
- goto skip_i_nonce;
- }
- if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
- WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len - 1);
- pos += 2;
- os_memcpy(pos, auth->i_nonce, nonce_len - 1);
- pos += nonce_len - 1;
- goto skip_i_nonce;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* I-nonce */
- WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, auth->i_nonce, nonce_len);
- pos += nonce_len;
-
-#ifdef CONFIG_TESTING_OPTIONS
-skip_i_nonce:
- if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
- goto skip_i_capab;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* I-capabilities */
- WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
- pos += 2;
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- auth->i_capab = auth->allowed_roles;
- *pos++ = auth->i_capab;
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
- wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
- pos[-1] = 0;
- }
-skip_i_capab:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- attr_end = wpabuf_put(msg, 0);
-
- /* OUI, OUI type, Crypto Suite, DPP frame type */
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = 3 + 1 + 1 + 1;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
- /* Attributes before Wrapped Data */
- addr[1] = attr_start;
- len[1] = attr_end - attr_start;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- siv_len = pos - clear;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
- if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
- 2, addr, len, wrapped_data) < 0) {
- wpabuf_free(msg);
- return NULL;
- }
- siv_len += AES_BLOCK_SIZE;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, siv_len);
-
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, siv_len);
- wpabuf_put_data(msg, wrapped_data, siv_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
- dpp_build_attr_status(msg, DPP_STATUS_OK);
- }
-skip_wrapped_data:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- wpa_hexdump_buf(MSG_DEBUG,
- "DPP: Authentication Request frame attributes", msg);
-
- return msg;
-}
-
-
-static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
- enum dpp_status_error status,
- const struct wpabuf *pr,
- size_t nonce_len,
- const u8 *r_pubkey_hash,
- const u8 *i_pubkey_hash,
- const u8 *r_nonce, const u8 *i_nonce,
- const u8 *wrapped_r_auth,
- size_t wrapped_r_auth_len,
- const u8 *siv_key)
-{
- struct wpabuf *msg;
-#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
- 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
- u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
- u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
- const u8 *addr[2];
- size_t len[2], siv_len, attr_len;
- u8 *attr_start, *attr_end, *pos;
-
- auth->waiting_auth_conf = 1;
- auth->auth_resp_tries = 0;
-
- /* Build DPP Authentication Response frame attributes */
- attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
- 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
-#ifdef CONFIG_DPP2
- attr_len += 5;
-#endif /* CONFIG_DPP2 */
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
- attr_len += 5;
-#endif /* CONFIG_TESTING_OPTIONS */
- msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
- if (!msg)
- return NULL;
-
- attr_start = wpabuf_put(msg, 0);
-
- /* DPP Status */
- if (status != 255)
- dpp_build_attr_status(msg, status);
-
- /* Responder Bootstrapping Key Hash */
- dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
-
- /* Initiator Bootstrapping Key Hash (mutual authentication) */
- dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
-
- /* Responder Protocol Key */
- if (pr) {
- wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
- wpabuf_put_le16(msg, wpabuf_len(pr));
- wpabuf_put_buf(msg, pr);
- }
-
-#ifdef CONFIG_DPP2
- /* Protocol Version */
- wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
- wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, 2);
-#endif /* CONFIG_DPP2 */
-
- attr_end = wpabuf_put(msg, 0);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
- goto skip_wrapped_data;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
- pos = clear;
-
- if (r_nonce) {
- /* R-nonce */
- WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, r_nonce, nonce_len);
- pos += nonce_len;
- }
-
- if (i_nonce) {
- /* I-nonce */
- WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
- pos += 2;
- WPA_PUT_LE16(pos, nonce_len);
- pos += 2;
- os_memcpy(pos, i_nonce, nonce_len);
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
- pos[nonce_len / 2] ^= 0x01;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- pos += nonce_len;
- }
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
- goto skip_r_capab;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- /* R-capabilities */
- WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
- pos += 2;
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
- DPP_CAPAB_ENROLLEE;
- *pos++ = auth->r_capab;
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
- wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
- pos[-1] = 0;
- } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
- wpa_printf(MSG_INFO,
- "DPP: TESTING - incompatible R-capabilities");
- if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
- (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
- pos[-1] = 0;
- else
- pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
- DPP_CAPAB_CONFIGURATOR;
- }
-skip_r_capab:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- if (wrapped_r_auth) {
- /* {R-auth}ke */
- WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
- pos += 2;
- WPA_PUT_LE16(pos, wrapped_r_auth_len);
- pos += 2;
- os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
- pos += wrapped_r_auth_len;
- }
-
- /* OUI, OUI type, Crypto Suite, DPP frame type */
- addr[0] = wpabuf_head_u8(msg) + 2;
- len[0] = 3 + 1 + 1 + 1;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
-
- /* Attributes before Wrapped Data */
- addr[1] = attr_start;
- len[1] = attr_end - attr_start;
- wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
-
- siv_len = pos - clear;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
- if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
- 2, addr, len, wrapped_data) < 0) {
- wpabuf_free(msg);
- return NULL;
- }
- siv_len += AES_BLOCK_SIZE;
- wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
- wrapped_data, siv_len);
-
- wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
- wpabuf_put_le16(msg, siv_len);
- wpabuf_put_data(msg, wrapped_data, siv_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
- wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
- dpp_build_attr_status(msg, DPP_STATUS_OK);
- }
-skip_wrapped_data:
-#endif /* CONFIG_TESTING_OPTIONS */
-
- wpa_hexdump_buf(MSG_DEBUG,
- "DPP: Authentication Response frame attributes", msg);
- return msg;
-}
-
-
static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
u16 num_modes, unsigned int freq)
{
@@ -2166,14 +566,23 @@ static int dpp_channel_local_list(struct dpp_authentication *auth,
}
-static int dpp_prepare_channel_list(struct dpp_authentication *auth,
- struct hostapd_hw_modes *own_modes,
- u16 num_modes)
+int dpp_prepare_channel_list(struct dpp_authentication *auth,
+ unsigned int neg_freq,
+ struct hostapd_hw_modes *own_modes, u16 num_modes)
{
int res;
char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
unsigned int i;
+ if (!own_modes) {
+ if (!neg_freq)
+ return -1;
+ auth->num_freq = 1;
+ auth->freq[0] = neg_freq;
+ auth->curr_freq = neg_freq;
+ return 0;
+ }
+
if (auth->peer_bi->num_freq > 0)
res = dpp_channel_intersect(auth, own_modes, num_modes);
else
@@ -2206,183 +615,55 @@ static int dpp_prepare_channel_list(struct dpp_authentication *auth,
}
-static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
+int dpp_gen_uri(struct dpp_bootstrap_info *bi)
{
- struct dpp_bootstrap_info *bi;
- char *pk = NULL;
+ char macstr[ETH_ALEN * 2 + 10];
size_t len;
- if (auth->own_bi)
- return 0; /* already generated */
-
- bi = os_zalloc(sizeof(*bi));
- if (!bi)
- return -1;
- bi->type = DPP_BOOTSTRAP_QR_CODE;
- pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
- if (!pk)
- goto fail;
-
len = 4; /* "DPP:" */
- len += 4 + os_strlen(pk);
+ if (bi->chan)
+ len += 3 + os_strlen(bi->chan); /* C:...; */
+ if (is_zero_ether_addr(bi->mac_addr))
+ macstr[0] = '\0';
+ else
+ os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
+ MAC2STR(bi->mac_addr));
+ len += os_strlen(macstr); /* M:...; */
+ if (bi->info)
+ len += 3 + os_strlen(bi->info); /* I:...; */
+#ifdef CONFIG_DPP2
+ len += 4; /* V:2; */
+#endif /* CONFIG_DPP2 */
+ len += 4 + os_strlen(bi->pk); /* K:...;; */
+
+ os_free(bi->uri);
bi->uri = os_malloc(len + 1);
if (!bi->uri)
- goto fail;
- os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
- wpa_printf(MSG_DEBUG,
- "DPP: Auto-generated own bootstrapping key info: URI %s",
- bi->uri);
-
- auth->tmp_own_bi = auth->own_bi = bi;
-
- os_free(pk);
-
+ return -1;
+ os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%sK:%s;;",
+ bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
+ bi->chan ? ";" : "",
+ macstr,
+ bi->info ? "I:" : "", bi->info ? bi->info : "",
+ bi->info ? ";" : "",
+ DPP_VERSION == 2 ? "V:2;" : "",
+ bi->pk);
return 0;
-fail:
- os_free(pk);
- dpp_bootstrap_info_free(bi);
- return -1;
}
-struct dpp_authentication * dpp_auth_init(void *msg_ctx,
- struct dpp_bootstrap_info *peer_bi,
- struct dpp_bootstrap_info *own_bi,
- u8 dpp_allowed_roles,
- unsigned int neg_freq,
- struct hostapd_hw_modes *own_modes,
- u16 num_modes)
+struct dpp_authentication *
+dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
{
struct dpp_authentication *auth;
- size_t nonce_len;
- size_t secret_len;
- struct wpabuf *pi = NULL;
- const u8 *r_pubkey_hash, *i_pubkey_hash;
-#ifdef CONFIG_TESTING_OPTIONS
- u8 test_hash[SHA256_MAC_LEN];
-#endif /* CONFIG_TESTING_OPTIONS */
auth = os_zalloc(sizeof(*auth));
if (!auth)
return NULL;
+ auth->global = dpp;
auth->msg_ctx = msg_ctx;
- auth->initiator = 1;
- auth->waiting_auth_resp = 1;
- auth->allowed_roles = dpp_allowed_roles;
- auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
- auth->peer_bi = peer_bi;
- auth->own_bi = own_bi;
- auth->curve = peer_bi->curve;
-
- if (dpp_autogen_bootstrap_key(auth) < 0 ||
- dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
- goto fail;
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_nonce_override_len > 0) {
- wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
- nonce_len = dpp_nonce_override_len;
- os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
- } else {
- nonce_len = auth->curve->nonce_len;
- if (random_get_bytes(auth->i_nonce, nonce_len)) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate I-nonce");
- goto fail;
- }
- }
-#else /* CONFIG_TESTING_OPTIONS */
- nonce_len = auth->curve->nonce_len;
- if (random_get_bytes(auth->i_nonce, nonce_len)) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
- goto fail;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_protocol_key_override_len) {
- const struct dpp_curve_params *tmp_curve;
-
- wpa_printf(MSG_INFO,
- "DPP: TESTING - override protocol key");
- auth->own_protocol_key = dpp_set_keypair(
- &