pull in new hostap code

This commit is contained in:
Mathy Vanhoef 2020-12-18 23:24:52 +04:00
commit f988e85c95
637 changed files with 44902 additions and 22716 deletions

31
.gitignore vendored
View File

@ -1,35 +1,8 @@
*.a
*.o
*.d
*.gcno
*.gcda
*.gcov
*.pyc
*~
.config
tests/hwsim/logs
tests/remote/logs
wpaspy/build
wpa_supplicant/eapol_test
wpa_supplicant/nfc_pw_token
wpa_supplicant/preauth_test
wpa_supplicant/wpa_cli
wpa_supplicant/wpa_passphrase
wpa_supplicant/wpa_supplicant
wpa_supplicant/wpa_priv
wpa_supplicant/wpa_gui/Makefile
wpa_supplicant/wpa_gui/wpa_gui
wpa_supplicant/wpa_gui-qt4/Makefile
wpa_supplicant/wpa_gui-qt4/wpa_gui
wpa_supplicant/libwpa_test1
wpa_supplicant/libwpa_test2
hostapd/hostapd
hostapd/hostapd_cli
hostapd/hlr_auc_gw
hostapd/nt_password_hash
mac80211_hwsim/tools/hwsim_test
wlantest/libwlantest.a
wlantest/test_vectors
wlantest/wlantest
wlantest/wlantest_cli
**/parallel-vm.log
tags
build/

View File

@ -322,6 +322,24 @@ fi.w1.wpa_supplicant1.CreateInterface.
</dl>
</li>
<li>
<h3>Roam ( s : addr ) --> nothing</h3>
<p>Initiate a roam to another BSS within the current ESS.</p>
<h4>Possible errors</h4>
<dl>
<dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
<dd>Missing address argument.</dd>
<dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
<dd>Invalid hardware address format.</dd>
<dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
<dd>Target BSS not found.</dd>
<dt>fi.w1.wpa_supplicant1.NotConnected</dt>
<dd>Interface is not connected to any network.</dd>
<dt>fi.w1.wpa_supplicant1.UnknownError</dt>
<dd>Scan processing was not included in the build.</dd>
</dl>
</li>
<li>
<h3>AddBlob ( s : name, ay : data ) --> nothing</h3>
<p>Adds a blob to the interface.</p>
@ -651,7 +669,7 @@ fi.w1.wpa_supplicant1.CreateInterface.
<tr><td>Pairwise</td><td>as</td><td>Possible array elements: "ccmp-256", "gcmp-256", "ccmp", "gcmp", "tkip", "none"</td>
<tr><td>Group</td><td>as</td><td>Possible array elements: "ccmp-256", "gcmp-256", "ccmp", "gcmp", "tkip", "wep104", "wep40"</td>
<tr><td>GroupMgmt</td><td>as</td><td>Possible array elements: "aes-128-cmac", "bip-gmac-128", "bip-gmac-256", "bip-cmac-256"</td>
<tr><td>KeyMgmt</td><td>as</td><td>Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "ieee8021x", "wpa-none", "wps", "none"</td>
<tr><td>KeyMgmt</td><td>as</td><td>Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "sae", "ieee8021x", "wpa-none", "wps", "none"</td>
<tr><td>Protocol</td><td>as</td><td>Possible array elements: "rsn", "wpa"</td>
<tr><td>AuthAlg</td><td>as</td><td>Possible array elements: "open", "shared", "leap"</td>
<tr><td>Scan</td><td>as</td><td>Possible array elements: "active", "passive", "ssid"</td>
@ -891,7 +909,7 @@ fi.w1.wpa_supplicant1.CreateInterface.
<li>
<h3>Hessid - s - (read/write)</h3>
<p>Homogenous ESS identifier</p>
<p>Homogeneous ESS identifier</p>
</li>
<li>
@ -2037,7 +2055,7 @@ scan results.
<tr><td>KeyMgmt</td><td>as</td><td>Key management suite. Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "wpa-eap-suite-b", "wpa-eap-suite-b-192", "wpa-fils-sha256", "wpa-fils-sha384", "wpa-ft-fils-sha256", "wpa-ft-fils-sha384", "sae", "ft-sae", "wpa-none"</td>
<tr><td>Pairwise</td><td>as</td><td>Pairwise cipher suites. Possible array elements: "ccmp", "tkip"</td>
<tr><td>Group</td><td>s</td><td>Group cipher suite. Possible values are: "ccmp", "tkip", "wep104", "wep40"</td>
<tr><td>MgmtGroup</td><td>s</td><td>Mangement frames cipher suite. Possible values are: "aes128cmac"</td>
<tr><td>MgmtGroup</td><td>s</td><td>Management frames cipher suite. Possible values are: "aes128cmac"</td>
</table>
</li>
<li>

View File

@ -278,7 +278,7 @@ TYPEDEF_HIDES_STRUCT = NO
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
# causing a significant performance penality.
# causing a significant performance penalty.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
# a logarithmic scale so increasing the size by one will roughly double the

View File

@ -156,7 +156,7 @@ ap_scan=1:
- wpa_supplicant requests scan with SIOCSIWSCAN
- driver reports scan complete with wireless event SIOCGIWSCAN
- wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
a larget buffer is needed)
a larger buffer is needed)
- wpa_supplicant decides which AP to use based on scan results
- wpa_supplicant configures driver to associate with the selected BSS
(SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ,

View File

@ -283,7 +283,7 @@ service discovery. The user of the P2P module is responsible for
providing P2P specific Service Request TLV(s) for queries and Service
Response TLV(s) for responses.
\subsection p2p_sd_query Quering services of peers
\subsection p2p_sd_query Querying services of peers
Service discovery is implemented by processing pending queries as a
part of the device discovery phase. \ref p2p_sd_request() function is used

View File

@ -1,28 +1,15 @@
ALL=eap_example
all: $(ALL)
ifndef CC
CC=gcc
endif
ifndef RANLIB
RANLIB=ranlib
endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
include ../src/build.rules
CFLAGS += -I.
CFLAGS += -I../src
CFLAGS += -I../src/utils
OBJS_both += ../src/utils/libutils.a
OBJS_both += ../src/crypto/libcrypto.a
OBJS_both += ../src/tls/libtls.a
EAP_LIBS += ../src/utils/libutils.a
EAP_LIBS += ../src/crypto/libcrypto.a
EAP_LIBS += ../src/tls/libtls.a
OBJS_both += ../src/eap_common/eap_peap_common.o
OBJS_both += ../src/eap_common/eap_psk_common.o
@ -95,41 +82,22 @@ OBJS_server += ../src/eap_server/eap_server_tls_common.o
CFLAGS += -DEAP_SERVER
ifndef LDO
LDO=$(CC)
endif
Q=@
E=echo
ifeq ($(V), 1)
Q=
E=true
endif
%.o: %.c
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server)
_OBJS_VAR := OBJS_lib
include ../src/objs.mk
OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o
_OBJS_VAR := OBJS_ex
include ../src/objs.mk
../src/utils/libutils.a:
$(MAKE) -C ../src/utils
../src/crypto/libcrypto.a:
$(MAKE) -C ../src/crypto
../src/tls/libtls.a:
$(MAKE) -C ../src/tls
_OBJS_VAR := EAP_LIBS
include ../src/objs.mk
ifneq ($(CONFIG_SOLIB), yes)
LIBEAP = libeap.a
libeap.a: $(OBJS_lib)
$(AR) crT libeap.a $(OBJS_lib)
libeap.a: $(EAP_LIBS) $(OBJS_lib)
$(AR) crT libeap.a $^
$(RANLIB) libeap.a
else
@ -137,16 +105,15 @@ CFLAGS += -fPIC -DPIC
LDFLAGS += -shared
LIBEAP = libeap.so
libeap.so: $(OBJS_lib)
$(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP)
libeap.so: $(EAP_LIBS) $(OBJS_lib)
$(LDO) $(LDFLAGS) $^ -o $(LIBEAP)
endif
eap_example: $(OBJS_ex) $(LIBEAP)
$(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS)
clean:
$(MAKE) -C ../src clean
rm -f core *~ *.o *.d libeap.a libeap.so $(ALL)
clean: common-clean
rm -f core *~ *.o *.d libeap.a libeap.so
-include $(OBJS:%.o=%.d)

View File

@ -18,16 +18,16 @@ void eap_example_server_rx(const u8 *data, size_t data_len);
struct eap_peer_ctx {
Boolean eapSuccess;
Boolean eapRestart;
Boolean eapFail;
Boolean eapResp;
Boolean eapNoResp;
Boolean eapReq;
Boolean portEnabled;
Boolean altAccept; /* for EAP */
Boolean altReject; /* for EAP */
Boolean eapTriggerStart;
bool eapSuccess;
bool eapRestart;
bool eapFail;
bool eapResp;
bool eapNoResp;
bool eapReq;
bool portEnabled;
bool altAccept; /* for EAP */
bool altReject; /* for EAP */
bool eapTriggerStart;
struct wpabuf *eapReqData; /* for EAP */
@ -48,11 +48,11 @@ static struct eap_peer_config * peer_get_config(void *ctx)
}
static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
static bool peer_get_bool(void *ctx, enum eapol_bool_var variable)
{
struct eap_peer_ctx *peer = ctx;
if (peer == NULL)
return FALSE;
return false;
switch (variable) {
case EAPOL_eapSuccess:
return peer->eapSuccess;
@ -75,12 +75,11 @@ static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
case EAPOL_eapTriggerStart:
return peer->eapTriggerStart;
}
return FALSE;
return false;
}
static void peer_set_bool(void *ctx, enum eapol_bool_var variable,
Boolean value)
static void peer_set_bool(void *ctx, enum eapol_bool_var variable, bool value)
{
struct eap_peer_ctx *peer = ctx;
if (peer == NULL)
@ -319,7 +318,7 @@ int eap_example_peer_init(void)
return -1;
/* Enable "port" to allow authentication */
eap_ctx.portEnabled = TRUE;
eap_ctx.portEnabled = true;
return 0;
}
@ -344,7 +343,7 @@ int eap_example_peer_step(void)
if (eap_ctx.eapResp) {
struct wpabuf *resp;
printf("==> Response\n");
eap_ctx.eapResp = FALSE;
eap_ctx.eapResp = false;
resp = eap_get_eapRespData(eap_ctx.eap);
if (resp) {
/* Send EAP response to the server */
@ -372,7 +371,7 @@ int eap_example_peer_step(void)
void eap_example_peer_rx(const u8 *data, size_t data_len)
{
/* Make received EAP message available to the EAP library */
eap_ctx.eapReq = TRUE;
eap_ctx.eapReq = true;
wpabuf_free(eap_ctx.eapReqData);
eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
}

View File

@ -234,8 +234,8 @@ int eap_example_server_init(void)
eap_ctx.eap_if = eap_get_interface(eap_ctx.eap);
/* Enable "port" and request EAP to start authentication. */
eap_ctx.eap_if->portEnabled = TRUE;
eap_ctx.eap_if->eapRestart = TRUE;
eap_ctx.eap_if->portEnabled = true;
eap_ctx.eap_if->eapRestart = true;
return 0;
}
@ -296,5 +296,5 @@ void eap_example_server_rx(const u8 *data, size_t data_len)
wpabuf_free(eap_ctx.eap_if->eapRespData);
eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
if (eap_ctx.eap_if->eapRespData)
eap_ctx.eap_if->eapResp = TRUE;
eap_ctx.eap_if->eapResp = true;
}

5
hostapd/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.config
hostapd
hostapd_cli
hlr_auc_gw
nt_password_hash

View File

@ -250,8 +250,13 @@ endif
ifdef CONFIG_SAE
L_CFLAGS += -DCONFIG_SAE
OBJS += src/common/sae.c
ifdef CONFIG_SAE_PK
L_CFLAGS += -DCONFIG_SAE_PK
OBJS += src/common/sae_pk.c
endif
NEED_ECC=y
NEED_DH_GROUPS=y
NEED_HMAC_SHA256_KDF=y
NEED_DRAGONFLY=y
endif
@ -281,10 +286,6 @@ L_CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
OBJS += src/ap/wnm_ap.c
endif
ifdef CONFIG_IEEE80211N
L_CFLAGS += -DCONFIG_IEEE80211N
endif
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
@ -313,6 +314,14 @@ OBJS += src/fst/fst_ctrl_iface.c
endif
endif
ifdef CONFIG_WEP
L_CFLAGS += -DCONFIG_WEP
endif
ifdef CONFIG_NO_TKIP
L_CFLAGS += -DCONFIG_NO_TKIP
endif
include $(LOCAL_PATH)/src/drivers/drivers.mk
@ -405,7 +414,7 @@ endif
ifdef CONFIG_EAP_SIM_COMMON
OBJS += src/eap_common/eap_sim_common.c
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
# replaced with another file implementating the interface specified in
# replaced with another file implementing the interface specified in
# eap_sim_db.h.
OBJS += src/eap_server/eap_sim_db.c
NEED_FIPS186_2_PRF=y
@ -532,6 +541,12 @@ endif
ifdef CONFIG_DPP
L_CFLAGS += -DCONFIG_DPP
OBJS += src/common/dpp.c
OBJS += src/common/dpp_auth.c
OBJS += src/common/dpp_backup.c
OBJS += src/common/dpp_crypto.c
OBJS += src/common/dpp_pkex.c
OBJS += src/common/dpp_reconfig.c
OBJS += src/common/dpp_tcp.c
OBJS += src/ap/dpp_hostapd.c
OBJS += src/ap/gas_query_ap.c
NEED_AES_SIV=y
@ -999,9 +1014,7 @@ OBJS += src/ap/hw_features.c
OBJS += src/ap/dfs.c
L_CFLAGS += -DNEED_AP_MLME
endif
ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
endif
ifdef CONFIG_IEEE80211AC
OBJS += src/ap/ieee802_11_vht.c

View File

@ -362,7 +362,7 @@ ChangeLog for hostapd
* RADIUS server functionality
- add minimal RADIUS accounting server support (hostapd-as-server);
this is mainly to enable testing coverage with hwsim scripts
- allow authentication log to be written into SQLite databse
- allow authentication log to be written into SQLite database
- added option for TLS protocol testing of an EAP peer by simulating
various misbehaviors/known attacks
- MAC ACL support for testing purposes
@ -668,7 +668,7 @@ ChangeLog for hostapd
* fixed HT Capabilities IE with nl80211 drivers
* moved generic AP functionality code into src/ap
* WPS: handle Selected Registrar as union of info from all Registrars
* remove obsolte Prism54.org driver wrapper
* remove obsolete Prism54.org driver wrapper
* added internal debugging mechanism with backtrace support and memory
allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
* EAP-FAST server: piggyback Phase 2 start with the end of Phase 1

View File

