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 *.pyc
*~ *~
.config
tests/hwsim/logs tests/hwsim/logs
tests/remote/logs tests/remote/logs
wpaspy/build 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 **/parallel-vm.log
tags
build/

View File

@ -322,6 +322,24 @@ fi.w1.wpa_supplicant1.CreateInterface.
</dl> </dl>
</li> </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> <li>
<h3>AddBlob ( s : name, ay : data ) --> nothing</h3> <h3>AddBlob ( s : name, ay : data ) --> nothing</h3>
<p>Adds a blob to the interface.</p> <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>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>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>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>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>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> <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> <li>
<h3>Hessid - s - (read/write)</h3> <h3>Hessid - s - (read/write)</h3>
<p>Homogenous ESS identifier</p> <p>Homogeneous ESS identifier</p>
</li> </li>
<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>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>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>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> </table>
</li> </li>
<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 # 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 # 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 # 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 # 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 # 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 # 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 - wpa_supplicant requests scan with SIOCSIWSCAN
- driver reports scan complete with wireless event SIOCGIWSCAN - driver reports scan complete with wireless event SIOCGIWSCAN
- wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if - 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 decides which AP to use based on scan results
- wpa_supplicant configures driver to associate with the selected BSS - wpa_supplicant configures driver to associate with the selected BSS
(SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ, (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 providing P2P specific Service Request TLV(s) for queries and Service
Response TLV(s) for responses. 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 Service discovery is implemented by processing pending queries as a
part of the device discovery phase. \ref p2p_sd_request() function is used part of the device discovery phase. \ref p2p_sd_request() function is used

View File

@ -1,28 +1,15 @@
ALL=eap_example ALL=eap_example
all: $(ALL) include ../src/build.rules
ifndef CC
CC=gcc
endif
ifndef RANLIB
RANLIB=ranlib
endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
CFLAGS += -I. CFLAGS += -I.
CFLAGS += -I../src CFLAGS += -I../src
CFLAGS += -I../src/utils CFLAGS += -I../src/utils
OBJS_both += ../src/utils/libutils.a EAP_LIBS += ../src/utils/libutils.a
OBJS_both += ../src/crypto/libcrypto.a EAP_LIBS += ../src/crypto/libcrypto.a
OBJS_both += ../src/tls/libtls.a EAP_LIBS += ../src/tls/libtls.a
OBJS_both += ../src/eap_common/eap_peap_common.o OBJS_both += ../src/eap_common/eap_peap_common.o
OBJS_both += ../src/eap_common/eap_psk_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 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_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_ex = eap_example.o eap_example_peer.o eap_example_server.o
_OBJS_VAR := OBJS_ex
include ../src/objs.mk
_OBJS_VAR := EAP_LIBS
../src/utils/libutils.a: include ../src/objs.mk
$(MAKE) -C ../src/utils
../src/crypto/libcrypto.a:
$(MAKE) -C ../src/crypto
../src/tls/libtls.a:
$(MAKE) -C ../src/tls
ifneq ($(CONFIG_SOLIB), yes) ifneq ($(CONFIG_SOLIB), yes)
LIBEAP = libeap.a LIBEAP = libeap.a
libeap.a: $(OBJS_lib) libeap.a: $(EAP_LIBS) $(OBJS_lib)
$(AR) crT libeap.a $(OBJS_lib) $(AR) crT libeap.a $^
$(RANLIB) libeap.a $(RANLIB) libeap.a
else else
@ -137,16 +105,15 @@ CFLAGS += -fPIC -DPIC
LDFLAGS += -shared LDFLAGS += -shared
LIBEAP = libeap.so LIBEAP = libeap.so
libeap.so: $(OBJS_lib) libeap.so: $(EAP_LIBS) $(OBJS_lib)
$(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP) $(LDO) $(LDFLAGS) $^ -o $(LIBEAP)
endif endif
eap_example: $(OBJS_ex) $(LIBEAP) eap_example: $(OBJS_ex) $(LIBEAP)
$(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS) $(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS)
clean: clean: common-clean
$(MAKE) -C ../src clean rm -f core *~ *.o *.d libeap.a libeap.so
rm -f core *~ *.o *.d libeap.a libeap.so $(ALL)
-include $(OBJS:%.o=%.d) -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 { struct eap_peer_ctx {
Boolean eapSuccess; bool eapSuccess;
Boolean eapRestart; bool eapRestart;
Boolean eapFail; bool eapFail;
Boolean eapResp; bool eapResp;
Boolean eapNoResp; bool eapNoResp;
Boolean eapReq; bool eapReq;
Boolean portEnabled; bool portEnabled;
Boolean altAccept; /* for EAP */ bool altAccept; /* for EAP */
Boolean altReject; /* for EAP */ bool altReject; /* for EAP */
Boolean eapTriggerStart; bool eapTriggerStart;
struct wpabuf *eapReqData; /* for EAP */ 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; struct eap_peer_ctx *peer = ctx;
if (peer == NULL) if (peer == NULL)
return FALSE; return false;
switch (variable) { switch (variable) {
case EAPOL_eapSuccess: case EAPOL_eapSuccess:
return peer->eapSuccess; return peer->eapSuccess;
@ -75,12 +75,11 @@ static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
case EAPOL_eapTriggerStart: case EAPOL_eapTriggerStart:
return peer->eapTriggerStart; return peer->eapTriggerStart;
} }
return FALSE; return false;
} }
static void peer_set_bool(void *ctx, enum eapol_bool_var variable, static void peer_set_bool(void *ctx, enum eapol_bool_var variable, bool value)
Boolean value)
{ {
struct eap_peer_ctx *peer = ctx; struct eap_peer_ctx *peer = ctx;
if (peer == NULL) if (peer == NULL)
@ -319,7 +318,7 @@ int eap_example_peer_init(void)
return -1; return -1;
/* Enable "port" to allow authentication */ /* Enable "port" to allow authentication */
eap_ctx.portEnabled = TRUE; eap_ctx.portEnabled = true;
return 0; return 0;
} }
@ -344,7 +343,7 @@ int eap_example_peer_step(void)
if (eap_ctx.eapResp) { if (eap_ctx.eapResp) {
struct wpabuf *resp; struct wpabuf *resp;
printf("==> Response\n"); printf("==> Response\n");
eap_ctx.eapResp = FALSE; eap_ctx.eapResp = false;
resp = eap_get_eapRespData(eap_ctx.eap); resp = eap_get_eapRespData(eap_ctx.eap);
if (resp) { if (resp) {
/* Send EAP response to the server */ /* 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) void eap_example_peer_rx(const u8 *data, size_t data_len)
{ {
/* Make received EAP message available to the EAP library */ /* Make received EAP message available to the EAP library */
eap_ctx.eapReq = TRUE; eap_ctx.eapReq = true;
wpabuf_free(eap_ctx.eapReqData); wpabuf_free(eap_ctx.eapReqData);
eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len); 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); eap_ctx.eap_if = eap_get_interface(eap_ctx.eap);
/* Enable "port" and request EAP to start authentication. */ /* Enable "port" and request EAP to start authentication. */
eap_ctx.eap_if->portEnabled = TRUE; eap_ctx.eap_if->portEnabled = true;
eap_ctx.eap_if->eapRestart = TRUE; eap_ctx.eap_if->eapRestart = true;
return 0; 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); wpabuf_free(eap_ctx.eap_if->eapRespData);
eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len); eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
if (eap_ctx.eap_if->eapRespData) 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 ifdef CONFIG_SAE
L_CFLAGS += -DCONFIG_SAE L_CFLAGS += -DCONFIG_SAE
OBJS += src/common/sae.c 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_ECC=y
NEED_DH_GROUPS=y NEED_DH_GROUPS=y
NEED_HMAC_SHA256_KDF=y
NEED_DRAGONFLY=y NEED_DRAGONFLY=y
endif endif
@ -281,10 +286,6 @@ L_CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
OBJS += src/ap/wnm_ap.c OBJS += src/ap/wnm_ap.c
endif endif
ifdef CONFIG_IEEE80211N
L_CFLAGS += -DCONFIG_IEEE80211N
endif
ifdef CONFIG_IEEE80211AC ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC
endif endif
@ -313,6 +314,14 @@ OBJS += src/fst/fst_ctrl_iface.c
endif endif
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 include $(LOCAL_PATH)/src/drivers/drivers.mk
@ -405,7 +414,7 @@ endif
ifdef CONFIG_EAP_SIM_COMMON ifdef CONFIG_EAP_SIM_COMMON
OBJS += src/eap_common/eap_sim_common.c OBJS += src/eap_common/eap_sim_common.c
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be # 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. # eap_sim_db.h.
OBJS += src/eap_server/eap_sim_db.c OBJS += src/eap_server/eap_sim_db.c
NEED_FIPS186_2_PRF=y NEED_FIPS186_2_PRF=y
@ -532,6 +541,12 @@ endif
ifdef CONFIG_DPP ifdef CONFIG_DPP
L_CFLAGS += -DCONFIG_DPP L_CFLAGS += -DCONFIG_DPP
OBJS += src/common/dpp.c 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/dpp_hostapd.c
OBJS += src/ap/gas_query_ap.c OBJS += src/ap/gas_query_ap.c
NEED_AES_SIV=y NEED_AES_SIV=y
@ -999,9 +1014,7 @@ OBJS += src/ap/hw_features.c
OBJS += src/ap/dfs.c OBJS += src/ap/dfs.c
L_CFLAGS += -DNEED_AP_MLME L_CFLAGS += -DNEED_AP_MLME
endif endif
ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c OBJS += src/ap/ieee802_11_ht.c
endif
ifdef CONFIG_IEEE80211AC ifdef CONFIG_IEEE80211AC
OBJS += src/ap/ieee802_11_vht.c OBJS += src/ap/ieee802_11_vht.c

View File

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

View File

@ -1,10 +1,7 @@
ifndef CC ALL=hostapd hostapd_cli
CC=gcc CONFIG_FILE = .config
endif
ifndef CFLAGS include ../src/build.rules
CFLAGS = -MMD -O2 -Wall -g
endif
ifdef LIBS ifdef LIBS
# If LIBS is set with some global build system defaults, clone those for # If LIBS is set with some global build system defaults, clone those for
@ -19,6 +16,9 @@ endif
ifndef LIBS_n ifndef LIBS_n
LIBS_n := $(LIBS) LIBS_n := $(LIBS)
endif endif
ifndef LIBS_s
LIBS_s := $(LIBS)
endif
endif endif
CFLAGS += $(EXTRA_CFLAGS) CFLAGS += $(EXTRA_CFLAGS)
@ -27,8 +27,6 @@ CFLAGS += -I$(abspath ../src/utils)
export BINDIR ?= /usr/local/bin/ export BINDIR ?= /usr/local/bin/
-include .config
ifndef CONFIG_NO_GITVER ifndef CONFIG_NO_GITVER
# Add VERSION_STR postfix for builds from a git repository # Add VERSION_STR postfix for builds from a git repository
ifeq ($(wildcard ../.git),../.git) ifeq ($(wildcard ../.git),../.git)
@ -122,6 +120,7 @@ LIBS += -lbfd -ldl -liberty -lz
LIBS_c += -lbfd -ldl -liberty -lz LIBS_c += -lbfd -ldl -liberty -lz
LIBS_h += -lbfd -ldl -liberty -lz LIBS_h += -lbfd -ldl -liberty -lz
LIBS_n += -lbfd -ldl -liberty -lz LIBS_n += -lbfd -ldl -liberty -lz
LIBS_s += -lbfd -ldl -liberty -lz
endif endif
endif endif
@ -294,8 +293,13 @@ endif
ifdef CONFIG_SAE ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE CFLAGS += -DCONFIG_SAE
OBJS += ../src/common/sae.o OBJS += ../src/common/sae.o
ifdef CONFIG_SAE_PK
CFLAGS += -DCONFIG_SAE_PK
OBJS += ../src/common/sae_pk.o
endif
NEED_ECC=y NEED_ECC=y
NEED_DH_GROUPS=y NEED_DH_GROUPS=y
NEED_HMAC_SHA256_KDF=y
NEED_AP_MLME=y NEED_AP_MLME=y
NEED_DRAGONFLY=y NEED_DRAGONFLY=y
endif endif
@ -331,10 +335,6 @@ CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
OBJS += ../src/ap/wnm_ap.o OBJS += ../src/ap/wnm_ap.o
endif endif
ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
endif
ifdef CONFIG_IEEE80211AC ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC
endif endif
@ -444,7 +444,7 @@ endif
ifdef CONFIG_EAP_SIM_COMMON ifdef CONFIG_EAP_SIM_COMMON
OBJS += ../src/eap_common/eap_sim_common.o OBJS += ../src/eap_common/eap_sim_common.o
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be # 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. # eap_sim_db.h.
OBJS += ../src/eap_server/eap_sim_db.o OBJS += ../src/eap_server/eap_sim_db.o
NEED_FIPS186_2_PRF=y NEED_FIPS186_2_PRF=y
@ -571,6 +571,12 @@ endif
ifdef CONFIG_DPP ifdef CONFIG_DPP
CFLAGS += -DCONFIG_DPP CFLAGS += -DCONFIG_DPP
OBJS += ../src/common/dpp.o 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/dpp_hostapd.o
OBJS += ../src/ap/gas_query_ap.o OBJS += ../src/ap/gas_query_ap.o
NEED_AES_SIV=y NEED_AES_SIV=y
@ -697,6 +703,7 @@ LIBS += -lssl
endif endif
OBJS += ../src/crypto/crypto_openssl.o OBJS += ../src/crypto/crypto_openssl.o
HOBJS += ../src/crypto/crypto_openssl.o HOBJS += ../src/crypto/crypto_openssl.o
SOBJS += ../src/crypto/crypto_openssl.o
ifdef NEED_FIPS186_2_PRF ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o OBJS += ../src/crypto/fips_prf_openssl.o
endif endif
@ -704,9 +711,11 @@ NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto LIBS += -lcrypto
LIBS_h += -lcrypto LIBS_h += -lcrypto
LIBS_n += -lcrypto LIBS_n += -lcrypto
LIBS_s += -lcrypto
ifdef CONFIG_TLS_ADD_DL ifdef CONFIG_TLS_ADD_DL
LIBS += -ldl LIBS += -ldl
LIBS_h += -ldl LIBS_h += -ldl
LIBS_s += -ldl
endif endif
ifndef CONFIG_TLS_DEFAULT_CIPHERS ifndef CONFIG_TLS_DEFAULT_CIPHERS
CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW" CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
@ -1155,9 +1164,7 @@ OBJS += ../src/ap/hw_features.o
OBJS += ../src/ap/dfs.o OBJS += ../src/ap/dfs.o
CFLAGS += -DNEED_AP_MLME CFLAGS += -DNEED_AP_MLME
endif endif
ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o OBJS += ../src/ap/ieee802_11_ht.o
endif
ifdef CONFIG_IEEE80211AC ifdef CONFIG_IEEE80211AC
OBJS += ../src/ap/ieee802_11_vht.o OBJS += ../src/ap/ieee802_11_vht.o
@ -1244,60 +1251,33 @@ OBJS += ../src/fst/fst_ctrl_iface.o
endif endif
endif endif
ALL=hostapd hostapd_cli ifdef CONFIG_WEP
CFLAGS += -DCONFIG_WEP
all: verify_config $(ALL)
Q=@
E=echo
ifeq ($(V), 1)
Q=
E=true
endif
ifeq ($(QUIET), 1)
Q=@
E=true
endif endif
ifdef CONFIG_CODE_COVERAGE ifdef CONFIG_NO_TKIP
%.o: %.c CFLAGS += -DCONFIG_NO_TKIP
@$(E) " CC " $<
$(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
else
%.o: %.c
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
@$(E) " CC " $<
endif 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)/%: % $(DESTDIR)$(BINDIR)/%: %
install -D $(<) $(@) install -D $(<) $(@)
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL)) install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL))
../src/drivers/build.hostapd: _OBJS_VAR := OBJS
@if [ -f ../src/drivers/build.wpa_supplicant ]; then \ include ../src/objs.mk
$(MAKE) -C ../src/drivers clean; \
fi
@touch ../src/drivers/build.hostapd
BCHECK=../src/drivers/build.hostapd hostapd: $(OBJS)
hostapd: $(BCHECK) $(OBJS)
$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS) $(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
@$(E) " LD " $@ @$(E) " LD " $@
ifdef CONFIG_WPA_TRACE ifdef CONFIG_WPA_TRACE
OBJS_c += ../src/utils/trace.o OBJS_c += ../src/utils/trace.o
endif endif
_OBJS_VAR := OBJS_c
include ../src/objs.mk
hostapd_cli: $(OBJS_c) hostapd_cli: $(OBJS_c)
$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c) $(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
@$(E) " LD " $@ @$(E) " LD " $@
@ -1332,6 +1312,35 @@ ifeq ($(CONFIG_TLS), linux)
HOBJS += ../src/crypto/crypto_linux.o HOBJS += ../src/crypto/crypto_linux.o
endif 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) nt_password_hash: $(NOBJS)
$(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n) $(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
@$(E) " LD " $@ @$(E) " LD " $@
@ -1340,15 +1349,17 @@ hlr_auc_gw: $(HOBJS)
$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h) $(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
@$(E) " LD " $@ @$(E) " LD " $@
sae_pk_gen: $(SOBJS)
$(Q)$(CC) $(LDFLAGS) -o sae_pk_gen $(SOBJS) $(LIBS_s)
@$(E) " LD " $@
.PHONY: lcov-html
lcov-html: lcov-html:
lcov -c -d .. > lcov.info lcov -c -d $(BUILDDIR) > lcov.info
genhtml lcov.info --output-directory lcov-html genhtml lcov.info --output-directory lcov-html
clean: clean: common-clean
$(MAKE) -C ../src clean rm -f core *~ nt_password_hash hlr_auc_gw
rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw rm -f sae_pk_gen
rm -f *.d *.gcno *.gcda *.gcov
rm -f lcov.info rm -f lcov.info
rm -rf lcov-html 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) # the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y #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. # 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 # This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed. # code is not needed.
@ -187,7 +184,7 @@ CONFIG_AP=y
#CONFIG_FST=y #CONFIG_FST=y
# Multiband Operation support # 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. # available to the AP and the devices that may associate with it.
#CONFIG_MBO=y #CONFIG_MBO=y
@ -204,3 +201,11 @@ CONFIG_WPA_CLI_EDIT=y
# /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before # /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before
# either wpa_supplicant or hostapd are run. # either wpa_supplicant or hostapd are run.
CONFIG_NO_RANDOM_POOL=y 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/common.h"
#include "utils/uuid.h" #include "utils/uuid.h"
#include "common/ieee802_11_defs.h" #include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "crypto/sha256.h" #include "crypto/sha256.h"
#include "crypto/tls.h" #include "crypto/tls.h"
#include "drivers/driver.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; struct hostapd_radius_attr *attr, *a;
attr = hostapd_parse_radius_attr(buf + 19); attr = hostapd_parse_radius_attr(buf + 19);
if (attr == NULL) { if (attr == NULL) {
wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s", wpa_printf(MSG_ERROR, "Invalid radius_accept_attr: %s",
buf + 19); buf + 19);
user = NULL; /* already in the BSS list */ user = NULL; /* already in the BSS list */
goto failed; 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, static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
char *val) char *val)
{ {
@ -843,6 +845,7 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
return 0; return 0;
} }
#endif /* CONFIG_WEP */
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val) 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 #ifdef CONFIG_IEEE80211R_AP
static int rkh_derive_key(const char *pos, u8 *key, size_t key_len) 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 */ #endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211N
static int hostapd_config_ht_capab(struct hostapd_config *conf, static int hostapd_config_ht_capab(struct hostapd_config *conf,
const char *capab) 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-]")) if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]"))
conf->secondary_channel = 0; 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]")) if (os_strstr(capab, "[GF]"))
conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD; conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
if (os_strstr(capab, "[SHORT-GI-20]")) if (os_strstr(capab, "[SHORT-GI-20]"))
@ -1212,7 +1108,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
return 0; return 0;
} }
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC #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); 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="); pos2 = os_strstr(pos, "|id=");
if (pos2) { if (pos2) {
if (!end) if (!end)
@ -2320,6 +2244,18 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
pw->password[end - val] = '\0'; 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; pw->next = bss->sae_passwords;
bss->sae_passwords = pw; bss->sae_passwords = pw;
@ -2327,6 +2263,9 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
fail: fail:
str_clear_free(pw->password); str_clear_free(pw->password);
os_free(pw->identifier); os_free(pw->identifier);
#ifdef CONFIG_SAE_PK
sae_deinit_pk(pw->pk);
#endif /* CONFIG_SAE_PK */
os_free(pw); os_free(pw);
return -1; return -1;
} }
@ -2471,6 +2410,13 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) { } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
bss->skip_inactivity_poll = atoi(pos); bss->skip_inactivity_poll = atoi(pos);
} else if (os_strcmp(buf, "country_code") == 0) { } 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); os_memcpy(conf->country, pos, 2);
} else if (os_strcmp(buf, "country3") == 0) { } else if (os_strcmp(buf, "country3") == 0) {
conf->country[2] = strtol(pos, NULL, 16); 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) { } else if (os_strcmp(buf, "eap_teap_auth") == 0) {
int val = atoi(pos); int val = atoi(pos);
if (val < 0 || val > 1) { if (val < 0 || val > 2) {
wpa_printf(MSG_ERROR, wpa_printf(MSG_ERROR,
"Line %d: Invalid eap_teap_auth value", "Line %d: Invalid eap_teap_auth value",
line); line);
@ -2674,6 +2620,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "erp_domain") == 0) { } else if (os_strcmp(buf, "erp_domain") == 0) {
os_free(bss->erp_domain); os_free(bss->erp_domain);
bss->erp_domain = os_strdup(pos); bss->erp_domain = os_strdup(pos);
#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) { } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
int val = atoi(pos); int val = atoi(pos);
@ -2701,6 +2648,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, bss->wep_rekeying_period); line, bss->wep_rekeying_period);
return 1; return 1;
} }
#endif /* CONFIG_WEP */
} else if (os_strcmp(buf, "eap_reauth_period") == 0) { } else if (os_strcmp(buf, "eap_reauth_period") == 0) {
bss->eap_reauth_period = atoi(pos); bss->eap_reauth_period = atoi(pos);
if (bss->eap_reauth_period < 0) { 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) { } else if (os_strcmp(buf, "wpa") == 0) {
bss->wpa = atoi(pos); 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) { } else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
bss->wpa_group_rekey = atoi(pos); bss->wpa_group_rekey = atoi(pos);
bss->wpa_group_rekey_set = 1; 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); bss->wpa_gmk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) { } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
bss->wpa_ptk_rekey = atoi(pos); 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) { } else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
char *endp; char *endp;
unsigned long val = strtoul(pos, &endp, 0); 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); bss->ignore_broadcast_ssid = atoi(pos);
} else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) { } else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
bss->no_probe_resp_if_max_sta = atoi(pos); bss->no_probe_resp_if_max_sta = atoi(pos);
#ifdef CONFIG_WEP
} else if (os_strcmp(buf, "wep_default_key") == 0) { } else if (os_strcmp(buf, "wep_default_key") == 0) {
bss->ssid.wep.idx = atoi(pos); bss->ssid.wep.idx = atoi(pos);
if (bss->ssid.wep.idx > 3) { if (bss->ssid.wep.idx > 3) {
@ -3330,6 +3298,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, buf); line, buf);
return 1; return 1;
} }
#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_VLAN #ifndef CONFIG_NO_VLAN
} else if (os_strcmp(buf, "dynamic_vlan") == 0) { } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
bss->ssid.dynamic_vlan = atoi(pos); 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) { } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
conf->ap_table_expiration_time = atoi(pos); conf->ap_table_expiration_time = atoi(pos);
} else if (os_strncmp(buf, "tx_queue_", 9) == 0) { } 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", wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item",
line); line);
return 1; return 1;
@ -3408,6 +3377,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos); line, pos);
return 1; 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) { } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
bss->assoc_sa_query_max_timeout = atoi(pos); bss->assoc_sa_query_max_timeout = atoi(pos);
if (bss->assoc_sa_query_max_timeout == 0) { 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) if (bss->ocv && !bss->ieee80211w)
bss->ieee80211w = 1; bss->ieee80211w = 1;
#endif /* CONFIG_OCV */ #endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211N
} else if (os_strcmp(buf, "ieee80211n") == 0) { } else if (os_strcmp(buf, "ieee80211n") == 0) {
conf->ieee80211n = atoi(pos); conf->ieee80211n = atoi(pos);
} else if (os_strcmp(buf, "ht_capab") == 0) { } 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); conf->require_ht = atoi(pos);
} else if (os_strcmp(buf, "obss_interval") == 0) { } else if (os_strcmp(buf, "obss_interval") == 0) {
conf->obss_interval = atoi(pos); conf->obss_interval = atoi(pos);
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC #ifdef CONFIG_IEEE80211AC
} else if (os_strcmp(buf, "ieee80211ac") == 0) { } else if (os_strcmp(buf, "ieee80211ac") == 0) {
conf->ieee80211ac = atoi(pos); 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) { } else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
conf->he_phy_capab.he_mu_beamformer = atoi(pos); conf->he_phy_capab.he_mu_beamformer = atoi(pos);
} else if (os_strcmp(buf, "he_bss_color") == 0) { } 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) { } else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
conf->he_op.he_default_pe_duration = atoi(pos); conf->he_op.he_default_pe_duration = atoi(pos);
} else if (os_strcmp(buf, "he_twt_required") == 0) { } 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; bss->own_ie_override = tmp;
} else if (os_strcmp(buf, "sae_reflection_attack") == 0) { } else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
bss->sae_reflection_attack = atoi(pos); 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) { } else if (os_strcmp(buf, "sae_commit_override") == 0) {
wpabuf_free(bss->sae_commit_override); wpabuf_free(bss->sae_commit_override);
bss->sae_commit_override = wpabuf_parse_bin(pos); 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) { } else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) {
wpabuf_free(bss->rsnxe_override_eapol); wpabuf_free(bss->rsnxe_override_eapol);
bss->rsnxe_override_eapol = wpabuf_parse_bin(pos); 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) { } else if (os_strcmp(buf, "gtk_rsc_override") == 0) {
wpabuf_free(bss->gtk_rsc_override); wpabuf_free(bss->gtk_rsc_override);
bss->gtk_rsc_override = wpabuf_parse_bin(pos); bss->gtk_rsc_override = wpabuf_parse_bin(pos);
} else if (os_strcmp(buf, "igtk_rsc_override") == 0) { } else if (os_strcmp(buf, "igtk_rsc_override") == 0) {
wpabuf_free(bss->igtk_rsc_override); wpabuf_free(bss->igtk_rsc_override);
bss->igtk_rsc_override = wpabuf_parse_bin(pos); 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 */ #endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_SAE #ifdef CONFIG_SAE
} else if (os_strcmp(buf, "sae_password") == 0) { } 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) { } else if (os_strcmp(buf, "dpp_controller") == 0) {
if (hostapd_dpp_controller_parse(bss, pos)) if (hostapd_dpp_controller_parse(bss, pos))
return 1; 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_DPP2 */
#endif /* CONFIG_DPP */ #endif /* CONFIG_DPP */
#ifdef CONFIG_OWE #ifdef CONFIG_OWE
@ -4431,8 +4450,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->rssi_reject_assoc_rssi = atoi(pos); conf->rssi_reject_assoc_rssi = atoi(pos);
} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) { } else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
conf->rssi_reject_assoc_timeout = atoi(pos); 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) { } else if (os_strcmp(buf, "pbss") == 0) {
bss->pbss = atoi(pos); bss->pbss = atoi(pos);
} else if (os_strcmp(buf, "transition_disable") == 0) {
bss->transition_disable = strtol(pos, NULL, 16);
#ifdef CONFIG_AIRTIME_POLICY #ifdef CONFIG_AIRTIME_POLICY
} else if (os_strcmp(buf, "airtime_mode") == 0) { } else if (os_strcmp(buf, "airtime_mode") == 0) {
int val = atoi(pos); 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; bss->mka_psk_set |= MKA_PSK_SET_CKN;
#endif /* CONFIG_MACSEC */ #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 { } else {
wpa_printf(MSG_ERROR, wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'", "Line %d: unknown configuration item '%s'",

View File

@ -49,6 +49,7 @@
#include "ap/ieee802_1x.h" #include "ap/ieee802_1x.h"
#include "ap/wpa_auth.h" #include "ap/wpa_auth.h"
#include "ap/wpa_auth_i.h" #include "ap/wpa_auth_i.h"
#include "ap/pmksa_cache_auth.h"
#include "ap/ieee802_11.h" #include "ap/ieee802_11.h"
#include "ap/sta_info.h" #include "ap/sta_info.h"
#include "ap/wps_hostapd.h" #include "ap/wps_hostapd.h"
@ -61,6 +62,7 @@
#include "ap/neighbor_db.h" #include "ap/neighbor_db.h"
#include "ap/rrm.h" #include "ap/rrm.h"
#include "ap/dpp_hostapd.h" #include "ap/dpp_hostapd.h"
#include "ap/dfs.h"
#include "wps/wps_defs.h" #include "wps/wps_defs.h"
#include "wps/wps.h" #include "wps/wps.h"
#include "fst/fst_ctrl_iface.h" #include "fst/fst_ctrl_iface.h"
@ -71,9 +73,6 @@
#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256 #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
#ifdef CONFIG_CTRL_IFACE_UDP #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 8877
#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50 #define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878 #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
@ -1294,6 +1293,22 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
pos += ret; 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; 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, static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
const char *band) const char *bands)
{ {
union wpa_event_data event; 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; * For example:
else if (os_strcmp(band, "5G") == 0) * SET setband 2G,6G
setband = WPA_SETBAND_5G; * SET setband 5G
else if (os_strcmp(band, "2G") == 0) * SET setband AUTO
setband = WPA_SETBAND_2G; */
else if (!os_strstr(bands, "AUTO")) {
return -1; 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)); os_memset(&event, 0, sizeof(event));
event.channel_list_changed.initiator = REGDOM_SET_BY_USER; event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; 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); hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_test") == 0) { } else if (os_strcasecmp(cmd, "dpp_test") == 0) {
dpp_test = atoi(value); dpp_test = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
dpp_version_override = atoi(value);
#endif /* CONFIG_DPP */ #endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO #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) { os_strcmp(cmd, "sae_pwe") == 0) {
if (hapd->started) if (hapd->started)
hostapd_setup_sae_pt(hapd->conf); 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; 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 || if (ip.ip_hl != 5 || ip.ip_v != 4 ||
ntohs(ip.ip_len) > HWSIM_IP_LEN) { ntohs(ip.ip_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"test data: RX - ignore unexpect IP header"); "test data: RX - ignore unexpected IP header");
return; return;
} }
@ -2147,6 +2197,32 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
if (hwaddr_aton(cmd, addr)) if (hwaddr_aton(cmd, addr))
return -1; 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 (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
if (hapd->last_igtk_alg == WPA_ALG_NONE) if (hapd->last_igtk_alg == WPA_ALG_NONE)
return -1; 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, static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
char *buf, size_t buflen) 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) { if (!sta || !sta->wpa_sm) {
wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR, wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
MAC2STR(addr)); MAC2STR(addr));
return -1; return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
} }
pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len); 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, wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
MAC2STR(addr)); MAC2STR(addr));
return -1; return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
} }
return wpa_snprintf_hex(buf, buflen, pmk, pmk_len); 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 */ #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, static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
char *pos) char *pos)
{ {
#ifdef NEED_AP_MLME #ifdef NEED_AP_MLME
struct csa_settings settings; struct csa_settings settings;
int ret; int ret;
int dfs_range = 0;
unsigned int i; unsigned int i;
int bandwidth;
u8 chan;
ret = hostapd_parse_csa_settings(pos, &settings); ret = hostapd_parse_csa_settings(pos, &settings);
if (ret) if (ret)
return 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++) { for (i = 0; i < iface->num_bss; i++) {
/* Save CHAN_SWITCH VHT config */ /* 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) char *buf, size_t buflen)
{ {
int ret; int ret;
char *pos; char *pos, *temp = NULL;
u8 *data = NULL; u8 *data = NULL;
unsigned int vendor_id, subcmd; unsigned int vendor_id, subcmd;
enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
struct wpabuf *reply; struct wpabuf *reply;
size_t data_len = 0; 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); vendor_id = strtoul(cmd, &pos, 16);
if (!isblank((unsigned char) *pos)) if (!isblank((unsigned char) *pos))
return -EINVAL; return -EINVAL;
@ -2567,7 +2817,9 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
if (*pos != '\0') { if (*pos != '\0') {
if (!isblank((unsigned char) *pos++)) if (!isblank((unsigned char) *pos++))
return -EINVAL; return -EINVAL;
data_len = os_strlen(pos);
temp = os_strchr(pos, ' ');
data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
} }
if (data_len) { 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); reply = wpabuf_alloc((buflen - 1) / 2);
if (!reply) { if (!reply) {
os_free(data); 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, ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
reply); nested_attr_flag, reply);
if (ret == 0) if (ret == 0)
ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply), 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, static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
const char *txtaddr) 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) { } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply, reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
reply_size); 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) { } else if (os_strcmp(buf, "TERMINATE") == 0) {
eloop_terminate(); eloop_terminate();
} else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) { } 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, reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
atoi(buf + 19), atoi(buf + 19),
reply, reply_size); 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) { } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
if (hostapd_dpp_auth_init(hapd, buf + 13) < 0) if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
reply_len = -1; 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) { } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0) if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
reply_len = -1; 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 */ #endif /* CONFIG_DPP */
#ifdef RADIUS_SERVER #ifdef RADIUS_SERVER
} else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) { } 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 reply_len;
int level = MSG_DEBUG; int level = MSG_DEBUG;
#ifdef CONFIG_CTRL_IFACE_UDP #ifdef CONFIG_CTRL_IFACE_UDP
unsigned char lcookie[COOKIE_LEN]; unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */ #endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 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 #ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) { if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7); os_memcpy(reply, "COOKIE=", 7);
wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
cookie, COOKIE_LEN); hapd->ctrl_iface_cookie,
reply_len = 7 + 2 * COOKIE_LEN; CTRL_IFACE_COOKIE_LEN);
reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto done; goto done;
} }
if (os_strncmp(buf, "COOKIE=", 7) != 0 || 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, wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request"); "CTRL: No cookie in the request - drop request");
os_free(reply); os_free(reply);
return; 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, wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request"); "CTRL: Invalid cookie in the request - drop request");
os_free(reply); os_free(reply);
return; return;
} }
pos = buf + 7 + 2 * COOKIE_LEN; pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*pos == ' ') while (*pos == ' ')
pos++; pos++;
#endif /* CONFIG_CTRL_IFACE_UDP */ #endif /* CONFIG_CTRL_IFACE_UDP */
@ -3777,7 +4087,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
dl_list_init(&hapd->ctrl_dst); dl_list_init(&hapd->ctrl_dst);
hapd->ctrl_sock = -1; 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 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE; 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_TESTING_OPTIONS
#ifdef CONFIG_DPP #ifdef CONFIG_DPP
dpp_test = DPP_TEST_DISABLED; 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_DPP */
#endif /* CONFIG_TESTING_OPTIONS */ #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, static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx) void *sock_ctx)
{ {
void *interfaces = eloop_ctx; struct hapd_interfaces *interfaces = eloop_ctx;
char buffer[256], *buf = buffer; char buffer[256], *buf = buffer;
int res; int res;
struct sockaddr_storage from; struct sockaddr_storage from;
@ -4365,7 +4680,7 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
int reply_len; int reply_len;
const int reply_size = 4096; const int reply_size = 4096;
#ifdef CONFIG_CTRL_IFACE_UDP #ifdef CONFIG_CTRL_IFACE_UDP
unsigned char lcookie[COOKIE_LEN]; unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */ #endif /* CONFIG_CTRL_IFACE_UDP */
res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, 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 #ifdef CONFIG_CTRL_IFACE_UDP
if (os_strcmp(buf, "GET_COOKIE") == 0) { if (os_strcmp(buf, "GET_COOKIE") == 0) {
os_memcpy(reply, "COOKIE=", 7); os_memcpy(reply, "COOKIE=", 7);
wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
gcookie, COOKIE_LEN); interfaces->ctrl_iface_cookie,
reply_len = 7 + 2 * COOKIE_LEN; CTRL_IFACE_COOKIE_LEN);
reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
goto send_reply; goto send_reply;
} }
if (os_strncmp(buf, "COOKIE=", 7) != 0 || 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, wpa_printf(MSG_DEBUG,
"CTRL: No cookie in the request - drop request"); "CTRL: No cookie in the request - drop request");
os_free(reply); os_free(reply);
return; 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, wpa_printf(MSG_DEBUG,
"CTRL: Invalid cookie in the request - drop request"); "CTRL: Invalid cookie in the request - drop request");
os_free(reply); os_free(reply);
return; return;
} }
buf += 7 + 2 * COOKIE_LEN; buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
while (*buf == ' ') while (*buf == ' ')
buf++; buf++;
#endif /* CONFIG_CTRL_IFACE_UDP */ #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 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
@ -4802,13 +5119,8 @@ static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst,
return; return;
idx = 0; idx = 0;
if (ifname) { 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_base = "IFNAME=";
io[idx].iov_len = 7; io[idx].iov_len = 7;
#endif /* CONFIG_CTRL_IFACE_UDP */
idx++; idx++;
io[idx].iov_base = (char *) ifname; io[idx].iov_base = (char *) ifname;
io[idx].iov_len = os_strlen(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) # the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y #CONFIG_DRIVER_RADIUS_ACL=y
# IEEE 802.11n (High Throughput) support
CONFIG_IEEE80211N=y
# Wireless Network Management (IEEE Std 802.11v-2011) # Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation. # Note: This is experimental and not complete implementation.
#CONFIG_WNM=y #CONFIG_WNM=y
@ -354,7 +351,7 @@ CONFIG_INTERWORKING=y
#CONFIG_ACS=y #CONFIG_ACS=y
# Multiband Operation support # 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. # available to the AP and the devices that may associate with it.
#CONFIG_MBO=y #CONFIG_MBO=y
@ -384,6 +381,19 @@ CONFIG_INTERWORKING=y
# parameter. See that parameter in hostapd.conf for more details. # parameter. See that parameter in hostapd.conf for more details.
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1 #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 # Frequency list can be provided as range using hyphen ('-') or individual
# frequencies can be specified by comma (',') separated values # frequencies can be specified by comma (',') separated values
# Default: all frequencies allowed in selected hw_mode # Default: all frequencies allowed in selected hw_mode
#freqlist=2437,5945,5965 #freqlist=2437,5955,5975
#freqlist=2437,5985-6105 #freqlist=2437,5985-6105
# Exclude DFS channels from ACS # 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. # Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
ieee80211n=1 ieee80211n=1
# disable_11n: Boolean (0/1) to disable HT for a specific BSS
#disable_11n=0
# ht_capab: HT capabilities (list of flags) # ht_capab: HT capabilities (list of flags)
# LDPC coding capability: [LDPC] = supported # LDPC coding capability: [LDPC] = supported
# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary # 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 # channels if needed or creation of 40 MHz channel maybe rejected based
# on overlapping BSSes. These changes are done automatically when hostapd # on overlapping BSSes. These changes are done automatically when hostapd
# is setting up the 40 MHz channel. # 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) # HT-greenfield: [GF] (disabled if not set)
# Short GI for 20 MHz: [SHORT-GI-20] (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) # 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. # Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
#ieee80211ac=1 #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_capab: VHT capabilities (list of flags)
# #
# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454] # vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
@ -788,6 +792,9 @@ ieee80211n=1
# 1 = enabled # 1 = enabled
#ieee80211ax=1 #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 #he_su_beamformer: HE single user beamformer support
# 0 = not supported (default) # 0 = not supported (default)
# 1 = supported # 1 = supported
@ -806,6 +813,9 @@ ieee80211n=1
# he_bss_color: BSS color (1-63) # he_bss_color: BSS color (1-63)
#he_bss_color=1 #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 #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 # Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
#he_default_pe_duration=0 #he_default_pe_duration=0
@ -821,11 +831,11 @@ ieee80211n=1
#he_rts_threshold=0 #he_rts_threshold=0
# HE operating channel information; see matching vht_* parameters for details. # 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. # On the 6 GHz band the center freq calculation starts from 5.950 GHz offset.
# For example idx=3 would result in 5955 MHz center frequency. In addition, # 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 # he_oper_chwidth is ignored, and the channel width is derived from the
# configured operating class or center frequency indexes (see # 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_chwidth
#he_oper_centr_freq_seg0_idx #he_oper_centr_freq_seg0_idx
#he_oper_centr_freq_seg1_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 # EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
# reauthentication). # reauthentication).
# Note: Reauthentications may enforce a disconnection, check the related
# parameter wpa_deny_ptk0_rekey for details.
#eap_reauth_period=3600 #eap_reauth_period=3600
# Use PAE group address (01:80:c2:00:00:03) instead of individual target # 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 # 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 # 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 # 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. # field is configured in hex format.
#eap_fast_a_id=101112131415161718191a1b1c1d1e1f #eap_fast_a_id=101112131415161718191a1b1c1d1e1f
@ -1226,6 +1238,8 @@ eap_server=0
# EAP-TEAP authentication type # EAP-TEAP authentication type
# 0 = inner EAP (default) # 0 = inner EAP (default)
# 1 = Basic-Password-Auth # 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_auth=0
# EAP-TEAP authentication behavior when using PAC # 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_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
wpa=2 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 # 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 # 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 # (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 # Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
# PTK to mitigate some attacks against TKIP deficiencies. # 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 #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 # 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. # Handshake are retried per 4-Way Handshake attempt.
# (dot11RSNAConfigPairwiseUpdateCount) # (dot11RSNAConfigPairwiseUpdateCount)
@ -1677,6 +1720,12 @@ wpa_pairwise_update_count=100
# available in deployed devices. # available in deployed devices.
#group_mgmt_cipher=AES-128-CMAC #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) # Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
# (maximum time to wait for a SA Query response) # (maximum time to wait for a SA Query response)
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295 # dot11AssociationSAQueryMaximumTimeout, 1...4294967295
@ -1692,6 +1741,19 @@ wpa_pairwise_update_count=100
# Enabling this automatically also enables ieee80211w, if not yet enabled. # Enabling this automatically also enables ieee80211w, if not yet enabled.
# 0 = disabled (default) # 0 = disabled (default)
# 1 = enabled # 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 #ocv=1
# disable_pmksa_caching: Disable PMKSA caching # disable_pmksa_caching: Disable PMKSA caching
@ -1723,7 +1785,7 @@ wpa_pairwise_update_count=100
# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and # be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In # by optional password identifier (dot11RSNAConfigPasswordIdentifier). In
# addition, an optional VLAN ID specification can be used to bind the station # 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 # 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 # (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. # special meaning of removing all previously added entries.
# #
# sae_password uses the following encoding: # 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: # Examples:
#sae_password=secret #sae_password=secret
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff #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) # default: 30 TUs (= 30.72 milliseconds)
#fils_hlp_wait_time=30 #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 ############################################## ##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID) # Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@ -1910,7 +1990,7 @@ wpa_pairwise_update_count=100
# Wildcard entry: # Wildcard entry:
# Upon receiving a response from R0KH, it will be added to this list, so # 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 # 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 #r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
# List of R1KHs in the same Mobility Domain # List of R1KHs in the same Mobility Domain
@ -1966,7 +2046,7 @@ wpa_pairwise_update_count=100
#ft_psk_generate_local=0 #ft_psk_generate_local=0
##### Neighbor table ########################################################## ##### 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 # detecting Overlapping Legacy BSS Condition). The oldest entry will be
# removed when adding a new entry that would make the list grow over this # 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 # limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
@ -2249,6 +2329,17 @@ wpa_pairwise_update_count=100
#dpp_csign #dpp_csign
#dpp_controller #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) ################################################# #### TDLS (IEEE 802.11z-2010) #################################################
# Prohibit use of TDLS in this BSS # Prohibit use of TDLS in this BSS
@ -2644,6 +2735,10 @@ wpa_pairwise_update_count=100
# threshold (range: 0..255, default=30). # threshold (range: 0..255, default=30).
#rssi_reject_assoc_timeout=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 ##################################### ##### Fast Session Transfer (FST) support #####################################
# #
# The options in this section are only available when the build configuration # 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); dir = opendir(ctrl_iface_dir);
if (dir == NULL) { if (dir == NULL) {
printf("Control interface directory '%s' could not be " printf("Control interface directory '%s' could not be "
"openned.\n", ctrl_iface_dir); "opened.\n", ctrl_iface_dir);
return; return;
} }
@ -1227,14 +1227,15 @@ static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
char cmd[256]; char cmd[256];
int res; int res;
if (argc < 2 || argc > 3) { if (argc < 2 || argc > 4) {
printf("Invalid vendor command\n" 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; return -1;
} }
res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1], res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s%s%s", argv[0],
argc == 3 ? argv[2] : ""); argv[1], argc >= 3 ? argv[2] : "",
argc == 4 ? " " : "", argc == 4 ? argv[3] : "");
if (os_snprintf_error(sizeof(cmd), res)) { if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long VENDOR command.\n"); printf("Too long VENDOR command.\n");
return -1; 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, static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
char *argv[]) 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); 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 */ #endif /* CONFIG_DPP */
@ -1650,6 +1689,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"<id> = get DPP bootstrap URI" }, "<id> = get DPP bootstrap URI" },
{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL, { "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
"<id> = show DPP bootstrap information" }, "<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, { "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
"peer=<id> [own=<id>] = initiate DPP bootstrapping" }, "peer=<id> [own=<id>] = initiate DPP bootstrapping" },
{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL, { "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
@ -1670,6 +1711,16 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"add PKEX code" }, "add PKEX code" },
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL, { "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
"*|<id> = remove DPP pkex information" }, "*|<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 */ #endif /* CONFIG_DPP */
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL, { "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
"=Add/Delete/Show/Clear accept MAC ACL" }, "=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; struct wowlan_triggers *triggs;
iface->drv_flags = capa.flags; iface->drv_flags = capa.flags;
iface->smps_modes = capa.smps_modes; iface->drv_flags2 = capa.flags2;
iface->probe_resp_offloads = capa.probe_resp_offloads; iface->probe_resp_offloads = capa.probe_resp_offloads;
/* /*
* Use default extended capa values from per-radio information * 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) static void show_version(void)
{ {
fprintf(stderr, fprintf(stderr,
"hostapd v" VERSION_STR "\n" "hostapd v%s\n"
"User space daemon for IEEE 802.11 AP management,\n" "User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
"Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> " "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 */ #endif /* CONFIG_ETH_P_OUI */
#ifdef CONFIG_DPP #ifdef CONFIG_DPP
os_memset(&dpp_conf, 0, sizeof(dpp_conf)); 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); interfaces.dpp = dpp_global_init(&dpp_conf);
if (!interfaces.dpp) if (!interfaces.dpp)
return -1; return -1;
@ -902,8 +906,11 @@ int main(int argc, char *argv[])
!!(interfaces.iface[i]->drv_flags & !!(interfaces.iface[i]->drv_flags &
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
hostapd_interface_deinit_free(interfaces.iface[i]); hostapd_interface_deinit_free(interfaces.iface[i]);
interfaces.iface[i] = NULL;
} }
os_free(interfaces.iface); os_free(interfaces.iface);
interfaces.iface = NULL;
interfaces.count = 0;
#ifdef CONFIG_DPP #ifdef CONFIG_DPP
dpp_global_deinit(interfaces.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 include ../../src/build.rules
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
CFLAGS += -I../../src/utils CFLAGS += -I../../src/utils
CFLAGS += -I../../src/common CFLAGS += -I../../src/common
@ -30,8 +8,17 @@ CFLAGS += -I../../src
ifndef CONFIG_NO_BROWSER ifndef CONFIG_NO_BROWSER
ifndef CONFIG_BROWSER_SYSTEM 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) GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0)
GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0) GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0)
endif
CFLAGS += $(GTKCFLAGS) CFLAGS += $(GTKCFLAGS)
LIBS += $(GTKLIBS) LIBS += $(GTKLIBS)
endif endif
@ -84,23 +71,11 @@ CFLAGS += -DEAP_TLS_OPENSSL
OBJS += ../../src/crypto/tls_openssl_ocsp.o OBJS += ../../src/crypto/tls_openssl_ocsp.o
LIBS += -lssl -lcrypto LIBS += -lssl -lcrypto
_OBJS_VAR := OBJS
include ../../src/objs.mk
hs20-osu-client: $(OBJS) hs20-osu-client: $(OBJS)
$(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS) $(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS)
@$(E) " LD " $@ @$(E) " LD " $@
%.o: %.c clean: common-clean
$(Q)$(CC) -c -o $@ $(CFLAGS) $< rm -f core *~
@$(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)

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, "Data: %s", data);
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data); wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
write_summary(ctx, "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); xml_node_get_text_free(ctx->xml, data);
if (res > 0) { if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully"); 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); wpa_ctrl_close(mon);
if (res < 0) { 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"); write_summary(ctx, "Could not connect to OSU network");
wpa_printf(MSG_INFO, "Remove OSU network connection"); wpa_printf(MSG_INFO, "Remove OSU network connection");
snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id); 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); snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
write_summary(ctx, "Start web browser with OSU provider selection page"); write_summary(ctx, "Start web browser with OSU provider selection page");
ret = hs20_web_browser(fname); ret = hs20_web_browser(fname, 0);
selected: selected:
if (ret > 0 && (size_t) ret <= osu_count) { 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) static int osu_cert_cb(void *_ctx, struct http_cert *cert)
{ {
struct hs20_osu_client *ctx = _ctx; struct hs20_osu_client *ctx = _ctx;
unsigned int i, j; size_t i, j;
int found; int found;
char *host = NULL; 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); size_t name_len = os_strlen(name);
wpa_printf(MSG_INFO, wpa_printf(MSG_INFO,
"[%i] Looking for icon file name '%s' match", "[%zu] Looking for icon file name '%s' match",
j, name); j, name);
for (i = 0; i < cert->num_logo; i++) { for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->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; char *pos;
wpa_printf(MSG_INFO, 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); i, logo->uri, (int) uri_len, (int) name_len);
if (uri_len < 1 + name_len) { if (uri_len < 1 + name_len) {
wpa_printf(MSG_INFO, "URI Length is too short"); 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) { if (logo->hash_len != 32) {
wpa_printf(MSG_INFO, 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); j, i, (int) logo->hash_len);
continue; continue;
} }
@ -3054,7 +3054,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
} }
wpa_printf(MSG_DEBUG, 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", wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
logo->hash, 32); logo->hash, 32);
wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]", 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) 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>] " " [-w<wpa_supplicant ctrl_iface dir>] "
"[-r<result file>] [-f<debug file>] \\\n" "[-r<result file>] [-f<debug file>] \\\n"
" [-s<summary file>] \\\n" " [-s<summary file>] \\\n"
@ -3198,7 +3198,7 @@ int main(int argc, char *argv[])
return -1; return -1;
for (;;) { 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) if (c < 0)
break; break;
switch (c) { switch (c) {
@ -3236,6 +3236,9 @@ int main(int argc, char *argv[])
case 't': case 't':
wpa_debug_timestamp++; wpa_debug_timestamp++;
break; break;
case 'T':
ctx.ignore_tls = 1;
break;
case 'w': case 'w':
wpas_ctrl_path = optarg; wpas_ctrl_path = optarg;
break; break;
@ -3403,7 +3406,7 @@ int main(int argc, char *argv[])
wpa_printf(MSG_INFO, "Launch web browser to URL %s", wpa_printf(MSG_INFO, "Launch web browser to URL %s",
argv[optind + 1]); 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); wpa_printf(MSG_INFO, "Web browser result: %d", ret);
} else if (strcmp(argv[optind], "parse_cert") == 0) { } else if (strcmp(argv[optind], "parse_cert") == 0) {
if (argc - optind < 2) { if (argc - optind < 2) {

View File

@ -50,6 +50,8 @@ struct hs20_osu_client {
const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */ const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
#define WORKAROUND_OCSP_OPTIONAL 0x00000001 #define WORKAROUND_OCSP_OPTIONAL 0x00000001
unsigned long int workarounds; 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); wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
write_summary(ctx, "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); xml_node_get_text_free(ctx->xml, uri);
if (res > 0) { if (res > 0) {
wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'", 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 include ../../src/build.rules
CC=gcc
endif
ifndef LDO
LDO=$(CC)
endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
endif
CFLAGS += -I../../src CFLAGS += -I../../src
CFLAGS += -I../../src/utils CFLAGS += -I../../src/utils
@ -43,14 +33,10 @@ CFLAGS += $(shell xml2-config --cflags)
LIBS += $(shell xml2-config --libs) LIBS += $(shell xml2-config --libs)
OBJS += ../../src/utils/xml_libxml2.o OBJS += ../../src/utils/xml_libxml2.o
_OBJS_VAR := OBJS
include ../../src/objs.mk
hs20_spp_server: $(OBJS) hs20_spp_server: $(OBJS)
$(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS) $(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS)
clean: clean: common-clean
rm -f core *~ *.o *.d hs20_spp_server rm -f core *~
rm -f ../../src/utils/*.o
rm -f ../../src/utils/*.d
rm -f ../../src/crypto/*.o
rm -f ../../src/crypto/*.d
-include $(OBJS:%.o=%.d)

View File

@ -1,3 +1,3 @@
#!/bin/sh #!/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 #!/bin/sh
# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
openssl ocsp \ openssl ocsp \
-no_nonce \ -no_nonce \
-CAfile ca.pem \ -CAfile ca.pem \

View File

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

View File

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

View File

@ -5,8 +5,8 @@ all:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
clean: clean:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done $(Q)for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
rm -f *~ $(Q)rm -f *~
install: install:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done 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 += -DHOSTAPD
CFLAGS += -DNEED_AP_MLME CFLAGS += -DNEED_AP_MLME
CFLAGS += -DCONFIG_ETH_P_OUI CFLAGS += -DCONFIG_ETH_P_OUI
@ -67,7 +57,4 @@ LIB_OBJS= \
wps_hostapd.o \ wps_hostapd.o \
x_snoop.o x_snoop.o
libap.a: $(LIB_OBJS) include ../lib.rules
$(AR) crT $@ $?
-include $(OBJS:%.o=%.d)

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; int i;
struct hostapd_channel_data *chan; struct hostapd_channel_data *chan;
for (i = 0; i < iface->current_mode->num_channels; i++) { for (i = 0; i < mode->num_channels; i++) {
chan = &iface->current_mode->channels[i]; chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED) if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
acs_clean_chan_surveys(chan); acs_clean_chan_surveys(chan);
@ -276,6 +276,15 @@ void acs_cleanup(struct hostapd_iface *iface)
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED; chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
chan->min_nf = 0; 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->chans_surveyed = 0;
iface->acs_num_completed_scans = 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; int i;
struct hostapd_channel_data *chan; struct hostapd_channel_data *chan;
int valid = 0;
for (i = 0; i < iface->current_mode->num_channels; i++) { for (i = 0; i < mode->num_channels; i++) {
chan = &iface->current_mode->channels[i]; chan = &mode->channels[i];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
acs_survey_list_is_sufficient(chan)) acs_survey_list_is_sufficient(chan))
valid++; return 1;
} }
/* We need at least survey data for one channel */ return 0;
return !!valid; }
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( static int is_in_freqlist(struct hostapd_iface *iface,
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; int i;
struct hostapd_channel_data *chan; struct hostapd_channel_data *chan;
for (i = 0; i < iface->current_mode->num_channels; i++) { for (i = 0; i < mode->num_channels; i++) {
chan = &iface->current_mode->channels[i]; chan = &mode->channels[i];
if (!acs_usable_chan(chan)) if (!acs_usable_chan(chan))
continue; continue;
@ -504,6 +538,9 @@ static void acs_survey_all_chans_intereference_factor(
if (!is_in_chanlist(iface, chan)) if (!is_in_chanlist(iface, chan))
continue; continue;
if (!is_in_freqlist(iface, chan))
continue;
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)", wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
chan->chan, chan->freq); 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, static void acs_survey_all_chans_interference_factor(
int freq) 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; struct hostapd_channel_data *chan;
int i; int i;
for (i = 0; i < iface->current_mode->num_channels; i++) { for (i = 0; i < mode->num_channels; i++) {
chan = &iface->current_mode->channels[i]; chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED) if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue; 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) static int is_24ghz_mode(enum hostapd_hw_mode mode)
{ {
return mode == HOSTAPD_MODE_IEEE80211B || 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 #define ACS_24GHZ_PREFER_1_6_11 0.8
#endif /* ACS_24GHZ_PREFER_1_6_11 */ #endif /* ACS_24GHZ_PREFER_1_6_11 */
/* static void
* At this point it's assumed chan->interface_factor has been computed. acs_find_ideal_chan_mode(struct hostapd_iface *iface,
* This function should be reusable regardless of interference computation struct hostapd_hw_modes *mode,
* option (survey, BSS, spectral, ...). chan->interference factor must be int n_chans, u32 bw,
* summable (i.e., must be always greater than zero). struct hostapd_channel_data **rand_chan,
*/ struct hostapd_channel_data **ideal_chan,
static struct hostapd_channel_data * long double *ideal_factor)
acs_find_ideal_chan(struct hostapd_iface *iface)
{ {
struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL, struct hostapd_channel_data *chan, *adj_chan = NULL;
*rand_chan = NULL; long double factor;
long double factor, ideal_factor = 0;
int i, j; int i, j;
int n_chans = 1;
u32 bw;
unsigned int k; unsigned int k;
/* TODO: HT40- support */ for (i = 0; i < mode->num_channels; i++) {
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++) {
double total_weight; double total_weight;
struct acs_bias *bias, tmp_bias; 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 /* Since in the current ACS implementation the first channel is
* always a primary channel, skip channels not available as * 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)) if (!is_in_chanlist(iface, chan))
continue; continue;
if (!is_in_freqlist(iface, chan))
continue;
if (!chan_bw_allowed(chan, bw, 1, 1)) { if (!chan_bw_allowed(chan, bw, 1, 1)) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"ACS: Channel %d: BW %u is not supported", "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 /* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */ * 11n Annex J */
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
iface->conf->ieee80211n && iface->conf->ieee80211n &&
iface->conf->secondary_channel && iface->conf->secondary_channel &&
!acs_usable_ht40_chan(chan)) { !acs_usable_ht40_chan(chan)) {
@ -646,7 +686,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
continue; continue;
} }
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) { (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
if (hostapd_get_oper_chwidth(iface->conf) == if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_80MHZ && CHANWIDTH_80MHZ &&
@ -698,7 +738,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
* channel interference factor. */ * channel interference factor. */
if (is_24ghz_mode(iface->current_mode->mode)) { if (is_24ghz_mode(mode->mode)) {
for (j = 0; j < n_chans; j++) { for (j = 0; j < n_chans; j++) {
adj_chan = acs_find_chan(iface, chan->freq + adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 5); (j * 20) - 5);
@ -744,7 +784,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
break; break;
bias = NULL; bias = NULL;
} }
} else if (is_24ghz_mode(iface->current_mode->mode) && } else if (is_24ghz_mode(mode->mode) &&
is_common_24ghz_chan(chan->chan)) { is_common_24ghz_chan(chan->chan)) {
tmp_bias.channel = chan->chan; tmp_bias.channel = chan->chan;
tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11; 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) && if (acs_usable_chan(chan) &&
(!ideal_chan || factor < ideal_factor)) { (!*ideal_chan || factor < *ideal_factor)) {
ideal_factor = factor; *ideal_factor = factor;
ideal_chan = chan; *ideal_chan = chan;
} }
/* This channel would at least be usable */ /* This channel would at least be usable */
if (!rand_chan) if (!(*rand_chan))
rand_chan = 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) { if (ideal_chan) {
@ -826,7 +923,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface)
return -1; return -1;
} }
acs_survey_all_chans_intereference_factor(iface); acs_survey_all_chans_interference_factor(iface);
return 0; 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; struct hostapd_channel_data *chan;
int i, *freq; int i;
os_memset(&params, 0, sizeof(params)); for (i = 0; i < mode->num_channels; i++) {
params.freqs = os_calloc(iface->current_mode->num_channels + 1, chan = &mode->channels[i];
sizeof(params.freqs[0]));
if (params.freqs == NULL)
return -1;
freq = params.freqs;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED) if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue; continue;
if (!is_in_chanlist(iface, chan)) if (!is_in_chanlist(iface, chan))
continue; continue;
if (!is_in_freqlist(iface, chan))
continue;
*freq++ = chan->freq; *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; *freq = 0;
if (params.freqs == freq) { if (params.freqs == freq) {
@ -978,7 +1105,8 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
return HOSTAPD_CHAN_ACS; return HOSTAPD_CHAN_ACS;
} }
if (!iface->current_mode) if (!iface->current_mode &&
iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
return HOSTAPD_CHAN_INVALID; return HOSTAPD_CHAN_INVALID;
acs_cleanup(iface); 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, unsigned int num_sta_min = 0, num_sta_prod = 1, num_sta_sum = 0,
wt_sum = 0; wt_sum = 0;
unsigned int quantum; unsigned int quantum;
Boolean all_div_min = TRUE; bool all_div_min = true;
Boolean apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC; bool apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC;
int wt, num_bss = 0, max_wt = 0; int wt, num_bss = 0, max_wt = 0;
size_t i; size_t i;
@ -169,7 +169,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
* integers. */ * integers. */
if (bss->num_backlogged_sta && if (bss->num_backlogged_sta &&
bss->num_backlogged_sta % num_sta_min > 0) 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 /* If we're in LIMIT mode, we only apply the weight
* scaling when the BSS(es) marked as limited would a * 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 (!apply_limit && bss->conf->airtime_limit) {
if (bss->num_backlogged_sta * wt_sum > if (bss->num_backlogged_sta * wt_sum >
bss->conf->airtime_weight * num_sta_sum) bss->conf->airtime_weight * num_sta_sum)
apply_limit = TRUE; apply_limit = true;
} }
} }
if (all_div_min) 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_syslog = (unsigned int) -1;
bss->logger_stdout = (unsigned int) -1; bss->logger_stdout = (unsigned int) -1;
#ifdef CONFIG_WEP
bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED; bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
bss->wep_rekeying_period = 300; bss->wep_rekeying_period = 300;
/* use key0 in individual key and key1 in broadcast key */ /* use key0 in individual key and key1 in broadcast key */
bss->broadcast_key_idx_min = 1; bss->broadcast_key_idx_min = 1;
bss->broadcast_key_idx_max = 2; 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->eap_reauth_period = 3600;
bss->wpa_group_rekey = 600; bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400; bss->wpa_gmk_rekey = 86400;
bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
bss->wpa_group_update_count = 4; bss->wpa_group_update_count = 4;
bss->wpa_pairwise_update_count = 4; bss->wpa_pairwise_update_count = 4;
bss->wpa_disable_eapol_key_retries = bss->wpa_disable_eapol_key_retries =
DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES; DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; 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_pairwise = WPA_CIPHER_TKIP;
bss->wpa_group = WPA_CIPHER_TKIP; bss->wpa_group = WPA_CIPHER_TKIP;
#endif /* CONFIG_NO_TKIP */
bss->rsn_pairwise = 0; bss->rsn_pairwise = 0;
bss->max_num_sta = MAX_STA_COUNT; 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. */ /* Default to strict CRL checking. */
bss->check_crl_strict = 1; 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; HE_OPERATION_RTS_THRESHOLD_OFFSET;
/* Set default basic MCS/NSS set to single stream MCS 0-7 */ /* 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_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 */ #endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character /* 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 hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw; 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 || conf->sae_pwe == 3 ||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt)) !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
return 0; /* PT not needed */ 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) static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{ {
int i; int i;
@ -640,6 +659,7 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
keys->key[i] = NULL; keys->key[i] = NULL;
} }
} }
#endif /* CONFIG_WEP */
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l) 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 #ifdef CONFIG_SAE
sae_deinit_pt(tmp->pt); sae_deinit_pt(tmp->pt);
#endif /* CONFIG_SAE */ #endif /* CONFIG_SAE */
#ifdef CONFIG_SAE_PK
sae_deinit_pk(tmp->pk);
#endif /* CONFIG_SAE_PK */
os_free(tmp); os_free(tmp);
} }
} }
@ -728,7 +751,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
str_clear_free(conf->ssid.wpa_passphrase); str_clear_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file); os_free(conf->ssid.wpa_psk_file);
#ifdef CONFIG_WEP
hostapd_config_free_wep(&conf->ssid.wep); hostapd_config_free_wep(&conf->ssid.wep);
#endif /* CONFIG_WEP */
#ifdef CONFIG_FULL_DYNAMIC_VLAN #ifdef CONFIG_FULL_DYNAMIC_VLAN
os_free(conf->ssid.vlan_tagged_interface); os_free(conf->ssid.vlan_tagged_interface);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */ #endif /* CONFIG_FULL_DYNAMIC_VLAN */
@ -890,7 +915,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override); wpabuf_free(conf->own_ie_override);
wpabuf_free(conf->sae_commit_override); wpabuf_free(conf->sae_commit_override);
wpabuf_free(conf->rsne_override_eapol);
wpabuf_free(conf->rsnxe_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->gtk_rsc_override);
wpabuf_free(conf->igtk_rsc_override); wpabuf_free(conf->igtk_rsc_override);
#endif /* CONFIG_TESTING_OPTIONS */ #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, static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf, struct hostapd_config *conf,
int full_config) int full_config)
@ -1102,6 +1161,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1; return -1;
} }
#ifdef CONFIG_WEP
if (bss->wpa) { if (bss->wpa) {
int wep, i; int wep, i;
@ -1119,6 +1179,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1; return -1;
} }
} }
#endif /* CONFIG_WEP */
if (full_config && bss->wpa && if (full_config && bss->wpa &&
bss->wpa_psk_radius != PSK_RADIUS_IGNORED && 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 */ #endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211N
if (full_config && conf->ieee80211n && if (full_config && conf->ieee80211n &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) { 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 " wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
"allowed, disabling HT capabilities"); "allowed, disabling HT capabilities");
} }
#ifdef CONFIG_WEP
if (full_config && conf->ieee80211n && if (full_config && conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) { 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 " wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
"allowed, disabling HT capabilities"); "allowed, disabling HT capabilities");
} }
#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211n && bss->wpa && if (full_config && conf->ieee80211n && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) && !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256))) 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 " wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
"requires CCMP/GCMP to be enabled, disabling HT " "requires CCMP/GCMP to be enabled, disabling HT "
"capabilities"); "capabilities");
} }
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC #ifdef CONFIG_IEEE80211AC
#ifdef CONFIG_WEP
if (full_config && conf->ieee80211ac && if (full_config && conf->ieee80211ac &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) { bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11ac = 1; bss->disable_11ac = true;
wpa_printf(MSG_ERROR, wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities"); "VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
} }
#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211ac && bss->wpa && if (full_config && conf->ieee80211ac && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) && !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256))) WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{ {
bss->disable_11ac = 1; bss->disable_11ac = true;
wpa_printf(MSG_ERROR, wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities"); "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; bss->wps_state = 0;
} }
#ifdef CONFIG_WEP
if (full_config && bss->wps_state && if (full_config && bss->wps_state &&
bss->ssid.wep.keys_set && bss->wpa == 0) { bss->ssid.wep.keys_set && bss->wpa == 0) {
wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be " wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
"disabled"); "disabled");
bss->wps_state = 0; bss->wps_state = 0;
} }
#endif /* CONFIG_WEP */
if (full_config && bss->wps_state && bss->wpa && if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) || (!(bss->wpa & 2) ||
@ -1268,6 +1333,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
} }
#endif /* CONFIG_OCV */ #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; 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, void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config) int full_config)
{ {
#ifdef CONFIG_WEP
if (bss->individual_wep_key_len == 0) { if (bss->individual_wep_key_len == 0) {
/* individual keys are not use; can use key idx0 for /* individual keys are not use; can use key idx0 for
* broadcast keys */ * broadcast keys */
bss->broadcast_key_idx_min = 0; bss->broadcast_key_idx_min = 0;
} }
#endif /* CONFIG_WEP */
if ((bss->wpa & 2) && bss->rsn_pairwise == 0) if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
bss->rsn_pairwise = bss->wpa_pairwise; 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) { } else if (bss->ieee802_1x) {
int cipher = WPA_CIPHER_NONE; int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X; bss->ssid.security_policy = SECURITY_IEEE_802_1X;
#ifdef CONFIG_WEP
bss->ssid.wep.default_len = bss->default_wep_key_len; bss->ssid.wep.default_len = bss->default_wep_key_len;
if (full_config && bss->default_wep_key_len) { if (full_config && bss->default_wep_key_len) {
cipher = bss->default_wep_key_len >= 13 ? cipher = bss->default_wep_key_len >= 13 ?
@ -1388,11 +1465,13 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
else else
cipher = WPA_CIPHER_WEP40; cipher = WPA_CIPHER_WEP40;
} }
#endif /* CONFIG_WEP */
bss->wpa_group = cipher; bss->wpa_group = cipher;
bss->wpa_pairwise = cipher; bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher; bss->rsn_pairwise = cipher;
if (full_config) if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA; bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
#ifdef CONFIG_WEP
} else if (bss->ssid.wep.keys_set) { } else if (bss->ssid.wep.keys_set) {
int cipher = WPA_CIPHER_WEP40; int cipher = WPA_CIPHER_WEP40;
if (bss->ssid.wep.len[0] >= 13) 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; bss->rsn_pairwise = cipher;
if (full_config) if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE; bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
#endif /* CONFIG_WEP */
} else if (bss->osen) { } else if (bss->osen) {
bss->ssid.security_policy = SECURITY_OSEN; bss->ssid.security_policy = SECURITY_OSEN;
bss->wpa_group = WPA_CIPHER_CCMP; 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 2;
return with_id; 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_r0kh;
struct ft_remote_r1kh; struct ft_remote_r1kh;
#ifdef CONFIG_WEP
#define NUM_WEP_KEYS 4 #define NUM_WEP_KEYS 4
struct hostapd_wep_keys { struct hostapd_wep_keys {
u8 idx; u8 idx;
@ -75,10 +76,13 @@ struct hostapd_wep_keys {
int keys_set; int keys_set;
size_t default_len; /* key length used for dynamic key generation */ size_t default_len; /* key length used for dynamic key generation */
}; };
#endif /* CONFIG_WEP */
typedef enum hostap_security_policy { typedef enum hostap_security_policy {
SECURITY_PLAINTEXT = 0, SECURITY_PLAINTEXT = 0,
#ifdef CONFIG_WEP
SECURITY_STATIC_WEP = 1, SECURITY_STATIC_WEP = 1,
#endif /* CONFIG_WEP */
SECURITY_IEEE_802_1X = 2, SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3, SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4, SECURITY_WPA = 4,
@ -102,7 +106,9 @@ struct hostapd_ssid {
char *wpa_psk_file; char *wpa_psk_file;
struct sae_pt *pt; struct sae_pt *pt;
#ifdef CONFIG_WEP
struct hostapd_wep_keys wep; struct hostapd_wep_keys wep;
#endif /* CONFIG_WEP */
#define DYNAMIC_VLAN_DISABLED 0 #define DYNAMIC_VLAN_DISABLED 0
#define DYNAMIC_VLAN_OPTIONAL 1 #define DYNAMIC_VLAN_OPTIONAL 1
@ -191,15 +197,6 @@ struct hostapd_radius_attr {
#define NUM_TX_QUEUES 4 #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 #define MAX_ROAMING_CONSORTIUM_LEN 15
struct hostapd_roaming_consortium { struct hostapd_roaming_consortium {
@ -255,6 +252,7 @@ struct sae_password_entry {
u8 peer_addr[ETH_ALEN]; u8 peer_addr[ETH_ALEN];
int vlan_id; int vlan_id;
struct sae_pt *pt; struct sae_pt *pt;
struct sae_pk *pk;
}; };
struct dpp_controller_conf { struct dpp_controller_conf {
@ -321,10 +319,12 @@ struct hostapd_bss_config {
size_t eap_req_id_text_len; size_t eap_req_id_text_len;
int eapol_key_index_workaround; int eapol_key_index_workaround;
#ifdef CONFIG_WEP
size_t default_wep_key_len; size_t default_wep_key_len;
int individual_wep_key_len; int individual_wep_key_len;
int wep_rekeying_period; int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max; int broadcast_key_idx_min, broadcast_key_idx_max;
#endif /* CONFIG_WEP */
int eap_reauth_period; int eap_reauth_period;
int erp_send_reauth_start; int erp_send_reauth_start;
char *erp_domain; char *erp_domain;
@ -346,9 +346,11 @@ struct hostapd_bss_config {
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */ int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
int extended_key_id;
int wpa_key_mgmt; int wpa_key_mgmt;
enum mfp_options ieee80211w; enum mfp_options ieee80211w;
int group_mgmt_cipher; int group_mgmt_cipher;
int beacon_prot;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */ /* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout; unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */ /* dot11AssociationSAQueryRetryTimeout (in TUs) */
@ -369,6 +371,7 @@ struct hostapd_bss_config {
int wpa_strict_rekey; int wpa_strict_rekey;
int wpa_gmk_rekey; int wpa_gmk_rekey;
int wpa_ptk_rekey; int wpa_ptk_rekey;
enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
u32 wpa_group_update_count; u32 wpa_group_update_count;
u32 wpa_pairwise_update_count; u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries; int wpa_disable_eapol_key_retries;
@ -528,8 +531,9 @@ struct hostapd_bss_config {
#define TDLS_PROHIBIT BIT(0) #define TDLS_PROHIBIT BIT(0)
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1) #define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls; int tdls;
int disable_11n; bool disable_11n;
int disable_11ac; bool disable_11ac;
bool disable_11ax;
/* IEEE 802.11v */ /* IEEE 802.11v */
int time_advertisement; int time_advertisement;
@ -666,10 +670,26 @@ struct hostapd_bss_config {
u8 bss_load_test_set; u8 bss_load_test_set;
struct wpabuf *own_ie_override; struct wpabuf *own_ie_override;
int sae_reflection_attack; 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 *sae_commit_override;
struct wpabuf *rsne_override_eapol;
struct wpabuf *rsnxe_override_eapol; struct wpabuf *rsnxe_override_eapol;
struct wpabuf *rsne_override_ft;
struct wpabuf *rsnxe_override_ft;
struct wpabuf *gtk_rsc_override; struct wpabuf *gtk_rsc_override;
struct wpabuf *igtk_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 */ #endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0) #define MESH_ENABLED BIT(0)
@ -725,6 +745,8 @@ struct hostapd_bss_config {
struct wpabuf *dpp_csign; struct wpabuf *dpp_csign;
#ifdef CONFIG_DPP2 #ifdef CONFIG_DPP2
struct dpp_controller_conf *dpp_controller; struct dpp_controller_conf *dpp_controller;
int dpp_configurator_connectivity;
int dpp_pfs;
#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */ #endif /* CONFIG_DPP */
@ -741,6 +763,8 @@ struct hostapd_bss_config {
u8 send_probe_response; u8 send_probe_response;
u8 transition_disable;
#define BACKHAUL_BSS 1 #define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2 #define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */ 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 - HE PHY capabilities
*/ */
struct he_phy_capabilities_info { struct he_phy_capabilities_info {
Boolean he_su_beamformer; bool he_su_beamformer;
Boolean he_su_beamformee; bool he_su_beamformee;
Boolean he_mu_beamformer; bool he_mu_beamformer;
}; };
/** /**
@ -854,6 +878,8 @@ struct he_phy_capabilities_info {
*/ */
struct he_operation { struct he_operation {
u8 he_bss_color; u8 he_bss_color;
u8 he_bss_color_disabled;
u8 he_bss_color_partial;
u8 he_default_pe_duration; u8 he_default_pe_duration;
u8 he_twt_required; u8 he_twt_required;
u16 he_rts_threshold; u16 he_rts_threshold;
@ -1013,6 +1039,7 @@ struct hostapd_config {
int rssi_reject_assoc_rssi; int rssi_reject_assoc_rssi;
int rssi_reject_assoc_timeout; int rssi_reject_assoc_timeout;
int rssi_ignore_probe_request;
#ifdef CONFIG_AIRTIME_POLICY #ifdef CONFIG_AIRTIME_POLICY
enum { 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, void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config); int full_config);
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf); 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); int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */ #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_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab, const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len, 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, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set) int set)
{ {
@ -439,6 +440,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.vht_capabilities = vht_capab; params.vht_capabilities = vht_capab;
params.he_capab = he_capab; params.he_capab = he_capab;
params.he_capab_len = he_capab_len; 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_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode; params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags); 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 hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and) 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 0;
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags, return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
flags_or, flags_and); 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, int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params) 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) if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
return 0; return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 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.freq_list = freq_list;
params.edmg_enabled = hapd->iface->conf->enable_edmg;
params.ht_enabled = !!(hapd->iface->conf->ieee80211n); params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab & 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_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab, const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len, 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, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set); int set);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled); 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); u16 *flags, u8 *dfs_domain);
int hostapd_driver_commit(struct hostapd_data *hapd); int hostapd_driver_commit(struct hostapd_data *hapd);
int hostapd_drv_none(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, int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params); struct wpa_driver_scan_params *params);
struct wpa_scan_results * hostapd_driver_get_scan_results( 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, static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
int vendor_id, int subcmd, int vendor_id, int subcmd,
const u8 *data, size_t data_len, const u8 *data, size_t data_len,
enum nested_attr nested_attr_flag,
struct wpabuf *buf) struct wpabuf *buf)
{ {
if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL) if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
return -1; return -1;
return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data, 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) 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 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) if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
return -1; 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 */ #endif /* AP_DRV_OPS */

View File

@ -228,7 +228,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
set_beacon++; set_beacon++;
} }
#ifdef CONFIG_IEEE80211N
if (!iface->olbc_ht && !ap->ht_support && if (!iface->olbc_ht && !ap->ht_support &&
(ap->channel == 0 || (ap->channel == 0 ||
ap->channel == iface->conf->channel || ap->channel == iface->conf->channel ||
@ -241,7 +240,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
MAC2STR(ap->addr), ap->channel); MAC2STR(ap->addr), ap->channel);
set_beacon++; set_beacon++;
} }
#endif /* CONFIG_IEEE80211N */
if (set_beacon) if (set_beacon)
ieee802_11_update_beacons(iface); ieee802_11_update_beacons(iface);
@ -285,14 +283,12 @@ void ap_list_timer(struct hostapd_iface *iface)
iface->olbc = 0; iface->olbc = 0;
set_beacon++; set_beacon++;
} }
#ifdef CONFIG_IEEE80211N
if (!olbc_ht && iface->olbc_ht) { if (!olbc_ht && iface->olbc_ht) {
wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore"); wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
iface->olbc_ht = 0; iface->olbc_ht = 0;
hostapd_ht_operation_update(iface); hostapd_ht_operation_update(iface);
set_beacon++; set_beacon++;
} }
#endif /* CONFIG_IEEE80211N */
} }
if (set_beacon) 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; const u8 *ie;
size_t ielen;
ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
if (ie == NULL || ielen > len) if (!ie || 2U + ie[1] > len)
return eid; return pos;
os_memcpy(eid, ie, ielen); os_memcpy(pos, ie, 2 + ie[1]);
return eid + ielen; 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 #ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) { if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
buflen += 3 + sizeof(struct ieee80211_he_capabilities) + buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) + 3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) + 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse); 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 */ #endif /* CONFIG_IEEE80211AX */
buflen += hostapd_mbo_ie_len(hapd); buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd); buflen += hostapd_eid_owe_trans_len(hapd);
buflen += hostapd_eid_dpp_cc_len(hapd);
resp = os_zalloc(buflen); resp = os_zalloc(buflen);
if (resp == NULL) if (resp == NULL)
@ -434,14 +522,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* Extended supported rates */ /* Extended supported rates */
pos = hostapd_eid_ext_supp_rates(hapd, pos); pos = hostapd_eid_ext_supp_rates(hapd, pos);
/* RSN, MDIE */ pos = hostapd_get_rsne(hapd, pos, epos - pos);
if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
(hapd->conf->osen && !hapd->conf->wpa)))
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(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_eid_rm_enabled_capab(hapd, pos, epos - pos);
pos = hostapd_get_mde(hapd, pos, epos - pos);
/* eCSA IE */ /* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, pos); 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 = csa_pos;
pos = hostapd_eid_supported_op_classes(hapd, 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_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos); pos = hostapd_eid_ht_operation(hapd, pos);
#endif /* CONFIG_IEEE80211N */
pos = hostapd_eid_ext_capab(hapd, pos); 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_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos); pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos); pos = hostapd_eid_txpower_envelope(hapd, pos);
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
} }
#endif /* CONFIG_IEEE80211AC */ #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_eid_fils_indic(hapd, pos, 0);
pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211AX #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_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_he_operation(hapd, pos); 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_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 */ #endif /* CONFIG_IEEE80211AX */
@ -503,10 +585,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_vendor_vht(hapd, pos); pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */ #endif /* CONFIG_IEEE80211AC */
/* WPA */ /* WPA / OSEN */
if (hapd->conf->wpa == WPA_PROTO_WPA || pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
(hapd->conf->osen && !hapd->conf->wpa)) pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
/* Wi-Fi Alliance WMM */ /* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos); 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_mbo(hapd, pos, (u8 *) resp + buflen - pos);
pos = hostapd_eid_owe_trans(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) { if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(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; size_t csa_offs_len;
struct radius_sta rad_info; 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) if (len < IEEE80211_HDRLEN)
return; return;
ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN; 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; size_t resp_len = 0;
#ifdef NEED_AP_MLME #ifdef NEED_AP_MLME
u16 capab_info; u16 capab_info;
u8 *pos, *tailpos, *csa_pos; u8 *pos, *tailpos, *tailend, *csa_pos;
#define BEACON_HEAD_BUF_SIZE 256 #define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512 #define BEACON_TAIL_BUF_SIZE 512
@ -1081,16 +1167,20 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211AC */ #endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX #ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) { if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) + tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) + 3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) + 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse); 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 */ #endif /* CONFIG_IEEE80211AX */
tail_len += hostapd_mbo_ie_len(hapd); tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd); tail_len += hostapd_eid_owe_trans_len(hapd);
tail_len += hostapd_eid_dpp_cc_len(hapd);
tailpos = tail = os_malloc(tail_len); tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) { if (head == NULL || tail == NULL) {
@ -1099,6 +1189,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
os_free(tail); os_free(tail);
return -1; return -1;
} }
tailend = tail + tail_len;
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_BEACON); WLAN_FC_STYPE_BEACON);
@ -1139,8 +1230,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
head_len = pos - (u8 *) head; head_len = pos - (u8 *) head;
tailpos = hostapd_eid_country(hapd, tailpos, tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
tail + BEACON_TAIL_BUF_SIZE - tailpos);
/* Power Constraint element */ /* Power Constraint element */
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos); tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
@ -1157,19 +1247,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
/* Extended supported rates */ /* Extended supported rates */
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
/* RSN, MDIE */ tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
if (!(hapd->conf->wpa == WPA_PROTO_WPA || tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
(hapd->conf->osen && !hapd->conf->wpa)))
tailpos = hostapd_eid_wpa(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE -
tailpos);
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos, tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailend - tailpos);
tailpos); tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
tailpos = hostapd_eid_bss_load(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
/* eCSA IE */ /* eCSA IE */
csa_pos = hostapd_eid_ecsa(hapd, tailpos); 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 = csa_pos;
tailpos = hostapd_eid_supported_op_classes(hapd, tailpos); 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_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos); tailpos = hostapd_eid_ht_operation(hapd, tailpos);
#endif /* CONFIG_IEEE80211N */
tailpos = hostapd_eid_ext_capab(hapd, tailpos); 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_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos); tailpos = hostapd_eid_vht_operation(hapd, tailpos);
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos); tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
} }
#endif /* CONFIG_IEEE80211AC */ #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_eid_fils_indic(hapd, tailpos, 0);
tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
#ifdef CONFIG_IEEE80211AX #ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) { if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
tailpos = hostapd_eid_he_capab(hapd, tailpos, tailpos = hostapd_eid_he_capab(hapd, tailpos,
IEEE80211_MODE_AP); IEEE80211_MODE_AP);
tailpos = hostapd_eid_he_operation(hapd, tailpos); 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_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 */ #endif /* CONFIG_IEEE80211AX */
@ -1234,12 +1314,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_vendor_vht(hapd, tailpos); tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */ #endif /* CONFIG_IEEE80211AC */
/* WPA */ /* WPA / OSEN */
if (hapd->conf->wpa == WPA_PROTO_WPA || tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
(hapd->conf->osen && !hapd->conf->wpa)) tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
tailpos = hostapd_eid_wpa(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE -
tailpos);
/* Wi-Fi Alliance WMM */ /* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos); 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_mbo(hapd, tailpos, tail + tail_len - tailpos);
tailpos = hostapd_eid_owe_trans(hapd, tailpos, tailpos = hostapd_eid_owe_trans(hapd, tailpos,
tail + tail_len - tailpos); tail + tail_len - tailpos);
tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
if (hapd->conf->vendor_elements) { if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(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->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->auth_algs = hapd->conf->auth_algs; params->auth_algs = hapd->conf->auth_algs;
params->wpa_version = hapd->conf->wpa; 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->ieee802_1x &&
(hapd->conf->default_wep_key_len || (hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len)); hapd->conf->individual_wep_key_len));
#endif /* CONFIG_WEP */
switch (hapd->conf->ignore_broadcast_ssid) { switch (hapd->conf->ignore_broadcast_ssid) {
case 0: case 0:
params->hide_ssid = NO_SSID_HIDING; params->hide_ssid = NO_SSID_HIDING;
@ -1326,7 +1407,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
break; break;
} }
params->isolate = hapd->conf->isolate; params->isolate = hapd->conf->isolate;
params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
#ifdef NEED_AP_MLME #ifdef NEED_AP_MLME
params->cts_protect = !!(ieee802_11_erp_info(hapd) & params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION); 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; hapd->iface->conf->spr.srg_obss_pd_min_offset;
params.he_spr_srg_obss_pd_max_offset = params.he_spr_srg_obss_pd_max_offset =
hapd->iface->conf->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 */ #endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0; hapd->reenable_beacon = 0;
#ifdef CONFIG_SAE
params.sae_pwe = hapd->conf->sae_pwe;
#endif /* CONFIG_SAE */
if (cmode && if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq, 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 */ #endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211N
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) { if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
res = os_snprintf(buf + len, buflen - len, res = os_snprintf(buf + len, buflen - len,
"ht_caps_info=0x%04x\n", "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)) if (!os_snprintf_error(buflen - len, res))
len += res; len += res;
} }
#endif /* CONFIG_IEEE80211N */
if (sta->ext_capability && if (sta->ext_capability &&
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) { 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->ieee80211n && !hapd->conf->disable_11n,
iface->conf->ieee80211ac && iface->conf->ieee80211ac &&
!hapd->conf->disable_11ac, !hapd->conf->disable_11ac,
iface->conf->ieee80211ax, iface->conf->ieee80211ax &&
!hapd->conf->disable_11ax,
iface->conf->beacon_int, iface->conf->beacon_int,
hapd->conf->dtim_period); hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret)) if (os_snprintf_error(buflen - len, ret))
@ -758,7 +757,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
len += ret; len += ret;
#ifdef CONFIG_IEEE80211AX #ifdef CONFIG_IEEE80211AX
if (iface->conf->ieee80211ax) { if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
ret = os_snprintf(buf + len, buflen - len, ret = os_snprintf(buf + len, buflen - len,
"he_oper_chwidth=%d\n" "he_oper_chwidth=%d\n"
"he_oper_centr_freq_seg0_idx=%d\n" "he_oper_centr_freq_seg0_idx=%d\n"

View File

@ -144,30 +144,44 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int i; int i;
u32 bw = num_chan_to_bw(num_chans); 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; return 0;
}
first_chan = &mode->channels[first_chan_idx]; first_chan = &mode->channels[first_chan_idx];
/* hostapd DFS implementation assumes the first channel as primary. /* hostapd DFS implementation assumes the first channel as primary.
* If it's not allowed to use the first channel as primary, decline the * If it's not allowed to use the first channel as primary, decline the
* whole channel range. */ * 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; return 0;
}
for (i = 0; i < num_chans; i++) { for (i = 0; i < num_chans; i++) {
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20, chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
first_chan_idx); first_chan_idx);
if (!chan) if (!chan) {
wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
first_chan->freq + i * 20);
return 0; return 0;
}
/* HT 40 MHz secondary channel availability checked only for /* HT 40 MHz secondary channel availability checked only for
* primary channel */ * 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; 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 0;
}
} }
return 1; return 1;
@ -210,22 +224,36 @@ static int dfs_find_channel(struct hostapd_iface *iface,
if (iface->conf->ieee80211n && if (iface->conf->ieee80211n &&
iface->conf->secondary_channel && iface->conf->secondary_channel &&
(!dfs_is_chan_allowed(chan, n_chans) || (!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; continue;
}
/* Skip incompatible chandefs */ /* 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; 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; continue;
}
if (ret_chan && idx == channel_idx) { 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; *ret_chan = chan;
return idx; 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++; channel_idx++;
} }
return 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, static void dfs_adjust_center_freq(struct hostapd_iface *iface,
struct hostapd_channel_data *chan, struct hostapd_channel_data *chan,
int secondary_channel, int secondary_channel,
int sec_chan_idx_80p80,
u8 *oper_centr_freq_seg0_idx, u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx) u8 *oper_centr_freq_seg1_idx)
{ {
@ -261,8 +290,14 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
case CHANWIDTH_160MHZ: case CHANWIDTH_160MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 14; *oper_centr_freq_seg0_idx = chan->chan + 14;
break; break;
case CHANWIDTH_80P80MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 6;
*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
break;
default: 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; *oper_centr_freq_seg0_idx = 0;
break; break;
} }
@ -441,8 +476,11 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
{ {
struct hostapd_hw_modes *mode; struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL; struct hostapd_channel_data *chan = NULL;
struct hostapd_channel_data *chan2 = NULL;
int num_available_chandefs; int num_available_chandefs;
int chan_idx; int chan_idx, chan_idx2;
int sec_chan_idx_80p80 = -1;
int i;
u32 _rand; u32 _rand;
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
@ -459,6 +497,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
/* Get the count first */ /* Get the count first */
num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); 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) if (num_available_chandefs == 0)
return NULL; return NULL;
@ -466,6 +506,12 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
return NULL; return NULL;
chan_idx = _rand % num_available_chandefs; chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar); 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+ */ /* dfs_find_channel() calculations assume HT40+ */
if (iface->conf->secondary_channel) if (iface->conf->secondary_channel)
@ -473,8 +519,45 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
else else
*secondary_channel = 0; *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, dfs_adjust_center_freq(iface, chan,
*secondary_channel, *secondary_channel,
sec_chan_idx_80p80,
oper_centr_freq_seg0_idx, oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_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; 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. * another radio.
*/ */
if (iface->state != HAPD_IFACE_ENABLED && if (iface->state != HAPD_IFACE_ENABLED &&
hostapd_config_dfs_chan_available(iface)) { hostapd_is_dfs_chan_available(iface)) {
hostapd_setup_interface_complete(iface, 0); hostapd_setup_interface_complete(iface, 0);
iface->cac_started = 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) static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
{ {
struct hostapd_channel_data *channel; struct hostapd_channel_data *channel;
@ -868,8 +989,14 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
skip_radar); skip_radar);
if (!channel) { if (!channel) {
wpa_printf(MSG_ERROR, "No valid channel available"); channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
return err; &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", wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@ -898,11 +1025,14 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
int secondary_channel; int secondary_channel;
u8 oper_centr_freq_seg0_idx; u8 oper_centr_freq_seg0_idx;
u8 oper_centr_freq_seg1_idx; u8 oper_centr_freq_seg1_idx;
u8 new_vht_oper_chwidth;
int skip_radar = 1; int skip_radar = 1;
struct csa_settings csa_settings; struct csa_settings csa_settings;
unsigned int i; unsigned int i;
int err = 1; int err = 1;
struct hostapd_hw_modes *cmode = iface->current_mode; 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)", wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no", __func__, iface->cac_started ? "yes" : "no",
@ -936,28 +1066,33 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
* requires to perform a CAC first. * requires to perform a CAC first.
*/ */
skip_radar = 0; 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_seg0_idx,
&oper_centr_freq_seg1_idx, &oper_centr_freq_seg1_idx,
skip_radar); &skip_radar);
if (!channel) { if (!channel) {
wpa_printf(MSG_INFO, /*
"%s: no DFS channels left, waiting for NOP to finish", * Toggle interface state to enter DFS state
__func__); * until NOP is finished.
return err; */
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
return 0;
} }
iface->freq = channel->freq; if (!skip_radar) {
iface->conf->channel = channel->chan; iface->freq = channel->freq;
iface->conf->secondary_channel = secondary_channel; iface->conf->channel = channel->chan;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, iface->conf->secondary_channel = secondary_channel;
oper_centr_freq_seg0_idx); hostapd_set_oper_centr_freq_seg0_idx(
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, iface->conf, oper_centr_freq_seg0_idx);
oper_centr_freq_seg1_idx); hostapd_set_oper_centr_freq_seg1_idx(
iface->conf, oper_centr_freq_seg1_idx);
hostapd_disable_iface(iface); hostapd_disable_iface(iface);
hostapd_enable_iface(iface); hostapd_enable_iface(iface);
return 0; return 0;
}
} }
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@ -966,10 +1101,17 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
"freq=%d chan=%d sec_chan=%d", channel->freq, "freq=%d chan=%d sec_chan=%d", channel->freq,
channel->chan, secondary_channel); 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 */ /* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings)); os_memset(&csa_settings, 0, sizeof(csa_settings));
csa_settings.cs_count = 5; csa_settings.cs_count = 5;
csa_settings.block_tx = 1; 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, err = hostapd_set_freq_params(&csa_settings.freq_params,
iface->conf->hw_mode, iface->conf->hw_mode,
channel->freq, channel->freq,
@ -980,11 +1122,11 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
iface->conf->ieee80211ac, iface->conf->ieee80211ac,
iface->conf->ieee80211ax, iface->conf->ieee80211ax,
secondary_channel, secondary_channel,
hostapd_get_oper_chwidth(iface->conf), new_vht_oper_chwidth,
oper_centr_freq_seg0_idx, oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx, oper_centr_freq_seg1_idx,
cmode->vht_capab, cmode->vht_capab,
&cmode->he_capab[IEEE80211_MODE_AP]); &cmode->he_capab[ieee80211_mode]);
if (err) { if (err) {
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); 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->freq = channel->freq;
iface->conf->channel = channel->chan; iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel; 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, hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx); oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 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; return 0;
/* mark radar frequency as invalid */ /* 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); cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
if (!res)
return 0;
/* Skip if reported radar event not overlapped our channels */ /* Skip if reported radar event not overlapped our channels */
res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); 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); __func__, iface->freq);
return 2; 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 ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2); int chan_offset, int chan_width, int cf1, int cf2);
int hostapd_is_dfs_required(struct hostapd_iface *iface); 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 hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width, int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2); int cf1, int cf2);
int hostapd_handle_dfs_offload(struct hostapd_iface *iface); 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 */ #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_auth_success(struct hostapd_data *hapd, int initiator);
static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx); static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd); 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 }; 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)); 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; return bi->id;
} }
@ -237,6 +248,10 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
hapd, NULL); hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL); 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); hostapd_drv_send_action_cancel_wait(hapd);
dpp_auth_deinit(hapd->dpp_auth); dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL; 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) int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
{ {
const char *pos; const char *pos;
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL; struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
struct dpp_authentication *auth;
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR; u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
unsigned int neg_freq = 0; 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="); pos = os_strstr(cmd, " peer=");
if (!pos) if (!pos)
@ -496,6 +534,25 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
return -1; 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="); pos = os_strstr(cmd, " own=");
if (pos) { if (pos) {
pos += 5; pos += 5;
@ -533,36 +590,46 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
if (pos) if (pos)
neg_freq = atoi(pos + 10); 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_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
hapd, NULL); hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL); 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); hostapd_drv_send_action_cancel_wait(hapd);
dpp_auth_deinit(hapd->dpp_auth); dpp_auth_deinit(hapd->dpp_auth);
} }
hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi, auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
allowed_roles, neg_freq, peer_bi, own_bi, allowed_roles, neg_freq,
hapd->iface->hw_features, hapd->iface->hw_features,
hapd->iface->num_hw_features); hapd->iface->num_hw_features);
if (!hapd->dpp_auth) if (!auth)
goto fail; goto fail;
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); hostapd_dpp_set_testing_options(hapd, auth);
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx, if (dpp_set_configurator(auth, cmd) < 0) {
hapd->dpp_auth, cmd) < 0) { dpp_auth_deinit(auth);
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
goto fail; goto fail;
} }
hapd->dpp_auth->neg_freq = neg_freq; auth->neg_freq = neg_freq;
if (!is_zero_ether_addr(peer_bi->mac_addr)) if (!is_zero_ether_addr(peer_bi->mac_addr))
os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr, os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
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); return hostapd_dpp_auth_init_next(hapd);
fail: fail:
return -1; 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, wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
MAC2STR(src)); 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 = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len); &r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_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_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, hapd->dpp_qr_mutual,
peer_bi, own_bi, freq, hdr, buf, len); peer_bi, own_bi, freq, hdr, buf, len);
if (!hapd->dpp_auth) { if (!hapd->dpp_auth) {
@ -671,8 +743,7 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
return; return;
} }
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx, if (dpp_set_configurator(hapd->dpp_auth,
hapd->dpp_auth,
hapd->dpp_configurator_params) < 0) { hapd->dpp_configurator_params) < 0) {
dpp_auth_deinit(hapd->dpp_auth); dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL; hapd->dpp_auth = NULL;
@ -708,7 +779,8 @@ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
* message. */ * message. */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s", wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
conf->connector); conf->connector);
} else if (conf->passphrase[0]) { }
if (conf->passphrase[0]) {
char hex[64 * 2 + 1]; char hex[64 * 2 + 1];
wpa_snprintf_hex(hex, sizeof(hex), 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 */ #endif /* CONFIG_DPP2 */
@ -1141,9 +1434,13 @@ static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
enum dpp_status_error status) enum dpp_status_error status)
{ {
struct wpabuf *msg; struct wpabuf *msg;
size_t len;
msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP, len = 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector);
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) if (!msg)
return; return;
@ -1216,6 +1513,15 @@ skip_status:
skip_connector: skip_connector:
#endif /* CONFIG_TESTING_OPTIONS */ #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 wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
" status=%d", MAC2STR(src), status); " status=%d", MAC2STR(src), status);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR 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: case DPP_PA_CONNECTION_STATUS_RESULT:
hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len); hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len);
break; 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 */ #endif /* CONFIG_DPP2 */
default: default:
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
@ -1610,7 +1928,7 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
struct wpabuf *resp; struct wpabuf *resp;
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa)); 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) { os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
#ifdef CONFIG_DPP2 #ifdef CONFIG_DPP2
if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data, 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_reply_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2 #ifdef CONFIG_DPP2
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
hapd, NULL);
if (ok && auth->peer_version >= 2 && if (ok && auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) { auth->conf_resp_status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); 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; int ret = -1;
char *curve = NULL; char *curve = NULL;
auth = os_zalloc(sizeof(*auth)); auth = dpp_alloc_auth(hapd->iface->interfaces->dpp, hapd->msg_ctx);
if (!auth) if (!auth)
return -1; return -1;
curve = get_param(cmd, " curve="); curve = get_param(cmd, " curve=");
hostapd_dpp_set_testing_options(hapd, auth); hostapd_dpp_set_testing_options(hapd, auth);
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx, if (dpp_set_configurator(auth, cmd) == 0 &&
auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 1) == 0) { dpp_configurator_own_config(auth, curve, 1) == 0) {
hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]); hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
ret = 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_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2 #ifdef CONFIG_DPP2
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd, eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL); NULL);
eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd, eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
NULL); NULL);
hostapd_dpp_chirp_stop(hapd);
#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth); dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL; hapd->dpp_auth = NULL;
@ -1903,3 +2225,359 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
os_free(hapd->dpp_configurator_params); os_free(hapd->dpp_configurator_params);
hapd->dpp_configurator_params = NULL; 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 #ifndef DPP_HOSTAPD_H
#define 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_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_uri(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_nfc_handover_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_init_global(struct hapd_interfaces *ifaces);
void hostapd_dpp_deinit_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 */ #endif /* DPP_HOSTAPD_H */