@ -1,10 +1,7 @@
ifndef CC
CC=gcc
endif
ALL=hostapd hostapd_cli
CONFIG_FILE = .config
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
include ../src/build.rules
ifdef LIBS
# If LIBS is set with some global build system defaults, clone those for
@ -19,6 +16,9 @@ endif
ifndef LIBS_n
LIBS_n := $(LIBS)
endif
ifndef LIBS_s
LIBS_s := $(LIBS)
endif
endif
CFLAGS += $(EXTRA_CFLAGS)
@ -27,8 +27,6 @@ CFLAGS += -I$(abspath ../src/utils)
export BINDIR ?= /usr/local/bin/
-include .config
ifndef CONFIG_NO_GITVER
# Add VERSION_STR postfix for builds from a git repository
ifeq ($(wildcard ../.git),../.git)
@ -122,6 +120,7 @@ LIBS += -lbfd -ldl -liberty -lz
LIBS_c += -lbfd -ldl -liberty -lz
LIBS_h += -lbfd -ldl -liberty -lz
LIBS_n += -lbfd -ldl -liberty -lz
LIBS_s += -lbfd -ldl -liberty -lz
endif
endif
@ -294,8 +293,13 @@ endif
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
OBJS += ../src/common/sae.o
ifdef CONFIG_SAE_PK
CFLAGS += -DCONFIG_SAE_PK
OBJS += ../src/common/sae_pk.o
endif
NEED_ECC=y
NEED_DH_GROUPS=y
NEED_HMAC_SHA256_KDF=y
NEED_AP_MLME=y
NEED_DRAGONFLY=y
endif
@ -331,10 +335,6 @@ CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
OBJS += ../src/ap/wnm_ap.o
endif
ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
endif
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
@ -444,7 +444,7 @@ endif
ifdef CONFIG_EAP_SIM_COMMON
OBJS += ../src/eap_common/eap_sim_common.o
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
# replaced with another file implementating the interface specified in
# replaced with another file implementing the interface specified in
# eap_sim_db.h.
OBJS += ../src/eap_server/eap_sim_db.o
NEED_FIPS186_2_PRF=y
@ -571,6 +571,12 @@ endif
ifdef CONFIG_DPP
CFLAGS += -DCONFIG_DPP
OBJS += ../src/common/dpp.o
OBJS += ../src/common/dpp_auth.o
OBJS += ../src/common/dpp_backup.o
OBJS += ../src/common/dpp_crypto.o
OBJS += ../src/common/dpp_pkex.o
OBJS += ../src/common/dpp_reconfig.o
OBJS += ../src/common/dpp_tcp.o
OBJS += ../src/ap/dpp_hostapd.o
OBJS += ../src/ap/gas_query_ap.o
NEED_AES_SIV=y
@ -697,6 +703,7 @@ LIBS += -lssl
endif
OBJS += ../src/crypto/crypto_openssl.o
HOBJS += ../src/crypto/crypto_openssl.o
SOBJS += ../src/crypto/crypto_openssl.o
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
@ -704,9 +711,11 @@ NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
LIBS_n += -lcrypto
LIBS_s += -lcrypto
ifdef CONFIG_TLS_ADD_DL
LIBS += -ldl
LIBS_h += -ldl
LIBS_s += -ldl
endif
ifndef CONFIG_TLS_DEFAULT_CIPHERS
CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
@ -1155,9 +1164,7 @@ OBJS += ../src/ap/hw_features.o
OBJS += ../src/ap/dfs.o
CFLAGS += -DNEED_AP_MLME
endif
ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
endif
ifdef CONFIG_IEEE80211AC
OBJS += ../src/ap/ieee802_11_vht.o
@ -1244,60 +1251,33 @@ OBJS += ../src/fst/fst_ctrl_iface.o
endif
endif
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
Q=@
E=echo
ifeq ($(V), 1)
Q=
E=true
endif
ifeq ($(QUIET), 1)
Q=@
E=true
ifdef CONFIG_WEP
CFLAGS += -DCONFIG_WEP
endif
ifdef CONFIG_CODE_COVERAGE
%.o: %.c
@$(E) " CC " $<
$(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
else
%.o: %.c
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
ifdef CONFIG_NO_TKIP
CFLAGS += -DCONFIG_NO_TKIP
endif
verify_config:
@if [ ! -r .config ]; then \
echo 'Building hostapd 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
$(DESTDIR)$(BINDIR)/%: %
install -D $(<) $(@)
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL))
../src/drivers/build.hostapd:
@if [ -f ../src/drivers/build.wpa_supplicant ]; then \
$(MAKE) -C ../src/drivers clean; \
fi
@touch ../src/drivers/build.hostapd
_OBJS_VAR := OBJS
include ../src/objs.mk
BCHECK=../src/drivers/build.hostapd
hostapd: $(BCHECK) $(OBJS)
hostapd: $(OBJS)
$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
@$(E) " LD " $@
ifdef CONFIG_WPA_TRACE
OBJS_c += ../src/utils/trace.o
endif
_OBJS_VAR := OBJS_c
include ../src/objs.mk
hostapd_cli: $(OBJS_c)
$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
@$(E) " LD " $@
@ -1332,6 +1312,35 @@ ifeq ($(CONFIG_TLS), linux)
HOBJS += ../src/crypto/crypto_linux.o
endif
SOBJS += sae_pk_gen.o
SOBJS += ../src/utils/common.o
SOBJS += ../src/utils/os_$(CONFIG_OS).o
SOBJS += ../src/utils/base64.o
SOBJS += ../src/utils/wpa_debug.o
SOBJS += ../src/utils/wpabuf.o
ifdef CONFIG_WPA_TRACE
SOBJS += ../src/utils/trace.o
endif
SOBJS += ../src/common/ieee802_11_common.o
SOBJS += ../src/common/sae.o
SOBJS += ../src/common/sae_pk.o
SOBJS += ../src/common/dragonfly.o
SOBJS += $(AESOBJS)
SOBJS += ../src/crypto/sha256-prf.o
SOBJS += ../src/crypto/sha384-prf.o
SOBJS += ../src/crypto/sha512-prf.o
SOBJS += ../src/crypto/dh_groups.o
SOBJS += ../src/crypto/sha256-kdf.o
SOBJS += ../src/crypto/sha384-kdf.o
SOBJS += ../src/crypto/sha512-kdf.o
_OBJS_VAR := NOBJS
include ../src/objs.mk
_OBJS_VAR := HOBJS
include ../src/objs.mk
_OBJS_VAR := SOBJS
include ../src/objs.mk
nt_password_hash: $(NOBJS)
$(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
@$(E) " LD " $@
@ -1340,15 +1349,17 @@ hlr_auc_gw: $(HOBJS)
$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
@$(E) " LD " $@
sae_pk_gen: $(SOBJS)
$(Q)$(CC) $(LDFLAGS) -o sae_pk_gen $(SOBJS) $(LIBS_s)
@$(E) " LD " $@
.PHONY: lcov-html
lcov-html:
lcov -c -d .. > lcov.info
lcov -c -d $(BUILDDIR) > lcov.info
genhtml lcov.info --output-directory lcov-html
clean:
$(MAKE) -C ../src clean
rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
rm -f *.d *.gcno *.gcda *.gcov
clean: common-clean
rm -f core *~ nt_password_hash hlr_auc_gw
rm -f sae_pk_gen
rm -f lcov.info
rm -rf lcov-html
-include $(OBJS:%.o=%.d)

View File

@ -125,9 +125,6 @@ CONFIG_IPV6=y
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
# IEEE 802.11n (High Throughput) support
CONFIG_IEEE80211N=y
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
@ -187,7 +184,7 @@ CONFIG_AP=y
#CONFIG_FST=y
# Multiband Operation support
# These extentions facilitate efficient use of multiple frequency bands
# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
@ -204,3 +201,11 @@ CONFIG_WPA_CLI_EDIT=y
# /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before
# either wpa_supplicant or hostapd are run.
CONFIG_NO_RANDOM_POOL=y
# Wired equivalent privacy (WEP)
# WEP is an obsolete cryptographic data confidentiality algorithm that is not
# considered secure. It should not be used for anything anymore. The
# functionality needed to use WEP is available in the current hostapd
# release under this optional build parameter. This functionality is subject to
# be completely removed in a future release.
CONFIG_WEP=y

View File

@ -14,6 +14,7 @@
#include "utils/common.h"
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "crypto/sha256.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
@ -340,7 +341,7 @@ static int hostapd_config_read_eap_user(const char *fname,
struct hostapd_radius_attr *attr, *a;
attr = hostapd_parse_radius_attr(buf + 19);
if (attr == NULL) {
wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s",
wpa_printf(MSG_ERROR, "Invalid radius_accept_attr: %s",
buf + 19);
user = NULL; /* already in the BSS list */
goto failed;
@ -793,6 +794,7 @@ static int hostapd_config_parse_cipher(int line, const char *value)
}
#ifdef CONFIG_WEP
static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
char *val)
{
@ -843,6 +845,7 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
return 0;
}
#endif /* CONFIG_WEP */
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
@ -940,104 +943,6 @@ static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
}
/* convert floats with one decimal place to value*10 int, i.e.,
* "1.5" will return 15 */
static int hostapd_config_read_int10(const char *value)
{
int i, d;
char *pos;
i = atoi(value);
pos = os_strchr(value, '.');
d = 0;
if (pos) {
pos++;
if (*pos >= '0' && *pos <= '9')
d = *pos - '0';
}
return i * 10 + d;
}
static int valid_cw(int cw)
{
return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
cw == 32767);
}
enum {
IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
};
static int hostapd_config_tx_queue(struct hostapd_config *conf,
const char *name, const char *val)
{
int num;
const char *pos;
struct hostapd_tx_queue_params *queue;
/* skip 'tx_queue_' prefix */
pos = name + 9;
if (os_strncmp(pos, "data", 4) == 0 &&
pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
num = pos[4] - '0';
pos += 6;
} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
os_strncmp(pos, "beacon_", 7) == 0) {
wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
return 0;
} else {
wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
return -1;
}
if (num >= NUM_TX_QUEUES) {
/* for backwards compatibility, do not trigger failure */
wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
return 0;
}
queue = &conf->tx_queue[num];
if (os_strcmp(pos, "aifs") == 0) {
queue->aifs = atoi(val);
if (queue->aifs < 0 || queue->aifs > 255) {
wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
queue->aifs);
return -1;
}
} else if (os_strcmp(pos, "cwmin") == 0) {
queue->cwmin = atoi(val);
if (!valid_cw(queue->cwmin)) {
wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
queue->cwmin);
return -1;
}
} else if (os_strcmp(pos, "cwmax") == 0) {
queue->cwmax = atoi(val);
if (!valid_cw(queue->cwmax)) {
wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
queue->cwmax);
return -1;
}
} else if (os_strcmp(pos, "burst") == 0) {
queue->burst = hostapd_config_read_int10(val);
} else {
wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
return -1;
}
return 0;
}
#ifdef CONFIG_IEEE80211R_AP
static int rkh_derive_key(const char *pos, u8 *key, size_t key_len)
@ -1151,7 +1056,6 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211N
static int hostapd_config_ht_capab(struct hostapd_config *conf,
const char *capab)
{
@ -1171,14 +1075,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
}
if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]"))
conf->secondary_channel = 0;
if (os_strstr(capab, "[SMPS-STATIC]")) {
conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
}
if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
}
if (os_strstr(capab, "[GF]"))
conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
if (os_strstr(capab, "[SHORT-GI-20]"))
@ -1212,7 +1108,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
return 0;
}
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
@ -2298,6 +2193,35 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
pw->vlan_id = atoi(pos2);
}
#ifdef CONFIG_SAE_PK
pos2 = os_strstr(pos, "|pk=");
if (pos2) {
const char *epos;
char *tmp;
if (!end)
end = pos2;
pos2 += 4;
epos = os_strchr(pos2, '|');
if (epos) {
tmp = os_malloc(epos - pos2 + 1);
if (!tmp)
goto fail;
os_memcpy(tmp, pos2, epos - pos2);
tmp[epos - pos2] = '\0';
} else {
tmp = os_strdup(pos2);
if (!tmp)
goto fail;
}
pw->pk = sae_parse_pk(tmp);
str_clear_free(tmp);
if (!pw->pk)
goto fail;
}
#endif /* CONFIG_SAE_PK */
pos2 = os_strstr(pos, "|id=");
if (pos2) {
if (!end)
@ -2320,6 +2244,18 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
pw->password[end - val] = '\0';
}
#ifdef CONFIG_SAE_PK
if (pw->pk &&
#ifdef CONFIG_TESTING_OPTIONS
!bss->sae_pk_password_check_skip &&
#endif /* CONFIG_TESTING_OPTIONS */
!sae_pk_valid_password(pw->password)) {
wpa_printf(MSG_INFO,
"Invalid SAE password for a SAE-PK sae_password entry");
goto fail;
}
#endif /* CONFIG_SAE_PK */
pw->next = bss->sae_passwords;
bss->sae_passwords = pw;
@ -2327,6 +2263,9 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
fail:
str_clear_free(pw->password);
os_free(pw->identifier);
#ifdef CONFIG_SAE_PK
sae_deinit_pk(pw->pk);
#endif /* CONFIG_SAE_PK */
os_free(pw);
return -1;
}
@ -2471,6 +2410,13 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
bss->skip_inactivity_poll = atoi(pos);
} else if (os_strcmp(buf, "country_code") == 0) {
if (pos[0] < 'A' || pos[0] > 'Z' ||
pos[1] < 'A' || pos[1] > 'Z') {
wpa_printf(MSG_ERROR,
"Line %d: Invalid country_code '%s'",
line, pos);
return 1;
}
os_memcpy(conf->country, pos, 2);
} else if (os_strcmp(buf, "country3") == 0) {
conf->country[2] = strtol(pos, NULL, 16);
@ -2613,7 +2559,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "eap_teap_auth") == 0) {
int val = atoi(pos);
if (val < 0 || val > 1) {
if (val < 0 || val > 2) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid eap_teap_auth value",
line);
@ -2674,6 +2620,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "erp_domain") == 0) {
os_free(bss->erp_domain);
bss->erp_domain = os_strdup(pos);
#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
int val = atoi(pos);
@ -2701,6 +2648,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, bss->wep_rekeying_period);
return 1;
}
#endif /* CONFIG_WEP */
} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
bss->eap_reauth_period = atoi(pos);
if (bss->eap_reauth_period < 0) {
@ -2875,6 +2823,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "wpa") == 0) {
bss->wpa = atoi(pos);
} else if (os_strcmp(buf, "extended_key_id") == 0) {
int val = atoi(pos);
if (val < 0 || val > 2) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid extended_key_id=%d; allowed range 0..2",
line, val);
return 1;
}
bss->extended_key_id = val;
} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
bss->wpa_group_rekey = atoi(pos);
bss->wpa_group_rekey_set = 1;
@ -2884,6 +2842,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->wpa_gmk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
bss->wpa_ptk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_deny_ptk0_rekey") == 0) {
bss->wpa_deny_ptk0_rekey = atoi(pos);
if (bss->wpa_deny_ptk0_rekey < 0 ||
bss->wpa_deny_ptk0_rekey > 2) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid wpa_deny_ptk0_rekey=%d; allowed range 0..2",
line, bss->wpa_deny_ptk0_rekey);
return 1;
}
} else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
char *endp;
unsigned long val = strtoul(pos, &endp, 0);
@ -3312,6 +3279,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->ignore_broadcast_ssid = atoi(pos);
} else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
bss->no_probe_resp_if_max_sta = atoi(pos);
#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_default_key") == 0) {
bss->ssid.wep.idx = atoi(pos);
if (bss->ssid.wep.idx > 3) {
@ -3330,6 +3298,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, buf);
return 1;
}
#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_VLAN
} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
bss->ssid.dynamic_vlan = atoi(pos);
@ -3361,7 +3330,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
conf->ap_table_expiration_time = atoi(pos);
} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
if (hostapd_config_tx_queue(conf, buf, pos)) {
if (hostapd_config_tx_queue(conf->tx_queue, buf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item",
line);
return 1;
@ -3408,6 +3377,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
} else if (os_strcmp(buf, "beacon_prot") == 0) {
bss->beacon_prot = atoi(pos);
} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
bss->assoc_sa_query_max_timeout = atoi(pos);
if (bss->assoc_sa_query_max_timeout == 0) {
@ -3428,7 +3399,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
if (bss->ocv && !bss->ieee80211w)
bss->ieee80211w = 1;
#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211N
} else if (os_strcmp(buf, "ieee80211n") == 0) {
conf->ieee80211n = atoi(pos);
} else if (os_strcmp(buf, "ht_capab") == 0) {
@ -3441,7 +3411,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->require_ht = atoi(pos);
} else if (os_strcmp(buf, "obss_interval") == 0) {
conf->obss_interval = atoi(pos);
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
} else if (os_strcmp(buf, "ieee80211ac") == 0) {
conf->ieee80211ac = atoi(pos);
@ -3474,7 +3443,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
conf->he_phy_capab.he_mu_beamformer = atoi(pos);
} else if (os_strcmp(buf, "he_bss_color") == 0) {
conf->he_op.he_bss_color = atoi(pos);
conf->he_op.he_bss_color = atoi(pos) & 0x3f;
conf->he_op.he_bss_color_disabled = 0;
} else if (os_strcmp(buf, "he_bss_color_partial") == 0) {
conf->he_op.he_bss_color_partial = atoi(pos);
} else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
conf->he_op.he_default_pe_duration = atoi(pos);
} else if (os_strcmp(buf, "he_twt_required") == 0) {
@ -4165,18 +4137,53 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->own_ie_override = tmp;
} else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
bss->sae_reflection_attack = atoi(pos);
} else if (os_strcmp(buf, "sae_commit_status") == 0) {
bss->sae_commit_status = atoi(pos);
} else if (os_strcmp(buf, "sae_pk_omit") == 0) {
bss->sae_pk_omit = atoi(pos);
} else if (os_strcmp(buf, "sae_pk_password_check_skip") == 0) {
bss->sae_pk_password_check_skip = atoi(pos);
} else if (os_strcmp(buf, "sae_commit_override") == 0) {
wpabuf_free(bss->sae_commit_override);
bss->sae_commit_override = wpabuf_parse_bin(pos);
} else if (os_strcmp(buf, "rsne_override_eapol") == 0) {
wpabuf_free(bss->rsne_override_eapol);
bss->rsne_override_eapol = wpabuf_parse_bin(pos);
} else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) {
wpabuf_free(bss->rsnxe_override_eapol);
bss->rsnxe_override_eapol = wpabuf_parse_bin(pos);
} else if (os_strcmp(buf, "rsne_override_ft") == 0) {
wpabuf_free(bss->rsne_override_ft);
bss->rsne_override_ft = wpabuf_parse_bin(pos);
} else if (os_strcmp(buf, "rsnxe_override_ft") == 0) {
wpabuf_free(bss->rsnxe_override_ft);
bss->rsnxe_override_ft = wpabuf_parse_bin(pos);
} else if (os_strcmp(buf, "gtk_rsc_override") == 0) {
wpabuf_free(bss->gtk_rsc_override);
bss->gtk_rsc_override = wpabuf_parse_bin(pos);
} else if (os_strcmp(buf, "igtk_rsc_override") == 0) {
wpabuf_free(bss->igtk_rsc_override);
bss->igtk_rsc_override = wpabuf_parse_bin(pos);
} else if (os_strcmp(buf, "no_beacon_rsnxe") == 0) {
bss->no_beacon_rsnxe = atoi(pos);
} else if (os_strcmp(buf, "skip_prune_assoc") == 0) {
bss->skip_prune_assoc = atoi(pos);
} else if (os_strcmp(buf, "ft_rsnxe_used") == 0) {
bss->ft_rsnxe_used = atoi(pos);
} else if (os_strcmp(buf, "oci_freq_override_eapol_m3") == 0) {
bss->oci_freq_override_eapol_m3 = atoi(pos);
} else if (os_strcmp(buf, "oci_freq_override_eapol_g1") == 0) {
bss->oci_freq_override_eapol_g1 = atoi(pos);
} else if (os_strcmp(buf, "oci_freq_override_saquery_req") == 0) {
bss->oci_freq_override_saquery_req = atoi(pos);
} else if (os_strcmp(buf, "oci_freq_override_saquery_resp") == 0) {
bss->oci_freq_override_saquery_resp = atoi(pos);
} else if (os_strcmp(buf, "oci_freq_override_ft_assoc") == 0) {
bss->oci_freq_override_ft_assoc = atoi(pos);
} else if (os_strcmp(buf, "oci_freq_override_fils_assoc") == 0) {
bss->oci_freq_override_fils_assoc = atoi(pos);
} else if (os_strcmp(buf, "oci_freq_override_wnm_sleep") == 0) {
bss->oci_freq_override_wnm_sleep = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_SAE
} else if (os_strcmp(buf, "sae_password") == 0) {
@ -4379,6 +4386,18 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "dpp_controller") == 0) {
if (hostapd_dpp_controller_parse(bss, pos))
return 1;
} else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) {
bss->dpp_configurator_connectivity = atoi(pos);
} else if (os_strcmp(buf, "dpp_pfs") == 0) {
int val = atoi(pos);
if (val < 0 || val > 2) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid dpp_pfs value '%s'",
line, pos);
return -1;
}
bss->dpp_pfs = val;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_OWE
@ -4431,8 +4450,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->rssi_reject_assoc_rssi = atoi(pos);
} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
conf->rssi_reject_assoc_timeout = atoi(pos);
} else if (os_strcmp(buf, "rssi_ignore_probe_request") == 0) {
conf->rssi_ignore_probe_request = atoi(pos);
} else if (os_strcmp(buf, "pbss") == 0) {
bss->pbss = atoi(pos);
} else if (os_strcmp(buf, "transition_disable") == 0) {
bss->transition_disable = strtol(pos, NULL, 16);
#ifdef CONFIG_AIRTIME_POLICY
} else if (os_strcmp(buf, "airtime_mode") == 0) {
int val = atoi(pos);
@ -4548,6 +4571,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
bss->mka_psk_set |= MKA_PSK_SET_CKN;
#endif /* CONFIG_MACSEC */
} else if (os_strcmp(buf, "disable_11n") == 0) {
bss->disable_11n = !!atoi(pos);
} else if (os_strcmp(buf, "disable_11ac") == 0) {
bss->disable_11ac = !!atoi(pos);
} else if (os_strcmp(buf, "disable_11ax") == 0) {
bss->disable_11ax = !!atoi(pos);
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",

View File

@ -49,6 +49,7 @@
#include "ap/ieee802_1x.h"
#include "ap/wpa_auth.h"
#include "ap/wpa_auth_i.h"
#include "ap/pmksa_cache_auth.h"
#include "ap/ieee802_11.h"
#include "ap/sta_info.h"
#include "ap/wps_hostapd.h"
@ -61,6 +62,7 @@
#include "ap/neighbor_db.h"
#include "ap/rrm.h"
#include "ap/dpp_hostapd.h"
#include "ap/dfs.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "fst/fst_ctrl_iface.h"
@ -71,9 +73,6 @@
#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
#ifdef CONFIG_CTRL_IFACE_UDP
#define COOKIE_LEN 8
static unsigned char cookie[COOKIE_LEN];
static unsigned char gcookie[COOKIE_LEN];
#define HOSTAPD_CTRL_IFACE_PORT 8877
#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
@ -1294,6 +1293,22 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
pos += ret;
}
if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
hapd->conf->wpa_deny_ptk0_rekey);
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
hapd->conf->extended_key_id);
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
return pos - buf;
}
@ -1336,21 +1351,29 @@ static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
const char *band)
const char *bands)
{
union wpa_event_data event;
enum set_band setband;
u32 setband_mask = WPA_SETBAND_AUTO;
if (os_strcmp(band, "AUTO") == 0)
setband = WPA_SETBAND_AUTO;
else if (os_strcmp(band, "5G") == 0)
setband = WPA_SETBAND_5G;
else if (os_strcmp(band, "2G") == 0)
setband = WPA_SETBAND_2G;
else
/*
* For example:
* SET setband 2G,6G
* SET setband 5G
* SET setband AUTO
*/
if (!os_strstr(bands, "AUTO")) {
if (os_strstr(bands, "5G"))
setband_mask |= WPA_SETBAND_5G;
if (os_strstr(bands, "6G"))
setband_mask |= WPA_SETBAND_6G;
if (os_strstr(bands, "2G"))
setband_mask |= WPA_SETBAND_2G;
if (setband_mask == WPA_SETBAND_AUTO)
return -1;
}
if (hostapd_drv_set_band(hapd, setband) == 0) {
if (hostapd_drv_set_band(hapd, setband_mask) == 0) {
os_memset(&event, 0, sizeof(event));
event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
@ -1418,6 +1441,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_test") == 0) {
dpp_test = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
dpp_version_override = atoi(value);
#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO
@ -1466,7 +1491,32 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
os_strcmp(cmd, "sae_pwe") == 0) {
if (hapd->started)
hostapd_setup_sae_pt(hapd->conf);
} else if (os_strcasecmp(cmd, "transition_disable") == 0) {
wpa_auth_set_transition_disable(hapd->wpa_auth,
hapd->conf->transition_disable);
}
#ifdef CONFIG_TESTING_OPTIONS
if (os_strcmp(cmd, "ft_rsnxe_used") == 0)
wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth,
hapd->conf->ft_rsnxe_used);
else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0)
wpa_auth_set_ocv_override_freq(
hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
atoi(value));
else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0)
wpa_auth_set_ocv_override_freq(
hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
atoi(value));
else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0)
wpa_auth_set_ocv_override_freq(
hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
atoi(value));
else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0)
wpa_auth_set_ocv_override_freq(
hapd->wpa_auth,
WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value));
#endif /* CONFIG_TESTING_OPTIONS */
}
return ret;
@ -1884,7 +1934,7 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
if (ip.ip_hl != 5 || ip.ip_v != 4 ||
ntohs(ip.ip_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore unexpect IP header");
"test data: RX - ignore unexpected IP header");
return;
}
@ -2147,6 +2197,32 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
if (hwaddr_aton(cmd, addr))
return -1;
if (is_broadcast_ether_addr(addr) && os_strstr(cmd, " BIGTK")) {
if (hapd->last_bigtk_alg == WPA_ALG_NONE)
return -1;
wpa_printf(MSG_INFO, "TESTING: Reset BIPN for BIGTK");
/* First, use a zero key to avoid any possible duplicate key
* avoidance in the driver. */
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_bigtk_alg,
broadcast_ether_addr,
hapd->last_bigtk_key_idx, 0, 1, NULL, 0,
zero, hapd->last_bigtk_len,
KEY_FLAG_GROUP_TX_DEFAULT) < 0)
return -1;
/* Set the previously configured key to reset its TSC */
return hostapd_drv_set_key(hapd->conf->iface, hapd,
hapd->last_bigtk_alg,
broadcast_ether_addr,
hapd->last_bigtk_key_idx, 0, 1, NULL,
0, hapd->last_bigtk,
hapd->last_bigtk_len,
KEY_FLAG_GROUP_TX_DEFAULT);
}
if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
if (hapd->last_igtk_alg == WPA_ALG_NONE)
return -1;
@ -2412,6 +2488,19 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
}
static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr,
char *buf, size_t buflen)
{
struct rsn_pmksa_cache_entry *pmksa;
pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, addr, NULL);
if (!pmksa)
return -1;
return wpa_snprintf_hex(buf, buflen, pmksa->pmk, pmksa->pmk_len);
}
static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
char *buf, size_t buflen)
{
@ -2427,13 +2516,13 @@ static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
if (!sta || !sta->wpa_sm) {
wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
MAC2STR(addr));
return -1;
return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
}
pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
if (!pmk) {
if (!pmk || !pmk_len) {
wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
MAC2STR(addr));
return -1;
return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
}
return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
@ -2501,18 +2590,175 @@ static int hostapd_get_channel(struct hostapd_data *hapd, char *buf, size_t buf
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef NEED_AP_MLME
static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params)
{
switch (params->bandwidth) {
case 0:
/* bandwidth not specified: use 20 MHz by default */
/* fall-through */
case 20:
if (params->center_freq1 &&
params->center_freq1 != params->freq)
return -1;
if (params->center_freq2 || params->sec_channel_offset)
return -1;
break;
case 40:
if (params->center_freq2 || !params->sec_channel_offset)
return -1;
if (!params->center_freq1)
break;
switch (params->sec_channel_offset) {
case 1:
if (params->freq + 10 != params->center_freq1)
return -1;
break;
case -1:
if (params->freq - 10 != params->center_freq1)
return -1;
break;
default:
return -1;
}
break;
case 80:
if (!params->center_freq1 || !params->sec_channel_offset)
return 1;
switch (params->sec_channel_offset) {
case 1:
if (params->freq - 10 != params->center_freq1 &&
params->freq + 30 != params->center_freq1)
return 1;
break;
case -1:
if (params->freq + 10 != params->center_freq1 &&
params->freq - 30 != params->center_freq1)
return -1;
break;
default:
return -1;
}
/* Adjacent and overlapped are not allowed for 80+80 */
if (params->center_freq2 &&
params->center_freq1 - params->center_freq2 <= 80 &&
params->center_freq2 - params->center_freq1 <= 80)
return 1;
break;
case 160:
if (!params->center_freq1 || params->center_freq2 ||
!params->sec_channel_offset)
return -1;
switch (params->sec_channel_offset) {
case 1:
if (params->freq + 70 != params->center_freq1 &&
params->freq + 30 != params->center_freq1 &&
params->freq - 10 != params->center_freq1 &&
params->freq - 50 != params->center_freq1)
return -1;
break;
case -1:
if (params->freq + 50 != params->center_freq1 &&
params->freq + 10 != params->center_freq1 &&
params->freq - 30 != params->center_freq1 &&
params->freq - 70 != params->center_freq1)
return -1;
break;
default:
return -1;
}
break;
default:
return -1;
}
return 0;
}
#endif /* NEED_AP_MLME */
static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
char *pos)
{
#ifdef NEED_AP_MLME
struct csa_settings settings;
int ret;
int dfs_range = 0;
unsigned int i;
int bandwidth;
u8 chan;
ret = hostapd_parse_csa_settings(pos, &settings);
if (ret)
return ret;
ret = hostapd_ctrl_check_freq_params(&settings.freq_params);
if (ret) {
wpa_printf(MSG_INFO,
"chanswitch: invalid frequency settings provided");
return ret;
}
switch (settings.freq_params.bandwidth) {
case 40:
bandwidth = CHAN_WIDTH_40;
break;
case 80:
if (settings.freq_params.center_freq2)
bandwidth = CHAN_WIDTH_80P80;
else
bandwidth = CHAN_WIDTH_80;
break;
case 160:
bandwidth = CHAN_WIDTH_160;
break;
default:
bandwidth = CHAN_WIDTH_20;
break;
}
if (settings.freq_params.center_freq1)
dfs_range += hostapd_is_dfs_overlap(
iface, bandwidth, settings.freq_params.center_freq1);
else
dfs_range += hostapd_is_dfs_overlap(
iface, bandwidth, settings.freq_params.freq);
if (settings.freq_params.center_freq2)
dfs_range += hostapd_is_dfs_overlap(
iface, bandwidth, settings.freq_params.center_freq2);
if (dfs_range) {
ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
if (ret == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_ERROR,
"Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
settings.freq_params.freq,
settings.freq_params.sec_channel_offset,
settings.freq_params.bandwidth);
return -1;
}
settings.freq_params.channel = chan;
wpa_printf(MSG_DEBUG,
"DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
settings.freq_params.channel,
settings.freq_params.freq,
settings.freq_params.sec_channel_offset,
settings.freq_params.bandwidth,
settings.freq_params.center_freq1);
/* Perform CAC and switch channel */
hostapd_switch_channel_fallback(iface, &settings.freq_params);
return 0;
}
for (i = 0; i < iface->num_bss; i++) {
/* Save CHAN_SWITCH VHT config */
@ -2551,13 +2797,17 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
char *buf, size_t buflen)
{
int ret;
char *pos;
char *pos, *temp = NULL;
u8 *data = NULL;
unsigned int vendor_id, subcmd;
enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
struct wpabuf *reply;
size_t data_len = 0;
/* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
/**
* cmd: <vendor id> <subcommand id> [<hex formatted data>]
* [nested=<0|1>]
*/
vendor_id = strtoul(cmd, &pos, 16);
if (!isblank((unsigned char) *pos))
return -EINVAL;
@ -2567,7 +2817,9 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
if (*pos != '\0') {
if (!isblank((unsigned char) *pos++))
return -EINVAL;
data_len = os_strlen(pos);
temp = os_strchr(pos, ' ');
data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
}
if (data_len) {
@ -2584,6 +2836,11 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
}
}
pos = os_strstr(cmd, "nested=");
if (pos)
nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED :
NESTED_ATTR_NOT_USED;
reply = wpabuf_alloc((buflen - 1) / 2);
if (!reply) {
os_free(data);
@ -2591,7 +2848,7 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
}
ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
reply);
nested_attr_flag, reply);
if (ret == 0)
ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
@ -3012,6 +3269,34 @@ static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
}
static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf,
size_t buflen)
{
int ret, i;
char *pos, *end;
ret = os_snprintf(buf, buflen, "%016llX:\n",
(long long unsigned) iface->drv_flags2);
if (os_snprintf_error(buflen, ret))
return -1;
pos = buf + ret;
end = buf + buflen;
for (i = 0; i < 64; i++) {
if (iface->drv_flags2 & (1LLU << i)) {
ret = os_snprintf(pos, end - pos, "%s\n",
driver_flag2_to_string(1LLU << i));
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
}
return pos - buf;
}
static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
const char *txtaddr)
{
@ -3443,6 +3728,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
reply_size);
} else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
reply_len = hostapd_ctrl_driver_flags2(hapd->iface, reply,
reply_size);
} else if (os_strcmp(buf, "TERMINATE") == 0) {
eloop_terminate();
} else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
@ -3551,6 +3839,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
atoi(buf + 19),
reply, reply_size);
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
if (dpp_bootstrap_set(hapd->iface->interfaces->dpp,
atoi(buf + 18),
os_strchr(buf + 18, ' ')) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
reply_len = -1;
@ -3594,6 +3887,21 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
reply_len = -1;
#ifdef CONFIG_DPP2
} else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
if (hostapd_dpp_controller_start(hapd, buf + 20) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
if (hostapd_dpp_controller_start(hapd, NULL) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
dpp_controller_stop(hapd->iface->interfaces->dpp);
} else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
if (hostapd_dpp_chirp(hapd, buf + 9) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
hostapd_dpp_chirp_stop(hapd);
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef RADIUS_SERVER
} else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
@ -3642,7 +3950,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
int reply_len;
int level = MSG_DEBUG;
#ifdef CONFIG_CTRL_IFACE_UDP
unsigned char lcookie[COOKIE_LEN];
unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@ -3667,28 +3975,30 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
#ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7);
wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
cookie, COOKIE_LEN);
reply_len = 7 + 2 * COOKIE_LEN;
wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
hapd->ctrl_iface_cookie,
CTRL_IFACE_COOKIE_LEN);
reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto done;
}
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request");
os_free(reply);
return;
}
if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
if (os_memcmp(hapd->ctrl_iface_cookie, lcookie,
CTRL_IFACE_COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request");
os_free(reply);
return;
}
pos = buf + 7 + 2 * COOKIE_LEN;
pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*pos == ' ')
pos++;
#endif /* CONFIG_CTRL_IFACE_UDP */
@ -3777,7 +4087,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
dl_list_init(&hapd->ctrl_dst);
hapd->ctrl_sock = -1;
os_get_random(cookie, COOKIE_LEN);
os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE;
@ -4091,6 +4401,11 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
#ifdef CONFIG_TESTING_OPTIONS
#ifdef CONFIG_DPP
dpp_test = DPP_TEST_DISABLED;
#ifdef CONFIG_DPP2
dpp_version_override = 2;
#else /* CONFIG_DPP2 */
dpp_version_override = 1;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
@ -4356,7 +4671,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
void *interfaces = eloop_ctx;
struct hapd_interfaces *interfaces = eloop_ctx;
char buffer[256], *buf = buffer;
int res;
struct sockaddr_storage from;
@ -4365,7 +4680,7 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
int reply_len;
const int reply_size = 4096;
#ifdef CONFIG_CTRL_IFACE_UDP
unsigned char lcookie[COOKIE_LEN];
unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
@ -4394,28 +4709,30 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
#ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7);
wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
gcookie, COOKIE_LEN);
reply_len = 7 + 2 * COOKIE_LEN;
wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
interfaces->ctrl_iface_cookie,
CTRL_IFACE_COOKIE_LEN);
reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto send_reply;
}
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request");
os_free(reply);
return;
}
if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie,
CTRL_IFACE_COOKIE_LEN) != 0) {
wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request");
os_free(reply);
return;
}
buf += 7 + 2 * COOKIE_LEN;
buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*buf == ' ')
buf++;
#endif /* CONFIG_CTRL_IFACE_UDP */
@ -4559,7 +4876,7 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
}
}
os_get_random(gcookie, COOKIE_LEN);
os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE;
@ -4802,13 +5119,8 @@ static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst,
return;
idx = 0;
if (ifname) {
#ifdef CONFIG_CTRL_IFACE_UDP
io[idx].iov_base = "IFACE=";
io[idx].iov_len = 6;
#else /* CONFIG_CTRL_IFACE_UDP */
io[idx].iov_base = "IFNAME=";
io[idx].iov_len = 7;
#endif /* CONFIG_CTRL_IFACE_UDP */
idx++;
io[idx].iov_base = (char *) ifname;
io[idx].iov_len = os_strlen(ifname);

View File

@ -148,9 +148,6 @@ CONFIG_IEEE80211R=y
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
# IEEE 802.11n (High Throughput) support
CONFIG_IEEE80211N=y
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
#CONFIG_WNM=y
@ -354,7 +351,7 @@ CONFIG_INTERWORKING=y
#CONFIG_ACS=y
# Multiband Operation support
# These extentions facilitate efficient use of multiple frequency bands
# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
@ -384,6 +381,19 @@ CONFIG_INTERWORKING=y
# parameter. See that parameter in hostapd.conf for more details.
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
CONFIG_TESTING_OPTIONS=y
# Wired equivalent privacy (WEP)
# WEP is an obsolete cryptographic data confidentiality algorithm that is not
# considered secure. It should not be used for anything anymore. The
# functionality needed to use WEP is available in the current hostapd
# release under this optional build parameter. This functionality is subject to
# be completely removed in a future release.
CONFIG_WEP=y
CONFIG_SAE=y
# Remove all TKIP functionality
# TKIP is an old cryptographic data confidentiality algorithm that is not
# considered secure. It should not be used anymore. For now, the default hostapd
# build includes this to allow mixed mode WPA+WPA2 networks to be enabled, but
# that functionality is subject to be removed in the future.
#CONFIG_NO_TKIP=y
CONFIG_TESTING_OPTIONS=y

View File

@ -210,7 +210,7 @@ channel=1
# Frequency list can be provided as range using hyphen ('-') or individual
# frequencies can be specified by comma (',') separated values
# Default: all frequencies allowed in selected hw_mode
#freqlist=2437,5945,5965
#freqlist=2437,5955,5975
#freqlist=2437,5985-6105
# Exclude DFS channels from ACS
@ -580,6 +580,9 @@ wmm_ac_vo_acm=0
# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
ieee80211n=1
# disable_11n: Boolean (0/1) to disable HT for a specific BSS
#disable_11n=0
# ht_capab: HT capabilities (list of flags)
# LDPC coding capability: [LDPC] = supported
# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
@ -598,8 +601,6 @@ ieee80211n=1
# channels if needed or creation of 40 MHz channel maybe rejected based
# on overlapping BSSes. These changes are done automatically when hostapd
# is setting up the 40 MHz channel.
# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
# (SMPS disabled if neither is set)
# HT-greenfield: [GF] (disabled if not set)
# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
@ -634,6 +635,9 @@ ieee80211n=1
# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
#ieee80211ac=1
# disable_11ac: Boolean (0/1) to disable VHT for a specific BSS
#disable_11ac=0
# vht_capab: VHT capabilities (list of flags)
#
# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
@ -788,6 +792,9 @@ ieee80211n=1
# 1 = enabled
#ieee80211ax=1
# disable_11ax: Boolean (0/1) to disable HE for a specific BSS
#disable_11ax=0
#he_su_beamformer: HE single user beamformer support
# 0 = not supported (default)
# 1 = supported
@ -806,6 +813,9 @@ ieee80211n=1
# he_bss_color: BSS color (1-63)
#he_bss_color=1
# he_bss_color_partial: BSS color AID equation
#he_bss_color_partial=0
#he_default_pe_duration: The duration of PE field in an HE PPDU in us
# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
#he_default_pe_duration=0
@ -821,11 +831,11 @@ ieee80211n=1
#he_rts_threshold=0
# HE operating channel information; see matching vht_* parameters for details.
# On the 6 GHz band the center freq calculation starts from 5.940 GHz offset.
# For example idx=3 would result in 5955 MHz center frequency. In addition,
# On the 6 GHz band the center freq calculation starts from 5.950 GHz offset.
# For example idx=3 would result in 5965 MHz center frequency. In addition,
# he_oper_chwidth is ignored, and the channel width is derived from the
# configured operating class or center frequency indexes (see
# IEEE P802.11ax/D4.3 Annex E, Table E-4).
# IEEE P802.11ax/D6.1 Annex E, Table E-4).
#he_oper_chwidth
#he_oper_centr_freq_seg0_idx
#he_oper_centr_freq_seg1_idx
@ -903,6 +913,8 @@ eapol_key_index_workaround=0
# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
# reauthentication).
# Note: Reauthentications may enforce a disconnection, check the related
# parameter wpa_deny_ptk0_rekey for details.
#eap_reauth_period=3600
# Use PAE group address (01:80:c2:00:00:03) instead of individual target
@ -1199,7 +1211,7 @@ eap_server=0
# should be unique across all issuing servers. In theory, this is a variable
# length field, but due to some existing implementations requiring A-ID to be
# 16 octets in length, it is strongly recommended to use that length for the
# field to provid interoperability with deployed peer implementations. This
# field to provide interoperability with deployed peer implementations. This
# field is configured in hex format.
#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
@ -1226,6 +1238,8 @@ eap_server=0
# EAP-TEAP authentication type
# 0 = inner EAP (default)
# 1 = Basic-Password-Auth
# 2 = Do not require Phase 2 authentication if client can be authenticated
# during Phase 1
#eap_teap_auth=0
# EAP-TEAP authentication behavior when using PAC
@ -1507,6 +1521,17 @@ own_ip_addr=127.0.0.1
# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
wpa=2
# Extended Key ID support for Individually Addressed frames
#
# Extended Key ID allows to rekey PTK keys without the impacts the "normal"
# PTK rekeying with only a single Key ID 0 has. It can only be used when the
# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher.
#
# 0 = force off, i.e., use only Key ID 0 (default)
# 1 = enable and use Extended Key ID support when possible
# 2 = identical to 1 but start with Key ID 1 when possible
#extended_key_id=0
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
@ -1607,8 +1632,26 @@ group_cipher=CCMP
# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
# PTK to mitigate some attacks against TKIP deficiencies.
# Warning: PTK rekeying is buggy with many drivers/devices and with such
# devices, the only secure method to rekey the PTK without Extended Key ID
# support requires a disconnection. Check the related parameter
# wpa_deny_ptk0_rekey for details.
#wpa_ptk_rekey=600
# Workaround for PTK rekey issues
#
# PTK0 rekeys (rekeying the PTK without "Extended Key ID for Individually
# Addressed Frames") can degrade the security and stability with some cards.
# To avoid such issues hostapd can replace those PTK rekeys (including EAP
# reauthentications) with disconnects.
#
# Available options:
# 0 = always rekey when configured/instructed (default)
# 1 = only rekey when the local driver is explicitly indicating it can perform
# this operation without issues
# 2 = never allow PTK0 rekeys
#wpa_deny_ptk0_rekey=0
# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
# Handshake are retried per 4-Way Handshake attempt.
# (dot11RSNAConfigPairwiseUpdateCount)
@ -1677,6 +1720,12 @@ wpa_pairwise_update_count=100
# available in deployed devices.
#group_mgmt_cipher=AES-128-CMAC
# Beacon Protection (management frame protection for Beacon frames)
# This depends on management frame protection being enabled (ieee80211w != 0).
# 0 = disabled (default)
# 1 = enabled
#beacon_prot=0
# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
# (maximum time to wait for a SA Query response)
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
@ -1692,6 +1741,19 @@ wpa_pairwise_update_count=100
# Enabling this automatically also enables ieee80211w, if not yet enabled.
# 0 = disabled (default)
# 1 = enabled
# 2 = enabled in workaround mode - Allow STA that claims OCV capability to
# connect even if the STA doesn't send OCI or negotiate PMF. This
# workaround is to improve interoperability with legacy STAs which are
# wrongly copying reserved bits of RSN capabilities from the AP's
# RSNE into (Re)Association Request frames. When this configuration is
# enabled, the AP considers STA is OCV capable only when the STA indicates
# MFP capability in (Re)Association Request frames and sends OCI in
# EAPOL-Key msg 2/4/FT Reassociation Request frame/FILS (Re)Association
# Request frame; otherwise, the AP disables OCV for the current connection
# with the STA. Enabling this workaround mode reduced OCV protection to
# some extend since it allows misbehavior to go through. As such, this
# should be enabled only if interoperability with misbehaving STAs is
# needed.
#ocv=1
# disable_pmksa_caching: Disable PMKSA caching
@ -1723,7 +1785,7 @@ wpa_pairwise_update_count=100
# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In
# addition, an optional VLAN ID specification can be used to bind the station
# to the specified VLAN whenver the specific SAE password entry is used.
# to the specified VLAN whenever the specific SAE password entry is used.
#
# If the peer MAC address is not included or is set to the wildcard address
# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
@ -1738,7 +1800,8 @@ wpa_pairwise_update_count=100
# special meaning of removing all previously added entries.
#
# sae_password uses the following encoding:
#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>][|id=<identifier>]
#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>]
#[|pk=<m:ECPrivateKey-base64>][|id=<identifier>]
# Examples:
#sae_password=secret
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
@ -1867,6 +1930,23 @@ wpa_pairwise_update_count=100
# default: 30 TUs (= 30.72 milliseconds)
#fils_hlp_wait_time=30
# Transition Disable indication
# The AP can notify authenticated stations to disable transition mode in their
# network profiles when the network has completed transition steps, i.e., once
# sufficiently large number of APs in the ESS have been updated to support the
# more secure alternative. When this indication is used, the stations are
# expected to automatically disable transition mode and less secure security
# options. This includes use of WEP, TKIP (including use of TKIP as the group
# cipher), and connections without PMF.
# Bitmap bits:
# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only
# allow SAE to be used)
# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE)
# (default: 0 = do not include Transition Disable KDE)
#transition_disable=0x01
##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@ -1910,7 +1990,7 @@ wpa_pairwise_update_count=100
# Wildcard entry:
# Upon receiving a response from R0KH, it will be added to this list, so
# subsequent requests won't be broadcast. If R0KH does not reply, it will be
# blacklisted.
# temporarily blocked (see rkh_neg_timeout).
#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
# List of R1KHs in the same Mobility Domain
@ -1966,7 +2046,7 @@ wpa_pairwise_update_count=100
#ft_psk_generate_local=0
##### Neighbor table ##########################################################
# Maximum number of entries kept in AP table (either for neigbor table or for
# Maximum number of entries kept in AP table (either for neighbor table or for
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
# removed when adding a new entry that would make the list grow over this
# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
@ -2249,6 +2329,17 @@ wpa_pairwise_update_count=100
#dpp_csign
#dpp_controller
# Configurator Connectivity indication
# 0: no Configurator is currently connected (default)
# 1: advertise that a Configurator is available
#dpp_configurator_connectivity=0
# DPP PFS
# 0: allow PFS to be used or not used (default)
# 1: require PFS to be used (note: not compatible with DPP R1)
# 2: do not allow PFS to be used
#dpp_pfs=0
#### TDLS (IEEE 802.11z-2010) #################################################
# Prohibit use of TDLS in this BSS
@ -2644,6 +2735,10 @@ wpa_pairwise_update_count=100
# threshold (range: 0..255, default=30).
#rssi_reject_assoc_timeout=30
# Ignore Probe Request frames if RSSI is below given threshold (in dBm)
# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
#rssi_ignore_probe_request=-75
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration

View File

@ -975,7 +975,7 @@ static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
dir = opendir(ctrl_iface_dir);
if (dir == NULL) {
printf("Control interface directory '%s' could not be "
"openned.\n", ctrl_iface_dir);
"opened.\n", ctrl_iface_dir);
return;
}
@ -1227,14 +1227,15 @@ static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
char cmd[256];
int res;
if (argc < 2 || argc > 3) {
if (argc < 2 || argc > 4) {
printf("Invalid vendor command\n"
"usage: <vendor id> <command id> [<hex formatted command argument>]\n");
"usage: <vendor id> <command id> [<hex formatted command argument>] [nested=<0|1>]\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
argc == 3 ? argv[2] : "");
res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s%s%s", argv[0],
argv[1], argc >= 3 ? argv[2] : "",
argc == 4 ? " " : "", argc == 4 ? argv[3] : "");
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long VENDOR command.\n");
return -1;
@ -1402,6 +1403,13 @@ static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
}
static int hostapd_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
}
static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@ -1464,6 +1472,37 @@ static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
}
#ifdef CONFIG_DPP2
static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
}
static int hostapd_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP");
}
static int hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return hostapd_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
}
static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
}
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
@ -1650,6 +1689,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"<id> = get DPP bootstrap URI" },
{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
"<id> = show DPP bootstrap information" },
{ "dpp_bootstrap_set", hostapd_cli_cmd_dpp_bootstrap_set, NULL,
"<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
@ -1670,6 +1711,16 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"add PKEX code" },
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
"*|<id> = remove DPP pkex information" },
#ifdef CONFIG_DPP2
{ "dpp_controller_start", hostapd_cli_cmd_dpp_controller_start, NULL,
"[tcp_port=<port>] [role=..] = start DPP controller" },
{ "dpp_controller_stop", hostapd_cli_cmd_dpp_controller_stop, NULL,
"= stop DPP controller" },
{ "dpp_chirp", hostapd_cli_cmd_dpp_chirp, NULL,
"own=<BI ID> iter=<count> = start DPP chirp" },
{ "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
"= stop DPP chirp" },
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
"=Add/Delete/Show/Clear accept MAC ACL" },

View File

@ -218,7 +218,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
struct wowlan_triggers *triggs;
iface->drv_flags = capa.flags;
iface->smps_modes = capa.smps_modes;
iface->drv_flags2 = capa.flags2;
iface->probe_resp_offloads = capa.probe_resp_offloads;
/*
* Use default extended capa values from per-radio information
@ -451,11 +451,12 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
static void show_version(void)
{
fprintf(stderr,
"hostapd v" VERSION_STR "\n"
"hostapd v%s\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
"Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
"and contributors\n");
"and contributors\n",
VERSION_STR);
}
@ -673,7 +674,10 @@ int main(int argc, char *argv[])
#endif /* CONFIG_ETH_P_OUI */
#ifdef CONFIG_DPP
os_memset(&dpp_conf, 0, sizeof(dpp_conf));
/* TODO: dpp_conf.msg_ctx? */
dpp_conf.cb_ctx = &interfaces;
#ifdef CONFIG_DPP2
dpp_conf.remove_bi = hostapd_dpp_remove_bi;
#endif /* CONFIG_DPP2 */
interfaces.dpp = dpp_global_init(&dpp_conf);
if (!interfaces.dpp)
return -1;
@ -902,8 +906,11 @@ int main(int argc, char *argv[])
!!(interfaces.iface[i]->drv_flags &
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
hostapd_interface_deinit_free(interfaces.iface[i]);
interfaces.iface[i] = NULL;
}
os_free(interfaces.iface);
interfaces.iface = NULL;
interfaces.count = 0;
#ifdef CONFIG_DPP
dpp_global_deinit(interfaces.dpp);

196
hostapd/sae_pk_gen.c Normal file
View File

@ -0,0 +1,196 @@
/*
* SAE-PK password/modifier generator
* Copyright (c) 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 "utils/common.h"
#include "utils/base64.h"
#include "crypto/crypto.h"
#include "common/sae.h"
int main(int argc, char *argv[])
{
char *der = NULL;
size_t der_len;
struct crypto_ec_key *key = NULL;
struct wpabuf *pub = NULL;
u8 *data = NULL, *m;
size_t data_len;
char *b64 = NULL, *pw = NULL, *pos, *src;
int sec, j;
int ret = -1;
u8 hash[SAE_MAX_HASH_LEN];
char hash_hex[2 * SAE_MAX_HASH_LEN + 1];
u8 pw_base_bin[SAE_MAX_HASH_LEN];
u8 *dst;
int group;
size_t hash_len;
unsigned long long i, expected;
char m_hex[2 * SAE_PK_M_LEN + 1];
u32 sec_1b, val20;
wpa_debug_level = MSG_INFO;
if (os_program_init() < 0)
goto fail;
if (argc != 4) {
fprintf(stderr,
"usage: sae_pk_gen <DER ECPrivateKey file> <Sec:3|5> <SSID>\n");
goto fail;
}
sec = atoi(argv[2]);
if (sec != 3 && sec != 5) {
fprintf(stderr,
"Invalid Sec value (allowed values: 3 and 5)\n");
goto fail;
}
sec_1b = sec == 3;
expected = 1;
for (j = 0; j < sec; j++)
expected *= 256;
der = os_readfile(argv[1], &der_len);
if (!der) {
fprintf(stderr, "Could not read %s: %s\n",
argv[1], strerror(errno));
goto fail;
}
key = crypto_ec_key_parse_priv((u8 *) der, der_len);
if (!key) {
fprintf(stderr, "Could not parse ECPrivateKey\n");
goto fail;
}
pub = crypto_ec_key_get_subject_public_key(key);
if (!pub) {
fprintf(stderr, "Failed to build SubjectPublicKey\n");
goto fail;
}
group = crypto_ec_key_group(key);
switch (group) {
case 19:
hash_len = 32;
break;
case 20:
hash_len = 48;
break;
case 21:
hash_len = 64;
break;
default:
fprintf(stderr, "Unsupported private key group\n");
goto fail;
}
data_len = os_strlen(argv[3]) + SAE_PK_M_LEN + wpabuf_len(pub);
data = os_malloc(data_len);
if (!data) {
fprintf(stderr, "No memory for data buffer\n");
goto fail;
}
os_memcpy(data, argv[3], os_strlen(argv[3]));
m = data + os_strlen(argv[3]);
if (os_get_random(m, SAE_PK_M_LEN) < 0) {
fprintf(stderr, "Could not generate random Modifier M\n");
goto fail;
}
os_memcpy(m + SAE_PK_M_LEN, wpabuf_head(pub), wpabuf_len(pub));
fprintf(stderr, "Searching for a suitable Modifier M value\n");
for (i = 0;; i++) {
if (sae_hash(hash_len, data, data_len, hash) < 0) {
fprintf(stderr, "Hash failed\n");
goto fail;
}
if (hash[0] == 0 && hash[1] == 0) {
if ((hash[2] & 0xf0) == 0)
fprintf(stderr, "\r%3.2f%%",
100.0 * (double) i / (double) expected);
for (j = 2; j < sec; j++) {
if (hash[j])
break;
}
if (j == sec)
break;
}
inc_byte_array(m, SAE_PK_M_LEN);
}
if (wpa_snprintf_hex(m_hex, sizeof(m_hex), m, SAE_PK_M_LEN) < 0 ||
wpa_snprintf_hex(hash_hex, sizeof(hash_hex), hash, hash_len) < 0)
goto fail;
fprintf(stderr, "\nFound a valid hash in %llu iterations: %s\n",
i + 1, hash_hex);
b64 = base64_encode(der, der_len, NULL);
if (!b64)
goto fail;
src = pos = b64;
while (*src) {
if (*src != '\n')
*pos++ = *src;
src++;
}
*pos = '\0';
/* Skip 8*Sec bits and add Sec_1b as the every 20th bit starting with
* one. */
os_memset(pw_base_bin, 0, sizeof(pw_base_bin));
dst = pw_base_bin;
for (j = 0; j < 8 * (int) hash_len / 20; j++) {
val20 = sae_pk_get_be19(hash + sec);
val20 |= sec_1b << 19;
sae_pk_buf_shift_left_19(hash + sec, hash_len - sec);
if (j & 1) {
*dst |= (val20 >> 16) & 0x0f;
dst++;
*dst++ = (val20 >> 8) & 0xff;
*dst++ = val20 & 0xff;
} else {
*dst++ = (val20 >> 12) & 0xff;
*dst++ = (val20 >> 4) & 0xff;
*dst = (val20 << 4) & 0xf0;
}
}
if (wpa_snprintf_hex(hash_hex, sizeof(hash_hex),
pw_base_bin, hash_len - sec) >= 0)
fprintf(stderr, "PasswordBase binary data for base32: %s",
hash_hex);
pw = sae_pk_base32_encode(pw_base_bin, 20 * 3 - 5);
if (!pw)
goto fail;
printf("# SAE-PK password/M/private key for Sec=%d.\n", sec);
printf("sae_password=%s|pk=%s:%s\n", pw, m_hex, b64);
printf("# Longer passwords can be used for improved security at the cost of usability:\n");
for (j = 4; j <= ((int) hash_len * 8 + 5 - 8 * sec) / 19; j++) {
os_free(pw);
pw = sae_pk_base32_encode(pw_base_bin, 20 * j - 5);
if (pw)
printf("# %s\n", pw);
}
ret = 0;
fail:
os_free(der);
wpabuf_free(pub);
crypto_ec_key_deinit(key);
os_free(data);
os_free(b64);
os_free(pw);
os_program_deinit();
return ret;
}