View File

@ -106,18 +106,45 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */ #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, int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *req_ies, size_t req_ies_len, int reassoc) const u8 *req_ies, size_t req_ies_len, int reassoc)
{ {
struct sta_info *sta; struct sta_info *sta;
int new_assoc, res; int new_assoc;
enum wpa_validate_result res;
struct ieee802_11_elems elems; struct ieee802_11_elems elems;
const u8 *ie; const u8 *ie;
size_t ielen; size_t ielen;
u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf; u8 *p = buf;
u16 reason = WLAN_REASON_UNSPECIFIED; u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS; int status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL; const u8 *p2p_dev_addr = NULL;
if (addr == NULL) { if (addr == NULL) {
@ -226,7 +253,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
} }
#endif /* CONFIG_P2P */ #endif /* CONFIG_P2P */
#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME #ifdef NEED_AP_MLME
if (elems.ht_capabilities && if (elems.ht_capabilities &&
(hapd->iface->conf->ht_capab & (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); ht40_intolerant_add(hapd->iface, sta);
} }
#endif /* NEED_AP_MLME */ #endif /* NEED_AP_MLME */
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_INTERWORKING #ifdef CONFIG_INTERWORKING
if (elems.ext_capab && elems.ext_capab_len > 4) { 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) { os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
struct wpabuf *wps; 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; sta->flags |= WLAN_STA_WPS;
wps = ieee802_11_vendor_ie_concat(ie, ielen, wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE); 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.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len, elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_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_printf(MSG_DEBUG,
"WPA/RSN information element rejected? (res %u)", "WPA/RSN information element rejected? (res %u)",
res); res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); 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; goto fail;
} }
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == if (check_sa_query_need(hapd, sta)) {
(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);
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
p = hostapd_eid_assoc_comeback_time(hapd, sta, p); 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 #ifdef CONFIG_SAE
if (hapd->conf->sae_pwe == 2 && if (hapd->conf->sae_pwe == 2 &&
sta->auth_alg == WLAN_AUTH_SAE && 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 && elems.rsnxe_len >= 1 &&
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) { (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
wpa_printf(MSG_INFO, "SAE: " MACSTR 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; return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */ #endif /* CONFIG_HS20 */
} }
#ifdef CONFIG_WPS
skip_wpa_check:
#endif /* CONFIG_WPS */
#ifdef CONFIG_MBO #ifdef CONFIG_MBO
if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) && 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 */ #endif /* CONFIG_MBO */
#ifdef CONFIG_WPS
skip_wpa_check:
#endif /* CONFIG_WPS */
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), 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) { if (!p) {
wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs"); wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
@ -579,17 +631,19 @@ skip_wpa_check:
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE && wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
elems.owe_dh) { elems.owe_dh) {
u8 *npos; u8 *npos;
u16 ret_status;
npos = owe_assoc_req_process(hapd, sta, npos = owe_assoc_req_process(hapd, sta,
elems.owe_dh, elems.owe_dh_len, elems.owe_dh, elems.owe_dh_len,
p, sizeof(buf) - (p - buf), p, sizeof(buf) - (p - buf),
&status); &ret_status);
status = ret_status;
if (npos) if (npos)
p = npos; p = npos;
if (!npos && if (!npos &&
status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { 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); p - buf);
return 0; return 0;
} }
@ -631,6 +685,11 @@ skip_wpa_check:
pfs_fail: pfs_fail:
#endif /* CONFIG_DPP2 */ #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) #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
@ -677,7 +736,8 @@ skip_wpa_check:
fail: fail:
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); if (status >= 0)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#endif /* CONFIG_IEEE80211R_AP */ #endif /* CONFIG_IEEE80211R_AP */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason); hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta); ap_free_sta(hapd, sta);
@ -715,6 +775,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
ap_sta_set_authorized(hapd, sta, 0); ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 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 offset, int width, int cf1, int cf2,
int finished) int finished)
{ {
/* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
#ifdef NEED_AP_MLME #ifdef NEED_AP_MLME
int channel, chwidth, is_dfs; int channel, chwidth, is_dfs;
u8 seg0_idx = 0, seg1_idx = 0; 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) { switch (hapd->iface->current_mode->mode) {
case HOSTAPD_MODE_IEEE80211A: 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; 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; seg1_idx = (cf2 - 5000) / 5;
break; break;
default: 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) { } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs); "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++) for (i = 0; i < hapd->iface->num_bss; i++)
hostapd_neighbor_set_own_report(hapd->iface->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 */ #endif /* NEED_AP_MLME */
} }
@ -1011,6 +1108,8 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
goto out; goto out;
} }
hapd->iconf->edmg_channel = acs_res->edmg_channel;
if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) { if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
/* set defaults for backwards compatibility */ /* set defaults for backwards compatibility */
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0); 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 */ #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( static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq) struct hostapd_iface *iface, unsigned int freq)
{ {
int i; int i;
struct hostapd_channel_data *chan; struct hostapd_channel_data *chan;
for (i = 0; i < iface->current_mode->num_channels; i++) { for (i = 0; i < iface->num_hw_features; i++) {
chan = &iface->current_mode->channels[i]; if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
if ((unsigned int) chan->freq == freq) continue;
chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
if (chan)
return chan; return chan;
} }

View File

@ -1555,11 +1555,14 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
di->prot = prot; di->prot = prot;
di->sd_resp = buf; di->sd_resp = buf;
di->sd_resp_pos = 0; di->sd_resp_pos = 0;
di->dpp = 1;
tx_buf = gas_build_initial_resp( tx_buf = gas_build_initial_resp(
dialog_token, WLAN_STATUS_SUCCESS, dialog_token, WLAN_STATUS_SUCCESS,
comeback_delay, 10); comeback_delay, 10 + 2);
if (tx_buf) if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf); gas_serv_write_dpp_adv_proto(tx_buf);
wpabuf_put_le16(tx_buf, 0);
}
} }
} else { } else {
wpa_printf(MSG_DEBUG, 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, tx_buf = gas_build_comeback_resp(dialog_token,
WLAN_STATUS_SUCCESS, WLAN_STATUS_SUCCESS,
dialog->sd_frag_id, more, 0, dialog->sd_frag_id, more, 0,
10 + frag_len); 10 + 2 + frag_len);
if (tx_buf) { if (tx_buf) {
gas_serv_write_dpp_adv_proto(tx_buf); gas_serv_write_dpp_adv_proto(tx_buf);
wpabuf_put_le16(tx_buf, frag_len);
wpabuf_put_buf(tx_buf, buf); wpabuf_put_buf(tx_buf, buf);
} }
} else } else