View File

@ -1,28 +1,6 @@
all: hs20-osu-client
ALL=hs20-osu-client
ifndef CC
CC=gcc
endif
ifndef LDO
LDO=$(CC)
endif
ifeq ($(QUIET), 1)
Q=@
E=true
else
Q=@
E=echo
ifeq ($(V), 1)
Q=
E=true
endif
endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
include ../../src/build.rules
CFLAGS += -I../../src/utils
CFLAGS += -I../../src/common
@ -30,8 +8,17 @@ CFLAGS += -I../../src
ifndef CONFIG_NO_BROWSER
ifndef CONFIG_BROWSER_SYSTEM
TEST_WK := $(shell pkg-config --silence-errors --cflags webkitgtk-3.0)
ifeq ($(TEST_WK),)
# Try webkit2
GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0)
GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0)
CFLAGS += -DUSE_WEBKIT2
else
GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0)
GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0)
endif
CFLAGS += $(GTKCFLAGS)
LIBS += $(GTKLIBS)
endif
@ -84,23 +71,11 @@ CFLAGS += -DEAP_TLS_OPENSSL
OBJS += ../../src/crypto/tls_openssl_ocsp.o
LIBS += -lssl -lcrypto
_OBJS_VAR := OBJS
include ../../src/objs.mk
hs20-osu-client: $(OBJS)
$(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS)
@$(E) " LD " $@
%.o: %.c
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
clean:
rm -f core *~ *.o *.d hs20-osu-client
rm -f ../../src/utils/*.o
rm -f ../../src/utils/*.d
rm -f ../../src/common/*.o
rm -f ../../src/common/*.d
rm -f ../../src/crypto/*.o
rm -f ../../src/crypto/*.d
rm -f ../../src/wps/*.o
rm -f ../../src/wps/*.d
-include $(OBJS:%.o=%.d)
clean: common-clean
rm -f core *~

View File

@ -407,7 +407,7 @@ static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
wpa_printf(MSG_INFO, "Data: %s", data);
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
write_summary(ctx, "Launch browser to URI '%s'", data);
res = hs20_web_browser(data);
res = hs20_web_browser(data, 1);
xml_node_get_text_free(ctx->xml, data);
if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully");

View File

@ -2233,7 +2233,7 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
wpa_ctrl_close(mon);
if (res < 0) {
wpa_printf(MSG_INFO, "Could not connect");
wpa_printf(MSG_INFO, "Could not connect to OSU network");
write_summary(ctx, "Could not connect to OSU network");
wpa_printf(MSG_INFO, "Remove OSU network connection");
snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
@ -2406,7 +2406,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
write_summary(ctx, "Start web browser with OSU provider selection page");
ret = hs20_web_browser(fname);
ret = hs20_web_browser(fname, 0);
selected:
if (ret > 0 && (size_t) ret <= osu_count) {
@ -2907,7 +2907,7 @@ static char * get_hostname(const char *url)
static int osu_cert_cb(void *_ctx, struct http_cert *cert)
{
struct hs20_osu_client *ctx = _ctx;
unsigned int i, j;
size_t i, j;
int found;
char *host = NULL;
@ -3002,7 +3002,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
size_t name_len = os_strlen(name);
wpa_printf(MSG_INFO,
"[%i] Looking for icon file name '%s' match",
"[%zu] Looking for icon file name '%s' match",
j, name);
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
@ -3010,7 +3010,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
char *pos;
wpa_printf(MSG_INFO,
"[%i] Comparing to '%s' uri_len=%d name_len=%d",
"[%zu] Comparing to '%s' uri_len=%d name_len=%d",
i, logo->uri, (int) uri_len, (int) name_len);
if (uri_len < 1 + name_len) {
wpa_printf(MSG_INFO, "URI Length is too short");
@ -3044,7 +3044,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
if (logo->hash_len != 32) {
wpa_printf(MSG_INFO,
"[%i][%i] Icon hash length invalid (should be 32): %d",
"[%zu][%zu] Icon hash length invalid (should be 32): %d",
j, i, (int) logo->hash_len);
continue;
}
@ -3054,7 +3054,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
}
wpa_printf(MSG_DEBUG,
"[%u][%u] Icon hash did not match", j, i);
"[%zu][%zu] Icon hash did not match", j, i);
wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
logo->hash, 32);
wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
@ -3152,7 +3152,7 @@ static void check_workarounds(struct hs20_osu_client *ctx)
static void usage(void)
{
printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n"
printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n"
" [-w<wpa_supplicant ctrl_iface dir>] "
"[-r<result file>] [-f<debug file>] \\\n"
" [-s<summary file>] \\\n"
@ -3198,7 +3198,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:");
if (c < 0)
break;
switch (c) {
@ -3236,6 +3236,9 @@ int main(int argc, char *argv[])
case 't':
wpa_debug_timestamp++;
break;
case 'T':
ctx.ignore_tls = 1;
break;
case 'w':
wpas_ctrl_path = optarg;
break;
@ -3403,7 +3406,7 @@ int main(int argc, char *argv[])
wpa_printf(MSG_INFO, "Launch web browser to URL %s",
argv[optind + 1]);
ret = hs20_web_browser(argv[optind + 1]);
ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls);
wpa_printf(MSG_INFO, "Web browser result: %d", ret);
} else if (strcmp(argv[optind], "parse_cert") == 0) {
if (argc - optind < 2) {

View File

@ -50,6 +50,8 @@ struct hs20_osu_client {
const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
unsigned long int workarounds;
int ignore_tls; /* whether to ignore TLS validation issues with HTTPS
* server certificate */
};

View File

@ -547,7 +547,7 @@ static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
}
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
write_summary(ctx, "Launch browser to URI '%s'", uri);
res = hs20_web_browser(uri);
res = hs20_web_browser(uri, 1);
xml_node_get_text_free(ctx->xml, uri);
if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",

1
hs20/server/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
hs20_spp_server

View File

@ -1,16 +1,6 @@
all: hs20_spp_server
ALL=hs20_spp_server
ifndef CC
CC=gcc
endif
ifndef LDO
LDO=$(CC)
endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
include ../../src/build.rules
CFLAGS += -I../../src
CFLAGS += -I../../src/utils
@ -43,14 +33,10 @@ CFLAGS += $(shell xml2-config --cflags)
LIBS += $(shell xml2-config --libs)
OBJS += ../../src/utils/xml_libxml2.o
_OBJS_VAR := OBJS
include ../../src/objs.mk
hs20_spp_server: $(OBJS)
$(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS)
clean:
rm -f core *~ *.o *.d hs20_spp_server
rm -f ../../src/utils/*.o
rm -f ../../src/utils/*.d
rm -f ../../src/crypto/*.o
rm -f ../../src/crypto/*.d
-include $(OBJS:%.o=%.d)
clean: common-clean
rm -f core *~

View File

@ -1,3 +1,3 @@
#!/bin/sh
openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text
openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err

View File

@ -1,5 +1,6 @@
#!/bin/sh
# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
openssl ocsp \
-no_nonce \
-CAfile ca.pem \

View File

@ -176,7 +176,7 @@ int main(int argc, char *argv[])
ctx.root_dir = optarg;
break;
case 'v':
printf("hs20_spp_server v" VERSION_STR "\n");
printf("hs20_spp_server v%s\n", VERSION_STR);
return 0;
default:
usage();

View File

@ -1,18 +1,6 @@
ALL=radius_example
all: $(ALL)
ifndef CC
CC=gcc
endif
ifndef LDO
LDO=$(CC)
endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
include ../src/build.rules
CFLAGS += -I.
CFLAGS += -I../src
@ -23,24 +11,18 @@ LIBS += ../src/crypto/libcrypto.a
LIBS += ../src/utils/libutils.a
LLIBS = -lrt
../src/utils/libutils.a:
$(MAKE) -C ../src/utils
../src/crypto/libcrypto.a:
$(MAKE) -C ../src/crypto
../src/radius/libradius.a:
$(MAKE) -C ../src/radius
#CLAGS += -DCONFIG_IPV6
OBJS_ex = radius_example.o
_OBJS_VAR := OBJS_ex
include ../src/objs.mk
_OBJS_VAR := LIBS
include ../src/objs.mk
radius_example: $(OBJS_ex) $(LIBS)
$(LDO) $(LDFLAGS) -o radius_example $(OBJS_ex) $(LIBS) $(LLIBS)
clean:
$(MAKE) -C ../src clean
rm -f core *~ *.o *.d $(ALL)
-include $(OBJS:%.o=%.d)
clean: common-clean
rm -f core *~ *.o *.d

View File

@ -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

View File

@ -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

View File

@ -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;
}
/* We need at least survey data for one channel */
return !!valid;
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;
}
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;
}
@ -918,29 +1015,59 @@ fail:
}
static int acs_request_scan(struct hostapd_iface *iface)
static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode,
int *freq)
{
struct wpa_driver_scan_params params;
struct hostapd_channel_data *chan;
int i, *freq;
int i;
os_memset(&params, 0, sizeof(params));
params.freqs = os_calloc(iface->current_mode->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];
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;
int i, *freq;
int num_channels;
struct hostapd_hw_modes *mode;
os_memset(&params, 0, sizeof(params));
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->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) {
@ -978,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);

View File

@ -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)

View File

@ -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
@ -448,7 +465,8 @@ 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 && !hostapd_sae_pw_id_in_use(conf)) ||
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 */
@ -632,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;
@ -640,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)
@ -696,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);
}
}
@ -728,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 */
@ -890,7 +915,10 @@ 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 */
@ -1091,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)
@ -1102,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;
@ -1119,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 &&
@ -1166,47 +1227,49 @@ 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;
bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
"allowed, disabling HT capabilities");
}
#ifdef CONFIG_WEP
if (full_config && conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11n = 1;
bss->disable_11n = true;
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) &&
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{
bss->disable_11n = 1;
bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
"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;
bss->disable_11ac = true;
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) &&
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{
bss->disable_11ac = 1;
bss->disable_11ac = true;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
}
@ -1219,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) ||
@ -1268,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;
}
@ -1348,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;
@ -1378,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 ?
@ -1388,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)
@ -1403,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;
@ -1441,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 */

View File

@ -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,
@ -102,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
@ -191,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 {
@ -255,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 {
@ -321,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;
@ -346,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) */
@ -369,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;
@ -528,8 +531,9 @@ struct hostapd_bss_config {
#define TDLS_PROHIBIT BIT(0)
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls;
int disable_11n;
int disable_11ac;
bool disable_11n;
bool disable_11ac;
bool disable_11ax;
/* IEEE 802.11v */
int time_advertisement;
@ -666,10 +670,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)
@ -725,6 +745,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 */
@ -741,6 +763,8 @@ struct hostapd_bss_config {
u8 send_probe_response;
u8 transition_disable;
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
@ -844,9 +868,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;
};
/**
@ -854,6 +878,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;
@ -1013,6 +1039,7 @@ struct hostapd_config {
int rssi_reject_assoc_rssi;
int rssi_reject_assoc_timeout;
int rssi_ignore_probe_request;
#ifdef CONFIG_AIRTIME_POLICY
enum {
@ -1117,6 +1144,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 */

View File

@ -418,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)
{
@ -439,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);
@ -588,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);
@ -650,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)
{
@ -714,7 +722,7 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
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, no_encrypt);
csa_offs, csa_offs_len, no_encrypt, 0);
}
@ -938,6 +946,7 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
}
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 &

View File

@ -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(
@ -348,12 +350,13 @@ static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
int vendor_id, int subcmd,
const u8 *data, size_t data_len,
enum nested_attr nested_attr_flag,
struct wpabuf *buf)
{
if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
return -1;
return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data,
data_len, buf);
data_len, nested_attr_flag, buf);
}
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
@ -382,11 +385,11 @@ hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
}
static inline int
hostapd_drv_set_band(struct hostapd_data *hapd, enum set_band band)
hostapd_drv_set_band(struct hostapd_data *hapd, u32 band_mask)
{
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
return -1;
return hapd->driver->set_band(hapd->drv_priv, band);
return hapd->driver->set_band(hapd->drv_priv, band_mask);
}
#endif /* AP_DRV_OPS */

View File

@ -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)

View File

@ -266,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(eid, ie, ielen);
return eid + ielen;
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(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];
}
@ -374,16 +458,20 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
}
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_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)
@ -434,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);
@ -450,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);
@ -483,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 && !hapd->conf->disable_11ax))
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) {
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
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 */
@ -503,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);
@ -539,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),
@ -736,6 +818,10 @@ void handle_probe_req(struct hostapd_data *hapd,
size_t csa_offs_len;
struct radius_sta rad_info;
if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
ssi_signal < hapd->iconf->rssi_ignore_probe_request)
return;
if (len < IEEE80211_HDRLEN)
return;
ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
@ -1052,7 +1138,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
@ -1081,16 +1167,20 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_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) {
@ -1099,6 +1189,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);
@ -1139,8 +1230,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);
@ -1157,19 +1247,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);
@ -1178,15 +1260,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);
@ -1213,19 +1288,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 && !hapd->conf->disable_11ax))
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) {
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
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 */
@ -1234,12 +1314,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);
@ -1272,6 +1349,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),
@ -1310,10 +1388,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;
@ -1326,7 +1407,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);
@ -1422,8 +1502,18 @@ 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;
#ifdef CONFIG_SAE
params.sae_pwe = hapd->conf->sae_pwe;
#endif /* CONFIG_SAE */
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,

View File

@ -345,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",
@ -354,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])) {
@ -750,7 +748,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
iface->conf->ieee80211n && !hapd->conf->disable_11n,
iface->conf->ieee80211ac &&
!hapd->conf->disable_11ac,
iface->conf->ieee80211ax,
iface->conf->ieee80211ax &&
!hapd->conf->disable_11ax,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
@ -758,7 +757,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
len += ret;
#ifdef CONFIG_IEEE80211AX
if (iface->conf->ieee80211ax) {
if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
ret = os_snprintf(buf + len, buflen - len,
"he_oper_chwidth=%d\n"
"he_oper_centr_freq_seg0_idx=%d\n"

View File

@ -144,31 +144,45 @@ 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);
@ -773,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;
@ -821,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;
}
@ -851,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;
@ -867,10 +988,16 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
&oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
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",
channel->chan);
@ -898,11 +1025,14 @@ 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);
int ieee80211_mode = IEEE80211_MODE_AP;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@ -936,29 +1066,34 @@ 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,
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
skip_radar);
&skip_radar);
if (!channel) {
wpa_printf(MSG_INFO,
"%s: no DFS channels left, waiting for NOP to finish",
__func__);
return err;
/*
* Toggle interface state to enter DFS state
* until NOP is finished.
*/
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
return 0;
}
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_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",
channel->chan);
@ -966,10 +1101,17 @@ 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;
csa_settings.block_tx = 1;
#ifdef CONFIG_MESH
if (iface->mconf)
ieee80211_mode = IEEE80211_MODE_MESH;
#endif /* CONFIG_MESH */
err = hostapd_set_freq_params(&csa_settings.freq_params,
iface->conf->hw_mode,
channel->freq,
@ -980,11 +1122,11 @@ 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,
&cmode->he_capab[IEEE80211_MODE_AP]);
&cmode->he_capab[ieee80211_mode]);
if (err) {
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
@ -1004,6 +1146,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,
@ -1040,8 +1183,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,
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);
@ -1161,3 +1306,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;
}

View File

@ -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 */

View File

@ -26,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 };
@ -59,6 +66,10 @@ 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;
}
@ -237,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;
@ -478,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)
@ -496,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;
@ -533,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,
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 (!hapd->dpp_auth)
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;
@ -618,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) {
@ -663,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) {
@ -671,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;
@ -708,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),
@ -1132,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 */
@ -1141,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;
@ -1216,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
@ -1581,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,
@ -1610,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,
@ -1646,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");
@ -1675,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;
@ -1891,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;
@ -1903,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 */

View File

@ -10,6 +10,8 @@
#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);
@ -39,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 */

View File

@ -106,18 +106,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) {
@ -226,7 +253,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 &
@ -240,7 +266,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) {
@ -300,6 +325,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);
@ -331,55 +367,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 if (res == WPA_INVALID_PMKID) {
reason = WLAN_REASON_INVALID_PMKID;
status = WLAN_STATUS_INVALID_PMKID;
} 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);
@ -412,7 +464,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
@ -475,6 +527,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) &&
@ -486,13 +541,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;
@ -579,17 +631,19 @@ 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),
&status);
&ret_status);
status = ret_status;
if (npos)
p = npos;
if (!npos &&
status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
hostapd_sta_assoc(hapd, addr, reassoc, ret_status, buf,
p - buf);
return 0;
}
@ -631,6 +685,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);
@ -677,6 +736,7 @@ skip_wpa_check:
fail:
#ifdef CONFIG_IEEE80211R_AP
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);
@ -715,6 +775,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);
@ -808,8 +869,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;
@ -859,9 +918,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:
@ -912,10 +980,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 */
}
@ -1011,6 +1108,8 @@ 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);
@ -1433,15 +1532,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;
}

View File

@ -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

View File

@ -58,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,
@ -74,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;
@ -89,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 */
}
@ -142,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);
}
@ -170,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
@ -284,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)
{
@ -326,7 +338,7 @@ 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, 0,
1, NULL, 0, ssid->wep.key[idx],
@ -339,8 +351,10 @@ 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)
void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
os_free(hapd->probereq_cb);
hapd->probereq_cb = NULL;
@ -420,11 +434,17 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_MESH
wpabuf_free(hapd->mesh_pending_auth);
hapd->mesh_pending_auth = NULL;
/* handling setup failure is already done */
hapd->setup_complete_cb = NULL;
#endif /* CONFIG_MESH */
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;
@ -478,14 +498,12 @@ static void sta_track_deinit(struct hostapd_iface *iface)
}
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
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);
@ -526,6 +544,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) {
@ -573,6 +593,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)
{
@ -604,11 +626,13 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
}
static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
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 */
}
@ -1159,13 +1183,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);
#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,
@ -1351,6 +1377,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;
@ -1754,7 +1795,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;
@ -1776,7 +1817,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;
@ -1788,7 +1829,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);
}
@ -1876,6 +1917,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;
@ -2110,6 +2158,13 @@ dfs_offload:
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
#ifdef CONFIG_MESH
if (delay_apply_cfg && !iface->mconf) {
wpa_printf(MSG_ERROR, "Error while completing mesh init");
goto fail;
}
#endif /* CONFIG_MESH */
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
iface->bss[0]->conf->iface);
if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
@ -2253,7 +2308,7 @@ int hostapd_setup_interface(struct hostapd_iface *iface)
ret = setup_interface(iface);
if (ret) {
wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
iface->bss[0]->conf->iface);
iface->conf ? iface->conf->bss[0]->iface : "N/A");
return -1;
}
@ -2349,12 +2404,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 */
}
@ -2637,6 +2690,12 @@ int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
{
size_t j;
if (!hapd_iface)
return -1;
if (hapd_iface->enable_iface_cb)
return hapd_iface->enable_iface_cb(hapd_iface);
if (hapd_iface->bss[0]->drv_priv != NULL) {
wpa_printf(MSG_ERROR, "Interface %s already enabled",
hapd_iface->conf->bss[0]->iface);
@ -2698,6 +2757,9 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
if (hapd_iface == NULL)
return -1;
if (hapd_iface->disable_iface_cb)
return hapd_iface->disable_iface_cb(hapd_iface);
if (hapd_iface->bss[0]->drv_priv == NULL) {
wpa_printf(MSG_INFO, "Interface %s already disabled",
hapd_iface->conf->bss[0]->iface);
@ -3118,6 +3180,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) {
@ -3629,3 +3692,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 */

View File

@ -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
@ -563,6 +589,9 @@ struct hostapd_iface {
/* Previous WMM element information */
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
int (*enable_iface_cb)(struct hostapd_iface *iface);
int (*disable_iface_cb)(struct hostapd_iface *iface);
};
/* hostapd.c */
@ -591,6 +620,9 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface);
int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
void hostapd_free_hapd_data(struct hostapd_data *hapd);
void hostapd_cleanup_iface_partial(struct hostapd_iface *iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
@ -606,6 +638,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,

View File

@ -224,7 +224,6 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
}
#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
int pri_freq, sec_freq;
@ -561,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 "
@ -687,12 +666,9 @@ 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))
@ -725,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;
}
@ -810,7 +785,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
/* 60 GHz channels 1..6 */
for (i = 0; i < 6; i++) {
int freq = 56160 + 2160 * i;
int freq = 56160 + 2160 * (i + 1);
if (edmg.channels & BIT(i)) {
contiguous++;
@ -904,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->freq) {
hostapd_determine_mode(iface);
if (hostapd_is_usable_chans(iface))
return HOSTAPD_CHAN_VALID;
else
@ -1033,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,
@ -1110,3 +1124,20 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
}
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;
}

View File

@ -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,
@ -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 */

View File

@ -25,6 +25,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"
@ -224,7 +225,7 @@ u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
u16 hostapd_own_capab_info(struct hostapd_data *hapd)
{
int capab = WLAN_CAPABILITY_ESS;
int privacy;
int privacy = 0;
int dfs;
int i;
@ -240,12 +241,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;
@ -285,6 +288,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,
@ -341,6 +345,7 @@ 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, struct sta_info *sta,
@ -380,9 +385,10 @@ static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
#ifdef CONFIG_SAE
if (hapd->conf->sae_confirm_immediate == 2 &&
auth_alg == WLAN_AUTH_SAE) {
if (auth_transaction == 1 &&
if (auth_transaction == 1 && sta &&
(resp == WLAN_STATUS_SUCCESS ||
resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) {
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);
@ -474,17 +480,23 @@ 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)
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) {
@ -498,6 +510,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) {
@ -511,7 +525,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 &&
@ -533,10 +547,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;
if (buf &&
sae_write_commit(sta->sae, buf, sta->sae->tmp ?
sta->sae->tmp->anti_clogging_token : NULL, rx_id);
sta->sae->tmp->anti_clogging_token : NULL,
rx_id) < 0) {
wpabuf_free(buf);
buf = NULL;
}
return buf;
}
@ -551,7 +568,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;
}
@ -571,8 +598,21 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
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;
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),
@ -636,13 +676,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;
}
@ -655,9 +697,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 "
@ -721,7 +762,10 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
}
p_idx = sae_token_hash(hapd, addr);
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++;
@ -889,9 +933,14 @@ 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, status_code);
if (ret)
@ -1101,20 +1150,28 @@ static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
{
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) ||
(sae_pwe == 1 &&
status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
(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)));
}
@ -1137,11 +1194,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;
@ -1183,6 +1244,7 @@ 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;
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");
@ -1328,7 +1390,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",
@ -1358,9 +1421,7 @@ 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)) {
if (check_sae_rejected_groups(hapd, sta->sae)) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply;
}
@ -1372,8 +1433,9 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
"SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr));
if (sta->sae->tmp)
h2e = sta->sae->tmp->h2e;
if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
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, h2e);
@ -1601,27 +1663,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)
return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
if (res == WPA_INVALID_PAIRWISE)
return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
if (res == WPA_INVALID_AKMP)
return WLAN_STATUS_AKMP_NOT_VALID;
if (res == WPA_ALLOC_FAIL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
if (res == WPA_INVALID_MDIE)
return WLAN_STATUS_INVALID_MDIE;
if (res == WPA_INVALID_PMKID)
return WLAN_STATUS_INVALID_PMKID;
if (res != WPA_IE_OK)
return WLAN_STATUS_INVALID_IE;
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;
case WPA_INVALID_PAIRWISE:
return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
case WPA_INVALID_AKMP:
return WLAN_STATUS_AKMP_NOT_VALID;
case WPA_NOT_ENABLED:
return WLAN_STATUS_INVALID_IE;
case WPA_ALLOC_FAIL:
return WLAN_STATUS_UNSPECIFIED_FAILURE;
case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
case WPA_INVALID_MGMT_GROUP_CIPHER:
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
case WPA_INVALID_MDIE:
return WLAN_STATUS_INVALID_MDIE;
case WPA_INVALID_PROTO:
return WLAN_STATUS_INVALID_IE;
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;
}
@ -1641,7 +1713,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;
@ -1817,11 +1889,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) {
@ -1831,8 +1903,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");
@ -1841,8 +1913,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;
@ -1985,12 +2057,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),
@ -2506,32 +2578,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) {
@ -2544,6 +2594,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,
@ -2562,6 +2613,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;
@ -3032,7 +3084,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");
@ -3104,11 +3156,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;
@ -3137,7 +3217,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;
@ -3148,7 +3227,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) {
@ -3177,12 +3255,25 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
elems.he_capabilities,
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 */
@ -3216,6 +3307,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,
@ -3245,7 +3338,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)
@ -3268,27 +3362,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;
@ -3341,7 +3417,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
@ -3366,7 +3442,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) {
@ -3393,7 +3470,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,
@ -3403,7 +3479,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) {
@ -3490,6 +3565,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,
@ -3503,9 +3579,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;
}
}
@ -3604,10 +3691,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);
@ -3631,6 +3716,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)) {
@ -3655,7 +3741,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;
@ -3725,7 +3812,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");
@ -3755,10 +3843,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 &&
@ -3785,11 +3871,12 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
p = hostapd_eid_he_operation(hapd, p);
p = hostapd_eid_spatial_reuse(hapd, p);
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
p = hostapd_eid_he_6ghz_band_cap(hapd, p);
}
#endif /* CONFIG_IEEE80211AX */
@ -3806,12 +3893,29 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_FST */
#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);
@ -3832,7 +3936,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),
@ -4024,7 +4128,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;
@ -4064,7 +4168,8 @@ 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;
@ -4072,6 +4177,7 @@ static void handle_assoc(struct hostapd_data *hapd,
#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))) {
@ -4284,6 +4390,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,
@ -4336,9 +4443,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,
@ -4443,12 +4548,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.
*/
@ -4485,6 +4591,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");
@ -4551,6 +4658,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");
@ -4682,14 +4790,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 ==
@ -4849,6 +4955,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);
@ -4967,6 +5078,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;
@ -4987,6 +5099,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
break;
}
}
#endif /* CONFIG_WEP */
}
@ -5487,4 +5600,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 */