View File

@ -58,8 +58,10 @@
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason); 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_setup_encryption(char *iface, struct hostapd_data *hapd);
static int hostapd_broadcast_wep_clear(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 int setup_interface2(struct hostapd_iface *iface);
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
static void hostapd_interface_setup_failure_handler(void *eloop_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; int ret;
for (i = 0; i < interfaces->count; i++) { for (i = 0; i < interfaces->count; i++) {
if (!interfaces->iface[i])
continue;
ret = cb(interfaces->iface[i], ctx); ret = cb(interfaces->iface[i], ctx);
if (ret) if (ret)
return ret; return ret;
@ -89,7 +93,9 @@ void hostapd_reconfig_encryption(struct hostapd_data *hapd)
return; return;
hostapd_set_privacy(hapd, 0); hostapd_set_privacy(hapd, 0);
#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd); 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); wpa_deinit(hapd->wpa_auth);
hapd->wpa_auth = NULL; hapd->wpa_auth = NULL;
hostapd_set_privacy(hapd, 0); hostapd_set_privacy(hapd, 0);
#ifdef CONFIG_WEP
hostapd_setup_encryption(hapd->conf->iface, hapd); hostapd_setup_encryption(hapd->conf->iface, hapd);
#endif /* CONFIG_WEP */
hostapd_set_generic_elem(hapd, (u8 *) "", 0); 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++) { for (j = 0; j < iface->num_bss; j++) {
hostapd_flush_old_stations(iface->bss[j], hostapd_flush_old_stations(iface->bss[j],
WLAN_REASON_PREV_AUTH_NOT_VALID); WLAN_REASON_PREV_AUTH_NOT_VALID);
#ifdef CONFIG_WEP
hostapd_broadcast_wep_clear(iface->bss[j]); hostapd_broadcast_wep_clear(iface->bss[j]);
#endif /* CONFIG_WEP */
#ifndef CONFIG_NO_RADIUS #ifndef CONFIG_NO_RADIUS
/* TODO: update dynamic data based on changed configuration /* 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, static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
const char *ifname) const char *ifname)
{ {
@ -326,7 +338,7 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
struct hostapd_ssid *ssid = &hapd->conf->ssid; struct hostapd_ssid *ssid = &hapd->conf->ssid;
idx = ssid->wep.idx; 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, hostapd_drv_set_key(hapd->conf->iface,
hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0, hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0,
1, NULL, 0, ssid->wep.key[idx], 1, NULL, 0, ssid->wep.key[idx],
@ -339,8 +351,10 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
return errors; 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); os_free(hapd->probereq_cb);
hapd->probereq_cb = NULL; hapd->probereq_cb = NULL;
@ -420,11 +434,17 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_MESH #ifdef CONFIG_MESH
wpabuf_free(hapd->mesh_pending_auth); wpabuf_free(hapd->mesh_pending_auth);
hapd->mesh_pending_auth = NULL; hapd->mesh_pending_auth = NULL;
/* handling setup failure is already done */
hapd->setup_complete_cb = NULL;
#endif /* CONFIG_MESH */ #endif /* CONFIG_MESH */
hostapd_clean_rrm(hapd); hostapd_clean_rrm(hapd);
fils_hlp_deinit(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 #ifdef CONFIG_SAE
{ {
struct hostapd_sae_commit_queue *q; 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); wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME #ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface); hostapd_stop_setup_timers(iface);
#endif /* NEED_AP_MLME */ #endif /* NEED_AP_MLME */
#endif /* CONFIG_IEEE80211N */
if (iface->current_mode) if (iface->current_mode)
acs_cleanup(iface); acs_cleanup(iface);
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); 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) static void hostapd_clear_wep(struct hostapd_data *hapd)
{ {
if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) { 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; return 0;
} }
#endif /* CONFIG_WEP */
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason) 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_free_stas(hapd);
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING); hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
#ifdef CONFIG_WEP
hostapd_clear_wep(hapd); 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 */ #endif /* CONFIG_MESH */
if (flush_old_stations) if (flush_old_stations)
hostapd_flush_old_stations(hapd, hostapd_flush(hapd);
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_set_privacy(hapd, 0); hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd); #ifdef CONFIG_WEP
if (!hostapd_drv_nl80211(hapd))
hostapd_broadcast_wep_clear(hapd);
if (hostapd_setup_encryption(conf->iface, hapd)) if (hostapd_setup_encryption(conf->iface, hapd))
return -1; return -1;
#endif /* CONFIG_WEP */
/* /*
* Fetch the SSID from the system and use it or, * 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) if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
return -1; 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) if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
return -1; 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, 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; 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, static const u8 * fst_hostapd_get_peer_first(void *ctx,
struct fst_get_peer_ctx **get_ctx, struct fst_get_peer_ctx **get_ctx,
Boolean mb_only) bool mb_only)
{ {
struct hostapd_data *hapd = ctx; 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, static const u8 * fst_hostapd_get_peer_next(void *ctx,
struct fst_get_peer_ctx **get_ctx, struct fst_get_peer_ctx **get_ctx,
Boolean mb_only) bool mb_only)
{ {
return fst_hostapd_get_sta(get_ctx, 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]) if (!bss->conf->owe_transition_ifname[0])
continue; 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); res = hostapd_owe_trans_get_info(bss);
if (res == 0) if (res == 0)
continue; continue;
@ -2110,6 +2158,13 @@ dfs_offload:
if (hapd->setup_complete_cb) if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx); 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.", wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
iface->bss[0]->conf->iface); iface->bss[0]->conf->iface);
if (iface->interfaces && iface->interfaces->terminate_on_error > 0) 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); ret = setup_interface(iface);
if (ret) { if (ret) {
wpa_printf(MSG_ERROR, "%s: Unable to setup interface.", 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; return -1;
} }
@ -2349,12 +2404,10 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
hostapd_bss_deinit(iface->bss[j]); hostapd_bss_deinit(iface->bss[j]);
} }
#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME #ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface); hostapd_stop_setup_timers(iface);
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL); eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
#endif /* NEED_AP_MLME */ #endif /* NEED_AP_MLME */
#endif /* CONFIG_IEEE80211N */
} }
@ -2637,6 +2690,12 @@ int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
{ {
size_t j; 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) { if (hapd_iface->bss[0]->drv_priv != NULL) {
wpa_printf(MSG_ERROR, "Interface %s already enabled", wpa_printf(MSG_ERROR, "Interface %s already enabled",
hapd_iface->conf->bss[0]->iface); hapd_iface->conf->bss[0]->iface);
@ -2698,6 +2757,9 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
if (hapd_iface == NULL) if (hapd_iface == NULL)
return -1; return -1;
if (hapd_iface->disable_iface_cb)
return hapd_iface->disable_iface_cb(hapd_iface);
if (hapd_iface->bss[0]->drv_priv == NULL) { if (hapd_iface->bss[0]->drv_priv == NULL) {
wpa_printf(MSG_INFO, "Interface %s already disabled", wpa_printf(MSG_INFO, "Interface %s already disabled",
hapd_iface->conf->bss[0]->iface); 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); hostapd_prune_associations(hapd, sta->addr);
ap_sta_clear_disconnect_timeouts(hapd, sta); ap_sta_clear_disconnect_timeouts(hapd, sta);
sta->post_csa_sa_query = 0;
#ifdef CONFIG_P2P #ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) { 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 */ #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; struct mesh_conf;
#endif /* CONFIG_MESH */ #endif /* CONFIG_MESH */
#ifdef CONFIG_CTRL_IFACE_UDP
#define CTRL_IFACE_COOKIE_LEN 8
#endif /* CONFIG_CTRL_IFACE_UDP */
struct hostapd_iface; struct hostapd_iface;
struct hapd_interfaces { struct hapd_interfaces {
@ -72,6 +76,11 @@ struct hapd_interfaces {
#ifdef CONFIG_DPP #ifdef CONFIG_DPP
struct dpp_global *dpp; struct dpp_global *dpp;
#endif /* CONFIG_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 { enum hostapd_chan_status {
@ -340,6 +349,11 @@ struct hostapd_data {
int last_igtk_key_idx; int last_igtk_key_idx;
u8 last_igtk[WPA_IGTK_MAX_LEN]; u8 last_igtk[WPA_IGTK_MAX_LEN];
size_t last_igtk_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 */ #endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO #ifdef CONFIG_MBO
@ -377,6 +391,16 @@ struct hostapd_data {
unsigned int dpp_resp_wait_time; unsigned int dpp_resp_wait_time;
unsigned int dpp_resp_max_tries; unsigned int dpp_resp_max_tries;
unsigned int dpp_resp_retry_time; 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 #ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override; char *dpp_config_obj_override;
char *dpp_discovery_override; char *dpp_discovery_override;
@ -395,6 +419,10 @@ struct hostapd_data {
#ifdef CONFIG_SQLITE #ifdef CONFIG_SQLITE
sqlite3 *rad_attr_db; sqlite3 *rad_attr_db;
#endif /* CONFIG_SQLITE */ #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]; struct ap_info *ap_hash[STA_HASH_SIZE];
u64 drv_flags; u64 drv_flags;
u64 drv_flags2;
/* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
unsigned int smps_modes;
/* /*
* A bitmap of supported protocols for probe response offload. See * A bitmap of supported protocols for probe response offload. See
@ -563,6 +589,9 @@ struct hostapd_iface {
/* Previous WMM element information */ /* Previous WMM element information */
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM]; 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 */ /* 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_enable_iface(struct hostapd_iface *hapd_iface);
int hostapd_reload_iface(struct hostapd_iface *hapd_iface); int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_disable_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_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_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); 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_cleanup_cs_params(struct hostapd_data *hapd);
void hostapd_periodic_iface(struct hostapd_iface *iface); void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd); 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 */ /* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd, 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) static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{ {
int pri_freq, sec_freq; int pri_freq, sec_freq;
@ -561,26 +560,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0; 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) && if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
!(hw & HT_CAP_INFO_GREEN_FIELD)) { !(hw & HT_CAP_INFO_GREEN_FIELD)) {
wpa_printf(MSG_ERROR, "Driver does not support configured " 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_IEEE80211AX */
#endif /* CONFIG_IEEE80211N */
int hostapd_check_ht_capab(struct hostapd_iface *iface) int hostapd_check_ht_capab(struct hostapd_iface *iface)
{ {
#ifdef CONFIG_IEEE80211N
int ret; int ret;
if (is_6ghz_freq(iface->freq)) if (is_6ghz_freq(iface->freq))
@ -725,7 +701,6 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
return ret; return ret;
if (!ieee80211n_allowed_ht40_channel_pair(iface)) if (!ieee80211n_allowed_ht40_channel_pair(iface))
return -1; return -1;
#endif /* CONFIG_IEEE80211N */
return 0; return 0;
} }
@ -810,7 +785,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
/* 60 GHz channels 1..6 */ /* 60 GHz channels 1..6 */
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
int freq = 56160 + 2160 * i; int freq = 56160 + 2160 * (i + 1);
if (edmg.channels & BIT(i)) { if (edmg.channels & BIT(i)) {
contiguous++; 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 static enum hostapd_chan_status
hostapd_check_chans(struct hostapd_iface *iface) hostapd_check_chans(struct hostapd_iface *iface)
{ {
if (iface->freq) { if (iface->freq) {
hostapd_determine_mode(iface);
if (hostapd_is_usable_chans(iface)) if (hostapd_is_usable_chans(iface))
return HOSTAPD_CHAN_VALID; return HOSTAPD_CHAN_VALID;
else else
@ -1033,9 +1041,15 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
} }
if (iface->current_mode == NULL) { if (iface->current_mode == NULL) {
if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) || if ((iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
!(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) (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, wpa_printf(MSG_ERROR,
"Hardware does not support configured mode"); "Hardware does not support configured mode");
hostapd_logger(iface->bss[0], NULL, hostapd_logger(iface->bss[0], NULL,
@ -1110,3 +1124,20 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
} }
return 0; 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, int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode); struct hostapd_hw_modes *mode);
void hostapd_stop_setup_timers(struct hostapd_iface *iface); 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 */ #else /* NEED_AP_MLME */
static inline void static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, 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 /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */ #endif /* HW_FEATURES_H */

View File

@ -25,6 +25,7 @@
#include "common/dpp.h" #include "common/dpp.h"
#include "common/ocv.h" #include "common/ocv.h"
#include "common/wpa_common.h" #include "common/wpa_common.h"
#include "common/wpa_ctrl.h"
#include "radius/radius.h" #include "radius/radius.h"
#include "radius/radius_client.h" #include "radius/radius_client.h"
#include "p2p/p2p.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) u16 hostapd_own_capab_info(struct hostapd_data *hapd)
{ {
int capab = WLAN_CAPABILITY_ESS; int capab = WLAN_CAPABILITY_ESS;
int privacy; int privacy = 0;
int dfs; int dfs;
int i; int i;
@ -240,12 +241,14 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
hapd->iconf->preamble == SHORT_PREAMBLE) hapd->iconf->preamble == SHORT_PREAMBLE)
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
#ifdef CONFIG_WEP
privacy = hapd->conf->ssid.wep.keys_set; privacy = hapd->conf->ssid.wep.keys_set;
if (hapd->conf->ieee802_1x && if (hapd->conf->ieee802_1x &&
(hapd->conf->default_wep_key_len || (hapd->conf->default_wep_key_len ||
hapd->conf->individual_wep_key_len)) hapd->conf->individual_wep_key_len))
privacy = 1; privacy = 1;
#endif /* CONFIG_WEP */
if (hapd->conf->wpa) if (hapd->conf->wpa)
privacy = 1; privacy = 1;
@ -285,6 +288,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
} }
#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4 #ifndef CONFIG_NO_RC4
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
u16 auth_transaction, const u8 *challenge, 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; return 0;
} }
#endif /* CONFIG_NO_RC4 */ #endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_WEP */
static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta, 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 #ifdef CONFIG_SAE
if (hapd->conf->sae_confirm_immediate == 2 && if (hapd->conf->sae_confirm_immediate == 2 &&
auth_alg == WLAN_AUTH_SAE) { auth_alg == WLAN_AUTH_SAE) {
if (auth_transaction == 1 && if (auth_transaction == 1 && sta &&
(resp == WLAN_STATUS_SUCCESS || (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, wpa_printf(MSG_DEBUG,
"TESTING: Postpone SAE Commit transmission until Confirm is ready"); "TESTING: Postpone SAE Commit transmission until Confirm is ready");
os_free(sta->sae_postponed_commit); 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; const char *rx_id = NULL;
int use_pt = 0; int use_pt = 0;
struct sae_pt *pt = NULL; struct sae_pt *pt = NULL;
const struct sae_pk *pk = NULL;
if (sta->sae->tmp) { if (sta->sae->tmp) {
rx_id = sta->sae->tmp->pw_id; 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) if (rx_id && hapd->conf->sae_pwe != 3)
use_pt = 1; use_pt = 1;
else if (status_code == WLAN_STATUS_SUCCESS) else if (status_code == WLAN_STATUS_SUCCESS)
use_pt = 0; 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; use_pt = 1;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) { 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; continue;
password = pw->password; password = pw->password;
pt = pw->pt; pt = pw->pt;
if (!(hapd->conf->mesh & MESH_ENABLED))
pk = pw->pk;
break; break;
} }
if (!password) { if (!password) {
@ -511,7 +525,7 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
if (update && use_pt && if (update && use_pt &&
sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr, sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
NULL) < 0) NULL, pk) < 0)
return NULL; return NULL;
if (update && !use_pt && 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 + buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
(rx_id ? 3 + os_strlen(rx_id) : 0)); (rx_id ? 3 + os_strlen(rx_id) : 0));
if (buf == NULL) if (buf &&
return NULL; sae_write_commit(sta->sae, buf, sta->sae->tmp ?
sae_write_commit(sta->sae, buf, sta->sae->tmp ? sta->sae->tmp->anti_clogging_token : NULL,
sta->sae->tmp->anti_clogging_token : NULL, rx_id); rx_id) < 0) {
wpabuf_free(buf);
buf = NULL;
}
return buf; return buf;
} }
@ -551,7 +568,17 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
if (buf == NULL) if (buf == NULL)
return 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; return buf;
} }
@ -571,8 +598,21 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
if (data == NULL) if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
status = (sta->sae->tmp && sta->sae->tmp->h2e) ? if (sta->sae->tmp && sta->sae->pk)
WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS; 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, reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
WLAN_AUTH_SAE, 1, WLAN_AUTH_SAE, 1,
status, wpabuf_head(data), 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]; u8 hash[SHA256_MAC_LEN];
hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key), if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
addr, ETH_ALEN, hash); addr, ETH_ALEN, hash) < 0)
return 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; u16 token_idx;
u8 idx; u8 idx;
if (token_len != SHA256_MAC_LEN) if (token_len != SHA256_MAC_LEN || sae_token_hash(hapd, addr, &idx) < 0)
return -1; return -1;
idx = sae_token_hash(hapd, addr);
token_idx = hapd->sae_pending_token_idx[idx]; token_idx = hapd->sae_pending_token_idx[idx];
if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) { if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from " 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); 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]; token_idx = hapd->sae_pending_token_idx[p_idx];
if (!token_idx) { if (!token_idx) {
hapd->sae_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) { switch (sta->sae->state) {
case SAE_NOTHING: case SAE_NOTHING:
if (auth_transaction == 1) { if (auth_transaction == 1) {
if (sta->sae->tmp) if (sta->sae->tmp) {
sta->sae->tmp->h2e = status_code == sta->sae->h2e =
WLAN_STATUS_SAE_HASH_TO_ELEMENT; (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, ret = auth_sae_send_commit(hapd, sta, bssid,
!allow_reuse, status_code); !allow_reuse, status_code);
if (ret) 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 sae_pwe = hapd->conf->sae_pwe;
int id_in_use; int id_in_use;
bool sae_pk = false;
id_in_use = hostapd_sae_pw_id_in_use(hapd->conf); id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
if (id_in_use == 2 && sae_pwe != 3) if (id_in_use == 2 && sae_pwe != 3)
sae_pwe = 1; sae_pwe = 1;
else if (id_in_use == 1 && sae_pwe == 0) else if (id_in_use == 1 && sae_pwe == 0)
sae_pwe = 2; 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) && return ((sae_pwe == 0 || sae_pwe == 3) &&
status_code == WLAN_STATUS_SUCCESS) || status_code == WLAN_STATUS_SUCCESS) ||
(sae_pwe == 1 && (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 && (sae_pwe == 2 &&
(status_code == WLAN_STATUS_SUCCESS || (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, 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; size_t i, count;
const u8 *pos; const u8 *pos;
if (!sae->tmp)
return 0;
groups = sae->tmp->peer_rejected_groups;
if (!groups) if (!groups)
return 0; 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"); wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
pos = mgmt->u.auth.variable; pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len; end = ((const u8 *) mgmt) + len;
resp = status_code;
send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp, pos, end - pos, auth_transaction, resp, pos, end - pos,
"auth-sae-reflection-attack"); "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 - ((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token, mgmt->u.auth.variable, &token,
&token_len, groups, status_code == &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) { if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack", "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) if (resp != WLAN_STATUS_SUCCESS)
goto reply; goto reply;
if (sta->sae->tmp && if (check_sae_rejected_groups(hapd, sta->sae)) {
check_sae_rejected_groups(
hapd, sta->sae->tmp->peer_rejected_groups)) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE; resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto reply; 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 " "SAE: Request anti-clogging token from "
MACSTR, MAC2STR(sta->addr)); MACSTR, MAC2STR(sta->addr));
if (sta->sae->tmp) if (sta->sae->tmp)
h2e = sta->sae->tmp->h2e; h2e = sta->sae->h2e;
if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
status_code == WLAN_STATUS_SAE_PK)
h2e = 1; h2e = 1;
data = auth_build_token_req(hapd, sta->sae->group, data = auth_build_token_req(hapd, sta->sae->group,
sta->addr, h2e); sta->addr, h2e);
@ -1601,27 +1663,37 @@ static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
#endif /* CONFIG_SAE */ #endif /* CONFIG_SAE */
static u16 wpa_res_to_status_code(int res) static u16 wpa_res_to_status_code(enum wpa_validate_result res)
{ {
if (res == WPA_INVALID_GROUP) switch (res) {
return WLAN_STATUS_GROUP_CIPHER_NOT_VALID; case WPA_IE_OK:
if (res == WPA_INVALID_PAIRWISE) return WLAN_STATUS_SUCCESS;
return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; case WPA_INVALID_IE:
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; return WLAN_STATUS_INVALID_IE;
return WLAN_STATUS_SUCCESS; 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; u16 resp = WLAN_STATUS_SUCCESS;
const u8 *end; const u8 *end;
struct ieee802_11_elems elems; struct ieee802_11_elems elems;
int res; enum wpa_validate_result res;
struct wpa_ie_data rsn; struct wpa_ie_data rsn;
struct rsn_pmksa_cache_entry *pmksa = NULL; 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); FILS_SESSION_LEN);
os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN); os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
/* FILS Wrapped Data */ /* Wrapped Data */
if (elems.fils_wrapped_data) { if (elems.wrapped_data) {
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data", wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
elems.fils_wrapped_data, elems.wrapped_data,
elems.fils_wrapped_data_len); elems.wrapped_data_len);
if (!pmksa) { if (!pmksa) {
#ifndef CONFIG_NO_RADIUS #ifndef CONFIG_NO_RADIUS
if (!sta->eapol_sm) { if (!sta->eapol_sm) {
@ -1831,8 +1903,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"FILS: Forward EAP-Initiate/Re-auth to authentication server"); "FILS: Forward EAP-Initiate/Re-auth to authentication server");
ieee802_1x_encapsulate_radius( ieee802_1x_encapsulate_radius(
hapd, sta, elems.fils_wrapped_data, hapd, sta, elems.wrapped_data,
elems.fils_wrapped_data_len); elems.wrapped_data_len);
sta->fils_pending_cb = cb; sta->fils_pending_cb = cb;
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"FILS: Will send Authentication frame once the response from authentication server is available"); "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 * to maintain a copy of the EAP-Initiate/Reauth
* message. */ * message. */
if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm), if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
elems.fils_wrapped_data, elems.wrapped_data,
elems.fils_wrapped_data_len, elems.wrapped_data_len,
sta->fils_erp_pmkid) == 0) sta->fils_erp_pmkid) == 0)
sta->fils_erp_pmkid_set = 1; sta->fils_erp_pmkid_set = 1;
return; return;
@ -1985,12 +2057,12 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION); wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN); wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
/* FILS Wrapped Data */ /* Wrapped Data */
if (!pmksa && erp_resp) { if (!pmksa && erp_resp) {
wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */ wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */ wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
/* Element ID Extension */ /* 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); wpabuf_put_buf(data, erp_resp);
if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm), 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)) && (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
!(hapd->conf->mesh & MESH_ENABLED) && !(hapd->conf->mesh & MESH_ENABLED) &&
!(sta->added_unassoc)) { !(sta->added_unassoc)) {
/* if (ap_sta_re_add(hapd, sta) < 0) {
* 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");
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail; goto fail;
} }
sta->added_unassoc = 1;
} }
switch (auth_alg) { switch (auth_alg) {
@ -2544,6 +2594,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_alg = WLAN_AUTH_OPEN; sta->auth_alg = WLAN_AUTH_OPEN;
mlme_authenticate_indication(hapd, sta); mlme_authenticate_indication(hapd, sta);
break; break;
#ifdef CONFIG_WEP
#ifndef CONFIG_NO_RC4 #ifndef CONFIG_NO_RC4
case WLAN_AUTH_SHARED_KEY: case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge, resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
@ -2562,6 +2613,7 @@ static void handle_auth(struct hostapd_data *hapd,
} }
break; break;
#endif /* CONFIG_NO_RC4 */ #endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_WEP */
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
case WLAN_AUTH_FT: case WLAN_AUTH_FT:
sta->auth_alg = WLAN_AUTH_FT; sta->auth_alg = WLAN_AUTH_FT;
@ -3032,7 +3084,7 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd,
u16 status; u16 status;
u8 *owe_buf, ie[256 * 2]; u8 *owe_buf, ie[256 * 2];
size_t ie_len = 0; size_t ie_len = 0;
int res; enum wpa_validate_result res;
if (!rsn_ie || rsn_ie_len < 2) { if (!rsn_ie || rsn_ie_len < 2) {
wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq"); wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
@ -3104,11 +3156,39 @@ end:
#endif /* CONFIG_OWE */ #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) const u8 *ies, size_t ies_len, int reassoc)
{ {
struct ieee802_11_elems elems; struct ieee802_11_elems elems;
u16 resp; int resp;
const u8 *wpa_ie; const u8 *wpa_ie;
size_t wpa_ie_len; size_t wpa_ie_len;
const u8 *p2p_dev_addr = NULL; 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) if (resp != WLAN_STATUS_SUCCESS)
return resp; return resp;
#ifdef CONFIG_IEEE80211N
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities); resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS) if (resp != WLAN_STATUS_SUCCESS)
return resp; return resp;
@ -3148,7 +3227,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"mandatory HT PHY - reject association"); "mandatory HT PHY - reject association");
return WLAN_STATUS_ASSOC_DENIED_NO_HT; return WLAN_STATUS_ASSOC_DENIED_NO_HT;
} }
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC #ifdef CONFIG_IEEE80211AC
if (hapd->iconf->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 */ #endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX #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, resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
elems.he_capabilities, elems.he_capabilities,
elems.he_capabilities_len); elems.he_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS) if (resp != WLAN_STATUS_SUCCESS)
return resp; 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 */ #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) { if (hapd->conf->wps_state && elems.wps_ie) {
wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association " wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
"Request - assume WPS is used"); "Request - assume WPS is used");
if (check_sa_query(hapd, sta, reassoc))
return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
sta->flags |= WLAN_STA_WPS; sta->flags |= WLAN_STA_WPS;
wpabuf_free(sta->wps_ie); wpabuf_free(sta->wps_ie);
sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, 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) { if (hapd->conf->wpa && wpa_ie) {
int res; enum wpa_validate_result res;
wpa_ie -= 2; wpa_ie -= 2;
wpa_ie_len += 2; wpa_ie_len += 2;
if (sta->wpa_sm == NULL) 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); resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS) if (resp != WLAN_STATUS_SUCCESS)
return resp; 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; return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
}
if (wpa_auth_uses_mfp(sta->wpa_sm)) if (wpa_auth_uses_mfp(sta->wpa_sm))
sta->flags |= WLAN_STA_MFP; 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 && if (hapd->conf->sae_pwe == 2 &&
sta->auth_alg == WLAN_AUTH_SAE && 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 && elems.rsnxe_len >= 1 &&
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) { (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
wpa_printf(MSG_INFO, "SAE: " MACSTR 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); dpp_pfs_free(sta->dpp_pfs);
sta->dpp_pfs = NULL; 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 && hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
elems.owe_dh) { elems.owe_dh) {
@ -3393,7 +3470,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
pfs_fail: pfs_fail:
#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP2 */
#ifdef CONFIG_IEEE80211N
if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) && if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
hostapd_logger(hapd, sta->addr, hostapd_logger(hapd, sta->addr,
@ -3403,7 +3479,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
"association"); "association");
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
} }
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_HS20 #ifdef CONFIG_HS20
} else if (hapd->conf->osen) { } else if (hapd->conf->osen) {
if (elems.osen == NULL) { 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; struct wpa_channel_info ci;
int tx_chanwidth; int tx_chanwidth;
int tx_seg1_idx; int tx_seg1_idx;
enum oci_verify_result res;
if (hostapd_drv_channel_info(hapd, &ci) != 0) { if (hostapd_drv_channel_info(hapd, &ci) != 0) {
wpa_printf(MSG_WARNING, 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) &tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci, res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
tx_chanwidth, tx_seg1_idx) != 0) { tx_chanwidth, tx_seg1_idx);
wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr); 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; return WLAN_STATUS_UNSPECIFIED_FAILURE;
} }
} }
@ -3604,10 +3691,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
sta->ft_over_ds = 0; sta->ft_over_ds = 0;
} }
#ifdef CONFIG_IEEE80211N
if (sta->flags & WLAN_STA_HT) if (sta->flags & WLAN_STA_HT)
hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap); hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC #ifdef CONFIG_IEEE80211AC
if (sta->flags & WLAN_STA_VHT) if (sta->flags & WLAN_STA_VHT)
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap); 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_VHT ? &vht_cap : NULL,
sta->flags & WLAN_STA_HE ? &he_cap : NULL, sta->flags & WLAN_STA_HE ? &he_cap : NULL,
sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0, sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
sta->he_6ghz_capab,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo, sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0, sta->vht_opmode, sta->p2p_ie ? 1 : 0,
set)) { 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, static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 status_code, int reassoc, 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; int send_len;
u8 *buf; u8 *buf;
@ -3725,7 +3812,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
* Transition Information, RSN, [RIC Response] */ * Transition Information, RSN, [RIC Response] */
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p, p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
buf + buflen - p, buf + buflen - p,
sta->auth_alg, ies, ies_len); sta->auth_alg, ies, ies_len,
omit_rsnxe);
if (!p) { if (!p) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"FT: Failed to write AssocResp IEs"); "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) if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
p = hostapd_eid_assoc_comeback_time(hapd, sta, p); p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
#ifdef CONFIG_IEEE80211N
p = hostapd_eid_ht_capabilities(hapd, p); p = hostapd_eid_ht_capabilities(hapd, p);
p = hostapd_eid_ht_operation(hapd, p); p = hostapd_eid_ht_operation(hapd, p);
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC #ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac && 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 */ #endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX #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_capab(hapd, p, IEEE80211_MODE_AP);
p = hostapd_eid_he_operation(hapd, p); p = hostapd_eid_he_operation(hapd, p);
p = hostapd_eid_spatial_reuse(hapd, p); p = hostapd_eid_spatial_reuse(hapd, p);
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p); p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
p = hostapd_eid_he_6ghz_band_cap(hapd, p);
} }
#endif /* CONFIG_IEEE80211AX */ #endif /* CONFIG_IEEE80211AX */
@ -3806,12 +3893,29 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
} }
#endif /* CONFIG_FST */ #endif /* CONFIG_FST */
p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p); #ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->rsnxe_override_ft &&
buf + buflen - p >=
(long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
sta && sta->auth_alg == WLAN_AUTH_FT) {
wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
wpabuf_len(hapd->conf->rsnxe_override_ft));
p += wpabuf_len(hapd->conf->rsnxe_override_ft);
goto rsnxe_done;
}
#endif /* CONFIG_TESTING_OPTIONS */
if (!omit_rsnxe)
p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
#ifdef CONFIG_TESTING_OPTIONS
rsnxe_done:
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_OWE #ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS && 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; struct wpabuf *pub;
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); 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 */ #endif /* CONFIG_OWE */
#ifdef CONFIG_DPP2 #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 && sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) { wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie), 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, reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
sta->fils_pending_assoc_is_reassoc, sta->fils_pending_assoc_is_reassoc,
sta->fils_pending_assoc_req, 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); os_free(sta->fils_pending_assoc_req);
sta->fils_pending_assoc_req = NULL; sta->fils_pending_assoc_req = NULL;
sta->fils_pending_assoc_req_len = 0; sta->fils_pending_assoc_req_len = 0;
@ -4064,7 +4168,8 @@ static void handle_assoc(struct hostapd_data *hapd,
int reassoc, int rssi) int reassoc, int rssi)
{ {
u16 capab_info, listen_interval, seq_ctrl, fc; 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; const u8 *pos;
int left, i; int left, i;
struct sta_info *sta; struct sta_info *sta;
@ -4072,6 +4177,7 @@ static void handle_assoc(struct hostapd_data *hapd,
#ifdef CONFIG_FILS #ifdef CONFIG_FILS
int delay_assoc = 0; int delay_assoc = 0;
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */
int omit_rsnxe = 0;
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_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); resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
if (resp != WLAN_STATUS_SUCCESS) if (resp != WLAN_STATUS_SUCCESS)
goto fail; goto fail;
omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
if (hostapd_get_aid(hapd, sta) < 0) { if (hostapd_get_aid(hapd, sta) < 0) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 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); ieee802_11_set_beacons(hapd->iface);
} }
#ifdef CONFIG_IEEE80211N
update_ht_state(hapd, sta); update_ht_state(hapd, sta);
#endif /* CONFIG_IEEE80211N */
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, HOSTAPD_LEVEL_DEBUG,
@ -4443,12 +4548,13 @@ static void handle_assoc(struct hostapd_data *hapd,
} }
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */
reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos, if (resp >= 0)
left, rssi); reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
pos, left, rssi, omit_rsnxe);
os_free(tmp); 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 * (the STA was added associated to the driver) or if the station was
* previously added unassociated. * previously added unassociated.
*/ */
@ -4485,6 +4591,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
ap_sta_set_authorized(hapd, sta, 0); ap_sta_set_authorized(hapd, sta, 0);
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); 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); wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated"); 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->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_ASSOC_REQ_OK); WLAN_STA_ASSOC_REQ_OK);
hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "deauthenticated"); HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@ -4682,14 +4790,12 @@ static int handle_action(struct hostapd_data *hapd,
#endif /* CONFIG_FST */ #endif /* CONFIG_FST */
case WLAN_ACTION_PUBLIC: case WLAN_ACTION_PUBLIC:
case WLAN_ACTION_PROTECTED_DUAL: case WLAN_ACTION_PROTECTED_DUAL:
#ifdef CONFIG_IEEE80211N
if (len >= IEEE80211_HDRLEN + 2 && if (len >= IEEE80211_HDRLEN + 2 &&
mgmt->u.action.u.public_action.action == mgmt->u.action.u.public_action.action ==
WLAN_PA_20_40_BSS_COEX) { WLAN_PA_20_40_BSS_COEX) {
hostapd_2040_coex_action(hapd, mgmt, len); hostapd_2040_coex_action(hapd, mgmt, len);
return 1; return 1;
} }
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_DPP #ifdef CONFIG_DPP
if (len >= IEEE80211_HDRLEN + 6 && if (len >= IEEE80211_HDRLEN + 6 &&
mgmt->u.action.u.vs_public_action.action == 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; 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) { if (stype == WLAN_FC_STYPE_PROBE_REQ) {
handle_probe_req(hapd, mgmt, len, ssi_signal); 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, struct sta_info *sta,
char *ifname_wds) char *ifname_wds)
{ {
#ifdef CONFIG_WEP
int i; int i;
struct hostapd_ssid *ssid = &hapd->conf->ssid; struct hostapd_ssid *ssid = &hapd->conf->ssid;
@ -4987,6 +5099,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
break; 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 */ #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); size_t len);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid); 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_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_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(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_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_mu_edca_parameter_set(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_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); int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, 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, u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
enum ieee80211_op_mode opmode, const u8 *he_capab, enum ieee80211_op_mode opmode, const u8 *he_capab,
size_t he_capab_len); 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, void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack); const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, 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); 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); 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 get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
int ap_seg1_idx, int *bandwidth, int *seg1_idx); 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 << params |= (hapd->iface->conf->he_op.he_rts_threshold <<
HE_OPERATION_RTS_THRESHOLD_OFFSET); HE_OPERATION_RTS_THRESHOLD_OFFSET);
if (hapd->iface->conf->he_op.he_bss_color) if (hapd->iface->conf->he_op.he_bss_color_disabled)
params |= (hapd->iface->conf->he_op.he_bss_color << params |= HE_OPERATION_BSS_COLOR_DISABLED;
HE_OPERATION_BSS_COLOR_OFFSET); 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 */ /* HE minimum required basic MCS and NSS for STAs */
oper->he_mcs_nss_set = 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, void hostapd_get_he_capab(struct hostapd_data *hapd,
const struct ieee80211_he_capabilities *he_cap, const struct ieee80211_he_capabilities *he_cap,
struct ieee80211_he_capabilities *neg_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) size_t he_capab_len)
{ {
if (!he_capab || !hapd->iconf->ieee80211ax || if (!he_capab || !hapd->iconf->ieee80211ax ||
hapd->conf->disable_11ax ||
!check_valid_he_mcs(hapd, he_capab, opmode) || !check_valid_he_mcs(hapd, he_capab, opmode) ||
ieee80211_invalid_he_cap_size(he_capab, he_capab_len) || ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) { 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; 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 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/40 MHz HT in 20/40 MHz BSS or
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS - 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 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 "utils/common.h"
#include "common/ieee802_11_defs.h" #include "common/ieee802_11_defs.h"
#include "common/ocv.h" #include "common/ocv.h"
#include "common/wpa_ctrl.h"
#include "hostapd.h" #include "hostapd.h"
#include "sta_info.h" #include "sta_info.h"
#include "ap_config.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"); "Failed to get channel info for OCI element in SA Query Request");
return; 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_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_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"); "Failed to get channel info for OCI element in SA Query Response");
return; 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_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len); oci_ie = os_zalloc(oci_ie_len);
@ -254,14 +275,21 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
return; return;
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci, if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
tx_chanwidth, tx_seg1_idx) != 0) { tx_chanwidth, tx_seg1_idx) !=
wpa_printf(MSG_WARNING, "%s", ocv_errorstr); 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; return;
} }
} }
#endif /* CONFIG_OCV */ #endif /* CONFIG_OCV */
if (action_type == WLAN_SA_QUERY_REQUEST) { 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); ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
return; 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)) wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
*pos |= 0x01; *pos |= 0x01;
#endif /* CONFIG_FILS */ #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; break;
case 10: /* Bits 80-87 */ case 10: /* Bits 80-87 */
#ifdef CONFIG_SAE #ifdef CONFIG_SAE
@ -392,6 +425,16 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
* Identifiers Used Exclusively */ * Identifiers Used Exclusively */
} }
#endif /* CONFIG_SAE */ #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; 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) !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
len = 10; len = 10;
#endif /* CONFIG_FILS */ #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 #ifdef CONFIG_SAE
if (len < 11 && hapd->conf->wpa && if (len < 11 && hapd->conf->wpa &&
wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
hostapd_sae_pw_id_in_use(hapd->conf)) hostapd_sae_pw_id_in_use(hapd->conf))
len = 11; len = 11;
#endif /* CONFIG_SAE */ #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) if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len; len = hapd->iface->extended_capa_len;
if (len == 0) 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, void ap_copy_sta_supp_op_classes(struct sta_info *sta,
const u8 *supp_op_classes, const u8 *supp_op_classes,
size_t supp_op_classes_len) 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 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
{ {
u8 *pos = eid; 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) || if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
!wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) || !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
(hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 && (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 || hapd->conf->sae_pwe == 3 ||
len < 3) len < 3)
return pos; return pos;
@ -1024,7 +1114,12 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
*pos++ = 1; *pos++ = 1;
/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
* used for now */ * 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; 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) u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
{ {
struct hostapd_iface *iface = hapd->iface; struct hostapd_iface *iface = hapd->iface;
@ -425,7 +372,9 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
{ {
u8 *pos = 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; return eid;
*pos++ = WLAN_EID_VENDOR_SPECIFIC; *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_FIPS
#ifndef CONFIG_NO_RC4 #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_NO_RC4 */
#endif /* CONFIG_FIPS */ #endif /* CONFIG_FIPS */
#endif /* CONFIG_WEP */
const char *radius_mode_txt(struct hostapd_data *hapd) 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); wpabuf_free(sm->eap_if->eapRespData);
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 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); wpabuf_free(sm->eap_if->eapRespData);
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
sm->eapolEap = TRUE; sm->eapolEap = true;
#endif /* CONFIG_ERP */ #endif /* CONFIG_ERP */
} }
@ -1138,7 +1140,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
} }
#endif /* CONFIG_WPS */ #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 /* 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"); "cached PMKSA available - ignore it since STA sent EAPOL-Start");
wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
} }
sta->eapol_sm->eapolStart = TRUE; sta->eapol_sm->eapolStart = true;
sta->eapol_sm->dot1xAuthEapolStartFramesRx++; sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap); eap_server_clear_identity(sta->eapol_sm->eap);
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 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 = sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
accounting_sta_stop(hapd, sta); accounting_sta_stop(hapd, sta);
sta->eapol_sm->eapolLogoff = TRUE; sta->eapol_sm->eapolLogoff = true;
sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
eap_server_clear_identity(sta->eapol_sm->eap); eap_server_clear_identity(sta->eapol_sm->eap);
break; break;
@ -1295,7 +1297,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
} }
#endif /* CONFIG_WPS */ #endif /* CONFIG_WPS */
sta->eapol_sm->eap_if->portEnabled = TRUE; sta->eapol_sm->eap_if->portEnabled = true;
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) { 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"); "PMK from FT - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state /* Setup EAPOL state machines to already authenticated state
* because of existing FT information from R0KH. */ * because of existing FT information from R0KH. */
sta->eapol_sm->keyRun = TRUE; sta->eapol_sm->keyRun = true;
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
sta->eapol_sm->authSuccess = TRUE; sta->eapol_sm->authSuccess = true;
sta->eapol_sm->authFail = FALSE; sta->eapol_sm->authFail = false;
sta->eapol_sm->portValid = TRUE; sta->eapol_sm->portValid = true;
if (sta->eapol_sm->eap) if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap); eap_sm_notify_cached(sta->eapol_sm->eap);
ap_sta_bind_vlan(hapd, sta); 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"); "PMK from FILS - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state /* Setup EAPOL state machines to already authenticated state
* because of existing FILS information. */ * because of existing FILS information. */
sta->eapol_sm->keyRun = TRUE; sta->eapol_sm->keyRun = true;
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
sta->eapol_sm->authSuccess = TRUE; sta->eapol_sm->authSuccess = true;
sta->eapol_sm->authFail = FALSE; sta->eapol_sm->authFail = false;
sta->eapol_sm->portValid = TRUE; sta->eapol_sm->portValid = true;
if (sta->eapol_sm->eap) if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap); eap_sm_notify_cached(sta->eapol_sm->eap);
wpa_auth_set_ptk_rekey_timer(sta->wpa_sm); 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"); "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
/* Setup EAPOL state machines to already authenticated state /* Setup EAPOL state machines to already authenticated state
* because of existing PMKSA information in the cache. */ * because of existing PMKSA information in the cache. */
sta->eapol_sm->keyRun = TRUE; sta->eapol_sm->keyRun = true;
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; sta->eapol_sm->eap_if->eapKeyAvailable = true;
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
sta->eapol_sm->authSuccess = TRUE; sta->eapol_sm->authSuccess = true;
sta->eapol_sm->authFail = FALSE; sta->eapol_sm->authFail = false;
if (sta->eapol_sm->eap) if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap); eap_sm_notify_cached(sta->eapol_sm->eap);
pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm); 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 * re-authentication without having to wait for the
* Supplicant to send EAPOL-Start. * Supplicant to send EAPOL-Start.
*/ */
sta->eapol_sm->reAuthenticate = TRUE; sta->eapol_sm->reAuthenticate = true;
} }
eapol_auth_step(sta->eapol_sm); 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->last_recv_radius) {
if (sm) if (sm)
sm->eap_if->aaaEapNoReq = TRUE; sm->eap_if->aaaEapNoReq = true;
return; return;
} }
@ -1427,7 +1429,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING, HOSTAPD_LEVEL_WARNING,
"could not extract EAP-Message from RADIUS message"); "could not extract EAP-Message from RADIUS message");
sm->eap_if->aaaEapNoReq = TRUE; sm->eap_if->aaaEapNoReq = true;
return; return;
} }
@ -1436,7 +1438,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
HOSTAPD_LEVEL_WARNING, HOSTAPD_LEVEL_WARNING,
"too short EAP packet received from authentication server"); "too short EAP packet received from authentication server");
wpabuf_free(eap); wpabuf_free(eap);
sm->eap_if->aaaEapNoReq = TRUE; sm->eap_if->aaaEapNoReq = true;
return; 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", "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s",
hdr->code, hdr->identifier, be_to_host16(hdr->length), hdr->code, hdr->identifier, be_to_host16(hdr->length),
buf); buf);
sm->eap_if->aaaEapReq = TRUE; sm->eap_if->aaaEapReq = true;
wpabuf_free(sm->eap_if->aaaEapReqData); wpabuf_free(sm->eap_if->aaaEapReqData);
sm->eap_if->aaaEapReqData = eap; 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, os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
keys->send, keys->send_len); keys->send, keys->send_len);
sm->eap_if->aaaEapKeyDataLen = len; sm->eap_if->aaaEapKeyDataLen = len;
sm->eap_if->aaaEapKeyAvailable = TRUE; sm->eap_if->aaaEapKeyAvailable = true;
} }
} else { } else {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
@ -1878,7 +1880,7 @@ static int ieee802_1x_update_vlan(struct radius_msg *msg,
if (vlan_desc.notempty && if (vlan_desc.notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { !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_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO, HOSTAPD_LEVEL_INFO,
"Invalid VLAN %d%s received from RADIUS server", "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 && if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
!vlan_desc.notempty) { !vlan_desc.notempty) {
sta->eapol_sm->authFail = TRUE; sta->eapol_sm->authFail = true;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO, HOSTAPD_LEVEL_INFO,
"authentication server did not include required VLAN ID in Access-Accept"); "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 else
ap_sta_no_session_timeout(hapd, sta); ap_sta_no_session_timeout(hapd, sta);
sm->eap_if->aaaSuccess = TRUE; sm->eap_if->aaaSuccess = true;
override_eapReq = 1; override_eapReq = 1;
ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
shared_secret_len); shared_secret_len);
@ -2029,7 +2031,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
(int) session_timeout : -1); (int) session_timeout : -1);
break; break;
case RADIUS_CODE_ACCESS_REJECT: case RADIUS_CODE_ACCESS_REJECT:
sm->eap_if->aaaFail = TRUE; sm->eap_if->aaaFail = true;
override_eapReq = 1; override_eapReq = 1;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE, if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
&reason_code) == 0) { &reason_code) == 0) {
@ -2040,7 +2042,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
} }
break; break;
case RADIUS_CODE_ACCESS_CHALLENGE: case RADIUS_CODE_ACCESS_CHALLENGE:
sm->eap_if->aaaEapReq = TRUE; sm->eap_if->aaaEapReq = true;
if (session_timeout_set) { if (session_timeout_set) {
/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
sm->eap_if->aaaMethodTimeout = session_timeout; 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); ieee802_1x_decapsulate_radius(hapd, sta);
if (override_eapReq) if (override_eapReq)
sm->eap_if->aaaEapReq = FALSE; sm->eap_if->aaaEapReq = false;
#ifdef CONFIG_FILS #ifdef CONFIG_FILS
#ifdef NEED_AP_MLME #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, wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
MAC2STR(sta->addr)); MAC2STR(sta->addr));
sm->eap_if->portEnabled = FALSE; sm->eap_if->portEnabled = false;
ap_sta_disconnect(hapd, sta, sta->addr, ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID); WLAN_REASON_PREV_AUTH_NOT_VALID);
} }
} }
#ifdef CONFIG_WEP
static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
{ {
struct eapol_authenticator *eapol = hapd->eapol_auth; 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) struct sta_info *sta, void *ctx)
{ {
if (sta->eapol_sm) { if (sta->eapol_sm) {
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; sta->eapol_sm->eap_if->eapKeyAvailable = true;
eapol_auth_step(sta->eapol_sm); eapol_auth_step(sta->eapol_sm);
} }
return 0; 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, static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
const u8 *data, size_t datalen) 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) static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
{ {
#ifndef CONFIG_FIPS #ifndef CONFIG_FIPS
@ -2372,6 +2379,7 @@ static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
#endif /* CONFIG_NO_RC4 */ #endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */ #endif /* CONFIG_FIPS */
} }
#endif /* CONFIG_WEP */
static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, 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 ieee802_1x_init(struct hostapd_data *hapd)
{ {
int i;
struct eapol_auth_config conf; struct eapol_auth_config conf;
struct eapol_auth_cb cb; struct eapol_auth_cb cb;
@ -2433,7 +2440,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.ctx = hapd; conf.ctx = hapd;
conf.eap_reauth_period = hapd->conf->eap_reauth_period; conf.eap_reauth_period = hapd->conf->eap_reauth_period;
conf.wpa = hapd->conf->wpa; conf.wpa = hapd->conf->wpa;
#ifdef CONFIG_WEP
conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; 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 = hapd->conf->eap_req_id_text;
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start; 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.logger = ieee802_1x_logger;
cb.set_port_authorized = ieee802_1x_set_port_authorized; cb.set_port_authorized = ieee802_1x_set_port_authorized;
cb.abort_auth = _ieee802_1x_abort_auth; cb.abort_auth = _ieee802_1x_abort_auth;
#ifdef CONFIG_WEP
cb.tx_key = _ieee802_1x_tx_key; cb.tx_key = _ieee802_1x_tx_key;
#endif /* CONFIG_WEP */
cb.eapol_event = ieee802_1x_eapol_event; cb.eapol_event = ieee802_1x_eapol_event;
#ifdef CONFIG_ERP #ifdef CONFIG_ERP
cb.erp_get_key = ieee802_1x_erp_get_key; cb.erp_get_key = ieee802_1x_erp_get_key;
@ -2469,17 +2480,21 @@ int ieee802_1x_init(struct hostapd_data *hapd)
return -1; return -1;
#endif /* CONFIG_NO_RADIUS */ #endif /* CONFIG_NO_RADIUS */
#ifdef CONFIG_WEP
if (hapd->conf->default_wep_key_len) { if (hapd->conf->default_wep_key_len) {
int i;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
hostapd_drv_set_key(hapd->conf->iface, hapd, hostapd_drv_set_key(hapd->conf->iface, hapd,
WPA_ALG_NONE, NULL, i, 0, 0, NULL, 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); ieee802_1x_rekey(hapd, NULL);
if (!hapd->eapol_auth->default_wep_key) if (!hapd->eapol_auth->default_wep_key)
return -1; return -1;
} }
#endif /* CONFIG_WEP */
return 0; return 0;
} }
@ -2499,7 +2514,9 @@ void ieee802_1x_erp_flush(struct hostapd_data *hapd)
void ieee802_1x_deinit(struct hostapd_data *hapd) void ieee802_1x_deinit(struct hostapd_data *hapd)
{ {
#ifdef CONFIG_WEP
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
#endif /* CONFIG_WEP */
if (hapd->driver && hapd->drv_priv && if (hapd->driver && hapd->drv_priv &&
(hapd->conf->ieee802_1x || hapd->conf->wpa)) (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, void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled) bool enabled)
{ {
if (!sm) if (!sm)
return; return;
sm->eap_if->portEnabled = enabled ? TRUE : FALSE; sm->eap_if->portEnabled = enabled;
eapol_auth_step(sm); eapol_auth_step(sm);
} }
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid)
int valid)
{ {
if (!sm) if (!sm)
return; return;
sm->portValid = valid ? TRUE : FALSE; sm->portValid = valid;
eapol_auth_step(sm); 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) if (!sm)
return; 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"; 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, const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
size_t *len); size_t *len);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled); bool enabled);
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid);
int valid); void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth);
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen); 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, int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen); 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); u16 capab = hostapd_own_capab_info(hapd);
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n; int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac; 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; struct wpa_ssid_value ssid;
u8 channel, op_class; u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0; 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 */ /* VHT bit added in IEEE P802.11-REVmc/D4.3 */
if (vht) if (vht)
bssid_info |= NEI_REP_BSSID_INFO_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 */ /* 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) { for (entry = pmksa->pmksa; entry; entry = entry->next) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0) if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue; 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, rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
entry->akmp); entry->akmp);
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0) 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; sta = NULL;
} else { } else {
sta->eapol_sm->radius_identifier = -1; sta->eapol_sm->radius_identifier = -1;
sta->eapol_sm->portValid = TRUE; sta->eapol_sm->portValid = true;
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH; 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 */ /* just in case */
ap_sta_set_authorized(hapd, sta, 0); ap_sta_set_authorized(hapd, sta, 0);
hostapd_set_sta_flags(hapd, sta);
if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); 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; sta->assoc_ie_taxonomy = NULL;
#endif /* CONFIG_TAXONOMY */ #endif /* CONFIG_TAXONOMY */
#ifdef CONFIG_IEEE80211N
ht40_intolerant_remove(hapd->iface, sta); ht40_intolerant_remove(hapd->iface, sta);
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_P2P #ifdef CONFIG_P2P
if (sta->no_p2p_set) { if (sta->no_p2p_set) {
@ -247,10 +246,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
} }
#endif /* CONFIG_P2P */ #endif /* CONFIG_P2P */
#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N) #ifdef NEED_AP_MLME
if (hostapd_ht_operation_update(hapd->iface) > 0) if (hostapd_ht_operation_update(hapd->iface) > 0)
set_beacon++; set_beacon++;
#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */ #endif /* NEED_AP_MLME */
#ifdef CONFIG_MESH #ifdef CONFIG_MESH
if (hapd->mesh_sta_free_cb) 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_capabilities);
os_free(sta->vht_operation); os_free(sta->vht_operation);
os_free(sta->he_capab); os_free(sta->he_capab);
os_free(sta->he_6ghz_capab);
hostapd_free_psk_list(sta->psk); hostapd_free_psk_list(sta->psk);
os_free(sta->identity); os_free(sta->identity);
os_free(sta->radius_cui); os_free(sta->radius_cui);
@ -547,6 +547,7 @@ skip_poll:
case STA_DISASSOC_FROM_CLI: case STA_DISASSOC_FROM_CLI:
ap_sta_set_authorized(hapd, sta, 0); ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~WLAN_STA_ASSOC; sta->flags &= ~WLAN_STA_ASSOC;
hostapd_set_sta_flags(hapd, sta);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (!sta->acct_terminate_cause) if (!sta->acct_terminate_cause)
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; sta->timeout_next = STA_DEAUTH;
} }
ap_sta_set_authorized(hapd, sta, 0); ap_sta_set_authorized(hapd, sta, 0);
hostapd_set_sta_flags(hapd, sta);
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - " "for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DISASSOC)", "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->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0); ap_sta_set_authorized(hapd, sta, 0);
hostapd_set_sta_flags(hapd, sta);
sta->timeout_next = STA_REMOVE; sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - " "for " MACSTR " (%d seconds - "
@ -1030,6 +1033,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
int ret; int ret;
int old_vlanid = sta->vlan_id_bound; 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; iface = hapd->conf->iface;
if (hapd->conf->ssid.vlan[0]) if (hapd->conf->ssid.vlan[0])
iface = hapd->conf->ssid.vlan; 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 && if (sta->sa_query_count > 0 &&
ap_check_sa_query_timeout(hapd, sta)) ap_check_sa_query_timeout(hapd, sta))
return; return;
if (sta->sa_query_count >= 1000)
return;
nbuf = os_realloc_array(sta->sa_query_trans_id, nbuf = os_realloc_array(sta->sa_query_trans_id,
sta->sa_query_count + 1, sta->sa_query_count + 1,
@ -1330,9 +1342,10 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
if (sta == NULL) if (sta == NULL)
return; return;
ap_sta_set_authorized(hapd, sta, 0); 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); wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 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 " wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - " "for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DEAUTH)", "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
@ -1420,7 +1433,8 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
int res; int res;
buf[0] = '\0'; 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_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""), (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_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""), (flags & WLAN_STA_VHT ? "[VHT]" : ""),
(flags & WLAN_STA_HE ? "[HE]" : ""), (flags & WLAN_STA_HE ? "[HE]" : ""),
(flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""), (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ? (flags & WLAN_STA_WNM_SLEEP_MODE ?
"[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, return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
hapd, sta); 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_PENDING_FILS_ERP BIT(22)
#define WLAN_STA_MULTI_AP BIT(23) #define WLAN_STA_MULTI_AP BIT(23)
#define WLAN_STA_HE BIT(24) #define WLAN_STA_HE BIT(24)
#define WLAN_STA_6GHZ BIT(25)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29) #define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30) #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31) #define WLAN_STA_NONERP BIT(31)
@ -121,6 +122,7 @@ struct sta_info {
unsigned int hs20_t_c_filtering:1; unsigned int hs20_t_c_filtering:1;
unsigned int ft_over_ds:1; unsigned int ft_over_ds:1;
unsigned int external_dh_updated:1; unsigned int external_dh_updated:1;
unsigned int post_csa_sa_query:1;
u16 auth_alg; u16 auth_alg;
@ -170,6 +172,7 @@ struct sta_info {
u8 vht_opmode; u8 vht_opmode;
struct ieee80211_he_capabilities *he_capab; struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len; size_t he_capab_len;
struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
int sa_query_count; /* number of pending SA Query requests; int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */ * 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); struct sta_info *sta);
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta); struct sta_info *sta);
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* STA_INFO_H */ #endif /* STA_INFO_H */