View File

@ -53,7 +53,6 @@ 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);
@ -64,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,
@ -96,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,
@ -182,6 +186,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);
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);

View File

@ -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 =
@ -308,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,
@ -387,6 +419,7 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
size_t he_capab_len)
{
if (!he_capab || !hapd->iconf->ieee80211ax ||
hapd->conf->disable_11ax ||
!check_valid_he_mcs(hapd, he_capab, opmode) ||
ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
@ -410,3 +443,45 @@ 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 ||
hapd->conf->disable_11ax ||
!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);
}

View File

@ -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

View File

@ -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);
@ -151,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);
@ -254,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;
}
@ -377,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
@ -392,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;
}
}
@ -440,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)
@ -860,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)
@ -1011,11 +1096,16 @@ 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) ||
!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)) ||
!hostapd_sae_pw_id_in_use(hapd->conf) && !sae_pk) ||
hapd->conf->sae_pwe == 3 ||
len < 3)
return pos;
@ -1024,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;
}

View File

@ -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;

View File

@ -137,6 +137,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
}
#ifdef CONFIG_WEP
#ifndef CONFIG_FIPS
#ifndef CONFIG_NO_RC4
@ -297,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)
@ -876,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;
}
@ -907,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 */
}
@ -1138,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
@ -1165,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);
@ -1178,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;
@ -1295,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) {
@ -1304,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);
@ -1327,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);
@ -1348,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);
@ -1365,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);
}
@ -1413,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;
}
@ -1427,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;
}
@ -1436,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;
}
@ -1471,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;
@ -1510,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,
@ -1878,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",
@ -1891,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");
@ -2017,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);
@ -2029,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) {
@ -2040,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;
@ -2061,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
@ -2107,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;
@ -2144,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;
@ -2198,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)
@ -2361,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
@ -2372,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,
@ -2422,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;
@ -2433,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;
@ -2448,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;
@ -2469,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, 0, NULL,
0, NULL, 0, KEY_FLAG_GROUP_RX_TX);
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;
}
@ -2499,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))
@ -2660,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;
@ -2690,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";
}

View File

@ -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);

View File

@ -220,7 +220,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
u16 capab = hostapd_own_capab_info(hapd);
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
int he = hapd->iconf->ieee80211ax;
int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
@ -256,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 */

View File

@ -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)

View File

@ -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;
}
}

View File

@ -165,6 +165,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);
@ -234,9 +235,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) {
@ -247,10 +246,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)
@ -328,6 +327,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);
@ -547,6 +547,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 =
@ -815,6 +816,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)",
@ -865,6 +867,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 - "
@ -1030,6 +1033,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;
@ -1136,6 +1146,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,
@ -1330,9 +1342,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)",
@ -1420,7 +1433,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%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]" : ""),
@ -1440,6 +1454,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
(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]" : ""));
@ -1493,3 +1508,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;
}

View File

@ -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 */
@ -358,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 */

View File

@ -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 &&

View File

@ -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);

View File

@ -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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -169,7 +169,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;
@ -177,6 +179,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;
@ -189,6 +192,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
@ -220,13 +224,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];
@ -238,7 +257,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 {
@ -285,6 +309,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,
@ -318,14 +343,16 @@ 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,
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,
@ -414,14 +441,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,
@ -438,6 +466,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);
@ -489,6 +518,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),
@ -502,5 +533,16 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
int wpa_auth_rekey_ptk(struct wpa_state_machine *sm, int early_install);
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 */

View File

@ -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)
@ -1897,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) {
@ -1985,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;
}
@ -2128,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,
@ -2140,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,
@ -2167,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;
@ -2198,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] |
@ -2237,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;
@ -2268,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);
@ -2282,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)
@ -2415,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;
@ -2442,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 ||
@ -2511,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;
@ -2522,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);
@ -2546,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;
@ -2584,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 (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;
@ -2632,7 +2803,16 @@ static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
}
void wpa_ft_install_ptk(struct wpa_state_machine *sm)
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, int retry)
{
enum wpa_alg alg;
int klen;
@ -2654,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,
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;
}
@ -2827,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)
@ -2957,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)) {
@ -3023,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");
@ -3060,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;
@ -3119,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;
@ -3132,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);
@ -3164,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;
@ -3182,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 {
@ -3195,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;
}
@ -3240,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;
}
@ -3309,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,
@ -3327,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 */
@ -3553,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);
@ -4433,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);
@ -4446,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;
}

View File

@ -41,6 +41,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
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;
@ -67,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
@ -120,14 +122,42 @@ 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) {
@ -144,6 +174,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
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);
@ -162,9 +198,16 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
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 */
}
@ -242,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)
@ -404,7 +446,11 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
}
#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);
@ -415,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) {
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;
@ -1000,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)
{
@ -1361,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,
@ -1376,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.");

View File

@ -40,20 +40,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];
@ -62,20 +62,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;
@ -94,8 +96,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];
@ -174,12 +177,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 {
@ -191,11 +194,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;
@ -275,7 +280,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,
@ -294,11 +300,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 */

View File

@ -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,
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)) {
/* 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;
}
wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
(data.capabilities & WPA_CAPABILITY_OCVC));
} else {
wpa_auth_set_ocv(sm, (data.capabilities & WPA_CAPABILITY_OCVC) ?
wpa_auth->conf.ocv : 0);
}
#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);

View File

@ -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;

View File

@ -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,
@ -363,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;
@ -372,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))
@ -386,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,
@ -558,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;
@ -567,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;
@ -610,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) {
@ -650,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=") ||
@ -1157,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)
@ -1176,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) {
@ -1195,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)
@ -1202,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) {
@ -1213,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) &&
@ -1259,8 +1304,6 @@ int hostapd_init_wps(struct hostapd_data *hapd,
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))
@ -1798,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
@ -1808,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

109
src/build.rules Normal file
View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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
*
@ -383,9 +388,10 @@ enum mesh_plink_state {
};
enum set_band {
WPA_SETBAND_AUTO,
WPA_SETBAND_5G,
WPA_SETBAND_2G
WPA_SETBAND_AUTO = 0,
WPA_SETBAND_5G = BIT(0),
WPA_SETBAND_2G = BIT(1),
WPA_SETBAND_6G = BIT(2),
};
enum wpa_radio_work_band {
@ -443,6 +449,27 @@ enum key_flag {
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 */

File diff suppressed because it is too large Load Diff

View File

@ -20,9 +20,22 @@
struct crypto_ecdh;
struct hostapd_ip_addr;
struct dpp_global;
struct json_token;
struct dpp_reconfig_id;
#ifdef CONFIG_TESTING_OPTIONS
#define DPP_VERSION (dpp_version_override)
extern int dpp_version_override;
#else /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_DPP2
#define DPP_VERSION 2
#else
#define DPP_VERSION 1
#endif
#endif /* CONFIG_TESTING_OPTIONS */
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
#define DPP_TCP_PORT 7871
#define DPP_TCP_PORT 8908
enum dpp_public_action_frame_type {
DPP_PA_AUTHENTICATION_REQ = 0,
@ -36,6 +49,11 @@ enum dpp_public_action_frame_type {
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
DPP_PA_CONFIGURATION_RESULT = 11,
DPP_PA_CONNECTION_STATUS_RESULT = 12,
DPP_PA_PRESENCE_ANNOUNCEMENT = 13,
DPP_PA_RECONFIG_ANNOUNCEMENT = 14,
DPP_PA_RECONFIG_AUTH_REQ = 15,
DPP_PA_RECONFIG_AUTH_RESP = 16,
DPP_PA_RECONFIG_AUTH_CONF = 17,
};
enum dpp_attribute_id {
@ -67,6 +85,12 @@ enum dpp_attribute_id {
DPP_ATTR_ENVELOPED_DATA = 0x101A,
DPP_ATTR_SEND_CONN_STATUS = 0x101B,
DPP_ATTR_CONN_STATUS = 0x101C,
DPP_ATTR_RECONFIG_FLAGS = 0x101D,
DPP_ATTR_C_SIGN_KEY_HASH = 0x101E,
DPP_ATTR_CSR_ATTR_REQ = 0x101F,
DPP_ATTR_A_NONCE = 0x1020,
DPP_ATTR_E_PRIME_ID = 0x1021,
DPP_ATTR_CONFIGURATOR_NONCE = 0x1022,
};
enum dpp_status_error {
@ -81,6 +105,15 @@ enum dpp_status_error {
DPP_STATUS_NO_MATCH = 8,
DPP_STATUS_CONFIG_REJECTED = 9,
DPP_STATUS_NO_AP = 10,
DPP_STATUS_CONFIGURE_PENDING = 11,
DPP_STATUS_CSR_NEEDED = 12,
DPP_STATUS_CSR_BAD = 13,
};
/* DPP Reconfig Flags object - connectorKey values */
enum dpp_connector_key {
DPP_CONFIG_REUSEKEY = 0,
DPP_CONFIG_REPLACEKEY = 1,
};
#define DPP_CAPAB_ENROLLEE BIT(0)
@ -91,6 +124,7 @@ enum dpp_status_error {
#define DPP_MAX_NONCE_LEN 32
#define DPP_MAX_HASH_LEN 64
#define DPP_MAX_SHARED_SECRET_LEN 66
#define DPP_CP_LEN 64
struct dpp_curve_params {
const char *name;
@ -120,12 +154,18 @@ struct dpp_bootstrap_info {
char *pk;
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
unsigned int num_freq;
bool channels_listed;
u8 version;
int own;
EVP_PKEY *pubkey;
u8 pubkey_hash[SHA256_MAC_LEN];
u8 pubkey_hash_chirp[SHA256_MAC_LEN];
const struct dpp_curve_params *curve;
unsigned int pkex_t; /* number of failures before dpp_pkex
* instantiation */
int nfc_negotiated; /* whether this has been used in NFC negotiated
* connection handover */
char *configurator_params;
};
#define PKEX_COUNTER_T_LIMIT 5
@ -162,6 +202,7 @@ enum dpp_akm {
DPP_AKM_PSK_SAE,
DPP_AKM_SAE_DPP,
DPP_AKM_PSK_SAE_DPP,
DPP_AKM_DOT1X,
};
enum dpp_netrole {
@ -187,11 +228,14 @@ struct dpp_configuration {
char *passphrase;
u8 psk[32];
int psk_set;
char *csrattrs;
};
struct dpp_asymmetric_key {
struct dpp_asymmetric_key *next;
EVP_PKEY *csign;
EVP_PKEY *pp_key;
char *config_template;
char *connector_template;
};
@ -199,26 +243,36 @@ struct dpp_asymmetric_key {
#define DPP_MAX_CONF_OBJ 10
struct dpp_authentication {
struct dpp_global *global;
void *msg_ctx;
u8 peer_version;
const struct dpp_curve_params *curve;
struct dpp_bootstrap_info *peer_bi;
struct dpp_bootstrap_info *own_bi;
struct dpp_bootstrap_info *tmp_own_bi;
struct dpp_bootstrap_info *tmp_peer_bi;
u8 waiting_pubkey_hash[SHA256_MAC_LEN];
int response_pending;
int reconfig;
enum dpp_connector_key reconfig_connector_key;
enum dpp_status_error auth_resp_status;
enum dpp_status_error conf_resp_status;
enum dpp_status_error force_conf_resp_status;
u8 peer_mac_addr[ETH_ALEN];
u8 i_nonce[DPP_MAX_NONCE_LEN];
u8 r_nonce[DPP_MAX_NONCE_LEN];
u8 e_nonce[DPP_MAX_NONCE_LEN];
u8 c_nonce[DPP_MAX_NONCE_LEN];
u8 i_capab;
u8 r_capab;
enum dpp_netrole e_netrole;
EVP_PKEY *own_protocol_key;
EVP_PKEY *peer_protocol_key;
EVP_PKEY *reconfig_old_protocol_key;
struct wpabuf *req_msg;
struct wpabuf *resp_msg;
struct wpabuf *reconfig_req_msg;
struct wpabuf *reconfig_resp_msg;
/* Intersection of possible frequencies for initiating DPP
* Authentication exchange */
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
@ -236,6 +290,7 @@ struct dpp_authentication {
u8 k1[DPP_MAX_HASH_LEN];
u8 k2[DPP_MAX_HASH_LEN];
u8 ke[DPP_MAX_HASH_LEN];
u8 bk[DPP_MAX_HASH_LEN];
int initiator;
int waiting_auth_resp;
int waiting_auth_conf;
@ -248,8 +303,10 @@ struct dpp_authentication {
int waiting_conf_result;
int waiting_conn_status_result;
int auth_success;
bool reconfig_success;
struct wpabuf *conf_req;
const struct wpabuf *conf_resp; /* owned by GAS server */
struct wpabuf *conf_resp_tcp;
struct dpp_configuration *conf_ap;
struct dpp_configuration *conf2_ap;
struct dpp_configuration *conf_sta;
@ -266,6 +323,11 @@ struct dpp_authentication {
int psk_set;
enum dpp_akm akm;
struct wpabuf *c_sign_key;
struct wpabuf *certbag;
struct wpabuf *certs;
struct wpabuf *cacert;
char *server_name;
struct wpabuf *pp_key;
} conf_obj[DPP_MAX_CONF_OBJ];
unsigned int num_conf_obj;
struct dpp_asymmetric_key *conf_key_pkg;
@ -274,6 +336,18 @@ struct dpp_authentication {
int send_conn_status;
int conn_status_requested;
int akm_use_selector;
int configurator_set;
u8 transaction_id;
u8 *csrattrs;
size_t csrattrs_len;
bool waiting_csr;
struct wpabuf *csr;
struct wpabuf *priv_key; /* DER-encoded private key used for csr */
bool waiting_cert;
char *trusted_eap_server_name;
struct wpabuf *cacert;
struct wpabuf *certbag;
void *cert_resp_ctx;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
@ -287,8 +361,12 @@ struct dpp_configurator {
unsigned int id;
int own;
EVP_PKEY *csign;
u8 kid_hash[SHA256_MAC_LEN];
char *kid;
const struct dpp_curve_params *curve;
char *connector; /* own Connector for reconfiguration */
EVP_PKEY *connector_key;
EVP_PKEY *pp_key;
};
struct dpp_introduction {
@ -301,6 +379,7 @@ struct dpp_relay_config {
const struct hostapd_ip_addr *ipaddr;
const u8 *pkhash;
void *msg_ctx;
void *cb_ctx;
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
size_t len);
@ -311,6 +390,12 @@ struct dpp_relay_config {
struct dpp_controller_config {
const char *configurator_params;
int tcp_port;
u8 allowed_roles;
int qr_mutual;
enum dpp_netrole netrole;
void *msg_ctx;
void *cb_ctx;
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
};
#ifdef CONFIG_TESTING_OPTIONS
@ -422,15 +507,16 @@ extern size_t dpp_nonce_override_len;
void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type);
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
const char *chan_list);
int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
struct dpp_bootstrap_info *peer_bi);
struct dpp_authentication *
dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx);
struct hostapd_hw_modes;
struct dpp_authentication * dpp_auth_init(void *msg_ctx,
struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
u8 dpp_allowed_roles,
@ -438,8 +524,8 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx,
struct hostapd_hw_modes *own_modes,
u16 num_modes);
struct dpp_authentication *
dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
struct dpp_bootstrap_info *peer_bi,
dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
int qr_mutual, struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi,
unsigned int freq, const u8 *hdr, const u8 *attr_start,
size_t attr_len);
@ -464,11 +550,13 @@ int dpp_akm_dpp(enum dpp_akm akm);
int dpp_akm_ver2(enum dpp_akm akm);
int dpp_configuration_valid(const struct dpp_configuration *conf);
void dpp_configuration_free(struct dpp_configuration *conf);
int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
struct dpp_authentication *auth,
const char *cmd);
int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd);
void dpp_auth_deinit(struct dpp_authentication *auth);
struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
u16 e_nonce_len, enum dpp_netrole netrole,
bool cert_req);
struct wpabuf *
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
size_t attr_len);
int dpp_conf_resp_rx(struct dpp_authentication *auth,
@ -498,9 +586,6 @@ const char * dpp_akm_selector_str(enum dpp_akm akm);
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
size_t buflen);
void dpp_configurator_free(struct dpp_configurator *conf);
struct dpp_configurator *
dpp_keygen_configurator(const char *curve, const u8 *privkey,
size_t privkey_len);
int dpp_configurator_own_config(struct dpp_authentication *auth,
const char *curve, int ap);
enum dpp_status_error
@ -545,6 +630,11 @@ struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
void dpp_pfs_free(struct dpp_pfs *pfs);
struct wpabuf * dpp_build_csr(struct dpp_authentication *auth,
const char *name);
struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7);
int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr);
struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
const char *uri);
struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
@ -559,16 +649,21 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
int dpp_bootstrap_info(struct dpp_global *dpp, int id,
char *reply, int reply_size);
int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params);
void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
const u8 *r_bootstrap,
struct dpp_bootstrap_info **own_bi,
struct dpp_bootstrap_info **peer_bi);
struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
const u8 *hash);
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
char *buf, size_t buflen);
int dpp_configurator_from_backup(struct dpp_global *dpp,
struct dpp_asymmetric_key *key);
struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
const u8 *kid);
int dpp_relay_add_controller(struct dpp_global *dpp,
struct dpp_relay_config *config);
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
@ -579,18 +674,61 @@ int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config);
void dpp_controller_stop(struct dpp_global *dpp);
struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
unsigned int id);
void dpp_controller_new_qr_code(struct dpp_global *dpp,
struct dpp_bootstrap_info *bi);
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
const struct hostapd_ip_addr *addr, int port);
const struct hostapd_ip_addr *addr, int port,
const char *name, enum dpp_netrole netrole, void *msg_ctx,
void *cb_ctx,
int (*process_conf_obj)(void *ctx,
struct dpp_authentication *auth));
struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
unsigned int freq, const u8 *hash);
struct dpp_global_config {
void *msg_ctx;
void *cb_ctx;
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
};
struct dpp_global * dpp_global_init(struct dpp_global_config *config);
void dpp_global_clear(struct dpp_global *dpp);
void dpp_global_deinit(struct dpp_global *dpp);
/* dpp_reconfig.c */
struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
size_t csign_key_len,
const u8 *net_access_key,
size_t net_access_key_len,
struct dpp_reconfig_id *id);
struct dpp_authentication *
dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
struct dpp_configurator *conf, unsigned int freq, u16 group,
const u8 *a_nonce_attr, size_t a_nonce_len,
const u8 *e_id_attr, size_t e_id_len);
struct dpp_authentication *
dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
const char *own_connector,
const u8 *net_access_key, size_t net_access_key_len,
const u8 *csign_key, size_t csign_key_len,
unsigned int freq, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
struct wpabuf *
dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
size_t csign_key_len,
const u8 *pp_key,
size_t pp_key_len);
int dpp_update_reconfig_id(struct dpp_reconfig_id *id);
void dpp_free_reconfig_id(struct dpp_reconfig_id *id);
#endif /* CONFIG_DPP */
#endif /* DPP_H */

1976
src/common/dpp_auth.c Normal file

File diff suppressed because it is too large Load Diff

1292
src/common/dpp_backup.c Normal file

File diff suppressed because it is too large Load Diff

3329
src/common/dpp_crypto.c Normal file

File diff suppressed because it is too large Load Diff

160
src/common/dpp_i.h Normal file
View File

@ -0,0 +1,160 @@
/*
* DPP module internal definitions
* 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.
*/
#ifndef DPP_I_H
#define DPP_I_H
#ifdef CONFIG_DPP
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);
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
#endif /* CONFIG_DPP2 */
};
/* dpp.c */
void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status);
void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash);
unsigned int dpp_next_id(struct dpp_global *dpp);
struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
const u8 *ssid, size_t ssid_len,
const char *channel_list);
struct json_token * dpp_parse_own_connector(const char *own_connector);
int dpp_connector_match_groups(struct json_token *own_root,
struct json_token *peer_root, bool reconfig);
int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
const char *kid, const struct dpp_curve_params *curve);
EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
const struct dpp_curve_params **key_curve);
int dpp_prepare_channel_list(struct dpp_authentication *auth,
unsigned int neg_freq,
struct hostapd_hw_modes *own_modes, u16 num_modes);
void dpp_auth_fail(struct dpp_authentication *auth, const char *txt);
int dpp_gen_uri(struct dpp_bootstrap_info *bi);
void dpp_write_adv_proto(struct wpabuf *buf);
void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query);
/* dpp_backup.c */
void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key);
struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth);
int dpp_conf_resp_env_data(struct dpp_authentication *auth,
const u8 *env_data, size_t env_data_len);
/* dpp_crypto.c */
struct dpp_signed_connector_info {
unsigned char *payload;
size_t payload_len;
};
enum dpp_status_error
dpp_process_signed_connector(struct dpp_signed_connector_info *info,
EVP_PKEY *csign_pub, const char *connector);
enum dpp_status_error
dpp_check_signed_connector(struct dpp_signed_connector_info *info,
const u8 *csign_key, size_t csign_key_len,
const u8 *peer_connector, size_t peer_connector_len);
const struct dpp_curve_params * dpp_get_curve_name(const char *name);
const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name);
const struct dpp_curve_params * dpp_get_curve_nid(int nid);
const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group);
int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
const u8 *data, size_t data_len);
struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix);
EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
const u8 *buf_x, const u8 *buf_y,
size_t len);
EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len);
int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len);
int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
const char *label, u8 *out, size_t outlen);
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);
int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer, u8 *secret, size_t *secret_len);
void dpp_debug_print_point(const char *title, const EC_GROUP *group,
const EC_POINT *point);
void dpp_debug_print_key(const char *title, EVP_PKEY *key);
int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
const u8 *salt, size_t salt_len, unsigned int iterations,
u8 *buf, size_t buflen);
int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi,
const u8 *data, size_t data_len);
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
const u8 *privkey, size_t privkey_len);
EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
const u8 *privkey, size_t privkey_len);
EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve);
int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len);
int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len);
int dpp_derive_bk_ke(struct dpp_authentication *auth);
int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth);
int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth);
int dpp_auth_derive_l_responder(struct dpp_authentication *auth);
int dpp_auth_derive_l_initiator(struct dpp_authentication *auth);
int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, unsigned int hash_len);
int dpp_derive_pmkid(const struct dpp_curve_params *curve,
EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid);
EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
const u8 *mac_init, const char *code,
const char *identifier, BN_CTX *bnctx,
EC_GROUP **ret_group);
EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
const u8 *mac_resp, const char *code,
const char *identifier, BN_CTX *bnctx,
EC_GROUP **ret_group);
int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
const u8 *Mx, size_t Mx_len,
const u8 *Nx, size_t Nx_len,
const char *code,
const u8 *Kx, size_t Kx_len,
u8 *z, unsigned int hash_len);
int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
const u8 *net_access_key,
size_t net_access_key_len,
struct json_token *peer_net_access_key);
int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
const u8 *r_proto, u16 r_proto_len,
struct json_token *net_access_key);
EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
EVP_PKEY *e_prime_id);
char * dpp_sign_connector(struct dpp_configurator *conf,
const struct wpabuf *dppcon);
int dpp_test_gen_invalid_key(struct wpabuf *msg,
const struct dpp_curve_params *curve);
struct dpp_reconfig_id {
const EC_GROUP *group;
EC_POINT *e_id; /* E-id */
EVP_PKEY *csign;
EVP_PKEY *a_nonce; /* A-NONCE */
EVP_PKEY *e_prime_id; /* E'-id */
EVP_PKEY *pp_key;
};
/* dpp_tcp.c */
void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
void *timeout_ctx);
void dpp_tcp_init_flush(struct dpp_global *dpp);
void dpp_relay_flush_controllers(struct dpp_global *dpp);
#endif /* CONFIG_DPP */
#endif /* DPP_I_H */

1324
src/common/dpp_pkex.c Normal file

File diff suppressed because it is too large Load Diff

958
src/common/dpp_reconfig.c Normal file
View File

@ -0,0 +1,958 @@
/*
* DPP reconfiguration
* Copyright (c) 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 <openssl/opensslv.h>
#include <openssl/err.h>
#include "utils/common.h"
#include "utils/json.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
#include "dpp.h"
#include "dpp_i.h"
#ifdef CONFIG_DPP2
static void dpp_build_attr_csign_key_hash(struct wpabuf *msg, const u8 *hash)
{
if (hash) {
wpa_printf(MSG_DEBUG, "DPP: Configurator C-sign key Hash");
wpabuf_put_le16(msg, DPP_ATTR_C_SIGN_KEY_HASH);
wpabuf_put_le16(msg, SHA256_MAC_LEN);
wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
}
}
struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
size_t csign_key_len,
const u8 *net_access_key,
size_t net_access_key_len,
struct dpp_reconfig_id *id)
{
struct wpabuf *msg = NULL;
EVP_PKEY *csign = NULL;
const unsigned char *p;
struct wpabuf *uncomp;
u8 hash[SHA256_MAC_LEN];
const u8 *addr[1];
size_t len[1];
int res;
size_t attr_len;
const struct dpp_curve_params *own_curve;
EVP_PKEY *own_key;
struct wpabuf *a_nonce = NULL, *e_id = NULL;
wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame");
own_key = dpp_set_keypair(&own_curve, net_access_key,
net_access_key_len);
if (!own_key) {
wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
goto fail;
}
p = csign_key;
csign = d2i_PUBKEY(NULL, &p, csign_key_len);
if (!csign) {
wpa_printf(MSG_ERROR,
"DPP: Failed to parse local C-sign-key information");
goto fail;
}
uncomp = dpp_get_pubkey_point(csign, 1);
EVP_PKEY_free(csign);
if (!uncomp)
goto fail;
addr[0] = wpabuf_head(uncomp);
len[0] = wpabuf_len(uncomp);
wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed C-sign key", addr[0], len[0]);
res = sha256_vector(1, addr, len, hash);
wpabuf_free(uncomp);
if (res < 0)
goto fail;
wpa_hexdump(MSG_DEBUG, "DPP: kid = SHA256(uncompressed C-sign key)",
hash, SHA256_MAC_LEN);
if (dpp_update_reconfig_id(id) < 0) {
wpa_printf(MSG_ERROR, "DPP: Failed to generate E'-id");
goto fail;
}
a_nonce = dpp_get_pubkey_point(id->a_nonce, 0);
e_id = dpp_get_pubkey_point(id->e_prime_id, 0);
if (!a_nonce || !e_id)
goto fail;
attr_len = 4 + SHA256_MAC_LEN;
attr_len += 4 + 2;
attr_len += 4 + wpabuf_len(a_nonce);
attr_len += 4 + wpabuf_len(e_id);
msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, attr_len);
if (!msg)
goto fail;
/* Configurator C-sign key Hash */
dpp_build_attr_csign_key_hash(msg, hash);
/* Finite Cyclic Group attribute */
wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
own_curve->ike_group);
wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
wpabuf_put_le16(msg, 2);
wpabuf_put_le16(msg, own_curve->ike_group);
/* A-NONCE */
wpabuf_put_le16(msg, DPP_ATTR_A_NONCE);
wpabuf_put_le16(msg, wpabuf_len(a_nonce));
wpabuf_put_buf(msg, a_nonce);
/* E'-id */
wpabuf_put_le16(msg, DPP_ATTR_E_PRIME_ID);
wpabuf_put_le16(msg, wpabuf_len(e_id));
wpabuf_put_buf(msg, e_id);
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Reconfig Announcement frame attributes", msg);
fail:
wpabuf_free(a_nonce);
wpabuf_free(e_id);
EVP_PKEY_free(own_key);
return msg;
}
static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth)
{
struct wpabuf *msg;
size_t attr_len;
/* Build DPP Reconfig Authentication Request frame attributes */
attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) +
4 + auth->curve->nonce_len;
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_REQ, attr_len);
if (!msg)
return NULL;
/* Transaction ID */
wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, auth->transaction_id);
/* Protocol Version */
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, DPP_VERSION);
/* DPP Connector */
wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
wpabuf_put_le16(msg, os_strlen(auth->conf->connector));
wpabuf_put_str(msg, auth->conf->connector);
/* C-nonce */
wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
wpabuf_put_le16(msg, auth->curve->nonce_len);
wpabuf_put_data(msg, auth->c_nonce, auth->curve->nonce_len);
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Reconfig Authentication Request frame attributes",
msg);
return msg;
}
static int
dpp_configurator_build_own_connector(struct dpp_configurator *conf,
const struct dpp_curve_params *curve)
{
struct wpabuf *dppcon = NULL;
int ret = -1;
if (conf->connector)
return 0; /* already generated */
wpa_printf(MSG_DEBUG,
"DPP: Sign own Configurator Connector for reconfiguration with curve %s",
conf->curve->name);
conf->connector_key = dpp_gen_keypair(curve);
if (!conf->connector_key)
goto fail;
/* Connector (JSON dppCon object) */
dppcon = wpabuf_alloc(1000 + 2 * curve->prime_len * 4 / 3);
if (!dppcon)
goto fail;
json_start_object(dppcon, NULL);
json_start_array(dppcon, "groups");
json_start_object(dppcon, NULL);
json_add_string(dppcon, "groupId", "*");
json_value_sep(dppcon);
json_add_string(dppcon, "netRole", "configurator");
json_end_object(dppcon);
json_end_array(dppcon);
json_value_sep(dppcon);
if (dpp_build_jwk(dppcon, "netAccessKey", conf->connector_key, NULL,
curve) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
goto fail;
}
json_end_object(dppcon);
wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
(const char *) wpabuf_head(dppcon));
conf->connector = dpp_sign_connector(conf, dppcon);
if (!conf->connector)
goto fail;
wpa_printf(MSG_DEBUG, "DPP: signedConnector: %s", conf->connector);
ret = 0;
fail:
wpabuf_free(dppcon);
return ret;
}
struct dpp_authentication *
dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
struct dpp_configurator *conf, unsigned int freq, u16 group,
const u8 *a_nonce_attr, size_t a_nonce_len,
const u8 *e_id_attr, size_t e_id_len)
{
struct dpp_authentication *auth;
const struct dpp_curve_params *curve;
EVP_PKEY *a_nonce, *e_prime_id;
EC_POINT *e_id;
curve = dpp_get_curve_ike_group(group);
if (!curve) {
wpa_printf(MSG_DEBUG,
"DPP: Unsupported group %u - cannot reconfigure",
group);
return NULL;
}
if (!a_nonce_attr) {
wpa_printf(MSG_INFO, "DPP: Missing required A-NONCE attribute");
return NULL;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: A-NONCE", a_nonce_attr, a_nonce_len);
a_nonce = dpp_set_pubkey_point(conf->csign, a_nonce_attr, a_nonce_len);
if (!a_nonce) {
wpa_printf(MSG_INFO, "DPP: Invalid A-NONCE");
return NULL;
}
dpp_debug_print_key("A-NONCE", a_nonce);
if (!e_id_attr) {
wpa_printf(MSG_INFO, "DPP: Missing required E'-id attribute");
return NULL;
}
e_prime_id = dpp_set_pubkey_point(conf->csign, e_id_attr, e_id_len);
if (!e_prime_id) {
wpa_printf(MSG_INFO, "DPP: Invalid E'-id");
EVP_PKEY_free(a_nonce);
return NULL;
}
dpp_debug_print_key("E'-id", e_prime_id);
e_id = dpp_decrypt_e_id(conf->pp_key, a_nonce, e_prime_id);
EVP_PKEY_free(a_nonce);
EVP_PKEY_free(e_prime_id);
if (!e_id) {
wpa_printf(MSG_INFO, "DPP: Could not decrypt E'-id");
return NULL;
}
/* TODO: could use E-id to determine whether reconfiguration with this
* Enrollee has already been started and is waiting for updated
* configuration instead of replying again before such configuration
* becomes available */
EC_POINT_clear_free(e_id);
auth = dpp_alloc_auth(dpp, msg_ctx);
if (!auth)
return NULL;
auth->conf = conf;
auth->reconfig = 1;
auth->initiator = 1;
auth->waiting_auth_resp = 1;
auth->allowed_roles = DPP_CAPAB_CONFIGURATOR;
auth->configurator = 1;
auth->curve = curve;
auth->transaction_id = 1;
if (freq && dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
goto fail;
if (dpp_configurator_build_own_connector(conf, curve) < 0)
goto fail;
if (random_get_bytes(auth->c_nonce, auth->curve->nonce_len)) {
wpa_printf(MSG_ERROR, "DPP: Failed to generate C-nonce");
goto fail;
}
auth->reconfig_req_msg = dpp_reconfig_build_req(auth);
if (!auth->reconfig_req_msg)
goto fail;
out:
return auth;
fail:
dpp_auth_deinit(auth);
auth = NULL;
goto out;
}
static int dpp_reconfig_build_resp(struct dpp_authentication *auth,
const char *own_connector,
struct wpabuf *conn_status)
{
struct wpabuf *msg = NULL, *clear, *pr = NULL;
u8 *attr_start, *attr_end;
size_t clear_len, attr_len, len[2];
const u8 *addr[2];
u8 *wrapped;
int res = -1;
/* Build DPP Reconfig Authentication Response frame attributes */
clear_len = 4 + auth->curve->nonce_len +
4 + wpabuf_len(conn_status);
clear = wpabuf_alloc(clear_len);
if (!clear)
goto fail;
/* C-nonce (wrapped) */
wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
wpabuf_put_le16(clear, auth->curve->nonce_len);
wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
/* Connection Status (wrapped) */
wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
wpabuf_put_le16(clear, wpabuf_len(conn_status));
wpabuf_put_buf(clear, conn_status);
pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
if (!pr)
goto fail;
attr_len = 4 + 1 + 4 + 1 +
4 + os_strlen(own_connector) +
4 + auth->curve->nonce_len +
4 + wpabuf_len(pr) +
4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_RESP, attr_len);
if (!msg)
goto fail;
attr_start = wpabuf_put(msg, 0);
/* Transaction ID */
wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, auth->transaction_id);
/* Protocol Version */
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, DPP_VERSION);
/* R-Connector */
wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
wpabuf_put_le16(msg, os_strlen(own_connector));
wpabuf_put_str(msg, own_connector);
/* E-nonce */
wpabuf_put_le16(msg, DPP_ATTR_ENROLLEE_NONCE);
wpabuf_put_le16(msg, auth->curve->nonce_len);
wpabuf_put_data(msg, auth->e_nonce, auth->curve->nonce_len);
/* Responder Protocol Key (Pr) */
wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
wpabuf_put_le16(msg, wpabuf_len(pr));
wpabuf_put_buf(msg, pr);
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]);
/* Wrapped Data: {C-nonce, E-nonce, Connection Status}ke */
wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
wpabuf_head(clear), wpabuf_len(clear),
2, addr, len, wrapped) < 0)
goto fail;
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Reconfig Authentication Response frame attributes",
msg);
wpabuf_free(auth->reconfig_resp_msg);
auth->reconfig_resp_msg = msg;
res = 0;
out:
wpabuf_free(clear);
wpabuf_free(pr);
return res;
fail:
wpabuf_free(msg);
goto out;
}
struct dpp_authentication *
dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
const char *own_connector,
const u8 *net_access_key, size_t net_access_key_len,
const u8 *csign_key, size_t csign_key_len,
unsigned int freq, const u8 *hdr,
const u8 *attr_start, size_t attr_len)
{
struct dpp_authentication *auth = NULL;
const u8 *trans_id, *version, *i_connector, *c_nonce;
u16 trans_id_len, version_len, i_connector_len, c_nonce_len;
struct dpp_signed_connector_info info;
enum dpp_status_error res;
struct json_token *root = NULL, *own_root = NULL, *token;
unsigned char *own_conn = NULL;
struct wpabuf *conn_status = NULL;
os_memset(&info, 0, sizeof(info));
trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID,
&trans_id_len);
if (!trans_id || trans_id_len != 1) {
wpa_printf(MSG_DEBUG,
"DPP: Peer did not include Transaction ID");
goto fail;
}
version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
&version_len);
if (!version || version_len < 1 || version[0] < 2) {
wpa_printf(MSG_DEBUG,
"DPP: Missing or invalid Protocol Version attribute");
goto fail;
}
i_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR,
&i_connector_len);
if (!i_connector) {
wpa_printf(MSG_DEBUG, "DPP: Missing I-Connector attribute");
goto fail;
}
wpa_hexdump_ascii(MSG_DEBUG, "DPP: I-Connector",
i_connector, i_connector_len);
c_nonce = dpp_get_attr(attr_start, attr_len,
DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
if (!c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) {
wpa_printf(MSG_DEBUG,
"DPP: Missing or invalid C-nonce attribute");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
i_connector, i_connector_len);
if (res != DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Invalid I-Connector");
goto fail;
}
root = json_parse((const char *) info.payload, info.payload_len);
own_root = dpp_parse_own_connector(own_connector);
if (!root || !own_root ||
!dpp_connector_match_groups(own_root, root, true)) {
wpa_printf(MSG_DEBUG,
"DPP: I-Connector does not include compatible group netrole with own connector");
goto fail;
}
token = json_get_member(root, "expiry");
if (token && token->type == JSON_STRING &&
dpp_key_expired(token->string, NULL)) {
wpa_printf(MSG_DEBUG,
"DPP: I-Connector (netAccessKey) has expired");
goto fail;
}
token = json_get_member(root, "netAccessKey");
if (!token || token->type != JSON_OBJECT) {
wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
goto fail;
}
auth = dpp_alloc_auth(dpp, msg_ctx);
if (!auth)
return NULL;
auth->reconfig = 1;
auth->allowed_roles = DPP_CAPAB_ENROLLEE;
if (dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
goto fail;
auth->transaction_id = trans_id[0];
auth->peer_version = version[0];
wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
auth->peer_version);
os_memcpy(auth->c_nonce, c_nonce, c_nonce_len);
if (dpp_reconfig_derive_ke_responder(auth, net_access_key,
net_access_key_len, token) < 0)
goto fail;
if (c_nonce_len != auth->curve->nonce_len) {
wpa_printf(MSG_DEBUG,
"DPP: Unexpected C-nonce length %u (curve nonce len %zu)",
c_nonce_len, auth->curve->nonce_len);
goto fail;
}
/* Build Connection Status object */
/* TODO: Get appropriate result value */
/* TODO: ssid64 and channelList */
conn_status = dpp_build_conn_status(DPP_STATUS_NO_AP, NULL, 0, NULL);
if (!conn_status)
goto fail;
if (dpp_reconfig_build_resp(auth, own_connector, conn_status) < 0)
goto fail;
out:
os_free(info.payload);
os_free(own_conn);
json_free(root);
json_free(own_root);
wpabuf_free(conn_status);
return auth;
fail:
dpp_auth_deinit(auth);
auth = NULL;
goto out;
}
struct wpabuf *
dpp_reconfig_build_conf(struct dpp_authentication *auth)
{
struct wpabuf *msg = NULL, *clear;
u8 *attr_start, *attr_end;
size_t clear_len, attr_len, len[2];
const u8 *addr[2];
u8 *wrapped;
u8 flags;
/* Build DPP Reconfig Authentication Confirm frame attributes */
clear_len = 4 + 1 + 4 + 1 + 2 * (4 + auth->curve->nonce_len) +
4 + 1;
clear = wpabuf_alloc(clear_len);
if (!clear)
goto fail;
/* Transaction ID */
wpabuf_put_le16(clear, DPP_ATTR_TRANSACTION_ID);
wpabuf_put_le16(clear, 1);
wpabuf_put_u8(clear, auth->transaction_id);
/* Protocol Version */
wpabuf_put_le16(clear, DPP_ATTR_PROTOCOL_VERSION);
wpabuf_put_le16(clear, 1);
wpabuf_put_u8(clear, auth->peer_version);
/* C-nonce (wrapped) */
wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
wpabuf_put_le16(clear, auth->curve->nonce_len);
wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
/* E-nonce (wrapped) */
wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
wpabuf_put_le16(clear, auth->curve->nonce_len);
wpabuf_put_data(clear, auth->e_nonce, auth->curve->nonce_len);
/* Reconfig-Flags (wrapped) */
flags = DPP_CONFIG_REPLACEKEY;
wpabuf_put_le16(clear, DPP_ATTR_RECONFIG_FLAGS);
wpabuf_put_le16(clear, 1);
wpabuf_put_u8(clear, flags);
attr_len = 4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
attr_len += 4 + 1;
msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_CONF, attr_len);
if (!msg)
goto fail;
attr_start = wpabuf_put(msg, 0);
/* DPP Status */
dpp_build_attr_status(msg, DPP_STATUS_OK);
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]);
/* Wrapped Data */
wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
wpabuf_head(clear), wpabuf_len(clear),
2, addr, len, wrapped) < 0)
goto fail;
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Reconfig Authentication Confirm frame attributes",
msg);
out:
wpabuf_free(clear);
return msg;
fail:
wpabuf_free(msg);
msg = NULL;
goto out;
}
struct wpabuf *
dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len)
{
const u8 *trans_id, *version, *r_connector, *r_proto, *wrapped_data,
*c_nonce, *e_nonce, *conn_status;
u16 trans_id_len, version_len, r_connector_len, r_proto_len,
wrapped_data_len, c_nonce_len, e_nonce_len, conn_status_len;
struct wpabuf *conf = NULL;
char *signed_connector = NULL;
struct dpp_signed_connector_info info;
enum dpp_status_error res;
struct json_token *root = NULL, *token, *conn_status_json = NULL;
const u8 *addr[2];
size_t len[2];
u8 *unwrapped = NULL;
size_t unwrapped_len = 0;
os_memset(&info, 0, sizeof(info));
if (!auth->reconfig || !auth->configurator)
goto fail;
wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len);
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
dpp_auth_fail(auth,
"Missing or invalid required Wrapped Data attribute");
goto fail;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
wrapped_data, wrapped_data_len);
attr_len = wrapped_data - 4 - attr_start;
trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID,
&trans_id_len);
if (!trans_id || trans_id_len != 1) {
dpp_auth_fail(auth, "Peer did not include Transaction ID");
goto fail;
}
if (trans_id[0] != auth->transaction_id) {
dpp_auth_fail(auth, "Transaction ID mismatch");
goto fail;
}
version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
&version_len);
if (!version || version_len < 1 || version[0] < 2) {
dpp_auth_fail(auth,
"Missing or invalid Protocol Version attribute");
goto fail;
}
auth->peer_version = version[0];
wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
auth->peer_version);
r_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR,
&r_connector_len);
if (!r_connector) {
dpp_auth_fail(auth, " Missing R-Connector attribute");
goto fail;
}
wpa_hexdump_ascii(MSG_DEBUG, "DPP: R-Connector",
r_connector, r_connector_len);
e_nonce = dpp_get_attr(attr_start, attr_len,
DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
dpp_auth_fail(auth, "Missing or invalid E-nonce");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
&r_proto_len);
if (!r_proto) {
dpp_auth_fail(auth,
"Missing required Responder Protocol Key attribute");
goto fail;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
r_proto, r_proto_len);
signed_connector = os_malloc(r_connector_len + 1);
if (!signed_connector)
goto fail;
os_memcpy(signed_connector, r_connector, r_connector_len);
signed_connector[r_connector_len] = '\0';
res = dpp_process_signed_connector(&info, auth->conf->csign,
signed_connector);
if (res != DPP_STATUS_OK) {
dpp_auth_fail(auth, "Invalid R-Connector");
goto fail;
}
root = json_parse((const char *) info.payload, info.payload_len);
if (!root) {
dpp_auth_fail(auth, "Invalid Connector payload");
goto fail;
}
/* Do not check netAccessKey expiration for reconfiguration to allow
* expired Connector to be updated. */
token = json_get_member(root, "netAccessKey");
if (!token || token->type != JSON_OBJECT) {
dpp_auth_fail(auth, "No netAccessKey object found");
goto fail;
}
if (dpp_reconfig_derive_ke_initiator(auth, r_proto, r_proto_len,
token) < 0)
goto fail;
addr[0] = hdr;
len[0] = DPP_HDR_LEN;
addr[1] = attr_start;
len[1] = attr_len;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
wrapped_data, wrapped_data_len);
unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
unwrapped = os_malloc(unwrapped_len);
if (!unwrapped)
goto fail;
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
wrapped_data, wrapped_data_len,
2, addr, len, unwrapped) < 0) {
dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
goto fail;
}
c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
dpp_auth_fail(auth, "Missing or invalid C-nonce");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
conn_status = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONN_STATUS, &conn_status_len);
if (!conn_status) {
dpp_auth_fail(auth, "Missing Connection Status attribute");
goto fail;
}
wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus",
conn_status, conn_status_len);
conn_status_json = json_parse((const char *) conn_status,
conn_status_len);
if (!conn_status_json) {
dpp_auth_fail(auth, "Could not parse connStatus");
goto fail;
}
/* TODO: use connStatus information */
conf = dpp_reconfig_build_conf(auth);
if (conf)
auth->reconfig_success = true;
out:
json_free(root);
json_free(conn_status_json);
bin_clear_free(unwrapped, unwrapped_len);
os_free(info.payload);
os_free(signed_connector);
return conf;
fail:
wpabuf_free(conf);
conf = NULL;
goto out;
}
int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len)
{
const u8 *trans_id, *version, *wrapped_data, *c_nonce, *e_nonce,
*reconfig_flags, *status;
u16 trans_id_len, version_len, wrapped_data_len, c_nonce_len,
e_nonce_len, reconfig_flags_len, status_len;
const u8 *addr[2];
size_t len[2];
u8 *unwrapped = NULL;
size_t unwrapped_len = 0;
int res = -1;
u8 flags;
if (!auth->reconfig || auth->configurator)
goto fail;
wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len);
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
dpp_auth_fail(auth,
"Missing or invalid required Wrapped Data attribute");
goto fail;
}
wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
wrapped_data, wrapped_data_len);
attr_len = wrapped_data - 4 - attr_start;
status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
&status_len);
if (!status || status_len < 1) {
dpp_auth_fail(auth,
"Missing or invalid required DPP Status attribute");
goto fail;
}
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
if (status[0] != DPP_STATUS_OK) {
dpp_auth_fail(auth,
"Reconfiguration did not complete successfully");
goto fail;
}
addr[0] = hdr;
len[0] = DPP_HDR_LEN;
addr[1] = attr_start;
len[1] = attr_len;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
wrapped_data, wrapped_data_len);
unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
unwrapped = os_malloc(unwrapped_len);
if (!unwrapped)
goto fail;
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
wrapped_data, wrapped_data_len,
2, addr, len, unwrapped) < 0) {
dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
goto fail;
}
trans_id = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_TRANSACTION_ID, &trans_id_len);
if (!trans_id || trans_id_len != 1 ||
trans_id[0] != auth->transaction_id) {
dpp_auth_fail(auth,
"Peer did not include valid Transaction ID");
goto fail;
}
version = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_PROTOCOL_VERSION, &version_len);
if (!version || version_len < 1 || version[0] != DPP_VERSION) {
dpp_auth_fail(auth,
"Missing or invalid Protocol Version attribute");
goto fail;
}
c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
dpp_auth_fail(auth, "Missing or invalid C-nonce");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
if (!e_nonce || e_nonce_len != auth->curve->nonce_len ||
os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
dpp_auth_fail(auth, "Missing or invalid E-nonce");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
reconfig_flags = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_RECONFIG_FLAGS,
&reconfig_flags_len);
if (!reconfig_flags || reconfig_flags_len < 1) {
dpp_auth_fail(auth, "Missing or invalid Reconfig-Flags");
goto fail;
}
flags = reconfig_flags[0] & BIT(0);
wpa_printf(MSG_DEBUG, "DPP: Reconfig Flags connectorKey=%u", flags);
auth->reconfig_connector_key = flags;
auth->reconfig_success = true;
res = 0;
fail:
bin_clear_free(unwrapped, unwrapped_len);
return res;
}
#endif /* CONFIG_DPP2 */