View File

@ -56,6 +56,10 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
ohapd = iface->bss[j]; ohapd = iface->bss[j];
if (ohapd == data->hapd) if (ohapd == data->hapd)
continue; continue;
#ifdef CONFIG_TESTING_OPTIONS
if (ohapd->conf->skip_prune_assoc)
continue;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FST #ifdef CONFIG_FST
/* Don't prune STAs belong to same FST */ /* Don't prune STAs belong to same FST */
if (ohapd->iface->fst && if (ohapd->iface->fst &&

View File

@ -22,7 +22,9 @@
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan, static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok) int existsok)
{ {
int ret, i; int ret;
#ifdef CONFIG_WEP
int i;
for (i = 0; i < NUM_WEP_KEYS; i++) { for (i = 0; i < NUM_WEP_KEYS; i++) {
if (!hapd->conf->ssid.wep.key[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); vlan->ifname);
return -1; return -1;
} }
#endif /* CONFIG_WEP */
if (!iface_exists(vlan->ifname)) if (!iface_exists(vlan->ifname))
ret = hostapd_vlan_if_add(hapd, 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 len;
size_t gtk_elem_len = 0; size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0; size_t igtk_elem_len = 0;
size_t bigtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie; struct wnm_sleep_element wnmsleep_ie;
u8 *wnmtfs_ie, *oci_ie; u8 *wnmtfs_ie, *oci_ie;
u8 wnmsleep_ie_len, oci_ie_len; 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); os_free(wnmtfs_ie);
return -1; 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_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_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_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26 #define MAX_IGTK_SUBELEM_LEN 26
#define MAX_BIGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN + MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
MAX_BIGTK_SUBELEM_LEN +
oci_ie_len); oci_ie_len);
if (mgmt == NULL) { if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 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; pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d", wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len); (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 *) WPA_PUT_LE16((u8 *)
&mgmt->u.action.u.wnm_sleep_resp.keydata_len, &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); os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */ /* copy TFS IE here */
@ -176,7 +197,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#endif /* CONFIG_OCV */ #endif /* CONFIG_OCV */
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len + 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 /* In driver, response frame should be forced to sent when STA is in
* PS mode */ * PS mode */
@ -189,8 +211,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
/* when entering wnmsleep /* when entering wnmsleep
* 1. pause the node in driver * 1. pause the node in driver
* 2. mark the node so that AP won't update GTK/IGTK during * 2. mark the node so that AP won't update GTK/IGTK/BIGTK
* WNM Sleep * during WNM Sleep
*/ */
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT && if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) { 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 /* when exiting wnmsleep
* 1. unmark the node * 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 * 3. unpause the node in driver
*/ */
if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT || 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_GTK_SUBELEM_LEN
#undef MAX_IGTK_SUBELEM_LEN #undef MAX_IGTK_SUBELEM_LEN
#undef MAX_BIGTK_SUBELEM_LEN
fail: fail:
os_free(wnmtfs_ie); os_free(wnmtfs_ie);
os_free(oci_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, if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
channel_width_to_int(ci.chanwidth), channel_width_to_int(ci.chanwidth),
ci.seg1_idx) != 0) { ci.seg1_idx) != OCI_SUCCESS) {
wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr); wpa_msg(hapd, MSG_WARNING, "WNM: OCV failed: %s",
ocv_errorstr);
return; 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, static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *buf, const u8 *addr, const u8 *buf,
size_t len) size_t len)
@ -526,8 +574,14 @@ static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
MAC2STR(addr), dialog_token, type); MAC2STR(addr), dialog_token, type);
wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements", wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
buf, len); 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); 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 { struct wpa_auth_config {
void *msg_ctx;
int wpa; int wpa;
int extended_key_id;
int wpa_key_mgmt; int wpa_key_mgmt;
int wpa_pairwise; int wpa_pairwise;
int wpa_group; int wpa_group;
@ -177,6 +179,7 @@ struct wpa_auth_config {
int wpa_strict_rekey; int wpa_strict_rekey;
int wpa_gmk_rekey; int wpa_gmk_rekey;
int wpa_ptk_rekey; int wpa_ptk_rekey;
int wpa_deny_ptk0_rekey;
u32 wpa_group_update_count; u32 wpa_group_update_count;
u32 wpa_pairwise_update_count; u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries; int wpa_disable_eapol_key_retries;
@ -189,6 +192,7 @@ struct wpa_auth_config {
int okc; int okc;
int tx_status; int tx_status;
enum mfp_options ieee80211w; enum mfp_options ieee80211w;
int beacon_prot;
int group_mgmt_cipher; int group_mgmt_cipher;
int sae_require_mfp; int sae_require_mfp;
#ifdef CONFIG_OCV #ifdef CONFIG_OCV
@ -220,13 +224,28 @@ struct wpa_auth_config {
double corrupt_gtk_rekey_mic_probability; double corrupt_gtk_rekey_mic_probability;
u8 own_ie_override[MAX_OWN_IE_OVERRIDE]; u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
size_t own_ie_override_len; 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]; u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
size_t rsnxe_override_eapol_len; 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 gtk_rsc_override[WPA_KEY_RSC_LEN];
u8 igtk_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 gtk_rsc_override_set:1;
unsigned int igtk_rsc_override_set:1; unsigned int igtk_rsc_override_set:1;
int ft_rsnxe_used;
#endif /* CONFIG_TESTING_OPTIONS */ #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 #ifdef CONFIG_P2P
u8 ip_addr_go[4]; u8 ip_addr_go[4];
u8 ip_addr_mask[4]; u8 ip_addr_mask[4];
@ -238,7 +257,12 @@ struct wpa_auth_config {
u8 fils_cache_id[FILS_CACHE_ID_LEN]; u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */ #endif /* CONFIG_FILS */
int sae_pwe; int sae_pwe;
bool sae_pk;
int owe_ptk_workaround; int owe_ptk_workaround;
u8 transition_disable;
#ifdef CONFIG_DPP2
int dpp_pfs;
#endif /* CONFIG_DPP2 */
}; };
typedef enum { typedef enum {
@ -285,6 +309,7 @@ struct wpa_auth_callbacks {
int *bandwidth, int *seg1_idx); int *bandwidth, int *seg1_idx);
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); 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, int (*set_vlan)(void *ctx, const u8 *sta_addr,
struct vlan_description *vlan); struct vlan_description *vlan);
int (*get_vlan)(void *ctx, const u8 *sta_addr, int (*get_vlan)(void *ctx, const u8 *sta_addr,
@ -318,19 +343,21 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth, int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf); struct wpa_auth_config *conf);
enum { enum wpa_validate_result {
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE, WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL, WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER, 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
struct wpa_state_machine *sm, int freq, wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_state_machine *sm, int freq,
const u8 *rsnxe, size_t rsnxe_len, const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len, const u8 *rsnxe, size_t rsnxe_len,
const u8 *owe_dh, size_t owe_dh_len); const u8 *mdie, size_t mdie_len,
const u8 *owe_dh, size_t owe_dh_len);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth, int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len); const u8 *osen_ie, size_t osen_ie_len);
@ -414,14 +441,15 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg, 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, void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
u16 auth_transaction, const u8 *ies, size_t ies_len, u16 auth_transaction, const u8 *ies, size_t ies_len,
void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 resp, u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len), const u8 *ies, size_t ies_len),
void *ctx); 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); size_t ies_len);
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t 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, 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); 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_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
int wpa_wnmsleep_igtk_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_sae(struct wpa_state_machine *sm);
int wpa_auth_uses_ft_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); 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_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_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, int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
void (*cb)(void *ctx1, void *ctx2), 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_gtk(struct wpa_authenticator *wpa_auth);
int wpa_auth_rekey_ptk(struct wpa_state_machine *sm, int early_install); 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_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 */ #endif /* WPA_AUTH_H */