1794
src/common/dpp_tcp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2017, Qualcomm Atheros, Inc.
* Copyright (c) 2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -23,8 +24,9 @@ struct gas_server_handler {
struct dl_list list;
u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
u8 adv_proto_id_len;
struct wpabuf * (*req_cb)(void *ctx, const u8 *sa,
const u8 *query, size_t query_len);
struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
const u8 *query, size_t query_len,
u16 *comeback_delay);
void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
void *ctx;
struct gas_server *gas;
@ -39,6 +41,7 @@ struct gas_server_response {
u8 dst[ETH_ALEN];
u8 dialog_token;
struct gas_server_handler *handler;
u16 comeback_delay;
};
struct gas_server {
@ -61,7 +64,8 @@ static void gas_server_response_timeout(void *eloop_ctx, void *user_ctx)
response, MAC2STR(response->dst), response->dialog_token,
response->freq, response->frag_id,
(unsigned long) response->offset,
(unsigned long) wpabuf_len(response->resp));
(unsigned long) (response->resp ?
wpabuf_len(response->resp) : 0));
response->handler->status_cb(response->handler->ctx,
response->resp, 0);
response->resp = NULL;
@ -83,30 +87,29 @@ static void gas_server_free_response(struct gas_server_response *response)
static void
gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
struct gas_server_response *response,
const u8 *da, int freq, u8 dialog_token,
struct wpabuf *query_resp)
struct wpabuf *query_resp, u16 comeback_delay)
{
size_t max_len = (freq > 56160) ? 928 : 1400;
size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
size_t resp_frag_len;
struct wpabuf *resp;
u16 comeback_delay;
struct gas_server_response *response;
if (!query_resp)
return;
response = os_zalloc(sizeof(*response));
if (!response) {
wpabuf_free(query_resp);
if (comeback_delay == 0 && !query_resp) {
gas_server_free_response(response);
return;
}
wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
response->freq = freq;
response->handler = handler;
os_memcpy(response->dst, da, ETH_ALEN);
response->dialog_token = dialog_token;
if (hdr_len + wpabuf_len(query_resp) > max_len) {
if (comeback_delay) {
/* Need more time to prepare the response */
resp_frag_len = 0;
response->comeback_delay = comeback_delay;
} else if (hdr_len + wpabuf_len(query_resp) > max_len) {
/* Need to use comeback to initiate fragmentation */
comeback_delay = 1;
resp_frag_len = 0;
@ -135,10 +138,12 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
/* Query Response Length */
wpabuf_put_le16(resp, resp_frag_len);
if (!comeback_delay)
if (!comeback_delay && query_resp)
wpabuf_put_buf(resp, query_resp);
if (comeback_delay) {
if (comeback_delay && !query_resp) {
wpa_printf(MSG_DEBUG, "GAS: No response available yet");
} else if (comeback_delay) {
wpa_printf(MSG_DEBUG,
"GAS: Need to fragment query response");
} else {
@ -165,6 +170,7 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
u16 query_req_len;
struct gas_server_handler *handler;
struct wpabuf *resp;
struct gas_server_response *response;
wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
data, len);
@ -210,8 +216,15 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
pos, end - pos);
}
response = os_zalloc(sizeof(*response));
if (!response)
return -1;
wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
list) {
u16 comeback_delay = 0;
if (adv_proto_len < 1 + handler->adv_proto_id_len ||
os_memcmp(adv_proto + 1, handler->adv_proto_id,
handler->adv_proto_id_len) != 0)
@ -219,17 +232,22 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
wpa_printf(MSG_DEBUG,
"GAS: Calling handler for the requested Advertisement Protocol ID");
resp = handler->req_cb(handler->ctx, sa, query_req,
query_req_len);
resp = handler->req_cb(handler->ctx, response, sa, query_req,
query_req_len, &comeback_delay);
wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
resp);
gas_server_send_resp(gas, handler, sa, freq, dialog_token,
resp);
if (comeback_delay)
wpa_printf(MSG_DEBUG,
"GAS: Handler requested comeback delay: %u TU",
comeback_delay);
gas_server_send_resp(gas, handler, response, sa, freq,
dialog_token, resp, comeback_delay);
return 0;
}
wpa_printf(MSG_DEBUG,
"GAS: No registered handler for the requested Advertisement Protocol ID");
gas_server_free_response(response);
return -1;
}
@ -243,6 +261,31 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
size_t hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
size_t remaining, resp_frag_len;
struct wpabuf *resp;
unsigned int wait_time = 0;
if (!response->resp) {
resp = gas_build_comeback_resp(response->dialog_token,
WLAN_STATUS_SUCCESS, 0, 0,
response->comeback_delay,
handler->adv_proto_id_len);
if (!resp) {
dl_list_del(&response->list);
gas_server_free_response(response);
return;
}
/* Advertisement Protocol element */
wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
wpabuf_put_u8(resp, 0x7f);
/* Advertisement Protocol ID */
wpabuf_put_data(resp, handler->adv_proto_id,
handler->adv_proto_id_len);
/* Query Response Length */
wpabuf_put_le16(resp, 0);
goto send_resp;
}
remaining = wpabuf_len(response->resp) - response->offset;
if (hdr_len + remaining > max_len)
@ -279,8 +322,11 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
response->offset += resp_frag_len;
gas->tx(gas->ctx, response->freq, response->dst, resp,
remaining > resp_frag_len ? 2000 : 0);
if (remaining > resp_frag_len)
wait_time = 2000;
send_resp:
gas->tx(gas->ctx, response->freq, response->dst, resp, wait_time);
wpabuf_free(resp);
}
@ -359,12 +405,19 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
static void gas_server_handle_tx_status(struct gas_server_response *response,
int ack)
{
if (ack && response->offset < wpabuf_len(response->resp)) {
if (ack && response->resp &&
response->offset < wpabuf_len(response->resp)) {
wpa_printf(MSG_DEBUG,
"GAS: More fragments remaining - keep pending entry");
return;
}
if (ack && !response->resp && response->comeback_delay) {
wpa_printf(MSG_DEBUG,
"GAS: Waiting for response - keep pending entry");
return;
}
if (!ack)
wpa_printf(MSG_DEBUG,
"GAS: No ACK received - drop pending entry");
@ -415,6 +468,27 @@ void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
}
int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
struct wpabuf *resp)
{
struct gas_server_response *tmp, *response = NULL;
dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
list) {
if (tmp == resp_ctx) {
response = tmp;
break;
}
}
if (!response || response->resp)
return -1;
response->resp = resp;
return 0;
}
struct gas_server * gas_server_init(void *ctx,
void (*tx)(void *ctx, int freq,
const u8 *da,
@ -461,8 +535,9 @@ void gas_server_deinit(struct gas_server *gas)
int gas_server_register(struct gas_server *gas,
const u8 *adv_proto_id, u8 adv_proto_id_len,
struct wpabuf *
(*req_cb)(void *ctx, const u8 *sa,
const u8 *query, size_t query_len),
(*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
const u8 *query, size_t query_len,
u16 *comeback_delay),
void (*status_cb)(void *ctx, struct wpabuf *resp,
int ok),
void *ctx)

View File

@ -1,6 +1,7 @@
/*
* Generic advertisement service (GAS) server
* Copyright (c) 2017, Qualcomm Atheros, Inc.
* Copyright (c) 2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -22,8 +23,9 @@ void gas_server_deinit(struct gas_server *gas);
int gas_server_register(struct gas_server *gas,
const u8 *adv_proto_id, u8 adv_proto_id_len,
struct wpabuf *
(*req_cb)(void *ctx, const u8 *sa,
const u8 *query, size_t query_len),
(*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
const u8 *query, size_t query_len,
u16 *comeback_delay),
void (*status_cb)(void *ctx, struct wpabuf *resp,
int ok),
void *ctx);
@ -32,6 +34,8 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
int freq);
void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
size_t data_len, int ack);
int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
struct wpabuf *resp);
#else /* CONFIG_GAS_SERVER */

View File

@ -415,7 +415,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1;
}
if (center_idx_to_bw_6ghz(channel) != 0) {
if (center_idx_to_bw_6ghz(channel) < 0) {
wpa_printf(MSG_ERROR,
"Invalid control channel for 6 GHz band");
return -1;
@ -475,13 +475,46 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return 0;
}
if (data->vht_enabled) switch (oper_chwidth) {
if (data->he_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
if (center_segment1 ||
(center_segment0 != 0 &&
5000 + center_segment0 * 5 != data->center_freq1 &&
2407 + center_segment0 * 5 != data->center_freq1))
if (mode == HOSTAPD_MODE_IEEE80211G && sec_channel_offset) {
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
wpa_printf(MSG_ERROR,
"40 MHz channel width is not supported in 2.4 GHz");
return -1;
}
break;
}
/* fall through */
case CHANWIDTH_80MHZ:
if (mode == HOSTAPD_MODE_IEEE80211A) {
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
wpa_printf(MSG_ERROR,
"40/80 MHz channel width is not supported in 5/6 GHz");
return -1;
}
}
break;
case CHANWIDTH_80P80MHZ:
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) {
wpa_printf(MSG_ERROR,
"80+80 MHz channel width is not supported in 5/6 GHz");
return -1;
}
break;
case CHANWIDTH_160MHZ:
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) {
wpa_printf(MSG_ERROR,
"160 MHz channel width is not supported in 5 / 6GHz");
return -1;
}
break;
} else if (data->vht_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
break;
case CHANWIDTH_80P80MHZ:
if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
@ -489,9 +522,38 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
"80+80 channel width is not supported!");
return -1;
}
if (center_segment1 == center_segment0 + 4 ||
center_segment1 == center_segment0 - 4)
/* fall through */
case CHANWIDTH_80MHZ:
break;
case CHANWIDTH_160MHZ:
if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
wpa_printf(MSG_ERROR,
"160 MHz channel width is not supported!");
return -1;
}
break;
}
if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
if (center_segment1 ||
(center_segment0 != 0 &&
5000 + center_segment0 * 5 != data->center_freq1 &&
2407 + center_segment0 * 5 != data->center_freq1)) {
wpa_printf(MSG_ERROR,
"20/40 MHz: center segment 0 (=%d) and center freq 1 (=%d) not in sync",
center_segment0, data->center_freq1);
return -1;
}
break;
case CHANWIDTH_80P80MHZ:
if (center_segment1 == center_segment0 + 4 ||
center_segment1 == center_segment0 - 4) {
wpa_printf(MSG_ERROR,
"80+80 MHz: center segment 1 only 20 MHz apart");
return -1;
}
data->center_freq2 = 5000 + center_segment1 * 5;
/* fall through */
case CHANWIDTH_80MHZ:
@ -500,8 +562,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment1) ||
(oper_chwidth == CHANWIDTH_80P80MHZ &&
!center_segment1) ||
!sec_channel_offset)
!sec_channel_offset) {
wpa_printf(MSG_ERROR,
"80/80+80 MHz: center segment 1 wrong or no second channel offset");
return -1;
}
if (!center_segment0) {
if (channel <= 48)
center_segment0 = 42;
@ -527,22 +592,25 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 == channel - 2 ||
center_segment0 == channel - 6)
data->center_freq1 = 5000 + center_segment0 * 5;
else
else {
wpa_printf(MSG_ERROR,
"Wrong coupling between HT and VHT/HE channel setting");
return -1;
}
}
break;
case CHANWIDTH_160MHZ:
data->bandwidth = 160;
if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
if (center_segment1) {
wpa_printf(MSG_ERROR,
"160MHZ channel width is not supported!");
"160 MHz: center segment 1 should not be set");
return -1;
}
if (center_segment1)
return -1;
if (!sec_channel_offset)
if (!sec_channel_offset) {
wpa_printf(MSG_ERROR,
"160 MHz: second channel offset not set");
return -1;
}
/*
* Note: HT/VHT config and params are coupled. Check if
* HT40 channel band is in VHT160 channel band configuration.
@ -556,8 +624,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 == channel - 10 ||
center_segment0 == channel - 14)
data->center_freq1 = 5000 + center_segment0 * 5;
else
else {
wpa_printf(MSG_ERROR,
"160 MHz: HT40 channel band is not in 160 MHz band");
return -1;
}
break;
}

View File

@ -130,6 +130,16 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
elems->multi_ap = pos;
elems->multi_ap_len = elen;
break;
case OWE_OUI_TYPE:
/* OWE Transition Mode element */
break;
case DPP_CC_OUI_TYPE:
/* DPP Configurator Connectivity element */
break;
case SAE_PK_OUI_TYPE:
elems->sae_pk = pos + 4;
elems->sae_pk_len = elen - 4;
break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@ -206,6 +216,8 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
ext_id = *pos++;
elen--;
elems->frag_ies.last_eid_ext = 0;
switch (ext_id) {
case WLAN_EID_EXT_ASSOC_DELAY_INFO:
if (elen != 1)
@ -245,9 +257,9 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->key_delivery = pos;
elems->key_delivery_len = elen;
break;
case WLAN_EID_EXT_FILS_WRAPPED_DATA:
elems->fils_wrapped_data = pos;
elems->fils_wrapped_data_len = elen;
case WLAN_EID_EXT_WRAPPED_DATA:
elems->wrapped_data = pos;
elems->wrapped_data_len = elen;
break;
case WLAN_EID_EXT_FILS_PUBLIC_KEY:
if (elen < 1)
@ -286,6 +298,11 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->short_ssid_list = pos;
elems->short_ssid_list_len = elen;
break;
case WLAN_EID_EXT_HE_6GHZ_BAND_CAP:
if (elen < sizeof(struct ieee80211_he_6ghz_band_cap))
break;
elems->he_6ghz_band_cap = pos;
break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@ -295,10 +312,39 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
return -1;
}
if (elen == 254)
elems->frag_ies.last_eid_ext = ext_id;
return 0;
}
static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies,
const u8 *pos, u8 elen)
{
if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) {
wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip");
return;
}
/*
* Note: while EID == 0 is a valid ID (SSID IE), it should not be
* fragmented.
*/
if (!frag_ies->last_eid) {
wpa_printf(MSG_MSGDUMP,
"Fragment without a valid last element - skip");
return;
}
frag_ies->frags[frag_ies->n_frags].ie = pos;
frag_ies->frags[frag_ies->n_frags].ie_len = elen;
frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid;
frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext;
frag_ies->n_frags++;
}
/**
* ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs
@ -331,6 +377,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elen);
break;
}
if (elems->ssid) {
wpa_printf(MSG_MSGDUMP,
"Ignored duplicated SSID element");
break;
}
elems->ssid = pos;
elems->ssid_len = elen;
break;
@ -515,8 +566,13 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->dils = pos;
elems->dils_len = elen;
break;
case WLAN_EID_S1G_CAPABILITIES:
if (elen < 15)
break;
elems->s1g_capab = pos;
break;
case WLAN_EID_FRAGMENT:
/* TODO */
ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
break;
case WLAN_EID_EXTENSION:
if (ieee802_11_parse_extension(pos, elen, elems,
@ -532,6 +588,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
id, elen);
break;
}
if (id != WLAN_EID_FRAGMENT && elen == 255)
elems->frag_ies.last_eid = id;
if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext)
elems->frag_ies.last_eid = 0;
}
if (!for_each_element_completed(elem, start, len)) {
@ -710,6 +772,98 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
}
/* convert floats with one decimal place to value*10 int, i.e.,
* "1.5" will return 15
*/
static int hostapd_config_read_int10(const char *value)
{
int i, d;
char *pos;
i = atoi(value);
pos = os_strchr(value, '.');
d = 0;
if (pos) {
pos++;
if (*pos >= '0' && *pos <= '9')
d = *pos - '0';
}
return i * 10 + d;
}
static int valid_cw(int cw)
{
return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
cw == 32767);
}
int hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[],
const char *name, const char *val)
{
int num;
const char *pos;
struct hostapd_tx_queue_params *queue;
/* skip 'tx_queue_' prefix */
pos = name + 9;
if (os_strncmp(pos, "data", 4) == 0 &&
pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
num = pos[4] - '0';
pos += 6;
} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
os_strncmp(pos, "beacon_", 7) == 0) {
wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
return 0;
} else {
wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
return -1;
}
if (num >= NUM_TX_QUEUES) {
/* for backwards compatibility, do not trigger failure */
wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
return 0;
}
queue = &tx_queue[num];
if (os_strcmp(pos, "aifs") == 0) {
queue->aifs = atoi(val);
if (queue->aifs < 0 || queue->aifs > 255) {
wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
queue->aifs);
return -1;
}
} else if (os_strcmp(pos, "cwmin") == 0) {
queue->cwmin = atoi(val);
if (!valid_cw(queue->cwmin)) {
wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
queue->cwmin);
return -1;
}
} else if (os_strcmp(pos, "cwmax") == 0) {
queue->cwmax = atoi(val);
if (!valid_cw(queue->cwmax)) {
wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
queue->cwmax);
return -1;
}
} else if (os_strcmp(pos, "burst") == 0) {
queue->burst = hostapd_config_read_int10(val);
} else {
wpa_printf(MSG_ERROR, "Unknown queue field '%s'", pos);
return -1;
}
return 0;
}
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
{
u8 op_class;
@ -880,16 +1034,35 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
if (freq > 5940 && freq <= 7105) {
int bw;
u8 idx = (freq - 5940) / 5;
bw = center_idx_to_bw_6ghz(idx);
if (bw < 0)
if (freq > 5950 && freq <= 7115) {
if ((freq - 5950) % 5)
return NUM_HOSTAPD_MODES;
*channel = idx;
*op_class = 131 + bw;
switch (chanwidth) {
case CHANWIDTH_80MHZ:
*op_class = 133;
break;
case CHANWIDTH_160MHZ:
*op_class = 134;
break;
case CHANWIDTH_80P80MHZ:
*op_class = 135;
break;
default:
if (sec_channel)
*op_class = 132;
else
*op_class = 131;
break;
}
*channel = (freq - 5950) / 5;
return HOSTAPD_MODE_IEEE80211A;
}
if (freq == 5935) {
*op_class = 136;
*channel = (freq - 5925) / 5;
return HOSTAPD_MODE_IEEE80211A;
}
@ -1269,7 +1442,11 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
if (chan < 1 || chan > 233)
return -1;
return 5940 + chan * 5;
return 5950 + chan * 5;
case 136: /* UHB channels, 20 MHz: 2 */
if (chan == 2)
return 5935;
return -1;
case 180: /* 60 GHz band, channels 1..8 */
if (chan < 1 || chan > 8)
return -1;
@ -1613,7 +1790,9 @@ const char * status2str(u16 status)
S2S(FILS_AUTHENTICATION_FAILURE)
S2S(UNKNOWN_AUTHENTICATION_SERVER)
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
S2S(DENIED_HE_NOT_SUPPORTED)
S2S(SAE_HASH_TO_ELEMENT)
S2S(SAE_PK)
}
return "UNKNOWN";
#undef S2S
@ -1711,8 +1890,12 @@ const struct oper_class_map global_op_class[] = {
*/
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP },
/*
* IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
@ -1723,6 +1906,12 @@ const struct oper_class_map global_op_class[] = {
{ HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP },
/* Keep the operating class 130 as the last entry as a workaround for
* the OneHundredAndThirty Delimiter value used in the Supported
* Operating Classes element to indicate the end of the Operating
* Classes field. */
{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
};
@ -2020,6 +2209,7 @@ int oper_class_bw_to_int(const struct oper_class_map *map)
switch (map->bw) {
case BW20:
return 20;
case BW40:
case BW40PLUS:
case BW40MINUS:
return 40;
@ -2055,41 +2245,44 @@ int center_idx_to_bw_6ghz(u8 idx)
}
int is_6ghz_freq(int freq)
bool is_6ghz_freq(int freq)
{
if (freq < 5940 || freq > 7105)
return 0;
if (freq < 5935 || freq > 7115)
return false;
if (center_idx_to_bw_6ghz((freq - 5940) / 5) < 0)
return 0;
if (freq == 5935)
return true;
return 1;
if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0)
return false;
return true;
}
int is_6ghz_op_class(u8 op_class)
bool is_6ghz_op_class(u8 op_class)
{
return op_class >= 131 && op_class <= 135;
return op_class >= 131 && op_class <= 136;
}
int is_6ghz_psc_frequency(int freq)
bool is_6ghz_psc_frequency(int freq)
{
int i;
if (!is_6ghz_freq(freq))
return 0;
if ((((freq - 5940) / 5) & 0x3) != 0x1)
return 0;
if (!is_6ghz_freq(freq) || freq == 5935)
return false;
if ((((freq - 5950) / 5) & 0x3) != 0x1)
return false;
i = (freq - 5940 + 55) % 80;
i = (freq - 5950 + 55) % 80;
if (i == 0)
i = (freq - 5940 + 55) / 80;
i = (freq - 5950 + 55) / 80;
if (i >= 1 && i <= 15)
return 1;
return true;
return 0;
return false;
}
@ -2320,6 +2513,8 @@ int op_class_to_bandwidth(u8 op_class)
case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
return 160;
case 136: /* UHB channels, 20 MHz: 2 */
return 20;
case 180: /* 60 GHz band, channels 1..8 */
return 2160;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
@ -2380,6 +2575,8 @@ int op_class_to_ch_width(u8 op_class)
return CHANWIDTH_160MHZ;
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
return CHANWIDTH_80P80MHZ;
case 136: /* UHB channels, 20 MHz: 2 */
return CHANWIDTH_USE_HT;
case 180: /* 60 GHz band, channels 1..8 */
return CHANWIDTH_2160MHZ;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
@ -2391,3 +2588,78 @@ int op_class_to_ch_width(u8 op_class)
}
return CHANWIDTH_USE_HT;
}
struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
u8 eid, u8 eid_ext,
const u8 *data, u8 len)
{
struct frag_ies_info *frag_ies = &elems->frag_ies;
struct wpabuf *buf;
unsigned int i;
if (!elems || !data || !len)
return NULL;
buf = wpabuf_alloc_copy(data, len);
if (!buf)
return NULL;
for (i = 0; i < frag_ies->n_frags; i++) {
int ret;
if (frag_ies->frags[i].eid != eid ||
frag_ies->frags[i].eid_ext != eid_ext)
continue;
ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len);
if (ret < 0) {
wpabuf_free(buf);
return NULL;
}
/* Copy only the fragment data (without the EID and length) */
wpabuf_put_data(buf, frag_ies->frags[i].ie,
frag_ies->frags[i].ie_len);
}
return buf;
}
struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
u8 eid, u8 eid_ext)
{
const u8 *data;
u8 len;
/*
* TODO: Defragmentation mechanism can be supported for all IEs. For now
* handle only those that are used (or use ieee802_11_defrag_data()).
*/
switch (eid) {
case WLAN_EID_EXTENSION:
switch (eid_ext) {
case WLAN_EID_EXT_FILS_HLP_CONTAINER:
data = elems->fils_hlp;
len = elems->fils_hlp_len;
break;
case WLAN_EID_EXT_WRAPPED_DATA:
data = elems->wrapped_data;
len = elems->wrapped_data_len;
break;
default:
wpa_printf(MSG_DEBUG,
"Defragmentation not supported. eid_ext=%u",
eid_ext);
return NULL;
}
break;
default:
wpa_printf(MSG_DEBUG,
"Defragmentation not supported. eid=%u", eid);
return NULL;
}
return ieee802_11_defrag_data(elems, eid, eid_ext, data, len);
}

View File

@ -21,6 +21,7 @@ struct element {
struct hostapd_hw_modes;
#define MAX_NOF_MB_IES_SUPPORTED 5
#define MAX_NUM_FRAG_IES_SUPPORTED 3
struct mb_ies_info {
struct {
@ -30,6 +31,21 @@ struct mb_ies_info {
u8 nof_ies;
};
struct frag_ies_info {
struct {
u8 eid;
u8 eid_ext;
const u8 *ie;
u8 ie_len;
} frags[MAX_NUM_FRAG_IES_SUPPORTED];
u8 n_frags;
/* the last parsed element ID and element extension ID */
u8 last_eid;
u8 last_eid_ext;
};
/* Parsed Information Elements */
struct ieee802_11_elems {
const u8 *ssid;
@ -85,7 +101,7 @@ struct ieee802_11_elems {
const u8 *fils_hlp;
const u8 *fils_ip_addr_assign;
const u8 *key_delivery;
const u8 *fils_wrapped_data;
const u8 *wrapped_data;
const u8 *fils_pk;
const u8 *fils_nonce;
const u8 *owe_dh;
@ -97,6 +113,9 @@ struct ieee802_11_elems {
const u8 *he_capabilities;
const u8 *he_operation;
const u8 *short_ssid_list;
const u8 *he_6ghz_band_cap;
const u8 *sae_pk;
const u8 *s1g_capab;
u8 ssid_len;
u8 supp_rates_len;
@ -138,7 +157,7 @@ struct ieee802_11_elems {
u8 fils_hlp_len;
u8 fils_ip_addr_assign_len;
u8 key_delivery_len;
u8 fils_wrapped_data_len;
u8 wrapped_data_len;
u8 fils_pk_len;
u8 owe_dh_len;
u8 power_capab_len;
@ -149,8 +168,10 @@ struct ieee802_11_elems {
u8 he_capabilities_len;
u8 he_operation_len;
u8 short_ssid_list_len;
u8 sae_pk_len;
struct mb_ies_info mb_ies;
struct frag_ies_info frag_ies;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@ -174,6 +195,18 @@ struct hostapd_wmm_ac_params {
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
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 NUM_TX_QUEUES 4
int hostapd_config_tx_queue(struct hostapd_tx_queue_params queue[],
const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
@ -200,8 +233,8 @@ struct oper_class_map {
u8 min_chan;
u8 max_chan;
u8 inc;
enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80, BW4320,
BW6480, BW8640} bw;
enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80,
BW4320, BW6480, BW8640} bw;
enum { P2P_SUPP, NO_P2P_SUPP } p2p;
};
@ -226,9 +259,9 @@ u8 country_to_global_op_class(const char *country, u8 op_class);
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
int oper_class_bw_to_int(const struct oper_class_map *map);
int center_idx_to_bw_6ghz(u8 idx);
int is_6ghz_freq(int freq);
int is_6ghz_op_class(u8 op_class);
int is_6ghz_psc_frequency(int freq);
bool is_6ghz_freq(int freq);
bool is_6ghz_op_class(u8 op_class);
bool is_6ghz_psc_frequency(int freq);
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len);
@ -293,4 +326,10 @@ void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
struct ieee80211_edmg_config requested);
struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
u8 eid, u8 eid_ext,
const u8 *data, u8 len);
struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
u8 eid, u8 eid_ext);
#endif /* IEEE802_11_COMMON_H */

View File

@ -204,7 +204,9 @@
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
#define WLAN_STATUS_DENIED_HE_NOT_SUPPORTED 124
#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126
#define WLAN_STATUS_SAE_PK 127
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
@ -441,7 +443,10 @@
#define WLAN_EID_DEVICE_LOCATION 204
#define WLAN_EID_WHITE_SPACE_MAP 205
#define WLAN_EID_FTM_PARAMETERS 206
#define WLAN_EID_S1G_BCN_COMPAT 213
#define WLAN_EID_S1G_CAPABILITIES 217
#define WLAN_EID_VENDOR_SPECIFIC 221
#define WLAN_EID_S1G_OPERATION 232
#define WLAN_EID_CAG_NUMBER 237
#define WLAN_EID_AP_CSN 239
#define WLAN_EID_FILS_INDICATION 240
@ -458,7 +463,7 @@
#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
#define WLAN_EID_EXT_KEY_DELIVERY 7
#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
#define WLAN_EID_EXT_WRAPPED_DATA 8
#define WLAN_EID_EXT_FTM_SYNC_INFO 9
#define WLAN_EID_EXT_EXTENDED_REQUEST 10
#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
@ -473,8 +478,11 @@
#define WLAN_EID_EXT_SPATIAL_REUSE 39
#define WLAN_EID_EXT_OCV_OCI 54
#define WLAN_EID_EXT_SHORT_SSID_LIST 58
#define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59
#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
#define WLAN_EID_EXT_EDMG_OPERATION 62
#define WLAN_EID_EXT_MSCS_DESCRIPTOR 88
#define WLAN_EID_EXT_TCLAS_MASK 89
#define WLAN_EID_EXT_REJECTED_GROUPS 92
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
@ -558,11 +566,15 @@
#define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80
#define WLAN_EXT_CAPAB_SAE_PW_ID 81
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
#define WLAN_EXT_CAPAB_MSCS 85
#define WLAN_EXT_CAPAB_SAE_PK_EXCLUSIVELY 88
/* Extended RSN Capabilities */
/* bits 0-3: Field length (n-1) */
#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
#define WLAN_RSNX_CAPAB_SAE_H2E 5
#define WLAN_RSNX_CAPAB_SAE_PK 6
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
@ -1315,6 +1327,10 @@ struct ieee80211_ampe_ie {
#define OWE_IE_VENDOR_TYPE 0x506f9a1c
#define OWE_OUI_TYPE 28
#define MULTI_AP_OUI_TYPE 0x1B
#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
#define DPP_CC_OUI_TYPE 0x1e
#define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f
#define SAE_PK_OUI_TYPE 0x1f
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_TEAR_DOWN BIT(4)
@ -1874,7 +1890,15 @@ enum wnm_sleep_mode_response_status {
/* WNM-Sleep Mode subelement IDs */
enum wnm_sleep_mode_subelement_id {
WNM_SLEEP_SUBELEM_GTK = 0,
WNM_SLEEP_SUBELEM_IGTK = 1
WNM_SLEEP_SUBELEM_IGTK = 1,
WNM_SLEEP_SUBELEM_BIGTK = 2,
};
/* WNM notification type (IEEE P802.11-REVmd/D3.0, Table 9-430) */
enum wnm_notification_Type {
WNM_NOTIF_TYPE_FIRMWARE_UPDATE = 0,
WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE = 2,
WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221,
};
/* Channel Switch modes (802.11h) */
@ -2090,7 +2114,7 @@ enum phy_type {
PHY_TYPE_VHT = 9,
};
/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
/* IEEE P802.11-REVmd/D3.0, 9.4.2.36 - Neighbor Report element */
/* BSSID Information Field */
#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
@ -2107,6 +2131,7 @@ enum phy_type {
#define NEI_REP_BSSID_INFO_HT BIT(11)
#define NEI_REP_BSSID_INFO_VHT BIT(12)
#define NEI_REP_BSSID_INFO_FTM BIT(13)
#define NEI_REP_BSSID_INFO_HE BIT(14)
/*
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
@ -2133,12 +2158,53 @@ struct ieee80211_he_operation {
le32 he_oper_params; /* HE Operation Parameters[3] and
* BSS Color Information[1] */
le16 he_mcs_nss_set;
u8 vht_op_info_chwidth;
u8 vht_op_info_chan_center_freq_seg0_idx;
u8 vht_op_info_chan_center_freq_seg1_idx;
/* Followed by conditional MaxBSSID Indicator subfield (u8) */
/* Followed by conditional VHT Operation Information (3 octets),
* Max Co-Hosted BSSID Indicator subfield (1 octet), and/or 6 GHz
* Operation Information subfield (5 octets). */
} STRUCT_PACKED;
/* IEEE P802.11ax/D6.0, Figure 9-787k - 6 GHz Operation Information field */
struct ieee80211_he_6ghz_oper_info {
u8 primary_chan;
u8 control;
u8 chan_center_freq_seg0;
u8 chan_center_freq_seg1;
u8 min_rate;
} STRUCT_PACKED;
#define HE_6GHZ_OPER_INFO_CTRL_CHAN_WIDTH_MASK (BIT(0) | BIT(1))
#define HE_6GHZ_OPER_INFO_CTRL_DUP_BEACON BIT(2)
/* IEEE P802.11ax/D6.0, 9.4.2.261 HE 6 GHz Band Capabilities element */
struct ieee80211_he_6ghz_band_cap {
/* Minimum MPDU Start Spacing B0..B2
* Maximum A-MPDU Length Exponent B3..B5
* Maximum MPDU Length B6..B7 */
le16 capab;
} STRUCT_PACKED;
#define HE_6GHZ_BAND_CAP_MIN_MPDU_START (BIT(0) | BIT(1) | BIT(2))
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_16K BIT(3)
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_32K BIT(4)
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_64K (BIT(3) | BIT(4))
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_128K BIT(5)
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_256K (BIT(3) | BIT(5))
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_512K (BIT(4) | BIT(5))
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_1024K (BIT(3) | BIT(4) | BIT(5))
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK (BIT(3) | BIT(4) | BIT(5))
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT 3
#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_7991 BIT(6)
#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_11454 BIT(7)
#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK (BIT(6) | BIT(7))
#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT 6
#define HE_6GHZ_BAND_CAP_SMPS_MASK (BIT(9) | BIT(10))
#define HE_6GHZ_BAND_CAP_SMPS_STATIC 0
#define HE_6GHZ_BAND_CAP_SMPS_DYNAMIC BIT(9)
#define HE_6GHZ_BAND_CAP_SMPS_DISABLED (BIT(9) | BIT(10))
#define HE_6GHZ_BAND_CAP_RD_RESPONDER BIT(11)
#define HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS BIT(12)
#define HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS BIT(13)
/*
* IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
*/
@ -2156,6 +2222,8 @@ struct ieee80211_spatial_reuse {
/* HE Capabilities Information defines */
#define HE_MACCAP_TWT_RESPONDER ((u8) BIT(2))
#define HE_PHYCAP_CHANNEL_WIDTH_SET_IDX 0
#define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \
BIT(3) | BIT(4)))
@ -2198,7 +2266,7 @@ struct ieee80211_spatial_reuse {
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
BIT(26) | BIT(27) | \
BIT(28) | BIT(29)))
#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(30))
#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30))
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
#define HE_OPERATION_BSS_COLOR_OFFSET 24
@ -2278,4 +2346,25 @@ enum edmg_bw_config {
/* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A
/* Robust AV streaming Action field values */
enum robust_av_streaming_action {
ROBUST_AV_SCS_REQ = 0,
ROBUST_AV_SCS_RESP = 1,
ROBUST_AV_GROUP_MEMBERSHIP_REQ = 2,
ROBUST_AV_GROUP_MEMBERSHIP_RESP = 3,
ROBUST_AV_MSCS_REQ = 4,
ROBUST_AV_MSCS_RESP = 5,
};
enum scs_request_type {
SCS_REQ_ADD = 0,
SCS_REQ_REMOVE = 1,
SCS_REQ_CHANGE = 2,
};
/* Optional subelement IDs for MSCS Descriptor element */
enum mscs_description_subelem {
MCSC_SUBELEM_STATUS = 1,
};
#endif /* IEEE802_11_DEFS_H */

View File

@ -45,6 +45,8 @@ int ocv_derive_all_parameters(struct oci_info *oci)
oci->sec_channel = 1;
else if (op_class_map->bw == BW40MINUS)
oci->sec_channel = -1;
else if (op_class_map->bw == BW40)
oci->sec_channel = (((oci->channel - 1) / 4) % 2) ? -1 : 1;
return 0;
}
@ -95,7 +97,8 @@ int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos)
}
int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
enum oci_verify_result
ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
struct wpa_channel_info *ci, int tx_chanwidth,
int tx_seg1_idx)
{
@ -103,15 +106,15 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
if (!oci_ie) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"OCV failed: did not receive mandatory OCI");
return -1;
"did not receive mandatory OCI");
return OCI_NOT_FOUND;
}
if (oci_ie_len != 3) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"OCV failed: received OCI of unexpected length (%d)",
"received OCI of unexpected length (%d)",
(int) oci_ie_len);
return -1;
return OCI_INVALID_LENGTH;
}
os_memset(&oci, 0, sizeof(oci));
@ -120,25 +123,25 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
oci.seg1_idx = oci_ie[2];
if (ocv_derive_all_parameters(&oci) != 0) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"OCV failed: unable to interpret received OCI");
return -1;
"unable to interpret received OCI");
return OCI_PARSE_ERROR;
}
/* Primary frequency used to send frames to STA must match the STA's */
if ((int) ci->frequency != oci.freq) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"OCV failed: primary channel mismatch in received OCI (we use %d but receiver is using %d)",
"primary channel mismatch in received OCI (we use %d but receiver is using %d)",
ci->frequency, oci.freq);
return -1;
return OCI_PRIMARY_FREQ_MISMATCH;
}
/* We shouldn't transmit with a higher bandwidth than the STA supports
*/
if (tx_chanwidth > oci.chanwidth) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"OCV failed: channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
"channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
tx_chanwidth, oci.chanwidth);
return -1;
return OCI_CHANNEL_WIDTH_MISMATCH;
}
/*
@ -150,9 +153,9 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
if (tx_chanwidth == 40 && ci->frequency < 2500 &&
ci->sec_channel != oci.sec_channel) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"OCV failed: secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
"secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
ci->sec_channel, oci.sec_channel);
return -1;
return OCI_SECONDARY_FREQ_MISMATCH;
}
/*
@ -163,10 +166,10 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
ci->chanwidth == CHAN_WIDTH_80P80) &&
tx_seg1_idx != oci.seg1_idx) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"OCV failed: frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
"frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
tx_seg1_idx, oci.seg1_idx);
return -1;
return OCI_SEG_1_INDEX_MISMATCH;
}
return 0;
return OCI_SUCCESS;
}

View File

@ -27,13 +27,20 @@ struct oci_info {
#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + OCV_OCI_LEN)
enum oci_verify_result {
OCI_SUCCESS, OCI_NOT_FOUND, OCI_INVALID_LENGTH, OCI_PARSE_ERROR,
OCI_PRIMARY_FREQ_MISMATCH, OCI_CHANNEL_WIDTH_MISMATCH,
OCI_SECONDARY_FREQ_MISMATCH, OCI_SEG_1_INDEX_MISMATCH
};
extern char ocv_errorstr[256];
int ocv_derive_all_parameters(struct oci_info *oci);
int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos);
int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos);
int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
enum oci_verify_result
ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
struct wpa_channel_info *ci, int tx_chanwidth,
int tx_seg1_idx);

View File

@ -82,6 +82,7 @@ struct privsep_cmd_set_key {
size_t seq_len;
u8 key[32];
size_t key_len;
enum key_flag key_flag;
};
enum privsep_event {

File diff suppressed because it is too large Load Diff

View File

@ -169,7 +169,7 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
* being smaller than prime. */
in_range = const_time_fill_msb((unsigned int) cmp_prime);
/* The algorithm description would skip the next steps if
* cmp_prime >= 0 (reutnr 0 here), but go through them regardless to
* cmp_prime >= 0 (return 0 here), but go through them regardless to
* minimize externally observable differences in behavior. */
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
@ -713,6 +713,8 @@ static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
goto fail;
const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
x1 = crypto_bignum_init_set(bin, prime_len);
if (!x1)
goto fail;
debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
/* gx1 = x1^3 + a * x1 + b */
@ -753,6 +755,8 @@ static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
goto fail;
const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
v = crypto_bignum_init_set(bin, prime_len);
if (!v)
goto fail;
debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
/* x = CSEL(l, x1, x2) */
@ -1052,10 +1056,17 @@ sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len,
wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
if (ssid_len > 32)
return NULL;
pt = os_zalloc(sizeof(*pt));
if (!pt)
return NULL;
#ifdef CONFIG_SAE_PK
os_memcpy(pt->ssid, ssid, ssid_len);
pt->ssid_len = ssid_len;
#endif /* CONFIG_SAE_PK */
pt->group = group;
pt->ec = crypto_ec_init(group);
if (pt->ec) {
@ -1354,14 +1365,15 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
identifier) < 0))
return -1;
sae->tmp->h2e = 0;
sae->h2e = 0;
sae->pk = 0;
return sae_derive_commit(sae);
}
int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
const u8 *addr1, const u8 *addr2,
int *rejected_groups)
int *rejected_groups, const struct sae_pk *pk)
{
if (!sae->tmp)
return -1;
@ -1377,6 +1389,11 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
return -1;
}
#ifdef CONFIG_SAE_PK
os_memcpy(sae->tmp->ssid, pt->ssid, pt->ssid_len);
sae->tmp->ssid_len = pt->ssid_len;
sae->tmp->ap_pk = pk;
#endif /* CONFIG_SAE_PK */
sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
wpabuf_free(sae->tmp->own_rejected_groups);
sae->tmp->own_rejected_groups = NULL;
@ -1409,7 +1426,7 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
return -1;
}
sae->tmp->h2e = 1;
sae->h2e = 1;
return sae_derive_commit(sae);
}
@ -1515,7 +1532,7 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
const u8 *salt;
struct wpabuf *rejected_groups = NULL;
u8 keyseed[SAE_MAX_HASH_LEN];
u8 keys[SAE_MAX_HASH_LEN + SAE_PMK_LEN];
u8 keys[2 * SAE_MAX_HASH_LEN + SAE_PMK_LEN];
struct crypto_bignum *tmp;
int ret = -1;
size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
@ -1530,14 +1547,17 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
* (commit-scalar + peer-commit-scalar) modulo r)
* PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
*
* When SAE-PK is used,
* KCK || PMK || KEK = KDF-Hash-Length(keyseed, "SAE-PK keys", context)
*/
if (!sae->tmp->h2e)
if (!sae->h2e)
hash_len = SHA256_MAC_LEN;
else if (sae->tmp->dh)
hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
else
hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
if (sae->tmp->h2e && (sae->tmp->own_rejected_groups ||
if (sae->h2e && (sae->tmp->own_rejected_groups ||
sae->tmp->peer_rejected_groups)) {
struct wpabuf *own, *peer;
@ -1589,15 +1609,40 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* octets). */
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
#ifdef CONFIG_SAE_PK
if (sae->pk) {
if (sae_kdf_hash(hash_len, keyseed, "SAE-PK keys",
val, sae->tmp->order_len,
keys, 2 * hash_len + SAE_PMK_LEN) < 0)
goto fail;
} else {
if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
val, sae->tmp->order_len,
keys, hash_len + SAE_PMK_LEN) < 0)
goto fail;
}
#else /* CONFIG_SAE_PK */
if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
val, sae->tmp->order_len,
keys, hash_len + SAE_PMK_LEN) < 0)
goto fail;
#endif /* !CONFIG_SAE_PK */
forced_memzero(keyseed, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, hash_len);
sae->tmp->kck_len = hash_len;
os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
#ifdef CONFIG_SAE_PK
if (sae->pk) {
os_memcpy(sae->tmp->kek, keys + hash_len + SAE_PMK_LEN,
hash_len);
sae->tmp->kek_len = hash_len;
wpa_hexdump_key(MSG_DEBUG, "SAE: KEK for SAE-PK",
sae->tmp->kek, sae->tmp->kek_len);
}
#endif /* CONFIG_SAE_PK */
forced_memzero(keys, sizeof(keys));
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
sae->tmp->kck, sae->tmp->kck_len);
@ -1623,38 +1668,42 @@ int sae_process_commit(struct sae_data *sae)
}
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
const struct wpabuf *token, const char *identifier)
{
u8 *pos;
if (sae->tmp == NULL)
return;
return -1;
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
if (!sae->tmp->h2e && token) {
if (!sae->h2e && token) {
wpabuf_put_buf(buf, token);
wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
wpabuf_head(token), wpabuf_len(token));
}
pos = wpabuf_put(buf, sae->tmp->prime_len);
crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
sae->tmp->prime_len, sae->tmp->prime_len);
if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
sae->tmp->prime_len, sae->tmp->prime_len) < 0)
return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
pos, sae->tmp->prime_len);
if (sae->tmp->ec) {
pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
crypto_ec_point_to_bin(sae->tmp->ec,
if (crypto_ec_point_to_bin(sae->tmp->ec,
sae->tmp->own_commit_element_ecc,
pos, pos + sae->tmp->prime_len);
pos, pos + sae->tmp->prime_len) < 0)
return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
pos, sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
pos + sae->tmp->prime_len, sae->tmp->prime_len);
} else {
pos = wpabuf_put(buf, sae->tmp->prime_len);
crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
sae->tmp->prime_len, sae->tmp->prime_len);
if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
sae->tmp->prime_len,
sae->tmp->prime_len) < 0)
return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
pos, sae->tmp->prime_len);
}
@ -1669,7 +1718,7 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
identifier);
}
if (sae->tmp->h2e && sae->tmp->own_rejected_groups) {
if (sae->h2e && sae->tmp->own_rejected_groups) {
wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
sae->tmp->own_rejected_groups);
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
@ -1679,7 +1728,7 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
}
if (sae->tmp->h2e && token) {
if (sae->h2e && token) {
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
wpabuf_put_u8(buf, 1 + wpabuf_len(token));
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
@ -1688,6 +1737,8 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
"SAE: Anti-clogging token (in container)",
token);
}
return 0;
}
@ -2183,13 +2234,14 @@ static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
}
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
{
const u8 *sc;
size_t hash_len;
int res;
if (sae->tmp == NULL)
return;
return -1;
hash_len = sae->tmp->kck_len;
@ -2200,17 +2252,26 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
sae->send_confirm++;
if (sae->tmp->ec)
sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
res = sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
sae->tmp->own_commit_element_ecc,
sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ecc,
wpabuf_put(buf, hash_len));
else
sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
res = sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
sae->tmp->own_commit_element_ffc,
sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ffc,
wpabuf_put(buf, hash_len));
if (res)
return res;
#ifdef CONFIG_SAE_PK
if (sae_write_confirm_pk(sae, buf) < 0)
return -1;
#endif /* CONFIG_SAE_PK */
return 0;
}
@ -2264,6 +2325,12 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
return -1;
}
#ifdef CONFIG_SAE_PK
if (sae_check_confirm_pk(sae, data + 2 + hash_len,
len - 2 - hash_len) < 0)
return -1;
#endif /* CONFIG_SAE_PK */
return 0;
}

Some files were not shown because too many files have changed in this diff Show More