View File

@ -14,6 +14,7 @@
#include "common/ieee802_11_defs.h" #include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h" #include "common/ieee802_11_common.h"
#include "common/ocv.h" #include "common/ocv.h"
#include "common/wpa_ctrl.h"
#include "drivers/driver.h" #include "drivers/driver.h"
#include "crypto/aes.h" #include "crypto/aes.h"
#include "crypto/aes_siv.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 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce, const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem, u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len) size_t subelem_len, int rsnxe_used)
{ {
u8 *pos = buf, *ielen; u8 *pos = buf, *ielen;
size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) : 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)); os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr); pos += sizeof(*hdr);
WPA_PUT_LE16(hdr->mic_control, 0); WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce) if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce) if (snonce)
@ -836,7 +837,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
os_memset(hdr, 0, sizeof(*hdr)); os_memset(hdr, 0, sizeof(*hdr));
pos += sizeof(*hdr); pos += sizeof(*hdr);
WPA_PUT_LE16(hdr->mic_control, 0); WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
if (anonce) if (anonce)
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
if (snonce) if (snonce)
@ -1897,7 +1898,7 @@ static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth,
return; 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); f_r0kh_id, f_r0kh_id_len);
if (r0kh) { if (r0kh) {
@ -1985,7 +1986,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
return -1; return -1;
} }
if (is_zero_ether_addr(r0kh->addr)) { 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); sm->r0kh_id, sm->r0kh_id_len);
return -1; 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, pmk_r0, pmk_r0_name,
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0) wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
return -1; 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)) 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, wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
pmk_r0_name, 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, if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
pmk_r1, sm->pmk_r1_name) < 0) pmk_r1, sm->pmk_r1_name) < 0)
return -1; 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)) 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, wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
sm->pmk_r1_name, sm->pairwise, &vlan, 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) static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
{ {
u8 *subelem; u8 *subelem;
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group; struct wpa_group *gsm = sm->group;
size_t subelem_len, pad_len; size_t subelem_len, pad_len;
const u8 *key; const u8 *key;
size_t key_len; size_t key_len;
u8 keybuf[32]; u8 keybuf[WPA_GTK_MAX_LEN];
const u8 *kek; const u8 *kek;
size_t kek_len; 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; pad_len += 8;
if (pad_len && key_len < sizeof(keybuf)) { if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len); 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); os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd; keybuf[key_len] = 0xdd;
key_len += pad_len; key_len += pad_len;
key = keybuf; 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]; key = gsm->GTK[gsm->GN - 1];
}
/* /*
* Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] | * 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) static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
{ {
u8 *subelem, *pos; u8 *subelem, *pos;
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
struct wpa_group *gsm = sm->group; struct wpa_group *gsm = sm->group;
size_t subelem_len; size_t subelem_len;
const u8 *kek; const u8 *kek, *igtk;
size_t kek_len; size_t kek_len;
size_t igtk_len; size_t igtk_len;
u8 dummy_igtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) { if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2; 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); wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6; pos += 6;
*pos++ = igtk_len; *pos++ = igtk_len;
if (aes_wrap(kek, kek_len, igtk_len / 8, igtk = gsm->IGTK[gsm->GN_igtk - 4];
gsm->IGTK[gsm->GN_igtk - 4], pos)) { 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, wpa_printf(MSG_DEBUG,
"FT: IGTK subelem encryption failed: kek_len=%d", "FT: IGTK subelem encryption failed: kek_len=%d",
(int) kek_len); (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, static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
u8 *pos, u8 *end, u8 id, u8 descr_count, u8 *pos, u8 *end, u8 id, u8 descr_count,
const u8 *ies, size_t ies_len) 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, u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg, 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 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
u8 *fte_mic, *elem_count; u8 *fte_mic, *elem_count;
size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0; 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; size_t rsnxe_len;
int rsnxe_used;
int res; int res;
struct wpa_auth_config *conf; struct wpa_auth_config *conf;
struct wpa_ft_ies parse; 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; 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 || if (auth_alg == WLAN_AUTH_FT ||
((auth_alg == WLAN_AUTH_FILS_SK || ((auth_alg == WLAN_AUTH_FILS_SK ||
auth_alg == WLAN_AUTH_FILS_SK_PFS || 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; subelem_len += igtk_len;
os_free(igtk); 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 #ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) { if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci; 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); os_free(subelem);
return NULL; 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; subelem_len += 2 + OCV_OCI_LEN;
nbuf = os_realloc(subelem, subelem_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; anonce = NULL;
snonce = 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, res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
anonce, snonce, pos, end - pos, anonce, snonce, pos, end - pos,
subelem, subelem_len); subelem, subelem_len, rsnxe_used);
os_free(subelem); os_free(subelem);
if (res < 0) if (res < 0)
return NULL; return NULL;
@ -2584,10 +2741,24 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
if (ric_start == pos) if (ric_start == pos)
ric_start = NULL; ric_start = NULL;
res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, sizeof(rsnxe)); if (omit_rsnxe) {
if (res < 0) rsnxe_len = 0;
return NULL; } else {
rsnxe_len = res; 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) if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
*elem_count += 1; *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; enum wpa_alg alg;
int klen; int klen;
@ -2654,19 +2834,22 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
return; 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 /* 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 * most likely without this.. At the moment, STA entry is added only
* after association has been completed. This function will be called * after association has been completed. This function will be called
* again after association to get the PTK configured, but that could be * again after association to get the PTK configured, but that could be
* optimized by adding the STA entry earlier. * 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)) sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
return; return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
sm->pairwise_set = TRUE; sm->pairwise_set = true;
sm->tk_already_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, conf->r1_key_holder,
sm->addr, out_pmk_r1, pmk_r1_name) < 0) sm->addr, out_pmk_r1, pmk_r1_name) < 0)
return -1; 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); os_get_reltime(&now);
if (r0->expiration) 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, sm->wpa_auth->conf.r1_key_holder, sm->addr,
pmk_r1_name, use_sha384) < 0) pmk_r1_name, use_sha384) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE; 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 && if (conf->ft_psk_generate_local &&
wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) { wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
@ -3023,9 +3202,9 @@ pmk_r1_derived:
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
sm->pairwise = pairwise; sm->pairwise = pairwise;
sm->PTK_valid = TRUE; sm->PTK_valid = true;
sm->tk_already_set = FALSE; sm->tk_already_set = false;
wpa_ft_install_ptk(sm); wpa_ft_install_ptk(sm, 0);
if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) { if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN"); wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
@ -3060,7 +3239,8 @@ pmk_r1_derived:
pos += ret; pos += ret;
ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len, 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) if (ret < 0)
goto fail; goto fail;
pos += ret; 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) size_t ies_len)
{ {
struct wpa_ft_ies parse; 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; int use_sha384;
const u8 *anonce, *snonce, *fte_mic; const u8 *anonce, *snonce, *fte_mic;
u8 fte_elem_count; u8 fte_elem_count;
int rsnxe_used;
struct wpa_auth_config *conf;
if (sm == NULL) if (sm == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
conf = &sm->wpa_auth->conf;
use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len); 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; mdie = (struct rsn_mdie *) parse.mdie;
if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
os_memcmp(mdie->mobility_domain, os_memcmp(mdie->mobility_domain, conf->mobility_domain,
sm->wpa_auth->conf.mobility_domain,
MOBILITY_DOMAIN_ID_LEN) != 0) { MOBILITY_DOMAIN_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
return WLAN_STATUS_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; anonce = ftie->anonce;
snonce = ftie->snonce; snonce = ftie->snonce;
rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1]; fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic; fte_mic = ftie->mic;
} else { } else {
@ -3195,6 +3378,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
anonce = ftie->anonce; anonce = ftie->anonce;
snonce = ftie->snonce; snonce = ftie->snonce;
rsnxe_used = ftie->mic_control[0] & 0x01;
fte_elem_count = ftie->mic_control[1]; fte_elem_count = ftie->mic_control[1];
fte_mic = ftie->mic; 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; 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) { FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocReq"); "ReassocReq");
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE", wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
parse.r1kh_id, FT_R1KH_ID_LEN); parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID", 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; 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; 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 #ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) { if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci; struct wpa_channel_info ci;
int tx_chanwidth; int tx_chanwidth;
int tx_seg1_idx; int tx_seg1_idx;
enum oci_verify_result res;
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) { if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
wpa_printf(MSG_WARNING, 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) &tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE; return WLAN_STATUS_UNSPECIFIED_FAILURE;
if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci, res = ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
tx_chanwidth, tx_seg1_idx) != 0) { tx_chanwidth, tx_seg1_idx);
wpa_printf(MSG_WARNING, "%s", ocv_errorstr); if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
return WLAN_STATUS_UNSPECIFIED_FAILURE; /* 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 */ #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 }, { .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, if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_len,
pmk_r0->pmk_r0_name, r1kh_id, pmk_r0->pmk_r0_name, r1kh_id,
s1kh_id, pmk_r1, pmk_r1_name) < 0) s1kh_id, pmk_r1, pmk_r1_name) < 0)
return -1; 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); WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
os_get_reltime(&now); os_get_reltime(&now);
@ -4433,7 +4633,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
return -1; return -1;
} }
status_code = WPA_GET_LE16(pos); status_code = WPA_GET_LE16(pos);
pos += 2;
wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response " wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
"(status_code=%d)", status_code); "(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; return -1;
} }
if (end > pos) {
wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
pos, end - pos);
}
return 0; 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)); os_memset(wconf, 0, sizeof(*wconf));
wconf->wpa = conf->wpa; wconf->wpa = conf->wpa;
wconf->extended_key_id = conf->extended_key_id;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt; wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise; wconf->wpa_pairwise = conf->wpa_pairwise;
wconf->wpa_group = conf->wpa_group; wconf->wpa_group = conf->wpa_group;
@ -67,6 +68,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#endif /* CONFIG_OCV */ #endif /* CONFIG_OCV */
wconf->okc = conf->okc; wconf->okc = conf->okc;
wconf->ieee80211w = conf->ieee80211w; wconf->ieee80211w = conf->ieee80211w;
wconf->beacon_prot = conf->beacon_prot;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher; wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
wconf->sae_require_mfp = conf->sae_require_mfp; wconf->sae_require_mfp = conf->sae_require_mfp;
#ifdef CONFIG_IEEE80211R_AP #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), wpabuf_head(conf->own_ie_override),
wconf->own_ie_override_len); 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 && if (conf->rsnxe_override_eapol &&
wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) { wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
wconf->rsnxe_override_eapol_set = 1;
wconf->rsnxe_override_eapol_len = wconf->rsnxe_override_eapol_len =
wpabuf_len(conf->rsnxe_override_eapol); wpabuf_len(conf->rsnxe_override_eapol);
os_memcpy(wconf->rsnxe_override_eapol, os_memcpy(wconf->rsnxe_override_eapol,
wpabuf_head(conf->rsnxe_override_eapol), wpabuf_head(conf->rsnxe_override_eapol),
wconf->rsnxe_override_eapol_len); 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 && if (conf->gtk_rsc_override &&
wpabuf_len(conf->gtk_rsc_override) > 0 && wpabuf_len(conf->gtk_rsc_override) > 0 &&
wpabuf_len(conf->gtk_rsc_override) <= WPA_KEY_RSC_LEN) { 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)); wpabuf_len(conf->igtk_rsc_override));
wconf->igtk_rsc_override_set = 1; 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 */ #endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P #ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4); 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; wconf->sae_pwe = 1;
else if (sae_pw_id == 1 && wconf->sae_pwe == 0) else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
wconf->sae_pwe = 2; wconf->sae_pwe = 2;
#ifdef CONFIG_SAE_PK
wconf->sae_pk = hostapd_sae_pk_in_use(conf);
#endif /* CONFIG_SAE_PK */
#ifdef CONFIG_OWE #ifdef CONFIG_OWE
wconf->owe_ptk_workaround = conf->owe_ptk_workaround; wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
#endif /* CONFIG_OWE */ #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; break;
case WPA_EAPOL_keyRun: case WPA_EAPOL_keyRun:
if (sta->eapol_sm) if (sta->eapol_sm)
sta->eapol_sm->keyRun = value ? TRUE : FALSE; sta->eapol_sm->keyRun = value;
break; break;
case WPA_EAPOL_keyAvailable: case WPA_EAPOL_keyAvailable:
if (sta->eapol_sm) if (sta->eapol_sm)
sta->eapol_sm->eap_if->eapKeyAvailable = sta->eapol_sm->eap_if->eapKeyAvailable = value;
value ? TRUE : FALSE;
break; break;
case WPA_EAPOL_keyDone: case WPA_EAPOL_keyDone:
if (sta->eapol_sm) if (sta->eapol_sm)
sta->eapol_sm->keyDone = value ? TRUE : FALSE; sta->eapol_sm->keyDone = value;
break; break;
case WPA_EAPOL_inc_EapolFramesTx: case WPA_EAPOL_inc_EapolFramesTx:
if (sta->eapol_sm) 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 #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; struct sta_info *sta;
sta = ap_get_sta(hapd, addr); 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); os_memcpy(sta->last_tk, key, key_len);
sta->last_tk_len = 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_128 ||
alg == WPA_ALG_BIP_GMAC_256 || alg == WPA_ALG_BIP_GMAC_256 ||
alg == WPA_ALG_BIP_CMAC_256) { alg == WPA_ALG_BIP_CMAC_256) {
hapd->last_igtk_alg = alg; if (idx == 4 || idx == 5) {
hapd->last_igtk_key_idx = idx; hapd->last_igtk_alg = alg;
if (key) hapd->last_igtk_key_idx = idx;
os_memcpy(hapd->last_igtk, key, key_len); if (key)
hapd->last_igtk_len = key_len; 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 { } else {
hapd->last_gtk_alg = alg; hapd->last_gtk_alg = alg;
hapd->last_gtk_key_idx = idx; 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, static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
struct vlan_description *vlan) struct vlan_description *vlan)
{ {
@ -1361,6 +1443,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
.send_ft_action = hostapd_wpa_auth_send_ft_action, .send_ft_action = hostapd_wpa_auth_send_ft_action,
.add_sta = hostapd_wpa_auth_add_sta, .add_sta = hostapd_wpa_auth_add_sta,
.add_sta_ft = hostapd_wpa_auth_add_sta_ft,
.add_tspec = hostapd_wpa_auth_add_tspec, .add_tspec = hostapd_wpa_auth_add_tspec,
.set_vlan = hostapd_wpa_auth_set_vlan, .set_vlan = hostapd_wpa_auth_set_vlan,
.get_vlan = hostapd_wpa_auth_get_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; size_t wpa_ie_len;
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf); 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) if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1; _conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME) if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
_conf.ap_mlme = 1; _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); hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) { if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed."); wpa_printf(MSG_ERROR, "WPA initialization failed.");

View File

@ -40,20 +40,20 @@ struct wpa_state_machine {
WPA_PTK_GROUP_KEYERROR WPA_PTK_GROUP_KEYERROR
} wpa_ptk_group_state; } wpa_ptk_group_state;
Boolean Init; bool Init;
Boolean DeauthenticationRequest; bool DeauthenticationRequest;
Boolean AuthenticationRequest; bool AuthenticationRequest;
Boolean ReAuthenticationRequest; bool ReAuthenticationRequest;
Boolean Disconnect; bool Disconnect;
u16 disconnect_reason; /* specific reason code to use with Disconnect */ u16 disconnect_reason; /* specific reason code to use with Disconnect */
u32 TimeoutCtr; u32 TimeoutCtr;
u32 GTimeoutCtr; u32 GTimeoutCtr;
Boolean TimeoutEvt; bool TimeoutEvt;
Boolean EAPOLKeyReceived; bool EAPOLKeyReceived;
Boolean EAPOLKeyPairwise; bool EAPOLKeyPairwise;
Boolean EAPOLKeyRequest; bool EAPOLKeyRequest;
Boolean MICVerified; bool MICVerified;
Boolean GUpdateStationKeys; bool GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN]; u8 ANonce[WPA_NONCE_LEN];
u8 SNonce[WPA_NONCE_LEN]; u8 SNonce[WPA_NONCE_LEN];
u8 alt_SNonce[WPA_NONCE_LEN]; u8 alt_SNonce[WPA_NONCE_LEN];
@ -62,20 +62,22 @@ struct wpa_state_machine {
unsigned int pmk_len; unsigned int pmk_len;
u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */ u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
struct wpa_ptk PTK; struct wpa_ptk PTK;
Boolean PTK_valid; u8 keyidx_active;
Boolean pairwise_set; bool use_ext_key_id;
Boolean tk_already_set; bool PTK_valid;
bool pairwise_set;
bool tk_already_set;
int keycount; int keycount;
Boolean Pair; bool Pair;
struct wpa_key_replay_counter { struct wpa_key_replay_counter {
u8 counter[WPA_REPLAY_COUNTER_LEN]; u8 counter[WPA_REPLAY_COUNTER_LEN];
Boolean valid; bool valid;
} key_replay[RSNA_MAX_EAPOL_RETRIES], } key_replay[RSNA_MAX_EAPOL_RETRIES],
prev_key_replay[RSNA_MAX_EAPOL_RETRIES]; prev_key_replay[RSNA_MAX_EAPOL_RETRIES];
Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */ bool PInitAKeys; /* WPA only, not in IEEE 802.11i */
Boolean PTKRequest; /* not in IEEE 802.11i state machine */ bool PTKRequest; /* not in IEEE 802.11i state machine */
Boolean has_GTK; bool has_GTK;
Boolean PtkGroupInit; /* init request for PTK Group state machine */ bool PtkGroupInit; /* init request for PTK Group state machine */
u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */ u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
size_t last_rx_eapol_key_len; size_t last_rx_eapol_key_len;
@ -94,8 +96,9 @@ struct wpa_state_machine {
#endif /* CONFIG_IEEE80211R_AP */ #endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1; unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1; unsigned int pmkid_set:1;
#ifdef CONFIG_OCV #ifdef CONFIG_OCV
unsigned int ocv_enabled:1; int ocv_enabled;
#endif /* CONFIG_OCV */ #endif /* CONFIG_OCV */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN]; u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
@ -174,12 +177,12 @@ struct wpa_group {
struct wpa_group *next; struct wpa_group *next;
int vlan_id; int vlan_id;
Boolean GInit; bool GInit;
int GKeyDoneStations; int GKeyDoneStations;
Boolean GTKReKey; bool GTKReKey;
int GTK_len; int GTK_len;
int GN, GM; int GN, GM;
Boolean GTKAuthenticator; bool GTKAuthenticator;
u8 Counter[WPA_NONCE_LEN]; u8 Counter[WPA_NONCE_LEN];
enum { enum {
@ -191,11 +194,13 @@ struct wpa_group {
u8 GMK[WPA_GMK_LEN]; u8 GMK[WPA_GMK_LEN];
u8 GTK[2][WPA_GTK_MAX_LEN]; u8 GTK[2][WPA_GTK_MAX_LEN];
u8 GNonce[WPA_NONCE_LEN]; u8 GNonce[WPA_NONCE_LEN];
Boolean changed; bool changed;
Boolean first_sta_seen; bool first_sta_seen;
Boolean reject_4way_hs_for_entropy; bool reject_4way_hs_for_entropy;
u8 IGTK[2][WPA_IGTK_MAX_LEN]; u8 IGTK[2][WPA_IGTK_MAX_LEN];
u8 BIGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk; int GN_igtk, GM_igtk;
int GN_bigtk, GM_bigtk;
/* Number of references except those in struct wpa_group->next */ /* Number of references except those in struct wpa_group->next */
unsigned int references; unsigned int references;
unsigned int num_setup_iface; 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, void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt); logger_level level, const char *txt);
void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, 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, void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int key_info, struct wpa_state_machine *sm, int key_info,
const u8 *key_rsc, const u8 *nonce, 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 *r0kh_id, size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce, const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem, 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); 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); 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_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, int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
const u8 *pmk_r0_name); const u8 *pmk_r0_name);
#endif /* CONFIG_IEEE80211R_AP */ #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) if (rsn_testing)
capab |= BIT(8) | BIT(15); capab |= BIT(8) | BIT(15);
#endif /* CONFIG_RSN_TESTING */ #endif /* CONFIG_RSN_TESTING */
if (conf->extended_key_id)
capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
WPA_PUT_LE16(pos, capab); WPA_PUT_LE16(pos, capab);
pos += 2; pos += 2;
@ -376,7 +378,7 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
{ {
u8 *pos = buf; 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 */ return 0; /* no supported extended RSN capabilities */
if (len < 3) if (len < 3)
@ -386,7 +388,12 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
*pos++ = 1; *pos++ = 1;
/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
* used for now */ * 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; 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
struct wpa_state_machine *sm, int freq, wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_state_machine *sm, int freq,
const u8 *rsnxe, size_t rsnxe_len, const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len, const u8 *rsnxe, size_t rsnxe_len,
const u8 *owe_dh, size_t owe_dh_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; struct wpa_ie_data data;
int ciphers, key_mgmt, res, version; int ciphers, key_mgmt, res, version;
u32 selector; u32 selector;
@ -799,14 +808,26 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_SAE */ #endif /* CONFIG_SAE */
#ifdef CONFIG_OCV #ifdef CONFIG_OCV
if ((data.capabilities & WPA_CAPABILITY_OCVC) && if (wpa_auth->conf.ocv && (data.capabilities & WPA_CAPABILITY_OCVC) &&
!(data.capabilities & WPA_CAPABILITY_MFPC)) { !(data.capabilities & WPA_CAPABILITY_MFPC)) {
wpa_printf(MSG_DEBUG, /* Some legacy MFP incapable STAs wrongly copy OCVC bit from
"Management frame protection required with OCV, but client did not enable it"); * AP RSN capabilities. To improve interoperability with such
return WPA_MGMT_FRAME_PROTECTION_VIOLATION; * legacy STAs allow connection without enabling OCV when the
* workaround mode (ocv=2) is enabled.
*/
if (wpa_auth->conf.ocv == 2) {
wpa_printf(MSG_DEBUG,
"Allow connecting MFP incapable and OCV capable STA without enabling OCV");
wpa_auth_set_ocv(sm, 0);
} else {
wpa_printf(MSG_DEBUG,
"Management frame protection required with OCV, but client did not enable it");
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
} else {
wpa_auth_set_ocv(sm, (data.capabilities & WPA_CAPABILITY_OCVC) ?
wpa_auth->conf.ocv : 0);
} }
wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
(data.capabilities & WPA_CAPABILITY_OCVC));
#endif /* CONFIG_OCV */ #endif /* CONFIG_OCV */
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || 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"); "OWE: No Diffie-Hellman Parameter element");
return WPA_INVALID_AKMP; 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 */ #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); sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
if (sm->pairwise < 0) if (sm->pairwise < 0)
return WPA_INVALID_PAIRWISE; return WPA_INVALID_PAIRWISE;
@ -944,6 +964,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
} }
#endif /* CONFIG_DPP */ #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) { if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
os_free(sm->wpa_ie); os_free(sm->wpa_ie);
sm->wpa_ie = os_malloc(wpa_ie_len); 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; 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; 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; 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; 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); wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE, res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
TRUE); true);
fail: fail:
bin_clear_free(msk, sizeof(*msk)); 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;; ckn->len = hapd->conf->mka_ckn_len;;
os_memcpy(ckn->name, hapd->conf->mka_ckn, 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) if (res)
goto free_cak; 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->addr, mac_addr, ETH_ALEN);
os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN); os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
os_memcpy(p->psk, psk, PMK_LEN); os_memcpy(p->psk, psk, PMK_LEN);
p->wps = 1;
if (hapd->new_psk_cb) { if (hapd->new_psk_cb) {
hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr, 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; 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)) && if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))) (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
bss->wpa = 3; bss->wpa = 3;
@ -372,6 +380,7 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
bss->wpa = 1; bss->wpa = 1;
else else
bss->wpa = 0; bss->wpa = 0;
#endif /* CONFIG_NO_TKIP */
if (bss->wpa) { if (bss->wpa) {
if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_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 else
bss->wpa_pairwise |= WPA_CIPHER_CCMP; bss->wpa_pairwise |= WPA_CIPHER_CCMP;
} }
#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP) if (cred->encr_type & WPS_ENCR_TKIP)
bss->wpa_pairwise |= WPA_CIPHER_TKIP; bss->wpa_pairwise |= WPA_CIPHER_TKIP;
#endif /* CONFIG_NO_TKIP */
bss->rsn_pairwise = bss->wpa_pairwise; bss->rsn_pairwise = bss->wpa_pairwise;
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
bss->wpa_pairwise, bss->wpa_pairwise,
@ -558,6 +569,13 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
fprintf(nconf, "\n"); 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)) && if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))) (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
wpa = 3; wpa = 3;
@ -567,6 +585,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
wpa = 1; wpa = 1;
else else
wpa = 0; wpa = 0;
#endif /* CONFIG_NO_TKIP */
if (wpa) { if (wpa) {
char *prefix; char *prefix;
@ -610,9 +629,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
prefix = " "; prefix = " ";
} }
#ifndef CONFIG_NO_TKIP
if (cred->encr_type & WPS_ENCR_TKIP) { if (cred->encr_type & WPS_ENCR_TKIP) {
fprintf(nconf, "%sTKIP", prefix); fprintf(nconf, "%sTKIP", prefix);
} }
#endif /* CONFIG_NO_TKIP */
fprintf(nconf, "\n"); fprintf(nconf, "\n");
if (cred->key_len >= 8 && cred->key_len < 64) { 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, "ssid=") ||
str_starts(buf, "ssid2=") || str_starts(buf, "ssid2=") ||
str_starts(buf, "auth_algs=") || str_starts(buf, "auth_algs=") ||
#ifdef CONFIG_WEP
str_starts(buf, "wep_default_key=") || str_starts(buf, "wep_default_key=") ||
str_starts(buf, "wep_key") || str_starts(buf, "wep_key") ||
#endif /* CONFIG_WEP */
str_starts(buf, "wps_state=") || str_starts(buf, "wps_state=") ||
(pmf_changed && str_starts(buf, "ieee80211w=")) || (pmf_changed && str_starts(buf, "ieee80211w=")) ||
str_starts(buf, "wpa=") || str_starts(buf, "wpa=") ||
@ -1157,12 +1180,24 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->encr_types_rsn |= WPS_ENCR_AES; wps->encr_types_rsn |= WPS_ENCR_AES;
} }
if (conf->rsn_pairwise & WPA_CIPHER_TKIP) { 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 |= WPS_ENCR_TKIP;
wps->encr_types_rsn |= WPS_ENCR_TKIP; wps->encr_types_rsn |= WPS_ENCR_TKIP;
#endif /* CONFIG_NO_TKIP */
} }
} }
if (conf->wpa & WPA_PROTO_WPA) { 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) if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
wps->auth_types |= WPS_AUTH_WPAPSK; wps->auth_types |= WPS_AUTH_WPAPSK;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) 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 |= WPS_ENCR_TKIP;
wps->encr_types_wpa |= WPS_ENCR_TKIP; wps->encr_types_wpa |= WPS_ENCR_TKIP;
} }
#endif /* CONFIG_NO_TKIP */
} }
if (conf->ssid.security_policy == SECURITY_PLAINTEXT) { 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, wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
conf->ssid.wpa_psk->psk, PMK_LEN); conf->ssid.wpa_psk->psk, PMK_LEN);
wps->network_key_len = 2 * PMK_LEN; wps->network_key_len = 2 * PMK_LEN;
#ifdef CONFIG_WEP
} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) { } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
wps->network_key = os_malloc(conf->ssid.wep.len[0]); wps->network_key = os_malloc(conf->ssid.wep.len[0]);
if (wps->network_key == NULL) 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], os_memcpy(wps->network_key, conf->ssid.wep.key[0],
conf->ssid.wep.len[0]); conf->ssid.wep.len[0]);
wps->network_key_len = conf->ssid.wep.len[0]; wps->network_key_len = conf->ssid.wep.len[0];
#endif /* CONFIG_WEP */
} }
if (conf->ssid.wpa_psk) { if (conf->ssid.wpa_psk) {
@ -1213,10 +1251,17 @@ int hostapd_init_wps(struct hostapd_data *hapd,
wps->ap_encr_type = wps->encr_types; wps->ap_encr_type = wps->encr_types;
if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) { if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
/* Override parameters to enable security by default */ /* 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->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP; wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
wps->encr_types_rsn = 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; wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
#endif /* CONFIG_NO_TKIP */
} }
if ((hapd->conf->multi_ap & FRONTHAUL_BSS) && 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.extra_cred_len = conf->extra_cred_len;
cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) && cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
conf->skip_cred_build; conf->skip_cred_build;
if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
cfg.static_wep_only = 1;
cfg.dualband = interface_count(hapd->iface) > 1; cfg.dualband = interface_count(hapd->iface) > 1;
if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) == if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
(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) if (os_strncmp(auth, "OPEN", 4) == 0)
cred.auth_type = WPS_AUTH_OPEN; cred.auth_type = WPS_AUTH_OPEN;
#ifndef CONFIG_NO_TKIP
else if (os_strncmp(auth, "WPAPSK", 6) == 0) else if (os_strncmp(auth, "WPAPSK", 6) == 0)
cred.auth_type = WPS_AUTH_WPAPSK; cred.auth_type = WPS_AUTH_WPAPSK;
#endif /* CONFIG_NO_TKIP */
else if (os_strncmp(auth, "WPA2PSK", 7) == 0) else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
cred.auth_type = WPS_AUTH_WPA2PSK; cred.auth_type = WPS_AUTH_WPA2PSK;
else else
@ -1808,8 +1853,10 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
if (encr) { if (encr) {
if (os_strncmp(encr, "NONE", 4) == 0) if (os_strncmp(encr, "NONE", 4) == 0)
cred.encr_type = WPS_ENCR_NONE; cred.encr_type = WPS_ENCR_NONE;
#ifndef CONFIG_NO_TKIP
else if (os_strncmp(encr, "TKIP", 4) == 0) else if (os_strncmp(encr, "TKIP", 4) == 0)
cred.encr_type = WPS_ENCR_TKIP; cred.encr_type = WPS_ENCR_TKIP;
#endif /* CONFIG_NO_TKIP */
else if (os_strncmp(encr, "CCMP", 4) == 0) else if (os_strncmp(encr, "CCMP", 4) == 0)
cred.encr_type = WPS_ENCR_AES; cred.encr_type = WPS_ENCR_AES;
else 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_IEEE80211R
CFLAGS += -DCONFIG_HS20 CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_SAE CFLAGS += -DCONFIG_SAE
@ -21,7 +11,4 @@ LIB_OBJS= \
sae.o \ sae.o \
wpa_common.o wpa_common.o
libcommon.a: $(LIB_OBJS) include ../lib.rules
$(AR) crT $@ $?
-include $(OBJS:%.o=%.d)

View File

@ -434,7 +434,8 @@ static int sae_tests(void)
goto fail; goto fail;
/* Check that output matches the test vector */ /* 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); wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
if (wpabuf_len(buf) != sizeof(local_commit) || 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 common_module_tests(void)
{ {
int ret = 0; int ret = 0;
@ -556,6 +646,7 @@ int common_module_tests(void)
if (ieee802_11_parse_tests() < 0 || if (ieee802_11_parse_tests() < 0 ||
gas_tests() < 0 || gas_tests() < 0 ||
sae_tests() < 0 || sae_tests() < 0 ||
sae_pk_tests() < 0 ||
rsn_ie_parse_tests() < 0) rsn_ie_parse_tests() < 0)
ret = -1; ret = -1;

View File

@ -9,15 +9,6 @@
#ifndef DEFS_H #ifndef DEFS_H
#define 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_NONE BIT(0)
#define WPA_CIPHER_WEP40 BIT(1) #define WPA_CIPHER_WEP40 BIT(1)
#define WPA_CIPHER_WEP104 BIT(2) #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)); 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) static inline int wpa_key_mgmt_wpa_psk(int akm)
{ {
return !!(akm & (WPA_KEY_MGMT_PSK | return !!(akm & (WPA_KEY_MGMT_PSK |
@ -192,8 +190,7 @@ enum wpa_alg {
WPA_ALG_WEP, WPA_ALG_WEP,
WPA_ALG_TKIP, WPA_ALG_TKIP,
WPA_ALG_CCMP, WPA_ALG_CCMP,
WPA_ALG_IGTK, WPA_ALG_BIP_CMAC_128,
WPA_ALG_PMK,
WPA_ALG_GCMP, WPA_ALG_GCMP,
WPA_ALG_SMS4, WPA_ALG_SMS4,
WPA_ALG_KRK, WPA_ALG_KRK,
@ -204,6 +201,14 @@ enum wpa_alg {
WPA_ALG_BIP_CMAC_256 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 * enum wpa_states - wpa_supplicant state
* *
@ -383,9 +388,10 @@ enum mesh_plink_state {
}; };
enum set_band { enum set_band {
WPA_SETBAND_AUTO, WPA_SETBAND_AUTO = 0,
WPA_SETBAND_5G, WPA_SETBAND_5G = BIT(0),
WPA_SETBAND_2G WPA_SETBAND_2G = BIT(1),
WPA_SETBAND_6G = BIT(2),
}; };
enum wpa_radio_work_band { 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 = KEY_FLAG_PAIRWISE | KEY_FLAG_RX,
KEY_FLAG_PAIRWISE_RX_TX_MODIFY = KEY_FLAG_PAIRWISE_RX_TX | KEY_FLAG_PAIRWISE_RX_TX_MODIFY = KEY_FLAG_PAIRWISE_RX_TX |
KEY_FLAG_MODIFY, 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 */ #endif /* DEFS_H */

File diff suppressed because it is too large Load Diff

View File

@ -20,9 +20,22 @@
struct crypto_ecdh; struct crypto_ecdh;
struct hostapd_ip_addr; struct hostapd_ip_addr;
struct dpp_global; 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_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 { enum dpp_public_action_frame_type {
DPP_PA_AUTHENTICATION_REQ = 0, DPP_PA_AUTHENTICATION_REQ = 0,
@ -36,6 +49,11 @@ enum dpp_public_action_frame_type {
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10, DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
DPP_PA_CONFIGURATION_RESULT = 11, DPP_PA_CONFIGURATION_RESULT = 11,
DPP_PA_CONNECTION_STATUS_RESULT = 12, 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 { enum dpp_attribute_id {
@ -67,6 +85,12 @@ enum dpp_attribute_id {
DPP_ATTR_ENVELOPED_DATA = 0x101A, DPP_ATTR_ENVELOPED_DATA = 0x101A,
DPP_ATTR_SEND_CONN_STATUS = 0x101B, DPP_ATTR_SEND_CONN_STATUS = 0x101B,
DPP_ATTR_CONN_STATUS = 0x101C, 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 { enum dpp_status_error {
@ -81,6 +105,15 @@ enum dpp_status_error {
DPP_STATUS_NO_MATCH = 8, DPP_STATUS_NO_MATCH = 8,
DPP_STATUS_CONFIG_REJECTED = 9, DPP_STATUS_CONFIG_REJECTED = 9,
DPP_STATUS_NO_AP = 10, 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) #define DPP_CAPAB_ENROLLEE BIT(0)
@ -91,6 +124,7 @@ enum dpp_status_error {
#define DPP_MAX_NONCE_LEN 32 #define DPP_MAX_NONCE_LEN 32
#define DPP_MAX_HASH_LEN 64 #define DPP_MAX_HASH_LEN 64
#define DPP_MAX_SHARED_SECRET_LEN 66 #define DPP_MAX_SHARED_SECRET_LEN 66
#define DPP_CP_LEN 64
struct dpp_curve_params { struct dpp_curve_params {
const char *name; const char *name;
@ -120,12 +154,18 @@ struct dpp_bootstrap_info {
char *pk; char *pk;
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ]; unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
unsigned int num_freq; unsigned int num_freq;
bool channels_listed;
u8 version;
int own; int own;
EVP_PKEY *pubkey; EVP_PKEY *pubkey;
u8 pubkey_hash[SHA256_MAC_LEN]; u8 pubkey_hash[SHA256_MAC_LEN];
u8 pubkey_hash_chirp[SHA256_MAC_LEN];
const struct dpp_curve_params *curve; const struct dpp_curve_params *curve;
unsigned int pkex_t; /* number of failures before dpp_pkex unsigned int pkex_t; /* number of failures before dpp_pkex
* instantiation */ * instantiation */
int nfc_negotiated; /* whether this has been used in NFC negotiated
* connection handover */
char *configurator_params;
}; };
#define PKEX_COUNTER_T_LIMIT 5 #define PKEX_COUNTER_T_LIMIT 5
@ -162,6 +202,7 @@ enum dpp_akm {
DPP_AKM_PSK_SAE, DPP_AKM_PSK_SAE,
DPP_AKM_SAE_DPP, DPP_AKM_SAE_DPP,
DPP_AKM_PSK_SAE_DPP, DPP_AKM_PSK_SAE_DPP,
DPP_AKM_DOT1X,
}; };
enum dpp_netrole { enum dpp_netrole {
@ -187,11 +228,14 @@ struct dpp_configuration {
char *passphrase; char *passphrase;
u8 psk[32]; u8 psk[32];
int psk_set; int psk_set;
char *csrattrs;
}; };
struct dpp_asymmetric_key { struct dpp_asymmetric_key {
struct dpp_asymmetric_key *next; struct dpp_asymmetric_key *next;
EVP_PKEY *csign; EVP_PKEY *csign;
EVP_PKEY *pp_key;
char *config_template; char *config_template;
char *connector_template; char *connector_template;
}; };
@ -199,26 +243,36 @@ struct dpp_asymmetric_key {
#define DPP_MAX_CONF_OBJ 10 #define DPP_MAX_CONF_OBJ 10
struct dpp_authentication { struct dpp_authentication {
struct dpp_global *global;
void *msg_ctx; void *msg_ctx;
u8 peer_version; u8 peer_version;
const struct dpp_curve_params *curve; const struct dpp_curve_params *curve;
struct dpp_bootstrap_info *peer_bi; struct dpp_bootstrap_info *peer_bi;
struct dpp_bootstrap_info *own_bi; struct dpp_bootstrap_info *own_bi;
struct dpp_bootstrap_info *tmp_own_bi; struct dpp_bootstrap_info *tmp_own_bi;
struct dpp_bootstrap_info *tmp_peer_bi;
u8 waiting_pubkey_hash[SHA256_MAC_LEN]; u8 waiting_pubkey_hash[SHA256_MAC_LEN];
int response_pending; int response_pending;
int reconfig;
enum dpp_connector_key reconfig_connector_key;
enum dpp_status_error auth_resp_status; enum dpp_status_error auth_resp_status;
enum dpp_status_error conf_resp_status; enum dpp_status_error conf_resp_status;
enum dpp_status_error force_conf_resp_status;
u8 peer_mac_addr[ETH_ALEN]; u8 peer_mac_addr[ETH_ALEN];
u8 i_nonce[DPP_MAX_NONCE_LEN]; u8 i_nonce[DPP_MAX_NONCE_LEN];
u8 r_nonce[DPP_MAX_NONCE_LEN]; u8 r_nonce[DPP_MAX_NONCE_LEN];
u8 e_nonce[DPP_MAX_NONCE_LEN]; u8 e_nonce[DPP_MAX_NONCE_LEN];
u8 c_nonce[DPP_MAX_NONCE_LEN];
u8 i_capab; u8 i_capab;
u8 r_capab; u8 r_capab;
enum dpp_netrole e_netrole;
EVP_PKEY *own_protocol_key; EVP_PKEY *own_protocol_key;
EVP_PKEY *peer_protocol_key; EVP_PKEY *peer_protocol_key;
EVP_PKEY *reconfig_old_protocol_key;
struct wpabuf *req_msg; struct wpabuf *req_msg;
struct wpabuf *resp_msg; struct wpabuf *resp_msg;
struct wpabuf *reconfig_req_msg;
struct wpabuf *reconfig_resp_msg;
/* Intersection of possible frequencies for initiating DPP /* Intersection of possible frequencies for initiating DPP
* Authentication exchange */ * Authentication exchange */
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ]; unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
@ -236,6 +290,7 @@ struct dpp_authentication {
u8 k1[DPP_MAX_HASH_LEN]; u8 k1[DPP_MAX_HASH_LEN];
u8 k2[DPP_MAX_HASH_LEN]; u8 k2[DPP_MAX_HASH_LEN];
u8 ke[DPP_MAX_HASH_LEN]; u8 ke[DPP_MAX_HASH_LEN];
u8 bk[DPP_MAX_HASH_LEN];
int initiator; int initiator;
int waiting_auth_resp; int waiting_auth_resp;
int waiting_auth_conf; int waiting_auth_conf;
@ -248,8 +303,10 @@ struct dpp_authentication {
int waiting_conf_result; int waiting_conf_result;
int waiting_conn_status_result; int waiting_conn_status_result;
int auth_success; int auth_success;
bool reconfig_success;
struct wpabuf *conf_req; struct wpabuf *conf_req;
const struct wpabuf *conf_resp; /* owned by GAS server */ const struct wpabuf *conf_resp; /* owned by GAS server */
struct wpabuf *conf_resp_tcp;
struct dpp_configuration *conf_ap; struct dpp_configuration *conf_ap;
struct dpp_configuration *conf2_ap; struct dpp_configuration *conf2_ap;
struct dpp_configuration *conf_sta; struct dpp_configuration *conf_sta;
@ -266,6 +323,11 @@ struct dpp_authentication {
int psk_set; int psk_set;
enum dpp_akm akm; enum dpp_akm akm;
struct wpabuf *c_sign_key; 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]; } conf_obj[DPP_MAX_CONF_OBJ];
unsigned int num_conf_obj; unsigned int num_conf_obj;
struct dpp_asymmetric_key *conf_key_pkg; struct dpp_asymmetric_key *conf_key_pkg;
@ -274,6 +336,18 @@ struct dpp_authentication {
int send_conn_status; int send_conn_status;
int conn_status_requested; int conn_status_requested;
int akm_use_selector; 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 #ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override; char *config_obj_override;
char *discovery_override; char *discovery_override;
@ -287,8 +361,12 @@ struct dpp_configurator {
unsigned int id; unsigned int id;
int own; int own;
EVP_PKEY *csign; EVP_PKEY *csign;
u8 kid_hash[SHA256_MAC_LEN];
char *kid; char *kid;
const struct dpp_curve_params *curve; const struct dpp_curve_params *curve;
char *connector; /* own Connector for reconfiguration */
EVP_PKEY *connector_key;
EVP_PKEY *pp_key;
}; };
struct dpp_introduction { struct dpp_introduction {
@ -301,6 +379,7 @@ struct dpp_relay_config {
const struct hostapd_ip_addr *ipaddr; const struct hostapd_ip_addr *ipaddr;
const u8 *pkhash; const u8 *pkhash;
void *msg_ctx;
void *cb_ctx; void *cb_ctx;
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg, void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
size_t len); size_t len);
@ -311,6 +390,12 @@ struct dpp_relay_config {
struct dpp_controller_config { struct dpp_controller_config {
const char *configurator_params; const char *configurator_params;
int tcp_port; 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 #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); void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type); 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, int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
const char *chan_list); const char *chan_list);
int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac); 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_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi, int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
struct dpp_bootstrap_info *peer_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 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 *peer_bi,
struct dpp_bootstrap_info *own_bi, struct dpp_bootstrap_info *own_bi,
u8 dpp_allowed_roles, u8 dpp_allowed_roles,
@ -438,8 +524,8 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx,
struct hostapd_hw_modes *own_modes, struct hostapd_hw_modes *own_modes,
u16 num_modes); u16 num_modes);
struct dpp_authentication * struct dpp_authentication *
dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
struct dpp_bootstrap_info *peer_bi, int qr_mutual, struct dpp_bootstrap_info *peer_bi,
struct dpp_bootstrap_info *own_bi, struct dpp_bootstrap_info *own_bi,
unsigned int freq, const u8 *hdr, const u8 *attr_start, unsigned int freq, const u8 *hdr, const u8 *attr_start,
size_t attr_len); 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_akm_ver2(enum dpp_akm akm);
int dpp_configuration_valid(const struct dpp_configuration *conf); int dpp_configuration_valid(const struct dpp_configuration *conf);
void dpp_configuration_free(struct dpp_configuration *conf); void dpp_configuration_free(struct dpp_configuration *conf);
int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx, int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd);
struct dpp_authentication *auth,
const char *cmd);
void dpp_auth_deinit(struct dpp_authentication *auth); void dpp_auth_deinit(struct dpp_authentication *auth);
struct wpabuf * 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, dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
size_t attr_len); size_t attr_len);
int dpp_conf_resp_rx(struct dpp_authentication *auth, 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, int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
size_t buflen); size_t buflen);
void dpp_configurator_free(struct dpp_configurator *conf); 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, int dpp_configurator_own_config(struct dpp_authentication *auth,
const char *curve, int ap); const char *curve, int ap);
enum dpp_status_error 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); 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); 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, struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
const char *uri); const char *uri);
struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp, 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); const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
int dpp_bootstrap_info(struct dpp_global *dpp, int id, int dpp_bootstrap_info(struct dpp_global *dpp, int id,
char *reply, int reply_size); 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, void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
const u8 *r_bootstrap, const u8 *r_bootstrap,
struct dpp_bootstrap_info **own_bi, struct dpp_bootstrap_info **own_bi,
struct dpp_bootstrap_info **peer_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_add(struct dpp_global *dpp, const char *cmd);
int dpp_configurator_remove(struct dpp_global *dpp, const char *id); int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id, int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
char *buf, size_t buflen); char *buf, size_t buflen);
int dpp_configurator_from_backup(struct dpp_global *dpp, int dpp_configurator_from_backup(struct dpp_global *dpp,
struct dpp_asymmetric_key *key); 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, int dpp_relay_add_controller(struct dpp_global *dpp,
struct dpp_relay_config *config); struct dpp_relay_config *config);
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, 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, int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config); struct dpp_controller_config *config);
void dpp_controller_stop(struct dpp_global *dpp); 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, 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 { struct dpp_global_config {
void *msg_ctx;
void *cb_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); struct dpp_global * dpp_global_init(struct dpp_global_config *config);
void dpp_global_clear(struct dpp_global *dpp); void dpp_global_clear(struct dpp_global *dpp);
void dpp_global_deinit(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 /* CONFIG_DPP */
#endif /* DPP_H */ #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 * Generic advertisement service (GAS) server
* Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2017, Qualcomm Atheros, Inc.
* Copyright (c) 2020, The Linux Foundation
* *
* This software may be distributed under the terms of the BSD license. * This software may be distributed under the terms of the BSD license.
* See README for more details. * See README for more details.
@ -23,8 +24,9 @@ struct gas_server_handler {
struct dl_list list; struct dl_list list;
u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN]; u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
u8 adv_proto_id_len; u8 adv_proto_id_len;
struct wpabuf * (*req_cb)(void *ctx, const u8 *sa, struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
const u8 *query, size_t query_len); const u8 *query, size_t query_len,
u16 *comeback_delay);
void (*status_cb)(void *ctx, struct wpabuf *resp, int ok); void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
void *ctx; void *ctx;
struct gas_server *gas; struct gas_server *gas;
@ -39,6 +41,7 @@ struct gas_server_response {
u8 dst[ETH_ALEN]; u8 dst[ETH_ALEN];
u8 dialog_token; u8 dialog_token;
struct gas_server_handler *handler; struct gas_server_handler *handler;
u16 comeback_delay;
}; };
struct gas_server { 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, MAC2STR(response->dst), response->dialog_token,
response->freq, response->frag_id, response->freq, response->frag_id,
(unsigned long) response->offset, (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->handler->status_cb(response->handler->ctx,
response->resp, 0); response->resp, 0);
response->resp = NULL; response->resp = NULL;
@ -83,30 +87,29 @@ static void gas_server_free_response(struct gas_server_response *response)
static void static void
gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler, 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, 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 max_len = (freq > 56160) ? 928 : 1400;
size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2; size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
size_t resp_frag_len; size_t resp_frag_len;
struct wpabuf *resp; struct wpabuf *resp;
u16 comeback_delay;
struct gas_server_response *response;
if (!query_resp) if (comeback_delay == 0 && !query_resp) {
return; gas_server_free_response(response);
response = os_zalloc(sizeof(*response));
if (!response) {
wpabuf_free(query_resp);
return; return;
} }
wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
response->freq = freq; response->freq = freq;
response->handler = handler; response->handler = handler;
os_memcpy(response->dst, da, ETH_ALEN); os_memcpy(response->dst, da, ETH_ALEN);
response->dialog_token = dialog_token; 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 */ /* Need to use comeback to initiate fragmentation */
comeback_delay = 1; comeback_delay = 1;
resp_frag_len = 0; resp_frag_len = 0;
@ -135,10 +138,12 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
/* Query Response Length */ /* Query Response Length */
wpabuf_put_le16(resp, resp_frag_len); wpabuf_put_le16(resp, resp_frag_len);
if (!comeback_delay) if (!comeback_delay && query_resp)
wpabuf_put_buf(resp, 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, wpa_printf(MSG_DEBUG,
"GAS: Need to fragment query response"); "GAS: Need to fragment query response");
} else { } else {
@ -165,6 +170,7 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
u16 query_req_len; u16 query_req_len;
struct gas_server_handler *handler; struct gas_server_handler *handler;
struct wpabuf *resp; struct wpabuf *resp;
struct gas_server_response *response;
wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame", wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
data, len); data, len);
@ -210,8 +216,15 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
pos, end - pos); 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, dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
list) { list) {
u16 comeback_delay = 0;
if (adv_proto_len < 1 + handler->adv_proto_id_len || if (adv_proto_len < 1 + handler->adv_proto_id_len ||
os_memcmp(adv_proto + 1, handler->adv_proto_id, os_memcmp(adv_proto + 1, handler->adv_proto_id,
handler->adv_proto_id_len) != 0) 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, wpa_printf(MSG_DEBUG,
"GAS: Calling handler for the requested Advertisement Protocol ID"); "GAS: Calling handler for the requested Advertisement Protocol ID");
resp = handler->req_cb(handler->ctx, sa, query_req, resp = handler->req_cb(handler->ctx, response, sa, query_req,
query_req_len); query_req_len, &comeback_delay);
wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler", wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
resp); resp);
gas_server_send_resp(gas, handler, sa, freq, dialog_token, if (comeback_delay)
resp); 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; return 0;
} }
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"GAS: No registered handler for the requested Advertisement Protocol ID"); "GAS: No registered handler for the requested Advertisement Protocol ID");
gas_server_free_response(response);
return -1; 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 hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
size_t remaining, resp_frag_len; size_t remaining, resp_frag_len;
struct wpabuf *resp; 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; remaining = wpabuf_len(response->resp) - response->offset;
if (hdr_len + remaining > max_len) 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; response->offset += resp_frag_len;
gas->tx(gas->ctx, response->freq, response->dst, resp, if (remaining > resp_frag_len)
remaining > resp_frag_len ? 2000 : 0); wait_time = 2000;
send_resp:
gas->tx(gas->ctx, response->freq, response->dst, resp, wait_time);
wpabuf_free(resp); 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, static void gas_server_handle_tx_status(struct gas_server_response *response,
int ack) int ack)
{ {
if (ack && response->offset < wpabuf_len(response->resp)) { if (ack && response->resp &&
response->offset < wpabuf_len(response->resp)) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"GAS: More fragments remaining - keep pending entry"); "GAS: More fragments remaining - keep pending entry");
return; return;
} }
if (ack && !response->resp && response->comeback_delay) {
wpa_printf(MSG_DEBUG,
"GAS: Waiting for response - keep pending entry");
return;
}
if (!ack) if (!ack)
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"GAS: No ACK received - drop pending entry"); "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, struct gas_server * gas_server_init(void *ctx,
void (*tx)(void *ctx, int freq, void (*tx)(void *ctx, int freq,
const u8 *da, const u8 *da,
@ -461,8 +535,9 @@ void gas_server_deinit(struct gas_server *gas)
int gas_server_register(struct gas_server *gas, int gas_server_register(struct gas_server *gas,
const u8 *adv_proto_id, u8 adv_proto_id_len, const u8 *adv_proto_id, u8 adv_proto_id_len,
struct wpabuf * struct wpabuf *
(*req_cb)(void *ctx, const u8 *sa, (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
const u8 *query, size_t query_len), const u8 *query, size_t query_len,
u16 *comeback_delay),
void (*status_cb)(void *ctx, struct wpabuf *resp, void (*status_cb)(void *ctx, struct wpabuf *resp,
int ok), int ok),
void *ctx) void *ctx)

View File

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

View File

@ -415,7 +415,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1; return -1;
} }
if (center_idx_to_bw_6ghz(channel) != 0) { if (center_idx_to_bw_6ghz(channel) < 0) {
wpa_printf(MSG_ERROR, wpa_printf(MSG_ERROR,
"Invalid control channel for 6 GHz band"); "Invalid control channel for 6 GHz band");
return -1; return -1;
@ -475,13 +475,46 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return 0; return 0;
} }
if (data->vht_enabled) switch (oper_chwidth) { if (data->he_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT: case CHANWIDTH_USE_HT:
if (center_segment1 || if (mode == HOSTAPD_MODE_IEEE80211G && sec_channel_offset) {
(center_segment0 != 0 && if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
5000 + center_segment0 * 5 != data->center_freq1 && HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
2407 + center_segment0 * 5 != data->center_freq1)) 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; 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; break;
case CHANWIDTH_80P80MHZ: case CHANWIDTH_80P80MHZ:
if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) { 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!"); "80+80 channel width is not supported!");
return -1; return -1;
} }
if (center_segment1 == center_segment0 + 4 || /* fall through */
center_segment1 == center_segment0 - 4) 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; 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; data->center_freq2 = 5000 + center_segment1 * 5;
/* fall through */ /* fall through */
case CHANWIDTH_80MHZ: case CHANWIDTH_80MHZ:
@ -500,8 +562,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment1) || center_segment1) ||
(oper_chwidth == CHANWIDTH_80P80MHZ && (oper_chwidth == CHANWIDTH_80P80MHZ &&
!center_segment1) || !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; return -1;
}
if (!center_segment0) { if (!center_segment0) {
if (channel <= 48) if (channel <= 48)
center_segment0 = 42; center_segment0 = 42;
@ -527,22 +592,25 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 == channel - 2 || center_segment0 == channel - 2 ||
center_segment0 == channel - 6) center_segment0 == channel - 6)
data->center_freq1 = 5000 + center_segment0 * 5; data->center_freq1 = 5000 + center_segment0 * 5;
else else {
wpa_printf(MSG_ERROR,
"Wrong coupling between HT and VHT/HE channel setting");
return -1; return -1;
}
} }
break; break;
case CHANWIDTH_160MHZ: case CHANWIDTH_160MHZ:
data->bandwidth = 160; data->bandwidth = 160;
if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | if (center_segment1) {
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
wpa_printf(MSG_ERROR, wpa_printf(MSG_ERROR,
"160MHZ channel width is not supported!"); "160 MHz: center segment 1 should not be set");
return -1; return -1;
} }
if (center_segment1) if (!sec_channel_offset) {
return -1; wpa_printf(MSG_ERROR,
if (!sec_channel_offset) "160 MHz: second channel offset not set");
return -1; return -1;
}
/* /*
* Note: HT/VHT config and params are coupled. Check if * Note: HT/VHT config and params are coupled. Check if
* HT40 channel band is in VHT160 channel band configuration. * 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 - 10 ||
center_segment0 == channel - 14) center_segment0 == channel - 14)
data->center_freq1 = 5000 + center_segment0 * 5; 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; return -1;
}
break; 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 = pos;
elems->multi_ap_len = elen; elems->multi_ap_len = elen;
break; 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: default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA " wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored " "information element ignored "
@ -206,6 +216,8 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
ext_id = *pos++; ext_id = *pos++;
elen--; elen--;
elems->frag_ies.last_eid_ext = 0;
switch (ext_id) { switch (ext_id) {
case WLAN_EID_EXT_ASSOC_DELAY_INFO: case WLAN_EID_EXT_ASSOC_DELAY_INFO:
if (elen != 1) 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 = pos;
elems->key_delivery_len = elen; elems->key_delivery_len = elen;
break; break;
case WLAN_EID_EXT_FILS_WRAPPED_DATA: case WLAN_EID_EXT_WRAPPED_DATA:
elems->fils_wrapped_data = pos; elems->wrapped_data = pos;
elems->fils_wrapped_data_len = elen; elems->wrapped_data_len = elen;
break; break;
case WLAN_EID_EXT_FILS_PUBLIC_KEY: case WLAN_EID_EXT_FILS_PUBLIC_KEY:
if (elen < 1) 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 = pos;
elems->short_ssid_list_len = elen; elems->short_ssid_list_len = elen;
break; 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: default:
if (show_errors) { if (show_errors) {
wpa_printf(MSG_MSGDUMP, wpa_printf(MSG_MSGDUMP,
@ -295,10 +312,39 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
return -1; return -1;
} }
if (elen == 254)
elems->frag_ies.last_eid_ext = ext_id;
return 0; 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 * ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs * @start: Pointer to the start of IEs
@ -331,6 +377,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elen); elen);
break; break;
} }
if (elems->ssid) {
wpa_printf(MSG_MSGDUMP,
"Ignored duplicated SSID element");
break;
}
elems->ssid = pos; elems->ssid = pos;
elems->ssid_len = elen; elems->ssid_len = elen;
break; break;
@ -515,8 +566,13 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->dils = pos; elems->dils = pos;
elems->dils_len = elen; elems->dils_len = elen;
break; break;
case WLAN_EID_S1G_CAPABILITIES:
if (elen < 15)
break;
elems->s1g_capab = pos;
break;
case WLAN_EID_FRAGMENT: case WLAN_EID_FRAGMENT:
/* TODO */ ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
break; break;
case WLAN_EID_EXTENSION: case WLAN_EID_EXTENSION:
if (ieee802_11_parse_extension(pos, elen, elems, 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); id, elen);
break; 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)) { 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) enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
{ {
u8 op_class; u8 op_class;
@ -880,16 +1034,35 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A; return HOSTAPD_MODE_IEEE80211A;
} }
if (freq > 5940 && freq <= 7105) { if (freq > 5950 && freq <= 7115) {
int bw; if ((freq - 5950) % 5)
u8 idx = (freq - 5940) / 5;
bw = center_idx_to_bw_6ghz(idx);
if (bw < 0)
return NUM_HOSTAPD_MODES; return NUM_HOSTAPD_MODES;
*channel = idx; switch (chanwidth) {
*op_class = 131 + bw; 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; 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.. */ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
if (chan < 1 || chan > 233) if (chan < 1 || chan > 233)
return -1; 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 */ case 180: /* 60 GHz band, channels 1..8 */
if (chan < 1 || chan > 8) if (chan < 1 || chan > 8)
return -1; return -1;
@ -1613,7 +1790,9 @@ const char * status2str(u16 status)
S2S(FILS_AUTHENTICATION_FAILURE) S2S(FILS_AUTHENTICATION_FAILURE)
S2S(UNKNOWN_AUTHENTICATION_SERVER) S2S(UNKNOWN_AUTHENTICATION_SERVER)
S2S(UNKNOWN_PASSWORD_IDENTIFIER) S2S(UNKNOWN_PASSWORD_IDENTIFIER)
S2S(DENIED_HE_NOT_SUPPORTED)
S2S(SAE_HASH_TO_ELEMENT) S2S(SAE_HASH_TO_ELEMENT)
S2S(SAE_PK)
} }
return "UNKNOWN"; return "UNKNOWN";
#undef S2S #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, 128, 36, 161, 4, BW80, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, 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, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, 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. * 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, 181, 9, 13, 1, BW4320, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, 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 } { -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) { switch (map->bw) {
case BW20: case BW20:
return 20; return 20;
case BW40:
case BW40PLUS: case BW40PLUS:
case BW40MINUS: case BW40MINUS:
return 40; 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) if (freq < 5935 || freq > 7115)
return 0; return false;
if (center_idx_to_bw_6ghz((freq - 5940) / 5) < 0) if (freq == 5935)
return 0; 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; int i;
if (!is_6ghz_freq(freq)) if (!is_6ghz_freq(freq) || freq == 5935)
return 0; return false;
if ((((freq - 5940) / 5) & 0x3) != 0x1) if ((((freq - 5950) / 5) & 0x3) != 0x1)
return 0; return false;
i = (freq - 5940 + 55) % 80; i = (freq - 5950 + 55) % 80;
if (i == 0) if (i == 0)
i = (freq - 5940 + 55) / 80; i = (freq - 5950 + 55) / 80;
if (i >= 1 && i <= 15) 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 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
return 160; return 160;
case 136: /* UHB channels, 20 MHz: 2 */
return 20;
case 180: /* 60 GHz band, channels 1..8 */ case 180: /* 60 GHz band, channels 1..8 */
return 2160; return 2160;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */ 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; return CHANWIDTH_160MHZ;
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
return CHANWIDTH_80P80MHZ; return CHANWIDTH_80P80MHZ;
case 136: /* UHB channels, 20 MHz: 2 */
return CHANWIDTH_USE_HT;
case 180: /* 60 GHz band, channels 1..8 */ case 180: /* 60 GHz band, channels 1..8 */
return CHANWIDTH_2160MHZ; return CHANWIDTH_2160MHZ;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */ 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; 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; struct hostapd_hw_modes;
#define MAX_NOF_MB_IES_SUPPORTED 5 #define MAX_NOF_MB_IES_SUPPORTED 5
#define MAX_NUM_FRAG_IES_SUPPORTED 3
struct mb_ies_info { struct mb_ies_info {
struct { struct {
@ -30,6 +31,21 @@ struct mb_ies_info {
u8 nof_ies; 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 */ /* Parsed Information Elements */
struct ieee802_11_elems { struct ieee802_11_elems {
const u8 *ssid; const u8 *ssid;
@ -85,7 +101,7 @@ struct ieee802_11_elems {
const u8 *fils_hlp; const u8 *fils_hlp;
const u8 *fils_ip_addr_assign; const u8 *fils_ip_addr_assign;
const u8 *key_delivery; const u8 *key_delivery;
const u8 *fils_wrapped_data; const u8 *wrapped_data;
const u8 *fils_pk; const u8 *fils_pk;
const u8 *fils_nonce; const u8 *fils_nonce;
const u8 *owe_dh; const u8 *owe_dh;
@ -97,6 +113,9 @@ struct ieee802_11_elems {
const u8 *he_capabilities; const u8 *he_capabilities;
const u8 *he_operation; const u8 *he_operation;
const u8 *short_ssid_list; const u8 *short_ssid_list;
const u8 *he_6ghz_band_cap;
const u8 *sae_pk;
const u8 *s1g_capab;
u8 ssid_len; u8 ssid_len;
u8 supp_rates_len; u8 supp_rates_len;
@ -138,7 +157,7 @@ struct ieee802_11_elems {
u8 fils_hlp_len; u8 fils_hlp_len;
u8 fils_ip_addr_assign_len; u8 fils_ip_addr_assign_len;
u8 key_delivery_len; u8 key_delivery_len;
u8 fils_wrapped_data_len; u8 wrapped_data_len;
u8 fils_pk_len; u8 fils_pk_len;
u8 owe_dh_len; u8 owe_dh_len;
u8 power_capab_len; u8 power_capab_len;
@ -149,8 +168,10 @@ struct ieee802_11_elems {
u8 he_capabilities_len; u8 he_capabilities_len;
u8 he_operation_len; u8 he_operation_len;
u8 short_ssid_list_len; u8 short_ssid_list_len;
u8 sae_pk_len;
struct mb_ies_info mb_ies; struct mb_ies_info mb_ies;
struct frag_ies_info frag_ies;
}; };
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; 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[], int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val); 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); 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); 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, enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
@ -200,8 +233,8 @@ struct oper_class_map {
u8 min_chan; u8 min_chan;
u8 max_chan; u8 max_chan;
u8 inc; u8 inc;
enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80, BW4320, enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80,
BW6480, BW8640} bw; BW4320, BW6480, BW8640} bw;
enum { P2P_SUPP, NO_P2P_SUPP } p2p; 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); 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 oper_class_bw_to_int(const struct oper_class_map *map);
int center_idx_to_bw_6ghz(u8 idx); int center_idx_to_bw_6ghz(u8 idx);
int is_6ghz_freq(int freq); bool is_6ghz_freq(int freq);
int is_6ghz_op_class(u8 op_class); bool is_6ghz_op_class(u8 op_class);
int is_6ghz_psc_frequency(int freq); bool is_6ghz_psc_frequency(int freq);
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len); 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, int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
struct ieee80211_edmg_config requested); 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 */ #endif /* IEEE802_11_COMMON_H */

View File

@ -204,7 +204,9 @@
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112 #define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113 #define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123 #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_HASH_TO_ELEMENT 126
#define WLAN_STATUS_SAE_PK 127
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */ /* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1 #define WLAN_REASON_UNSPECIFIED 1
@ -441,7 +443,10 @@
#define WLAN_EID_DEVICE_LOCATION 204 #define WLAN_EID_DEVICE_LOCATION 204
#define WLAN_EID_WHITE_SPACE_MAP 205 #define WLAN_EID_WHITE_SPACE_MAP 205
#define WLAN_EID_FTM_PARAMETERS 206 #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_VENDOR_SPECIFIC 221
#define WLAN_EID_S1G_OPERATION 232
#define WLAN_EID_CAG_NUMBER 237 #define WLAN_EID_CAG_NUMBER 237
#define WLAN_EID_AP_CSN 239 #define WLAN_EID_AP_CSN 239
#define WLAN_EID_FILS_INDICATION 240 #define WLAN_EID_FILS_INDICATION 240
@ -458,7 +463,7 @@
#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5 #define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6 #define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
#define WLAN_EID_EXT_KEY_DELIVERY 7 #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_FTM_SYNC_INFO 9
#define WLAN_EID_EXT_EXTENDED_REQUEST 10 #define WLAN_EID_EXT_EXTENDED_REQUEST 10
#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11 #define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
@ -473,8 +478,11 @@
#define WLAN_EID_EXT_SPATIAL_REUSE 39 #define WLAN_EID_EXT_SPATIAL_REUSE 39
#define WLAN_EID_EXT_OCV_OCI 54 #define WLAN_EID_EXT_OCV_OCI 54
#define WLAN_EID_EXT_SHORT_SSID_LIST 58 #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_CAPABILITIES 61
#define WLAN_EID_EXT_EDMG_OPERATION 62 #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_REJECTED_GROUPS 92
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93 #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_COMPLETE_NON_TX_BSSID_PROFILE 80
#define WLAN_EXT_CAPAB_SAE_PW_ID 81 #define WLAN_EXT_CAPAB_SAE_PW_ID 81
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82 #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 */ /* Extended RSN Capabilities */
/* bits 0-3: Field length (n-1) */ /* bits 0-3: Field length (n-1) */
#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4 #define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
#define WLAN_RSNX_CAPAB_SAE_H2E 5 #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) */ /* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0 #define WLAN_ACTION_SPECTRUM_MGMT 0
@ -1315,6 +1327,10 @@ struct ieee80211_ampe_ie {
#define OWE_IE_VENDOR_TYPE 0x506f9a1c #define OWE_IE_VENDOR_TYPE 0x506f9a1c
#define OWE_OUI_TYPE 28 #define OWE_OUI_TYPE 28
#define MULTI_AP_OUI_TYPE 0x1B #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_SUB_ELEM_TYPE 0x06
#define MULTI_AP_TEAR_DOWN BIT(4) #define MULTI_AP_TEAR_DOWN BIT(4)
@ -1874,7 +1890,15 @@ enum wnm_sleep_mode_response_status {
/* WNM-Sleep Mode subelement IDs */ /* WNM-Sleep Mode subelement IDs */
enum wnm_sleep_mode_subelement_id { enum wnm_sleep_mode_subelement_id {
WNM_SLEEP_SUBELEM_GTK = 0, 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) */ /* Channel Switch modes (802.11h) */
@ -2090,7 +2114,7 @@ enum phy_type {
PHY_TYPE_VHT = 9, 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 */ /* BSSID Information Field */
#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0) #define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1) #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_HT BIT(11)
#define NEI_REP_BSSID_INFO_VHT BIT(12) #define NEI_REP_BSSID_INFO_VHT BIT(12)
#define NEI_REP_BSSID_INFO_FTM BIT(13) #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 * 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 le32 he_oper_params; /* HE Operation Parameters[3] and
* BSS Color Information[1] */ * BSS Color Information[1] */
le16 he_mcs_nss_set; le16 he_mcs_nss_set;
u8 vht_op_info_chwidth; /* Followed by conditional VHT Operation Information (3 octets),
u8 vht_op_info_chan_center_freq_seg0_idx; * Max Co-Hosted BSSID Indicator subfield (1 octet), and/or 6 GHz
u8 vht_op_info_chan_center_freq_seg1_idx; * Operation Information subfield (5 octets). */
/* Followed by conditional MaxBSSID Indicator subfield (u8) */
} STRUCT_PACKED; } 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 * 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 */ /* 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_SET_IDX 0
#define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \ #define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \
BIT(3) | BIT(4))) BIT(3) | BIT(4)))
@ -2198,7 +2266,7 @@ struct ieee80211_spatial_reuse {
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \ #define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
BIT(26) | BIT(27) | \ BIT(26) | BIT(27) | \
BIT(28) | BIT(29))) 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_DISABLED ((u32) BIT(31))
#define HE_OPERATION_BSS_COLOR_OFFSET 24 #define HE_OPERATION_BSS_COLOR_OFFSET 24
@ -2278,4 +2346,25 @@ enum edmg_bw_config {
/* DPP Public Action frame identifiers - OUI_WFA */ /* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A #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 */ #endif /* IEEE802_11_DEFS_H */

View File

@ -45,6 +45,8 @@ int ocv_derive_all_parameters(struct oci_info *oci)
oci->sec_channel = 1; oci->sec_channel = 1;
else if (op_class_map->bw == BW40MINUS) else if (op_class_map->bw == BW40MINUS)
oci->sec_channel = -1; oci->sec_channel = -1;
else if (op_class_map->bw == BW40)
oci->sec_channel = (((oci->channel - 1) / 4) % 2) ? -1 : 1;
return 0; return 0;
} }
@ -95,23 +97,24 @@ 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
struct wpa_channel_info *ci, int tx_chanwidth, ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
int tx_seg1_idx) struct wpa_channel_info *ci, int tx_chanwidth,
int tx_seg1_idx)
{ {
struct oci_info oci; struct oci_info oci;
if (!oci_ie) { if (!oci_ie) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr), os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"OCV failed: did not receive mandatory OCI"); "did not receive mandatory OCI");
return -1; return OCI_NOT_FOUND;
} }
if (oci_ie_len != 3) { if (oci_ie_len != 3) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr), 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); (int) oci_ie_len);
return -1; return OCI_INVALID_LENGTH;
} }
os_memset(&oci, 0, sizeof(oci)); 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]; oci.seg1_idx = oci_ie[2];
if (ocv_derive_all_parameters(&oci) != 0) { if (ocv_derive_all_parameters(&oci) != 0) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr), os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"OCV failed: unable to interpret received OCI"); "unable to interpret received OCI");
return -1; return OCI_PARSE_ERROR;
} }
/* Primary frequency used to send frames to STA must match the STA's */ /* Primary frequency used to send frames to STA must match the STA's */
if ((int) ci->frequency != oci.freq) { if ((int) ci->frequency != oci.freq) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr), 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); ci->frequency, oci.freq);
return -1; return OCI_PRIMARY_FREQ_MISMATCH;
} }
/* We shouldn't transmit with a higher bandwidth than the STA supports /* We shouldn't transmit with a higher bandwidth than the STA supports
*/ */
if (tx_chanwidth > oci.chanwidth) { if (tx_chanwidth > oci.chanwidth) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr), 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); 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 && if (tx_chanwidth == 40 && ci->frequency < 2500 &&
ci->sec_channel != oci.sec_channel) { ci->sec_channel != oci.sec_channel) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr), 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); 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) && ci->chanwidth == CHAN_WIDTH_80P80) &&
tx_seg1_idx != oci.seg1_idx) { tx_seg1_idx != oci.seg1_idx) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr), 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); tx_seg1_idx, oci.seg1_idx);
return -1; return OCI_SEG_1_INDEX_MISMATCH;
} }
return 0; return OCI_SUCCESS;
} }

View File

@ -27,14 +27,21 @@ struct oci_info {
#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN) #define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + 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]; extern char ocv_errorstr[256];
int ocv_derive_all_parameters(struct oci_info *oci); int ocv_derive_all_parameters(struct oci_info *oci);
int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos); 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_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos); 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
struct wpa_channel_info *ci, int tx_chanwidth, ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
int tx_seg1_idx); struct wpa_channel_info *ci, int tx_chanwidth,
int tx_seg1_idx);
#endif /* OCV_H */ #endif /* OCV_H */

View File

@ -82,6 +82,7 @@ struct privsep_cmd_set_key {
size_t seq_len; size_t seq_len;
u8 key[32]; u8 key[32];
size_t key_len; size_t key_len;
enum key_flag key_flag;
}; };
enum privsep_event { 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. */ * being smaller than prime. */
in_range = const_time_fill_msb((unsigned int) cmp_prime); in_range = const_time_fill_msb((unsigned int) cmp_prime);
/* The algorithm description would skip the next steps if /* 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. */ * minimize externally observable differences in behavior. */
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len); 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; goto fail;
const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin); const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
x1 = crypto_bignum_init_set(bin, prime_len); x1 = crypto_bignum_init_set(bin, prime_len);
if (!x1)
goto fail;
debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len); debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
/* gx1 = x1^3 + a * x1 + b */ /* gx1 = x1^3 + a * x1 + b */
@ -753,6 +755,8 @@ static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
goto fail; goto fail;
const_time_select_bin(is_qr, bin1, bin2, prime_len, bin); const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
v = crypto_bignum_init_set(bin, prime_len); v = crypto_bignum_init_set(bin, prime_len);
if (!v)
goto fail;
debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len); debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
/* x = CSEL(l, x1, x2) */ /* 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); wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
if (ssid_len > 32)
return NULL;
pt = os_zalloc(sizeof(*pt)); pt = os_zalloc(sizeof(*pt));
if (!pt) if (!pt)
return NULL; 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->group = group;
pt->ec = crypto_ec_init(group); pt->ec = crypto_ec_init(group);
if (pt->ec) { if (pt->ec) {
@ -1354,14 +1365,15 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
identifier) < 0)) identifier) < 0))
return -1; return -1;
sae->tmp->h2e = 0; sae->h2e = 0;
sae->pk = 0;
return sae_derive_commit(sae); return sae_derive_commit(sae);
} }
int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt, int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
const u8 *addr1, const u8 *addr2, const u8 *addr1, const u8 *addr2,
int *rejected_groups) int *rejected_groups, const struct sae_pk *pk)
{ {
if (!sae->tmp) if (!sae->tmp)
return -1; return -1;
@ -1377,6 +1389,11 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
return -1; 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; sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
wpabuf_free(sae->tmp->own_rejected_groups); wpabuf_free(sae->tmp->own_rejected_groups);
sae->tmp->own_rejected_groups = NULL; 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; return -1;
} }
sae->tmp->h2e = 1; sae->h2e = 1;
return sae_derive_commit(sae); return sae_derive_commit(sae);
} }
@ -1515,7 +1532,7 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
const u8 *salt; const u8 *salt;
struct wpabuf *rejected_groups = NULL; struct wpabuf *rejected_groups = NULL;
u8 keyseed[SAE_MAX_HASH_LEN]; 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; struct crypto_bignum *tmp;
int ret = -1; int ret = -1;
size_t hash_len, salt_len, prime_len = sae->tmp->prime_len; size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
@ -1530,15 +1547,18 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK", * KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
* (commit-scalar + peer-commit-scalar) modulo r) * (commit-scalar + peer-commit-scalar) modulo r)
* PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128) * 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; hash_len = SHA256_MAC_LEN;
else if (sae->tmp->dh) else if (sae->tmp->dh)
hash_len = sae_ffc_prime_len_2_hash_len(prime_len); hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
else else
hash_len = sae_ecc_prime_len_2_hash_len(prime_len); 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)) { sae->tmp->peer_rejected_groups)) {
struct wpabuf *own, *peer; struct wpabuf *own, *peer;
own = sae->tmp->own_rejected_groups; own = sae->tmp->own_rejected_groups;
@ -1589,15 +1609,40 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* octets). */ * octets). */
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len); crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_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", if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
val, sae->tmp->order_len, val, sae->tmp->order_len,
keys, hash_len + SAE_PMK_LEN) < 0) keys, hash_len + SAE_PMK_LEN) < 0)
goto fail; goto fail;
#endif /* !CONFIG_SAE_PK */
forced_memzero(keyseed, sizeof(keyseed)); forced_memzero(keyseed, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, hash_len); os_memcpy(sae->tmp->kck, keys, hash_len);
sae->tmp->kck_len = hash_len; sae->tmp->kck_len = hash_len;
os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN); os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
os_memcpy(sae->pmkid, val, SAE_PMKID_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)); forced_memzero(keys, sizeof(keys));
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
sae->tmp->kck, sae->tmp->kck_len); 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) const struct wpabuf *token, const char *identifier)
{ {
u8 *pos; u8 *pos;
if (sae->tmp == NULL) if (sae->tmp == NULL)
return; return -1;
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */ wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
if (!sae->tmp->h2e && token) { if (!sae->h2e && token) {
wpabuf_put_buf(buf, token); wpabuf_put_buf(buf, token);
wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token", wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
wpabuf_head(token), wpabuf_len(token)); wpabuf_head(token), wpabuf_len(token));
} }
pos = wpabuf_put(buf, sae->tmp->prime_len); pos = wpabuf_put(buf, sae->tmp->prime_len);
crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
sae->tmp->prime_len, sae->tmp->prime_len); sae->tmp->prime_len, sae->tmp->prime_len) < 0)
return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar", wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
pos, sae->tmp->prime_len); pos, sae->tmp->prime_len);
if (sae->tmp->ec) { if (sae->tmp->ec) {
pos = wpabuf_put(buf, 2 * sae->tmp->prime_len); 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, 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)", wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
pos, sae->tmp->prime_len); pos, sae->tmp->prime_len);
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)", wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
pos + sae->tmp->prime_len, sae->tmp->prime_len); pos + sae->tmp->prime_len, sae->tmp->prime_len);
} else { } else {
pos = wpabuf_put(buf, sae->tmp->prime_len); pos = wpabuf_put(buf, sae->tmp->prime_len);
crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
sae->tmp->prime_len, sae->tmp->prime_len); sae->tmp->prime_len,
sae->tmp->prime_len) < 0)
return -1;
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element", wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
pos, sae->tmp->prime_len); pos, sae->tmp->prime_len);
} }
@ -1669,7 +1718,7 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
identifier); 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", wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
sae->tmp->own_rejected_groups); sae->tmp->own_rejected_groups);
wpabuf_put_u8(buf, WLAN_EID_EXTENSION); 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); 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, WLAN_EID_EXTENSION);
wpabuf_put_u8(buf, 1 + wpabuf_len(token)); wpabuf_put_u8(buf, 1 + wpabuf_len(token));
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_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)", "SAE: Anti-clogging token (in container)",
token); 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; const u8 *sc;
size_t hash_len; size_t hash_len;
int res;
if (sae->tmp == NULL) if (sae->tmp == NULL)
return; return -1;
hash_len = sae->tmp->kck_len; hash_len = sae->tmp->kck_len;
@ -2200,17 +2252,26 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
sae->send_confirm++; sae->send_confirm++;
if (sae->tmp->ec) 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->tmp->own_commit_element_ecc,
sae->peer_commit_scalar, sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ecc, sae->tmp->peer_commit_element_ecc,
wpabuf_put(buf, hash_len)); wpabuf_put(buf, hash_len));
else 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->tmp->own_commit_element_ffc,
sae->peer_commit_scalar, sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ffc, sae->tmp->peer_commit_element_ffc,
wpabuf_put(buf, hash_len)); 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; 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; return 0;
} }

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