mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-25 00:38:24 -05:00
pull in new hostap code
This commit is contained in:
commit
f988e85c95
31
.gitignore
vendored
31
.gitignore
vendored
@ -1,35 +1,8 @@
|
||||
*.a
|
||||
*.o
|
||||
*.d
|
||||
*.gcno
|
||||
*.gcda
|
||||
*.gcov
|
||||
*.pyc
|
||||
*~
|
||||
.config
|
||||
tests/hwsim/logs
|
||||
tests/remote/logs
|
||||
wpaspy/build
|
||||
wpa_supplicant/eapol_test
|
||||
wpa_supplicant/nfc_pw_token
|
||||
wpa_supplicant/preauth_test
|
||||
wpa_supplicant/wpa_cli
|
||||
wpa_supplicant/wpa_passphrase
|
||||
wpa_supplicant/wpa_supplicant
|
||||
wpa_supplicant/wpa_priv
|
||||
wpa_supplicant/wpa_gui/Makefile
|
||||
wpa_supplicant/wpa_gui/wpa_gui
|
||||
wpa_supplicant/wpa_gui-qt4/Makefile
|
||||
wpa_supplicant/wpa_gui-qt4/wpa_gui
|
||||
wpa_supplicant/libwpa_test1
|
||||
wpa_supplicant/libwpa_test2
|
||||
hostapd/hostapd
|
||||
hostapd/hostapd_cli
|
||||
hostapd/hlr_auc_gw
|
||||
hostapd/nt_password_hash
|
||||
mac80211_hwsim/tools/hwsim_test
|
||||
wlantest/libwlantest.a
|
||||
wlantest/test_vectors
|
||||
wlantest/wlantest
|
||||
wlantest/wlantest_cli
|
||||
**/parallel-vm.log
|
||||
tags
|
||||
build/
|
||||
|
@ -322,6 +322,24 @@ fi.w1.wpa_supplicant1.CreateInterface.
|
||||
</dl>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<h3>Roam ( s : addr ) --> nothing</h3>
|
||||
<p>Initiate a roam to another BSS within the current ESS.</p>
|
||||
<h4>Possible errors</h4>
|
||||
<dl>
|
||||
<dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
|
||||
<dd>Missing address argument.</dd>
|
||||
<dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
|
||||
<dd>Invalid hardware address format.</dd>
|
||||
<dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
|
||||
<dd>Target BSS not found.</dd>
|
||||
<dt>fi.w1.wpa_supplicant1.NotConnected</dt>
|
||||
<dd>Interface is not connected to any network.</dd>
|
||||
<dt>fi.w1.wpa_supplicant1.UnknownError</dt>
|
||||
<dd>Scan processing was not included in the build.</dd>
|
||||
</dl>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<h3>AddBlob ( s : name, ay : data ) --> nothing</h3>
|
||||
<p>Adds a blob to the interface.</p>
|
||||
@ -651,7 +669,7 @@ fi.w1.wpa_supplicant1.CreateInterface.
|
||||
<tr><td>Pairwise</td><td>as</td><td>Possible array elements: "ccmp-256", "gcmp-256", "ccmp", "gcmp", "tkip", "none"</td>
|
||||
<tr><td>Group</td><td>as</td><td>Possible array elements: "ccmp-256", "gcmp-256", "ccmp", "gcmp", "tkip", "wep104", "wep40"</td>
|
||||
<tr><td>GroupMgmt</td><td>as</td><td>Possible array elements: "aes-128-cmac", "bip-gmac-128", "bip-gmac-256", "bip-cmac-256"</td>
|
||||
<tr><td>KeyMgmt</td><td>as</td><td>Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "ieee8021x", "wpa-none", "wps", "none"</td>
|
||||
<tr><td>KeyMgmt</td><td>as</td><td>Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "sae", "ieee8021x", "wpa-none", "wps", "none"</td>
|
||||
<tr><td>Protocol</td><td>as</td><td>Possible array elements: "rsn", "wpa"</td>
|
||||
<tr><td>AuthAlg</td><td>as</td><td>Possible array elements: "open", "shared", "leap"</td>
|
||||
<tr><td>Scan</td><td>as</td><td>Possible array elements: "active", "passive", "ssid"</td>
|
||||
@ -891,7 +909,7 @@ fi.w1.wpa_supplicant1.CreateInterface.
|
||||
|
||||
<li>
|
||||
<h3>Hessid - s - (read/write)</h3>
|
||||
<p>Homogenous ESS identifier</p>
|
||||
<p>Homogeneous ESS identifier</p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
@ -2037,7 +2055,7 @@ scan results.
|
||||
<tr><td>KeyMgmt</td><td>as</td><td>Key management suite. Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "wpa-eap-suite-b", "wpa-eap-suite-b-192", "wpa-fils-sha256", "wpa-fils-sha384", "wpa-ft-fils-sha256", "wpa-ft-fils-sha384", "sae", "ft-sae", "wpa-none"</td>
|
||||
<tr><td>Pairwise</td><td>as</td><td>Pairwise cipher suites. Possible array elements: "ccmp", "tkip"</td>
|
||||
<tr><td>Group</td><td>s</td><td>Group cipher suite. Possible values are: "ccmp", "tkip", "wep104", "wep40"</td>
|
||||
<tr><td>MgmtGroup</td><td>s</td><td>Mangement frames cipher suite. Possible values are: "aes128cmac"</td>
|
||||
<tr><td>MgmtGroup</td><td>s</td><td>Management frames cipher suite. Possible values are: "aes128cmac"</td>
|
||||
</table>
|
||||
</li>
|
||||
<li>
|
||||
|
@ -278,7 +278,7 @@ TYPEDEF_HIDES_STRUCT = NO
|
||||
# For small to medium size projects (<1000 input files) the default value is
|
||||
# probably good enough. For larger projects a too small cache size can cause
|
||||
# doxygen to be busy swapping symbols to and from disk most of the time
|
||||
# causing a significant performance penality.
|
||||
# causing a significant performance penalty.
|
||||
# If the system has enough physical memory increasing the cache will improve the
|
||||
# performance by keeping more symbols in memory. Note that the value works on
|
||||
# a logarithmic scale so increasing the size by one will roughly double the
|
||||
|
@ -156,7 +156,7 @@ ap_scan=1:
|
||||
- wpa_supplicant requests scan with SIOCSIWSCAN
|
||||
- driver reports scan complete with wireless event SIOCGIWSCAN
|
||||
- wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
|
||||
a larget buffer is needed)
|
||||
a larger buffer is needed)
|
||||
- wpa_supplicant decides which AP to use based on scan results
|
||||
- wpa_supplicant configures driver to associate with the selected BSS
|
||||
(SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ,
|
||||
|
@ -283,7 +283,7 @@ service discovery. The user of the P2P module is responsible for
|
||||
providing P2P specific Service Request TLV(s) for queries and Service
|
||||
Response TLV(s) for responses.
|
||||
|
||||
\subsection p2p_sd_query Quering services of peers
|
||||
\subsection p2p_sd_query Querying services of peers
|
||||
|
||||
Service discovery is implemented by processing pending queries as a
|
||||
part of the device discovery phase. \ref p2p_sd_request() function is used
|
||||
|
@ -1,28 +1,15 @@
|
||||
ALL=eap_example
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
ifndef CC
|
||||
CC=gcc
|
||||
endif
|
||||
|
||||
ifndef RANLIB
|
||||
RANLIB=ranlib
|
||||
endif
|
||||
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
endif
|
||||
|
||||
include ../src/build.rules
|
||||
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../src
|
||||
CFLAGS += -I../src/utils
|
||||
|
||||
|
||||
OBJS_both += ../src/utils/libutils.a
|
||||
OBJS_both += ../src/crypto/libcrypto.a
|
||||
OBJS_both += ../src/tls/libtls.a
|
||||
EAP_LIBS += ../src/utils/libutils.a
|
||||
EAP_LIBS += ../src/crypto/libcrypto.a
|
||||
EAP_LIBS += ../src/tls/libtls.a
|
||||
|
||||
OBJS_both += ../src/eap_common/eap_peap_common.o
|
||||
OBJS_both += ../src/eap_common/eap_psk_common.o
|
||||
@ -95,41 +82,22 @@ OBJS_server += ../src/eap_server/eap_server_tls_common.o
|
||||
CFLAGS += -DEAP_SERVER
|
||||
|
||||
|
||||
ifndef LDO
|
||||
LDO=$(CC)
|
||||
endif
|
||||
|
||||
Q=@
|
||||
E=echo
|
||||
ifeq ($(V), 1)
|
||||
Q=
|
||||
E=true
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
|
||||
@$(E) " CC " $<
|
||||
|
||||
|
||||
OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server)
|
||||
_OBJS_VAR := OBJS_lib
|
||||
include ../src/objs.mk
|
||||
|
||||
OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o
|
||||
_OBJS_VAR := OBJS_ex
|
||||
include ../src/objs.mk
|
||||
|
||||
|
||||
../src/utils/libutils.a:
|
||||
$(MAKE) -C ../src/utils
|
||||
|
||||
../src/crypto/libcrypto.a:
|
||||
$(MAKE) -C ../src/crypto
|
||||
|
||||
../src/tls/libtls.a:
|
||||
$(MAKE) -C ../src/tls
|
||||
_OBJS_VAR := EAP_LIBS
|
||||
include ../src/objs.mk
|
||||
|
||||
|
||||
ifneq ($(CONFIG_SOLIB), yes)
|
||||
LIBEAP = libeap.a
|
||||
libeap.a: $(OBJS_lib)
|
||||
$(AR) crT libeap.a $(OBJS_lib)
|
||||
libeap.a: $(EAP_LIBS) $(OBJS_lib)
|
||||
$(AR) crT libeap.a $^
|
||||
$(RANLIB) libeap.a
|
||||
|
||||
else
|
||||
@ -137,16 +105,15 @@ CFLAGS += -fPIC -DPIC
|
||||
LDFLAGS += -shared
|
||||
|
||||
LIBEAP = libeap.so
|
||||
libeap.so: $(OBJS_lib)
|
||||
$(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP)
|
||||
libeap.so: $(EAP_LIBS) $(OBJS_lib)
|
||||
$(LDO) $(LDFLAGS) $^ -o $(LIBEAP)
|
||||
|
||||
endif
|
||||
|
||||
eap_example: $(OBJS_ex) $(LIBEAP)
|
||||
$(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS)
|
||||
|
||||
clean:
|
||||
$(MAKE) -C ../src clean
|
||||
rm -f core *~ *.o *.d libeap.a libeap.so $(ALL)
|
||||
clean: common-clean
|
||||
rm -f core *~ *.o *.d libeap.a libeap.so
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
|
@ -18,16 +18,16 @@ void eap_example_server_rx(const u8 *data, size_t data_len);
|
||||
|
||||
|
||||
struct eap_peer_ctx {
|
||||
Boolean eapSuccess;
|
||||
Boolean eapRestart;
|
||||
Boolean eapFail;
|
||||
Boolean eapResp;
|
||||
Boolean eapNoResp;
|
||||
Boolean eapReq;
|
||||
Boolean portEnabled;
|
||||
Boolean altAccept; /* for EAP */
|
||||
Boolean altReject; /* for EAP */
|
||||
Boolean eapTriggerStart;
|
||||
bool eapSuccess;
|
||||
bool eapRestart;
|
||||
bool eapFail;
|
||||
bool eapResp;
|
||||
bool eapNoResp;
|
||||
bool eapReq;
|
||||
bool portEnabled;
|
||||
bool altAccept; /* for EAP */
|
||||
bool altReject; /* for EAP */
|
||||
bool eapTriggerStart;
|
||||
|
||||
struct wpabuf *eapReqData; /* for EAP */
|
||||
|
||||
@ -48,11 +48,11 @@ static struct eap_peer_config * peer_get_config(void *ctx)
|
||||
}
|
||||
|
||||
|
||||
static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
|
||||
static bool peer_get_bool(void *ctx, enum eapol_bool_var variable)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
return FALSE;
|
||||
return false;
|
||||
switch (variable) {
|
||||
case EAPOL_eapSuccess:
|
||||
return peer->eapSuccess;
|
||||
@ -75,12 +75,11 @@ static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
|
||||
case EAPOL_eapTriggerStart:
|
||||
return peer->eapTriggerStart;
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void peer_set_bool(void *ctx, enum eapol_bool_var variable,
|
||||
Boolean value)
|
||||
static void peer_set_bool(void *ctx, enum eapol_bool_var variable, bool value)
|
||||
{
|
||||
struct eap_peer_ctx *peer = ctx;
|
||||
if (peer == NULL)
|
||||
@ -319,7 +318,7 @@ int eap_example_peer_init(void)
|
||||
return -1;
|
||||
|
||||
/* Enable "port" to allow authentication */
|
||||
eap_ctx.portEnabled = TRUE;
|
||||
eap_ctx.portEnabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -344,7 +343,7 @@ int eap_example_peer_step(void)
|
||||
if (eap_ctx.eapResp) {
|
||||
struct wpabuf *resp;
|
||||
printf("==> Response\n");
|
||||
eap_ctx.eapResp = FALSE;
|
||||
eap_ctx.eapResp = false;
|
||||
resp = eap_get_eapRespData(eap_ctx.eap);
|
||||
if (resp) {
|
||||
/* Send EAP response to the server */
|
||||
@ -372,7 +371,7 @@ int eap_example_peer_step(void)
|
||||
void eap_example_peer_rx(const u8 *data, size_t data_len)
|
||||
{
|
||||
/* Make received EAP message available to the EAP library */
|
||||
eap_ctx.eapReq = TRUE;
|
||||
eap_ctx.eapReq = true;
|
||||
wpabuf_free(eap_ctx.eapReqData);
|
||||
eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
|
||||
}
|
||||
|
@ -234,8 +234,8 @@ int eap_example_server_init(void)
|
||||
eap_ctx.eap_if = eap_get_interface(eap_ctx.eap);
|
||||
|
||||
/* Enable "port" and request EAP to start authentication. */
|
||||
eap_ctx.eap_if->portEnabled = TRUE;
|
||||
eap_ctx.eap_if->eapRestart = TRUE;
|
||||
eap_ctx.eap_if->portEnabled = true;
|
||||
eap_ctx.eap_if->eapRestart = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -296,5 +296,5 @@ void eap_example_server_rx(const u8 *data, size_t data_len)
|
||||
wpabuf_free(eap_ctx.eap_if->eapRespData);
|
||||
eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
|
||||
if (eap_ctx.eap_if->eapRespData)
|
||||
eap_ctx.eap_if->eapResp = TRUE;
|
||||
eap_ctx.eap_if->eapResp = true;
|
||||
}
|
||||
|
5
hostapd/.gitignore
vendored
Normal file
5
hostapd/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.config
|
||||
hostapd
|
||||
hostapd_cli
|
||||
hlr_auc_gw
|
||||
nt_password_hash
|
@ -250,8 +250,13 @@ endif
|
||||
ifdef CONFIG_SAE
|
||||
L_CFLAGS += -DCONFIG_SAE
|
||||
OBJS += src/common/sae.c
|
||||
ifdef CONFIG_SAE_PK
|
||||
L_CFLAGS += -DCONFIG_SAE_PK
|
||||
OBJS += src/common/sae_pk.c
|
||||
endif
|
||||
NEED_ECC=y
|
||||
NEED_DH_GROUPS=y
|
||||
NEED_HMAC_SHA256_KDF=y
|
||||
NEED_DRAGONFLY=y
|
||||
endif
|
||||
|
||||
@ -281,10 +286,6 @@ L_CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
|
||||
OBJS += src/ap/wnm_ap.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211N
|
||||
L_CFLAGS += -DCONFIG_IEEE80211N
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211AC
|
||||
L_CFLAGS += -DCONFIG_IEEE80211AC
|
||||
endif
|
||||
@ -313,6 +314,14 @@ OBJS += src/fst/fst_ctrl_iface.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WEP
|
||||
L_CFLAGS += -DCONFIG_WEP
|
||||
endif
|
||||
|
||||
ifdef CONFIG_NO_TKIP
|
||||
L_CFLAGS += -DCONFIG_NO_TKIP
|
||||
endif
|
||||
|
||||
|
||||
include $(LOCAL_PATH)/src/drivers/drivers.mk
|
||||
|
||||
@ -405,7 +414,7 @@ endif
|
||||
ifdef CONFIG_EAP_SIM_COMMON
|
||||
OBJS += src/eap_common/eap_sim_common.c
|
||||
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
|
||||
# replaced with another file implementating the interface specified in
|
||||
# replaced with another file implementing the interface specified in
|
||||
# eap_sim_db.h.
|
||||
OBJS += src/eap_server/eap_sim_db.c
|
||||
NEED_FIPS186_2_PRF=y
|
||||
@ -532,6 +541,12 @@ endif
|
||||
ifdef CONFIG_DPP
|
||||
L_CFLAGS += -DCONFIG_DPP
|
||||
OBJS += src/common/dpp.c
|
||||
OBJS += src/common/dpp_auth.c
|
||||
OBJS += src/common/dpp_backup.c
|
||||
OBJS += src/common/dpp_crypto.c
|
||||
OBJS += src/common/dpp_pkex.c
|
||||
OBJS += src/common/dpp_reconfig.c
|
||||
OBJS += src/common/dpp_tcp.c
|
||||
OBJS += src/ap/dpp_hostapd.c
|
||||
OBJS += src/ap/gas_query_ap.c
|
||||
NEED_AES_SIV=y
|
||||
@ -999,9 +1014,7 @@ OBJS += src/ap/hw_features.c
|
||||
OBJS += src/ap/dfs.c
|
||||
L_CFLAGS += -DNEED_AP_MLME
|
||||
endif
|
||||
ifdef CONFIG_IEEE80211N
|
||||
OBJS += src/ap/ieee802_11_ht.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211AC
|
||||
OBJS += src/ap/ieee802_11_vht.c
|
||||
|
@ -362,7 +362,7 @@ ChangeLog for hostapd
|
||||
* RADIUS server functionality
|
||||
- add minimal RADIUS accounting server support (hostapd-as-server);
|
||||
this is mainly to enable testing coverage with hwsim scripts
|
||||
- allow authentication log to be written into SQLite databse
|
||||
- allow authentication log to be written into SQLite database
|
||||
- added option for TLS protocol testing of an EAP peer by simulating
|
||||
various misbehaviors/known attacks
|
||||
- MAC ACL support for testing purposes
|
||||
@ -668,7 +668,7 @@ ChangeLog for hostapd
|
||||
* fixed HT Capabilities IE with nl80211 drivers
|
||||
* moved generic AP functionality code into src/ap
|
||||
* WPS: handle Selected Registrar as union of info from all Registrars
|
||||
* remove obsolte Prism54.org driver wrapper
|
||||
* remove obsolete Prism54.org driver wrapper
|
||||
* added internal debugging mechanism with backtrace support and memory
|
||||
allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
|
||||
* EAP-FAST server: piggyback Phase 2 start with the end of Phase 1
|
||||
|
131
hostapd/Makefile
131
hostapd/Makefile
@ -1,10 +1,7 @@
|
||||
ifndef CC
|
||||
CC=gcc
|
||||
endif
|
||||
ALL=hostapd hostapd_cli
|
||||
CONFIG_FILE = .config
|
||||
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
endif
|
||||
include ../src/build.rules
|
||||
|
||||
ifdef LIBS
|
||||
# If LIBS is set with some global build system defaults, clone those for
|
||||
@ -19,6 +16,9 @@ endif
|
||||
ifndef LIBS_n
|
||||
LIBS_n := $(LIBS)
|
||||
endif
|
||||
ifndef LIBS_s
|
||||
LIBS_s := $(LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS += $(EXTRA_CFLAGS)
|
||||
@ -27,8 +27,6 @@ CFLAGS += -I$(abspath ../src/utils)
|
||||
|
||||
export BINDIR ?= /usr/local/bin/
|
||||
|
||||
-include .config
|
||||
|
||||
ifndef CONFIG_NO_GITVER
|
||||
# Add VERSION_STR postfix for builds from a git repository
|
||||
ifeq ($(wildcard ../.git),../.git)
|
||||
@ -122,6 +120,7 @@ LIBS += -lbfd -ldl -liberty -lz
|
||||
LIBS_c += -lbfd -ldl -liberty -lz
|
||||
LIBS_h += -lbfd -ldl -liberty -lz
|
||||
LIBS_n += -lbfd -ldl -liberty -lz
|
||||
LIBS_s += -lbfd -ldl -liberty -lz
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -294,8 +293,13 @@ endif
|
||||
ifdef CONFIG_SAE
|
||||
CFLAGS += -DCONFIG_SAE
|
||||
OBJS += ../src/common/sae.o
|
||||
ifdef CONFIG_SAE_PK
|
||||
CFLAGS += -DCONFIG_SAE_PK
|
||||
OBJS += ../src/common/sae_pk.o
|
||||
endif
|
||||
NEED_ECC=y
|
||||
NEED_DH_GROUPS=y
|
||||
NEED_HMAC_SHA256_KDF=y
|
||||
NEED_AP_MLME=y
|
||||
NEED_DRAGONFLY=y
|
||||
endif
|
||||
@ -331,10 +335,6 @@ CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP
|
||||
OBJS += ../src/ap/wnm_ap.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211N
|
||||
CFLAGS += -DCONFIG_IEEE80211N
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211AC
|
||||
CFLAGS += -DCONFIG_IEEE80211AC
|
||||
endif
|
||||
@ -444,7 +444,7 @@ endif
|
||||
ifdef CONFIG_EAP_SIM_COMMON
|
||||
OBJS += ../src/eap_common/eap_sim_common.o
|
||||
# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
|
||||
# replaced with another file implementating the interface specified in
|
||||
# replaced with another file implementing the interface specified in
|
||||
# eap_sim_db.h.
|
||||
OBJS += ../src/eap_server/eap_sim_db.o
|
||||
NEED_FIPS186_2_PRF=y
|
||||
@ -571,6 +571,12 @@ endif
|
||||
ifdef CONFIG_DPP
|
||||
CFLAGS += -DCONFIG_DPP
|
||||
OBJS += ../src/common/dpp.o
|
||||
OBJS += ../src/common/dpp_auth.o
|
||||
OBJS += ../src/common/dpp_backup.o
|
||||
OBJS += ../src/common/dpp_crypto.o
|
||||
OBJS += ../src/common/dpp_pkex.o
|
||||
OBJS += ../src/common/dpp_reconfig.o
|
||||
OBJS += ../src/common/dpp_tcp.o
|
||||
OBJS += ../src/ap/dpp_hostapd.o
|
||||
OBJS += ../src/ap/gas_query_ap.o
|
||||
NEED_AES_SIV=y
|
||||
@ -697,6 +703,7 @@ LIBS += -lssl
|
||||
endif
|
||||
OBJS += ../src/crypto/crypto_openssl.o
|
||||
HOBJS += ../src/crypto/crypto_openssl.o
|
||||
SOBJS += ../src/crypto/crypto_openssl.o
|
||||
ifdef NEED_FIPS186_2_PRF
|
||||
OBJS += ../src/crypto/fips_prf_openssl.o
|
||||
endif
|
||||
@ -704,9 +711,11 @@ NEED_TLS_PRF_SHA256=y
|
||||
LIBS += -lcrypto
|
||||
LIBS_h += -lcrypto
|
||||
LIBS_n += -lcrypto
|
||||
LIBS_s += -lcrypto
|
||||
ifdef CONFIG_TLS_ADD_DL
|
||||
LIBS += -ldl
|
||||
LIBS_h += -ldl
|
||||
LIBS_s += -ldl
|
||||
endif
|
||||
ifndef CONFIG_TLS_DEFAULT_CIPHERS
|
||||
CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW"
|
||||
@ -1155,9 +1164,7 @@ OBJS += ../src/ap/hw_features.o
|
||||
OBJS += ../src/ap/dfs.o
|
||||
CFLAGS += -DNEED_AP_MLME
|
||||
endif
|
||||
ifdef CONFIG_IEEE80211N
|
||||
OBJS += ../src/ap/ieee802_11_ht.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IEEE80211AC
|
||||
OBJS += ../src/ap/ieee802_11_vht.o
|
||||
@ -1244,60 +1251,33 @@ OBJS += ../src/fst/fst_ctrl_iface.o
|
||||
endif
|
||||
endif
|
||||
|
||||
ALL=hostapd hostapd_cli
|
||||
|
||||
all: verify_config $(ALL)
|
||||
|
||||
Q=@
|
||||
E=echo
|
||||
ifeq ($(V), 1)
|
||||
Q=
|
||||
E=true
|
||||
endif
|
||||
ifeq ($(QUIET), 1)
|
||||
Q=@
|
||||
E=true
|
||||
ifdef CONFIG_WEP
|
||||
CFLAGS += -DCONFIG_WEP
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CODE_COVERAGE
|
||||
%.o: %.c
|
||||
@$(E) " CC " $<
|
||||
$(Q)cd $(dir $@); $(CC) -c -o $(notdir $@) $(CFLAGS) $(notdir $<)
|
||||
else
|
||||
%.o: %.c
|
||||
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
|
||||
@$(E) " CC " $<
|
||||
ifdef CONFIG_NO_TKIP
|
||||
CFLAGS += -DCONFIG_NO_TKIP
|
||||
endif
|
||||
|
||||
verify_config:
|
||||
@if [ ! -r .config ]; then \
|
||||
echo 'Building hostapd requires a configuration file'; \
|
||||
echo '(.config). See README for more instructions. You can'; \
|
||||
echo 'run "cp defconfig .config" to create an example'; \
|
||||
echo 'configuration.'; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
$(DESTDIR)$(BINDIR)/%: %
|
||||
install -D $(<) $(@)
|
||||
|
||||
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL))
|
||||
|
||||
../src/drivers/build.hostapd:
|
||||
@if [ -f ../src/drivers/build.wpa_supplicant ]; then \
|
||||
$(MAKE) -C ../src/drivers clean; \
|
||||
fi
|
||||
@touch ../src/drivers/build.hostapd
|
||||
_OBJS_VAR := OBJS
|
||||
include ../src/objs.mk
|
||||
|
||||
BCHECK=../src/drivers/build.hostapd
|
||||
|
||||
hostapd: $(BCHECK) $(OBJS)
|
||||
hostapd: $(OBJS)
|
||||
$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
|
||||
@$(E) " LD " $@
|
||||
|
||||
ifdef CONFIG_WPA_TRACE
|
||||
OBJS_c += ../src/utils/trace.o
|
||||
endif
|
||||
|
||||
_OBJS_VAR := OBJS_c
|
||||
include ../src/objs.mk
|
||||
|
||||
hostapd_cli: $(OBJS_c)
|
||||
$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
|
||||
@$(E) " LD " $@
|
||||
@ -1332,6 +1312,35 @@ ifeq ($(CONFIG_TLS), linux)
|
||||
HOBJS += ../src/crypto/crypto_linux.o
|
||||
endif
|
||||
|
||||
SOBJS += sae_pk_gen.o
|
||||
SOBJS += ../src/utils/common.o
|
||||
SOBJS += ../src/utils/os_$(CONFIG_OS).o
|
||||
SOBJS += ../src/utils/base64.o
|
||||
SOBJS += ../src/utils/wpa_debug.o
|
||||
SOBJS += ../src/utils/wpabuf.o
|
||||
ifdef CONFIG_WPA_TRACE
|
||||
SOBJS += ../src/utils/trace.o
|
||||
endif
|
||||
SOBJS += ../src/common/ieee802_11_common.o
|
||||
SOBJS += ../src/common/sae.o
|
||||
SOBJS += ../src/common/sae_pk.o
|
||||
SOBJS += ../src/common/dragonfly.o
|
||||
SOBJS += $(AESOBJS)
|
||||
SOBJS += ../src/crypto/sha256-prf.o
|
||||
SOBJS += ../src/crypto/sha384-prf.o
|
||||
SOBJS += ../src/crypto/sha512-prf.o
|
||||
SOBJS += ../src/crypto/dh_groups.o
|
||||
SOBJS += ../src/crypto/sha256-kdf.o
|
||||
SOBJS += ../src/crypto/sha384-kdf.o
|
||||
SOBJS += ../src/crypto/sha512-kdf.o
|
||||
|
||||
_OBJS_VAR := NOBJS
|
||||
include ../src/objs.mk
|
||||
_OBJS_VAR := HOBJS
|
||||
include ../src/objs.mk
|
||||
_OBJS_VAR := SOBJS
|
||||
include ../src/objs.mk
|
||||
|
||||
nt_password_hash: $(NOBJS)
|
||||
$(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
|
||||
@$(E) " LD " $@
|
||||
@ -1340,15 +1349,17 @@ hlr_auc_gw: $(HOBJS)
|
||||
$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
|
||||
@$(E) " LD " $@
|
||||
|
||||
sae_pk_gen: $(SOBJS)
|
||||
$(Q)$(CC) $(LDFLAGS) -o sae_pk_gen $(SOBJS) $(LIBS_s)
|
||||
@$(E) " LD " $@
|
||||
|
||||
.PHONY: lcov-html
|
||||
lcov-html:
|
||||
lcov -c -d .. > lcov.info
|
||||
lcov -c -d $(BUILDDIR) > lcov.info
|
||||
genhtml lcov.info --output-directory lcov-html
|
||||
|
||||
clean:
|
||||
$(MAKE) -C ../src clean
|
||||
rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
|
||||
rm -f *.d *.gcno *.gcda *.gcov
|
||||
clean: common-clean
|
||||
rm -f core *~ nt_password_hash hlr_auc_gw
|
||||
rm -f sae_pk_gen
|
||||
rm -f lcov.info
|
||||
rm -rf lcov-html
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
|
@ -125,9 +125,6 @@ CONFIG_IPV6=y
|
||||
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
|
||||
#CONFIG_DRIVER_RADIUS_ACL=y
|
||||
|
||||
# IEEE 802.11n (High Throughput) support
|
||||
CONFIG_IEEE80211N=y
|
||||
|
||||
# Remove debugging code that is printing out debug messages to stdout.
|
||||
# This can be used to reduce the size of the hostapd considerably if debugging
|
||||
# code is not needed.
|
||||
@ -187,7 +184,7 @@ CONFIG_AP=y
|
||||
#CONFIG_FST=y
|
||||
|
||||
# Multiband Operation support
|
||||
# These extentions facilitate efficient use of multiple frequency bands
|
||||
# These extensions facilitate efficient use of multiple frequency bands
|
||||
# available to the AP and the devices that may associate with it.
|
||||
#CONFIG_MBO=y
|
||||
|
||||
@ -204,3 +201,11 @@ CONFIG_WPA_CLI_EDIT=y
|
||||
# /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before
|
||||
# either wpa_supplicant or hostapd are run.
|
||||
CONFIG_NO_RANDOM_POOL=y
|
||||
|
||||
# Wired equivalent privacy (WEP)
|
||||
# WEP is an obsolete cryptographic data confidentiality algorithm that is not
|
||||
# considered secure. It should not be used for anything anymore. The
|
||||
# functionality needed to use WEP is available in the current hostapd
|
||||
# release under this optional build parameter. This functionality is subject to
|
||||
# be completely removed in a future release.
|
||||
CONFIG_WEP=y
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "utils/common.h"
|
||||
#include "utils/uuid.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/sae.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "drivers/driver.h"
|
||||
@ -340,7 +341,7 @@ static int hostapd_config_read_eap_user(const char *fname,
|
||||
struct hostapd_radius_attr *attr, *a;
|
||||
attr = hostapd_parse_radius_attr(buf + 19);
|
||||
if (attr == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s",
|
||||
wpa_printf(MSG_ERROR, "Invalid radius_accept_attr: %s",
|
||||
buf + 19);
|
||||
user = NULL; /* already in the BSS list */
|
||||
goto failed;
|
||||
@ -793,6 +794,7 @@ static int hostapd_config_parse_cipher(int line, const char *value)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
|
||||
char *val)
|
||||
{
|
||||
@ -843,6 +845,7 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
|
||||
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
|
||||
@ -940,104 +943,6 @@ static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
|
||||
}
|
||||
|
||||
|
||||
/* convert floats with one decimal place to value*10 int, i.e.,
|
||||
* "1.5" will return 15 */
|
||||
static int hostapd_config_read_int10(const char *value)
|
||||
{
|
||||
int i, d;
|
||||
char *pos;
|
||||
|
||||
i = atoi(value);
|
||||
pos = os_strchr(value, '.');
|
||||
d = 0;
|
||||
if (pos) {
|
||||
pos++;
|
||||
if (*pos >= '0' && *pos <= '9')
|
||||
d = *pos - '0';
|
||||
}
|
||||
|
||||
return i * 10 + d;
|
||||
}
|
||||
|
||||
|
||||
static int valid_cw(int cw)
|
||||
{
|
||||
return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
|
||||
cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
|
||||
cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
|
||||
cw == 32767);
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
|
||||
IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
|
||||
IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
|
||||
IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
|
||||
};
|
||||
|
||||
static int hostapd_config_tx_queue(struct hostapd_config *conf,
|
||||
const char *name, const char *val)
|
||||
{
|
||||
int num;
|
||||
const char *pos;
|
||||
struct hostapd_tx_queue_params *queue;
|
||||
|
||||
/* skip 'tx_queue_' prefix */
|
||||
pos = name + 9;
|
||||
if (os_strncmp(pos, "data", 4) == 0 &&
|
||||
pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
|
||||
num = pos[4] - '0';
|
||||
pos += 6;
|
||||
} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
|
||||
os_strncmp(pos, "beacon_", 7) == 0) {
|
||||
wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
|
||||
return 0;
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num >= NUM_TX_QUEUES) {
|
||||
/* for backwards compatibility, do not trigger failure */
|
||||
wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
queue = &conf->tx_queue[num];
|
||||
|
||||
if (os_strcmp(pos, "aifs") == 0) {
|
||||
queue->aifs = atoi(val);
|
||||
if (queue->aifs < 0 || queue->aifs > 255) {
|
||||
wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
|
||||
queue->aifs);
|
||||
return -1;
|
||||
}
|
||||
} else if (os_strcmp(pos, "cwmin") == 0) {
|
||||
queue->cwmin = atoi(val);
|
||||
if (!valid_cw(queue->cwmin)) {
|
||||
wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
|
||||
queue->cwmin);
|
||||
return -1;
|
||||
}
|
||||
} else if (os_strcmp(pos, "cwmax") == 0) {
|
||||
queue->cwmax = atoi(val);
|
||||
if (!valid_cw(queue->cwmax)) {
|
||||
wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
|
||||
queue->cwmax);
|
||||
return -1;
|
||||
}
|
||||
} else if (os_strcmp(pos, "burst") == 0) {
|
||||
queue->burst = hostapd_config_read_int10(val);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
|
||||
static int rkh_derive_key(const char *pos, u8 *key, size_t key_len)
|
||||
@ -1151,7 +1056,6 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
static int hostapd_config_ht_capab(struct hostapd_config *conf,
|
||||
const char *capab)
|
||||
{
|
||||
@ -1171,14 +1075,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
|
||||
}
|
||||
if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]"))
|
||||
conf->secondary_channel = 0;
|
||||
if (os_strstr(capab, "[SMPS-STATIC]")) {
|
||||
conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
|
||||
conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
|
||||
}
|
||||
if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
|
||||
conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
|
||||
conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
|
||||
}
|
||||
if (os_strstr(capab, "[GF]"))
|
||||
conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
|
||||
if (os_strstr(capab, "[SHORT-GI-20]"))
|
||||
@ -1212,7 +1108,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
@ -2298,6 +2193,35 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
|
||||
pw->vlan_id = atoi(pos2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
pos2 = os_strstr(pos, "|pk=");
|
||||
if (pos2) {
|
||||
const char *epos;
|
||||
char *tmp;
|
||||
|
||||
if (!end)
|
||||
end = pos2;
|
||||
pos2 += 4;
|
||||
epos = os_strchr(pos2, '|');
|
||||
if (epos) {
|
||||
tmp = os_malloc(epos - pos2 + 1);
|
||||
if (!tmp)
|
||||
goto fail;
|
||||
os_memcpy(tmp, pos2, epos - pos2);
|
||||
tmp[epos - pos2] = '\0';
|
||||
} else {
|
||||
tmp = os_strdup(pos2);
|
||||
if (!tmp)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pw->pk = sae_parse_pk(tmp);
|
||||
str_clear_free(tmp);
|
||||
if (!pw->pk)
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
pos2 = os_strstr(pos, "|id=");
|
||||
if (pos2) {
|
||||
if (!end)
|
||||
@ -2320,6 +2244,18 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
|
||||
pw->password[end - val] = '\0';
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (pw->pk &&
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
!bss->sae_pk_password_check_skip &&
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
!sae_pk_valid_password(pw->password)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Invalid SAE password for a SAE-PK sae_password entry");
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
pw->next = bss->sae_passwords;
|
||||
bss->sae_passwords = pw;
|
||||
|
||||
@ -2327,6 +2263,9 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
|
||||
fail:
|
||||
str_clear_free(pw->password);
|
||||
os_free(pw->identifier);
|
||||
#ifdef CONFIG_SAE_PK
|
||||
sae_deinit_pk(pw->pk);
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
os_free(pw);
|
||||
return -1;
|
||||
}
|
||||
@ -2471,6 +2410,13 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
|
||||
bss->skip_inactivity_poll = atoi(pos);
|
||||
} else if (os_strcmp(buf, "country_code") == 0) {
|
||||
if (pos[0] < 'A' || pos[0] > 'Z' ||
|
||||
pos[1] < 'A' || pos[1] > 'Z') {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid country_code '%s'",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
os_memcpy(conf->country, pos, 2);
|
||||
} else if (os_strcmp(buf, "country3") == 0) {
|
||||
conf->country[2] = strtol(pos, NULL, 16);
|
||||
@ -2613,7 +2559,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "eap_teap_auth") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 1) {
|
||||
if (val < 0 || val > 2) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid eap_teap_auth value",
|
||||
line);
|
||||
@ -2674,6 +2620,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "erp_domain") == 0) {
|
||||
os_free(bss->erp_domain);
|
||||
bss->erp_domain = os_strdup(pos);
|
||||
#ifdef CONFIG_WEP
|
||||
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
@ -2701,6 +2648,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line, bss->wep_rekeying_period);
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
|
||||
bss->eap_reauth_period = atoi(pos);
|
||||
if (bss->eap_reauth_period < 0) {
|
||||
@ -2875,6 +2823,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
}
|
||||
} else if (os_strcmp(buf, "wpa") == 0) {
|
||||
bss->wpa = atoi(pos);
|
||||
} else if (os_strcmp(buf, "extended_key_id") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 2) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid extended_key_id=%d; allowed range 0..2",
|
||||
line, val);
|
||||
return 1;
|
||||
}
|
||||
bss->extended_key_id = val;
|
||||
} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
|
||||
bss->wpa_group_rekey = atoi(pos);
|
||||
bss->wpa_group_rekey_set = 1;
|
||||
@ -2884,6 +2842,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->wpa_gmk_rekey = atoi(pos);
|
||||
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
|
||||
bss->wpa_ptk_rekey = atoi(pos);
|
||||
} else if (os_strcmp(buf, "wpa_deny_ptk0_rekey") == 0) {
|
||||
bss->wpa_deny_ptk0_rekey = atoi(pos);
|
||||
if (bss->wpa_deny_ptk0_rekey < 0 ||
|
||||
bss->wpa_deny_ptk0_rekey > 2) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid wpa_deny_ptk0_rekey=%d; allowed range 0..2",
|
||||
line, bss->wpa_deny_ptk0_rekey);
|
||||
return 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
|
||||
char *endp;
|
||||
unsigned long val = strtoul(pos, &endp, 0);
|
||||
@ -3312,6 +3279,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->ignore_broadcast_ssid = atoi(pos);
|
||||
} else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
|
||||
bss->no_probe_resp_if_max_sta = atoi(pos);
|
||||
#ifdef CONFIG_WEP
|
||||
} else if (os_strcmp(buf, "wep_default_key") == 0) {
|
||||
bss->ssid.wep.idx = atoi(pos);
|
||||
if (bss->ssid.wep.idx > 3) {
|
||||
@ -3330,6 +3298,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line, buf);
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
|
||||
bss->ssid.dynamic_vlan = atoi(pos);
|
||||
@ -3361,7 +3330,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
|
||||
conf->ap_table_expiration_time = atoi(pos);
|
||||
} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
|
||||
if (hostapd_config_tx_queue(conf, buf, pos)) {
|
||||
if (hostapd_config_tx_queue(conf->tx_queue, buf, pos)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item",
|
||||
line);
|
||||
return 1;
|
||||
@ -3408,6 +3377,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "beacon_prot") == 0) {
|
||||
bss->beacon_prot = atoi(pos);
|
||||
} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
|
||||
bss->assoc_sa_query_max_timeout = atoi(pos);
|
||||
if (bss->assoc_sa_query_max_timeout == 0) {
|
||||
@ -3428,7 +3399,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
if (bss->ocv && !bss->ieee80211w)
|
||||
bss->ieee80211w = 1;
|
||||
#endif /* CONFIG_OCV */
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
} else if (os_strcmp(buf, "ieee80211n") == 0) {
|
||||
conf->ieee80211n = atoi(pos);
|
||||
} else if (os_strcmp(buf, "ht_capab") == 0) {
|
||||
@ -3441,7 +3411,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
conf->require_ht = atoi(pos);
|
||||
} else if (os_strcmp(buf, "obss_interval") == 0) {
|
||||
conf->obss_interval = atoi(pos);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
} else if (os_strcmp(buf, "ieee80211ac") == 0) {
|
||||
conf->ieee80211ac = atoi(pos);
|
||||
@ -3474,7 +3443,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
|
||||
conf->he_phy_capab.he_mu_beamformer = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_bss_color") == 0) {
|
||||
conf->he_op.he_bss_color = atoi(pos);
|
||||
conf->he_op.he_bss_color = atoi(pos) & 0x3f;
|
||||
conf->he_op.he_bss_color_disabled = 0;
|
||||
} else if (os_strcmp(buf, "he_bss_color_partial") == 0) {
|
||||
conf->he_op.he_bss_color_partial = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
|
||||
conf->he_op.he_default_pe_duration = atoi(pos);
|
||||
} else if (os_strcmp(buf, "he_twt_required") == 0) {
|
||||
@ -4165,18 +4137,53 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->own_ie_override = tmp;
|
||||
} else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
|
||||
bss->sae_reflection_attack = atoi(pos);
|
||||
} else if (os_strcmp(buf, "sae_commit_status") == 0) {
|
||||
bss->sae_commit_status = atoi(pos);
|
||||
} else if (os_strcmp(buf, "sae_pk_omit") == 0) {
|
||||
bss->sae_pk_omit = atoi(pos);
|
||||
} else if (os_strcmp(buf, "sae_pk_password_check_skip") == 0) {
|
||||
bss->sae_pk_password_check_skip = atoi(pos);
|
||||
} else if (os_strcmp(buf, "sae_commit_override") == 0) {
|
||||
wpabuf_free(bss->sae_commit_override);
|
||||
bss->sae_commit_override = wpabuf_parse_bin(pos);
|
||||
} else if (os_strcmp(buf, "rsne_override_eapol") == 0) {
|
||||
wpabuf_free(bss->rsne_override_eapol);
|
||||
bss->rsne_override_eapol = wpabuf_parse_bin(pos);
|
||||
} else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) {
|
||||
wpabuf_free(bss->rsnxe_override_eapol);
|
||||
bss->rsnxe_override_eapol = wpabuf_parse_bin(pos);
|
||||
} else if (os_strcmp(buf, "rsne_override_ft") == 0) {
|
||||
wpabuf_free(bss->rsne_override_ft);
|
||||
bss->rsne_override_ft = wpabuf_parse_bin(pos);
|
||||
} else if (os_strcmp(buf, "rsnxe_override_ft") == 0) {
|
||||
wpabuf_free(bss->rsnxe_override_ft);
|
||||
bss->rsnxe_override_ft = wpabuf_parse_bin(pos);
|
||||
} else if (os_strcmp(buf, "gtk_rsc_override") == 0) {
|
||||
wpabuf_free(bss->gtk_rsc_override);
|
||||
bss->gtk_rsc_override = wpabuf_parse_bin(pos);
|
||||
} else if (os_strcmp(buf, "igtk_rsc_override") == 0) {
|
||||
wpabuf_free(bss->igtk_rsc_override);
|
||||
bss->igtk_rsc_override = wpabuf_parse_bin(pos);
|
||||
} else if (os_strcmp(buf, "no_beacon_rsnxe") == 0) {
|
||||
bss->no_beacon_rsnxe = atoi(pos);
|
||||
} else if (os_strcmp(buf, "skip_prune_assoc") == 0) {
|
||||
bss->skip_prune_assoc = atoi(pos);
|
||||
} else if (os_strcmp(buf, "ft_rsnxe_used") == 0) {
|
||||
bss->ft_rsnxe_used = atoi(pos);
|
||||
} else if (os_strcmp(buf, "oci_freq_override_eapol_m3") == 0) {
|
||||
bss->oci_freq_override_eapol_m3 = atoi(pos);
|
||||
} else if (os_strcmp(buf, "oci_freq_override_eapol_g1") == 0) {
|
||||
bss->oci_freq_override_eapol_g1 = atoi(pos);
|
||||
} else if (os_strcmp(buf, "oci_freq_override_saquery_req") == 0) {
|
||||
bss->oci_freq_override_saquery_req = atoi(pos);
|
||||
} else if (os_strcmp(buf, "oci_freq_override_saquery_resp") == 0) {
|
||||
bss->oci_freq_override_saquery_resp = atoi(pos);
|
||||
} else if (os_strcmp(buf, "oci_freq_override_ft_assoc") == 0) {
|
||||
bss->oci_freq_override_ft_assoc = atoi(pos);
|
||||
} else if (os_strcmp(buf, "oci_freq_override_fils_assoc") == 0) {
|
||||
bss->oci_freq_override_fils_assoc = atoi(pos);
|
||||
} else if (os_strcmp(buf, "oci_freq_override_wnm_sleep") == 0) {
|
||||
bss->oci_freq_override_wnm_sleep = atoi(pos);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_SAE
|
||||
} else if (os_strcmp(buf, "sae_password") == 0) {
|
||||
@ -4379,6 +4386,18 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "dpp_controller") == 0) {
|
||||
if (hostapd_dpp_controller_parse(bss, pos))
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) {
|
||||
bss->dpp_configurator_connectivity = atoi(pos);
|
||||
} else if (os_strcmp(buf, "dpp_pfs") == 0) {
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val < 0 || val > 2) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid dpp_pfs value '%s'",
|
||||
line, pos);
|
||||
return -1;
|
||||
}
|
||||
bss->dpp_pfs = val;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#endif /* CONFIG_DPP */
|
||||
#ifdef CONFIG_OWE
|
||||
@ -4431,8 +4450,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
conf->rssi_reject_assoc_rssi = atoi(pos);
|
||||
} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
|
||||
conf->rssi_reject_assoc_timeout = atoi(pos);
|
||||
} else if (os_strcmp(buf, "rssi_ignore_probe_request") == 0) {
|
||||
conf->rssi_ignore_probe_request = atoi(pos);
|
||||
} else if (os_strcmp(buf, "pbss") == 0) {
|
||||
bss->pbss = atoi(pos);
|
||||
} else if (os_strcmp(buf, "transition_disable") == 0) {
|
||||
bss->transition_disable = strtol(pos, NULL, 16);
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
} else if (os_strcmp(buf, "airtime_mode") == 0) {
|
||||
int val = atoi(pos);
|
||||
@ -4548,6 +4571,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
}
|
||||
bss->mka_psk_set |= MKA_PSK_SET_CKN;
|
||||
#endif /* CONFIG_MACSEC */
|
||||
} else if (os_strcmp(buf, "disable_11n") == 0) {
|
||||
bss->disable_11n = !!atoi(pos);
|
||||
} else if (os_strcmp(buf, "disable_11ac") == 0) {
|
||||
bss->disable_11ac = !!atoi(pos);
|
||||
} else if (os_strcmp(buf, "disable_11ax") == 0) {
|
||||
bss->disable_11ax = !!atoi(pos);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: unknown configuration item '%s'",
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "ap/ieee802_1x.h"
|
||||
#include "ap/wpa_auth.h"
|
||||
#include "ap/wpa_auth_i.h"
|
||||
#include "ap/pmksa_cache_auth.h"
|
||||
#include "ap/ieee802_11.h"
|
||||
#include "ap/sta_info.h"
|
||||
#include "ap/wps_hostapd.h"
|
||||
@ -61,6 +62,7 @@
|
||||
#include "ap/neighbor_db.h"
|
||||
#include "ap/rrm.h"
|
||||
#include "ap/dpp_hostapd.h"
|
||||
#include "ap/dfs.h"
|
||||
#include "wps/wps_defs.h"
|
||||
#include "wps/wps.h"
|
||||
#include "fst/fst_ctrl_iface.h"
|
||||
@ -71,9 +73,6 @@
|
||||
#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
#define COOKIE_LEN 8
|
||||
static unsigned char cookie[COOKIE_LEN];
|
||||
static unsigned char gcookie[COOKIE_LEN];
|
||||
#define HOSTAPD_CTRL_IFACE_PORT 8877
|
||||
#define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50
|
||||
#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878
|
||||
@ -1294,6 +1293,22 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
|
||||
ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
|
||||
hapd->conf->wpa_deny_ptk0_rekey);
|
||||
if (os_snprintf_error(end - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
|
||||
ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
|
||||
hapd->conf->extended_key_id);
|
||||
if (os_snprintf_error(end - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
@ -1336,21 +1351,29 @@ static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
|
||||
const char *band)
|
||||
const char *bands)
|
||||
{
|
||||
union wpa_event_data event;
|
||||
enum set_band setband;
|
||||
u32 setband_mask = WPA_SETBAND_AUTO;
|
||||
|
||||
if (os_strcmp(band, "AUTO") == 0)
|
||||
setband = WPA_SETBAND_AUTO;
|
||||
else if (os_strcmp(band, "5G") == 0)
|
||||
setband = WPA_SETBAND_5G;
|
||||
else if (os_strcmp(band, "2G") == 0)
|
||||
setband = WPA_SETBAND_2G;
|
||||
else
|
||||
return -1;
|
||||
/*
|
||||
* For example:
|
||||
* SET setband 2G,6G
|
||||
* SET setband 5G
|
||||
* SET setband AUTO
|
||||
*/
|
||||
if (!os_strstr(bands, "AUTO")) {
|
||||
if (os_strstr(bands, "5G"))
|
||||
setband_mask |= WPA_SETBAND_5G;
|
||||
if (os_strstr(bands, "6G"))
|
||||
setband_mask |= WPA_SETBAND_6G;
|
||||
if (os_strstr(bands, "2G"))
|
||||
setband_mask |= WPA_SETBAND_2G;
|
||||
if (setband_mask == WPA_SETBAND_AUTO)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hostapd_drv_set_band(hapd, setband) == 0) {
|
||||
if (hostapd_drv_set_band(hapd, setband_mask) == 0) {
|
||||
os_memset(&event, 0, sizeof(event));
|
||||
event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
|
||||
event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
|
||||
@ -1418,6 +1441,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
|
||||
hapd->dpp_ignore_netaccesskey_mismatch = atoi(value);
|
||||
} else if (os_strcasecmp(cmd, "dpp_test") == 0) {
|
||||
dpp_test = atoi(value);
|
||||
} else if (os_strcasecmp(cmd, "dpp_version_override") == 0) {
|
||||
dpp_version_override = atoi(value);
|
||||
#endif /* CONFIG_DPP */
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_MBO
|
||||
@ -1466,7 +1491,32 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
|
||||
os_strcmp(cmd, "sae_pwe") == 0) {
|
||||
if (hapd->started)
|
||||
hostapd_setup_sae_pt(hapd->conf);
|
||||
} else if (os_strcasecmp(cmd, "transition_disable") == 0) {
|
||||
wpa_auth_set_transition_disable(hapd->wpa_auth,
|
||||
hapd->conf->transition_disable);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (os_strcmp(cmd, "ft_rsnxe_used") == 0)
|
||||
wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth,
|
||||
hapd->conf->ft_rsnxe_used);
|
||||
else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0)
|
||||
wpa_auth_set_ocv_override_freq(
|
||||
hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
|
||||
atoi(value));
|
||||
else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0)
|
||||
wpa_auth_set_ocv_override_freq(
|
||||
hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
|
||||
atoi(value));
|
||||
else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0)
|
||||
wpa_auth_set_ocv_override_freq(
|
||||
hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
|
||||
atoi(value));
|
||||
else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0)
|
||||
wpa_auth_set_ocv_override_freq(
|
||||
hapd->wpa_auth,
|
||||
WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value));
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -1884,7 +1934,7 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
if (ip.ip_hl != 5 || ip.ip_v != 4 ||
|
||||
ntohs(ip.ip_len) > HWSIM_IP_LEN) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"test data: RX - ignore unexpect IP header");
|
||||
"test data: RX - ignore unexpected IP header");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2147,6 +2197,32 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
|
||||
if (hwaddr_aton(cmd, addr))
|
||||
return -1;
|
||||
|
||||
if (is_broadcast_ether_addr(addr) && os_strstr(cmd, " BIGTK")) {
|
||||
if (hapd->last_bigtk_alg == WPA_ALG_NONE)
|
||||
return -1;
|
||||
|
||||
wpa_printf(MSG_INFO, "TESTING: Reset BIPN for BIGTK");
|
||||
|
||||
/* First, use a zero key to avoid any possible duplicate key
|
||||
* avoidance in the driver. */
|
||||
if (hostapd_drv_set_key(hapd->conf->iface, hapd,
|
||||
hapd->last_bigtk_alg,
|
||||
broadcast_ether_addr,
|
||||
hapd->last_bigtk_key_idx, 0, 1, NULL, 0,
|
||||
zero, hapd->last_bigtk_len,
|
||||
KEY_FLAG_GROUP_TX_DEFAULT) < 0)
|
||||
return -1;
|
||||
|
||||
/* Set the previously configured key to reset its TSC */
|
||||
return hostapd_drv_set_key(hapd->conf->iface, hapd,
|
||||
hapd->last_bigtk_alg,
|
||||
broadcast_ether_addr,
|
||||
hapd->last_bigtk_key_idx, 0, 1, NULL,
|
||||
0, hapd->last_bigtk,
|
||||
hapd->last_bigtk_len,
|
||||
KEY_FLAG_GROUP_TX_DEFAULT);
|
||||
}
|
||||
|
||||
if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
|
||||
if (hapd->last_igtk_alg == WPA_ALG_NONE)
|
||||
return -1;
|
||||
@ -2412,6 +2488,19 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
struct rsn_pmksa_cache_entry *pmksa;
|
||||
|
||||
pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, addr, NULL);
|
||||
if (!pmksa)
|
||||
return -1;
|
||||
|
||||
return wpa_snprintf_hex(buf, buflen, pmksa->pmk, pmksa->pmk_len);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
@ -2427,13 +2516,13 @@ static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd,
|
||||
if (!sta || !sta->wpa_sm) {
|
||||
wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR,
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
|
||||
}
|
||||
pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
|
||||
if (!pmk) {
|
||||
if (!pmk || !pmk_len) {
|
||||
wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR,
|
||||
MAC2STR(addr));
|
||||
return -1;
|
||||
return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen);
|
||||
}
|
||||
|
||||
return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
|
||||
@ -2501,18 +2590,175 @@ static int hostapd_get_channel(struct hostapd_data *hapd, char *buf, size_t buf
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params)
|
||||
{
|
||||
switch (params->bandwidth) {
|
||||
case 0:
|
||||
/* bandwidth not specified: use 20 MHz by default */
|
||||
/* fall-through */
|
||||
case 20:
|
||||
if (params->center_freq1 &&
|
||||
params->center_freq1 != params->freq)
|
||||
return -1;
|
||||
|
||||
if (params->center_freq2 || params->sec_channel_offset)
|
||||
return -1;
|
||||
break;
|
||||
case 40:
|
||||
if (params->center_freq2 || !params->sec_channel_offset)
|
||||
return -1;
|
||||
|
||||
if (!params->center_freq1)
|
||||
break;
|
||||
switch (params->sec_channel_offset) {
|
||||
case 1:
|
||||
if (params->freq + 10 != params->center_freq1)
|
||||
return -1;
|
||||
break;
|
||||
case -1:
|
||||
if (params->freq - 10 != params->center_freq1)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 80:
|
||||
if (!params->center_freq1 || !params->sec_channel_offset)
|
||||
return 1;
|
||||
|
||||
switch (params->sec_channel_offset) {
|
||||
case 1:
|
||||
if (params->freq - 10 != params->center_freq1 &&
|
||||
params->freq + 30 != params->center_freq1)
|
||||
return 1;
|
||||
break;
|
||||
case -1:
|
||||
if (params->freq + 10 != params->center_freq1 &&
|
||||
params->freq - 30 != params->center_freq1)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Adjacent and overlapped are not allowed for 80+80 */
|
||||
if (params->center_freq2 &&
|
||||
params->center_freq1 - params->center_freq2 <= 80 &&
|
||||
params->center_freq2 - params->center_freq1 <= 80)
|
||||
return 1;
|
||||
break;
|
||||
case 160:
|
||||
if (!params->center_freq1 || params->center_freq2 ||
|
||||
!params->sec_channel_offset)
|
||||
return -1;
|
||||
|
||||
switch (params->sec_channel_offset) {
|
||||
case 1:
|
||||
if (params->freq + 70 != params->center_freq1 &&
|
||||
params->freq + 30 != params->center_freq1 &&
|
||||
params->freq - 10 != params->center_freq1 &&
|
||||
params->freq - 50 != params->center_freq1)
|
||||
return -1;
|
||||
break;
|
||||
case -1:
|
||||
if (params->freq + 50 != params->center_freq1 &&
|
||||
params->freq + 10 != params->center_freq1 &&
|
||||
params->freq - 30 != params->center_freq1 &&
|
||||
params->freq - 70 != params->center_freq1)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
|
||||
char *pos)
|
||||
{
|
||||
#ifdef NEED_AP_MLME
|
||||
struct csa_settings settings;
|
||||
int ret;
|
||||
int dfs_range = 0;
|
||||
unsigned int i;
|
||||
int bandwidth;
|
||||
u8 chan;
|
||||
|
||||
ret = hostapd_parse_csa_settings(pos, &settings);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hostapd_ctrl_check_freq_params(&settings.freq_params);
|
||||
if (ret) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"chanswitch: invalid frequency settings provided");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (settings.freq_params.bandwidth) {
|
||||
case 40:
|
||||
bandwidth = CHAN_WIDTH_40;
|
||||
break;
|
||||
case 80:
|
||||
if (settings.freq_params.center_freq2)
|
||||
bandwidth = CHAN_WIDTH_80P80;
|
||||
else
|
||||
bandwidth = CHAN_WIDTH_80;
|
||||
break;
|
||||
case 160:
|
||||
bandwidth = CHAN_WIDTH_160;
|
||||
break;
|
||||
default:
|
||||
bandwidth = CHAN_WIDTH_20;
|
||||
break;
|
||||
}
|
||||
|
||||
if (settings.freq_params.center_freq1)
|
||||
dfs_range += hostapd_is_dfs_overlap(
|
||||
iface, bandwidth, settings.freq_params.center_freq1);
|
||||
else
|
||||
dfs_range += hostapd_is_dfs_overlap(
|
||||
iface, bandwidth, settings.freq_params.freq);
|
||||
|
||||
if (settings.freq_params.center_freq2)
|
||||
dfs_range += hostapd_is_dfs_overlap(
|
||||
iface, bandwidth, settings.freq_params.center_freq2);
|
||||
|
||||
if (dfs_range) {
|
||||
ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan);
|
||||
if (ret == NUM_HOSTAPD_MODES) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)",
|
||||
settings.freq_params.freq,
|
||||
settings.freq_params.sec_channel_offset,
|
||||
settings.freq_params.bandwidth);
|
||||
return -1;
|
||||
}
|
||||
|
||||
settings.freq_params.channel = chan;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)",
|
||||
settings.freq_params.channel,
|
||||
settings.freq_params.freq,
|
||||
settings.freq_params.sec_channel_offset,
|
||||
settings.freq_params.bandwidth,
|
||||
settings.freq_params.center_freq1);
|
||||
|
||||
/* Perform CAC and switch channel */
|
||||
hostapd_switch_channel_fallback(iface, &settings.freq_params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
|
||||
/* Save CHAN_SWITCH VHT config */
|
||||
@ -2551,13 +2797,17 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
int ret;
|
||||
char *pos;
|
||||
char *pos, *temp = NULL;
|
||||
u8 *data = NULL;
|
||||
unsigned int vendor_id, subcmd;
|
||||
enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED;
|
||||
struct wpabuf *reply;
|
||||
size_t data_len = 0;
|
||||
|
||||
/* cmd: <vendor id> <subcommand id> [<hex formatted data>] */
|
||||
/**
|
||||
* cmd: <vendor id> <subcommand id> [<hex formatted data>]
|
||||
* [nested=<0|1>]
|
||||
*/
|
||||
vendor_id = strtoul(cmd, &pos, 16);
|
||||
if (!isblank((unsigned char) *pos))
|
||||
return -EINVAL;
|
||||
@ -2567,7 +2817,9 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
|
||||
if (*pos != '\0') {
|
||||
if (!isblank((unsigned char) *pos++))
|
||||
return -EINVAL;
|
||||
data_len = os_strlen(pos);
|
||||
|
||||
temp = os_strchr(pos, ' ');
|
||||
data_len = temp ? (size_t) (temp - pos) : os_strlen(pos);
|
||||
}
|
||||
|
||||
if (data_len) {
|
||||
@ -2584,6 +2836,11 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, "nested=");
|
||||
if (pos)
|
||||
nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED :
|
||||
NESTED_ATTR_NOT_USED;
|
||||
|
||||
reply = wpabuf_alloc((buflen - 1) / 2);
|
||||
if (!reply) {
|
||||
os_free(data);
|
||||
@ -2591,7 +2848,7 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
|
||||
}
|
||||
|
||||
ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len,
|
||||
reply);
|
||||
nested_attr_flag, reply);
|
||||
|
||||
if (ret == 0)
|
||||
ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply),
|
||||
@ -3012,6 +3269,34 @@ static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
int ret, i;
|
||||
char *pos, *end;
|
||||
|
||||
ret = os_snprintf(buf, buflen, "%016llX:\n",
|
||||
(long long unsigned) iface->drv_flags2);
|
||||
if (os_snprintf_error(buflen, ret))
|
||||
return -1;
|
||||
|
||||
pos = buf + ret;
|
||||
end = buf + buflen;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (iface->drv_flags2 & (1LLU << i)) {
|
||||
ret = os_snprintf(pos, end - pos, "%s\n",
|
||||
driver_flag2_to_string(1LLU << i));
|
||||
if (os_snprintf_error(end - pos, ret))
|
||||
return -1;
|
||||
pos += ret;
|
||||
}
|
||||
}
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
|
||||
const char *txtaddr)
|
||||
{
|
||||
@ -3443,6 +3728,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
} else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
|
||||
reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
|
||||
reply_size);
|
||||
} else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) {
|
||||
reply_len = hostapd_ctrl_driver_flags2(hapd->iface, reply,
|
||||
reply_size);
|
||||
} else if (os_strcmp(buf, "TERMINATE") == 0) {
|
||||
eloop_terminate();
|
||||
} else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
|
||||
@ -3551,6 +3839,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp,
|
||||
atoi(buf + 19),
|
||||
reply, reply_size);
|
||||
} else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) {
|
||||
if (dpp_bootstrap_set(hapd->iface->interfaces->dpp,
|
||||
atoi(buf + 18),
|
||||
os_strchr(buf + 18, ' ')) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) {
|
||||
if (hostapd_dpp_auth_init(hapd, buf + 13) < 0)
|
||||
reply_len = -1;
|
||||
@ -3594,6 +3887,21 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||
} else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) {
|
||||
if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0)
|
||||
reply_len = -1;
|
||||
#ifdef CONFIG_DPP2
|
||||
} else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) {
|
||||
if (hostapd_dpp_controller_start(hapd, buf + 20) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) {
|
||||
if (hostapd_dpp_controller_start(hapd, NULL) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
|
||||
dpp_controller_stop(hapd->iface->interfaces->dpp);
|
||||
} else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
|
||||
if (hostapd_dpp_chirp(hapd, buf + 9) < 0)
|
||||
reply_len = -1;
|
||||
} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
|
||||
hostapd_dpp_chirp_stop(hapd);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#endif /* CONFIG_DPP */
|
||||
#ifdef RADIUS_SERVER
|
||||
} else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
|
||||
@ -3642,7 +3950,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
|
||||
int reply_len;
|
||||
int level = MSG_DEBUG;
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
unsigned char lcookie[COOKIE_LEN];
|
||||
unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
|
||||
@ -3667,28 +3975,30 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
if (os_strcmp(buf, "GET_COOKIE") == 0) {
|
||||
os_memcpy(reply, "COOKIE=", 7);
|
||||
wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
|
||||
cookie, COOKIE_LEN);
|
||||
reply_len = 7 + 2 * COOKIE_LEN;
|
||||
wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
|
||||
hapd->ctrl_iface_cookie,
|
||||
CTRL_IFACE_COOKIE_LEN);
|
||||
reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
|
||||
hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
|
||||
hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"CTRL: No cookie in the request - drop request");
|
||||
os_free(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
|
||||
if (os_memcmp(hapd->ctrl_iface_cookie, lcookie,
|
||||
CTRL_IFACE_COOKIE_LEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"CTRL: Invalid cookie in the request - drop request");
|
||||
os_free(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = buf + 7 + 2 * COOKIE_LEN;
|
||||
pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN;
|
||||
while (*pos == ' ')
|
||||
pos++;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
@ -3777,7 +4087,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
|
||||
|
||||
dl_list_init(&hapd->ctrl_dst);
|
||||
hapd->ctrl_sock = -1;
|
||||
os_get_random(cookie, COOKIE_LEN);
|
||||
os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
@ -4091,6 +4401,11 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
#ifdef CONFIG_DPP
|
||||
dpp_test = DPP_TEST_DISABLED;
|
||||
#ifdef CONFIG_DPP2
|
||||
dpp_version_override = 2;
|
||||
#else /* CONFIG_DPP2 */
|
||||
dpp_version_override = 1;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#endif /* CONFIG_DPP */
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
@ -4356,7 +4671,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
|
||||
static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
|
||||
void *sock_ctx)
|
||||
{
|
||||
void *interfaces = eloop_ctx;
|
||||
struct hapd_interfaces *interfaces = eloop_ctx;
|
||||
char buffer[256], *buf = buffer;
|
||||
int res;
|
||||
struct sockaddr_storage from;
|
||||
@ -4365,7 +4680,7 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
|
||||
int reply_len;
|
||||
const int reply_size = 4096;
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
unsigned char lcookie[COOKIE_LEN];
|
||||
unsigned char lcookie[CTRL_IFACE_COOKIE_LEN];
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
|
||||
@ -4394,28 +4709,30 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
if (os_strcmp(buf, "GET_COOKIE") == 0) {
|
||||
os_memcpy(reply, "COOKIE=", 7);
|
||||
wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
|
||||
gcookie, COOKIE_LEN);
|
||||
reply_len = 7 + 2 * COOKIE_LEN;
|
||||
wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1,
|
||||
interfaces->ctrl_iface_cookie,
|
||||
CTRL_IFACE_COOKIE_LEN);
|
||||
reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN;
|
||||
goto send_reply;
|
||||
}
|
||||
|
||||
if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
|
||||
hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
|
||||
hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"CTRL: No cookie in the request - drop request");
|
||||
os_free(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
|
||||
if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie,
|
||||
CTRL_IFACE_COOKIE_LEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"CTRL: Invalid cookie in the request - drop request");
|
||||
os_free(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
buf += 7 + 2 * COOKIE_LEN;
|
||||
buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN;
|
||||
while (*buf == ' ')
|
||||
buf++;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
@ -4559,7 +4876,7 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
|
||||
}
|
||||
}
|
||||
|
||||
os_get_random(gcookie, COOKIE_LEN);
|
||||
os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN);
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
@ -4802,13 +5119,8 @@ static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst,
|
||||
return;
|
||||
idx = 0;
|
||||
if (ifname) {
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
io[idx].iov_base = "IFACE=";
|
||||
io[idx].iov_len = 6;
|
||||
#else /* CONFIG_CTRL_IFACE_UDP */
|
||||
io[idx].iov_base = "IFNAME=";
|
||||
io[idx].iov_len = 7;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
idx++;
|
||||
io[idx].iov_base = (char *) ifname;
|
||||
io[idx].iov_len = os_strlen(ifname);
|
||||
|
@ -148,9 +148,6 @@ CONFIG_IEEE80211R=y
|
||||
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
|
||||
#CONFIG_DRIVER_RADIUS_ACL=y
|
||||
|
||||
# IEEE 802.11n (High Throughput) support
|
||||
CONFIG_IEEE80211N=y
|
||||
|
||||
# Wireless Network Management (IEEE Std 802.11v-2011)
|
||||
# Note: This is experimental and not complete implementation.
|
||||
#CONFIG_WNM=y
|
||||
@ -354,7 +351,7 @@ CONFIG_INTERWORKING=y
|
||||
#CONFIG_ACS=y
|
||||
|
||||
# Multiband Operation support
|
||||
# These extentions facilitate efficient use of multiple frequency bands
|
||||
# These extensions facilitate efficient use of multiple frequency bands
|
||||
# available to the AP and the devices that may associate with it.
|
||||
#CONFIG_MBO=y
|
||||
|
||||
@ -384,6 +381,19 @@ CONFIG_INTERWORKING=y
|
||||
# parameter. See that parameter in hostapd.conf for more details.
|
||||
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
|
||||
|
||||
CONFIG_TESTING_OPTIONS=y
|
||||
# Wired equivalent privacy (WEP)
|
||||
# WEP is an obsolete cryptographic data confidentiality algorithm that is not
|
||||
# considered secure. It should not be used for anything anymore. The
|
||||
# functionality needed to use WEP is available in the current hostapd
|
||||
# release under this optional build parameter. This functionality is subject to
|
||||
# be completely removed in a future release.
|
||||
CONFIG_WEP=y
|
||||
|
||||
CONFIG_SAE=y
|
||||
# Remove all TKIP functionality
|
||||
# TKIP is an old cryptographic data confidentiality algorithm that is not
|
||||
# considered secure. It should not be used anymore. For now, the default hostapd
|
||||
# build includes this to allow mixed mode WPA+WPA2 networks to be enabled, but
|
||||
# that functionality is subject to be removed in the future.
|
||||
#CONFIG_NO_TKIP=y
|
||||
|
||||
CONFIG_TESTING_OPTIONS=y
|
||||
|
@ -210,7 +210,7 @@ channel=1
|
||||
# Frequency list can be provided as range using hyphen ('-') or individual
|
||||
# frequencies can be specified by comma (',') separated values
|
||||
# Default: all frequencies allowed in selected hw_mode
|
||||
#freqlist=2437,5945,5965
|
||||
#freqlist=2437,5955,5975
|
||||
#freqlist=2437,5985-6105
|
||||
|
||||
# Exclude DFS channels from ACS
|
||||
@ -580,6 +580,9 @@ wmm_ac_vo_acm=0
|
||||
# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
|
||||
ieee80211n=1
|
||||
|
||||
# disable_11n: Boolean (0/1) to disable HT for a specific BSS
|
||||
#disable_11n=0
|
||||
|
||||
# ht_capab: HT capabilities (list of flags)
|
||||
# LDPC coding capability: [LDPC] = supported
|
||||
# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
|
||||
@ -598,8 +601,6 @@ ieee80211n=1
|
||||
# channels if needed or creation of 40 MHz channel maybe rejected based
|
||||
# on overlapping BSSes. These changes are done automatically when hostapd
|
||||
# is setting up the 40 MHz channel.
|
||||
# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
|
||||
# (SMPS disabled if neither is set)
|
||||
# HT-greenfield: [GF] (disabled if not set)
|
||||
# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
|
||||
# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
|
||||
@ -634,6 +635,9 @@ ieee80211n=1
|
||||
# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
|
||||
#ieee80211ac=1
|
||||
|
||||
# disable_11ac: Boolean (0/1) to disable VHT for a specific BSS
|
||||
#disable_11ac=0
|
||||
|
||||
# vht_capab: VHT capabilities (list of flags)
|
||||
#
|
||||
# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
|
||||
@ -788,6 +792,9 @@ ieee80211n=1
|
||||
# 1 = enabled
|
||||
#ieee80211ax=1
|
||||
|
||||
# disable_11ax: Boolean (0/1) to disable HE for a specific BSS
|
||||
#disable_11ax=0
|
||||
|
||||
#he_su_beamformer: HE single user beamformer support
|
||||
# 0 = not supported (default)
|
||||
# 1 = supported
|
||||
@ -806,6 +813,9 @@ ieee80211n=1
|
||||
# he_bss_color: BSS color (1-63)
|
||||
#he_bss_color=1
|
||||
|
||||
# he_bss_color_partial: BSS color AID equation
|
||||
#he_bss_color_partial=0
|
||||
|
||||
#he_default_pe_duration: The duration of PE field in an HE PPDU in us
|
||||
# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
|
||||
#he_default_pe_duration=0
|
||||
@ -821,11 +831,11 @@ ieee80211n=1
|
||||
#he_rts_threshold=0
|
||||
|
||||
# HE operating channel information; see matching vht_* parameters for details.
|
||||
# On the 6 GHz band the center freq calculation starts from 5.940 GHz offset.
|
||||
# For example idx=3 would result in 5955 MHz center frequency. In addition,
|
||||
# On the 6 GHz band the center freq calculation starts from 5.950 GHz offset.
|
||||
# For example idx=3 would result in 5965 MHz center frequency. In addition,
|
||||
# he_oper_chwidth is ignored, and the channel width is derived from the
|
||||
# configured operating class or center frequency indexes (see
|
||||
# IEEE P802.11ax/D4.3 Annex E, Table E-4).
|
||||
# IEEE P802.11ax/D6.1 Annex E, Table E-4).
|
||||
#he_oper_chwidth
|
||||
#he_oper_centr_freq_seg0_idx
|
||||
#he_oper_centr_freq_seg1_idx
|
||||
@ -903,6 +913,8 @@ eapol_key_index_workaround=0
|
||||
|
||||
# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
|
||||
# reauthentication).
|
||||
# Note: Reauthentications may enforce a disconnection, check the related
|
||||
# parameter wpa_deny_ptk0_rekey for details.
|
||||
#eap_reauth_period=3600
|
||||
|
||||
# Use PAE group address (01:80:c2:00:00:03) instead of individual target
|
||||
@ -1199,7 +1211,7 @@ eap_server=0
|
||||
# should be unique across all issuing servers. In theory, this is a variable
|
||||
# length field, but due to some existing implementations requiring A-ID to be
|
||||
# 16 octets in length, it is strongly recommended to use that length for the
|
||||
# field to provid interoperability with deployed peer implementations. This
|
||||
# field to provide interoperability with deployed peer implementations. This
|
||||
# field is configured in hex format.
|
||||
#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
|
||||
|
||||
@ -1226,6 +1238,8 @@ eap_server=0
|
||||
# EAP-TEAP authentication type
|
||||
# 0 = inner EAP (default)
|
||||
# 1 = Basic-Password-Auth
|
||||
# 2 = Do not require Phase 2 authentication if client can be authenticated
|
||||
# during Phase 1
|
||||
#eap_teap_auth=0
|
||||
|
||||
# EAP-TEAP authentication behavior when using PAC
|
||||
@ -1507,6 +1521,17 @@ own_ip_addr=127.0.0.1
|
||||
# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
|
||||
wpa=2
|
||||
|
||||
# Extended Key ID support for Individually Addressed frames
|
||||
#
|
||||
# Extended Key ID allows to rekey PTK keys without the impacts the "normal"
|
||||
# PTK rekeying with only a single Key ID 0 has. It can only be used when the
|
||||
# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher.
|
||||
#
|
||||
# 0 = force off, i.e., use only Key ID 0 (default)
|
||||
# 1 = enable and use Extended Key ID support when possible
|
||||
# 2 = identical to 1 but start with Key ID 1 when possible
|
||||
#extended_key_id=0
|
||||
|
||||
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
|
||||
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
|
||||
# (8..63 characters) that will be converted to PSK. This conversion uses SSID
|
||||
@ -1607,8 +1632,26 @@ group_cipher=CCMP
|
||||
|
||||
# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
|
||||
# PTK to mitigate some attacks against TKIP deficiencies.
|
||||
# Warning: PTK rekeying is buggy with many drivers/devices and with such
|
||||
# devices, the only secure method to rekey the PTK without Extended Key ID
|
||||
# support requires a disconnection. Check the related parameter
|
||||
# wpa_deny_ptk0_rekey for details.
|
||||
#wpa_ptk_rekey=600
|
||||
|
||||
# Workaround for PTK rekey issues
|
||||
#
|
||||
# PTK0 rekeys (rekeying the PTK without "Extended Key ID for Individually
|
||||
# Addressed Frames") can degrade the security and stability with some cards.
|
||||
# To avoid such issues hostapd can replace those PTK rekeys (including EAP
|
||||
# reauthentications) with disconnects.
|
||||
#
|
||||
# Available options:
|
||||
# 0 = always rekey when configured/instructed (default)
|
||||
# 1 = only rekey when the local driver is explicitly indicating it can perform
|
||||
# this operation without issues
|
||||
# 2 = never allow PTK0 rekeys
|
||||
#wpa_deny_ptk0_rekey=0
|
||||
|
||||
# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
|
||||
# Handshake are retried per 4-Way Handshake attempt.
|
||||
# (dot11RSNAConfigPairwiseUpdateCount)
|
||||
@ -1677,6 +1720,12 @@ wpa_pairwise_update_count=100
|
||||
# available in deployed devices.
|
||||
#group_mgmt_cipher=AES-128-CMAC
|
||||
|
||||
# Beacon Protection (management frame protection for Beacon frames)
|
||||
# This depends on management frame protection being enabled (ieee80211w != 0).
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#beacon_prot=0
|
||||
|
||||
# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
|
||||
# (maximum time to wait for a SA Query response)
|
||||
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
|
||||
@ -1692,6 +1741,19 @@ wpa_pairwise_update_count=100
|
||||
# Enabling this automatically also enables ieee80211w, if not yet enabled.
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
# 2 = enabled in workaround mode - Allow STA that claims OCV capability to
|
||||
# connect even if the STA doesn't send OCI or negotiate PMF. This
|
||||
# workaround is to improve interoperability with legacy STAs which are
|
||||
# wrongly copying reserved bits of RSN capabilities from the AP's
|
||||
# RSNE into (Re)Association Request frames. When this configuration is
|
||||
# enabled, the AP considers STA is OCV capable only when the STA indicates
|
||||
# MFP capability in (Re)Association Request frames and sends OCI in
|
||||
# EAPOL-Key msg 2/4/FT Reassociation Request frame/FILS (Re)Association
|
||||
# Request frame; otherwise, the AP disables OCV for the current connection
|
||||
# with the STA. Enabling this workaround mode reduced OCV protection to
|
||||
# some extend since it allows misbehavior to go through. As such, this
|
||||
# should be enabled only if interoperability with misbehaving STAs is
|
||||
# needed.
|
||||
#ocv=1
|
||||
|
||||
# disable_pmksa_caching: Disable PMKSA caching
|
||||
@ -1723,7 +1785,7 @@ wpa_pairwise_update_count=100
|
||||
# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
|
||||
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). In
|
||||
# addition, an optional VLAN ID specification can be used to bind the station
|
||||
# to the specified VLAN whenver the specific SAE password entry is used.
|
||||
# to the specified VLAN whenever the specific SAE password entry is used.
|
||||
#
|
||||
# If the peer MAC address is not included or is set to the wildcard address
|
||||
# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
|
||||
@ -1738,7 +1800,8 @@ wpa_pairwise_update_count=100
|
||||
# special meaning of removing all previously added entries.
|
||||
#
|
||||
# sae_password uses the following encoding:
|
||||
#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>][|id=<identifier>]
|
||||
#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>]
|
||||
#[|pk=<m:ECPrivateKey-base64>][|id=<identifier>]
|
||||
# Examples:
|
||||
#sae_password=secret
|
||||
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
|
||||
@ -1867,6 +1930,23 @@ wpa_pairwise_update_count=100
|
||||
# default: 30 TUs (= 30.72 milliseconds)
|
||||
#fils_hlp_wait_time=30
|
||||
|
||||
# Transition Disable indication
|
||||
# The AP can notify authenticated stations to disable transition mode in their
|
||||
# network profiles when the network has completed transition steps, i.e., once
|
||||
# sufficiently large number of APs in the ESS have been updated to support the
|
||||
# more secure alternative. When this indication is used, the stations are
|
||||
# expected to automatically disable transition mode and less secure security
|
||||
# options. This includes use of WEP, TKIP (including use of TKIP as the group
|
||||
# cipher), and connections without PMF.
|
||||
# Bitmap bits:
|
||||
# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only
|
||||
# allow SAE to be used)
|
||||
# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
|
||||
# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
|
||||
# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE)
|
||||
# (default: 0 = do not include Transition Disable KDE)
|
||||
#transition_disable=0x01
|
||||
|
||||
##### IEEE 802.11r configuration ##############################################
|
||||
|
||||
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
|
||||
@ -1910,7 +1990,7 @@ wpa_pairwise_update_count=100
|
||||
# Wildcard entry:
|
||||
# Upon receiving a response from R0KH, it will be added to this list, so
|
||||
# subsequent requests won't be broadcast. If R0KH does not reply, it will be
|
||||
# blacklisted.
|
||||
# temporarily blocked (see rkh_neg_timeout).
|
||||
#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
|
||||
|
||||
# List of R1KHs in the same Mobility Domain
|
||||
@ -1966,7 +2046,7 @@ wpa_pairwise_update_count=100
|
||||
#ft_psk_generate_local=0
|
||||
|
||||
##### Neighbor table ##########################################################
|
||||
# Maximum number of entries kept in AP table (either for neigbor table or for
|
||||
# Maximum number of entries kept in AP table (either for neighbor table or for
|
||||
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
|
||||
# removed when adding a new entry that would make the list grow over this
|
||||
# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
|
||||
@ -2249,6 +2329,17 @@ wpa_pairwise_update_count=100
|
||||
#dpp_csign
|
||||
#dpp_controller
|
||||
|
||||
# Configurator Connectivity indication
|
||||
# 0: no Configurator is currently connected (default)
|
||||
# 1: advertise that a Configurator is available
|
||||
#dpp_configurator_connectivity=0
|
||||
|
||||
# DPP PFS
|
||||
# 0: allow PFS to be used or not used (default)
|
||||
# 1: require PFS to be used (note: not compatible with DPP R1)
|
||||
# 2: do not allow PFS to be used
|
||||
#dpp_pfs=0
|
||||
|
||||
#### TDLS (IEEE 802.11z-2010) #################################################
|
||||
|
||||
# Prohibit use of TDLS in this BSS
|
||||
@ -2644,6 +2735,10 @@ wpa_pairwise_update_count=100
|
||||
# threshold (range: 0..255, default=30).
|
||||
#rssi_reject_assoc_timeout=30
|
||||
|
||||
# Ignore Probe Request frames if RSSI is below given threshold (in dBm)
|
||||
# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
|
||||
#rssi_ignore_probe_request=-75
|
||||
|
||||
##### Fast Session Transfer (FST) support #####################################
|
||||
#
|
||||
# The options in this section are only available when the build configuration
|
||||
|
@ -975,7 +975,7 @@ static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
|
||||
dir = opendir(ctrl_iface_dir);
|
||||
if (dir == NULL) {
|
||||
printf("Control interface directory '%s' could not be "
|
||||
"openned.\n", ctrl_iface_dir);
|
||||
"opened.\n", ctrl_iface_dir);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1227,14 +1227,15 @@ static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
char cmd[256];
|
||||
int res;
|
||||
|
||||
if (argc < 2 || argc > 3) {
|
||||
if (argc < 2 || argc > 4) {
|
||||
printf("Invalid vendor command\n"
|
||||
"usage: <vendor id> <command id> [<hex formatted command argument>]\n");
|
||||
"usage: <vendor id> <command id> [<hex formatted command argument>] [nested=<0|1>]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
|
||||
argc == 3 ? argv[2] : "");
|
||||
res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s%s%s", argv[0],
|
||||
argv[1], argc >= 3 ? argv[2] : "",
|
||||
argc == 4 ? " " : "", argc == 4 ? argv[3] : "");
|
||||
if (os_snprintf_error(sizeof(cmd), res)) {
|
||||
printf("Too long VENDOR command.\n");
|
||||
return -1;
|
||||
@ -1402,6 +1403,13 @@ static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
@ -1464,6 +1472,37 @@ static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
|
||||
return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
|
||||
static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP");
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
|
||||
@ -1650,6 +1689,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"<id> = get DPP bootstrap URI" },
|
||||
{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
|
||||
"<id> = show DPP bootstrap information" },
|
||||
{ "dpp_bootstrap_set", hostapd_cli_cmd_dpp_bootstrap_set, NULL,
|
||||
"<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" },
|
||||
{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
|
||||
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
|
||||
{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
|
||||
@ -1670,6 +1711,16 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"add PKEX code" },
|
||||
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
|
||||
"*|<id> = remove DPP pkex information" },
|
||||
#ifdef CONFIG_DPP2
|
||||
{ "dpp_controller_start", hostapd_cli_cmd_dpp_controller_start, NULL,
|
||||
"[tcp_port=<port>] [role=..] = start DPP controller" },
|
||||
{ "dpp_controller_stop", hostapd_cli_cmd_dpp_controller_stop, NULL,
|
||||
"= stop DPP controller" },
|
||||
{ "dpp_chirp", hostapd_cli_cmd_dpp_chirp, NULL,
|
||||
"own=<BI ID> iter=<count> = start DPP chirp" },
|
||||
{ "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
|
||||
"= stop DPP chirp" },
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#endif /* CONFIG_DPP */
|
||||
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
|
||||
"=Add/Delete/Show/Clear accept MAC ACL" },
|
||||
|
@ -218,7 +218,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
struct wowlan_triggers *triggs;
|
||||
|
||||
iface->drv_flags = capa.flags;
|
||||
iface->smps_modes = capa.smps_modes;
|
||||
iface->drv_flags2 = capa.flags2;
|
||||
iface->probe_resp_offloads = capa.probe_resp_offloads;
|
||||
/*
|
||||
* Use default extended capa values from per-radio information
|
||||
@ -451,11 +451,12 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
|
||||
static void show_version(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"hostapd v" VERSION_STR "\n"
|
||||
"hostapd v%s\n"
|
||||
"User space daemon for IEEE 802.11 AP management,\n"
|
||||
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
|
||||
"Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
|
||||
"and contributors\n");
|
||||
"and contributors\n",
|
||||
VERSION_STR);
|
||||
}
|
||||
|
||||
|
||||
@ -673,7 +674,10 @@ int main(int argc, char *argv[])
|
||||
#endif /* CONFIG_ETH_P_OUI */
|
||||
#ifdef CONFIG_DPP
|
||||
os_memset(&dpp_conf, 0, sizeof(dpp_conf));
|
||||
/* TODO: dpp_conf.msg_ctx? */
|
||||
dpp_conf.cb_ctx = &interfaces;
|
||||
#ifdef CONFIG_DPP2
|
||||
dpp_conf.remove_bi = hostapd_dpp_remove_bi;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
interfaces.dpp = dpp_global_init(&dpp_conf);
|
||||
if (!interfaces.dpp)
|
||||
return -1;
|
||||
@ -902,8 +906,11 @@ int main(int argc, char *argv[])
|
||||
!!(interfaces.iface[i]->drv_flags &
|
||||
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
||||
hostapd_interface_deinit_free(interfaces.iface[i]);
|
||||
interfaces.iface[i] = NULL;
|
||||
}
|
||||
os_free(interfaces.iface);
|
||||
interfaces.iface = NULL;
|
||||
interfaces.count = 0;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
dpp_global_deinit(interfaces.dpp);
|
||||
|
196
hostapd/sae_pk_gen.c
Normal file
196
hostapd/sae_pk_gen.c
Normal 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;
|
||||
}
|
@ -1,28 +1,6 @@
|
||||
all: hs20-osu-client
|
||||
ALL=hs20-osu-client
|
||||
|
||||
ifndef CC
|
||||
CC=gcc
|
||||
endif
|
||||
|
||||
ifndef LDO
|
||||
LDO=$(CC)
|
||||
endif
|
||||
|
||||
ifeq ($(QUIET), 1)
|
||||
Q=@
|
||||
E=true
|
||||
else
|
||||
Q=@
|
||||
E=echo
|
||||
ifeq ($(V), 1)
|
||||
Q=
|
||||
E=true
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
endif
|
||||
include ../../src/build.rules
|
||||
|
||||
CFLAGS += -I../../src/utils
|
||||
CFLAGS += -I../../src/common
|
||||
@ -30,8 +8,17 @@ CFLAGS += -I../../src
|
||||
|
||||
ifndef CONFIG_NO_BROWSER
|
||||
ifndef CONFIG_BROWSER_SYSTEM
|
||||
TEST_WK := $(shell pkg-config --silence-errors --cflags webkitgtk-3.0)
|
||||
ifeq ($(TEST_WK),)
|
||||
# Try webkit2
|
||||
GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0)
|
||||
GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0)
|
||||
CFLAGS += -DUSE_WEBKIT2
|
||||
else
|
||||
GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0)
|
||||
GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0)
|
||||
endif
|
||||
|
||||
CFLAGS += $(GTKCFLAGS)
|
||||
LIBS += $(GTKLIBS)
|
||||
endif
|
||||
@ -84,23 +71,11 @@ CFLAGS += -DEAP_TLS_OPENSSL
|
||||
OBJS += ../../src/crypto/tls_openssl_ocsp.o
|
||||
LIBS += -lssl -lcrypto
|
||||
|
||||
_OBJS_VAR := OBJS
|
||||
include ../../src/objs.mk
|
||||
hs20-osu-client: $(OBJS)
|
||||
$(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS)
|
||||
@$(E) " LD " $@
|
||||
|
||||
%.o: %.c
|
||||
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
|
||||
@$(E) " CC " $<
|
||||
|
||||
clean:
|
||||
rm -f core *~ *.o *.d hs20-osu-client
|
||||
rm -f ../../src/utils/*.o
|
||||
rm -f ../../src/utils/*.d
|
||||
rm -f ../../src/common/*.o
|
||||
rm -f ../../src/common/*.d
|
||||
rm -f ../../src/crypto/*.o
|
||||
rm -f ../../src/crypto/*.d
|
||||
rm -f ../../src/wps/*.o
|
||||
rm -f ../../src/wps/*.d
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
clean: common-clean
|
||||
rm -f core *~
|
||||
|
@ -407,7 +407,7 @@ static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
|
||||
wpa_printf(MSG_INFO, "Data: %s", data);
|
||||
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
|
||||
write_summary(ctx, "Launch browser to URI '%s'", data);
|
||||
res = hs20_web_browser(data);
|
||||
res = hs20_web_browser(data, 1);
|
||||
xml_node_get_text_free(ctx->xml, data);
|
||||
if (res > 0) {
|
||||
wpa_printf(MSG_INFO, "User response in browser completed successfully");
|
||||
|
@ -2233,7 +2233,7 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
|
||||
wpa_ctrl_close(mon);
|
||||
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_INFO, "Could not connect");
|
||||
wpa_printf(MSG_INFO, "Could not connect to OSU network");
|
||||
write_summary(ctx, "Could not connect to OSU network");
|
||||
wpa_printf(MSG_INFO, "Remove OSU network connection");
|
||||
snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
|
||||
@ -2406,7 +2406,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
|
||||
snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
|
||||
write_summary(ctx, "Start web browser with OSU provider selection page");
|
||||
ret = hs20_web_browser(fname);
|
||||
ret = hs20_web_browser(fname, 0);
|
||||
|
||||
selected:
|
||||
if (ret > 0 && (size_t) ret <= osu_count) {
|
||||
@ -2907,7 +2907,7 @@ static char * get_hostname(const char *url)
|
||||
static int osu_cert_cb(void *_ctx, struct http_cert *cert)
|
||||
{
|
||||
struct hs20_osu_client *ctx = _ctx;
|
||||
unsigned int i, j;
|
||||
size_t i, j;
|
||||
int found;
|
||||
char *host = NULL;
|
||||
|
||||
@ -3002,7 +3002,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
|
||||
size_t name_len = os_strlen(name);
|
||||
|
||||
wpa_printf(MSG_INFO,
|
||||
"[%i] Looking for icon file name '%s' match",
|
||||
"[%zu] Looking for icon file name '%s' match",
|
||||
j, name);
|
||||
for (i = 0; i < cert->num_logo; i++) {
|
||||
struct http_logo *logo = &cert->logo[i];
|
||||
@ -3010,7 +3010,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
|
||||
char *pos;
|
||||
|
||||
wpa_printf(MSG_INFO,
|
||||
"[%i] Comparing to '%s' uri_len=%d name_len=%d",
|
||||
"[%zu] Comparing to '%s' uri_len=%d name_len=%d",
|
||||
i, logo->uri, (int) uri_len, (int) name_len);
|
||||
if (uri_len < 1 + name_len) {
|
||||
wpa_printf(MSG_INFO, "URI Length is too short");
|
||||
@ -3044,7 +3044,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
|
||||
|
||||
if (logo->hash_len != 32) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"[%i][%i] Icon hash length invalid (should be 32): %d",
|
||||
"[%zu][%zu] Icon hash length invalid (should be 32): %d",
|
||||
j, i, (int) logo->hash_len);
|
||||
continue;
|
||||
}
|
||||
@ -3054,7 +3054,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"[%u][%u] Icon hash did not match", j, i);
|
||||
"[%zu][%zu] Icon hash did not match", j, i);
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
|
||||
logo->hash, 32);
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
|
||||
@ -3152,7 +3152,7 @@ static void check_workarounds(struct hs20_osu_client *ctx)
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n"
|
||||
printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n"
|
||||
" [-w<wpa_supplicant ctrl_iface dir>] "
|
||||
"[-r<result file>] [-f<debug file>] \\\n"
|
||||
" [-s<summary file>] \\\n"
|
||||
@ -3198,7 +3198,7 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
|
||||
c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
@ -3236,6 +3236,9 @@ int main(int argc, char *argv[])
|
||||
case 't':
|
||||
wpa_debug_timestamp++;
|
||||
break;
|
||||
case 'T':
|
||||
ctx.ignore_tls = 1;
|
||||
break;
|
||||
case 'w':
|
||||
wpas_ctrl_path = optarg;
|
||||
break;
|
||||
@ -3403,7 +3406,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
wpa_printf(MSG_INFO, "Launch web browser to URL %s",
|
||||
argv[optind + 1]);
|
||||
ret = hs20_web_browser(argv[optind + 1]);
|
||||
ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls);
|
||||
wpa_printf(MSG_INFO, "Web browser result: %d", ret);
|
||||
} else if (strcmp(argv[optind], "parse_cert") == 0) {
|
||||
if (argc - optind < 2) {
|
||||
|
@ -50,6 +50,8 @@ struct hs20_osu_client {
|
||||
const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
|
||||
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
|
||||
unsigned long int workarounds;
|
||||
int ignore_tls; /* whether to ignore TLS validation issues with HTTPS
|
||||
* server certificate */
|
||||
};
|
||||
|
||||
|
||||
|
@ -547,7 +547,7 @@ static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
|
||||
}
|
||||
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
|
||||
write_summary(ctx, "Launch browser to URI '%s'", uri);
|
||||
res = hs20_web_browser(uri);
|
||||
res = hs20_web_browser(uri, 1);
|
||||
xml_node_get_text_free(ctx->xml, uri);
|
||||
if (res > 0) {
|
||||
wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
|
||||
|
1
hs20/server/.gitignore
vendored
Normal file
1
hs20/server/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
hs20_spp_server
|
@ -1,16 +1,6 @@
|
||||
all: hs20_spp_server
|
||||
ALL=hs20_spp_server
|
||||
|
||||
ifndef CC
|
||||
CC=gcc
|
||||
endif
|
||||
|
||||
ifndef LDO
|
||||
LDO=$(CC)
|
||||
endif
|
||||
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
endif
|
||||
include ../../src/build.rules
|
||||
|
||||
CFLAGS += -I../../src
|
||||
CFLAGS += -I../../src/utils
|
||||
@ -43,14 +33,10 @@ CFLAGS += $(shell xml2-config --cflags)
|
||||
LIBS += $(shell xml2-config --libs)
|
||||
OBJS += ../../src/utils/xml_libxml2.o
|
||||
|
||||
_OBJS_VAR := OBJS
|
||||
include ../../src/objs.mk
|
||||
hs20_spp_server: $(OBJS)
|
||||
$(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f core *~ *.o *.d hs20_spp_server
|
||||
rm -f ../../src/utils/*.o
|
||||
rm -f ../../src/utils/*.d
|
||||
rm -f ../../src/crypto/*.o
|
||||
rm -f ../../src/crypto/*.d
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
clean: common-clean
|
||||
rm -f core *~
|
||||
|
@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text
|
||||
openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err
|
||||
|
@ -1,5 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
|
||||
openssl ocsp \
|
||||
-no_nonce \
|
||||
-CAfile ca.pem \
|
||||
|
@ -176,7 +176,7 @@ int main(int argc, char *argv[])
|
||||
ctx.root_dir = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
printf("hs20_spp_server v" VERSION_STR "\n");
|
||||
printf("hs20_spp_server v%s\n", VERSION_STR);
|
||||
return 0;
|
||||
default:
|
||||
usage();
|
||||
|
@ -1,18 +1,6 @@
|
||||
ALL=radius_example
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
ifndef CC
|
||||
CC=gcc
|
||||
endif
|
||||
|
||||
ifndef LDO
|
||||
LDO=$(CC)
|
||||
endif
|
||||
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
endif
|
||||
include ../src/build.rules
|
||||
|
||||
CFLAGS += -I.
|
||||
CFLAGS += -I../src
|
||||
@ -23,24 +11,18 @@ LIBS += ../src/crypto/libcrypto.a
|
||||
LIBS += ../src/utils/libutils.a
|
||||
LLIBS = -lrt
|
||||
|
||||
../src/utils/libutils.a:
|
||||
$(MAKE) -C ../src/utils
|
||||
|
||||
../src/crypto/libcrypto.a:
|
||||
$(MAKE) -C ../src/crypto
|
||||
|
||||
../src/radius/libradius.a:
|
||||
$(MAKE) -C ../src/radius
|
||||
|
||||
#CLAGS += -DCONFIG_IPV6
|
||||
|
||||
OBJS_ex = radius_example.o
|
||||
|
||||
_OBJS_VAR := OBJS_ex
|
||||
include ../src/objs.mk
|
||||
|
||||
_OBJS_VAR := LIBS
|
||||
include ../src/objs.mk
|
||||
|
||||
radius_example: $(OBJS_ex) $(LIBS)
|
||||
$(LDO) $(LDFLAGS) -o radius_example $(OBJS_ex) $(LIBS) $(LLIBS)
|
||||
|
||||
clean:
|
||||
$(MAKE) -C ../src clean
|
||||
rm -f core *~ *.o *.d $(ALL)
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
clean: common-clean
|
||||
rm -f core *~ *.o *.d
|
||||
|
@ -5,8 +5,8 @@ all:
|
||||
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
|
||||
|
||||
clean:
|
||||
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
|
||||
rm -f *~
|
||||
$(Q)for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
|
||||
$(Q)rm -f *~
|
||||
|
||||
install:
|
||||
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done
|
||||
|
@ -1,13 +1,3 @@
|
||||
all: libap.a
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o *.d *.gcno *.gcda *.gcov libap.a
|
||||
|
||||
install:
|
||||
@echo Nothing to be made.
|
||||
|
||||
include ../lib.rules
|
||||
|
||||
CFLAGS += -DHOSTAPD
|
||||
CFLAGS += -DNEED_AP_MLME
|
||||
CFLAGS += -DCONFIG_ETH_P_OUI
|
||||
@ -67,7 +57,4 @@ LIB_OBJS= \
|
||||
wps_hostapd.o \
|
||||
x_snoop.o
|
||||
|
||||
libap.a: $(LIB_OBJS)
|
||||
$(AR) crT $@ $?
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
include ../lib.rules
|
||||
|
300
src/ap/acs.c
300
src/ap/acs.c
@ -261,13 +261,13 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
|
||||
}
|
||||
|
||||
|
||||
void acs_cleanup(struct hostapd_iface *iface)
|
||||
static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
chan = &mode->channels[i];
|
||||
|
||||
if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
|
||||
acs_clean_chan_surveys(chan);
|
||||
@ -276,6 +276,15 @@ void acs_cleanup(struct hostapd_iface *iface)
|
||||
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
|
||||
chan->min_nf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void acs_cleanup(struct hostapd_iface *iface)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < iface->num_hw_features; i++)
|
||||
acs_cleanup_mode(&iface->hw_features[i]);
|
||||
|
||||
iface->chans_surveyed = 0;
|
||||
iface->acs_num_completed_scans = 0;
|
||||
@ -453,21 +462,35 @@ static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
|
||||
}
|
||||
|
||||
|
||||
static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
|
||||
static int acs_surveys_are_sufficient_mode(struct hostapd_hw_modes *mode)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_channel_data *chan;
|
||||
int valid = 0;
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
chan = &mode->channels[i];
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
acs_survey_list_is_sufficient(chan))
|
||||
valid++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We need at least survey data for one channel */
|
||||
return !!valid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_hw_modes *mode;
|
||||
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
mode = &iface->hw_features[i];
|
||||
if (!hostapd_hw_skip_mode(iface, mode) &&
|
||||
acs_surveys_are_sufficient_mode(mode))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -489,14 +512,25 @@ static int is_in_chanlist(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
static void acs_survey_all_chans_intereference_factor(
|
||||
struct hostapd_iface *iface)
|
||||
static int is_in_freqlist(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data *chan)
|
||||
{
|
||||
if (!iface->conf->acs_freq_list.num)
|
||||
return 1;
|
||||
|
||||
return freq_range_list_includes(&iface->conf->acs_freq_list,
|
||||
chan->freq);
|
||||
}
|
||||
|
||||
|
||||
static void acs_survey_mode_interference_factor(
|
||||
struct hostapd_iface *iface, struct hostapd_hw_modes *mode)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
chan = &mode->channels[i];
|
||||
|
||||
if (!acs_usable_chan(chan))
|
||||
continue;
|
||||
@ -504,6 +538,9 @@ static void acs_survey_all_chans_intereference_factor(
|
||||
if (!is_in_chanlist(iface, chan))
|
||||
continue;
|
||||
|
||||
if (!is_in_freqlist(iface, chan))
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
|
||||
chan->chan, chan->freq);
|
||||
|
||||
@ -515,14 +552,28 @@ static void acs_survey_all_chans_intereference_factor(
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
|
||||
int freq)
|
||||
static void acs_survey_all_chans_interference_factor(
|
||||
struct hostapd_iface *iface)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_hw_modes *mode;
|
||||
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
mode = &iface->hw_features[i];
|
||||
if (!hostapd_hw_skip_mode(iface, mode))
|
||||
acs_survey_mode_interference_factor(iface, mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_channel_data *
|
||||
acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq)
|
||||
{
|
||||
struct hostapd_channel_data *chan;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
chan = &mode->channels[i];
|
||||
|
||||
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
continue;
|
||||
@ -535,6 +586,26 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_channel_data *
|
||||
acs_find_chan(struct hostapd_iface *iface, int freq)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_hw_modes *mode;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
mode = &iface->hw_features[i];
|
||||
if (!hostapd_hw_skip_mode(iface, mode)) {
|
||||
chan = acs_find_chan_mode(mode, freq);
|
||||
if (chan)
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int is_24ghz_mode(enum hostapd_hw_mode mode)
|
||||
{
|
||||
return mode == HOSTAPD_MODE_IEEE80211B ||
|
||||
@ -565,58 +636,24 @@ static int is_common_24ghz_chan(int chan)
|
||||
#define ACS_24GHZ_PREFER_1_6_11 0.8
|
||||
#endif /* ACS_24GHZ_PREFER_1_6_11 */
|
||||
|
||||
/*
|
||||
* At this point it's assumed chan->interface_factor has been computed.
|
||||
* This function should be reusable regardless of interference computation
|
||||
* option (survey, BSS, spectral, ...). chan->interference factor must be
|
||||
* summable (i.e., must be always greater than zero).
|
||||
*/
|
||||
static struct hostapd_channel_data *
|
||||
acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
static void
|
||||
acs_find_ideal_chan_mode(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode,
|
||||
int n_chans, u32 bw,
|
||||
struct hostapd_channel_data **rand_chan,
|
||||
struct hostapd_channel_data **ideal_chan,
|
||||
long double *ideal_factor)
|
||||
{
|
||||
struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
|
||||
*rand_chan = NULL;
|
||||
long double factor, ideal_factor = 0;
|
||||
struct hostapd_channel_data *chan, *adj_chan = NULL;
|
||||
long double factor;
|
||||
int i, j;
|
||||
int n_chans = 1;
|
||||
u32 bw;
|
||||
unsigned int k;
|
||||
|
||||
/* TODO: HT40- support */
|
||||
|
||||
if (iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel == -1) {
|
||||
wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel)
|
||||
n_chans = 2;
|
||||
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_80MHZ:
|
||||
n_chans = 4;
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
n_chans = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bw = num_chan_to_bw(n_chans);
|
||||
|
||||
/* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Survey analysis for selected bandwidth %d MHz", bw);
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
double total_weight;
|
||||
struct acs_bias *bias, tmp_bias;
|
||||
|
||||
chan = &iface->current_mode->channels[i];
|
||||
chan = &mode->channels[i];
|
||||
|
||||
/* Since in the current ACS implementation the first channel is
|
||||
* always a primary channel, skip channels not available as
|
||||
@ -628,6 +665,9 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
if (!is_in_chanlist(iface, chan))
|
||||
continue;
|
||||
|
||||
if (!is_in_freqlist(iface, chan))
|
||||
continue;
|
||||
|
||||
if (!chan_bw_allowed(chan, bw, 1, 1)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Channel %d: BW %u is not supported",
|
||||
@ -637,7 +677,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
|
||||
/* HT40 on 5 GHz has a limited set of primary channels as per
|
||||
* 11n Annex J */
|
||||
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel &&
|
||||
!acs_usable_ht40_chan(chan)) {
|
||||
@ -646,7 +686,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
|
||||
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
|
||||
if (hostapd_get_oper_chwidth(iface->conf) ==
|
||||
CHANWIDTH_80MHZ &&
|
||||
@ -698,7 +738,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
|
||||
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
|
||||
* channel interference factor. */
|
||||
if (is_24ghz_mode(iface->current_mode->mode)) {
|
||||
if (is_24ghz_mode(mode->mode)) {
|
||||
for (j = 0; j < n_chans; j++) {
|
||||
adj_chan = acs_find_chan(iface, chan->freq +
|
||||
(j * 20) - 5);
|
||||
@ -744,7 +784,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
break;
|
||||
bias = NULL;
|
||||
}
|
||||
} else if (is_24ghz_mode(iface->current_mode->mode) &&
|
||||
} else if (is_24ghz_mode(mode->mode) &&
|
||||
is_common_24ghz_chan(chan->chan)) {
|
||||
tmp_bias.channel = chan->chan;
|
||||
tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
|
||||
@ -763,14 +803,71 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
if (acs_usable_chan(chan) &&
|
||||
(!ideal_chan || factor < ideal_factor)) {
|
||||
ideal_factor = factor;
|
||||
ideal_chan = chan;
|
||||
(!*ideal_chan || factor < *ideal_factor)) {
|
||||
*ideal_factor = factor;
|
||||
*ideal_chan = chan;
|
||||
}
|
||||
|
||||
/* This channel would at least be usable */
|
||||
if (!rand_chan)
|
||||
rand_chan = chan;
|
||||
if (!(*rand_chan))
|
||||
*rand_chan = chan;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* At this point it's assumed chan->interference_factor has been computed.
|
||||
* This function should be reusable regardless of interference computation
|
||||
* option (survey, BSS, spectral, ...). chan->interference factor must be
|
||||
* summable (i.e., must be always greater than zero).
|
||||
*/
|
||||
static struct hostapd_channel_data *
|
||||
acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_channel_data *ideal_chan = NULL,
|
||||
*rand_chan = NULL;
|
||||
long double ideal_factor = 0;
|
||||
int i;
|
||||
int n_chans = 1;
|
||||
u32 bw;
|
||||
struct hostapd_hw_modes *mode;
|
||||
|
||||
/* TODO: HT40- support */
|
||||
|
||||
if (iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel == -1) {
|
||||
wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel)
|
||||
n_chans = 2;
|
||||
|
||||
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
|
||||
switch (hostapd_get_oper_chwidth(iface->conf)) {
|
||||
case CHANWIDTH_80MHZ:
|
||||
n_chans = 4;
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
n_chans = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bw = num_chan_to_bw(n_chans);
|
||||
|
||||
/* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ACS: Survey analysis for selected bandwidth %d MHz", bw);
|
||||
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
mode = &iface->hw_features[i];
|
||||
if (!hostapd_hw_skip_mode(iface, mode))
|
||||
acs_find_ideal_chan_mode(iface, mode, n_chans, bw,
|
||||
&rand_chan, &ideal_chan,
|
||||
&ideal_factor);
|
||||
}
|
||||
|
||||
if (ideal_chan) {
|
||||
@ -826,7 +923,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface)
|
||||
return -1;
|
||||
}
|
||||
|
||||
acs_survey_all_chans_intereference_factor(iface);
|
||||
acs_survey_all_chans_interference_factor(iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -918,29 +1015,59 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
static int acs_request_scan(struct hostapd_iface *iface)
|
||||
static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode,
|
||||
int *freq)
|
||||
{
|
||||
struct wpa_driver_scan_params params;
|
||||
struct hostapd_channel_data *chan;
|
||||
int i, *freq;
|
||||
int i;
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
params.freqs = os_calloc(iface->current_mode->num_channels + 1,
|
||||
sizeof(params.freqs[0]));
|
||||
if (params.freqs == NULL)
|
||||
return -1;
|
||||
|
||||
freq = params.freqs;
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
chan = &mode->channels[i];
|
||||
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
continue;
|
||||
|
||||
if (!is_in_chanlist(iface, chan))
|
||||
continue;
|
||||
|
||||
if (!is_in_freqlist(iface, chan))
|
||||
continue;
|
||||
|
||||
*freq++ = chan->freq;
|
||||
}
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
|
||||
static int acs_request_scan(struct hostapd_iface *iface)
|
||||
{
|
||||
struct wpa_driver_scan_params params;
|
||||
int i, *freq;
|
||||
int num_channels;
|
||||
struct hostapd_hw_modes *mode;
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
|
||||
num_channels = 0;
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
mode = &iface->hw_features[i];
|
||||
if (!hostapd_hw_skip_mode(iface, mode))
|
||||
num_channels += mode->num_channels;
|
||||
}
|
||||
|
||||
params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0]));
|
||||
if (params.freqs == NULL)
|
||||
return -1;
|
||||
|
||||
freq = params.freqs;
|
||||
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
mode = &iface->hw_features[i];
|
||||
if (!hostapd_hw_skip_mode(iface, mode))
|
||||
freq = acs_request_scan_add_freqs(iface, mode, freq);
|
||||
}
|
||||
|
||||
*freq = 0;
|
||||
|
||||
if (params.freqs == freq) {
|
||||
@ -978,7 +1105,8 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
|
||||
return HOSTAPD_CHAN_ACS;
|
||||
}
|
||||
|
||||
if (!iface->current_mode)
|
||||
if (!iface->current_mode &&
|
||||
iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
|
||||
acs_cleanup(iface);
|
||||
|
@ -134,8 +134,8 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
|
||||
unsigned int num_sta_min = 0, num_sta_prod = 1, num_sta_sum = 0,
|
||||
wt_sum = 0;
|
||||
unsigned int quantum;
|
||||
Boolean all_div_min = TRUE;
|
||||
Boolean apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC;
|
||||
bool all_div_min = true;
|
||||
bool apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC;
|
||||
int wt, num_bss = 0, max_wt = 0;
|
||||
size_t i;
|
||||
|
||||
@ -169,7 +169,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
|
||||
* integers. */
|
||||
if (bss->num_backlogged_sta &&
|
||||
bss->num_backlogged_sta % num_sta_min > 0)
|
||||
all_div_min = FALSE;
|
||||
all_div_min = false;
|
||||
|
||||
/* If we're in LIMIT mode, we only apply the weight
|
||||
* scaling when the BSS(es) marked as limited would a
|
||||
@ -178,7 +178,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
|
||||
if (!apply_limit && bss->conf->airtime_limit) {
|
||||
if (bss->num_backlogged_sta * wt_sum >
|
||||
bss->conf->airtime_weight * num_sta_sum)
|
||||
apply_limit = TRUE;
|
||||
apply_limit = true;
|
||||
}
|
||||
}
|
||||
if (all_div_min)
|
||||
|
@ -54,23 +54,33 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
bss->logger_syslog = (unsigned int) -1;
|
||||
bss->logger_stdout = (unsigned int) -1;
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
|
||||
|
||||
bss->wep_rekeying_period = 300;
|
||||
/* use key0 in individual key and key1 in broadcast key */
|
||||
bss->broadcast_key_idx_min = 1;
|
||||
bss->broadcast_key_idx_max = 2;
|
||||
#else /* CONFIG_WEP */
|
||||
bss->auth_algs = WPA_AUTH_ALG_OPEN;
|
||||
#endif /* CONFIG_WEP */
|
||||
bss->eap_reauth_period = 3600;
|
||||
|
||||
bss->wpa_group_rekey = 600;
|
||||
bss->wpa_gmk_rekey = 86400;
|
||||
bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
|
||||
bss->wpa_group_update_count = 4;
|
||||
bss->wpa_pairwise_update_count = 4;
|
||||
bss->wpa_disable_eapol_key_retries =
|
||||
DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
|
||||
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
|
||||
#ifdef CONFIG_NO_TKIP
|
||||
bss->wpa_pairwise = WPA_CIPHER_CCMP;
|
||||
bss->wpa_group = WPA_CIPHER_CCMP;
|
||||
#else /* CONFIG_NO_TKIP */
|
||||
bss->wpa_pairwise = WPA_CIPHER_TKIP;
|
||||
bss->wpa_group = WPA_CIPHER_TKIP;
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
bss->rsn_pairwise = 0;
|
||||
|
||||
bss->max_num_sta = MAX_STA_COUNT;
|
||||
@ -150,6 +160,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
|
||||
/* Default to strict CRL checking. */
|
||||
bss->check_crl_strict = 1;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
bss->sae_commit_status = -1;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
}
|
||||
|
||||
|
||||
@ -251,6 +265,9 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
HE_OPERATION_RTS_THRESHOLD_OFFSET;
|
||||
/* Set default basic MCS/NSS set to single stream MCS 0-7 */
|
||||
conf->he_op.he_basic_mcs_nss_set = 0xfffc;
|
||||
conf->he_op.he_bss_color_disabled = 1;
|
||||
conf->he_op.he_bss_color_partial = 0;
|
||||
conf->he_op.he_bss_color = 1;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/* The third octet of the country string uses an ASCII space character
|
||||
@ -448,7 +465,8 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
|
||||
struct hostapd_ssid *ssid = &conf->ssid;
|
||||
struct sae_password_entry *pw;
|
||||
|
||||
if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf)) ||
|
||||
if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
|
||||
!hostapd_sae_pk_in_use(conf)) ||
|
||||
conf->sae_pwe == 3 ||
|
||||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt))
|
||||
return 0; /* PT not needed */
|
||||
@ -632,6 +650,7 @@ void hostapd_config_free_eap_users(struct hostapd_eap_user *user)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
|
||||
{
|
||||
int i;
|
||||
@ -640,6 +659,7 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
|
||||
keys->key[i] = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
|
||||
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
|
||||
@ -696,6 +716,9 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
|
||||
#ifdef CONFIG_SAE
|
||||
sae_deinit_pt(tmp->pt);
|
||||
#endif /* CONFIG_SAE */
|
||||
#ifdef CONFIG_SAE_PK
|
||||
sae_deinit_pk(tmp->pk);
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
os_free(tmp);
|
||||
}
|
||||
}
|
||||
@ -728,7 +751,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
|
||||
str_clear_free(conf->ssid.wpa_passphrase);
|
||||
os_free(conf->ssid.wpa_psk_file);
|
||||
#ifdef CONFIG_WEP
|
||||
hostapd_config_free_wep(&conf->ssid.wep);
|
||||
#endif /* CONFIG_WEP */
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
os_free(conf->ssid.vlan_tagged_interface);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
@ -890,7 +915,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
wpabuf_free(conf->own_ie_override);
|
||||
wpabuf_free(conf->sae_commit_override);
|
||||
wpabuf_free(conf->rsne_override_eapol);
|
||||
wpabuf_free(conf->rsnxe_override_eapol);
|
||||
wpabuf_free(conf->rsne_override_ft);
|
||||
wpabuf_free(conf->rsnxe_override_ft);
|
||||
wpabuf_free(conf->gtk_rsc_override);
|
||||
wpabuf_free(conf->igtk_rsc_override);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
@ -1091,6 +1119,37 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
static bool hostapd_sae_pk_password_without_pk(struct hostapd_bss_config *bss)
|
||||
{
|
||||
struct sae_password_entry *pw;
|
||||
bool res = false;
|
||||
|
||||
if (bss->ssid.wpa_passphrase &&
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
!bss->sae_pk_password_check_skip &&
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
sae_pk_valid_password(bss->ssid.wpa_passphrase))
|
||||
res = true;
|
||||
|
||||
for (pw = bss->sae_passwords; pw; pw = pw->next) {
|
||||
if (!pw->pk &&
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
!bss->sae_pk_password_check_skip &&
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
sae_pk_valid_password(pw->password))
|
||||
return true;
|
||||
|
||||
if (bss->ssid.wpa_passphrase && res && pw->pk &&
|
||||
os_strcmp(bss->ssid.wpa_passphrase, pw->password) == 0)
|
||||
res = false;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
|
||||
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
struct hostapd_config *conf,
|
||||
int full_config)
|
||||
@ -1102,6 +1161,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
if (bss->wpa) {
|
||||
int wep, i;
|
||||
|
||||
@ -1119,6 +1179,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
if (full_config && bss->wpa &&
|
||||
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
|
||||
@ -1166,47 +1227,49 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if (full_config && conf->ieee80211n &&
|
||||
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
|
||||
bss->disable_11n = 1;
|
||||
bss->disable_11n = true;
|
||||
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
|
||||
"allowed, disabling HT capabilities");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
if (full_config && conf->ieee80211n &&
|
||||
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
|
||||
bss->disable_11n = 1;
|
||||
bss->disable_11n = true;
|
||||
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
|
||||
"allowed, disabling HT capabilities");
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
if (full_config && conf->ieee80211n && bss->wpa &&
|
||||
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
|
||||
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
|
||||
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
|
||||
{
|
||||
bss->disable_11n = 1;
|
||||
bss->disable_11n = true;
|
||||
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
|
||||
"requires CCMP/GCMP to be enabled, disabling HT "
|
||||
"capabilities");
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
#ifdef CONFIG_WEP
|
||||
if (full_config && conf->ieee80211ac &&
|
||||
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
|
||||
bss->disable_11ac = 1;
|
||||
bss->disable_11ac = true;
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
if (full_config && conf->ieee80211ac && bss->wpa &&
|
||||
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
|
||||
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
|
||||
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
|
||||
{
|
||||
bss->disable_11ac = 1;
|
||||
bss->disable_11ac = true;
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
|
||||
}
|
||||
@ -1219,12 +1282,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
bss->wps_state = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
if (full_config && bss->wps_state &&
|
||||
bss->ssid.wep.keys_set && bss->wpa == 0) {
|
||||
wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
|
||||
"disabled");
|
||||
bss->wps_state = 0;
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
if (full_config && bss->wps_state && bss->wpa &&
|
||||
(!(bss->wpa & 2) ||
|
||||
@ -1268,6 +1333,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (full_config && hostapd_sae_pk_in_use(bss) &&
|
||||
hostapd_sae_pk_password_without_pk(bss)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"SAE-PK: SAE password uses SAE-PK style, but does not have PK configured");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1348,11 +1422,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
|
||||
void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
int full_config)
|
||||
{
|
||||
#ifdef CONFIG_WEP
|
||||
if (bss->individual_wep_key_len == 0) {
|
||||
/* individual keys are not use; can use key idx0 for
|
||||
* broadcast keys */
|
||||
bss->broadcast_key_idx_min = 0;
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
|
||||
bss->rsn_pairwise = bss->wpa_pairwise;
|
||||
@ -1378,6 +1454,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
} else if (bss->ieee802_1x) {
|
||||
int cipher = WPA_CIPHER_NONE;
|
||||
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
|
||||
#ifdef CONFIG_WEP
|
||||
bss->ssid.wep.default_len = bss->default_wep_key_len;
|
||||
if (full_config && bss->default_wep_key_len) {
|
||||
cipher = bss->default_wep_key_len >= 13 ?
|
||||
@ -1388,11 +1465,13 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
else
|
||||
cipher = WPA_CIPHER_WEP40;
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
bss->wpa_group = cipher;
|
||||
bss->wpa_pairwise = cipher;
|
||||
bss->rsn_pairwise = cipher;
|
||||
if (full_config)
|
||||
bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
|
||||
#ifdef CONFIG_WEP
|
||||
} else if (bss->ssid.wep.keys_set) {
|
||||
int cipher = WPA_CIPHER_WEP40;
|
||||
if (bss->ssid.wep.len[0] >= 13)
|
||||
@ -1403,6 +1482,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
bss->rsn_pairwise = cipher;
|
||||
if (full_config)
|
||||
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
|
||||
#endif /* CONFIG_WEP */
|
||||
} else if (bss->osen) {
|
||||
bss->ssid.security_policy = SECURITY_OSEN;
|
||||
bss->wpa_group = WPA_CIPHER_CCMP;
|
||||
@ -1441,3 +1521,38 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
|
||||
return 2;
|
||||
return with_id;
|
||||
}
|
||||
|
||||
|
||||
bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf)
|
||||
{
|
||||
#ifdef CONFIG_SAE_PK
|
||||
struct sae_password_entry *pw;
|
||||
|
||||
for (pw = conf->sae_passwords; pw; pw = pw->next) {
|
||||
if (pw->pk)
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
|
||||
{
|
||||
bool with_pk = false;
|
||||
struct sae_password_entry *pw;
|
||||
|
||||
if (conf->ssid.wpa_passphrase)
|
||||
return false;
|
||||
|
||||
for (pw = conf->sae_passwords; pw; pw = pw->next) {
|
||||
if (!pw->pk)
|
||||
return false;
|
||||
with_pk = true;
|
||||
}
|
||||
|
||||
return with_pk;
|
||||
}
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
@ -67,6 +67,7 @@ struct hostapd_radius_servers;
|
||||
struct ft_remote_r0kh;
|
||||
struct ft_remote_r1kh;
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
#define NUM_WEP_KEYS 4
|
||||
struct hostapd_wep_keys {
|
||||
u8 idx;
|
||||
@ -75,10 +76,13 @@ struct hostapd_wep_keys {
|
||||
int keys_set;
|
||||
size_t default_len; /* key length used for dynamic key generation */
|
||||
};
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
typedef enum hostap_security_policy {
|
||||
SECURITY_PLAINTEXT = 0,
|
||||
#ifdef CONFIG_WEP
|
||||
SECURITY_STATIC_WEP = 1,
|
||||
#endif /* CONFIG_WEP */
|
||||
SECURITY_IEEE_802_1X = 2,
|
||||
SECURITY_WPA_PSK = 3,
|
||||
SECURITY_WPA = 4,
|
||||
@ -102,7 +106,9 @@ struct hostapd_ssid {
|
||||
char *wpa_psk_file;
|
||||
struct sae_pt *pt;
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
struct hostapd_wep_keys wep;
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
#define DYNAMIC_VLAN_DISABLED 0
|
||||
#define DYNAMIC_VLAN_OPTIONAL 1
|
||||
@ -191,15 +197,6 @@ struct hostapd_radius_attr {
|
||||
|
||||
|
||||
#define NUM_TX_QUEUES 4
|
||||
|
||||
struct hostapd_tx_queue_params {
|
||||
int aifs;
|
||||
int cwmin;
|
||||
int cwmax;
|
||||
int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
|
||||
};
|
||||
|
||||
|
||||
#define MAX_ROAMING_CONSORTIUM_LEN 15
|
||||
|
||||
struct hostapd_roaming_consortium {
|
||||
@ -255,6 +252,7 @@ struct sae_password_entry {
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
int vlan_id;
|
||||
struct sae_pt *pt;
|
||||
struct sae_pk *pk;
|
||||
};
|
||||
|
||||
struct dpp_controller_conf {
|
||||
@ -321,10 +319,12 @@ struct hostapd_bss_config {
|
||||
size_t eap_req_id_text_len;
|
||||
int eapol_key_index_workaround;
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
size_t default_wep_key_len;
|
||||
int individual_wep_key_len;
|
||||
int wep_rekeying_period;
|
||||
int broadcast_key_idx_min, broadcast_key_idx_max;
|
||||
#endif /* CONFIG_WEP */
|
||||
int eap_reauth_period;
|
||||
int erp_send_reauth_start;
|
||||
char *erp_domain;
|
||||
@ -346,9 +346,11 @@ struct hostapd_bss_config {
|
||||
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
|
||||
|
||||
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
|
||||
int extended_key_id;
|
||||
int wpa_key_mgmt;
|
||||
enum mfp_options ieee80211w;
|
||||
int group_mgmt_cipher;
|
||||
int beacon_prot;
|
||||
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
|
||||
unsigned int assoc_sa_query_max_timeout;
|
||||
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
|
||||
@ -369,6 +371,7 @@ struct hostapd_bss_config {
|
||||
int wpa_strict_rekey;
|
||||
int wpa_gmk_rekey;
|
||||
int wpa_ptk_rekey;
|
||||
enum ptk0_rekey_handling wpa_deny_ptk0_rekey;
|
||||
u32 wpa_group_update_count;
|
||||
u32 wpa_pairwise_update_count;
|
||||
int wpa_disable_eapol_key_retries;
|
||||
@ -528,8 +531,9 @@ struct hostapd_bss_config {
|
||||
#define TDLS_PROHIBIT BIT(0)
|
||||
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
|
||||
int tdls;
|
||||
int disable_11n;
|
||||
int disable_11ac;
|
||||
bool disable_11n;
|
||||
bool disable_11ac;
|
||||
bool disable_11ax;
|
||||
|
||||
/* IEEE 802.11v */
|
||||
int time_advertisement;
|
||||
@ -666,10 +670,26 @@ struct hostapd_bss_config {
|
||||
u8 bss_load_test_set;
|
||||
struct wpabuf *own_ie_override;
|
||||
int sae_reflection_attack;
|
||||
int sae_commit_status;
|
||||
int sae_pk_omit;
|
||||
int sae_pk_password_check_skip;
|
||||
struct wpabuf *sae_commit_override;
|
||||
struct wpabuf *rsne_override_eapol;
|
||||
struct wpabuf *rsnxe_override_eapol;
|
||||
struct wpabuf *rsne_override_ft;
|
||||
struct wpabuf *rsnxe_override_ft;
|
||||
struct wpabuf *gtk_rsc_override;
|
||||
struct wpabuf *igtk_rsc_override;
|
||||
int no_beacon_rsnxe;
|
||||
int skip_prune_assoc;
|
||||
int ft_rsnxe_used;
|
||||
unsigned int oci_freq_override_eapol_m3;
|
||||
unsigned int oci_freq_override_eapol_g1;
|
||||
unsigned int oci_freq_override_saquery_req;
|
||||
unsigned int oci_freq_override_saquery_resp;
|
||||
unsigned int oci_freq_override_ft_assoc;
|
||||
unsigned int oci_freq_override_fils_assoc;
|
||||
unsigned int oci_freq_override_wnm_sleep;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#define MESH_ENABLED BIT(0)
|
||||
@ -725,6 +745,8 @@ struct hostapd_bss_config {
|
||||
struct wpabuf *dpp_csign;
|
||||
#ifdef CONFIG_DPP2
|
||||
struct dpp_controller_conf *dpp_controller;
|
||||
int dpp_configurator_connectivity;
|
||||
int dpp_pfs;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
@ -741,6 +763,8 @@ struct hostapd_bss_config {
|
||||
|
||||
u8 send_probe_response;
|
||||
|
||||
u8 transition_disable;
|
||||
|
||||
#define BACKHAUL_BSS 1
|
||||
#define FRONTHAUL_BSS 2
|
||||
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
|
||||
@ -844,9 +868,9 @@ struct hostapd_bss_config {
|
||||
* struct he_phy_capabilities_info - HE PHY capabilities
|
||||
*/
|
||||
struct he_phy_capabilities_info {
|
||||
Boolean he_su_beamformer;
|
||||
Boolean he_su_beamformee;
|
||||
Boolean he_mu_beamformer;
|
||||
bool he_su_beamformer;
|
||||
bool he_su_beamformee;
|
||||
bool he_mu_beamformer;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -854,6 +878,8 @@ struct he_phy_capabilities_info {
|
||||
*/
|
||||
struct he_operation {
|
||||
u8 he_bss_color;
|
||||
u8 he_bss_color_disabled;
|
||||
u8 he_bss_color_partial;
|
||||
u8 he_default_pe_duration;
|
||||
u8 he_twt_required;
|
||||
u16 he_rts_threshold;
|
||||
@ -1013,6 +1039,7 @@ struct hostapd_config {
|
||||
|
||||
int rssi_reject_assoc_rssi;
|
||||
int rssi_reject_assoc_timeout;
|
||||
int rssi_ignore_probe_request;
|
||||
|
||||
#ifdef CONFIG_AIRTIME_POLICY
|
||||
enum {
|
||||
@ -1117,6 +1144,8 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config);
|
||||
void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
int full_config);
|
||||
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
|
||||
bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
|
||||
bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
|
||||
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
|
||||
|
||||
#endif /* HOSTAPD_CONFIG_H */
|
||||
|
@ -418,6 +418,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
const struct ieee80211_he_capabilities *he_capab,
|
||||
size_t he_capab_len,
|
||||
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
|
||||
int set)
|
||||
{
|
||||
@ -439,6 +440,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
params.vht_capabilities = vht_capab;
|
||||
params.he_capab = he_capab;
|
||||
params.he_capab_len = he_capab_len;
|
||||
params.he_6ghz_capab = he_6ghz_capab;
|
||||
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
|
||||
params.vht_opmode = vht_opmode;
|
||||
params.flags = hostapd_sta_flags_to_drv(flags);
|
||||
@ -588,7 +590,7 @@ int hostapd_set_frag(struct hostapd_data *hapd, int frag)
|
||||
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
|
||||
int total_flags, int flags_or, int flags_and)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
|
||||
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->sta_set_flags)
|
||||
return 0;
|
||||
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
|
||||
flags_or, flags_and);
|
||||
@ -650,6 +652,12 @@ int hostapd_drv_none(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
bool hostapd_drv_nl80211(struct hostapd_data *hapd)
|
||||
{
|
||||
return hapd->driver && os_strcmp(hapd->driver->name, "nl80211") == 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_driver_scan(struct hostapd_data *hapd,
|
||||
struct wpa_driver_scan_params *params)
|
||||
{
|
||||
@ -714,7 +722,7 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
|
||||
if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
|
||||
csa_offs, csa_offs_len, no_encrypt);
|
||||
csa_offs, csa_offs_len, no_encrypt, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -938,6 +946,7 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
params.freq_list = freq_list;
|
||||
params.edmg_enabled = hapd->iface->conf->enable_edmg;
|
||||
|
||||
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
|
||||
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
|
||||
|
@ -43,6 +43,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
const struct ieee80211_he_capabilities *he_capab,
|
||||
size_t he_capab_len,
|
||||
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
|
||||
int set);
|
||||
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
|
||||
@ -80,6 +81,7 @@ hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||
u16 *flags, u8 *dfs_domain);
|
||||
int hostapd_driver_commit(struct hostapd_data *hapd);
|
||||
int hostapd_drv_none(struct hostapd_data *hapd);
|
||||
bool hostapd_drv_nl80211(struct hostapd_data *hapd);
|
||||
int hostapd_driver_scan(struct hostapd_data *hapd,
|
||||
struct wpa_driver_scan_params *params);
|
||||
struct wpa_scan_results * hostapd_driver_get_scan_results(
|
||||
@ -348,12 +350,13 @@ static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
|
||||
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
|
||||
int vendor_id, int subcmd,
|
||||
const u8 *data, size_t data_len,
|
||||
enum nested_attr nested_attr_flag,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL)
|
||||
return -1;
|
||||
return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data,
|
||||
data_len, buf);
|
||||
data_len, nested_attr_flag, buf);
|
||||
}
|
||||
|
||||
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
|
||||
@ -382,11 +385,11 @@ hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
static inline int
|
||||
hostapd_drv_set_band(struct hostapd_data *hapd, enum set_band band)
|
||||
hostapd_drv_set_band(struct hostapd_data *hapd, u32 band_mask)
|
||||
{
|
||||
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
|
||||
return -1;
|
||||
return hapd->driver->set_band(hapd->drv_priv, band);
|
||||
return hapd->driver->set_band(hapd->drv_priv, band_mask);
|
||||
}
|
||||
|
||||
#endif /* AP_DRV_OPS */
|
||||
|
@ -228,7 +228,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
|
||||
set_beacon++;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if (!iface->olbc_ht && !ap->ht_support &&
|
||||
(ap->channel == 0 ||
|
||||
ap->channel == iface->conf->channel ||
|
||||
@ -241,7 +240,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
|
||||
MAC2STR(ap->addr), ap->channel);
|
||||
set_beacon++;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
if (set_beacon)
|
||||
ieee802_11_update_beacons(iface);
|
||||
@ -285,14 +283,12 @@ void ap_list_timer(struct hostapd_iface *iface)
|
||||
iface->olbc = 0;
|
||||
set_beacon++;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if (!olbc_ht && iface->olbc_ht) {
|
||||
wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
|
||||
iface->olbc_ht = 0;
|
||||
hostapd_ht_operation_update(iface);
|
||||
set_beacon++;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
}
|
||||
|
||||
if (set_beacon)
|
||||
|
214
src/ap/beacon.c
214
src/ap/beacon.c
@ -266,17 +266,101 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
|
||||
{
|
||||
const u8 *ies;
|
||||
size_t ies_len;
|
||||
|
||||
ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
|
||||
if (!ies)
|
||||
return NULL;
|
||||
|
||||
return get_ie(ies, ies_len, eid);
|
||||
}
|
||||
|
||||
|
||||
static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd,
|
||||
u32 vendor_type)
|
||||
{
|
||||
const u8 *ies;
|
||||
size_t ies_len;
|
||||
|
||||
ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len);
|
||||
if (!ies)
|
||||
return NULL;
|
||||
|
||||
return get_vendor_ie(ies, ies_len, vendor_type);
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len)
|
||||
{
|
||||
const u8 *ie;
|
||||
size_t ielen;
|
||||
|
||||
ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
|
||||
if (ie == NULL || ielen > len)
|
||||
return eid;
|
||||
ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
|
||||
if (!ie || 2U + ie[1] > len)
|
||||
return pos;
|
||||
|
||||
os_memcpy(eid, ie, ielen);
|
||||
return eid + ielen;
|
||||
os_memcpy(pos, ie, 2 + ie[1]);
|
||||
return pos + 2 + ie[1];
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len)
|
||||
{
|
||||
const u8 *ie;
|
||||
|
||||
ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
|
||||
if (!ie || 2U + ie[1] > len)
|
||||
return pos;
|
||||
|
||||
os_memcpy(pos, ie, 2 + ie[1]);
|
||||
return pos + 2 + ie[1];
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len)
|
||||
{
|
||||
const u8 *ie;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->conf->no_beacon_rsnxe) {
|
||||
wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon");
|
||||
return pos;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
|
||||
if (!ie || 2U + ie[1] > len)
|
||||
return pos;
|
||||
|
||||
os_memcpy(pos, ie, 2 + ie[1]);
|
||||
return pos + 2 + ie[1];
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
|
||||
{
|
||||
const u8 *ie;
|
||||
|
||||
ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE);
|
||||
if (!ie || 2U + ie[1] > len)
|
||||
return pos;
|
||||
|
||||
os_memcpy(pos, ie, 2 + ie[1]);
|
||||
return pos + 2 + ie[1];
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
|
||||
{
|
||||
const u8 *ie;
|
||||
|
||||
ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
|
||||
if (!ie || 2U + ie[1] > len)
|
||||
return pos;
|
||||
|
||||
os_memcpy(pos, ie, 2 + ie[1]);
|
||||
return pos + 2 + ie[1];
|
||||
}
|
||||
|
||||
|
||||
@ -374,16 +458,20 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
|
||||
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation) +
|
||||
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
|
||||
3 + sizeof(struct ieee80211_spatial_reuse);
|
||||
if (is_6ghz_op_class(hapd->iconf->op_class))
|
||||
buflen += sizeof(struct ieee80211_he_6ghz_oper_info) +
|
||||
3 + sizeof(struct ieee80211_he_6ghz_band_cap);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
buflen += hostapd_mbo_ie_len(hapd);
|
||||
buflen += hostapd_eid_owe_trans_len(hapd);
|
||||
buflen += hostapd_eid_dpp_cc_len(hapd);
|
||||
|
||||
resp = os_zalloc(buflen);
|
||||
if (resp == NULL)
|
||||
@ -434,14 +522,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
/* Extended supported rates */
|
||||
pos = hostapd_eid_ext_supp_rates(hapd, pos);
|
||||
|
||||
/* RSN, MDIE */
|
||||
if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
|
||||
(hapd->conf->osen && !hapd->conf->wpa)))
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
|
||||
|
||||
pos = hostapd_get_rsne(hapd, pos, epos - pos);
|
||||
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
|
||||
|
||||
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
|
||||
pos = hostapd_get_mde(hapd, pos, epos - pos);
|
||||
|
||||
/* eCSA IE */
|
||||
csa_pos = hostapd_eid_ecsa(hapd, pos);
|
||||
@ -450,15 +534,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
pos = csa_pos;
|
||||
|
||||
pos = hostapd_eid_supported_op_classes(hapd, pos);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
/* Secondary Channel Offset element */
|
||||
/* TODO: The standard doesn't specify a position for this element. */
|
||||
pos = hostapd_eid_secondary_channel(hapd, pos);
|
||||
|
||||
pos = hostapd_eid_ht_capabilities(hapd, pos);
|
||||
pos = hostapd_eid_ht_operation(hapd, pos);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
pos = hostapd_eid_ext_capab(hapd, pos);
|
||||
|
||||
@ -483,18 +560,23 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
|
||||
pos = hostapd_eid_vht_operation(hapd, pos);
|
||||
pos = hostapd_eid_txpower_envelope(hapd, pos);
|
||||
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
|
||||
(hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
|
||||
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
|
||||
|
||||
pos = hostapd_eid_fils_indic(hapd, pos, 0);
|
||||
pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
|
||||
pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
|
||||
pos = hostapd_eid_he_operation(hapd, pos);
|
||||
pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
|
||||
pos = hostapd_eid_spatial_reuse(hapd, pos);
|
||||
pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
|
||||
pos = hostapd_eid_he_6ghz_band_cap(hapd, pos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -503,10 +585,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
pos = hostapd_eid_vendor_vht(hapd, pos);
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
/* WPA */
|
||||
if (hapd->conf->wpa == WPA_PROTO_WPA ||
|
||||
(hapd->conf->osen && !hapd->conf->wpa))
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
|
||||
/* WPA / OSEN */
|
||||
pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
|
||||
pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
|
||||
|
||||
/* Wi-Fi Alliance WMM */
|
||||
pos = hostapd_eid_wmm(hapd, pos);
|
||||
@ -539,6 +620,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
|
||||
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
|
||||
pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
|
||||
pos = hostapd_eid_dpp_cc(hapd, pos, (u8 *) resp + buflen - pos);
|
||||
|
||||
if (hapd->conf->vendor_elements) {
|
||||
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
|
||||
@ -736,6 +818,10 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
size_t csa_offs_len;
|
||||
struct radius_sta rad_info;
|
||||
|
||||
if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
|
||||
ssi_signal < hapd->iconf->rssi_ignore_probe_request)
|
||||
return;
|
||||
|
||||
if (len < IEEE80211_HDRLEN)
|
||||
return;
|
||||
ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
|
||||
@ -1052,7 +1138,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
size_t resp_len = 0;
|
||||
#ifdef NEED_AP_MLME
|
||||
u16 capab_info;
|
||||
u8 *pos, *tailpos, *csa_pos;
|
||||
u8 *pos, *tailpos, *tailend, *csa_pos;
|
||||
|
||||
#define BEACON_HEAD_BUF_SIZE 256
|
||||
#define BEACON_TAIL_BUF_SIZE 512
|
||||
@ -1081,16 +1167,20 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
|
||||
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation) +
|
||||
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
|
||||
3 + sizeof(struct ieee80211_spatial_reuse);
|
||||
if (is_6ghz_op_class(hapd->iconf->op_class))
|
||||
tail_len += sizeof(struct ieee80211_he_6ghz_oper_info) +
|
||||
3 + sizeof(struct ieee80211_he_6ghz_band_cap);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
tail_len += hostapd_mbo_ie_len(hapd);
|
||||
tail_len += hostapd_eid_owe_trans_len(hapd);
|
||||
tail_len += hostapd_eid_dpp_cc_len(hapd);
|
||||
|
||||
tailpos = tail = os_malloc(tail_len);
|
||||
if (head == NULL || tail == NULL) {
|
||||
@ -1099,6 +1189,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
os_free(tail);
|
||||
return -1;
|
||||
}
|
||||
tailend = tail + tail_len;
|
||||
|
||||
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||
WLAN_FC_STYPE_BEACON);
|
||||
@ -1139,8 +1230,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
|
||||
head_len = pos - (u8 *) head;
|
||||
|
||||
tailpos = hostapd_eid_country(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE - tailpos);
|
||||
tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos);
|
||||
|
||||
/* Power Constraint element */
|
||||
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
|
||||
@ -1157,19 +1247,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
/* Extended supported rates */
|
||||
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
|
||||
|
||||
/* RSN, MDIE */
|
||||
if (!(hapd->conf->wpa == WPA_PROTO_WPA ||
|
||||
(hapd->conf->osen && !hapd->conf->wpa)))
|
||||
tailpos = hostapd_eid_wpa(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos);
|
||||
|
||||
tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos);
|
||||
tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos);
|
||||
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos);
|
||||
|
||||
tailpos = hostapd_eid_bss_load(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE - tailpos);
|
||||
tailend - tailpos);
|
||||
tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos);
|
||||
|
||||
/* eCSA IE */
|
||||
csa_pos = hostapd_eid_ecsa(hapd, tailpos);
|
||||
@ -1178,15 +1260,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = csa_pos;
|
||||
|
||||
tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
/* Secondary Channel Offset element */
|
||||
/* TODO: The standard doesn't specify a position for this element. */
|
||||
tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
|
||||
|
||||
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
|
||||
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
tailpos = hostapd_eid_ext_capab(hapd, tailpos);
|
||||
|
||||
@ -1213,19 +1288,24 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
|
||||
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
|
||||
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
|
||||
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
|
||||
(hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
|
||||
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
|
||||
|
||||
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
|
||||
tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
|
||||
tailpos = hostapd_eid_he_capab(hapd, tailpos,
|
||||
IEEE80211_MODE_AP);
|
||||
tailpos = hostapd_eid_he_operation(hapd, tailpos);
|
||||
tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
|
||||
tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
|
||||
tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
|
||||
tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -1234,12 +1314,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
/* WPA */
|
||||
if (hapd->conf->wpa == WPA_PROTO_WPA ||
|
||||
(hapd->conf->osen && !hapd->conf->wpa))
|
||||
tailpos = hostapd_eid_wpa(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos);
|
||||
/* WPA / OSEN */
|
||||
tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
|
||||
tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
|
||||
|
||||
/* Wi-Fi Alliance WMM */
|
||||
tailpos = hostapd_eid_wmm(hapd, tailpos);
|
||||
@ -1272,6 +1349,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
|
||||
tailpos = hostapd_eid_owe_trans(hapd, tailpos,
|
||||
tail + tail_len - tailpos);
|
||||
tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
|
||||
|
||||
if (hapd->conf->vendor_elements) {
|
||||
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
|
||||
@ -1310,10 +1388,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
|
||||
params->auth_algs = hapd->conf->auth_algs;
|
||||
params->wpa_version = hapd->conf->wpa;
|
||||
params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
|
||||
params->privacy = hapd->conf->wpa;
|
||||
#ifdef CONFIG_WEP
|
||||
params->privacy |= hapd->conf->ssid.wep.keys_set ||
|
||||
(hapd->conf->ieee802_1x &&
|
||||
(hapd->conf->default_wep_key_len ||
|
||||
hapd->conf->individual_wep_key_len));
|
||||
#endif /* CONFIG_WEP */
|
||||
switch (hapd->conf->ignore_broadcast_ssid) {
|
||||
case 0:
|
||||
params->hide_ssid = NO_SSID_HIDING;
|
||||
@ -1326,7 +1407,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
break;
|
||||
}
|
||||
params->isolate = hapd->conf->isolate;
|
||||
params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
|
||||
#ifdef NEED_AP_MLME
|
||||
params->cts_protect = !!(ieee802_11_erp_info(hapd) &
|
||||
ERP_INFO_USE_PROTECTION);
|
||||
@ -1422,8 +1502,18 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
|
||||
hapd->iface->conf->spr.srg_obss_pd_min_offset;
|
||||
params.he_spr_srg_obss_pd_max_offset =
|
||||
hapd->iface->conf->spr.srg_obss_pd_max_offset;
|
||||
params.he_bss_color_disabled =
|
||||
hapd->iface->conf->he_op.he_bss_color_disabled;
|
||||
params.he_bss_color_partial =
|
||||
hapd->iface->conf->he_op.he_bss_color_partial;
|
||||
params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
|
||||
params.twt_responder = hostapd_get_he_twt_responder(hapd,
|
||||
IEEE80211_MODE_AP);
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
hapd->reenable_beacon = 0;
|
||||
#ifdef CONFIG_SAE
|
||||
params.sae_pwe = hapd->conf->sae_pwe;
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
if (cmode &&
|
||||
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
|
||||
|
@ -345,7 +345,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
|
||||
res = os_snprintf(buf + len, buflen - len,
|
||||
"ht_caps_info=0x%04x\n",
|
||||
@ -354,7 +353,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
if (sta->ext_capability &&
|
||||
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
|
||||
@ -750,7 +748,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
iface->conf->ieee80211n && !hapd->conf->disable_11n,
|
||||
iface->conf->ieee80211ac &&
|
||||
!hapd->conf->disable_11ac,
|
||||
iface->conf->ieee80211ax,
|
||||
iface->conf->ieee80211ax &&
|
||||
!hapd->conf->disable_11ax,
|
||||
iface->conf->beacon_int,
|
||||
hapd->conf->dtim_period);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
@ -758,7 +757,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
len += ret;
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (iface->conf->ieee80211ax) {
|
||||
if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"he_oper_chwidth=%d\n"
|
||||
"he_oper_centr_freq_seg0_idx=%d\n"
|
||||
|
274
src/ap/dfs.c
274
src/ap/dfs.c
@ -144,30 +144,44 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
|
||||
int i;
|
||||
u32 bw = num_chan_to_bw(num_chans);
|
||||
|
||||
if (first_chan_idx + num_chans > mode->num_channels)
|
||||
if (first_chan_idx + num_chans > mode->num_channels) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DFS: some channels in range not defined");
|
||||
return 0;
|
||||
}
|
||||
|
||||
first_chan = &mode->channels[first_chan_idx];
|
||||
|
||||
/* hostapd DFS implementation assumes the first channel as primary.
|
||||
* If it's not allowed to use the first channel as primary, decline the
|
||||
* whole channel range. */
|
||||
if (!chan_pri_allowed(first_chan))
|
||||
if (!chan_pri_allowed(first_chan)) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_chans; i++) {
|
||||
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
|
||||
first_chan_idx);
|
||||
if (!chan)
|
||||
if (!chan) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
|
||||
first_chan->freq + i * 20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* HT 40 MHz secondary channel availability checked only for
|
||||
* primary channel */
|
||||
if (!chan_bw_allowed(chan, bw, 1, !i))
|
||||
if (!chan_bw_allowed(chan, bw, 1, !i)) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
|
||||
first_chan->freq + i * 20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dfs_channel_available(chan, skip_radar))
|
||||
if (!dfs_channel_available(chan, skip_radar)) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
|
||||
first_chan->freq + i * 20);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -210,22 +224,36 @@ static int dfs_find_channel(struct hostapd_iface *iface,
|
||||
if (iface->conf->ieee80211n &&
|
||||
iface->conf->secondary_channel &&
|
||||
(!dfs_is_chan_allowed(chan, n_chans) ||
|
||||
!(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
|
||||
!(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DFS: channel %d (%d) is incompatible",
|
||||
chan->freq, chan->chan);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip incompatible chandefs */
|
||||
if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
|
||||
if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DFS: range not available for %d (%d)",
|
||||
chan->freq, chan->chan);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_in_chanlist(iface, chan))
|
||||
if (!is_in_chanlist(iface, chan)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DFS: channel %d (%d) not in chanlist",
|
||||
chan->freq, chan->chan);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret_chan && idx == channel_idx) {
|
||||
wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
|
||||
wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
|
||||
chan->freq, chan->chan);
|
||||
*ret_chan = chan;
|
||||
return idx;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
|
||||
wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
|
||||
chan->freq, chan->chan);
|
||||
channel_idx++;
|
||||
}
|
||||
return channel_idx;
|
||||
@ -235,6 +263,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
|
||||
static void dfs_adjust_center_freq(struct hostapd_iface *iface,
|
||||
struct hostapd_channel_data *chan,
|
||||
int secondary_channel,
|
||||
int sec_chan_idx_80p80,
|
||||
u8 *oper_centr_freq_seg0_idx,
|
||||
u8 *oper_centr_freq_seg1_idx)
|
||||
{
|
||||
@ -261,8 +290,14 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
|
||||
case CHANWIDTH_160MHZ:
|
||||
*oper_centr_freq_seg0_idx = chan->chan + 14;
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
*oper_centr_freq_seg0_idx = chan->chan + 6;
|
||||
*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
|
||||
break;
|
||||
|
||||
default:
|
||||
wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
|
||||
wpa_printf(MSG_INFO,
|
||||
"DFS: Unsupported channel width configuration");
|
||||
*oper_centr_freq_seg0_idx = 0;
|
||||
break;
|
||||
}
|
||||
@ -441,8 +476,11 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
{
|
||||
struct hostapd_hw_modes *mode;
|
||||
struct hostapd_channel_data *chan = NULL;
|
||||
struct hostapd_channel_data *chan2 = NULL;
|
||||
int num_available_chandefs;
|
||||
int chan_idx;
|
||||
int chan_idx, chan_idx2;
|
||||
int sec_chan_idx_80p80 = -1;
|
||||
int i;
|
||||
u32 _rand;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
|
||||
@ -459,6 +497,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
|
||||
/* Get the count first */
|
||||
num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
|
||||
wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
|
||||
num_available_chandefs);
|
||||
if (num_available_chandefs == 0)
|
||||
return NULL;
|
||||
|
||||
@ -466,6 +506,12 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
return NULL;
|
||||
chan_idx = _rand % num_available_chandefs;
|
||||
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
|
||||
if (!chan) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: no random channel found");
|
||||
return NULL;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
|
||||
chan->freq, chan->chan);
|
||||
|
||||
/* dfs_find_channel() calculations assume HT40+ */
|
||||
if (iface->conf->secondary_channel)
|
||||
@ -473,8 +519,45 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
else
|
||||
*secondary_channel = 0;
|
||||
|
||||
/* Get secondary channel for HT80P80 */
|
||||
if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
|
||||
if (num_available_chandefs <= 1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"only 1 valid chan, can't support 80+80");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop all channels except channel1 to find a valid channel2
|
||||
* that is not adjacent to channel1.
|
||||
*/
|
||||
for (i = 0; i < num_available_chandefs - 1; i++) {
|
||||
/* start from chan_idx + 1, end when chan_idx - 1 */
|
||||
chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
|
||||
dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
|
||||
if (chan2 && abs(chan2->chan - chan->chan) > 12) {
|
||||
/* two channels are not adjacent */
|
||||
sec_chan_idx_80p80 = chan2->chan;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DFS: got second chan: %d (%d)",
|
||||
chan2->freq, chan2->chan);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we got a valid secondary channel which is not
|
||||
* adjacent to the first channel.
|
||||
*/
|
||||
if (sec_chan_idx_80p80 == -1) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"DFS: failed to get chan2 for 80+80");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dfs_adjust_center_freq(iface, chan,
|
||||
*secondary_channel,
|
||||
sec_chan_idx_80p80,
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx);
|
||||
|
||||
@ -773,7 +856,7 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
|
||||
int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
|
||||
{
|
||||
int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
|
||||
|
||||
@ -821,7 +904,7 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
* another radio.
|
||||
*/
|
||||
if (iface->state != HAPD_IFACE_ENABLED &&
|
||||
hostapd_config_dfs_chan_available(iface)) {
|
||||
hostapd_is_dfs_chan_available(iface)) {
|
||||
hostapd_setup_interface_complete(iface, 0);
|
||||
iface->cac_started = 0;
|
||||
}
|
||||
@ -851,6 +934,44 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_channel_data *
|
||||
dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
|
||||
u8 *oper_centr_freq_seg0_idx,
|
||||
u8 *oper_centr_freq_seg1_idx, int *skip_radar)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
|
||||
for (;;) {
|
||||
channel = dfs_get_valid_channel(iface, secondary_channel,
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx,
|
||||
*skip_radar);
|
||||
if (channel) {
|
||||
wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
|
||||
channel->chan);
|
||||
return channel;
|
||||
}
|
||||
|
||||
if (*skip_radar) {
|
||||
*skip_radar = 0;
|
||||
} else {
|
||||
int oper_chwidth;
|
||||
|
||||
oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
|
||||
if (oper_chwidth == CHANWIDTH_USE_HT)
|
||||
break;
|
||||
*skip_radar = 1;
|
||||
hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
|
||||
}
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO,
|
||||
"%s: no DFS channels left, waiting for NOP to finish",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
@ -868,8 +989,14 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
skip_radar);
|
||||
|
||||
if (!channel) {
|
||||
wpa_printf(MSG_ERROR, "No valid channel available");
|
||||
return err;
|
||||
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
&skip_radar);
|
||||
if (!channel) {
|
||||
wpa_printf(MSG_ERROR, "No valid channel available");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
|
||||
@ -898,11 +1025,14 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
int secondary_channel;
|
||||
u8 oper_centr_freq_seg0_idx;
|
||||
u8 oper_centr_freq_seg1_idx;
|
||||
u8 new_vht_oper_chwidth;
|
||||
int skip_radar = 1;
|
||||
struct csa_settings csa_settings;
|
||||
unsigned int i;
|
||||
int err = 1;
|
||||
struct hostapd_hw_modes *cmode = iface->current_mode;
|
||||
u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
|
||||
int ieee80211_mode = IEEE80211_MODE_AP;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
|
||||
__func__, iface->cac_started ? "yes" : "no",
|
||||
@ -936,28 +1066,33 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
* requires to perform a CAC first.
|
||||
*/
|
||||
skip_radar = 0;
|
||||
channel = dfs_get_valid_channel(iface, &secondary_channel,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
skip_radar);
|
||||
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
|
||||
&oper_centr_freq_seg0_idx,
|
||||
&oper_centr_freq_seg1_idx,
|
||||
&skip_radar);
|
||||
if (!channel) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"%s: no DFS channels left, waiting for NOP to finish",
|
||||
__func__);
|
||||
return err;
|
||||
/*
|
||||
* Toggle interface state to enter DFS state
|
||||
* until NOP is finished.
|
||||
*/
|
||||
hostapd_disable_iface(iface);
|
||||
hostapd_enable_iface(iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = secondary_channel;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
|
||||
oper_centr_freq_seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
|
||||
oper_centr_freq_seg1_idx);
|
||||
if (!skip_radar) {
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = secondary_channel;
|
||||
hostapd_set_oper_centr_freq_seg0_idx(
|
||||
iface->conf, oper_centr_freq_seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(
|
||||
iface->conf, oper_centr_freq_seg1_idx);
|
||||
|
||||
hostapd_disable_iface(iface);
|
||||
hostapd_enable_iface(iface);
|
||||
return 0;
|
||||
hostapd_disable_iface(iface);
|
||||
hostapd_enable_iface(iface);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
channel->chan, secondary_channel);
|
||||
|
||||
new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
|
||||
hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
|
||||
|
||||
/* Setup CSA request */
|
||||
os_memset(&csa_settings, 0, sizeof(csa_settings));
|
||||
csa_settings.cs_count = 5;
|
||||
csa_settings.block_tx = 1;
|
||||
#ifdef CONFIG_MESH
|
||||
if (iface->mconf)
|
||||
ieee80211_mode = IEEE80211_MODE_MESH;
|
||||
#endif /* CONFIG_MESH */
|
||||
err = hostapd_set_freq_params(&csa_settings.freq_params,
|
||||
iface->conf->hw_mode,
|
||||
channel->freq,
|
||||
@ -980,11 +1122,11 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
iface->conf->ieee80211ac,
|
||||
iface->conf->ieee80211ax,
|
||||
secondary_channel,
|
||||
hostapd_get_oper_chwidth(iface->conf),
|
||||
new_vht_oper_chwidth,
|
||||
oper_centr_freq_seg0_idx,
|
||||
oper_centr_freq_seg1_idx,
|
||||
cmode->vht_capab,
|
||||
&cmode->he_capab[IEEE80211_MODE_AP]);
|
||||
&cmode->he_capab[ieee80211_mode]);
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
|
||||
@ -1004,6 +1146,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
iface->freq = channel->freq;
|
||||
iface->conf->channel = channel->chan;
|
||||
iface->conf->secondary_channel = secondary_channel;
|
||||
hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
|
||||
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
|
||||
oper_centr_freq_seg0_idx);
|
||||
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
|
||||
@ -1040,8 +1183,10 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
|
||||
return 0;
|
||||
|
||||
/* mark radar frequency as invalid */
|
||||
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
|
||||
cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
|
||||
res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
|
||||
cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
/* Skip if reported radar event not overlapped our channels */
|
||||
res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
|
||||
@ -1161,3 +1306,56 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
|
||||
__func__, iface->freq);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
|
||||
int center_freq)
|
||||
{
|
||||
struct hostapd_channel_data *chan;
|
||||
struct hostapd_hw_modes *mode = iface->current_mode;
|
||||
int half_width;
|
||||
int res = 0;
|
||||
int i;
|
||||
|
||||
if (!iface->conf->ieee80211h || !mode ||
|
||||
mode->mode != HOSTAPD_MODE_IEEE80211A)
|
||||
return 0;
|
||||
|
||||
switch (width) {
|
||||
case CHAN_WIDTH_20_NOHT:
|
||||
case CHAN_WIDTH_20:
|
||||
half_width = 10;
|
||||
break;
|
||||
case CHAN_WIDTH_40:
|
||||
half_width = 20;
|
||||
break;
|
||||
case CHAN_WIDTH_80:
|
||||
case CHAN_WIDTH_80P80:
|
||||
half_width = 40;
|
||||
break;
|
||||
case CHAN_WIDTH_160:
|
||||
half_width = 80;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported",
|
||||
width);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
chan = &mode->channels[i];
|
||||
|
||||
if (!(chan->flag & HOSTAPD_CHAN_RADAR))
|
||||
continue;
|
||||
|
||||
if (center_freq - chan->freq < half_width &&
|
||||
chan->freq - center_freq < half_width)
|
||||
res++;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DFS: (%d, %d): in range: %s",
|
||||
center_freq - half_width, center_freq + half_width,
|
||||
res ? "yes" : "no");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -25,9 +25,12 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
|
||||
int ht_enabled,
|
||||
int chan_offset, int chan_width, int cf1, int cf2);
|
||||
int hostapd_is_dfs_required(struct hostapd_iface *iface);
|
||||
int hostapd_is_dfs_chan_available(struct hostapd_iface *iface);
|
||||
int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
|
||||
int ht_enabled, int chan_offset, int chan_width,
|
||||
int cf1, int cf2);
|
||||
int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
|
||||
int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
|
||||
int center_freq);
|
||||
|
||||
#endif /* DFS_H */
|
||||
|
@ -26,6 +26,13 @@ static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
|
||||
static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
|
||||
#ifdef CONFIG_DPP2
|
||||
static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
|
||||
void *timeout_ctx);
|
||||
static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
|
||||
struct dpp_authentication *auth,
|
||||
struct dpp_config_obj *conf);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
@ -59,6 +66,10 @@ int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd)
|
||||
wpabuf_len(hapd->dpp_auth->resp_msg));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
dpp_controller_new_qr_code(hapd->iface->interfaces->dpp, bi);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
return bi->id;
|
||||
}
|
||||
|
||||
@ -237,6 +248,10 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
|
||||
hapd, NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
|
||||
NULL);
|
||||
#ifdef CONFIG_DPP2
|
||||
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
|
||||
hapd, NULL);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
hostapd_drv_send_action_cancel_wait(hapd);
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
@ -478,12 +493,35 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
static int hostapd_dpp_process_conf_obj(void *ctx,
|
||||
struct dpp_authentication *auth)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < auth->num_conf_obj; i++)
|
||||
hostapd_dpp_handle_config_obj(hapd, auth,
|
||||
&auth->conf_obj[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
|
||||
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
|
||||
{
|
||||
const char *pos;
|
||||
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
|
||||
struct dpp_authentication *auth;
|
||||
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
|
||||
unsigned int neg_freq = 0;
|
||||
int tcp = 0;
|
||||
#ifdef CONFIG_DPP2
|
||||
int tcp_port = DPP_TCP_PORT;
|
||||
struct hostapd_ip_addr ipaddr;
|
||||
char *addr;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
pos = os_strstr(cmd, " peer=");
|
||||
if (!pos)
|
||||
@ -496,6 +534,25 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
pos = os_strstr(cmd, " tcp_port=");
|
||||
if (pos) {
|
||||
pos += 10;
|
||||
tcp_port = atoi(pos);
|
||||
}
|
||||
|
||||
addr = get_param(cmd, " tcp_addr=");
|
||||
if (addr) {
|
||||
int res;
|
||||
|
||||
res = hostapd_parse_ip_addr(addr, &ipaddr);
|
||||
os_free(addr);
|
||||
if (res)
|
||||
return -1;
|
||||
tcp = 1;
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
pos = os_strstr(cmd, " own=");
|
||||
if (pos) {
|
||||
pos += 5;
|
||||
@ -533,36 +590,46 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
|
||||
if (pos)
|
||||
neg_freq = atoi(pos + 10);
|
||||
|
||||
if (hapd->dpp_auth) {
|
||||
if (!tcp && hapd->dpp_auth) {
|
||||
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
|
||||
hapd, NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
|
||||
NULL);
|
||||
#ifdef CONFIG_DPP2
|
||||
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
|
||||
hapd, NULL);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
hostapd_drv_send_action_cancel_wait(hapd);
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
}
|
||||
|
||||
hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi,
|
||||
allowed_roles, neg_freq,
|
||||
hapd->iface->hw_features,
|
||||
hapd->iface->num_hw_features);
|
||||
if (!hapd->dpp_auth)
|
||||
auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
|
||||
peer_bi, own_bi, allowed_roles, neg_freq,
|
||||
hapd->iface->hw_features,
|
||||
hapd->iface->num_hw_features);
|
||||
if (!auth)
|
||||
goto fail;
|
||||
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
|
||||
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
|
||||
hapd->dpp_auth, cmd) < 0) {
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
hostapd_dpp_set_testing_options(hapd, auth);
|
||||
if (dpp_set_configurator(auth, cmd) < 0) {
|
||||
dpp_auth_deinit(auth);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hapd->dpp_auth->neg_freq = neg_freq;
|
||||
auth->neg_freq = neg_freq;
|
||||
|
||||
if (!is_zero_ether_addr(peer_bi->mac_addr))
|
||||
os_memcpy(hapd->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
|
||||
ETH_ALEN);
|
||||
os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
if (tcp)
|
||||
return dpp_tcp_init(hapd->iface->interfaces->dpp, auth,
|
||||
&ipaddr, tcp_port, hapd->conf->dpp_name,
|
||||
DPP_NETROLE_AP, hapd->msg_ctx, hapd,
|
||||
hostapd_dpp_process_conf_obj);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
hapd->dpp_auth = auth;
|
||||
return hostapd_dpp_auth_init_next(hapd);
|
||||
fail:
|
||||
return -1;
|
||||
@ -618,6 +685,10 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
|
||||
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
|
||||
MAC2STR(src));
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
hostapd_dpp_chirp_stop(hapd);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
|
||||
&r_bootstrap_len);
|
||||
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
|
||||
@ -663,7 +734,8 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
|
||||
}
|
||||
|
||||
hapd->dpp_auth_ok_on_ack = 0;
|
||||
hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles,
|
||||
hapd->dpp_auth = dpp_auth_req_rx(hapd->iface->interfaces->dpp,
|
||||
hapd->msg_ctx, hapd->dpp_allowed_roles,
|
||||
hapd->dpp_qr_mutual,
|
||||
peer_bi, own_bi, freq, hdr, buf, len);
|
||||
if (!hapd->dpp_auth) {
|
||||
@ -671,8 +743,7 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
|
||||
return;
|
||||
}
|
||||
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
|
||||
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
|
||||
hapd->dpp_auth,
|
||||
if (dpp_set_configurator(hapd->dpp_auth,
|
||||
hapd->dpp_configurator_params) < 0) {
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
@ -708,7 +779,8 @@ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
|
||||
* message. */
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
|
||||
conf->connector);
|
||||
} else if (conf->passphrase[0]) {
|
||||
}
|
||||
if (conf->passphrase[0]) {
|
||||
char hex[64 * 2 + 1];
|
||||
|
||||
wpa_snprintf_hex(hex, sizeof(hex),
|
||||
@ -1132,6 +1204,227 @@ static void hostapd_dpp_rx_conn_status_result(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
|
||||
const u8 *hdr, const u8 *buf, size_t len,
|
||||
unsigned int freq)
|
||||
{
|
||||
const u8 *r_bootstrap;
|
||||
u16 r_bootstrap_len;
|
||||
struct dpp_bootstrap_info *peer_bi;
|
||||
struct dpp_authentication *auth;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
|
||||
MAC2STR(src));
|
||||
|
||||
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
|
||||
&r_bootstrap_len);
|
||||
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
|
||||
"Missing or invalid required Responder Bootstrapping Key Hash attribute");
|
||||
return;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
|
||||
r_bootstrap, r_bootstrap_len);
|
||||
peer_bi = dpp_bootstrap_find_chirp(hapd->iface->interfaces->dpp,
|
||||
r_bootstrap);
|
||||
dpp_notify_chirp_received(hapd->msg_ctx,
|
||||
peer_bi ? (int) peer_bi->id : -1,
|
||||
src, freq, r_bootstrap);
|
||||
if (!peer_bi) {
|
||||
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
|
||||
src, hdr, buf, len, freq, NULL,
|
||||
r_bootstrap) == 0)
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: No matching bootstrapping information found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (hapd->dpp_auth) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Ignore Presence Announcement during ongoing Authentication");
|
||||
return;
|
||||
}
|
||||
|
||||
auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
|
||||
peer_bi, NULL, DPP_CAPAB_CONFIGURATOR, freq, NULL,
|
||||
0);
|
||||
if (!auth)
|
||||
return;
|
||||
hostapd_dpp_set_testing_options(hapd, auth);
|
||||
if (dpp_set_configurator(auth,
|
||||
hapd->dpp_configurator_params) < 0) {
|
||||
dpp_auth_deinit(auth);
|
||||
return;
|
||||
}
|
||||
|
||||
auth->neg_freq = freq;
|
||||
|
||||
if (!is_zero_ether_addr(peer_bi->mac_addr))
|
||||
os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
|
||||
|
||||
hapd->dpp_auth = auth;
|
||||
if (hostapd_dpp_auth_init_next(hapd) < 0) {
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
|
||||
void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct dpp_authentication *auth = hapd->dpp_auth;
|
||||
|
||||
if (!auth)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Reconfig Reply wait timeout");
|
||||
hostapd_dpp_listen_stop(hapd);
|
||||
dpp_auth_deinit(auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src,
|
||||
const u8 *hdr, const u8 *buf, size_t len,
|
||||
unsigned int freq)
|
||||
{
|
||||
const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
|
||||
u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
|
||||
struct dpp_configurator *conf;
|
||||
struct dpp_authentication *auth;
|
||||
unsigned int wait_time, max_wait_time;
|
||||
u16 group;
|
||||
|
||||
if (hapd->dpp_auth) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Ignore Reconfig Announcement during ongoing Authentication");
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Reconfig Announcement from " MACSTR,
|
||||
MAC2STR(src));
|
||||
|
||||
csign_hash = dpp_get_attr(buf, len, DPP_ATTR_C_SIGN_KEY_HASH,
|
||||
&csign_hash_len);
|
||||
if (!csign_hash || csign_hash_len != SHA256_MAC_LEN) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
|
||||
"Missing or invalid required Configurator C-sign key Hash attribute");
|
||||
return;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator C-sign key Hash (kid)",
|
||||
csign_hash, csign_hash_len);
|
||||
conf = dpp_configurator_find_kid(hapd->iface->interfaces->dpp,
|
||||
csign_hash);
|
||||
if (!conf) {
|
||||
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
|
||||
src, hdr, buf, len, freq, NULL,
|
||||
NULL) == 0)
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: No matching Configurator information found");
|
||||
return;
|
||||
}
|
||||
|
||||
fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
|
||||
&fcgroup_len);
|
||||
if (!fcgroup || fcgroup_len != 2) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
|
||||
"Missing or invalid required Finite Cyclic Group attribute");
|
||||
return;
|
||||
}
|
||||
group = WPA_GET_LE16(fcgroup);
|
||||
wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
|
||||
|
||||
a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
|
||||
e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
|
||||
|
||||
auth = dpp_reconfig_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
|
||||
conf, freq, group, a_nonce, a_nonce_len,
|
||||
e_id, e_id_len);
|
||||
if (!auth)
|
||||
return;
|
||||
hostapd_dpp_set_testing_options(hapd, auth);
|
||||
if (dpp_set_configurator(auth, hapd->dpp_configurator_params) < 0) {
|
||||
dpp_auth_deinit(auth);
|
||||
return;
|
||||
}
|
||||
|
||||
os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
|
||||
hapd->dpp_auth = auth;
|
||||
|
||||
hapd->dpp_in_response_listen = 0;
|
||||
hapd->dpp_auth_ok_on_ack = 0;
|
||||
wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
|
||||
max_wait_time = hapd->dpp_resp_wait_time ?
|
||||
hapd->dpp_resp_wait_time : 2000;
|
||||
if (wait_time > max_wait_time)
|
||||
wait_time = max_wait_time;
|
||||
wait_time += 10; /* give the driver some extra time to complete */
|
||||
eloop_register_timeout(wait_time / 1000, (wait_time % 1000) * 1000,
|
||||
hostapd_dpp_reconfig_reply_wait_timeout,
|
||||
hapd, NULL);
|
||||
wait_time -= 10;
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
|
||||
" freq=%u type=%d",
|
||||
MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_REQ);
|
||||
if (hostapd_drv_send_action(hapd, freq, wait_time, src,
|
||||
wpabuf_head(auth->reconfig_req_msg),
|
||||
wpabuf_len(auth->reconfig_req_msg)) < 0) {
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hostapd_dpp_rx_reconfig_auth_resp(struct hostapd_data *hapd, const u8 *src,
|
||||
const u8 *hdr, const u8 *buf, size_t len,
|
||||
unsigned int freq)
|
||||
{
|
||||
struct dpp_authentication *auth = hapd->dpp_auth;
|
||||
struct wpabuf *conf;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Response from "
|
||||
MACSTR, MAC2STR(src));
|
||||
|
||||
if (!auth || !auth->reconfig || !auth->configurator) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: No DPP Reconfig Authentication in progress - drop");
|
||||
return;
|
||||
}
|
||||
|
||||
if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
|
||||
MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
conf = dpp_reconfig_auth_resp_rx(auth, hdr, buf, len);
|
||||
if (!conf)
|
||||
return;
|
||||
|
||||
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
|
||||
hapd, NULL);
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
|
||||
" freq=%u type=%d",
|
||||
MAC2STR(src), freq, DPP_PA_RECONFIG_AUTH_CONF);
|
||||
if (hostapd_drv_send_action(hapd, freq, 500, src,
|
||||
wpabuf_head(conf), wpabuf_len(conf)) < 0) {
|
||||
wpabuf_free(conf);
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
return;
|
||||
}
|
||||
wpabuf_free(conf);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
|
||||
@ -1141,9 +1434,13 @@ static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
|
||||
enum dpp_status_error status)
|
||||
{
|
||||
struct wpabuf *msg;
|
||||
size_t len;
|
||||
|
||||
msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP,
|
||||
5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector));
|
||||
len = 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector);
|
||||
#ifdef CONFIG_DPP2
|
||||
len += 5;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP, len);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
@ -1216,6 +1513,15 @@ skip_status:
|
||||
skip_connector:
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
if (DPP_VERSION > 1) {
|
||||
/* Protocol Version */
|
||||
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
|
||||
wpabuf_put_le16(msg, 1);
|
||||
wpabuf_put_u8(msg, DPP_VERSION);
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR
|
||||
" status=%d", MAC2STR(src), status);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
|
||||
@ -1581,6 +1887,18 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
|
||||
case DPP_PA_CONNECTION_STATUS_RESULT:
|
||||
hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len);
|
||||
break;
|
||||
case DPP_PA_PRESENCE_ANNOUNCEMENT:
|
||||
hostapd_dpp_rx_presence_announcement(hapd, src, hdr, buf, len,
|
||||
freq);
|
||||
break;
|
||||
case DPP_PA_RECONFIG_ANNOUNCEMENT:
|
||||
hostapd_dpp_rx_reconfig_announcement(hapd, src, hdr, buf, len,
|
||||
freq);
|
||||
break;
|
||||
case DPP_PA_RECONFIG_AUTH_RESP:
|
||||
hostapd_dpp_rx_reconfig_auth_resp(hapd, src, hdr, buf, len,
|
||||
freq);
|
||||
break;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -1610,7 +1928,7 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
|
||||
struct wpabuf *resp;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
|
||||
if (!auth || !auth->auth_success ||
|
||||
if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
|
||||
os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
|
||||
#ifdef CONFIG_DPP2
|
||||
if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data,
|
||||
@ -1646,6 +1964,8 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
|
||||
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
|
||||
#ifdef CONFIG_DPP2
|
||||
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
|
||||
hapd, NULL);
|
||||
if (ok && auth->peer_version >= 2 &&
|
||||
auth->conf_resp_status == DPP_STATUS_OK) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
|
||||
@ -1675,14 +1995,13 @@ int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
|
||||
int ret = -1;
|
||||
char *curve = NULL;
|
||||
|
||||
auth = os_zalloc(sizeof(*auth));
|
||||
auth = dpp_alloc_auth(hapd->iface->interfaces->dpp, hapd->msg_ctx);
|
||||
if (!auth)
|
||||
return -1;
|
||||
|
||||
curve = get_param(cmd, " curve=");
|
||||
hostapd_dpp_set_testing_options(hapd, auth);
|
||||
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
|
||||
auth, cmd) == 0 &&
|
||||
if (dpp_set_configurator(auth, cmd) == 0 &&
|
||||
dpp_configurator_own_config(auth, curve, 1) == 0) {
|
||||
hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
|
||||
ret = 0;
|
||||
@ -1891,10 +2210,13 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
|
||||
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
|
||||
#ifdef CONFIG_DPP2
|
||||
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
|
||||
hapd, NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
|
||||
NULL);
|
||||
eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
|
||||
NULL);
|
||||
hostapd_dpp_chirp_stop(hapd);
|
||||
#endif /* CONFIG_DPP2 */
|
||||
dpp_auth_deinit(hapd->dpp_auth);
|
||||
hapd->dpp_auth = NULL;
|
||||
@ -1903,3 +2225,359 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
|
||||
os_free(hapd->dpp_configurator_params);
|
||||
hapd->dpp_configurator_params = NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
|
||||
int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd)
|
||||
{
|
||||
struct dpp_controller_config config;
|
||||
const char *pos;
|
||||
|
||||
os_memset(&config, 0, sizeof(config));
|
||||
config.allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
|
||||
config.netrole = DPP_NETROLE_AP;
|
||||
config.msg_ctx = hapd->msg_ctx;
|
||||
config.cb_ctx = hapd;
|
||||
config.process_conf_obj = hostapd_dpp_process_conf_obj;
|
||||
if (cmd) {
|
||||
pos = os_strstr(cmd, " tcp_port=");
|
||||
if (pos) {
|
||||
pos += 10;
|
||||
config.tcp_port = atoi(pos);
|
||||
}
|
||||
|
||||
pos = os_strstr(cmd, " role=");
|
||||
if (pos) {
|
||||
pos += 6;
|
||||
if (os_strncmp(pos, "configurator", 12) == 0)
|
||||
config.allowed_roles = DPP_CAPAB_CONFIGURATOR;
|
||||
else if (os_strncmp(pos, "enrollee", 8) == 0)
|
||||
config.allowed_roles = DPP_CAPAB_ENROLLEE;
|
||||
else if (os_strncmp(pos, "either", 6) == 0)
|
||||
config.allowed_roles = DPP_CAPAB_CONFIGURATOR |
|
||||
DPP_CAPAB_ENROLLEE;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
|
||||
}
|
||||
config.configurator_params = hapd->dpp_configurator_params;
|
||||
return dpp_controller_start(hapd->iface->interfaces->dpp, &config);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
|
||||
|
||||
static void hostapd_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
|
||||
hostapd_drv_send_action_cancel_wait(hapd);
|
||||
hostapd_dpp_chirp_next(hapd, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_dpp_chirp_start(struct hostapd_data *hapd)
|
||||
{
|
||||
struct wpabuf *msg;
|
||||
int type;
|
||||
|
||||
msg = hapd->dpp_presence_announcement;
|
||||
type = DPP_PA_PRESENCE_ANNOUNCEMENT;
|
||||
wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", hapd->dpp_chirp_freq);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
|
||||
" freq=%u type=%d",
|
||||
MAC2STR(broadcast), hapd->dpp_chirp_freq, type);
|
||||
if (hostapd_drv_send_action(
|
||||
hapd, hapd->dpp_chirp_freq, 2000, broadcast,
|
||||
wpabuf_head(msg), wpabuf_len(msg)) < 0 ||
|
||||
eloop_register_timeout(2, 0, hostapd_dpp_chirp_timeout,
|
||||
hapd, NULL) < 0)
|
||||
hostapd_dpp_chirp_stop(hapd);
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_hw_modes *
|
||||
dpp_get_mode(struct hostapd_data *hapd,
|
||||
enum hostapd_hw_mode mode)
|
||||
{
|
||||
struct hostapd_hw_modes *modes = hapd->iface->hw_features;
|
||||
u16 num_modes = hapd->iface->num_hw_features;
|
||||
u16 i;
|
||||
|
||||
for (i = 0; i < num_modes; i++) {
|
||||
if (modes[i].mode != mode ||
|
||||
!modes[i].num_channels || !modes[i].channels)
|
||||
continue;
|
||||
return &modes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hostapd_dpp_chirp_scan_res_handler(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
struct wpa_scan_results *scan_res;
|
||||
struct dpp_bootstrap_info *bi = hapd->dpp_chirp_bi;
|
||||
unsigned int i;
|
||||
struct hostapd_hw_modes *mode;
|
||||
int c;
|
||||
|
||||
if (!bi)
|
||||
return;
|
||||
|
||||
hapd->dpp_chirp_scan_done = 1;
|
||||
|
||||
scan_res = hostapd_driver_get_scan_results(hapd);
|
||||
|
||||
os_free(hapd->dpp_chirp_freqs);
|
||||
hapd->dpp_chirp_freqs = NULL;
|
||||
|
||||
/* Channels from own bootstrapping info */
|
||||
if (bi) {
|
||||
for (i = 0; i < bi->num_freq; i++)
|
||||
int_array_add_unique(&hapd->dpp_chirp_freqs,
|
||||
bi->freq[i]);
|
||||
}
|
||||
|
||||
/* Preferred chirping channels */
|
||||
int_array_add_unique(&hapd->dpp_chirp_freqs, 2437);
|
||||
|
||||
mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211A);
|
||||
if (mode) {
|
||||
int chan44 = 0, chan149 = 0;
|
||||
|
||||
for (c = 0; c < mode->num_channels; c++) {
|
||||
struct hostapd_channel_data *chan = &mode->channels[c];
|
||||
|
||||
if (chan->flag & (HOSTAPD_CHAN_DISABLED |
|
||||
HOSTAPD_CHAN_RADAR))
|
||||
continue;
|
||||
if (chan->freq == 5220)
|
||||
chan44 = 1;
|
||||
if (chan->freq == 5745)
|
||||
chan149 = 1;
|
||||
}
|
||||
if (chan149)
|
||||
int_array_add_unique(&hapd->dpp_chirp_freqs, 5745);
|
||||
else if (chan44)
|
||||
int_array_add_unique(&hapd->dpp_chirp_freqs, 5220);
|
||||
}
|
||||
|
||||
mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211AD);
|
||||
if (mode) {
|
||||
for (c = 0; c < mode->num_channels; c++) {
|
||||
struct hostapd_channel_data *chan = &mode->channels[c];
|
||||
|
||||
if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
|
||||
HOSTAPD_CHAN_RADAR)) ||
|
||||
chan->freq != 60480)
|
||||
continue;
|
||||
int_array_add_unique(&hapd->dpp_chirp_freqs, 60480);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add channels from scan results for APs that advertise Configurator
|
||||
* Connectivity element */
|
||||
for (i = 0; scan_res && i < scan_res->num; i++) {
|
||||
struct wpa_scan_res *bss = scan_res->res[i];
|
||||
size_t ie_len = bss->ie_len;
|
||||
|
||||
if (!ie_len)
|
||||
ie_len = bss->beacon_ie_len;
|
||||
if (get_vendor_ie((const u8 *) (bss + 1), ie_len,
|
||||
DPP_CC_IE_VENDOR_TYPE))
|
||||
int_array_add_unique(&hapd->dpp_chirp_freqs,
|
||||
bss->freq);
|
||||
}
|
||||
|
||||
if (!hapd->dpp_chirp_freqs ||
|
||||
eloop_register_timeout(0, 0, hostapd_dpp_chirp_next,
|
||||
hapd, NULL) < 0)
|
||||
hostapd_dpp_chirp_stop(hapd);
|
||||
|
||||
wpa_scan_results_free(scan_res);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
int i;
|
||||
|
||||
if (hapd->dpp_chirp_listen)
|
||||
hostapd_dpp_listen_stop(hapd);
|
||||
|
||||
if (hapd->dpp_chirp_freq == 0) {
|
||||
if (hapd->dpp_chirp_round % 4 == 0 &&
|
||||
!hapd->dpp_chirp_scan_done) {
|
||||
struct wpa_driver_scan_params params;
|
||||
int ret;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Update channel list for chirping");
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
ret = hostapd_driver_scan(hapd, ¶ms);
|
||||
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 */
|
||||
|
@ -10,6 +10,8 @@
|
||||
#ifndef DPP_HOSTAPD_H
|
||||
#define DPP_HOSTAPD_H
|
||||
|
||||
struct dpp_bootstrap_info;
|
||||
|
||||
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd);
|
||||
@ -39,4 +41,9 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd);
|
||||
void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
|
||||
void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
|
||||
|
||||
int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
|
||||
void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
|
||||
void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
|
||||
|
||||
#endif /* DPP_HOSTAPD_H */
|
||||
|
@ -106,18 +106,45 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
|
||||
static bool check_sa_query_need(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
if ((sta->flags &
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
|
||||
return false;
|
||||
|
||||
if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
|
||||
ap_check_sa_query_timeout(hapd, sta);
|
||||
|
||||
if (!sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) {
|
||||
/*
|
||||
* STA has already been associated with MFP and SA Query timeout
|
||||
* has not been reached. Reject the association attempt
|
||||
* temporarily and start SA Query, if one is not pending.
|
||||
*/
|
||||
if (sta->sa_query_count == 0)
|
||||
ap_sta_start_sa_query(hapd, sta);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *req_ies, size_t req_ies_len, int reassoc)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
int new_assoc, res;
|
||||
int new_assoc;
|
||||
enum wpa_validate_result res;
|
||||
struct ieee802_11_elems elems;
|
||||
const u8 *ie;
|
||||
size_t ielen;
|
||||
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
|
||||
u8 *p = buf;
|
||||
u16 reason = WLAN_REASON_UNSPECIFIED;
|
||||
u16 status = WLAN_STATUS_SUCCESS;
|
||||
int status = WLAN_STATUS_SUCCESS;
|
||||
const u8 *p2p_dev_addr = NULL;
|
||||
|
||||
if (addr == NULL) {
|
||||
@ -226,7 +253,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
#ifdef NEED_AP_MLME
|
||||
if (elems.ht_capabilities &&
|
||||
(hapd->iface->conf->ht_capab &
|
||||
@ -240,7 +266,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
ht40_intolerant_add(hapd->iface, sta);
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
if (elems.ext_capab && elems.ext_capab_len > 4) {
|
||||
@ -300,6 +325,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
|
||||
struct wpabuf *wps;
|
||||
|
||||
if (check_sa_query_need(hapd, sta)) {
|
||||
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
|
||||
|
||||
p = hostapd_eid_assoc_comeback_time(hapd, sta,
|
||||
p);
|
||||
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status,
|
||||
buf, p - buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sta->flags |= WLAN_STA_WPS;
|
||||
wps = ieee802_11_vendor_ie_concat(ie, ielen,
|
||||
WPS_IE_VENDOR_TYPE);
|
||||
@ -331,55 +367,71 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
elems.rsnxe ? elems.rsnxe_len + 2 : 0,
|
||||
elems.mdie, elems.mdie_len,
|
||||
elems.owe_dh, elems.owe_dh_len);
|
||||
if (res != WPA_IE_OK) {
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
switch (res) {
|
||||
case WPA_IE_OK:
|
||||
reason = WLAN_REASON_UNSPECIFIED;
|
||||
status = WLAN_STATUS_SUCCESS;
|
||||
break;
|
||||
case WPA_INVALID_IE:
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
break;
|
||||
case WPA_INVALID_GROUP:
|
||||
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
|
||||
status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
|
||||
break;
|
||||
case WPA_INVALID_PAIRWISE:
|
||||
reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
|
||||
status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
|
||||
break;
|
||||
case WPA_INVALID_AKMP:
|
||||
reason = WLAN_REASON_AKMP_NOT_VALID;
|
||||
status = WLAN_STATUS_AKMP_NOT_VALID;
|
||||
break;
|
||||
case WPA_NOT_ENABLED:
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
break;
|
||||
case WPA_ALLOC_FAIL:
|
||||
reason = WLAN_REASON_UNSPECIFIED;
|
||||
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
break;
|
||||
case WPA_MGMT_FRAME_PROTECTION_VIOLATION:
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
break;
|
||||
case WPA_INVALID_MGMT_GROUP_CIPHER:
|
||||
reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
|
||||
status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
|
||||
break;
|
||||
case WPA_INVALID_MDIE:
|
||||
reason = WLAN_REASON_INVALID_MDE;
|
||||
status = WLAN_STATUS_INVALID_MDIE;
|
||||
break;
|
||||
case WPA_INVALID_PROTO:
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
break;
|
||||
case WPA_INVALID_PMKID:
|
||||
reason = WLAN_REASON_INVALID_PMKID;
|
||||
status = WLAN_STATUS_INVALID_PMKID;
|
||||
break;
|
||||
case WPA_DENIED_OTHER_REASON:
|
||||
reason = WLAN_REASON_UNSPECIFIED;
|
||||
status = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
|
||||
break;
|
||||
}
|
||||
if (status != WLAN_STATUS_SUCCESS) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA/RSN information element rejected? (res %u)",
|
||||
res);
|
||||
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
|
||||
if (res == WPA_INVALID_GROUP) {
|
||||
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
|
||||
status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
|
||||
} else if (res == WPA_INVALID_PAIRWISE) {
|
||||
reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
|
||||
status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
|
||||
} else if (res == WPA_INVALID_AKMP) {
|
||||
reason = WLAN_REASON_AKMP_NOT_VALID;
|
||||
status = WLAN_STATUS_AKMP_NOT_VALID;
|
||||
} else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
|
||||
reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
|
||||
status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
|
||||
} else if (res == WPA_INVALID_PMKID) {
|
||||
reason = WLAN_REASON_INVALID_PMKID;
|
||||
status = WLAN_STATUS_INVALID_PMKID;
|
||||
} else {
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
|
||||
!sta->sa_query_timed_out &&
|
||||
sta->sa_query_count > 0)
|
||||
ap_check_sa_query_timeout(hapd, sta);
|
||||
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
|
||||
!sta->sa_query_timed_out &&
|
||||
(sta->auth_alg != WLAN_AUTH_FT)) {
|
||||
/*
|
||||
* STA has already been associated with MFP and SA
|
||||
* Query timeout has not been reached. Reject the
|
||||
* association attempt temporarily and start SA Query,
|
||||
* if one is not pending.
|
||||
*/
|
||||
|
||||
if (sta->sa_query_count == 0)
|
||||
ap_sta_start_sa_query(hapd, sta);
|
||||
|
||||
if (check_sa_query_need(hapd, sta)) {
|
||||
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
|
||||
|
||||
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
|
||||
@ -412,7 +464,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
#ifdef CONFIG_SAE
|
||||
if (hapd->conf->sae_pwe == 2 &&
|
||||
sta->auth_alg == WLAN_AUTH_SAE &&
|
||||
sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
|
||||
sta->sae && !sta->sae->h2e &&
|
||||
elems.rsnxe && elems.rsnxe_len >= 1 &&
|
||||
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
|
||||
wpa_printf(MSG_INFO, "SAE: " MACSTR
|
||||
@ -475,6 +527,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
return WLAN_STATUS_INVALID_IE;
|
||||
#endif /* CONFIG_HS20 */
|
||||
}
|
||||
#ifdef CONFIG_WPS
|
||||
skip_wpa_check:
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
|
||||
@ -486,13 +541,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
skip_wpa_check:
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
|
||||
sta->auth_alg, req_ies, req_ies_len);
|
||||
sta->auth_alg, req_ies, req_ies_len,
|
||||
!elems.rsnxe);
|
||||
if (!p) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
@ -579,17 +631,19 @@ skip_wpa_check:
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
|
||||
elems.owe_dh) {
|
||||
u8 *npos;
|
||||
u16 ret_status;
|
||||
|
||||
npos = owe_assoc_req_process(hapd, sta,
|
||||
elems.owe_dh, elems.owe_dh_len,
|
||||
p, sizeof(buf) - (p - buf),
|
||||
&status);
|
||||
&ret_status);
|
||||
status = ret_status;
|
||||
if (npos)
|
||||
p = npos;
|
||||
|
||||
if (!npos &&
|
||||
status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, ret_status, buf,
|
||||
p - buf);
|
||||
return 0;
|
||||
}
|
||||
@ -631,6 +685,11 @@ skip_wpa_check:
|
||||
pfs_fail:
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
if (elems.rrm_enabled &&
|
||||
elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
|
||||
os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
|
||||
sizeof(sta->rrm_enabled_capa));
|
||||
|
||||
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
|
||||
@ -677,7 +736,8 @@ skip_wpa_check:
|
||||
|
||||
fail:
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
if (status >= 0)
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
|
||||
ap_free_sta(hapd, sta);
|
||||
@ -715,6 +775,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
|
||||
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
|
||||
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||
@ -808,8 +869,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
int offset, int width, int cf1, int cf2,
|
||||
int finished)
|
||||
{
|
||||
/* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
int channel, chwidth, is_dfs;
|
||||
u8 seg0_idx = 0, seg1_idx = 0;
|
||||
@ -859,9 +918,18 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
|
||||
switch (hapd->iface->current_mode->mode) {
|
||||
case HOSTAPD_MODE_IEEE80211A:
|
||||
if (cf1 > 5000)
|
||||
if (cf1 == 5935)
|
||||
seg0_idx = (cf1 - 5925) / 5;
|
||||
else if (cf1 > 5950)
|
||||
seg0_idx = (cf1 - 5950) / 5;
|
||||
else if (cf1 > 5000)
|
||||
seg0_idx = (cf1 - 5000) / 5;
|
||||
if (cf2 > 5000)
|
||||
|
||||
if (cf2 == 5935)
|
||||
seg1_idx = (cf2 - 5925) / 5;
|
||||
else if (cf2 > 5950)
|
||||
seg1_idx = (cf2 - 5950) / 5;
|
||||
else if (cf2 > 5000)
|
||||
seg1_idx = (cf2 - 5000) / 5;
|
||||
break;
|
||||
default:
|
||||
@ -912,10 +980,39 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
|
||||
"freq=%d dfs=%d", freq, is_dfs);
|
||||
} else if (is_dfs &&
|
||||
hostapd_is_dfs_required(hapd->iface) &&
|
||||
!hostapd_is_dfs_chan_available(hapd->iface) &&
|
||||
!hapd->iface->cac_started) {
|
||||
hostapd_disable_iface(hapd->iface);
|
||||
hostapd_enable_iface(hapd->iface);
|
||||
}
|
||||
|
||||
for (i = 0; i < hapd->iface->num_bss; i++)
|
||||
hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if (hapd->conf->ocv) {
|
||||
struct sta_info *sta;
|
||||
bool check_sa_query = false;
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (wpa_auth_uses_ocv(sta->wpa_sm) &&
|
||||
!(sta->flags & WLAN_STA_WNM_SLEEP_MODE)) {
|
||||
sta->post_csa_sa_query = 1;
|
||||
check_sa_query = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (check_sa_query) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OCV: Check post-CSA SA Query initiation in 15 seconds");
|
||||
eloop_register_timeout(15, 0,
|
||||
hostapd_ocv_check_csa_sa_query,
|
||||
hapd, NULL);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
|
||||
@ -1011,6 +1108,8 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
hapd->iconf->edmg_channel = acs_res->edmg_channel;
|
||||
|
||||
if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
|
||||
/* set defaults for backwards compatibility */
|
||||
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
|
||||
@ -1433,15 +1532,33 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
|
||||
#endif /* HOSTAPD */
|
||||
|
||||
|
||||
static struct hostapd_channel_data *
|
||||
hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
chan = &mode->channels[i];
|
||||
if ((unsigned int) chan->freq == freq)
|
||||
return chan;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_channel_data * hostapd_get_mode_channel(
|
||||
struct hostapd_iface *iface, unsigned int freq)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
if ((unsigned int) chan->freq == freq)
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
|
||||
continue;
|
||||
chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
|
||||
if (chan)
|
||||
return chan;
|
||||
}
|
||||
|
||||
|
@ -1555,11 +1555,14 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
|
||||
di->prot = prot;
|
||||
di->sd_resp = buf;
|
||||
di->sd_resp_pos = 0;
|
||||
di->dpp = 1;
|
||||
tx_buf = gas_build_initial_resp(
|
||||
dialog_token, WLAN_STATUS_SUCCESS,
|
||||
comeback_delay, 10);
|
||||
if (tx_buf)
|
||||
comeback_delay, 10 + 2);
|
||||
if (tx_buf) {
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
wpabuf_put_le16(tx_buf, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -1782,9 +1785,10 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
|
||||
tx_buf = gas_build_comeback_resp(dialog_token,
|
||||
WLAN_STATUS_SUCCESS,
|
||||
dialog->sd_frag_id, more, 0,
|
||||
10 + frag_len);
|
||||
10 + 2 + frag_len);
|
||||
if (tx_buf) {
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
wpabuf_put_le16(tx_buf, frag_len);
|
||||
wpabuf_put_buf(tx_buf, buf);
|
||||
}
|
||||
} else
|
||||
|
115
src/ap/hostapd.c
115
src/ap/hostapd.c
@ -58,8 +58,10 @@
|
||||
|
||||
|
||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
||||
#ifdef CONFIG_WEP
|
||||
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
|
||||
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
|
||||
#endif /* CONFIG_WEP */
|
||||
static int setup_interface2(struct hostapd_iface *iface);
|
||||
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
|
||||
@ -74,6 +76,8 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < interfaces->count; i++) {
|
||||
if (!interfaces->iface[i])
|
||||
continue;
|
||||
ret = cb(interfaces->iface[i], ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -89,7 +93,9 @@ void hostapd_reconfig_encryption(struct hostapd_data *hapd)
|
||||
return;
|
||||
|
||||
hostapd_set_privacy(hapd, 0);
|
||||
#ifdef CONFIG_WEP
|
||||
hostapd_setup_encryption(hapd->conf->iface, hapd);
|
||||
#endif /* CONFIG_WEP */
|
||||
}
|
||||
|
||||
|
||||
@ -142,7 +148,9 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
|
||||
wpa_deinit(hapd->wpa_auth);
|
||||
hapd->wpa_auth = NULL;
|
||||
hostapd_set_privacy(hapd, 0);
|
||||
#ifdef CONFIG_WEP
|
||||
hostapd_setup_encryption(hapd->conf->iface, hapd);
|
||||
#endif /* CONFIG_WEP */
|
||||
hostapd_set_generic_elem(hapd, (u8 *) "", 0);
|
||||
}
|
||||
|
||||
@ -170,7 +178,9 @@ static void hostapd_clear_old(struct hostapd_iface *iface)
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
hostapd_flush_old_stations(iface->bss[j],
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
#ifdef CONFIG_WEP
|
||||
hostapd_broadcast_wep_clear(iface->bss[j]);
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
/* TODO: update dynamic data based on changed configuration
|
||||
@ -284,6 +294,8 @@ int hostapd_reload_config(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
|
||||
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
|
||||
const char *ifname)
|
||||
{
|
||||
@ -326,7 +338,7 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
|
||||
struct hostapd_ssid *ssid = &hapd->conf->ssid;
|
||||
|
||||
idx = ssid->wep.idx;
|
||||
if (ssid->wep.default_len &&
|
||||
if (ssid->wep.default_len && ssid->wep.key[idx] &&
|
||||
hostapd_drv_set_key(hapd->conf->iface,
|
||||
hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0,
|
||||
1, NULL, 0, ssid->wep.key[idx],
|
||||
@ -339,8 +351,10 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
|
||||
return errors;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
|
||||
void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
{
|
||||
os_free(hapd->probereq_cb);
|
||||
hapd->probereq_cb = NULL;
|
||||
@ -420,11 +434,17 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
#ifdef CONFIG_MESH
|
||||
wpabuf_free(hapd->mesh_pending_auth);
|
||||
hapd->mesh_pending_auth = NULL;
|
||||
/* handling setup failure is already done */
|
||||
hapd->setup_complete_cb = NULL;
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
hostapd_clean_rrm(hapd);
|
||||
fils_hlp_deinit(hapd);
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
eloop_cancel_timeout(hostapd_ocv_check_csa_sa_query, hapd, NULL);
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
{
|
||||
struct hostapd_sae_commit_queue *q;
|
||||
@ -478,14 +498,12 @@ static void sta_track_deinit(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
|
||||
void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
#ifdef NEED_AP_MLME
|
||||
hostapd_stop_setup_timers(iface);
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
if (iface->current_mode)
|
||||
acs_cleanup(iface);
|
||||
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
|
||||
@ -526,6 +544,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
|
||||
static void hostapd_clear_wep(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) {
|
||||
@ -573,6 +593,8 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
|
||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
|
||||
{
|
||||
@ -604,11 +626,13 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
|
||||
void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
|
||||
{
|
||||
hostapd_free_stas(hapd);
|
||||
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
|
||||
#ifdef CONFIG_WEP
|
||||
hostapd_clear_wep(hapd);
|
||||
#endif /* CONFIG_WEP */
|
||||
}
|
||||
|
||||
|
||||
@ -1159,13 +1183,15 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
if (flush_old_stations)
|
||||
hostapd_flush_old_stations(hapd,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
hostapd_flush(hapd);
|
||||
hostapd_set_privacy(hapd, 0);
|
||||
|
||||
hostapd_broadcast_wep_clear(hapd);
|
||||
#ifdef CONFIG_WEP
|
||||
if (!hostapd_drv_nl80211(hapd))
|
||||
hostapd_broadcast_wep_clear(hapd);
|
||||
if (hostapd_setup_encryption(conf->iface, hapd))
|
||||
return -1;
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
/*
|
||||
* Fetch the SSID from the system and use it or,
|
||||
@ -1351,6 +1377,21 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
|
||||
return -1;
|
||||
|
||||
if (flush_old_stations && !conf->start_disabled &&
|
||||
conf->broadcast_deauth) {
|
||||
u8 addr[ETH_ALEN];
|
||||
|
||||
/* Should any previously associated STA not have noticed that
|
||||
* the AP had stopped and restarted, send one more
|
||||
* deauthentication notification now that the AP is ready to
|
||||
* operate. */
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Deauthenticate all stations at BSS start");
|
||||
os_memset(addr, 0xff, ETH_ALEN);
|
||||
hostapd_drv_sta_deauth(hapd, addr,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
}
|
||||
|
||||
if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
|
||||
return -1;
|
||||
|
||||
@ -1754,7 +1795,7 @@ static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr,
|
||||
|
||||
|
||||
static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
|
||||
Boolean mb_only)
|
||||
bool mb_only)
|
||||
{
|
||||
struct sta_info *s = (struct sta_info *) *get_ctx;
|
||||
|
||||
@ -1776,7 +1817,7 @@ static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
|
||||
|
||||
static const u8 * fst_hostapd_get_peer_first(void *ctx,
|
||||
struct fst_get_peer_ctx **get_ctx,
|
||||
Boolean mb_only)
|
||||
bool mb_only)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
|
||||
@ -1788,7 +1829,7 @@ static const u8 * fst_hostapd_get_peer_first(void *ctx,
|
||||
|
||||
static const u8 * fst_hostapd_get_peer_next(void *ctx,
|
||||
struct fst_get_peer_ctx **get_ctx,
|
||||
Boolean mb_only)
|
||||
bool mb_only)
|
||||
{
|
||||
return fst_hostapd_get_sta(get_ctx, mb_only);
|
||||
}
|
||||
@ -1876,6 +1917,13 @@ static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
|
||||
|
||||
if (!bss->conf->owe_transition_ifname[0])
|
||||
continue;
|
||||
if (bss->iface->state != HAPD_IFACE_ENABLED) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Interface %s state %s - defer beacon update",
|
||||
bss->conf->iface,
|
||||
hostapd_state_text(bss->iface->state));
|
||||
continue;
|
||||
}
|
||||
res = hostapd_owe_trans_get_info(bss);
|
||||
if (res == 0)
|
||||
continue;
|
||||
@ -2110,6 +2158,13 @@ dfs_offload:
|
||||
if (hapd->setup_complete_cb)
|
||||
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
if (delay_apply_cfg && !iface->mconf) {
|
||||
wpa_printf(MSG_ERROR, "Error while completing mesh init");
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
|
||||
iface->bss[0]->conf->iface);
|
||||
if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
|
||||
@ -2253,7 +2308,7 @@ int hostapd_setup_interface(struct hostapd_iface *iface)
|
||||
ret = setup_interface(iface);
|
||||
if (ret) {
|
||||
wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
|
||||
iface->bss[0]->conf->iface);
|
||||
iface->conf ? iface->conf->bss[0]->iface : "N/A");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2349,12 +2404,10 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||
hostapd_bss_deinit(iface->bss[j]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
#ifdef NEED_AP_MLME
|
||||
hostapd_stop_setup_timers(iface);
|
||||
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
}
|
||||
|
||||
|
||||
@ -2637,6 +2690,12 @@ int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
|
||||
{
|
||||
size_t j;
|
||||
|
||||
if (!hapd_iface)
|
||||
return -1;
|
||||
|
||||
if (hapd_iface->enable_iface_cb)
|
||||
return hapd_iface->enable_iface_cb(hapd_iface);
|
||||
|
||||
if (hapd_iface->bss[0]->drv_priv != NULL) {
|
||||
wpa_printf(MSG_ERROR, "Interface %s already enabled",
|
||||
hapd_iface->conf->bss[0]->iface);
|
||||
@ -2698,6 +2757,9 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
|
||||
if (hapd_iface == NULL)
|
||||
return -1;
|
||||
|
||||
if (hapd_iface->disable_iface_cb)
|
||||
return hapd_iface->disable_iface_cb(hapd_iface);
|
||||
|
||||
if (hapd_iface->bss[0]->drv_priv == NULL) {
|
||||
wpa_printf(MSG_INFO, "Interface %s already disabled",
|
||||
hapd_iface->conf->bss[0]->iface);
|
||||
@ -3118,6 +3180,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
||||
hostapd_prune_associations(hapd, sta->addr);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
sta->post_csa_sa_query = 0;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
|
||||
@ -3629,3 +3692,25 @@ void hostapd_periodic_iface(struct hostapd_iface *iface)
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OCV: Post-CSA SA Query initiation check");
|
||||
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (!sta->post_csa_sa_query)
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "OCV: OCVC STA " MACSTR
|
||||
" did not start SA Query after CSA - disconnect",
|
||||
MAC2STR(sta->addr));
|
||||
ap_sta_disconnect(hapd, sta, sta->addr,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
@ -38,6 +38,10 @@ union wps_event_data;
|
||||
struct mesh_conf;
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
#define CTRL_IFACE_COOKIE_LEN 8
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
struct hostapd_iface;
|
||||
|
||||
struct hapd_interfaces {
|
||||
@ -72,6 +76,11 @@ struct hapd_interfaces {
|
||||
#ifdef CONFIG_DPP
|
||||
struct dpp_global *dpp;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
};
|
||||
|
||||
enum hostapd_chan_status {
|
||||
@ -340,6 +349,11 @@ struct hostapd_data {
|
||||
int last_igtk_key_idx;
|
||||
u8 last_igtk[WPA_IGTK_MAX_LEN];
|
||||
size_t last_igtk_len;
|
||||
|
||||
enum wpa_alg last_bigtk_alg;
|
||||
int last_bigtk_key_idx;
|
||||
u8 last_bigtk[WPA_BIGTK_MAX_LEN];
|
||||
size_t last_bigtk_len;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
@ -377,6 +391,16 @@ struct hostapd_data {
|
||||
unsigned int dpp_resp_wait_time;
|
||||
unsigned int dpp_resp_max_tries;
|
||||
unsigned int dpp_resp_retry_time;
|
||||
#ifdef CONFIG_DPP2
|
||||
struct wpabuf *dpp_presence_announcement;
|
||||
struct dpp_bootstrap_info *dpp_chirp_bi;
|
||||
int dpp_chirp_freq;
|
||||
int *dpp_chirp_freqs;
|
||||
int dpp_chirp_iter;
|
||||
int dpp_chirp_round;
|
||||
int dpp_chirp_scan_done;
|
||||
int dpp_chirp_listen;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
char *dpp_config_obj_override;
|
||||
char *dpp_discovery_override;
|
||||
@ -395,6 +419,10 @@ struct hostapd_data {
|
||||
#ifdef CONFIG_SQLITE
|
||||
sqlite3 *rad_attr_db;
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
};
|
||||
|
||||
|
||||
@ -462,9 +490,7 @@ struct hostapd_iface {
|
||||
struct ap_info *ap_hash[STA_HASH_SIZE];
|
||||
|
||||
u64 drv_flags;
|
||||
|
||||
/* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
|
||||
unsigned int smps_modes;
|
||||
u64 drv_flags2;
|
||||
|
||||
/*
|
||||
* A bitmap of supported protocols for probe response offload. See
|
||||
@ -563,6 +589,9 @@ struct hostapd_iface {
|
||||
|
||||
/* Previous WMM element information */
|
||||
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
|
||||
|
||||
int (*enable_iface_cb)(struct hostapd_iface *iface);
|
||||
int (*disable_iface_cb)(struct hostapd_iface *iface);
|
||||
};
|
||||
|
||||
/* hostapd.c */
|
||||
@ -591,6 +620,9 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface);
|
||||
int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
|
||||
int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
|
||||
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
|
||||
void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
|
||||
void hostapd_free_hapd_data(struct hostapd_data *hapd);
|
||||
void hostapd_cleanup_iface_partial(struct hostapd_iface *iface);
|
||||
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
|
||||
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
|
||||
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
|
||||
@ -606,6 +638,7 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
|
||||
void hostapd_periodic_iface(struct hostapd_iface *iface);
|
||||
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
|
||||
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
|
||||
|
||||
/* utils.c */
|
||||
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
|
@ -224,7 +224,6 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
|
||||
{
|
||||
int pri_freq, sec_freq;
|
||||
@ -561,26 +560,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (conf & HT_CAP_INFO_SMPS_MASK) {
|
||||
case HT_CAP_INFO_SMPS_STATIC:
|
||||
if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Driver does not support configured HT capability [SMPS-STATIC]");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case HT_CAP_INFO_SMPS_DYNAMIC:
|
||||
if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Driver does not support configured HT capability [SMPS-DYNAMIC]");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case HT_CAP_INFO_SMPS_DISABLED:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
|
||||
!(hw & HT_CAP_INFO_GREEN_FIELD)) {
|
||||
wpa_printf(MSG_ERROR, "Driver does not support configured "
|
||||
@ -687,12 +666,9 @@ static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface)
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
|
||||
int hostapd_check_ht_capab(struct hostapd_iface *iface)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
int ret;
|
||||
|
||||
if (is_6ghz_freq(iface->freq))
|
||||
@ -725,7 +701,6 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
|
||||
return ret;
|
||||
if (!ieee80211n_allowed_ht40_channel_pair(iface))
|
||||
return -1;
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -810,7 +785,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
|
||||
|
||||
/* 60 GHz channels 1..6 */
|
||||
for (i = 0; i < 6; i++) {
|
||||
int freq = 56160 + 2160 * i;
|
||||
int freq = 56160 + 2160 * (i + 1);
|
||||
|
||||
if (edmg.channels & BIT(i)) {
|
||||
contiguous++;
|
||||
@ -904,10 +879,43 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_determine_mode(struct hostapd_iface *iface)
|
||||
{
|
||||
int i;
|
||||
enum hostapd_hw_mode target_mode;
|
||||
|
||||
if (iface->current_mode ||
|
||||
iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
|
||||
return;
|
||||
|
||||
if (iface->freq < 4000)
|
||||
target_mode = HOSTAPD_MODE_IEEE80211G;
|
||||
else if (iface->freq > 50000)
|
||||
target_mode = HOSTAPD_MODE_IEEE80211AD;
|
||||
else
|
||||
target_mode = HOSTAPD_MODE_IEEE80211A;
|
||||
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
struct hostapd_hw_modes *mode;
|
||||
|
||||
mode = &iface->hw_features[i];
|
||||
if (mode->mode == target_mode) {
|
||||
iface->current_mode = mode;
|
||||
iface->conf->hw_mode = mode->mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iface->current_mode)
|
||||
wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
|
||||
}
|
||||
|
||||
|
||||
static enum hostapd_chan_status
|
||||
hostapd_check_chans(struct hostapd_iface *iface)
|
||||
{
|
||||
if (iface->freq) {
|
||||
hostapd_determine_mode(iface);
|
||||
if (hostapd_is_usable_chans(iface))
|
||||
return HOSTAPD_CHAN_VALID;
|
||||
else
|
||||
@ -1033,9 +1041,15 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
if (iface->current_mode == NULL) {
|
||||
if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
|
||||
!(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
|
||||
{
|
||||
if ((iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
|
||||
(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Using offloaded hw_mode=any ACS");
|
||||
} else if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) &&
|
||||
iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211ANY) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Using internal ACS for hw_mode=any");
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Hardware does not support configured mode");
|
||||
hostapd_logger(iface->bss[0], NULL,
|
||||
@ -1110,3 +1124,20 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_hw_skip_mode(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (iface->current_mode)
|
||||
return mode != iface->current_mode;
|
||||
if (mode->mode != HOSTAPD_MODE_IEEE80211B)
|
||||
return 0;
|
||||
for (i = 0; i < iface->num_hw_features; i++) {
|
||||
if (iface->hw_features[i].mode == HOSTAPD_MODE_IEEE80211G)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ int hostapd_check_edmg_capab(struct hostapd_iface *iface);
|
||||
int hostapd_prepare_rates(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode);
|
||||
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
|
||||
int hostapd_hw_skip_mode(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode);
|
||||
#else /* NEED_AP_MLME */
|
||||
static inline void
|
||||
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||
@ -77,6 +79,12 @@ static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int hostapd_hw_skip_mode(struct hostapd_iface *iface,
|
||||
struct hostapd_hw_modes *mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
#endif /* HW_FEATURES_H */
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "common/dpp.h"
|
||||
#include "common/ocv.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "p2p/p2p.h"
|
||||
@ -224,7 +225,7 @@ u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
u16 hostapd_own_capab_info(struct hostapd_data *hapd)
|
||||
{
|
||||
int capab = WLAN_CAPABILITY_ESS;
|
||||
int privacy;
|
||||
int privacy = 0;
|
||||
int dfs;
|
||||
int i;
|
||||
|
||||
@ -240,12 +241,14 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
|
||||
hapd->iconf->preamble == SHORT_PREAMBLE)
|
||||
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
privacy = hapd->conf->ssid.wep.keys_set;
|
||||
|
||||
if (hapd->conf->ieee802_1x &&
|
||||
(hapd->conf->default_wep_key_len ||
|
||||
hapd->conf->individual_wep_key_len))
|
||||
privacy = 1;
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
if (hapd->conf->wpa)
|
||||
privacy = 1;
|
||||
@ -285,6 +288,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
#ifndef CONFIG_NO_RC4
|
||||
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 auth_transaction, const u8 *challenge,
|
||||
@ -341,6 +345,7 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
|
||||
static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
@ -380,9 +385,10 @@ static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
#ifdef CONFIG_SAE
|
||||
if (hapd->conf->sae_confirm_immediate == 2 &&
|
||||
auth_alg == WLAN_AUTH_SAE) {
|
||||
if (auth_transaction == 1 &&
|
||||
if (auth_transaction == 1 && sta &&
|
||||
(resp == WLAN_STATUS_SUCCESS ||
|
||||
resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) {
|
||||
resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
|
||||
resp == WLAN_STATUS_SAE_PK)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"TESTING: Postpone SAE Commit transmission until Confirm is ready");
|
||||
os_free(sta->sae_postponed_commit);
|
||||
@ -474,17 +480,23 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
|
||||
const char *rx_id = NULL;
|
||||
int use_pt = 0;
|
||||
struct sae_pt *pt = NULL;
|
||||
const struct sae_pk *pk = NULL;
|
||||
|
||||
if (sta->sae->tmp) {
|
||||
rx_id = sta->sae->tmp->pw_id;
|
||||
use_pt = sta->sae->tmp->h2e;
|
||||
use_pt = sta->sae->h2e;
|
||||
#ifdef CONFIG_SAE_PK
|
||||
os_memcpy(sta->sae->tmp->own_addr, hapd->own_addr, ETH_ALEN);
|
||||
os_memcpy(sta->sae->tmp->peer_addr, sta->addr, ETH_ALEN);
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
}
|
||||
|
||||
if (rx_id && hapd->conf->sae_pwe != 3)
|
||||
use_pt = 1;
|
||||
else if (status_code == WLAN_STATUS_SUCCESS)
|
||||
use_pt = 0;
|
||||
else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
|
||||
else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
|
||||
status_code == WLAN_STATUS_SAE_PK)
|
||||
use_pt = 1;
|
||||
|
||||
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
|
||||
@ -498,6 +510,8 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
|
||||
continue;
|
||||
password = pw->password;
|
||||
pt = pw->pt;
|
||||
if (!(hapd->conf->mesh & MESH_ENABLED))
|
||||
pk = pw->pk;
|
||||
break;
|
||||
}
|
||||
if (!password) {
|
||||
@ -511,7 +525,7 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
|
||||
|
||||
if (update && use_pt &&
|
||||
sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
|
||||
NULL) < 0)
|
||||
NULL, pk) < 0)
|
||||
return NULL;
|
||||
|
||||
if (update && !use_pt &&
|
||||
@ -533,10 +547,13 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
|
||||
|
||||
buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN +
|
||||
(rx_id ? 3 + os_strlen(rx_id) : 0));
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
sae_write_commit(sta->sae, buf, sta->sae->tmp ?
|
||||
sta->sae->tmp->anti_clogging_token : NULL, rx_id);
|
||||
if (buf &&
|
||||
sae_write_commit(sta->sae, buf, sta->sae->tmp ?
|
||||
sta->sae->tmp->anti_clogging_token : NULL,
|
||||
rx_id) < 0) {
|
||||
wpabuf_free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -551,7 +568,17 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
sae_write_confirm(sta->sae, buf);
|
||||
#ifdef CONFIG_SAE_PK
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (sta->sae->tmp)
|
||||
sta->sae->tmp->omit_pk_elem = hapd->conf->sae_pk_omit;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
if (sae_write_confirm(sta->sae, buf) < 0) {
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -571,8 +598,21 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
|
||||
if (data == NULL)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
|
||||
status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
|
||||
WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
|
||||
if (sta->sae->tmp && sta->sae->pk)
|
||||
status = WLAN_STATUS_SAE_PK;
|
||||
else if (sta->sae->tmp && sta->sae->h2e)
|
||||
status = WLAN_STATUS_SAE_HASH_TO_ELEMENT;
|
||||
else
|
||||
status = WLAN_STATUS_SUCCESS;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->conf->sae_commit_status >= 0 &&
|
||||
hapd->conf->sae_commit_status != status) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"TESTING: Override SAE commit status code %u --> %d",
|
||||
status, hapd->conf->sae_commit_status);
|
||||
status = hapd->conf->sae_commit_status;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
|
||||
WLAN_AUTH_SAE, 1,
|
||||
status, wpabuf_head(data),
|
||||
@ -636,13 +676,15 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr)
|
||||
static int sae_token_hash(struct hostapd_data *hapd, const u8 *addr, u8 *idx)
|
||||
{
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
|
||||
hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
|
||||
addr, ETH_ALEN, hash);
|
||||
return hash[0];
|
||||
if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
|
||||
addr, ETH_ALEN, hash) < 0)
|
||||
return -1;
|
||||
*idx = hash[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -655,9 +697,8 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
|
||||
u16 token_idx;
|
||||
u8 idx;
|
||||
|
||||
if (token_len != SHA256_MAC_LEN)
|
||||
if (token_len != SHA256_MAC_LEN || sae_token_hash(hapd, addr, &idx) < 0)
|
||||
return -1;
|
||||
idx = sae_token_hash(hapd, addr);
|
||||
token_idx = hapd->sae_pending_token_idx[idx];
|
||||
if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
|
||||
@ -721,7 +762,10 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
|
||||
}
|
||||
|
||||
p_idx = sae_token_hash(hapd, addr);
|
||||
if (sae_token_hash(hapd, addr, &p_idx) < 0) {
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
token_idx = hapd->sae_pending_token_idx[p_idx];
|
||||
if (!token_idx) {
|
||||
hapd->sae_token_idx++;
|
||||
@ -889,9 +933,14 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
switch (sta->sae->state) {
|
||||
case SAE_NOTHING:
|
||||
if (auth_transaction == 1) {
|
||||
if (sta->sae->tmp)
|
||||
sta->sae->tmp->h2e = status_code ==
|
||||
WLAN_STATUS_SAE_HASH_TO_ELEMENT;
|
||||
if (sta->sae->tmp) {
|
||||
sta->sae->h2e =
|
||||
(status_code ==
|
||||
WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
|
||||
status_code == WLAN_STATUS_SAE_PK);
|
||||
sta->sae->pk =
|
||||
status_code == WLAN_STATUS_SAE_PK;
|
||||
}
|
||||
ret = auth_sae_send_commit(hapd, sta, bssid,
|
||||
!allow_reuse, status_code);
|
||||
if (ret)
|
||||
@ -1101,20 +1150,28 @@ static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
|
||||
{
|
||||
int sae_pwe = hapd->conf->sae_pwe;
|
||||
int id_in_use;
|
||||
bool sae_pk = false;
|
||||
|
||||
id_in_use = hostapd_sae_pw_id_in_use(hapd->conf);
|
||||
if (id_in_use == 2 && sae_pwe != 3)
|
||||
sae_pwe = 1;
|
||||
else if (id_in_use == 1 && sae_pwe == 0)
|
||||
sae_pwe = 2;
|
||||
#ifdef CONFIG_SAE_PK
|
||||
sae_pk = hostapd_sae_pk_in_use(hapd->conf);
|
||||
if (sae_pwe == 0 && sae_pk)
|
||||
sae_pwe = 2;
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
return ((sae_pwe == 0 || sae_pwe == 3) &&
|
||||
status_code == WLAN_STATUS_SUCCESS) ||
|
||||
(sae_pwe == 1 &&
|
||||
status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
|
||||
(status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
|
||||
(sae_pk && status_code == WLAN_STATUS_SAE_PK))) ||
|
||||
(sae_pwe == 2 &&
|
||||
(status_code == WLAN_STATUS_SUCCESS ||
|
||||
status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
|
||||
status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
|
||||
(sae_pk && status_code == WLAN_STATUS_SAE_PK)));
|
||||
}
|
||||
|
||||
|
||||
@ -1137,11 +1194,15 @@ static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
|
||||
|
||||
|
||||
static int check_sae_rejected_groups(struct hostapd_data *hapd,
|
||||
const struct wpabuf *groups)
|
||||
struct sae_data *sae)
|
||||
{
|
||||
const struct wpabuf *groups;
|
||||
size_t i, count;
|
||||
const u8 *pos;
|
||||
|
||||
if (!sae->tmp)
|
||||
return 0;
|
||||
groups = sae->tmp->peer_rejected_groups;
|
||||
if (!groups)
|
||||
return 0;
|
||||
|
||||
@ -1183,6 +1244,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack");
|
||||
pos = mgmt->u.auth.variable;
|
||||
end = ((const u8 *) mgmt) + len;
|
||||
resp = status_code;
|
||||
send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
|
||||
auth_transaction, resp, pos, end - pos,
|
||||
"auth-sae-reflection-attack");
|
||||
@ -1328,7 +1390,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
((const u8 *) mgmt) + len -
|
||||
mgmt->u.auth.variable, &token,
|
||||
&token_len, groups, status_code ==
|
||||
WLAN_STATUS_SAE_HASH_TO_ELEMENT);
|
||||
WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
|
||||
status_code == WLAN_STATUS_SAE_PK);
|
||||
if (resp == SAE_SILENTLY_DISCARD) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"SAE: Drop commit message from " MACSTR " due to reflection attack",
|
||||
@ -1358,9 +1421,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
goto reply;
|
||||
|
||||
if (sta->sae->tmp &&
|
||||
check_sae_rejected_groups(
|
||||
hapd, sta->sae->tmp->peer_rejected_groups)) {
|
||||
if (check_sae_rejected_groups(hapd, sta->sae)) {
|
||||
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
goto reply;
|
||||
}
|
||||
@ -1372,8 +1433,9 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
"SAE: Request anti-clogging token from "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
if (sta->sae->tmp)
|
||||
h2e = sta->sae->tmp->h2e;
|
||||
if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
|
||||
h2e = sta->sae->h2e;
|
||||
if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
|
||||
status_code == WLAN_STATUS_SAE_PK)
|
||||
h2e = 1;
|
||||
data = auth_build_token_req(hapd, sta->sae->group,
|
||||
sta->addr, h2e);
|
||||
@ -1601,27 +1663,37 @@ static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr)
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
|
||||
static u16 wpa_res_to_status_code(int res)
|
||||
static u16 wpa_res_to_status_code(enum wpa_validate_result res)
|
||||
{
|
||||
if (res == WPA_INVALID_GROUP)
|
||||
return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
|
||||
if (res == WPA_INVALID_PAIRWISE)
|
||||
return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
|
||||
if (res == WPA_INVALID_AKMP)
|
||||
return WLAN_STATUS_AKMP_NOT_VALID;
|
||||
if (res == WPA_ALLOC_FAIL)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
|
||||
return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
|
||||
if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
|
||||
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
|
||||
if (res == WPA_INVALID_MDIE)
|
||||
return WLAN_STATUS_INVALID_MDIE;
|
||||
if (res == WPA_INVALID_PMKID)
|
||||
return WLAN_STATUS_INVALID_PMKID;
|
||||
if (res != WPA_IE_OK)
|
||||
switch (res) {
|
||||
case WPA_IE_OK:
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
case WPA_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;
|
||||
const u8 *end;
|
||||
struct ieee802_11_elems elems;
|
||||
int res;
|
||||
enum wpa_validate_result res;
|
||||
struct wpa_ie_data rsn;
|
||||
struct rsn_pmksa_cache_entry *pmksa = NULL;
|
||||
|
||||
@ -1817,11 +1889,11 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
FILS_SESSION_LEN);
|
||||
os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
|
||||
|
||||
/* FILS Wrapped Data */
|
||||
if (elems.fils_wrapped_data) {
|
||||
/* Wrapped Data */
|
||||
if (elems.wrapped_data) {
|
||||
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
|
||||
elems.fils_wrapped_data,
|
||||
elems.fils_wrapped_data_len);
|
||||
elems.wrapped_data,
|
||||
elems.wrapped_data_len);
|
||||
if (!pmksa) {
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
if (!sta->eapol_sm) {
|
||||
@ -1831,8 +1903,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Forward EAP-Initiate/Re-auth to authentication server");
|
||||
ieee802_1x_encapsulate_radius(
|
||||
hapd, sta, elems.fils_wrapped_data,
|
||||
elems.fils_wrapped_data_len);
|
||||
hapd, sta, elems.wrapped_data,
|
||||
elems.wrapped_data_len);
|
||||
sta->fils_pending_cb = cb;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Will send Authentication frame once the response from authentication server is available");
|
||||
@ -1841,8 +1913,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
* to maintain a copy of the EAP-Initiate/Reauth
|
||||
* message. */
|
||||
if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm),
|
||||
elems.fils_wrapped_data,
|
||||
elems.fils_wrapped_data_len,
|
||||
elems.wrapped_data,
|
||||
elems.wrapped_data_len,
|
||||
sta->fils_erp_pmkid) == 0)
|
||||
sta->fils_erp_pmkid_set = 1;
|
||||
return;
|
||||
@ -1985,12 +2057,12 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
|
||||
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
|
||||
wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
|
||||
|
||||
/* FILS Wrapped Data */
|
||||
/* Wrapped Data */
|
||||
if (!pmksa && erp_resp) {
|
||||
wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
|
||||
wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
|
||||
/* Element ID Extension */
|
||||
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
|
||||
wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA);
|
||||
wpabuf_put_buf(data, erp_resp);
|
||||
|
||||
if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
|
||||
@ -2506,32 +2578,10 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
(!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
|
||||
!(hapd->conf->mesh & MESH_ENABLED) &&
|
||||
!(sta->added_unassoc)) {
|
||||
/*
|
||||
* If a station that is already associated to the AP, is trying
|
||||
* to authenticate again, remove the STA entry, in order to make
|
||||
* sure the STA PS state gets cleared and configuration gets
|
||||
* updated. To handle this, station's added_unassoc flag is
|
||||
* cleared once the station has completed association.
|
||||
*/
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
|
||||
WLAN_STA_AUTHORIZED);
|
||||
|
||||
if (hostapd_sta_add(hapd, sta->addr, 0, 0,
|
||||
sta->supported_rates,
|
||||
sta->supported_rates_len,
|
||||
0, NULL, NULL, NULL, 0,
|
||||
sta->flags, 0, 0, 0, 0)) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_NOTICE,
|
||||
"Could not add STA to kernel driver");
|
||||
if (ap_sta_re_add(hapd, sta) < 0) {
|
||||
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sta->added_unassoc = 1;
|
||||
}
|
||||
|
||||
switch (auth_alg) {
|
||||
@ -2544,6 +2594,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
sta->auth_alg = WLAN_AUTH_OPEN;
|
||||
mlme_authenticate_indication(hapd, sta);
|
||||
break;
|
||||
#ifdef CONFIG_WEP
|
||||
#ifndef CONFIG_NO_RC4
|
||||
case WLAN_AUTH_SHARED_KEY:
|
||||
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
|
||||
@ -2562,6 +2613,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
#endif /* CONFIG_WEP */
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
case WLAN_AUTH_FT:
|
||||
sta->auth_alg = WLAN_AUTH_FT;
|
||||
@ -3032,7 +3084,7 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd,
|
||||
u16 status;
|
||||
u8 *owe_buf, ie[256 * 2];
|
||||
size_t ie_len = 0;
|
||||
int res;
|
||||
enum wpa_validate_result res;
|
||||
|
||||
if (!rsn_ie || rsn_ie_len < 2) {
|
||||
wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
|
||||
@ -3104,11 +3156,39 @@ end:
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
|
||||
static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int reassoc)
|
||||
{
|
||||
if ((sta->flags &
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
|
||||
return false;
|
||||
|
||||
if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
|
||||
ap_check_sa_query_timeout(hapd, sta);
|
||||
|
||||
if (!sta->sa_query_timed_out &&
|
||||
(!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
|
||||
/*
|
||||
* STA has already been associated with MFP and SA Query timeout
|
||||
* has not been reached. Reject the association attempt
|
||||
* temporarily and start SA Query, if one is not pending.
|
||||
*/
|
||||
if (sta->sa_query_count == 0)
|
||||
ap_sta_start_sa_query(hapd, sta);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ies, size_t ies_len, int reassoc)
|
||||
{
|
||||
struct ieee802_11_elems elems;
|
||||
u16 resp;
|
||||
int resp;
|
||||
const u8 *wpa_ie;
|
||||
size_t wpa_ie_len;
|
||||
const u8 *p2p_dev_addr = NULL;
|
||||
@ -3137,7 +3217,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
@ -3148,7 +3227,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
"mandatory HT PHY - reject association");
|
||||
return WLAN_STATUS_ASSOC_DENIED_NO_HT;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->iconf->ieee80211ac) {
|
||||
@ -3177,12 +3255,25 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
|
||||
resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
|
||||
elems.he_capabilities,
|
||||
elems.he_capabilities_len);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
if (is_6ghz_op_class(hapd->iconf->op_class)) {
|
||||
if (!(sta->flags & WLAN_STA_HE)) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Station does not support mandatory HE PHY - reject association");
|
||||
return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
|
||||
}
|
||||
resp = copy_sta_he_6ghz_capab(hapd, sta,
|
||||
elems.he_6ghz_band_cap);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -3216,6 +3307,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
if (hapd->conf->wps_state && elems.wps_ie) {
|
||||
wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
|
||||
"Request - assume WPS is used");
|
||||
if (check_sa_query(hapd, sta, reassoc))
|
||||
return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
|
||||
sta->flags |= WLAN_STA_WPS;
|
||||
wpabuf_free(sta->wps_ie);
|
||||
sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
|
||||
@ -3245,7 +3338,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
|
||||
if (hapd->conf->wpa && wpa_ie) {
|
||||
int res;
|
||||
enum wpa_validate_result res;
|
||||
|
||||
wpa_ie -= 2;
|
||||
wpa_ie_len += 2;
|
||||
if (sta->wpa_sm == NULL)
|
||||
@ -3268,27 +3362,9 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
resp = wpa_res_to_status_code(res);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
return resp;
|
||||
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
|
||||
!sta->sa_query_timed_out &&
|
||||
sta->sa_query_count > 0)
|
||||
ap_check_sa_query_timeout(hapd, sta);
|
||||
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
|
||||
!sta->sa_query_timed_out &&
|
||||
(!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
|
||||
/*
|
||||
* STA has already been associated with MFP and SA
|
||||
* Query timeout has not been reached. Reject the
|
||||
* association attempt temporarily and start SA Query,
|
||||
* if one is not pending.
|
||||
*/
|
||||
|
||||
if (sta->sa_query_count == 0)
|
||||
ap_sta_start_sa_query(hapd, sta);
|
||||
|
||||
if (check_sa_query(hapd, sta, reassoc))
|
||||
return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
|
||||
}
|
||||
|
||||
if (wpa_auth_uses_mfp(sta->wpa_sm))
|
||||
sta->flags |= WLAN_STA_MFP;
|
||||
@ -3341,7 +3417,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
||||
if (hapd->conf->sae_pwe == 2 &&
|
||||
sta->auth_alg == WLAN_AUTH_SAE &&
|
||||
sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
|
||||
sta->sae && !sta->sae->h2e &&
|
||||
elems.rsnxe && elems.rsnxe_len >= 1 &&
|
||||
(elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
|
||||
wpa_printf(MSG_INFO, "SAE: " MACSTR
|
||||
@ -3366,7 +3442,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
dpp_pfs_free(sta->dpp_pfs);
|
||||
sta->dpp_pfs = NULL;
|
||||
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
|
||||
if (DPP_VERSION > 1 &&
|
||||
(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
|
||||
hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
|
||||
elems.owe_dh) {
|
||||
@ -3393,7 +3470,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
pfs_fail:
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
|
||||
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
@ -3403,7 +3479,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
"association");
|
||||
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
#ifdef CONFIG_HS20
|
||||
} else if (hapd->conf->osen) {
|
||||
if (elems.osen == NULL) {
|
||||
@ -3490,6 +3565,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct wpa_channel_info ci;
|
||||
int tx_chanwidth;
|
||||
int tx_seg1_idx;
|
||||
enum oci_verify_result res;
|
||||
|
||||
if (hostapd_drv_channel_info(hapd, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
@ -3503,9 +3579,20 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
&tx_seg1_idx) < 0)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
|
||||
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
|
||||
tx_chanwidth, tx_seg1_idx) != 0) {
|
||||
wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
|
||||
res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
|
||||
tx_chanwidth, tx_seg1_idx);
|
||||
if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
|
||||
res == OCI_NOT_FOUND) {
|
||||
/* Work around misbehaving STAs */
|
||||
wpa_printf(MSG_INFO,
|
||||
"FILS: Disable OCV with a STA that does not send OCI");
|
||||
wpa_auth_set_ocv(sta->wpa_sm, 0);
|
||||
} else if (res != OCI_SUCCESS) {
|
||||
wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
|
||||
ocv_errorstr);
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
|
||||
MACSTR " frame=fils-reassoc-req error=%s",
|
||||
MAC2STR(sta->addr), ocv_errorstr);
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -3604,10 +3691,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
|
||||
sta->ft_over_ds = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if (sta->flags & WLAN_STA_HT)
|
||||
hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (sta->flags & WLAN_STA_VHT)
|
||||
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
|
||||
@ -3631,6 +3716,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
|
||||
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
|
||||
sta->flags & WLAN_STA_HE ? &he_cap : NULL,
|
||||
sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
|
||||
sta->he_6ghz_capab,
|
||||
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
|
||||
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
|
||||
set)) {
|
||||
@ -3655,7 +3741,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
|
||||
|
||||
static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *addr, u16 status_code, int reassoc,
|
||||
const u8 *ies, size_t ies_len, int rssi)
|
||||
const u8 *ies, size_t ies_len, int rssi,
|
||||
int omit_rsnxe)
|
||||
{
|
||||
int send_len;
|
||||
u8 *buf;
|
||||
@ -3725,7 +3812,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
* Transition Information, RSN, [RIC Response] */
|
||||
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
|
||||
buf + buflen - p,
|
||||
sta->auth_alg, ies, ies_len);
|
||||
sta->auth_alg, ies, ies_len,
|
||||
omit_rsnxe);
|
||||
if (!p) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: Failed to write AssocResp IEs");
|
||||
@ -3755,10 +3843,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
|
||||
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
p = hostapd_eid_ht_capabilities(hapd, p);
|
||||
p = hostapd_eid_ht_operation(hapd, p);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
|
||||
@ -3785,11 +3871,12 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
|
||||
p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
|
||||
p = hostapd_eid_he_operation(hapd, p);
|
||||
p = hostapd_eid_spatial_reuse(hapd, p);
|
||||
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
|
||||
p = hostapd_eid_he_6ghz_band_cap(hapd, p);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
@ -3806,12 +3893,29 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->conf->rsnxe_override_ft &&
|
||||
buf + buflen - p >=
|
||||
(long int) wpabuf_len(hapd->conf->rsnxe_override_ft) &&
|
||||
sta && sta->auth_alg == WLAN_AUTH_FT) {
|
||||
wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override");
|
||||
os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft),
|
||||
wpabuf_len(hapd->conf->rsnxe_override_ft));
|
||||
p += wpabuf_len(hapd->conf->rsnxe_override_ft);
|
||||
goto rsnxe_done;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
if (!omit_rsnxe)
|
||||
p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
rsnxe_done:
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
|
||||
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
|
||||
!wpa_auth_sta_get_pmksa(sta->wpa_sm)) {
|
||||
struct wpabuf *pub;
|
||||
|
||||
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
|
||||
@ -3832,7 +3936,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
|
||||
if (DPP_VERSION > 1 && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
|
||||
sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS &&
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) {
|
||||
os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie),
|
||||
@ -4024,7 +4128,7 @@ void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
|
||||
sta->fils_pending_assoc_is_reassoc,
|
||||
sta->fils_pending_assoc_req,
|
||||
sta->fils_pending_assoc_req_len, 0);
|
||||
sta->fils_pending_assoc_req_len, 0, 0);
|
||||
os_free(sta->fils_pending_assoc_req);
|
||||
sta->fils_pending_assoc_req = NULL;
|
||||
sta->fils_pending_assoc_req_len = 0;
|
||||
@ -4064,7 +4168,8 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||
int reassoc, int rssi)
|
||||
{
|
||||
u16 capab_info, listen_interval, seq_ctrl, fc;
|
||||
u16 resp = WLAN_STATUS_SUCCESS, reply_res;
|
||||
int resp = WLAN_STATUS_SUCCESS;
|
||||
u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
const u8 *pos;
|
||||
int left, i;
|
||||
struct sta_info *sta;
|
||||
@ -4072,6 +4177,7 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||
#ifdef CONFIG_FILS
|
||||
int delay_assoc = 0;
|
||||
#endif /* CONFIG_FILS */
|
||||
int omit_rsnxe = 0;
|
||||
|
||||
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
|
||||
sizeof(mgmt->u.assoc_req))) {
|
||||
@ -4284,6 +4390,7 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
|
||||
if (resp != WLAN_STATUS_SUCCESS)
|
||||
goto fail;
|
||||
omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
|
||||
|
||||
if (hostapd_get_aid(hapd, sta) < 0) {
|
||||
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
||||
@ -4336,9 +4443,7 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||
ieee802_11_set_beacons(hapd->iface);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
update_ht_state(hapd, sta);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -4443,12 +4548,13 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
|
||||
left, rssi);
|
||||
if (resp >= 0)
|
||||
reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc,
|
||||
pos, left, rssi, omit_rsnxe);
|
||||
os_free(tmp);
|
||||
|
||||
/*
|
||||
* Remove the station in case tranmission of a success response fails
|
||||
* Remove the station in case transmission of a success response fails
|
||||
* (the STA was added associated to the driver) or if the station was
|
||||
* previously added unassociated.
|
||||
*/
|
||||
@ -4485,6 +4591,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "disassociated");
|
||||
@ -4551,6 +4658,7 @@ static void handle_deauth(struct hostapd_data *hapd,
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
|
||||
WLAN_STA_ASSOC_REQ_OK);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "deauthenticated");
|
||||
@ -4682,14 +4790,12 @@ static int handle_action(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_FST */
|
||||
case WLAN_ACTION_PUBLIC:
|
||||
case WLAN_ACTION_PROTECTED_DUAL:
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if (len >= IEEE80211_HDRLEN + 2 &&
|
||||
mgmt->u.action.u.public_action.action ==
|
||||
WLAN_PA_20_40_BSS_COEX) {
|
||||
hostapd_2040_coex_action(hapd, mgmt, len);
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
#ifdef CONFIG_DPP
|
||||
if (len >= IEEE80211_HDRLEN + 6 &&
|
||||
mgmt->u.action.u.vs_public_action.action ==
|
||||
@ -4849,6 +4955,11 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hapd->iface->state != HAPD_IFACE_ENABLED) {
|
||||
wpa_printf(MSG_DEBUG, "MGMT: Ignore management frame while interface is not enabled (SA=" MACSTR " DA=" MACSTR " subtype=%u)",
|
||||
MAC2STR(mgmt->sa), MAC2STR(mgmt->da), stype);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stype == WLAN_FC_STYPE_PROBE_REQ) {
|
||||
handle_probe_req(hapd, mgmt, len, ssi_signal);
|
||||
@ -4967,6 +5078,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
char *ifname_wds)
|
||||
{
|
||||
#ifdef CONFIG_WEP
|
||||
int i;
|
||||
struct hostapd_ssid *ssid = &hapd->conf->ssid;
|
||||
|
||||
@ -4987,6 +5099,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
}
|
||||
|
||||
|
||||
@ -5487,4 +5600,57 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 bw, chan1, chan2 = 0;
|
||||
int freq1;
|
||||
|
||||
if (!hapd->cs_freq_params.channel ||
|
||||
(!hapd->cs_freq_params.vht_enabled &&
|
||||
!hapd->cs_freq_params.he_enabled))
|
||||
return eid;
|
||||
|
||||
/* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
|
||||
switch (hapd->cs_freq_params.bandwidth) {
|
||||
case 40:
|
||||
bw = 0;
|
||||
break;
|
||||
case 80:
|
||||
/* check if it's 80+80 */
|
||||
if (!hapd->cs_freq_params.center_freq2)
|
||||
bw = 1;
|
||||
else
|
||||
bw = 3;
|
||||
break;
|
||||
case 160:
|
||||
bw = 2;
|
||||
break;
|
||||
default:
|
||||
/* not valid VHT bandwidth or not in CSA */
|
||||
return eid;
|
||||
}
|
||||
|
||||
freq1 = hapd->cs_freq_params.center_freq1 ?
|
||||
hapd->cs_freq_params.center_freq1 :
|
||||
hapd->cs_freq_params.freq;
|
||||
if (ieee80211_freq_to_chan(freq1, &chan1) !=
|
||||
HOSTAPD_MODE_IEEE80211A)
|
||||
return eid;
|
||||
|
||||
if (hapd->cs_freq_params.center_freq2 &&
|
||||
ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
|
||||
&chan2) != HOSTAPD_MODE_IEEE80211A)
|
||||
return eid;
|
||||
|
||||
*eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
|
||||
*eid++ = 5; /* Length of Channel Switch Wrapper */
|
||||
*eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
|
||||
*eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
|
||||
*eid++ = bw; /* New Channel Width */
|
||||
*eid++ = chan1; /* New Channel Center Frequency Segment 0 */
|
||||
*eid++ = chan2; /* New Channel Center Frequency Segment 1 */
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
@ -53,7 +53,6 @@ u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
size_t len);
|
||||
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
|
||||
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
|
||||
@ -64,6 +63,7 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid);
|
||||
|
||||
int hostapd_ht_operation_update(struct hostapd_iface *iface);
|
||||
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
@ -96,6 +96,10 @@ u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
enum ieee80211_op_mode opmode, const u8 *he_capab,
|
||||
size_t he_capab_len);
|
||||
u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *he_6ghz_capab);
|
||||
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
|
||||
enum ieee80211_op_mode mode);
|
||||
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *buf, size_t len, int ack);
|
||||
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
|
||||
@ -182,6 +186,9 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
|
||||
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
|
||||
|
||||
size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd);
|
||||
u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len);
|
||||
|
||||
int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
|
||||
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
|
||||
|
||||
|
@ -192,9 +192,12 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
params |= (hapd->iface->conf->he_op.he_rts_threshold <<
|
||||
HE_OPERATION_RTS_THRESHOLD_OFFSET);
|
||||
|
||||
if (hapd->iface->conf->he_op.he_bss_color)
|
||||
params |= (hapd->iface->conf->he_op.he_bss_color <<
|
||||
HE_OPERATION_BSS_COLOR_OFFSET);
|
||||
if (hapd->iface->conf->he_op.he_bss_color_disabled)
|
||||
params |= HE_OPERATION_BSS_COLOR_DISABLED;
|
||||
if (hapd->iface->conf->he_op.he_bss_color_partial)
|
||||
params |= HE_OPERATION_BSS_COLOR_PARTIAL;
|
||||
params |= hapd->iface->conf->he_op.he_bss_color <<
|
||||
HE_OPERATION_BSS_COLOR_OFFSET;
|
||||
|
||||
/* HE minimum required basic MCS and NSS for STAs */
|
||||
oper->he_mcs_nss_set =
|
||||
@ -308,6 +311,35 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
|
||||
struct he_capabilities *he_cap;
|
||||
struct ieee80211_he_6ghz_band_cap *cap;
|
||||
u16 capab;
|
||||
u8 *pos;
|
||||
|
||||
if (!mode || !is_6ghz_op_class(hapd->iconf->op_class) ||
|
||||
!is_6ghz_freq(hapd->iface->freq))
|
||||
return eid;
|
||||
|
||||
he_cap = &mode->he_capab[IEEE80211_MODE_AP];
|
||||
capab = he_cap->he_6ghz_capa;
|
||||
capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
|
||||
|
||||
pos = eid;
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + sizeof(*cap);
|
||||
*pos++ = WLAN_EID_EXT_HE_6GHZ_BAND_CAP;
|
||||
|
||||
cap = (struct ieee80211_he_6ghz_band_cap *) pos;
|
||||
cap->capab = host_to_le16(capab);
|
||||
pos += sizeof(*cap);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_get_he_capab(struct hostapd_data *hapd,
|
||||
const struct ieee80211_he_capabilities *he_cap,
|
||||
struct ieee80211_he_capabilities *neg_he_cap,
|
||||
@ -387,6 +419,7 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
size_t he_capab_len)
|
||||
{
|
||||
if (!he_capab || !hapd->iconf->ieee80211ax ||
|
||||
hapd->conf->disable_11ax ||
|
||||
!check_valid_he_mcs(hapd, he_capab, opmode) ||
|
||||
ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
|
||||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
|
||||
@ -410,3 +443,45 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *he_6ghz_capab)
|
||||
{
|
||||
if (!he_6ghz_capab || !hapd->iconf->ieee80211ax ||
|
||||
hapd->conf->disable_11ax ||
|
||||
!is_6ghz_op_class(hapd->iconf->op_class)) {
|
||||
sta->flags &= ~WLAN_STA_6GHZ;
|
||||
os_free(sta->he_6ghz_capab);
|
||||
sta->he_6ghz_capab = NULL;
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!sta->he_6ghz_capab) {
|
||||
sta->he_6ghz_capab =
|
||||
os_zalloc(sizeof(struct ieee80211_he_6ghz_band_cap));
|
||||
if (!sta->he_6ghz_capab)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
sta->flags |= WLAN_STA_6GHZ;
|
||||
os_memcpy(sta->he_6ghz_capab, he_6ghz_capab,
|
||||
sizeof(struct ieee80211_he_6ghz_band_cap));
|
||||
|
||||
return WLAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
|
||||
enum ieee80211_op_mode mode)
|
||||
{
|
||||
u8 *mac_cap;
|
||||
|
||||
if (!hapd->iface->current_mode ||
|
||||
!hapd->iface->current_mode->he_capab[mode].he_supported)
|
||||
return 0;
|
||||
|
||||
mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
|
||||
|
||||
return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER);
|
||||
}
|
||||
|
@ -109,33 +109,9 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 sec_ch;
|
||||
|
||||
if (!hapd->cs_freq_params.channel ||
|
||||
!hapd->cs_freq_params.sec_channel_offset ||
|
||||
is_6ghz_op_class(hapd->iconf->op_class))
|
||||
return eid;
|
||||
|
||||
if (hapd->cs_freq_params.sec_channel_offset == -1)
|
||||
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
|
||||
else if (hapd->cs_freq_params.sec_channel_offset == 1)
|
||||
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
|
||||
else
|
||||
return eid;
|
||||
|
||||
*eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
|
||||
*eid++ = 1;
|
||||
*eid++ = sec_ch;
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
op_mode
|
||||
Set to 0 (HT pure) under the followign conditions
|
||||
Set to 0 (HT pure) under the following conditions
|
||||
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
|
||||
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
|
||||
Set to 1 (HT non-member protection) if there may be non-HT STAs
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "utils/common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ocv.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_config.h"
|
||||
@ -72,6 +73,16 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
|
||||
"Failed to get channel info for OCI element in SA Query Request");
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->conf->oci_freq_override_saquery_req) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"TEST: Override OCI frequency %d -> %u MHz",
|
||||
ci.frequency,
|
||||
hapd->conf->oci_freq_override_saquery_req);
|
||||
ci.frequency =
|
||||
hapd->conf->oci_freq_override_saquery_req;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
oci_ie_len = OCV_OCI_EXTENDED_LEN;
|
||||
oci_ie = os_zalloc(oci_ie_len);
|
||||
@ -151,6 +162,16 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
|
||||
"Failed to get channel info for OCI element in SA Query Response");
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->conf->oci_freq_override_saquery_resp) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"TEST: Override OCI frequency %d -> %u MHz",
|
||||
ci.frequency,
|
||||
hapd->conf->oci_freq_override_saquery_resp);
|
||||
ci.frequency =
|
||||
hapd->conf->oci_freq_override_saquery_resp;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
oci_ie_len = OCV_OCI_EXTENDED_LEN;
|
||||
oci_ie = os_zalloc(oci_ie_len);
|
||||
@ -254,14 +275,21 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
|
||||
return;
|
||||
|
||||
if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
|
||||
tx_chanwidth, tx_seg1_idx) != 0) {
|
||||
wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
|
||||
tx_chanwidth, tx_seg1_idx) !=
|
||||
OCI_SUCCESS) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
|
||||
MACSTR " frame=saquery%s error=%s",
|
||||
MAC2STR(sa),
|
||||
action_type == WLAN_SA_QUERY_REQUEST ?
|
||||
"req" : "resp", ocv_errorstr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
if (action_type == WLAN_SA_QUERY_REQUEST) {
|
||||
if (sta)
|
||||
sta->post_csa_sa_query = 0;
|
||||
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
|
||||
return;
|
||||
}
|
||||
@ -377,6 +405,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
|
||||
*pos |= 0x01;
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax &&
|
||||
hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
|
||||
*pos |= 0x40; /* Bit 78 - TWT responder */
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
break;
|
||||
case 10: /* Bits 80-87 */
|
||||
#ifdef CONFIG_SAE
|
||||
@ -392,6 +425,16 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
* Identifiers Used Exclusively */
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
if (hapd->conf->beacon_prot)
|
||||
*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
|
||||
break;
|
||||
case 11: /* Bits 88-95 */
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (hapd->conf->wpa &&
|
||||
wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
|
||||
hostapd_sae_pk_exclusively(hapd->conf))
|
||||
*pos |= 0x01; /* Bit 88 - SAE PK Exclusively */
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -440,12 +483,25 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
|
||||
len = 10;
|
||||
#endif /* CONFIG_FILS */
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (len < 10 && hapd->iconf->ieee80211ax &&
|
||||
hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
|
||||
len = 10;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
#ifdef CONFIG_SAE
|
||||
if (len < 11 && hapd->conf->wpa &&
|
||||
wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
|
||||
hostapd_sae_pw_id_in_use(hapd->conf))
|
||||
len = 11;
|
||||
#endif /* CONFIG_SAE */
|
||||
if (len < 11 && hapd->conf->beacon_prot)
|
||||
len = 11;
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (len < 12 && hapd->conf->wpa &&
|
||||
wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
|
||||
hostapd_sae_pk_exclusively(hapd->conf))
|
||||
len = 12;
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
if (len < hapd->iface->extended_capa_len)
|
||||
len = hapd->iface->extended_capa_len;
|
||||
if (len == 0)
|
||||
@ -860,6 +916,35 @@ u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
|
||||
}
|
||||
|
||||
|
||||
size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef CONFIG_DPP2
|
||||
if (hapd->conf->dpp_configurator_connectivity)
|
||||
return 6;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
if (!hapd->conf->dpp_configurator_connectivity || len < 6)
|
||||
return pos;
|
||||
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = 4;
|
||||
WPA_PUT_BE24(pos, OUI_WFA);
|
||||
pos += 3;
|
||||
*pos++ = DPP_CC_OUI_TYPE;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
|
||||
const u8 *supp_op_classes,
|
||||
size_t supp_op_classes_len)
|
||||
@ -1011,11 +1096,16 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
|
||||
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
bool sae_pk = false;
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
sae_pk = hostapd_sae_pk_in_use(hapd->conf);
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
|
||||
!wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
|
||||
(hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
|
||||
!hostapd_sae_pw_id_in_use(hapd->conf)) ||
|
||||
!hostapd_sae_pw_id_in_use(hapd->conf) && !sae_pk) ||
|
||||
hapd->conf->sae_pwe == 3 ||
|
||||
len < 3)
|
||||
return pos;
|
||||
@ -1024,7 +1114,12 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
*pos++ = 1;
|
||||
/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
|
||||
* used for now */
|
||||
*pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
|
||||
*pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (sae_pk)
|
||||
*pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
pos++;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
@ -167,59 +167,6 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 bw, chan1, chan2 = 0;
|
||||
int freq1;
|
||||
|
||||
if (!hapd->cs_freq_params.channel ||
|
||||
!hapd->cs_freq_params.vht_enabled)
|
||||
return eid;
|
||||
|
||||
/* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
|
||||
switch (hapd->cs_freq_params.bandwidth) {
|
||||
case 40:
|
||||
bw = 0;
|
||||
break;
|
||||
case 80:
|
||||
/* check if it's 80+80 */
|
||||
if (!hapd->cs_freq_params.center_freq2)
|
||||
bw = 1;
|
||||
else
|
||||
bw = 3;
|
||||
break;
|
||||
case 160:
|
||||
bw = 2;
|
||||
break;
|
||||
default:
|
||||
/* not valid VHT bandwidth or not in CSA */
|
||||
return eid;
|
||||
}
|
||||
|
||||
freq1 = hapd->cs_freq_params.center_freq1 ?
|
||||
hapd->cs_freq_params.center_freq1 :
|
||||
hapd->cs_freq_params.freq;
|
||||
if (ieee80211_freq_to_chan(freq1, &chan1) !=
|
||||
HOSTAPD_MODE_IEEE80211A)
|
||||
return eid;
|
||||
|
||||
if (hapd->cs_freq_params.center_freq2 &&
|
||||
ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
|
||||
&chan2) != HOSTAPD_MODE_IEEE80211A)
|
||||
return eid;
|
||||
|
||||
*eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
|
||||
*eid++ = 5; /* Length of Channel Switch Wrapper */
|
||||
*eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
|
||||
*eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
|
||||
*eid++ = bw; /* New Channel Width */
|
||||
*eid++ = chan1; /* New Channel Center Frequency Segment 0 */
|
||||
*eid++ = chan2; /* New Channel Center Frequency Segment 1 */
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
@ -425,7 +372,9 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
/* Vendor VHT is applicable only to 2.4 GHz */
|
||||
if (!hapd->iface->current_mode ||
|
||||
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
|
||||
return eid;
|
||||
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
|
@ -137,6 +137,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
#ifndef CONFIG_FIPS
|
||||
#ifndef CONFIG_NO_RC4
|
||||
|
||||
@ -297,6 +298,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
#endif /* CONFIG_FIPS */
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
|
||||
const char *radius_mode_txt(struct hostapd_data *hapd)
|
||||
@ -876,7 +878,7 @@ static void handle_eap_response(struct hostapd_data *hapd,
|
||||
|
||||
wpabuf_free(sm->eap_if->eapRespData);
|
||||
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
|
||||
sm->eapolEap = TRUE;
|
||||
sm->eapolEap = true;
|
||||
}
|
||||
|
||||
|
||||
@ -907,7 +909,7 @@ static void handle_eap_initiate(struct hostapd_data *hapd,
|
||||
|
||||
wpabuf_free(sm->eap_if->eapRespData);
|
||||
sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
|
||||
sm->eapolEap = TRUE;
|
||||
sm->eapolEap = true;
|
||||
#endif /* CONFIG_ERP */
|
||||
}
|
||||
|
||||
@ -1138,7 +1140,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
}
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
sta->eapol_sm->eap_if->portEnabled = TRUE;
|
||||
sta->eapol_sm->eap_if->portEnabled = true;
|
||||
}
|
||||
|
||||
/* since we support version 1, we can ignore version field and proceed
|
||||
@ -1165,7 +1167,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
"cached PMKSA available - ignore it since STA sent EAPOL-Start");
|
||||
wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
|
||||
}
|
||||
sta->eapol_sm->eapolStart = TRUE;
|
||||
sta->eapol_sm->eapolStart = true;
|
||||
sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
|
||||
eap_server_clear_identity(sta->eapol_sm->eap);
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
|
||||
@ -1178,7 +1180,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
sta->acct_terminate_cause =
|
||||
RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
|
||||
accounting_sta_stop(hapd, sta);
|
||||
sta->eapol_sm->eapolLogoff = TRUE;
|
||||
sta->eapol_sm->eapolLogoff = true;
|
||||
sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
|
||||
eap_server_clear_identity(sta->eapol_sm->eap);
|
||||
break;
|
||||
@ -1295,7 +1297,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
sta->eapol_sm->eap_if->portEnabled = TRUE;
|
||||
sta->eapol_sm->eap_if->portEnabled = true;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (sta->auth_alg == WLAN_AUTH_FT) {
|
||||
@ -1304,13 +1306,13 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
"PMK from FT - skip IEEE 802.1X/EAP");
|
||||
/* Setup EAPOL state machines to already authenticated state
|
||||
* because of existing FT information from R0KH. */
|
||||
sta->eapol_sm->keyRun = TRUE;
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
|
||||
sta->eapol_sm->keyRun = true;
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = true;
|
||||
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
|
||||
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
|
||||
sta->eapol_sm->authSuccess = TRUE;
|
||||
sta->eapol_sm->authFail = FALSE;
|
||||
sta->eapol_sm->portValid = TRUE;
|
||||
sta->eapol_sm->authSuccess = true;
|
||||
sta->eapol_sm->authFail = false;
|
||||
sta->eapol_sm->portValid = true;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
ap_sta_bind_vlan(hapd, sta);
|
||||
@ -1327,13 +1329,13 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
"PMK from FILS - skip IEEE 802.1X/EAP");
|
||||
/* Setup EAPOL state machines to already authenticated state
|
||||
* because of existing FILS information. */
|
||||
sta->eapol_sm->keyRun = TRUE;
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
|
||||
sta->eapol_sm->keyRun = true;
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = true;
|
||||
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
|
||||
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
|
||||
sta->eapol_sm->authSuccess = TRUE;
|
||||
sta->eapol_sm->authFail = FALSE;
|
||||
sta->eapol_sm->portValid = TRUE;
|
||||
sta->eapol_sm->authSuccess = true;
|
||||
sta->eapol_sm->authFail = false;
|
||||
sta->eapol_sm->portValid = true;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
wpa_auth_set_ptk_rekey_timer(sta->wpa_sm);
|
||||
@ -1348,12 +1350,12 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
"PMK from PMKSA cache - skip IEEE 802.1X/EAP");
|
||||
/* Setup EAPOL state machines to already authenticated state
|
||||
* because of existing PMKSA information in the cache. */
|
||||
sta->eapol_sm->keyRun = TRUE;
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
|
||||
sta->eapol_sm->keyRun = true;
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = true;
|
||||
sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
|
||||
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
|
||||
sta->eapol_sm->authSuccess = TRUE;
|
||||
sta->eapol_sm->authFail = FALSE;
|
||||
sta->eapol_sm->authSuccess = true;
|
||||
sta->eapol_sm->authFail = false;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
|
||||
@ -1365,7 +1367,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
* re-authentication without having to wait for the
|
||||
* Supplicant to send EAPOL-Start.
|
||||
*/
|
||||
sta->eapol_sm->reAuthenticate = TRUE;
|
||||
sta->eapol_sm->reAuthenticate = true;
|
||||
}
|
||||
eapol_auth_step(sta->eapol_sm);
|
||||
}
|
||||
@ -1413,7 +1415,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
|
||||
|
||||
if (!sm || !sm->last_recv_radius) {
|
||||
if (sm)
|
||||
sm->eap_if->aaaEapNoReq = TRUE;
|
||||
sm->eap_if->aaaEapNoReq = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1427,7 +1429,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"could not extract EAP-Message from RADIUS message");
|
||||
sm->eap_if->aaaEapNoReq = TRUE;
|
||||
sm->eap_if->aaaEapNoReq = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1436,7 +1438,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"too short EAP packet received from authentication server");
|
||||
wpabuf_free(eap);
|
||||
sm->eap_if->aaaEapNoReq = TRUE;
|
||||
sm->eap_if->aaaEapNoReq = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1471,7 +1473,7 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
|
||||
"decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s",
|
||||
hdr->code, hdr->identifier, be_to_host16(hdr->length),
|
||||
buf);
|
||||
sm->eap_if->aaaEapReq = TRUE;
|
||||
sm->eap_if->aaaEapReq = true;
|
||||
|
||||
wpabuf_free(sm->eap_if->aaaEapReqData);
|
||||
sm->eap_if->aaaEapReqData = eap;
|
||||
@ -1510,7 +1512,7 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
|
||||
os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
|
||||
keys->send, keys->send_len);
|
||||
sm->eap_if->aaaEapKeyDataLen = len;
|
||||
sm->eap_if->aaaEapKeyAvailable = TRUE;
|
||||
sm->eap_if->aaaEapKeyAvailable = true;
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
@ -1878,7 +1880,7 @@ static int ieee802_1x_update_vlan(struct radius_msg *msg,
|
||||
|
||||
if (vlan_desc.notempty &&
|
||||
!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
sta->eapol_sm->authFail = true;
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN %d%s received from RADIUS server",
|
||||
@ -1891,7 +1893,7 @@ static int ieee802_1x_update_vlan(struct radius_msg *msg,
|
||||
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
|
||||
!vlan_desc.notempty) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
sta->eapol_sm->authFail = true;
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"authentication server did not include required VLAN ID in Access-Accept");
|
||||
@ -2017,7 +2019,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
else
|
||||
ap_sta_no_session_timeout(hapd, sta);
|
||||
|
||||
sm->eap_if->aaaSuccess = TRUE;
|
||||
sm->eap_if->aaaSuccess = true;
|
||||
override_eapReq = 1;
|
||||
ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
|
||||
shared_secret_len);
|
||||
@ -2029,7 +2031,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
(int) session_timeout : -1);
|
||||
break;
|
||||
case RADIUS_CODE_ACCESS_REJECT:
|
||||
sm->eap_if->aaaFail = TRUE;
|
||||
sm->eap_if->aaaFail = true;
|
||||
override_eapReq = 1;
|
||||
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
|
||||
&reason_code) == 0) {
|
||||
@ -2040,7 +2042,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
}
|
||||
break;
|
||||
case RADIUS_CODE_ACCESS_CHALLENGE:
|
||||
sm->eap_if->aaaEapReq = TRUE;
|
||||
sm->eap_if->aaaEapReq = true;
|
||||
if (session_timeout_set) {
|
||||
/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
|
||||
sm->eap_if->aaaMethodTimeout = session_timeout;
|
||||
@ -2061,7 +2063,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
|
||||
ieee802_1x_decapsulate_radius(hapd, sta);
|
||||
if (override_eapReq)
|
||||
sm->eap_if->aaaEapReq = FALSE;
|
||||
sm->eap_if->aaaEapReq = false;
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
#ifdef NEED_AP_MLME
|
||||
@ -2107,13 +2109,15 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
|
||||
MAC2STR(sta->addr));
|
||||
|
||||
sm->eap_if->portEnabled = FALSE;
|
||||
sm->eap_if->portEnabled = false;
|
||||
ap_sta_disconnect(hapd, sta, sta->addr,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
|
||||
static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
|
||||
{
|
||||
struct eapol_authenticator *eapol = hapd->eapol_auth;
|
||||
@ -2144,7 +2148,7 @@ static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, void *ctx)
|
||||
{
|
||||
if (sta->eapol_sm) {
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = true;
|
||||
eapol_auth_step(sta->eapol_sm);
|
||||
}
|
||||
return 0;
|
||||
@ -2198,6 +2202,8 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
|
||||
static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
|
||||
const u8 *data, size_t datalen)
|
||||
@ -2361,6 +2367,7 @@ static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
|
||||
{
|
||||
#ifndef CONFIG_FIPS
|
||||
@ -2372,6 +2379,7 @@ static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
|
||||
#endif /* CONFIG_NO_RC4 */
|
||||
#endif /* CONFIG_FIPS */
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
|
||||
static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
|
||||
@ -2422,7 +2430,6 @@ static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
|
||||
|
||||
int ieee802_1x_init(struct hostapd_data *hapd)
|
||||
{
|
||||
int i;
|
||||
struct eapol_auth_config conf;
|
||||
struct eapol_auth_cb cb;
|
||||
|
||||
@ -2433,7 +2440,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
|
||||
conf.ctx = hapd;
|
||||
conf.eap_reauth_period = hapd->conf->eap_reauth_period;
|
||||
conf.wpa = hapd->conf->wpa;
|
||||
#ifdef CONFIG_WEP
|
||||
conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
|
||||
#endif /* CONFIG_WEP */
|
||||
conf.eap_req_id_text = hapd->conf->eap_req_id_text;
|
||||
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
|
||||
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
|
||||
@ -2448,7 +2457,9 @@ int ieee802_1x_init(struct hostapd_data *hapd)
|
||||
cb.logger = ieee802_1x_logger;
|
||||
cb.set_port_authorized = ieee802_1x_set_port_authorized;
|
||||
cb.abort_auth = _ieee802_1x_abort_auth;
|
||||
#ifdef CONFIG_WEP
|
||||
cb.tx_key = _ieee802_1x_tx_key;
|
||||
#endif /* CONFIG_WEP */
|
||||
cb.eapol_event = ieee802_1x_eapol_event;
|
||||
#ifdef CONFIG_ERP
|
||||
cb.erp_get_key = ieee802_1x_erp_get_key;
|
||||
@ -2469,17 +2480,21 @@ int ieee802_1x_init(struct hostapd_data *hapd)
|
||||
return -1;
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
#ifdef CONFIG_WEP
|
||||
if (hapd->conf->default_wep_key_len) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
hostapd_drv_set_key(hapd->conf->iface, hapd,
|
||||
WPA_ALG_NONE, NULL, i, 0, 0, NULL,
|
||||
0, NULL, 0, KEY_FLAG_GROUP_RX_TX);
|
||||
0, NULL, 0, KEY_FLAG_GROUP);
|
||||
|
||||
ieee802_1x_rekey(hapd, NULL);
|
||||
|
||||
if (!hapd->eapol_auth->default_wep_key)
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2499,7 +2514,9 @@ void ieee802_1x_erp_flush(struct hostapd_data *hapd)
|
||||
|
||||
void ieee802_1x_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef CONFIG_WEP
|
||||
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
if (hapd->driver && hapd->drv_priv &&
|
||||
(hapd->conf->ieee802_1x || hapd->conf->wpa))
|
||||
@ -2660,26 +2677,25 @@ const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
|
||||
|
||||
|
||||
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
|
||||
int enabled)
|
||||
bool enabled)
|
||||
{
|
||||
if (!sm)
|
||||
return;
|
||||
sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
|
||||
sm->eap_if->portEnabled = enabled;
|
||||
eapol_auth_step(sm);
|
||||
}
|
||||
|
||||
|
||||
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
|
||||
int valid)
|
||||
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid)
|
||||
{
|
||||
if (!sm)
|
||||
return;
|
||||
sm->portValid = valid ? TRUE : FALSE;
|
||||
sm->portValid = valid;
|
||||
eapol_auth_step(sm);
|
||||
}
|
||||
|
||||
|
||||
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
|
||||
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth)
|
||||
{
|
||||
if (!sm)
|
||||
return;
|
||||
@ -2690,7 +2706,7 @@ void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
|
||||
}
|
||||
|
||||
|
||||
static const char * bool_txt(Boolean val)
|
||||
static const char * bool_txt(bool val)
|
||||
{
|
||||
return val ? "TRUE" : "FALSE";
|
||||
}
|
||||
|
@ -42,10 +42,9 @@ const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
|
||||
const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
|
||||
size_t *len);
|
||||
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
|
||||
int enabled);
|
||||
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
|
||||
int valid);
|
||||
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
|
||||
bool enabled);
|
||||
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid);
|
||||
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth);
|
||||
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
|
||||
int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
char *buf, size_t buflen);
|
||||
|
@ -220,7 +220,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
|
||||
u16 capab = hostapd_own_capab_info(hapd);
|
||||
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
|
||||
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
|
||||
int he = hapd->iconf->ieee80211ax;
|
||||
int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
|
||||
struct wpa_ssid_value ssid;
|
||||
u8 channel, op_class;
|
||||
u8 center_freq1_idx = 0, center_freq2_idx = 0;
|
||||
@ -256,6 +256,8 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
|
||||
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
|
||||
if (vht)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_VHT;
|
||||
if (he)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_HE;
|
||||
}
|
||||
|
||||
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
|
||||
|
@ -516,6 +516,11 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
|
||||
for (entry = pmksa->pmksa; entry; entry = entry->next) {
|
||||
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
|
||||
continue;
|
||||
if (wpa_key_mgmt_sae(entry->akmp)) {
|
||||
if (os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
|
||||
return entry;
|
||||
continue;
|
||||
}
|
||||
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
|
||||
entry->akmp);
|
||||
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
|
||||
|
@ -82,7 +82,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
|
||||
sta = NULL;
|
||||
} else {
|
||||
sta->eapol_sm->radius_identifier = -1;
|
||||
sta->eapol_sm->portValid = TRUE;
|
||||
sta->eapol_sm->portValid = true;
|
||||
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +165,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
/* just in case */
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
|
||||
if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
|
||||
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
|
||||
@ -234,9 +235,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->assoc_ie_taxonomy = NULL;
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
ht40_intolerant_remove(hapd->iface, sta);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (sta->no_p2p_set) {
|
||||
@ -247,10 +246,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
|
||||
#ifdef NEED_AP_MLME
|
||||
if (hostapd_ht_operation_update(hapd->iface) > 0)
|
||||
set_beacon++;
|
||||
#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
if (hapd->mesh_sta_free_cb)
|
||||
@ -328,6 +327,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
os_free(sta->vht_capabilities);
|
||||
os_free(sta->vht_operation);
|
||||
os_free(sta->he_capab);
|
||||
os_free(sta->he_6ghz_capab);
|
||||
hostapd_free_psk_list(sta->psk);
|
||||
os_free(sta->identity);
|
||||
os_free(sta->radius_cui);
|
||||
@ -547,6 +547,7 @@ skip_poll:
|
||||
case STA_DISASSOC_FROM_CLI:
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->flags &= ~WLAN_STA_ASSOC;
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||
if (!sta->acct_terminate_cause)
|
||||
sta->acct_terminate_cause =
|
||||
@ -815,6 +816,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
sta->timeout_next = STA_DEAUTH;
|
||||
}
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - "
|
||||
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
|
||||
@ -865,6 +867,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
sta->timeout_next = STA_REMOVE;
|
||||
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - "
|
||||
@ -1030,6 +1033,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
int ret;
|
||||
int old_vlanid = sta->vlan_id_bound;
|
||||
|
||||
if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Do not override WDS VLAN assignment for STA "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
iface = hapd->conf->iface;
|
||||
if (hapd->conf->ssid.vlan[0])
|
||||
iface = hapd->conf->ssid.vlan;
|
||||
@ -1136,6 +1146,8 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
if (sta->sa_query_count > 0 &&
|
||||
ap_check_sa_query_timeout(hapd, sta))
|
||||
return;
|
||||
if (sta->sa_query_count >= 1000)
|
||||
return;
|
||||
|
||||
nbuf = os_realloc_array(sta->sa_query_trans_id,
|
||||
sta->sa_query_count + 1,
|
||||
@ -1330,9 +1342,10 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
if (sta == NULL)
|
||||
return;
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||
wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - "
|
||||
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
|
||||
@ -1420,7 +1433,8 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
|
||||
int res;
|
||||
|
||||
buf[0] = '\0';
|
||||
res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
res = os_snprintf(buf, buflen,
|
||||
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
|
||||
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
|
||||
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
|
||||
@ -1440,6 +1454,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
|
||||
(flags & WLAN_STA_HT ? "[HT]" : ""),
|
||||
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
|
||||
(flags & WLAN_STA_HE ? "[HE]" : ""),
|
||||
(flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
|
||||
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
|
||||
(flags & WLAN_STA_WNM_SLEEP_MODE ?
|
||||
"[WNM_SLEEP_MODE]" : ""));
|
||||
@ -1493,3 +1508,33 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
|
||||
hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
/*
|
||||
* If a station that is already associated to the AP, is trying to
|
||||
* authenticate again, remove the STA entry, in order to make sure the
|
||||
* STA PS state gets cleared and configuration gets updated. To handle
|
||||
* this, station's added_unassoc flag is cleared once the station has
|
||||
* completed association.
|
||||
*/
|
||||
ap_sta_set_authorized(hapd, sta, 0);
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED);
|
||||
|
||||
if (hostapd_sta_add(hapd, sta->addr, 0, 0,
|
||||
sta->supported_rates,
|
||||
sta->supported_rates_len,
|
||||
0, NULL, NULL, NULL, 0, NULL,
|
||||
sta->flags, 0, 0, 0, 0)) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_NOTICE,
|
||||
"Could not add STA to kernel driver");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sta->added_unassoc = 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -38,6 +38,7 @@
|
||||
#define WLAN_STA_PENDING_FILS_ERP BIT(22)
|
||||
#define WLAN_STA_MULTI_AP BIT(23)
|
||||
#define WLAN_STA_HE BIT(24)
|
||||
#define WLAN_STA_6GHZ BIT(25)
|
||||
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
|
||||
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
|
||||
#define WLAN_STA_NONERP BIT(31)
|
||||
@ -121,6 +122,7 @@ struct sta_info {
|
||||
unsigned int hs20_t_c_filtering:1;
|
||||
unsigned int ft_over_ds:1;
|
||||
unsigned int external_dh_updated:1;
|
||||
unsigned int post_csa_sa_query:1;
|
||||
|
||||
u16 auth_alg;
|
||||
|
||||
@ -170,6 +172,7 @@ struct sta_info {
|
||||
u8 vht_opmode;
|
||||
struct ieee80211_he_capabilities *he_capab;
|
||||
size_t he_capab_len;
|
||||
struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
|
||||
|
||||
int sa_query_count; /* number of pending SA Query requests;
|
||||
* 0 = no SA Query in progress */
|
||||
@ -358,5 +361,6 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
#endif /* STA_INFO_H */
|
||||
|
@ -56,6 +56,10 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
|
||||
ohapd = iface->bss[j];
|
||||
if (ohapd == data->hapd)
|
||||
continue;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (ohapd->conf->skip_prune_assoc)
|
||||
continue;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_FST
|
||||
/* Don't prune STAs belong to same FST */
|
||||
if (ohapd->iface->fst &&
|
||||
|
@ -22,7 +22,9 @@
|
||||
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
|
||||
int existsok)
|
||||
{
|
||||
int ret, i;
|
||||
int ret;
|
||||
#ifdef CONFIG_WEP
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_WEP_KEYS; i++) {
|
||||
if (!hapd->conf->ssid.wep.key[i])
|
||||
@ -32,6 +34,7 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
|
||||
vlan->ifname);
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_WEP */
|
||||
|
||||
if (!iface_exists(vlan->ifname))
|
||||
ret = hostapd_vlan_if_add(hapd, vlan->ifname);
|
||||
|
@ -54,6 +54,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
size_t len;
|
||||
size_t gtk_elem_len = 0;
|
||||
size_t igtk_elem_len = 0;
|
||||
size_t bigtk_elem_len = 0;
|
||||
struct wnm_sleep_element wnmsleep_ie;
|
||||
u8 *wnmtfs_ie, *oci_ie;
|
||||
u8 wnmsleep_ie_len, oci_ie_len;
|
||||
@ -102,6 +103,15 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
os_free(wnmtfs_ie);
|
||||
return -1;
|
||||
}
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->conf->oci_freq_override_wnm_sleep) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"TEST: Override OCI frequency %d -> %u MHz",
|
||||
ci.frequency,
|
||||
hapd->conf->oci_freq_override_wnm_sleep);
|
||||
ci.frequency = hapd->conf->oci_freq_override_wnm_sleep;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
oci_ie_len = OCV_OCI_EXTENDED_LEN;
|
||||
oci_ie = os_zalloc(oci_ie_len);
|
||||
@ -122,8 +132,10 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
|
||||
#define MAX_GTK_SUBELEM_LEN 45
|
||||
#define MAX_IGTK_SUBELEM_LEN 26
|
||||
#define MAX_BIGTK_SUBELEM_LEN 26
|
||||
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
|
||||
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
|
||||
MAX_BIGTK_SUBELEM_LEN +
|
||||
oci_ie_len);
|
||||
if (mgmt == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
|
||||
@ -157,10 +169,19 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
pos += igtk_elem_len;
|
||||
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
|
||||
(int) igtk_elem_len);
|
||||
if (hapd->conf->beacon_prot) {
|
||||
res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
bigtk_elem_len = res;
|
||||
pos += bigtk_elem_len;
|
||||
wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d",
|
||||
(int) bigtk_elem_len);
|
||||
}
|
||||
|
||||
WPA_PUT_LE16((u8 *)
|
||||
&mgmt->u.action.u.wnm_sleep_resp.keydata_len,
|
||||
gtk_elem_len + igtk_elem_len);
|
||||
gtk_elem_len + igtk_elem_len + bigtk_elem_len);
|
||||
}
|
||||
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
|
||||
/* copy TFS IE here */
|
||||
@ -176,7 +197,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
|
||||
igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
|
||||
igtk_elem_len + bigtk_elem_len +
|
||||
wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
|
||||
|
||||
/* In driver, response frame should be forced to sent when STA is in
|
||||
* PS mode */
|
||||
@ -189,8 +211,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
|
||||
/* when entering wnmsleep
|
||||
* 1. pause the node in driver
|
||||
* 2. mark the node so that AP won't update GTK/IGTK during
|
||||
* WNM Sleep
|
||||
* 2. mark the node so that AP won't update GTK/IGTK/BIGTK
|
||||
* during WNM Sleep
|
||||
*/
|
||||
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
|
||||
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
|
||||
@ -201,7 +223,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
}
|
||||
/* when exiting wnmsleep
|
||||
* 1. unmark the node
|
||||
* 2. start GTK/IGTK update if MFP is not used
|
||||
* 2. start GTK/IGTK/BIGTK update if MFP is not used
|
||||
* 3. unpause the node in driver
|
||||
*/
|
||||
if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
|
||||
@ -221,6 +243,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
|
||||
#undef MAX_GTK_SUBELEM_LEN
|
||||
#undef MAX_IGTK_SUBELEM_LEN
|
||||
#undef MAX_BIGTK_SUBELEM_LEN
|
||||
fail:
|
||||
os_free(wnmtfs_ie);
|
||||
os_free(oci_ie);
|
||||
@ -303,8 +326,9 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
|
||||
|
||||
if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
|
||||
channel_width_to_int(ci.chanwidth),
|
||||
ci.seg1_idx) != 0) {
|
||||
wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
|
||||
ci.seg1_idx) != OCI_SUCCESS) {
|
||||
wpa_msg(hapd, MSG_WARNING, "WNM: OCV failed: %s",
|
||||
ocv_errorstr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -508,6 +532,30 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void wnm_beacon_protection_failure(struct hostapd_data *hapd,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
if (!hapd->conf->beacon_prot)
|
||||
return;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
|
||||
wpa_printf(MSG_DEBUG, "Station " MACSTR
|
||||
" not found for received WNM-Notification Request",
|
||||
MAC2STR(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Beacon protection failure reported");
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_UNPROT_BEACON "reporter="
|
||||
MACSTR, MAC2STR(addr));
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
|
||||
const u8 *addr, const u8 *buf,
|
||||
size_t len)
|
||||
@ -526,8 +574,14 @@ static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
|
||||
MAC2STR(addr), dialog_token, type);
|
||||
wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
|
||||
buf, len);
|
||||
if (type == WLAN_EID_VENDOR_SPECIFIC)
|
||||
switch (type) {
|
||||
case WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE:
|
||||
wnm_beacon_protection_failure(hapd, addr);
|
||||
break;
|
||||
case WNM_NOTIF_TYPE_VENDOR_SPECIFIC:
|
||||
mbo_ap_wnm_notification_req(hapd, addr, buf, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
1198
src/ap/wpa_auth.c
1198
src/ap/wpa_auth.c
File diff suppressed because it is too large
Load Diff
@ -169,7 +169,9 @@ struct ft_remote_r1kh {
|
||||
|
||||
|
||||
struct wpa_auth_config {
|
||||
void *msg_ctx;
|
||||
int wpa;
|
||||
int extended_key_id;
|
||||
int wpa_key_mgmt;
|
||||
int wpa_pairwise;
|
||||
int wpa_group;
|
||||
@ -177,6 +179,7 @@ struct wpa_auth_config {
|
||||
int wpa_strict_rekey;
|
||||
int wpa_gmk_rekey;
|
||||
int wpa_ptk_rekey;
|
||||
int wpa_deny_ptk0_rekey;
|
||||
u32 wpa_group_update_count;
|
||||
u32 wpa_pairwise_update_count;
|
||||
int wpa_disable_eapol_key_retries;
|
||||
@ -189,6 +192,7 @@ struct wpa_auth_config {
|
||||
int okc;
|
||||
int tx_status;
|
||||
enum mfp_options ieee80211w;
|
||||
int beacon_prot;
|
||||
int group_mgmt_cipher;
|
||||
int sae_require_mfp;
|
||||
#ifdef CONFIG_OCV
|
||||
@ -220,13 +224,28 @@ struct wpa_auth_config {
|
||||
double corrupt_gtk_rekey_mic_probability;
|
||||
u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
|
||||
size_t own_ie_override_len;
|
||||
u8 rsne_override_eapol[MAX_OWN_IE_OVERRIDE];
|
||||
size_t rsne_override_eapol_len;
|
||||
u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
|
||||
size_t rsnxe_override_eapol_len;
|
||||
u8 rsne_override_ft[MAX_OWN_IE_OVERRIDE];
|
||||
size_t rsne_override_ft_len;
|
||||
u8 rsnxe_override_ft[MAX_OWN_IE_OVERRIDE];
|
||||
size_t rsnxe_override_ft_len;
|
||||
u8 gtk_rsc_override[WPA_KEY_RSC_LEN];
|
||||
u8 igtk_rsc_override[WPA_KEY_RSC_LEN];
|
||||
unsigned int rsne_override_eapol_set:1;
|
||||
unsigned int rsnxe_override_eapol_set:1;
|
||||
unsigned int rsne_override_ft_set:1;
|
||||
unsigned int rsnxe_override_ft_set:1;
|
||||
unsigned int gtk_rsc_override_set:1;
|
||||
unsigned int igtk_rsc_override_set:1;
|
||||
int ft_rsnxe_used;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
unsigned int oci_freq_override_eapol_m3;
|
||||
unsigned int oci_freq_override_eapol_g1;
|
||||
unsigned int oci_freq_override_ft_assoc;
|
||||
unsigned int oci_freq_override_fils_assoc;
|
||||
#ifdef CONFIG_P2P
|
||||
u8 ip_addr_go[4];
|
||||
u8 ip_addr_mask[4];
|
||||
@ -238,7 +257,12 @@ struct wpa_auth_config {
|
||||
u8 fils_cache_id[FILS_CACHE_ID_LEN];
|
||||
#endif /* CONFIG_FILS */
|
||||
int sae_pwe;
|
||||
bool sae_pk;
|
||||
int owe_ptk_workaround;
|
||||
u8 transition_disable;
|
||||
#ifdef CONFIG_DPP2
|
||||
int dpp_pfs;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@ -285,6 +309,7 @@ struct wpa_auth_callbacks {
|
||||
int *bandwidth, int *seg1_idx);
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
|
||||
int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
|
||||
int (*set_vlan)(void *ctx, const u8 *sta_addr,
|
||||
struct vlan_description *vlan);
|
||||
int (*get_vlan)(void *ctx, const u8 *sta_addr,
|
||||
@ -318,19 +343,21 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth);
|
||||
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_auth_config *conf);
|
||||
|
||||
enum {
|
||||
enum wpa_validate_result {
|
||||
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
|
||||
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
|
||||
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
|
||||
WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID
|
||||
WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID,
|
||||
WPA_DENIED_OTHER_REASON
|
||||
};
|
||||
|
||||
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, int freq,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
const u8 *rsnxe, size_t rsnxe_len,
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len);
|
||||
enum wpa_validate_result
|
||||
wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, int freq,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
const u8 *rsnxe, size_t rsnxe_len,
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len);
|
||||
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm,
|
||||
const u8 *osen_ie, size_t osen_ie_len);
|
||||
@ -414,14 +441,15 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
size_t max_len, int auth_alg,
|
||||
const u8 *req_ies, size_t req_ies_len);
|
||||
const u8 *req_ies, size_t req_ies_len,
|
||||
int omit_rsnxe);
|
||||
void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
|
||||
u16 auth_transaction, const u8 *ies, size_t ies_len,
|
||||
void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
|
||||
u16 auth_transaction, u16 resp,
|
||||
const u8 *ies, size_t ies_len),
|
||||
void *ctx);
|
||||
u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
size_t ies_len);
|
||||
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
|
||||
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||
@ -438,6 +466,7 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
|
||||
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
|
||||
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
|
||||
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
|
||||
int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos);
|
||||
|
||||
int wpa_auth_uses_sae(struct wpa_state_machine *sm);
|
||||
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
|
||||
@ -489,6 +518,8 @@ u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
|
||||
const u8 *req_ies, size_t req_ies_len);
|
||||
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
|
||||
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
|
||||
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
|
||||
u8 val);
|
||||
|
||||
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
|
||||
void (*cb)(void *ctx1, void *ctx2),
|
||||
@ -502,5 +533,16 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
|
||||
int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth);
|
||||
int wpa_auth_rekey_ptk(struct wpa_state_machine *sm, int early_install);
|
||||
void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm);
|
||||
void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val);
|
||||
|
||||
enum wpa_auth_ocv_override_frame {
|
||||
WPA_AUTH_OCV_OVERRIDE_EAPOL_M3,
|
||||
WPA_AUTH_OCV_OVERRIDE_EAPOL_G1,
|
||||
WPA_AUTH_OCV_OVERRIDE_FT_ASSOC,
|
||||
WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC,
|
||||
};
|
||||
void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth,
|
||||
enum wpa_auth_ocv_override_frame frame,
|
||||
unsigned int freq);
|
||||
|
||||
#endif /* WPA_AUTH_H */
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "common/ocv.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "drivers/driver.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes_siv.h"
|
||||
@ -808,7 +809,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
|
||||
const u8 *r0kh_id, size_t r0kh_id_len,
|
||||
const u8 *anonce, const u8 *snonce,
|
||||
u8 *buf, size_t len, const u8 *subelem,
|
||||
size_t subelem_len)
|
||||
size_t subelem_len, int rsnxe_used)
|
||||
{
|
||||
u8 *pos = buf, *ielen;
|
||||
size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) :
|
||||
@ -826,7 +827,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
|
||||
|
||||
os_memset(hdr, 0, sizeof(*hdr));
|
||||
pos += sizeof(*hdr);
|
||||
WPA_PUT_LE16(hdr->mic_control, 0);
|
||||
WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
|
||||
if (anonce)
|
||||
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
|
||||
if (snonce)
|
||||
@ -836,7 +837,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
|
||||
|
||||
os_memset(hdr, 0, sizeof(*hdr));
|
||||
pos += sizeof(*hdr);
|
||||
WPA_PUT_LE16(hdr->mic_control, 0);
|
||||
WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used);
|
||||
if (anonce)
|
||||
os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
|
||||
if (snonce)
|
||||
@ -1897,7 +1898,7 @@ static void wpa_ft_block_r0kh(struct wpa_authenticator *wpa_auth,
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "FT: Blacklist R0KH-ID",
|
||||
wpa_hexdump(MSG_DEBUG, "FT: Temporarily block R0KH-ID",
|
||||
f_r0kh_id, f_r0kh_id_len);
|
||||
|
||||
if (r0kh) {
|
||||
@ -1985,7 +1986,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
|
||||
return -1;
|
||||
}
|
||||
if (is_zero_ether_addr(r0kh->addr)) {
|
||||
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is blacklisted",
|
||||
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID is temporarily blocked",
|
||||
sm->r0kh_id, sm->r0kh_id_len);
|
||||
return -1;
|
||||
}
|
||||
@ -2128,8 +2129,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
|
||||
pmk_r0, pmk_r0_name,
|
||||
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
|
||||
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
|
||||
wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
|
||||
pmk_r0_name,
|
||||
@ -2140,9 +2139,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
|
||||
if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
|
||||
pmk_r1, sm->pmk_r1_name) < 0)
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
|
||||
WPA_PMK_NAME_LEN);
|
||||
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
|
||||
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
|
||||
sm->pmk_r1_name, sm->pairwise, &vlan,
|
||||
@ -2167,11 +2163,12 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
|
||||
static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||
{
|
||||
u8 *subelem;
|
||||
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
|
||||
struct wpa_group *gsm = sm->group;
|
||||
size_t subelem_len, pad_len;
|
||||
const u8 *key;
|
||||
size_t key_len;
|
||||
u8 keybuf[32];
|
||||
u8 keybuf[WPA_GTK_MAX_LEN];
|
||||
const u8 *kek;
|
||||
size_t kek_len;
|
||||
|
||||
@ -2198,12 +2195,30 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||
pad_len += 8;
|
||||
if (pad_len && key_len < sizeof(keybuf)) {
|
||||
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
|
||||
if (conf->disable_gtk ||
|
||||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
|
||||
/*
|
||||
* Provide unique random GTK to each STA to prevent use
|
||||
* of GTK in the BSS.
|
||||
*/
|
||||
if (random_get_bytes(keybuf, key_len) < 0)
|
||||
return NULL;
|
||||
}
|
||||
os_memset(keybuf + key_len, 0, pad_len);
|
||||
keybuf[key_len] = 0xdd;
|
||||
key_len += pad_len;
|
||||
key = keybuf;
|
||||
} else
|
||||
} else if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
|
||||
/*
|
||||
* Provide unique random GTK to each STA to prevent use of GTK
|
||||
* in the BSS.
|
||||
*/
|
||||
if (random_get_bytes(keybuf, key_len) < 0)
|
||||
return NULL;
|
||||
key = keybuf;
|
||||
} else {
|
||||
key = gsm->GTK[gsm->GN - 1];
|
||||
}
|
||||
|
||||
/*
|
||||
* Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
|
||||
@ -2237,11 +2252,13 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||
{
|
||||
u8 *subelem, *pos;
|
||||
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
|
||||
struct wpa_group *gsm = sm->group;
|
||||
size_t subelem_len;
|
||||
const u8 *kek;
|
||||
const u8 *kek, *igtk;
|
||||
size_t kek_len;
|
||||
size_t igtk_len;
|
||||
u8 dummy_igtk[WPA_IGTK_MAX_LEN];
|
||||
|
||||
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
|
||||
kek = sm->PTK.kek2;
|
||||
@ -2268,8 +2285,19 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
|
||||
pos += 6;
|
||||
*pos++ = igtk_len;
|
||||
if (aes_wrap(kek, kek_len, igtk_len / 8,
|
||||
gsm->IGTK[gsm->GN_igtk - 4], pos)) {
|
||||
igtk = gsm->IGTK[gsm->GN_igtk - 4];
|
||||
if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
|
||||
/*
|
||||
* Provide unique random IGTK to each STA to prevent use of
|
||||
* IGTK in the BSS.
|
||||
*/
|
||||
if (random_get_bytes(dummy_igtk, igtk_len / 8) < 0) {
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
igtk = dummy_igtk;
|
||||
}
|
||||
if (aes_wrap(kek, kek_len, igtk_len / 8, igtk, pos)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: IGTK subelem encryption failed: kek_len=%d",
|
||||
(int) kek_len);
|
||||
@ -2282,6 +2310,66 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||
}
|
||||
|
||||
|
||||
static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||
{
|
||||
u8 *subelem, *pos;
|
||||
struct wpa_group *gsm = sm->group;
|
||||
size_t subelem_len;
|
||||
const u8 *kek, *bigtk;
|
||||
size_t kek_len;
|
||||
size_t bigtk_len;
|
||||
u8 dummy_bigtk[WPA_IGTK_MAX_LEN];
|
||||
|
||||
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
|
||||
kek = sm->PTK.kek2;
|
||||
kek_len = sm->PTK.kek2_len;
|
||||
} else {
|
||||
kek = sm->PTK.kek;
|
||||
kek_len = sm->PTK.kek_len;
|
||||
}
|
||||
|
||||
bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
|
||||
|
||||
/* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] |
|
||||
* Key[16+8] */
|
||||
subelem_len = 1 + 1 + 2 + 6 + 1 + bigtk_len + 8;
|
||||
subelem = os_zalloc(subelem_len);
|
||||
if (subelem == NULL)
|
||||
return NULL;
|
||||
|
||||
pos = subelem;
|
||||
*pos++ = FTIE_SUBELEM_BIGTK;
|
||||
*pos++ = subelem_len - 2;
|
||||
WPA_PUT_LE16(pos, gsm->GN_bigtk);
|
||||
pos += 2;
|
||||
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
|
||||
pos += 6;
|
||||
*pos++ = bigtk_len;
|
||||
bigtk = gsm->IGTK[gsm->GN_bigtk - 6];
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
|
||||
/*
|
||||
* Provide unique random BIGTK to each OSEN STA to prevent use
|
||||
* of BIGTK in the BSS.
|
||||
*/
|
||||
if (random_get_bytes(dummy_bigtk, bigtk_len / 8) < 0) {
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
bigtk = dummy_bigtk;
|
||||
}
|
||||
if (aes_wrap(kek, kek_len, bigtk_len / 8, bigtk, pos)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: BIGTK subelem encryption failed: kek_len=%d",
|
||||
(int) kek_len);
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*len = subelem_len;
|
||||
return subelem;
|
||||
}
|
||||
|
||||
|
||||
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
|
||||
u8 *pos, u8 *end, u8 id, u8 descr_count,
|
||||
const u8 *ies, size_t ies_len)
|
||||
@ -2415,13 +2503,15 @@ static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
|
||||
|
||||
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
size_t max_len, int auth_alg,
|
||||
const u8 *req_ies, size_t req_ies_len)
|
||||
const u8 *req_ies, size_t req_ies_len,
|
||||
int omit_rsnxe)
|
||||
{
|
||||
u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
|
||||
u8 *fte_mic, *elem_count;
|
||||
size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
|
||||
u8 rsnxe[10];
|
||||
u8 rsnxe_buf[10], *rsnxe = rsnxe_buf;
|
||||
size_t rsnxe_len;
|
||||
int rsnxe_used;
|
||||
int res;
|
||||
struct wpa_auth_config *conf;
|
||||
struct wpa_ft_ies parse;
|
||||
@ -2442,6 +2532,32 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
|
||||
end = pos + max_len;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (auth_alg == WLAN_AUTH_FT &&
|
||||
sm->wpa_auth->conf.rsne_override_ft_set) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"TESTING: RSNE FT override for MIC calculation");
|
||||
rsnie = sm->wpa_auth->conf.rsne_override_ft;
|
||||
rsnie_len = sm->wpa_auth->conf.rsne_override_ft_len;
|
||||
if (end - pos < (long int) rsnie_len)
|
||||
return pos;
|
||||
os_memcpy(pos, rsnie, rsnie_len);
|
||||
rsnie = pos;
|
||||
pos += rsnie_len;
|
||||
if (rsnie_len > PMKID_LEN && sm->pmk_r1_name_valid) {
|
||||
int idx;
|
||||
|
||||
/* Replace all 0xff PMKID with the valid PMKR1Name */
|
||||
for (idx = 0; idx < PMKID_LEN; idx++) {
|
||||
if (rsnie[rsnie_len - 1 - idx] != 0xff)
|
||||
break;
|
||||
}
|
||||
if (idx == PMKID_LEN)
|
||||
os_memcpy(&rsnie[rsnie_len - PMKID_LEN],
|
||||
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
if (auth_alg == WLAN_AUTH_FT ||
|
||||
((auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
@ -2511,6 +2627,29 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
subelem_len += igtk_len;
|
||||
os_free(igtk);
|
||||
}
|
||||
if (sm->mgmt_frame_prot && conf->beacon_prot) {
|
||||
u8 *bigtk;
|
||||
size_t bigtk_len;
|
||||
u8 *nbuf;
|
||||
|
||||
bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
|
||||
if (!bigtk) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: Failed to add BIGTK subelement");
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
nbuf = os_realloc(subelem, subelem_len + bigtk_len);
|
||||
if (!nbuf) {
|
||||
os_free(subelem);
|
||||
os_free(bigtk);
|
||||
return NULL;
|
||||
}
|
||||
subelem = nbuf;
|
||||
os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
|
||||
subelem_len += bigtk_len;
|
||||
os_free(bigtk);
|
||||
}
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_auth_uses_ocv(sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
@ -2522,6 +2661,15 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (conf->oci_freq_override_ft_assoc) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"TEST: Override OCI frequency %d -> %u MHz",
|
||||
ci.frequency,
|
||||
conf->oci_freq_override_ft_assoc);
|
||||
ci.frequency = conf->oci_freq_override_ft_assoc;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
subelem_len += 2 + OCV_OCI_LEN;
|
||||
nbuf = os_realloc(subelem, subelem_len);
|
||||
@ -2546,9 +2694,18 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
anonce = NULL;
|
||||
snonce = NULL;
|
||||
}
|
||||
rsnxe_used = (auth_alg == WLAN_AUTH_FT) &&
|
||||
(conf->sae_pwe == 1 || conf->sae_pwe == 2);
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (sm->wpa_auth->conf.ft_rsnxe_used) {
|
||||
rsnxe_used = sm->wpa_auth->conf.ft_rsnxe_used == 1;
|
||||
wpa_printf(MSG_DEBUG, "TESTING: FT: Force RSNXE Used %d",
|
||||
rsnxe_used);
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len,
|
||||
anonce, snonce, pos, end - pos,
|
||||
subelem, subelem_len);
|
||||
subelem, subelem_len, rsnxe_used);
|
||||
os_free(subelem);
|
||||
if (res < 0)
|
||||
return NULL;
|
||||
@ -2584,10 +2741,24 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
if (ric_start == pos)
|
||||
ric_start = NULL;
|
||||
|
||||
res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, sizeof(rsnxe));
|
||||
if (res < 0)
|
||||
return NULL;
|
||||
rsnxe_len = res;
|
||||
if (omit_rsnxe) {
|
||||
rsnxe_len = 0;
|
||||
} else {
|
||||
res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe,
|
||||
sizeof(rsnxe_buf));
|
||||
if (res < 0)
|
||||
return NULL;
|
||||
rsnxe_len = res;
|
||||
}
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (auth_alg == WLAN_AUTH_FT &&
|
||||
sm->wpa_auth->conf.rsnxe_override_ft_set) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"TESTING: RSNXE FT override for MIC calculation");
|
||||
rsnxe = sm->wpa_auth->conf.rsnxe_override_ft;
|
||||
rsnxe_len = sm->wpa_auth->conf.rsnxe_override_ft_len;
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
|
||||
*elem_count += 1;
|
||||
|
||||
@ -2632,7 +2803,16 @@ static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
|
||||
|
||||
void wpa_ft_install_ptk(struct wpa_state_machine *sm)
|
||||
static inline int wpa_auth_add_sta_ft(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *addr)
|
||||
{
|
||||
if (!wpa_auth->cb->add_sta_ft)
|
||||
return -1;
|
||||
return wpa_auth->cb->add_sta_ft(wpa_auth->cb_ctx, addr);
|
||||
}
|
||||
|
||||
|
||||
void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry)
|
||||
{
|
||||
enum wpa_alg alg;
|
||||
int klen;
|
||||
@ -2654,19 +2834,22 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!retry)
|
||||
wpa_auth_add_sta_ft(sm->wpa_auth, sm->addr);
|
||||
|
||||
/* FIX: add STA entry to kernel/driver here? The set_key will fail
|
||||
* most likely without this.. At the moment, STA entry is added only
|
||||
* after association has been completed. This function will be called
|
||||
* again after association to get the PTK configured, but that could be
|
||||
* optimized by adding the STA entry earlier.
|
||||
*/
|
||||
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
|
||||
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active,
|
||||
sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
|
||||
return;
|
||||
|
||||
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
|
||||
sm->pairwise_set = TRUE;
|
||||
sm->tk_already_set = TRUE;
|
||||
sm->pairwise_set = true;
|
||||
sm->tk_already_set = true;
|
||||
}
|
||||
|
||||
|
||||
@ -2827,8 +3010,6 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth,
|
||||
conf->r1_key_holder,
|
||||
sm->addr, out_pmk_r1, pmk_r1_name) < 0)
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, r0->pmk_r0_len);
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
|
||||
|
||||
os_get_reltime(&now);
|
||||
if (r0->expiration)
|
||||
@ -2957,8 +3138,6 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
|
||||
sm->wpa_auth->conf.r1_key_holder, sm->addr,
|
||||
pmk_r1_name, use_sha384) < 0)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
|
||||
pmk_r1_name, WPA_PMK_NAME_LEN);
|
||||
|
||||
if (conf->ft_psk_generate_local &&
|
||||
wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
|
||||
@ -3023,9 +3202,9 @@ pmk_r1_derived:
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
|
||||
sm->pairwise = pairwise;
|
||||
sm->PTK_valid = TRUE;
|
||||
sm->tk_already_set = FALSE;
|
||||
wpa_ft_install_ptk(sm);
|
||||
sm->PTK_valid = true;
|
||||
sm->tk_already_set = false;
|
||||
wpa_ft_install_ptk(sm, 0);
|
||||
|
||||
if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
|
||||
@ -3060,7 +3239,8 @@ pmk_r1_derived:
|
||||
pos += ret;
|
||||
|
||||
ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len,
|
||||
sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
|
||||
sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0,
|
||||
0);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
pos += ret;
|
||||
@ -3119,7 +3299,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
|
||||
}
|
||||
|
||||
|
||||
u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
size_t ies_len)
|
||||
{
|
||||
struct wpa_ft_ies parse;
|
||||
@ -3132,10 +3312,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
int use_sha384;
|
||||
const u8 *anonce, *snonce, *fte_mic;
|
||||
u8 fte_elem_count;
|
||||
int rsnxe_used;
|
||||
struct wpa_auth_config *conf;
|
||||
|
||||
if (sm == NULL)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
|
||||
conf = &sm->wpa_auth->conf;
|
||||
use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt);
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
|
||||
@ -3164,8 +3347,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
|
||||
mdie = (struct rsn_mdie *) parse.mdie;
|
||||
if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
|
||||
os_memcmp(mdie->mobility_domain,
|
||||
sm->wpa_auth->conf.mobility_domain,
|
||||
os_memcmp(mdie->mobility_domain, conf->mobility_domain,
|
||||
MOBILITY_DOMAIN_ID_LEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
|
||||
return WLAN_STATUS_INVALID_MDIE;
|
||||
@ -3182,6 +3364,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
|
||||
anonce = ftie->anonce;
|
||||
snonce = ftie->snonce;
|
||||
rsnxe_used = ftie->mic_control[0] & 0x01;
|
||||
fte_elem_count = ftie->mic_control[1];
|
||||
fte_mic = ftie->mic;
|
||||
} else {
|
||||
@ -3195,6 +3378,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
|
||||
anonce = ftie->anonce;
|
||||
snonce = ftie->snonce;
|
||||
rsnxe_used = ftie->mic_control[0] & 0x01;
|
||||
fte_elem_count = ftie->mic_control[1];
|
||||
fte_mic = ftie->mic;
|
||||
}
|
||||
@ -3240,14 +3424,14 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
return WLAN_STATUS_INVALID_FTIE;
|
||||
}
|
||||
|
||||
if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
|
||||
if (os_memcmp_const(parse.r1kh_id, conf->r1_key_holder,
|
||||
FT_R1KH_ID_LEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
|
||||
"ReassocReq");
|
||||
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
|
||||
parse.r1kh_id, FT_R1KH_ID_LEN);
|
||||
wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
|
||||
sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
|
||||
conf->r1_key_holder, FT_R1KH_ID_LEN);
|
||||
return WLAN_STATUS_INVALID_FTIE;
|
||||
}
|
||||
|
||||
@ -3309,11 +3493,19 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
return WLAN_STATUS_INVALID_FTIE;
|
||||
}
|
||||
|
||||
if (rsnxe_used && (conf->sae_pwe == 1 || conf->sae_pwe == 2) &&
|
||||
!parse.rsnxe) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"FT: FTE indicated that STA uses RSNXE, but RSNXE was not included");
|
||||
return -1; /* discard request */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_auth_uses_ocv(sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
int tx_chanwidth;
|
||||
int tx_seg1_idx;
|
||||
enum oci_verify_result res;
|
||||
|
||||
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
|
||||
wpa_printf(MSG_WARNING,
|
||||
@ -3327,10 +3519,21 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
|
||||
&tx_seg1_idx) < 0)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
|
||||
if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
|
||||
tx_chanwidth, tx_seg1_idx) != 0) {
|
||||
wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
res = ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
|
||||
tx_chanwidth, tx_seg1_idx);
|
||||
if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
|
||||
/* Work around misbehaving STAs */
|
||||
wpa_printf(MSG_INFO,
|
||||
"Disable OCV with a STA that does not send OCI");
|
||||
wpa_auth_set_ocv(sm, 0);
|
||||
} else if (res != OCI_SUCCESS) {
|
||||
wpa_printf(MSG_WARNING, "OCV failed: %s", ocv_errorstr);
|
||||
if (sm->wpa_auth->conf.msg_ctx)
|
||||
wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO,
|
||||
OCV_FAILURE "addr=" MACSTR
|
||||
" frame=ft-reassoc-req error=%s",
|
||||
MAC2STR(sm->addr), ocv_errorstr);
|
||||
return WLAN_STATUS_INVALID_FTIE;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_OCV */
|
||||
@ -3553,14 +3756,11 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
|
||||
{ .type = FT_RRB_LAST_EMPTY, .len = 0, .data = NULL },
|
||||
};
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 for peer AP");
|
||||
if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_len,
|
||||
pmk_r0->pmk_r0_name, r1kh_id,
|
||||
s1kh_id, pmk_r1, pmk_r1_name) < 0)
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 (for peer AP)",
|
||||
pmk_r1, pmk_r1_len);
|
||||
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name (for peer AP)",
|
||||
pmk_r1_name, WPA_PMK_NAME_LEN);
|
||||
WPA_PUT_LE16(f_pairwise, pmk_r0->pairwise);
|
||||
|
||||
os_get_reltime(&now);
|
||||
@ -4433,7 +4633,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||
return -1;
|
||||
}
|
||||
status_code = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
|
||||
"(status_code=%d)", status_code);
|
||||
@ -4446,11 +4645,6 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (end > pos) {
|
||||
wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end",
|
||||
pos, end - pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
|
||||
os_memset(wconf, 0, sizeof(*wconf));
|
||||
wconf->wpa = conf->wpa;
|
||||
wconf->extended_key_id = conf->extended_key_id;
|
||||
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
|
||||
wconf->wpa_pairwise = conf->wpa_pairwise;
|
||||
wconf->wpa_group = conf->wpa_group;
|
||||
@ -67,6 +68,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
#endif /* CONFIG_OCV */
|
||||
wconf->okc = conf->okc;
|
||||
wconf->ieee80211w = conf->ieee80211w;
|
||||
wconf->beacon_prot = conf->beacon_prot;
|
||||
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
|
||||
wconf->sae_require_mfp = conf->sae_require_mfp;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
@ -120,14 +122,42 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
wpabuf_head(conf->own_ie_override),
|
||||
wconf->own_ie_override_len);
|
||||
}
|
||||
if (conf->rsne_override_eapol &&
|
||||
wpabuf_len(conf->rsne_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
|
||||
wconf->rsne_override_eapol_set = 1;
|
||||
wconf->rsne_override_eapol_len =
|
||||
wpabuf_len(conf->rsne_override_eapol);
|
||||
os_memcpy(wconf->rsne_override_eapol,
|
||||
wpabuf_head(conf->rsne_override_eapol),
|
||||
wconf->rsne_override_eapol_len);
|
||||
}
|
||||
if (conf->rsnxe_override_eapol &&
|
||||
wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
|
||||
wconf->rsnxe_override_eapol_set = 1;
|
||||
wconf->rsnxe_override_eapol_len =
|
||||
wpabuf_len(conf->rsnxe_override_eapol);
|
||||
os_memcpy(wconf->rsnxe_override_eapol,
|
||||
wpabuf_head(conf->rsnxe_override_eapol),
|
||||
wconf->rsnxe_override_eapol_len);
|
||||
}
|
||||
if (conf->rsne_override_ft &&
|
||||
wpabuf_len(conf->rsne_override_ft) <= MAX_OWN_IE_OVERRIDE) {
|
||||
wconf->rsne_override_ft_set = 1;
|
||||
wconf->rsne_override_ft_len =
|
||||
wpabuf_len(conf->rsne_override_ft);
|
||||
os_memcpy(wconf->rsne_override_ft,
|
||||
wpabuf_head(conf->rsne_override_ft),
|
||||
wconf->rsne_override_ft_len);
|
||||
}
|
||||
if (conf->rsnxe_override_ft &&
|
||||
wpabuf_len(conf->rsnxe_override_ft) <= MAX_OWN_IE_OVERRIDE) {
|
||||
wconf->rsnxe_override_ft_set = 1;
|
||||
wconf->rsnxe_override_ft_len =
|
||||
wpabuf_len(conf->rsnxe_override_ft);
|
||||
os_memcpy(wconf->rsnxe_override_ft,
|
||||
wpabuf_head(conf->rsnxe_override_ft),
|
||||
wconf->rsnxe_override_ft_len);
|
||||
}
|
||||
if (conf->gtk_rsc_override &&
|
||||
wpabuf_len(conf->gtk_rsc_override) > 0 &&
|
||||
wpabuf_len(conf->gtk_rsc_override) <= WPA_KEY_RSC_LEN) {
|
||||
@ -144,6 +174,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
wpabuf_len(conf->igtk_rsc_override));
|
||||
wconf->igtk_rsc_override_set = 1;
|
||||
}
|
||||
wconf->ft_rsnxe_used = conf->ft_rsnxe_used;
|
||||
wconf->oci_freq_override_eapol_m3 = conf->oci_freq_override_eapol_m3;
|
||||
wconf->oci_freq_override_eapol_g1 = conf->oci_freq_override_eapol_g1;
|
||||
wconf->oci_freq_override_ft_assoc = conf->oci_freq_override_ft_assoc;
|
||||
wconf->oci_freq_override_fils_assoc =
|
||||
conf->oci_freq_override_fils_assoc;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_P2P
|
||||
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
|
||||
@ -162,9 +198,16 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
|
||||
wconf->sae_pwe = 1;
|
||||
else if (sae_pw_id == 1 && wconf->sae_pwe == 0)
|
||||
wconf->sae_pwe = 2;
|
||||
#ifdef CONFIG_SAE_PK
|
||||
wconf->sae_pk = hostapd_sae_pk_in_use(conf);
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
#ifdef CONFIG_OWE
|
||||
wconf->owe_ptk_workaround = conf->owe_ptk_workaround;
|
||||
#endif /* CONFIG_OWE */
|
||||
wconf->transition_disable = conf->transition_disable;
|
||||
#ifdef CONFIG_DPP2
|
||||
wconf->dpp_pfs = conf->dpp_pfs;
|
||||
#endif /* CONFIG_DPP2 */
|
||||
}
|
||||
|
||||
|
||||
@ -242,16 +285,15 @@ static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
|
||||
break;
|
||||
case WPA_EAPOL_keyRun:
|
||||
if (sta->eapol_sm)
|
||||
sta->eapol_sm->keyRun = value ? TRUE : FALSE;
|
||||
sta->eapol_sm->keyRun = value;
|
||||
break;
|
||||
case WPA_EAPOL_keyAvailable:
|
||||
if (sta->eapol_sm)
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable =
|
||||
value ? TRUE : FALSE;
|
||||
sta->eapol_sm->eap_if->eapKeyAvailable = value;
|
||||
break;
|
||||
case WPA_EAPOL_keyDone:
|
||||
if (sta->eapol_sm)
|
||||
sta->eapol_sm->keyDone = value ? TRUE : FALSE;
|
||||
sta->eapol_sm->keyDone = value;
|
||||
break;
|
||||
case WPA_EAPOL_inc_EapolFramesTx:
|
||||
if (sta->eapol_sm)
|
||||
@ -404,7 +446,11 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (addr && !is_broadcast_ether_addr(addr)) {
|
||||
if (key_flag & KEY_FLAG_MODIFY) {
|
||||
/* We are updating an already installed key. Don't overwrite
|
||||
* the already stored key information with zeros.
|
||||
*/
|
||||
} else if (addr && !is_broadcast_ether_addr(addr)) {
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
@ -415,15 +461,23 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
|
||||
os_memcpy(sta->last_tk, key, key_len);
|
||||
sta->last_tk_len = key_len;
|
||||
}
|
||||
} else if (alg == WPA_ALG_IGTK ||
|
||||
} else if (alg == WPA_ALG_BIP_CMAC_128 ||
|
||||
alg == WPA_ALG_BIP_GMAC_128 ||
|
||||
alg == WPA_ALG_BIP_GMAC_256 ||
|
||||
alg == WPA_ALG_BIP_CMAC_256) {
|
||||
hapd->last_igtk_alg = alg;
|
||||
hapd->last_igtk_key_idx = idx;
|
||||
if (key)
|
||||
os_memcpy(hapd->last_igtk, key, key_len);
|
||||
hapd->last_igtk_len = key_len;
|
||||
if (idx == 4 || idx == 5) {
|
||||
hapd->last_igtk_alg = alg;
|
||||
hapd->last_igtk_key_idx = idx;
|
||||
if (key)
|
||||
os_memcpy(hapd->last_igtk, key, key_len);
|
||||
hapd->last_igtk_len = key_len;
|
||||
} else if (idx == 6 || idx == 7) {
|
||||
hapd->last_bigtk_alg = alg;
|
||||
hapd->last_bigtk_key_idx = idx;
|
||||
if (key)
|
||||
os_memcpy(hapd->last_bigtk, key, key_len);
|
||||
hapd->last_bigtk_len = key_len;
|
||||
}
|
||||
} else {
|
||||
hapd->last_gtk_alg = alg;
|
||||
hapd->last_gtk_key_idx = idx;
|
||||
@ -1000,6 +1054,34 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_add_sta_ft(void *ctx, const u8 *sta_addr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, sta_addr);
|
||||
if (!sta)
|
||||
return -1;
|
||||
|
||||
if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
|
||||
(sta->flags & WLAN_STA_MFP) && ap_sta_is_authorized(sta) &&
|
||||
!(hapd->conf->mesh & MESH_ENABLED) && !(sta->added_unassoc)) {
|
||||
/* We could not do this in handle_auth() since there was a
|
||||
* PMF-enabled association for the STA and the new
|
||||
* authentication attempt was not yet fully processed. Now that
|
||||
* we are ready to configure the TK to the driver,
|
||||
* authentication has succeeded and we can clean up the driver
|
||||
* STA entry to avoid issues with any maintained state from the
|
||||
* previous association. */
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: Remove and re-add driver STA entry after successful FT authentication");
|
||||
return ap_sta_re_add(hapd, sta);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
|
||||
struct vlan_description *vlan)
|
||||
{
|
||||
@ -1361,6 +1443,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
.send_ft_action = hostapd_wpa_auth_send_ft_action,
|
||||
.add_sta = hostapd_wpa_auth_add_sta,
|
||||
.add_sta_ft = hostapd_wpa_auth_add_sta_ft,
|
||||
.add_tspec = hostapd_wpa_auth_add_tspec,
|
||||
.set_vlan = hostapd_wpa_auth_set_vlan,
|
||||
.get_vlan = hostapd_wpa_auth_get_vlan,
|
||||
@ -1376,10 +1459,27 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
size_t wpa_ie_len;
|
||||
|
||||
hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
|
||||
_conf.msg_ctx = hapd->msg_ctx;
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
|
||||
_conf.tx_status = 1;
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
|
||||
_conf.ap_mlme = 1;
|
||||
|
||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
|
||||
(hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
|
||||
(hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
|
||||
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO,
|
||||
"Disable PTK0 rekey support - replaced with disconnect");
|
||||
_conf.wpa_deny_ptk0_rekey = 1;
|
||||
}
|
||||
|
||||
if (_conf.extended_key_id &&
|
||||
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID))
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Extended Key ID supported");
|
||||
else
|
||||
_conf.extended_key_id = 0;
|
||||
|
||||
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
|
||||
if (hapd->wpa_auth == NULL) {
|
||||
wpa_printf(MSG_ERROR, "WPA initialization failed.");
|
||||
|
@ -40,20 +40,20 @@ struct wpa_state_machine {
|
||||
WPA_PTK_GROUP_KEYERROR
|
||||
} wpa_ptk_group_state;
|
||||
|
||||
Boolean Init;
|
||||
Boolean DeauthenticationRequest;
|
||||
Boolean AuthenticationRequest;
|
||||
Boolean ReAuthenticationRequest;
|
||||
Boolean Disconnect;
|
||||
bool Init;
|
||||
bool DeauthenticationRequest;
|
||||
bool AuthenticationRequest;
|
||||
bool ReAuthenticationRequest;
|
||||
bool Disconnect;
|
||||
u16 disconnect_reason; /* specific reason code to use with Disconnect */
|
||||
u32 TimeoutCtr;
|
||||
u32 GTimeoutCtr;
|
||||
Boolean TimeoutEvt;
|
||||
Boolean EAPOLKeyReceived;
|
||||
Boolean EAPOLKeyPairwise;
|
||||
Boolean EAPOLKeyRequest;
|
||||
Boolean MICVerified;
|
||||
Boolean GUpdateStationKeys;
|
||||
bool TimeoutEvt;
|
||||
bool EAPOLKeyReceived;
|
||||
bool EAPOLKeyPairwise;
|
||||
bool EAPOLKeyRequest;
|
||||
bool MICVerified;
|
||||
bool GUpdateStationKeys;
|
||||
u8 ANonce[WPA_NONCE_LEN];
|
||||
u8 SNonce[WPA_NONCE_LEN];
|
||||
u8 alt_SNonce[WPA_NONCE_LEN];
|
||||
@ -62,20 +62,22 @@ struct wpa_state_machine {
|
||||
unsigned int pmk_len;
|
||||
u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
|
||||
struct wpa_ptk PTK;
|
||||
Boolean PTK_valid;
|
||||
Boolean pairwise_set;
|
||||
Boolean tk_already_set;
|
||||
u8 keyidx_active;
|
||||
bool use_ext_key_id;
|
||||
bool PTK_valid;
|
||||
bool pairwise_set;
|
||||
bool tk_already_set;
|
||||
int keycount;
|
||||
Boolean Pair;
|
||||
bool Pair;
|
||||
struct wpa_key_replay_counter {
|
||||
u8 counter[WPA_REPLAY_COUNTER_LEN];
|
||||
Boolean valid;
|
||||
bool valid;
|
||||
} key_replay[RSNA_MAX_EAPOL_RETRIES],
|
||||
prev_key_replay[RSNA_MAX_EAPOL_RETRIES];
|
||||
Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
|
||||
Boolean PTKRequest; /* not in IEEE 802.11i state machine */
|
||||
Boolean has_GTK;
|
||||
Boolean PtkGroupInit; /* init request for PTK Group state machine */
|
||||
bool PInitAKeys; /* WPA only, not in IEEE 802.11i */
|
||||
bool PTKRequest; /* not in IEEE 802.11i state machine */
|
||||
bool has_GTK;
|
||||
bool PtkGroupInit; /* init request for PTK Group state machine */
|
||||
|
||||
u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
|
||||
size_t last_rx_eapol_key_len;
|
||||
@ -94,8 +96,9 @@ struct wpa_state_machine {
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
unsigned int is_wnmsleep:1;
|
||||
unsigned int pmkid_set:1;
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
unsigned int ocv_enabled:1;
|
||||
int ocv_enabled;
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||
@ -174,12 +177,12 @@ struct wpa_group {
|
||||
struct wpa_group *next;
|
||||
int vlan_id;
|
||||
|
||||
Boolean GInit;
|
||||
bool GInit;
|
||||
int GKeyDoneStations;
|
||||
Boolean GTKReKey;
|
||||
bool GTKReKey;
|
||||
int GTK_len;
|
||||
int GN, GM;
|
||||
Boolean GTKAuthenticator;
|
||||
bool GTKAuthenticator;
|
||||
u8 Counter[WPA_NONCE_LEN];
|
||||
|
||||
enum {
|
||||
@ -191,11 +194,13 @@ struct wpa_group {
|
||||
u8 GMK[WPA_GMK_LEN];
|
||||
u8 GTK[2][WPA_GTK_MAX_LEN];
|
||||
u8 GNonce[WPA_NONCE_LEN];
|
||||
Boolean changed;
|
||||
Boolean first_sta_seen;
|
||||
Boolean reject_4way_hs_for_entropy;
|
||||
bool changed;
|
||||
bool first_sta_seen;
|
||||
bool reject_4way_hs_for_entropy;
|
||||
u8 IGTK[2][WPA_IGTK_MAX_LEN];
|
||||
u8 BIGTK[2][WPA_IGTK_MAX_LEN];
|
||||
int GN_igtk, GM_igtk;
|
||||
int GN_bigtk, GM_bigtk;
|
||||
/* Number of references except those in struct wpa_group->next */
|
||||
unsigned int references;
|
||||
unsigned int num_setup_iface;
|
||||
@ -275,7 +280,8 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len);
|
||||
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
logger_level level, const char *txt);
|
||||
void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
logger_level level, const char *fmt, ...);
|
||||
logger_level level, const char *fmt, ...)
|
||||
PRINTF_FORMAT(4, 5);
|
||||
void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, int key_info,
|
||||
const u8 *key_rsc, const u8 *nonce,
|
||||
@ -294,11 +300,11 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
|
||||
const u8 *r0kh_id, size_t r0kh_id_len,
|
||||
const u8 *anonce, const u8 *snonce,
|
||||
u8 *buf, size_t len, const u8 *subelem,
|
||||
size_t subelem_len);
|
||||
size_t subelem_len, int rsnxe_used);
|
||||
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
|
||||
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
|
||||
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
|
||||
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
|
||||
void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry);
|
||||
int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
|
||||
const u8 *pmk_r0_name);
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
@ -297,6 +297,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
if (rsn_testing)
|
||||
capab |= BIT(8) | BIT(15);
|
||||
#endif /* CONFIG_RSN_TESTING */
|
||||
if (conf->extended_key_id)
|
||||
capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
|
||||
WPA_PUT_LE16(pos, capab);
|
||||
pos += 2;
|
||||
|
||||
@ -376,7 +378,7 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
||||
{
|
||||
u8 *pos = buf;
|
||||
|
||||
if (conf->sae_pwe != 1 && conf->sae_pwe != 2)
|
||||
if (conf->sae_pwe != 1 && conf->sae_pwe != 2 && !conf->sae_pk)
|
||||
return 0; /* no supported extended RSN capabilities */
|
||||
|
||||
if (len < 3)
|
||||
@ -386,7 +388,12 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
|
||||
*pos++ = 1;
|
||||
/* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
|
||||
* used for now */
|
||||
*pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
|
||||
*pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (conf->sae_pk)
|
||||
*pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
pos++;
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
@ -546,13 +553,15 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
|
||||
}
|
||||
|
||||
|
||||
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, int freq,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
const u8 *rsnxe, size_t rsnxe_len,
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len)
|
||||
enum wpa_validate_result
|
||||
wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, int freq,
|
||||
const u8 *wpa_ie, size_t wpa_ie_len,
|
||||
const u8 *rsnxe, size_t rsnxe_len,
|
||||
const u8 *mdie, size_t mdie_len,
|
||||
const u8 *owe_dh, size_t owe_dh_len)
|
||||
{
|
||||
struct wpa_auth_config *conf = &wpa_auth->conf;
|
||||
struct wpa_ie_data data;
|
||||
int ciphers, key_mgmt, res, version;
|
||||
u32 selector;
|
||||
@ -799,14 +808,26 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_OCV
|
||||
if ((data.capabilities & WPA_CAPABILITY_OCVC) &&
|
||||
if (wpa_auth->conf.ocv && (data.capabilities & WPA_CAPABILITY_OCVC) &&
|
||||
!(data.capabilities & WPA_CAPABILITY_MFPC)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Management frame protection required with OCV, but client did not enable it");
|
||||
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
|
||||
/* Some legacy MFP incapable STAs wrongly copy OCVC bit from
|
||||
* AP RSN capabilities. To improve interoperability with such
|
||||
* legacy STAs allow connection without enabling OCV when the
|
||||
* workaround mode (ocv=2) is enabled.
|
||||
*/
|
||||
if (wpa_auth->conf.ocv == 2) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Allow connecting MFP incapable and OCV capable STA without enabling OCV");
|
||||
wpa_auth_set_ocv(sm, 0);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Management frame protection required with OCV, but client did not enable it");
|
||||
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
|
||||
}
|
||||
} else {
|
||||
wpa_auth_set_ocv(sm, (data.capabilities & WPA_CAPABILITY_OCVC) ?
|
||||
wpa_auth->conf.ocv : 0);
|
||||
}
|
||||
wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
|
||||
(data.capabilities & WPA_CAPABILITY_OCVC));
|
||||
#endif /* CONFIG_OCV */
|
||||
|
||||
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
|
||||
@ -847,19 +868,18 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
"OWE: No Diffie-Hellman Parameter element");
|
||||
return WPA_INVALID_AKMP;
|
||||
}
|
||||
#ifdef CONFIG_DPP
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && owe_dh) {
|
||||
/* Diffie-Hellman Parameter element can be used with DPP as
|
||||
* well, so allow this to proceed. */
|
||||
} else
|
||||
#endif /* CONFIG_DPP */
|
||||
if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM");
|
||||
return WPA_INVALID_AKMP;
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
#ifdef CONFIG_DPP2
|
||||
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
|
||||
((conf->dpp_pfs == 1 && !owe_dh) ||
|
||||
(conf->dpp_pfs == 2 && owe_dh))) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: PFS %s",
|
||||
conf->dpp_pfs == 1 ? "required" : "not allowed");
|
||||
return WPA_DENIED_OTHER_REASON;
|
||||
}
|
||||
#endif /* CONFIG_DPP2 */
|
||||
|
||||
sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
|
||||
if (sm->pairwise < 0)
|
||||
return WPA_INVALID_PAIRWISE;
|
||||
@ -944,6 +964,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 &&
|
||||
sm->pairwise != WPA_CIPHER_TKIP &&
|
||||
(data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
|
||||
sm->use_ext_key_id = true;
|
||||
if (conf->extended_key_id == 2 &&
|
||||
!wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
|
||||
!wpa_key_mgmt_fils(sm->wpa_key_mgmt))
|
||||
sm->keyidx_active = 1;
|
||||
else
|
||||
sm->keyidx_active = 0;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RSN: Extended Key ID supported (start with %d)",
|
||||
sm->keyidx_active);
|
||||
} else {
|
||||
sm->use_ext_key_id = false;
|
||||
}
|
||||
|
||||
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
|
||||
os_free(sm->wpa_ie);
|
||||
sm->wpa_ie = os_malloc(wpa_ie_len);
|
||||
|
@ -52,7 +52,7 @@ static int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap)
|
||||
}
|
||||
|
||||
|
||||
static int hapd_enable_protect_frames(void *priv, Boolean enabled)
|
||||
static int hapd_enable_protect_frames(void *priv, bool enabled)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
@ -62,7 +62,7 @@ static int hapd_enable_protect_frames(void *priv, Boolean enabled)
|
||||
}
|
||||
|
||||
|
||||
static int hapd_enable_encrypt(void *priv, Boolean enabled)
|
||||
static int hapd_enable_encrypt(void *priv, bool enabled)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
@ -72,7 +72,7 @@ static int hapd_enable_encrypt(void *priv, Boolean enabled)
|
||||
}
|
||||
|
||||
|
||||
static int hapd_set_replay_protect(void *priv, Boolean enabled, u32 window)
|
||||
static int hapd_set_replay_protect(void *priv, bool enabled, u32 window)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
@ -93,7 +93,7 @@ static int hapd_set_current_cipher_suite(void *priv, u64 cs)
|
||||
}
|
||||
|
||||
|
||||
static int hapd_enable_controlled_port(void *priv, Boolean enabled)
|
||||
static int hapd_enable_controlled_port(void *priv, bool enabled)
|
||||
{
|
||||
struct hostapd_data *hapd = priv;
|
||||
|
||||
@ -465,7 +465,7 @@ void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
|
||||
wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
|
||||
|
||||
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
|
||||
TRUE);
|
||||
true);
|
||||
|
||||
fail:
|
||||
bin_clear_free(msk, sizeof(*msk));
|
||||
@ -507,7 +507,7 @@ void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
|
||||
ckn->len = hapd->conf->mka_ckn_len;;
|
||||
os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len);
|
||||
|
||||
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, TRUE);
|
||||
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, true);
|
||||
if (res)
|
||||
goto free_cak;
|
||||
|
||||
|
@ -125,6 +125,7 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
|
||||
os_memcpy(p->addr, mac_addr, ETH_ALEN);
|
||||
os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
|
||||
os_memcpy(p->psk, psk, PMK_LEN);
|
||||
p->wps = 1;
|
||||
|
||||
if (hapd->new_psk_cb) {
|
||||
hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
|
||||
@ -363,6 +364,13 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
|
||||
bss->ssid.ssid_set = 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NO_TKIP
|
||||
if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK |
|
||||
WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
|
||||
bss->wpa = 2;
|
||||
else
|
||||
bss->wpa = 0;
|
||||
#else /* CONFIG_NO_TKIP */
|
||||
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
|
||||
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
|
||||
bss->wpa = 3;
|
||||
@ -372,6 +380,7 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
|
||||
bss->wpa = 1;
|
||||
else
|
||||
bss->wpa = 0;
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
|
||||
if (bss->wpa) {
|
||||
if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
|
||||
@ -386,8 +395,10 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
|
||||
else
|
||||
bss->wpa_pairwise |= WPA_CIPHER_CCMP;
|
||||
}
|
||||
#ifndef CONFIG_NO_TKIP
|
||||
if (cred->encr_type & WPS_ENCR_TKIP)
|
||||
bss->wpa_pairwise |= WPA_CIPHER_TKIP;
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
bss->rsn_pairwise = bss->wpa_pairwise;
|
||||
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
|
||||
bss->wpa_pairwise,
|
||||
@ -558,6 +569,13 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
fprintf(nconf, "\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NO_TKIP
|
||||
if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK |
|
||||
WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
|
||||
wpa = 2;
|
||||
else
|
||||
wpa = 0;
|
||||
#else /* CONFIG_NO_TKIP */
|
||||
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
|
||||
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
|
||||
wpa = 3;
|
||||
@ -567,6 +585,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
wpa = 1;
|
||||
else
|
||||
wpa = 0;
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
|
||||
if (wpa) {
|
||||
char *prefix;
|
||||
@ -610,9 +629,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
|
||||
prefix = " ";
|
||||
}
|
||||
#ifndef CONFIG_NO_TKIP
|
||||
if (cred->encr_type & WPS_ENCR_TKIP) {
|
||||
fprintf(nconf, "%sTKIP", prefix);
|
||||
}
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
fprintf(nconf, "\n");
|
||||
|
||||
if (cred->key_len >= 8 && cred->key_len < 64) {
|
||||
@ -650,8 +671,10 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
(str_starts(buf, "ssid=") ||
|
||||
str_starts(buf, "ssid2=") ||
|
||||
str_starts(buf, "auth_algs=") ||
|
||||
#ifdef CONFIG_WEP
|
||||
str_starts(buf, "wep_default_key=") ||
|
||||
str_starts(buf, "wep_key") ||
|
||||
#endif /* CONFIG_WEP */
|
||||
str_starts(buf, "wps_state=") ||
|
||||
(pmf_changed && str_starts(buf, "ieee80211w=")) ||
|
||||
str_starts(buf, "wpa=") ||
|
||||
@ -1157,12 +1180,24 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
wps->encr_types_rsn |= WPS_ENCR_AES;
|
||||
}
|
||||
if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
|
||||
#ifdef CONFIG_NO_TKIP
|
||||
wpa_printf(MSG_INFO, "WPS: TKIP not supported");
|
||||
goto fail;
|
||||
#else /* CONFIG_NO_TKIP */
|
||||
wps->encr_types |= WPS_ENCR_TKIP;
|
||||
wps->encr_types_rsn |= WPS_ENCR_TKIP;
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
}
|
||||
}
|
||||
|
||||
if (conf->wpa & WPA_PROTO_WPA) {
|
||||
#ifdef CONFIG_NO_TKIP
|
||||
if (!(conf->wpa & WPA_PROTO_RSN)) {
|
||||
wpa_printf(MSG_INFO, "WPS: WPA(v1) not supported");
|
||||
goto fail;
|
||||
}
|
||||
conf->wpa &= ~WPA_PROTO_WPA;
|
||||
#else /* CONFIG_NO_TKIP */
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
|
||||
wps->auth_types |= WPS_AUTH_WPAPSK;
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
@ -1176,6 +1211,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
wps->encr_types |= WPS_ENCR_TKIP;
|
||||
wps->encr_types_wpa |= WPS_ENCR_TKIP;
|
||||
}
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
}
|
||||
|
||||
if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
|
||||
@ -1195,6 +1231,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
|
||||
conf->ssid.wpa_psk->psk, PMK_LEN);
|
||||
wps->network_key_len = 2 * PMK_LEN;
|
||||
#ifdef CONFIG_WEP
|
||||
} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
|
||||
wps->network_key = os_malloc(conf->ssid.wep.len[0]);
|
||||
if (wps->network_key == NULL)
|
||||
@ -1202,6 +1239,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
os_memcpy(wps->network_key, conf->ssid.wep.key[0],
|
||||
conf->ssid.wep.len[0]);
|
||||
wps->network_key_len = conf->ssid.wep.len[0];
|
||||
#endif /* CONFIG_WEP */
|
||||
}
|
||||
|
||||
if (conf->ssid.wpa_psk) {
|
||||
@ -1213,10 +1251,17 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
wps->ap_encr_type = wps->encr_types;
|
||||
if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
|
||||
/* Override parameters to enable security by default */
|
||||
#ifdef CONFIG_NO_TKIP
|
||||
wps->auth_types = WPS_AUTH_WPA2PSK;
|
||||
wps->encr_types = WPS_ENCR_AES;
|
||||
wps->encr_types_rsn = WPS_ENCR_AES;
|
||||
wps->encr_types_wpa = WPS_ENCR_AES;
|
||||
#else /* CONFIG_NO_TKIP */
|
||||
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
|
||||
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
|
||||
wps->encr_types_rsn = WPS_ENCR_AES | WPS_ENCR_TKIP;
|
||||
wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
}
|
||||
|
||||
if ((hapd->conf->multi_ap & FRONTHAUL_BSS) &&
|
||||
@ -1259,8 +1304,6 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
cfg.extra_cred_len = conf->extra_cred_len;
|
||||
cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
|
||||
conf->skip_cred_build;
|
||||
if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
|
||||
cfg.static_wep_only = 1;
|
||||
cfg.dualband = interface_count(hapd->iface) > 1;
|
||||
if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
|
||||
(WPS_RF_50GHZ | WPS_RF_24GHZ))
|
||||
@ -1798,8 +1841,10 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
|
||||
|
||||
if (os_strncmp(auth, "OPEN", 4) == 0)
|
||||
cred.auth_type = WPS_AUTH_OPEN;
|
||||
#ifndef CONFIG_NO_TKIP
|
||||
else if (os_strncmp(auth, "WPAPSK", 6) == 0)
|
||||
cred.auth_type = WPS_AUTH_WPAPSK;
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
|
||||
cred.auth_type = WPS_AUTH_WPA2PSK;
|
||||
else
|
||||
@ -1808,8 +1853,10 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
|
||||
if (encr) {
|
||||
if (os_strncmp(encr, "NONE", 4) == 0)
|
||||
cred.encr_type = WPS_ENCR_NONE;
|
||||
#ifndef CONFIG_NO_TKIP
|
||||
else if (os_strncmp(encr, "TKIP", 4) == 0)
|
||||
cred.encr_type = WPS_ENCR_TKIP;
|
||||
#endif /* CONFIG_NO_TKIP */
|
||||
else if (os_strncmp(encr, "CCMP", 4) == 0)
|
||||
cred.encr_type = WPS_ENCR_AES;
|
||||
else
|
||||
|
109
src/build.rules
Normal file
109
src/build.rules
Normal 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)
|
@ -1,13 +1,3 @@
|
||||
all: libcommon.a
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcommon.a
|
||||
|
||||
install:
|
||||
@echo Nothing to be made.
|
||||
|
||||
include ../lib.rules
|
||||
|
||||
CFLAGS += -DCONFIG_IEEE80211R
|
||||
CFLAGS += -DCONFIG_HS20
|
||||
CFLAGS += -DCONFIG_SAE
|
||||
@ -21,7 +11,4 @@ LIB_OBJS= \
|
||||
sae.o \
|
||||
wpa_common.o
|
||||
|
||||
libcommon.a: $(LIB_OBJS)
|
||||
$(AR) crT $@ $?
|
||||
|
||||
-include $(OBJS:%.o=%.d)
|
||||
include ../lib.rules
|
||||
|
@ -434,7 +434,8 @@ static int sae_tests(void)
|
||||
goto fail;
|
||||
|
||||
/* Check that output matches the test vector */
|
||||
sae_write_commit(&sae, buf, NULL, pwid);
|
||||
if (sae_write_commit(&sae, buf, NULL, pwid) < 0)
|
||||
goto fail;
|
||||
wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf);
|
||||
|
||||
if (wpabuf_len(buf) != sizeof(local_commit) ||
|
||||
@ -547,6 +548,95 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
static int sae_pk_tests(void)
|
||||
{
|
||||
#ifdef CONFIG_SAE_PK
|
||||
const char *invalid[] = { "a2bc-de3f-ghim-", "a2bcde3fghim", "", NULL };
|
||||
struct {
|
||||
const char *pw;
|
||||
const u8 *val;
|
||||
} valid[] = {
|
||||
{ "a2bc-de3f-ghim", (u8 *) "\x06\x82\x21\x93\x65\x31\xd0\xc0" },
|
||||
{ "aaaa-aaaa-aaaj", (u8 *) "\x00\x00\x00\x00\x00\x00\x00\x90" },
|
||||
{ "7777-7777-777f", (u8 *) "\xff\xff\xff\xff\xff\xff\xfe\x50" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
int i;
|
||||
bool failed;
|
||||
|
||||
for (i = 0; invalid[i]; i++) {
|
||||
if (sae_pk_valid_password(invalid[i])) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"SAE-PK: Invalid password '%s' not recognized",
|
||||
invalid[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
failed = false;
|
||||
for (i = 0; valid[i].pw; i++) {
|
||||
u8 *res;
|
||||
size_t res_len;
|
||||
char *b32;
|
||||
const char *pw = valid[i].pw;
|
||||
const u8 *val = valid[i].val;
|
||||
size_t pw_len = os_strlen(pw);
|
||||
size_t bits = (pw_len - pw_len / 5) * 5;
|
||||
size_t bytes = (bits + 7) / 8;
|
||||
|
||||
if (!sae_pk_valid_password(pw)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"SAE-PK: Valid password '%s' not recognized",
|
||||
pw);
|
||||
failed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
res = sae_pk_base32_decode(pw, pw_len, &res_len);
|
||||
if (!res) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"SAE-PK: Failed to decode password '%s'",
|
||||
valid[i].pw);
|
||||
failed = true;
|
||||
continue;
|
||||
}
|
||||
if (res_len != bytes || os_memcmp(val, res, res_len) != 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"SAE-PK: Mismatch for decoded password '%s'",
|
||||
valid[i].pw);
|
||||
wpa_hexdump(MSG_INFO, "SAE-PK: Decoded value",
|
||||
res, res_len);
|
||||
wpa_hexdump(MSG_INFO, "SAE-PK: Expected value",
|
||||
val, bytes);
|
||||
failed = true;
|
||||
}
|
||||
os_free(res);
|
||||
|
||||
b32 = sae_pk_base32_encode(val, bits - 5);
|
||||
if (!b32) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"SAE-PK: Failed to encode password '%s'",
|
||||
pw);
|
||||
failed = true;
|
||||
continue;
|
||||
}
|
||||
if (os_strcmp(b32, pw) != 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"SAE-PK: Mismatch for password '%s'", pw);
|
||||
wpa_printf(MSG_INFO, "SAE-PK: Encoded value: '%s'",
|
||||
b32);
|
||||
failed = true;
|
||||
}
|
||||
os_free(b32);
|
||||
}
|
||||
|
||||
return failed ? -1 : 0;
|
||||
#else /* CONFIG_SAE_PK */
|
||||
return 0;
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
}
|
||||
|
||||
|
||||
int common_module_tests(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -556,6 +646,7 @@ int common_module_tests(void)
|
||||
if (ieee802_11_parse_tests() < 0 ||
|
||||
gas_tests() < 0 ||
|
||||
sae_tests() < 0 ||
|
||||
sae_pk_tests() < 0 ||
|
||||
rsn_ie_parse_tests() < 0)
|
||||
ret = -1;
|
||||
|
||||
|
@ -9,15 +9,6 @@
|
||||
#ifndef DEFS_H
|
||||
#define DEFS_H
|
||||
|
||||
#ifdef FALSE
|
||||
#undef FALSE
|
||||
#endif
|
||||
#ifdef TRUE
|
||||
#undef TRUE
|
||||
#endif
|
||||
typedef enum { FALSE = 0, TRUE = 1 } Boolean;
|
||||
|
||||
|
||||
#define WPA_CIPHER_NONE BIT(0)
|
||||
#define WPA_CIPHER_WEP40 BIT(1)
|
||||
#define WPA_CIPHER_WEP104 BIT(2)
|
||||
@ -82,6 +73,13 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
|
||||
WPA_KEY_MGMT_FT_FILS_SHA384));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_wpa_psk_no_sae(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_PSK |
|
||||
WPA_KEY_MGMT_FT_PSK |
|
||||
WPA_KEY_MGMT_PSK_SHA256));
|
||||
}
|
||||
|
||||
static inline int wpa_key_mgmt_wpa_psk(int akm)
|
||||
{
|
||||
return !!(akm & (WPA_KEY_MGMT_PSK |
|
||||
@ -192,8 +190,7 @@ enum wpa_alg {
|
||||
WPA_ALG_WEP,
|
||||
WPA_ALG_TKIP,
|
||||
WPA_ALG_CCMP,
|
||||
WPA_ALG_IGTK,
|
||||
WPA_ALG_PMK,
|
||||
WPA_ALG_BIP_CMAC_128,
|
||||
WPA_ALG_GCMP,
|
||||
WPA_ALG_SMS4,
|
||||
WPA_ALG_KRK,
|
||||
@ -204,6 +201,14 @@ enum wpa_alg {
|
||||
WPA_ALG_BIP_CMAC_256
|
||||
};
|
||||
|
||||
static inline int wpa_alg_bip(enum wpa_alg alg)
|
||||
{
|
||||
return alg == WPA_ALG_BIP_CMAC_128 ||
|
||||
alg == WPA_ALG_BIP_GMAC_128 ||
|
||||
alg == WPA_ALG_BIP_GMAC_256 ||
|
||||
alg == WPA_ALG_BIP_CMAC_256;
|
||||
}
|
||||
|
||||
/**
|
||||
* enum wpa_states - wpa_supplicant state
|
||||
*
|
||||
@ -383,9 +388,10 @@ enum mesh_plink_state {
|
||||
};
|
||||
|
||||
enum set_band {
|
||||
WPA_SETBAND_AUTO,
|
||||
WPA_SETBAND_5G,
|
||||
WPA_SETBAND_2G
|
||||
WPA_SETBAND_AUTO = 0,
|
||||
WPA_SETBAND_5G = BIT(0),
|
||||
WPA_SETBAND_2G = BIT(1),
|
||||
WPA_SETBAND_6G = BIT(2),
|
||||
};
|
||||
|
||||
enum wpa_radio_work_band {
|
||||
@ -443,6 +449,27 @@ enum key_flag {
|
||||
KEY_FLAG_PAIRWISE_RX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX,
|
||||
KEY_FLAG_PAIRWISE_RX_TX_MODIFY = KEY_FLAG_PAIRWISE_RX_TX |
|
||||
KEY_FLAG_MODIFY,
|
||||
/* Max allowed flags for each key type */
|
||||
KEY_FLAG_PAIRWISE_MASK = KEY_FLAG_PAIRWISE_RX_TX_MODIFY,
|
||||
KEY_FLAG_GROUP_MASK = KEY_FLAG_GROUP_RX_TX_DEFAULT,
|
||||
KEY_FLAG_PMK_MASK = KEY_FLAG_PMK,
|
||||
};
|
||||
|
||||
static inline int check_key_flag(enum key_flag key_flag)
|
||||
{
|
||||
return !!(!key_flag ||
|
||||
((key_flag & (KEY_FLAG_PAIRWISE | KEY_FLAG_MODIFY)) &&
|
||||
(key_flag & ~KEY_FLAG_PAIRWISE_MASK)) ||
|
||||
((key_flag & KEY_FLAG_GROUP) &&
|
||||
(key_flag & ~KEY_FLAG_GROUP_MASK)) ||
|
||||
((key_flag & KEY_FLAG_PMK) &&
|
||||
(key_flag & ~KEY_FLAG_PMK_MASK)));
|
||||
}
|
||||
|
||||
enum ptk0_rekey_handling {
|
||||
PTK0_REKEY_ALLOW_ALWAYS,
|
||||
PTK0_REKEY_ALLOW_LOCAL_OK,
|
||||
PTK0_REKEY_ALLOW_NEVER
|
||||
};
|
||||
|
||||
#endif /* DEFS_H */
|
||||
|
9093
src/common/dpp.c
9093
src/common/dpp.c
File diff suppressed because it is too large
Load Diff
166
src/common/dpp.h
166
src/common/dpp.h
@ -20,9 +20,22 @@
|
||||
struct crypto_ecdh;
|
||||
struct hostapd_ip_addr;
|
||||
struct dpp_global;
|
||||
struct json_token;
|
||||
struct dpp_reconfig_id;
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
#define DPP_VERSION (dpp_version_override)
|
||||
extern int dpp_version_override;
|
||||
#else /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_DPP2
|
||||
#define DPP_VERSION 2
|
||||
#else
|
||||
#define DPP_VERSION 1
|
||||
#endif
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
|
||||
#define DPP_TCP_PORT 7871
|
||||
#define DPP_TCP_PORT 8908
|
||||
|
||||
enum dpp_public_action_frame_type {
|
||||
DPP_PA_AUTHENTICATION_REQ = 0,
|
||||
@ -36,6 +49,11 @@ enum dpp_public_action_frame_type {
|
||||
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
|
||||
DPP_PA_CONFIGURATION_RESULT = 11,
|
||||
DPP_PA_CONNECTION_STATUS_RESULT = 12,
|
||||
DPP_PA_PRESENCE_ANNOUNCEMENT = 13,
|
||||
DPP_PA_RECONFIG_ANNOUNCEMENT = 14,
|
||||
DPP_PA_RECONFIG_AUTH_REQ = 15,
|
||||
DPP_PA_RECONFIG_AUTH_RESP = 16,
|
||||
DPP_PA_RECONFIG_AUTH_CONF = 17,
|
||||
};
|
||||
|
||||
enum dpp_attribute_id {
|
||||
@ -67,6 +85,12 @@ enum dpp_attribute_id {
|
||||
DPP_ATTR_ENVELOPED_DATA = 0x101A,
|
||||
DPP_ATTR_SEND_CONN_STATUS = 0x101B,
|
||||
DPP_ATTR_CONN_STATUS = 0x101C,
|
||||
DPP_ATTR_RECONFIG_FLAGS = 0x101D,
|
||||
DPP_ATTR_C_SIGN_KEY_HASH = 0x101E,
|
||||
DPP_ATTR_CSR_ATTR_REQ = 0x101F,
|
||||
DPP_ATTR_A_NONCE = 0x1020,
|
||||
DPP_ATTR_E_PRIME_ID = 0x1021,
|
||||
DPP_ATTR_CONFIGURATOR_NONCE = 0x1022,
|
||||
};
|
||||
|
||||
enum dpp_status_error {
|
||||
@ -81,6 +105,15 @@ enum dpp_status_error {
|
||||
DPP_STATUS_NO_MATCH = 8,
|
||||
DPP_STATUS_CONFIG_REJECTED = 9,
|
||||
DPP_STATUS_NO_AP = 10,
|
||||
DPP_STATUS_CONFIGURE_PENDING = 11,
|
||||
DPP_STATUS_CSR_NEEDED = 12,
|
||||
DPP_STATUS_CSR_BAD = 13,
|
||||
};
|
||||
|
||||
/* DPP Reconfig Flags object - connectorKey values */
|
||||
enum dpp_connector_key {
|
||||
DPP_CONFIG_REUSEKEY = 0,
|
||||
DPP_CONFIG_REPLACEKEY = 1,
|
||||
};
|
||||
|
||||
#define DPP_CAPAB_ENROLLEE BIT(0)
|
||||
@ -91,6 +124,7 @@ enum dpp_status_error {
|
||||
#define DPP_MAX_NONCE_LEN 32
|
||||
#define DPP_MAX_HASH_LEN 64
|
||||
#define DPP_MAX_SHARED_SECRET_LEN 66
|
||||
#define DPP_CP_LEN 64
|
||||
|
||||
struct dpp_curve_params {
|
||||
const char *name;
|
||||
@ -120,12 +154,18 @@ struct dpp_bootstrap_info {
|
||||
char *pk;
|
||||
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
|
||||
unsigned int num_freq;
|
||||
bool channels_listed;
|
||||
u8 version;
|
||||
int own;
|
||||
EVP_PKEY *pubkey;
|
||||
u8 pubkey_hash[SHA256_MAC_LEN];
|
||||
u8 pubkey_hash_chirp[SHA256_MAC_LEN];
|
||||
const struct dpp_curve_params *curve;
|
||||
unsigned int pkex_t; /* number of failures before dpp_pkex
|
||||
* instantiation */
|
||||
int nfc_negotiated; /* whether this has been used in NFC negotiated
|
||||
* connection handover */
|
||||
char *configurator_params;
|
||||
};
|
||||
|
||||
#define PKEX_COUNTER_T_LIMIT 5
|
||||
@ -162,6 +202,7 @@ enum dpp_akm {
|
||||
DPP_AKM_PSK_SAE,
|
||||
DPP_AKM_SAE_DPP,
|
||||
DPP_AKM_PSK_SAE_DPP,
|
||||
DPP_AKM_DOT1X,
|
||||
};
|
||||
|
||||
enum dpp_netrole {
|
||||
@ -187,11 +228,14 @@ struct dpp_configuration {
|
||||
char *passphrase;
|
||||
u8 psk[32];
|
||||
int psk_set;
|
||||
|
||||
char *csrattrs;
|
||||
};
|
||||
|
||||
struct dpp_asymmetric_key {
|
||||
struct dpp_asymmetric_key *next;
|
||||
EVP_PKEY *csign;
|
||||
EVP_PKEY *pp_key;
|
||||
char *config_template;
|
||||
char *connector_template;
|
||||
};
|
||||
@ -199,26 +243,36 @@ struct dpp_asymmetric_key {
|
||||
#define DPP_MAX_CONF_OBJ 10
|
||||
|
||||
struct dpp_authentication {
|
||||
struct dpp_global *global;
|
||||
void *msg_ctx;
|
||||
u8 peer_version;
|
||||
const struct dpp_curve_params *curve;
|
||||
struct dpp_bootstrap_info *peer_bi;
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
struct dpp_bootstrap_info *tmp_own_bi;
|
||||
struct dpp_bootstrap_info *tmp_peer_bi;
|
||||
u8 waiting_pubkey_hash[SHA256_MAC_LEN];
|
||||
int response_pending;
|
||||
int reconfig;
|
||||
enum dpp_connector_key reconfig_connector_key;
|
||||
enum dpp_status_error auth_resp_status;
|
||||
enum dpp_status_error conf_resp_status;
|
||||
enum dpp_status_error force_conf_resp_status;
|
||||
u8 peer_mac_addr[ETH_ALEN];
|
||||
u8 i_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 r_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 e_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 c_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 i_capab;
|
||||
u8 r_capab;
|
||||
enum dpp_netrole e_netrole;
|
||||
EVP_PKEY *own_protocol_key;
|
||||
EVP_PKEY *peer_protocol_key;
|
||||
EVP_PKEY *reconfig_old_protocol_key;
|
||||
struct wpabuf *req_msg;
|
||||
struct wpabuf *resp_msg;
|
||||
struct wpabuf *reconfig_req_msg;
|
||||
struct wpabuf *reconfig_resp_msg;
|
||||
/* Intersection of possible frequencies for initiating DPP
|
||||
* Authentication exchange */
|
||||
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
|
||||
@ -236,6 +290,7 @@ struct dpp_authentication {
|
||||
u8 k1[DPP_MAX_HASH_LEN];
|
||||
u8 k2[DPP_MAX_HASH_LEN];
|
||||
u8 ke[DPP_MAX_HASH_LEN];
|
||||
u8 bk[DPP_MAX_HASH_LEN];
|
||||
int initiator;
|
||||
int waiting_auth_resp;
|
||||
int waiting_auth_conf;
|
||||
@ -248,8 +303,10 @@ struct dpp_authentication {
|
||||
int waiting_conf_result;
|
||||
int waiting_conn_status_result;
|
||||
int auth_success;
|
||||
bool reconfig_success;
|
||||
struct wpabuf *conf_req;
|
||||
const struct wpabuf *conf_resp; /* owned by GAS server */
|
||||
struct wpabuf *conf_resp_tcp;
|
||||
struct dpp_configuration *conf_ap;
|
||||
struct dpp_configuration *conf2_ap;
|
||||
struct dpp_configuration *conf_sta;
|
||||
@ -266,6 +323,11 @@ struct dpp_authentication {
|
||||
int psk_set;
|
||||
enum dpp_akm akm;
|
||||
struct wpabuf *c_sign_key;
|
||||
struct wpabuf *certbag;
|
||||
struct wpabuf *certs;
|
||||
struct wpabuf *cacert;
|
||||
char *server_name;
|
||||
struct wpabuf *pp_key;
|
||||
} conf_obj[DPP_MAX_CONF_OBJ];
|
||||
unsigned int num_conf_obj;
|
||||
struct dpp_asymmetric_key *conf_key_pkg;
|
||||
@ -274,6 +336,18 @@ struct dpp_authentication {
|
||||
int send_conn_status;
|
||||
int conn_status_requested;
|
||||
int akm_use_selector;
|
||||
int configurator_set;
|
||||
u8 transaction_id;
|
||||
u8 *csrattrs;
|
||||
size_t csrattrs_len;
|
||||
bool waiting_csr;
|
||||
struct wpabuf *csr;
|
||||
struct wpabuf *priv_key; /* DER-encoded private key used for csr */
|
||||
bool waiting_cert;
|
||||
char *trusted_eap_server_name;
|
||||
struct wpabuf *cacert;
|
||||
struct wpabuf *certbag;
|
||||
void *cert_resp_ctx;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
char *config_obj_override;
|
||||
char *discovery_override;
|
||||
@ -287,8 +361,12 @@ struct dpp_configurator {
|
||||
unsigned int id;
|
||||
int own;
|
||||
EVP_PKEY *csign;
|
||||
u8 kid_hash[SHA256_MAC_LEN];
|
||||
char *kid;
|
||||
const struct dpp_curve_params *curve;
|
||||
char *connector; /* own Connector for reconfiguration */
|
||||
EVP_PKEY *connector_key;
|
||||
EVP_PKEY *pp_key;
|
||||
};
|
||||
|
||||
struct dpp_introduction {
|
||||
@ -301,6 +379,7 @@ struct dpp_relay_config {
|
||||
const struct hostapd_ip_addr *ipaddr;
|
||||
const u8 *pkhash;
|
||||
|
||||
void *msg_ctx;
|
||||
void *cb_ctx;
|
||||
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
|
||||
size_t len);
|
||||
@ -311,6 +390,12 @@ struct dpp_relay_config {
|
||||
struct dpp_controller_config {
|
||||
const char *configurator_params;
|
||||
int tcp_port;
|
||||
u8 allowed_roles;
|
||||
int qr_mutual;
|
||||
enum dpp_netrole netrole;
|
||||
void *msg_ctx;
|
||||
void *cb_ctx;
|
||||
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
@ -422,15 +507,16 @@ extern size_t dpp_nonce_override_len;
|
||||
|
||||
void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
|
||||
const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type);
|
||||
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
|
||||
int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
|
||||
const char *chan_list);
|
||||
int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
|
||||
int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
|
||||
int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
|
||||
struct dpp_bootstrap_info *peer_bi);
|
||||
struct dpp_authentication *
|
||||
dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx);
|
||||
struct hostapd_hw_modes;
|
||||
struct dpp_authentication * dpp_auth_init(void *msg_ctx,
|
||||
struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
|
||||
struct dpp_bootstrap_info *peer_bi,
|
||||
struct dpp_bootstrap_info *own_bi,
|
||||
u8 dpp_allowed_roles,
|
||||
@ -438,8 +524,8 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx,
|
||||
struct hostapd_hw_modes *own_modes,
|
||||
u16 num_modes);
|
||||
struct dpp_authentication *
|
||||
dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
|
||||
struct dpp_bootstrap_info *peer_bi,
|
||||
dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
|
||||
int qr_mutual, struct dpp_bootstrap_info *peer_bi,
|
||||
struct dpp_bootstrap_info *own_bi,
|
||||
unsigned int freq, const u8 *hdr, const u8 *attr_start,
|
||||
size_t attr_len);
|
||||
@ -464,11 +550,13 @@ int dpp_akm_dpp(enum dpp_akm akm);
|
||||
int dpp_akm_ver2(enum dpp_akm akm);
|
||||
int dpp_configuration_valid(const struct dpp_configuration *conf);
|
||||
void dpp_configuration_free(struct dpp_configuration *conf);
|
||||
int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
|
||||
struct dpp_authentication *auth,
|
||||
const char *cmd);
|
||||
int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd);
|
||||
void dpp_auth_deinit(struct dpp_authentication *auth);
|
||||
struct wpabuf *
|
||||
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
|
||||
u16 e_nonce_len, enum dpp_netrole netrole,
|
||||
bool cert_req);
|
||||
struct wpabuf *
|
||||
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
|
||||
size_t attr_len);
|
||||
int dpp_conf_resp_rx(struct dpp_authentication *auth,
|
||||
@ -498,9 +586,6 @@ const char * dpp_akm_selector_str(enum dpp_akm akm);
|
||||
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
|
||||
size_t buflen);
|
||||
void dpp_configurator_free(struct dpp_configurator *conf);
|
||||
struct dpp_configurator *
|
||||
dpp_keygen_configurator(const char *curve, const u8 *privkey,
|
||||
size_t privkey_len);
|
||||
int dpp_configurator_own_config(struct dpp_authentication *auth,
|
||||
const char *curve, int ap);
|
||||
enum dpp_status_error
|
||||
@ -545,6 +630,11 @@ struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
|
||||
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
|
||||
void dpp_pfs_free(struct dpp_pfs *pfs);
|
||||
|
||||
struct wpabuf * dpp_build_csr(struct dpp_authentication *auth,
|
||||
const char *name);
|
||||
struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7);
|
||||
int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr);
|
||||
|
||||
struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
|
||||
const char *uri);
|
||||
struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
|
||||
@ -559,16 +649,21 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
|
||||
const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
|
||||
int dpp_bootstrap_info(struct dpp_global *dpp, int id,
|
||||
char *reply, int reply_size);
|
||||
int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params);
|
||||
void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
|
||||
const u8 *r_bootstrap,
|
||||
struct dpp_bootstrap_info **own_bi,
|
||||
struct dpp_bootstrap_info **peer_bi);
|
||||
struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
|
||||
const u8 *hash);
|
||||
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
|
||||
int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
|
||||
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
|
||||
char *buf, size_t buflen);
|
||||
int dpp_configurator_from_backup(struct dpp_global *dpp,
|
||||
struct dpp_asymmetric_key *key);
|
||||
struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
|
||||
const u8 *kid);
|
||||
int dpp_relay_add_controller(struct dpp_global *dpp,
|
||||
struct dpp_relay_config *config);
|
||||
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
|
||||
@ -579,18 +674,61 @@ int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
|
||||
int dpp_controller_start(struct dpp_global *dpp,
|
||||
struct dpp_controller_config *config);
|
||||
void dpp_controller_stop(struct dpp_global *dpp);
|
||||
struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
|
||||
unsigned int id);
|
||||
void dpp_controller_new_qr_code(struct dpp_global *dpp,
|
||||
struct dpp_bootstrap_info *bi);
|
||||
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
|
||||
const struct hostapd_ip_addr *addr, int port);
|
||||
const struct hostapd_ip_addr *addr, int port,
|
||||
const char *name, enum dpp_netrole netrole, void *msg_ctx,
|
||||
void *cb_ctx,
|
||||
int (*process_conf_obj)(void *ctx,
|
||||
struct dpp_authentication *auth));
|
||||
|
||||
struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
|
||||
void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
|
||||
unsigned int freq, const u8 *hash);
|
||||
|
||||
struct dpp_global_config {
|
||||
void *msg_ctx;
|
||||
void *cb_ctx;
|
||||
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
|
||||
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
|
||||
};
|
||||
|
||||
struct dpp_global * dpp_global_init(struct dpp_global_config *config);
|
||||
void dpp_global_clear(struct dpp_global *dpp);
|
||||
void dpp_global_deinit(struct dpp_global *dpp);
|
||||
|
||||
/* dpp_reconfig.c */
|
||||
|
||||
struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
|
||||
size_t csign_key_len,
|
||||
const u8 *net_access_key,
|
||||
size_t net_access_key_len,
|
||||
struct dpp_reconfig_id *id);
|
||||
struct dpp_authentication *
|
||||
dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
|
||||
struct dpp_configurator *conf, unsigned int freq, u16 group,
|
||||
const u8 *a_nonce_attr, size_t a_nonce_len,
|
||||
const u8 *e_id_attr, size_t e_id_len);
|
||||
struct dpp_authentication *
|
||||
dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
|
||||
const char *own_connector,
|
||||
const u8 *net_access_key, size_t net_access_key_len,
|
||||
const u8 *csign_key, size_t csign_key_len,
|
||||
unsigned int freq, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
struct wpabuf *
|
||||
dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
|
||||
struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
|
||||
size_t csign_key_len,
|
||||
const u8 *pp_key,
|
||||
size_t pp_key_len);
|
||||
int dpp_update_reconfig_id(struct dpp_reconfig_id *id);
|
||||
void dpp_free_reconfig_id(struct dpp_reconfig_id *id);
|
||||
|
||||
#endif /* CONFIG_DPP */
|
||||
#endif /* DPP_H */
|
||||
|
1976
src/common/dpp_auth.c
Normal file
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
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
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
160
src/common/dpp_i.h
Normal 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
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
958
src/common/dpp_reconfig.c
Normal 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
1794
src/common/dpp_tcp.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) server
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2020, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -23,8 +24,9 @@ struct gas_server_handler {
|
||||
struct dl_list list;
|
||||
u8 adv_proto_id[MAX_ADV_PROTO_ID_LEN];
|
||||
u8 adv_proto_id_len;
|
||||
struct wpabuf * (*req_cb)(void *ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len);
|
||||
struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len,
|
||||
u16 *comeback_delay);
|
||||
void (*status_cb)(void *ctx, struct wpabuf *resp, int ok);
|
||||
void *ctx;
|
||||
struct gas_server *gas;
|
||||
@ -39,6 +41,7 @@ struct gas_server_response {
|
||||
u8 dst[ETH_ALEN];
|
||||
u8 dialog_token;
|
||||
struct gas_server_handler *handler;
|
||||
u16 comeback_delay;
|
||||
};
|
||||
|
||||
struct gas_server {
|
||||
@ -61,7 +64,8 @@ static void gas_server_response_timeout(void *eloop_ctx, void *user_ctx)
|
||||
response, MAC2STR(response->dst), response->dialog_token,
|
||||
response->freq, response->frag_id,
|
||||
(unsigned long) response->offset,
|
||||
(unsigned long) wpabuf_len(response->resp));
|
||||
(unsigned long) (response->resp ?
|
||||
wpabuf_len(response->resp) : 0));
|
||||
response->handler->status_cb(response->handler->ctx,
|
||||
response->resp, 0);
|
||||
response->resp = NULL;
|
||||
@ -83,30 +87,29 @@ static void gas_server_free_response(struct gas_server_response *response)
|
||||
|
||||
static void
|
||||
gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
|
||||
struct gas_server_response *response,
|
||||
const u8 *da, int freq, u8 dialog_token,
|
||||
struct wpabuf *query_resp)
|
||||
struct wpabuf *query_resp, u16 comeback_delay)
|
||||
{
|
||||
size_t max_len = (freq > 56160) ? 928 : 1400;
|
||||
size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2;
|
||||
size_t resp_frag_len;
|
||||
struct wpabuf *resp;
|
||||
u16 comeback_delay;
|
||||
struct gas_server_response *response;
|
||||
|
||||
if (!query_resp)
|
||||
return;
|
||||
|
||||
response = os_zalloc(sizeof(*response));
|
||||
if (!response) {
|
||||
wpabuf_free(query_resp);
|
||||
if (comeback_delay == 0 && !query_resp) {
|
||||
gas_server_free_response(response);
|
||||
return;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
|
||||
|
||||
response->freq = freq;
|
||||
response->handler = handler;
|
||||
os_memcpy(response->dst, da, ETH_ALEN);
|
||||
response->dialog_token = dialog_token;
|
||||
if (hdr_len + wpabuf_len(query_resp) > max_len) {
|
||||
if (comeback_delay) {
|
||||
/* Need more time to prepare the response */
|
||||
resp_frag_len = 0;
|
||||
response->comeback_delay = comeback_delay;
|
||||
} else if (hdr_len + wpabuf_len(query_resp) > max_len) {
|
||||
/* Need to use comeback to initiate fragmentation */
|
||||
comeback_delay = 1;
|
||||
resp_frag_len = 0;
|
||||
@ -135,10 +138,12 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler,
|
||||
|
||||
/* Query Response Length */
|
||||
wpabuf_put_le16(resp, resp_frag_len);
|
||||
if (!comeback_delay)
|
||||
if (!comeback_delay && query_resp)
|
||||
wpabuf_put_buf(resp, query_resp);
|
||||
|
||||
if (comeback_delay) {
|
||||
if (comeback_delay && !query_resp) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No response available yet");
|
||||
} else if (comeback_delay) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Need to fragment query response");
|
||||
} else {
|
||||
@ -165,6 +170,7 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
u16 query_req_len;
|
||||
struct gas_server_handler *handler;
|
||||
struct wpabuf *resp;
|
||||
struct gas_server_response *response;
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame",
|
||||
data, len);
|
||||
@ -210,8 +216,15 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
pos, end - pos);
|
||||
}
|
||||
|
||||
response = os_zalloc(sizeof(*response));
|
||||
if (!response)
|
||||
return -1;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
|
||||
dl_list_for_each(handler, &gas->handlers, struct gas_server_handler,
|
||||
list) {
|
||||
u16 comeback_delay = 0;
|
||||
|
||||
if (adv_proto_len < 1 + handler->adv_proto_id_len ||
|
||||
os_memcmp(adv_proto + 1, handler->adv_proto_id,
|
||||
handler->adv_proto_id_len) != 0)
|
||||
@ -219,17 +232,22 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Calling handler for the requested Advertisement Protocol ID");
|
||||
resp = handler->req_cb(handler->ctx, sa, query_req,
|
||||
query_req_len);
|
||||
resp = handler->req_cb(handler->ctx, response, sa, query_req,
|
||||
query_req_len, &comeback_delay);
|
||||
wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler",
|
||||
resp);
|
||||
gas_server_send_resp(gas, handler, sa, freq, dialog_token,
|
||||
resp);
|
||||
if (comeback_delay)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Handler requested comeback delay: %u TU",
|
||||
comeback_delay);
|
||||
gas_server_send_resp(gas, handler, response, sa, freq,
|
||||
dialog_token, resp, comeback_delay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: No registered handler for the requested Advertisement Protocol ID");
|
||||
gas_server_free_response(response);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -243,6 +261,31 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
|
||||
size_t hdr_len = 24 + 2 + 6 + 3 + handler->adv_proto_id_len + 2;
|
||||
size_t remaining, resp_frag_len;
|
||||
struct wpabuf *resp;
|
||||
unsigned int wait_time = 0;
|
||||
|
||||
if (!response->resp) {
|
||||
resp = gas_build_comeback_resp(response->dialog_token,
|
||||
WLAN_STATUS_SUCCESS, 0, 0,
|
||||
response->comeback_delay,
|
||||
handler->adv_proto_id_len);
|
||||
if (!resp) {
|
||||
dl_list_del(&response->list);
|
||||
gas_server_free_response(response);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Advertisement Protocol element */
|
||||
wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */
|
||||
wpabuf_put_u8(resp, 0x7f);
|
||||
/* Advertisement Protocol ID */
|
||||
wpabuf_put_data(resp, handler->adv_proto_id,
|
||||
handler->adv_proto_id_len);
|
||||
|
||||
/* Query Response Length */
|
||||
wpabuf_put_le16(resp, 0);
|
||||
goto send_resp;
|
||||
}
|
||||
|
||||
remaining = wpabuf_len(response->resp) - response->offset;
|
||||
if (hdr_len + remaining > max_len)
|
||||
@ -279,8 +322,11 @@ gas_server_handle_rx_comeback_req(struct gas_server_response *response)
|
||||
|
||||
response->offset += resp_frag_len;
|
||||
|
||||
gas->tx(gas->ctx, response->freq, response->dst, resp,
|
||||
remaining > resp_frag_len ? 2000 : 0);
|
||||
if (remaining > resp_frag_len)
|
||||
wait_time = 2000;
|
||||
|
||||
send_resp:
|
||||
gas->tx(gas->ctx, response->freq, response->dst, resp, wait_time);
|
||||
wpabuf_free(resp);
|
||||
}
|
||||
|
||||
@ -359,12 +405,19 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
static void gas_server_handle_tx_status(struct gas_server_response *response,
|
||||
int ack)
|
||||
{
|
||||
if (ack && response->offset < wpabuf_len(response->resp)) {
|
||||
if (ack && response->resp &&
|
||||
response->offset < wpabuf_len(response->resp)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: More fragments remaining - keep pending entry");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ack && !response->resp && response->comeback_delay) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Waiting for response - keep pending entry");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ack)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: No ACK received - drop pending entry");
|
||||
@ -415,6 +468,27 @@ void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
|
||||
}
|
||||
|
||||
|
||||
int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
|
||||
struct wpabuf *resp)
|
||||
{
|
||||
struct gas_server_response *tmp, *response = NULL;
|
||||
|
||||
dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
|
||||
list) {
|
||||
if (tmp == resp_ctx) {
|
||||
response = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!response || response->resp)
|
||||
return -1;
|
||||
|
||||
response->resp = resp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct gas_server * gas_server_init(void *ctx,
|
||||
void (*tx)(void *ctx, int freq,
|
||||
const u8 *da,
|
||||
@ -461,8 +535,9 @@ void gas_server_deinit(struct gas_server *gas)
|
||||
int gas_server_register(struct gas_server *gas,
|
||||
const u8 *adv_proto_id, u8 adv_proto_id_len,
|
||||
struct wpabuf *
|
||||
(*req_cb)(void *ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len),
|
||||
(*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len,
|
||||
u16 *comeback_delay),
|
||||
void (*status_cb)(void *ctx, struct wpabuf *resp,
|
||||
int ok),
|
||||
void *ctx)
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) server
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2020, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -22,8 +23,9 @@ void gas_server_deinit(struct gas_server *gas);
|
||||
int gas_server_register(struct gas_server *gas,
|
||||
const u8 *adv_proto_id, u8 adv_proto_id_len,
|
||||
struct wpabuf *
|
||||
(*req_cb)(void *ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len),
|
||||
(*req_cb)(void *ctx, void *resp_ctx, const u8 *sa,
|
||||
const u8 *query, size_t query_len,
|
||||
u16 *comeback_delay),
|
||||
void (*status_cb)(void *ctx, struct wpabuf *resp,
|
||||
int ok),
|
||||
void *ctx);
|
||||
@ -32,6 +34,8 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa,
|
||||
int freq);
|
||||
void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
|
||||
size_t data_len, int ack);
|
||||
int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
|
||||
struct wpabuf *resp);
|
||||
|
||||
#else /* CONFIG_GAS_SERVER */
|
||||
|
||||
|
@ -415,7 +415,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (center_idx_to_bw_6ghz(channel) != 0) {
|
||||
if (center_idx_to_bw_6ghz(channel) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Invalid control channel for 6 GHz band");
|
||||
return -1;
|
||||
@ -475,13 +475,46 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data->vht_enabled) switch (oper_chwidth) {
|
||||
if (data->he_enabled) switch (oper_chwidth) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
if (center_segment1 ||
|
||||
(center_segment0 != 0 &&
|
||||
5000 + center_segment0 * 5 != data->center_freq1 &&
|
||||
2407 + center_segment0 * 5 != data->center_freq1))
|
||||
if (mode == HOSTAPD_MODE_IEEE80211G && sec_channel_offset) {
|
||||
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"40 MHz channel width is not supported in 2.4 GHz");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case CHANWIDTH_80MHZ:
|
||||
if (mode == HOSTAPD_MODE_IEEE80211A) {
|
||||
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"40/80 MHz channel width is not supported in 5/6 GHz");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"80+80 MHz channel width is not supported in 5/6 GHz");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
|
||||
HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"160 MHz channel width is not supported in 5 / 6GHz");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
} else if (data->vht_enabled) switch (oper_chwidth) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
|
||||
@ -489,9 +522,38 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
"80+80 channel width is not supported!");
|
||||
return -1;
|
||||
}
|
||||
if (center_segment1 == center_segment0 + 4 ||
|
||||
center_segment1 == center_segment0 - 4)
|
||||
/* fall through */
|
||||
case CHANWIDTH_80MHZ:
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
|
||||
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"160 MHz channel width is not supported!");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) {
|
||||
case CHANWIDTH_USE_HT:
|
||||
if (center_segment1 ||
|
||||
(center_segment0 != 0 &&
|
||||
5000 + center_segment0 * 5 != data->center_freq1 &&
|
||||
2407 + center_segment0 * 5 != data->center_freq1)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"20/40 MHz: center segment 0 (=%d) and center freq 1 (=%d) not in sync",
|
||||
center_segment0, data->center_freq1);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
if (center_segment1 == center_segment0 + 4 ||
|
||||
center_segment1 == center_segment0 - 4) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"80+80 MHz: center segment 1 only 20 MHz apart");
|
||||
return -1;
|
||||
}
|
||||
data->center_freq2 = 5000 + center_segment1 * 5;
|
||||
/* fall through */
|
||||
case CHANWIDTH_80MHZ:
|
||||
@ -500,8 +562,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
center_segment1) ||
|
||||
(oper_chwidth == CHANWIDTH_80P80MHZ &&
|
||||
!center_segment1) ||
|
||||
!sec_channel_offset)
|
||||
!sec_channel_offset) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"80/80+80 MHz: center segment 1 wrong or no second channel offset");
|
||||
return -1;
|
||||
}
|
||||
if (!center_segment0) {
|
||||
if (channel <= 48)
|
||||
center_segment0 = 42;
|
||||
@ -527,22 +592,25 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
center_segment0 == channel - 2 ||
|
||||
center_segment0 == channel - 6)
|
||||
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||
else
|
||||
else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Wrong coupling between HT and VHT/HE channel setting");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
data->bandwidth = 160;
|
||||
if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
|
||||
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
|
||||
if (center_segment1) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"160MHZ channel width is not supported!");
|
||||
"160 MHz: center segment 1 should not be set");
|
||||
return -1;
|
||||
}
|
||||
if (center_segment1)
|
||||
return -1;
|
||||
if (!sec_channel_offset)
|
||||
if (!sec_channel_offset) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"160 MHz: second channel offset not set");
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Note: HT/VHT config and params are coupled. Check if
|
||||
* HT40 channel band is in VHT160 channel band configuration.
|
||||
@ -556,8 +624,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
|
||||
center_segment0 == channel - 10 ||
|
||||
center_segment0 == channel - 14)
|
||||
data->center_freq1 = 5000 + center_segment0 * 5;
|
||||
else
|
||||
else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"160 MHz: HT40 channel band is not in 160 MHz band");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,16 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
|
||||
elems->multi_ap = pos;
|
||||
elems->multi_ap_len = elen;
|
||||
break;
|
||||
case OWE_OUI_TYPE:
|
||||
/* OWE Transition Mode element */
|
||||
break;
|
||||
case DPP_CC_OUI_TYPE:
|
||||
/* DPP Configurator Connectivity element */
|
||||
break;
|
||||
case SAE_PK_OUI_TYPE:
|
||||
elems->sae_pk = pos + 4;
|
||||
elems->sae_pk_len = elen - 4;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
|
||||
"information element ignored "
|
||||
@ -206,6 +216,8 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
|
||||
ext_id = *pos++;
|
||||
elen--;
|
||||
|
||||
elems->frag_ies.last_eid_ext = 0;
|
||||
|
||||
switch (ext_id) {
|
||||
case WLAN_EID_EXT_ASSOC_DELAY_INFO:
|
||||
if (elen != 1)
|
||||
@ -245,9 +257,9 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
|
||||
elems->key_delivery = pos;
|
||||
elems->key_delivery_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_WRAPPED_DATA:
|
||||
elems->fils_wrapped_data = pos;
|
||||
elems->fils_wrapped_data_len = elen;
|
||||
case WLAN_EID_EXT_WRAPPED_DATA:
|
||||
elems->wrapped_data = pos;
|
||||
elems->wrapped_data_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_FILS_PUBLIC_KEY:
|
||||
if (elen < 1)
|
||||
@ -286,6 +298,11 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
|
||||
elems->short_ssid_list = pos;
|
||||
elems->short_ssid_list_len = elen;
|
||||
break;
|
||||
case WLAN_EID_EXT_HE_6GHZ_BAND_CAP:
|
||||
if (elen < sizeof(struct ieee80211_he_6ghz_band_cap))
|
||||
break;
|
||||
elems->he_6ghz_band_cap = pos;
|
||||
break;
|
||||
default:
|
||||
if (show_errors) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
@ -295,10 +312,39 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (elen == 254)
|
||||
elems->frag_ies.last_eid_ext = ext_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies,
|
||||
const u8 *pos, u8 elen)
|
||||
{
|
||||
if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) {
|
||||
wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: while EID == 0 is a valid ID (SSID IE), it should not be
|
||||
* fragmented.
|
||||
*/
|
||||
if (!frag_ies->last_eid) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"Fragment without a valid last element - skip");
|
||||
return;
|
||||
}
|
||||
|
||||
frag_ies->frags[frag_ies->n_frags].ie = pos;
|
||||
frag_ies->frags[frag_ies->n_frags].ie_len = elen;
|
||||
frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid;
|
||||
frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext;
|
||||
frag_ies->n_frags++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ieee802_11_parse_elems - Parse information elements in management frames
|
||||
* @start: Pointer to the start of IEs
|
||||
@ -331,6 +377,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elen);
|
||||
break;
|
||||
}
|
||||
if (elems->ssid) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"Ignored duplicated SSID element");
|
||||
break;
|
||||
}
|
||||
elems->ssid = pos;
|
||||
elems->ssid_len = elen;
|
||||
break;
|
||||
@ -515,8 +566,13 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elems->dils = pos;
|
||||
elems->dils_len = elen;
|
||||
break;
|
||||
case WLAN_EID_S1G_CAPABILITIES:
|
||||
if (elen < 15)
|
||||
break;
|
||||
elems->s1g_capab = pos;
|
||||
break;
|
||||
case WLAN_EID_FRAGMENT:
|
||||
/* TODO */
|
||||
ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
|
||||
break;
|
||||
case WLAN_EID_EXTENSION:
|
||||
if (ieee802_11_parse_extension(pos, elen, elems,
|
||||
@ -532,6 +588,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
id, elen);
|
||||
break;
|
||||
}
|
||||
|
||||
if (id != WLAN_EID_FRAGMENT && elen == 255)
|
||||
elems->frag_ies.last_eid = id;
|
||||
|
||||
if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext)
|
||||
elems->frag_ies.last_eid = 0;
|
||||
}
|
||||
|
||||
if (!for_each_element_completed(elem, start, len)) {
|
||||
@ -710,6 +772,98 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
|
||||
}
|
||||
|
||||
|
||||
/* convert floats with one decimal place to value*10 int, i.e.,
|
||||
* "1.5" will return 15
|
||||
*/
|
||||
static int hostapd_config_read_int10(const char *value)
|
||||
{
|
||||
int i, d;
|
||||
char *pos;
|
||||
|
||||
i = atoi(value);
|
||||
pos = os_strchr(value, '.');
|
||||
d = 0;
|
||||
if (pos) {
|
||||
pos++;
|
||||
if (*pos >= '0' && *pos <= '9')
|
||||
d = *pos - '0';
|
||||
}
|
||||
|
||||
return i * 10 + d;
|
||||
}
|
||||
|
||||
|
||||
static int valid_cw(int cw)
|
||||
{
|
||||
return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
|
||||
cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
|
||||
cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
|
||||
cw == 32767);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_config_tx_queue(struct hostapd_tx_queue_params tx_queue[],
|
||||
const char *name, const char *val)
|
||||
{
|
||||
int num;
|
||||
const char *pos;
|
||||
struct hostapd_tx_queue_params *queue;
|
||||
|
||||
/* skip 'tx_queue_' prefix */
|
||||
pos = name + 9;
|
||||
if (os_strncmp(pos, "data", 4) == 0 &&
|
||||
pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
|
||||
num = pos[4] - '0';
|
||||
pos += 6;
|
||||
} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
|
||||
os_strncmp(pos, "beacon_", 7) == 0) {
|
||||
wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
|
||||
return 0;
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num >= NUM_TX_QUEUES) {
|
||||
/* for backwards compatibility, do not trigger failure */
|
||||
wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
queue = &tx_queue[num];
|
||||
|
||||
if (os_strcmp(pos, "aifs") == 0) {
|
||||
queue->aifs = atoi(val);
|
||||
if (queue->aifs < 0 || queue->aifs > 255) {
|
||||
wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
|
||||
queue->aifs);
|
||||
return -1;
|
||||
}
|
||||
} else if (os_strcmp(pos, "cwmin") == 0) {
|
||||
queue->cwmin = atoi(val);
|
||||
if (!valid_cw(queue->cwmin)) {
|
||||
wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
|
||||
queue->cwmin);
|
||||
return -1;
|
||||
}
|
||||
} else if (os_strcmp(pos, "cwmax") == 0) {
|
||||
queue->cwmax = atoi(val);
|
||||
if (!valid_cw(queue->cwmax)) {
|
||||
wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
|
||||
queue->cwmax);
|
||||
return -1;
|
||||
}
|
||||
} else if (os_strcmp(pos, "burst") == 0) {
|
||||
queue->burst = hostapd_config_read_int10(val);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Unknown queue field '%s'", pos);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
|
||||
{
|
||||
u8 op_class;
|
||||
@ -880,16 +1034,35 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
if (freq > 5940 && freq <= 7105) {
|
||||
int bw;
|
||||
u8 idx = (freq - 5940) / 5;
|
||||
|
||||
bw = center_idx_to_bw_6ghz(idx);
|
||||
if (bw < 0)
|
||||
if (freq > 5950 && freq <= 7115) {
|
||||
if ((freq - 5950) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
*channel = idx;
|
||||
*op_class = 131 + bw;
|
||||
switch (chanwidth) {
|
||||
case CHANWIDTH_80MHZ:
|
||||
*op_class = 133;
|
||||
break;
|
||||
case CHANWIDTH_160MHZ:
|
||||
*op_class = 134;
|
||||
break;
|
||||
case CHANWIDTH_80P80MHZ:
|
||||
*op_class = 135;
|
||||
break;
|
||||
default:
|
||||
if (sec_channel)
|
||||
*op_class = 132;
|
||||
else
|
||||
*op_class = 131;
|
||||
break;
|
||||
}
|
||||
|
||||
*channel = (freq - 5950) / 5;
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
if (freq == 5935) {
|
||||
*op_class = 136;
|
||||
*channel = (freq - 5925) / 5;
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
@ -1269,7 +1442,11 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
|
||||
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
|
||||
if (chan < 1 || chan > 233)
|
||||
return -1;
|
||||
return 5940 + chan * 5;
|
||||
return 5950 + chan * 5;
|
||||
case 136: /* UHB channels, 20 MHz: 2 */
|
||||
if (chan == 2)
|
||||
return 5935;
|
||||
return -1;
|
||||
case 180: /* 60 GHz band, channels 1..8 */
|
||||
if (chan < 1 || chan > 8)
|
||||
return -1;
|
||||
@ -1613,7 +1790,9 @@ const char * status2str(u16 status)
|
||||
S2S(FILS_AUTHENTICATION_FAILURE)
|
||||
S2S(UNKNOWN_AUTHENTICATION_SERVER)
|
||||
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
|
||||
S2S(DENIED_HE_NOT_SUPPORTED)
|
||||
S2S(SAE_HASH_TO_ELEMENT)
|
||||
S2S(SAE_PK)
|
||||
}
|
||||
return "UNKNOWN";
|
||||
#undef S2S
|
||||
@ -1711,8 +1890,12 @@ const struct oper_class_map global_op_class[] = {
|
||||
*/
|
||||
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP },
|
||||
|
||||
/*
|
||||
* IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
|
||||
@ -1723,6 +1906,12 @@ const struct oper_class_map global_op_class[] = {
|
||||
{ HOSTAPD_MODE_IEEE80211AD, 181, 9, 13, 1, BW4320, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211AD, 182, 17, 20, 1, BW6480, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211AD, 183, 25, 27, 1, BW8640, P2P_SUPP },
|
||||
|
||||
/* Keep the operating class 130 as the last entry as a workaround for
|
||||
* the OneHundredAndThirty Delimiter value used in the Supported
|
||||
* Operating Classes element to indicate the end of the Operating
|
||||
* Classes field. */
|
||||
{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
|
||||
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
|
||||
};
|
||||
|
||||
@ -2020,6 +2209,7 @@ int oper_class_bw_to_int(const struct oper_class_map *map)
|
||||
switch (map->bw) {
|
||||
case BW20:
|
||||
return 20;
|
||||
case BW40:
|
||||
case BW40PLUS:
|
||||
case BW40MINUS:
|
||||
return 40;
|
||||
@ -2055,41 +2245,44 @@ int center_idx_to_bw_6ghz(u8 idx)
|
||||
}
|
||||
|
||||
|
||||
int is_6ghz_freq(int freq)
|
||||
bool is_6ghz_freq(int freq)
|
||||
{
|
||||
if (freq < 5940 || freq > 7105)
|
||||
return 0;
|
||||
if (freq < 5935 || freq > 7115)
|
||||
return false;
|
||||
|
||||
if (center_idx_to_bw_6ghz((freq - 5940) / 5) < 0)
|
||||
return 0;
|
||||
if (freq == 5935)
|
||||
return true;
|
||||
|
||||
return 1;
|
||||
if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int is_6ghz_op_class(u8 op_class)
|
||||
bool is_6ghz_op_class(u8 op_class)
|
||||
{
|
||||
return op_class >= 131 && op_class <= 135;
|
||||
return op_class >= 131 && op_class <= 136;
|
||||
}
|
||||
|
||||
|
||||
int is_6ghz_psc_frequency(int freq)
|
||||
bool is_6ghz_psc_frequency(int freq)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!is_6ghz_freq(freq))
|
||||
return 0;
|
||||
if ((((freq - 5940) / 5) & 0x3) != 0x1)
|
||||
return 0;
|
||||
if (!is_6ghz_freq(freq) || freq == 5935)
|
||||
return false;
|
||||
if ((((freq - 5950) / 5) & 0x3) != 0x1)
|
||||
return false;
|
||||
|
||||
i = (freq - 5940 + 55) % 80;
|
||||
i = (freq - 5950 + 55) % 80;
|
||||
if (i == 0)
|
||||
i = (freq - 5940 + 55) / 80;
|
||||
i = (freq - 5950 + 55) / 80;
|
||||
|
||||
if (i >= 1 && i <= 15)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -2320,6 +2513,8 @@ int op_class_to_bandwidth(u8 op_class)
|
||||
case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
|
||||
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
|
||||
return 160;
|
||||
case 136: /* UHB channels, 20 MHz: 2 */
|
||||
return 20;
|
||||
case 180: /* 60 GHz band, channels 1..8 */
|
||||
return 2160;
|
||||
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
|
||||
@ -2380,6 +2575,8 @@ int op_class_to_ch_width(u8 op_class)
|
||||
return CHANWIDTH_160MHZ;
|
||||
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
|
||||
return CHANWIDTH_80P80MHZ;
|
||||
case 136: /* UHB channels, 20 MHz: 2 */
|
||||
return CHANWIDTH_USE_HT;
|
||||
case 180: /* 60 GHz band, channels 1..8 */
|
||||
return CHANWIDTH_2160MHZ;
|
||||
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
|
||||
@ -2391,3 +2588,78 @@ int op_class_to_ch_width(u8 op_class)
|
||||
}
|
||||
return CHANWIDTH_USE_HT;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
|
||||
u8 eid, u8 eid_ext,
|
||||
const u8 *data, u8 len)
|
||||
{
|
||||
struct frag_ies_info *frag_ies = &elems->frag_ies;
|
||||
struct wpabuf *buf;
|
||||
unsigned int i;
|
||||
|
||||
if (!elems || !data || !len)
|
||||
return NULL;
|
||||
|
||||
buf = wpabuf_alloc_copy(data, len);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < frag_ies->n_frags; i++) {
|
||||
int ret;
|
||||
|
||||
if (frag_ies->frags[i].eid != eid ||
|
||||
frag_ies->frags[i].eid_ext != eid_ext)
|
||||
continue;
|
||||
|
||||
ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len);
|
||||
if (ret < 0) {
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Copy only the fragment data (without the EID and length) */
|
||||
wpabuf_put_data(buf, frag_ies->frags[i].ie,
|
||||
frag_ies->frags[i].ie_len);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
|
||||
u8 eid, u8 eid_ext)
|
||||
{
|
||||
const u8 *data;
|
||||
u8 len;
|
||||
|
||||
/*
|
||||
* TODO: Defragmentation mechanism can be supported for all IEs. For now
|
||||
* handle only those that are used (or use ieee802_11_defrag_data()).
|
||||
*/
|
||||
switch (eid) {
|
||||
case WLAN_EID_EXTENSION:
|
||||
switch (eid_ext) {
|
||||
case WLAN_EID_EXT_FILS_HLP_CONTAINER:
|
||||
data = elems->fils_hlp;
|
||||
len = elems->fils_hlp_len;
|
||||
break;
|
||||
case WLAN_EID_EXT_WRAPPED_DATA:
|
||||
data = elems->wrapped_data;
|
||||
len = elems->wrapped_data_len;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Defragmentation not supported. eid_ext=%u",
|
||||
eid_ext);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Defragmentation not supported. eid=%u", eid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ieee802_11_defrag_data(elems, eid, eid_ext, data, len);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ struct element {
|
||||
struct hostapd_hw_modes;
|
||||
|
||||
#define MAX_NOF_MB_IES_SUPPORTED 5
|
||||
#define MAX_NUM_FRAG_IES_SUPPORTED 3
|
||||
|
||||
struct mb_ies_info {
|
||||
struct {
|
||||
@ -30,6 +31,21 @@ struct mb_ies_info {
|
||||
u8 nof_ies;
|
||||
};
|
||||
|
||||
struct frag_ies_info {
|
||||
struct {
|
||||
u8 eid;
|
||||
u8 eid_ext;
|
||||
const u8 *ie;
|
||||
u8 ie_len;
|
||||
} frags[MAX_NUM_FRAG_IES_SUPPORTED];
|
||||
|
||||
u8 n_frags;
|
||||
|
||||
/* the last parsed element ID and element extension ID */
|
||||
u8 last_eid;
|
||||
u8 last_eid_ext;
|
||||
};
|
||||
|
||||
/* Parsed Information Elements */
|
||||
struct ieee802_11_elems {
|
||||
const u8 *ssid;
|
||||
@ -85,7 +101,7 @@ struct ieee802_11_elems {
|
||||
const u8 *fils_hlp;
|
||||
const u8 *fils_ip_addr_assign;
|
||||
const u8 *key_delivery;
|
||||
const u8 *fils_wrapped_data;
|
||||
const u8 *wrapped_data;
|
||||
const u8 *fils_pk;
|
||||
const u8 *fils_nonce;
|
||||
const u8 *owe_dh;
|
||||
@ -97,6 +113,9 @@ struct ieee802_11_elems {
|
||||
const u8 *he_capabilities;
|
||||
const u8 *he_operation;
|
||||
const u8 *short_ssid_list;
|
||||
const u8 *he_6ghz_band_cap;
|
||||
const u8 *sae_pk;
|
||||
const u8 *s1g_capab;
|
||||
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
@ -138,7 +157,7 @@ struct ieee802_11_elems {
|
||||
u8 fils_hlp_len;
|
||||
u8 fils_ip_addr_assign_len;
|
||||
u8 key_delivery_len;
|
||||
u8 fils_wrapped_data_len;
|
||||
u8 wrapped_data_len;
|
||||
u8 fils_pk_len;
|
||||
u8 owe_dh_len;
|
||||
u8 power_capab_len;
|
||||
@ -149,8 +168,10 @@ struct ieee802_11_elems {
|
||||
u8 he_capabilities_len;
|
||||
u8 he_operation_len;
|
||||
u8 short_ssid_list_len;
|
||||
u8 sae_pk_len;
|
||||
|
||||
struct mb_ies_info mb_ies;
|
||||
struct frag_ies_info frag_ies;
|
||||
};
|
||||
|
||||
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
|
||||
@ -174,6 +195,18 @@ struct hostapd_wmm_ac_params {
|
||||
|
||||
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
|
||||
const char *name, const char *val);
|
||||
|
||||
struct hostapd_tx_queue_params {
|
||||
int aifs;
|
||||
int cwmin;
|
||||
int cwmax;
|
||||
int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
|
||||
};
|
||||
|
||||
#define NUM_TX_QUEUES 4
|
||||
|
||||
int hostapd_config_tx_queue(struct hostapd_tx_queue_params queue[],
|
||||
const char *name, const char *val);
|
||||
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
|
||||
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
|
||||
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
@ -200,8 +233,8 @@ struct oper_class_map {
|
||||
u8 min_chan;
|
||||
u8 max_chan;
|
||||
u8 inc;
|
||||
enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80, BW4320,
|
||||
BW6480, BW8640} bw;
|
||||
enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80,
|
||||
BW4320, BW6480, BW8640} bw;
|
||||
enum { P2P_SUPP, NO_P2P_SUPP } p2p;
|
||||
};
|
||||
|
||||
@ -226,9 +259,9 @@ u8 country_to_global_op_class(const char *country, u8 op_class);
|
||||
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
|
||||
int oper_class_bw_to_int(const struct oper_class_map *map);
|
||||
int center_idx_to_bw_6ghz(u8 idx);
|
||||
int is_6ghz_freq(int freq);
|
||||
int is_6ghz_op_class(u8 op_class);
|
||||
int is_6ghz_psc_frequency(int freq);
|
||||
bool is_6ghz_freq(int freq);
|
||||
bool is_6ghz_op_class(u8 op_class);
|
||||
bool is_6ghz_psc_frequency(int freq);
|
||||
|
||||
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
|
||||
size_t nei_rep_len);
|
||||
@ -293,4 +326,10 @@ void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
|
||||
int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
|
||||
struct ieee80211_edmg_config requested);
|
||||
|
||||
struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
|
||||
u8 eid, u8 eid_ext,
|
||||
const u8 *data, u8 len);
|
||||
struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
|
||||
u8 eid, u8 eid_ext);
|
||||
|
||||
#endif /* IEEE802_11_COMMON_H */
|
||||
|
@ -204,7 +204,9 @@
|
||||
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
|
||||
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
|
||||
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
|
||||
#define WLAN_STATUS_DENIED_HE_NOT_SUPPORTED 124
|
||||
#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126
|
||||
#define WLAN_STATUS_SAE_PK 127
|
||||
|
||||
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
|
||||
#define WLAN_REASON_UNSPECIFIED 1
|
||||
@ -441,7 +443,10 @@
|
||||
#define WLAN_EID_DEVICE_LOCATION 204
|
||||
#define WLAN_EID_WHITE_SPACE_MAP 205
|
||||
#define WLAN_EID_FTM_PARAMETERS 206
|
||||
#define WLAN_EID_S1G_BCN_COMPAT 213
|
||||
#define WLAN_EID_S1G_CAPABILITIES 217
|
||||
#define WLAN_EID_VENDOR_SPECIFIC 221
|
||||
#define WLAN_EID_S1G_OPERATION 232
|
||||
#define WLAN_EID_CAG_NUMBER 237
|
||||
#define WLAN_EID_AP_CSN 239
|
||||
#define WLAN_EID_FILS_INDICATION 240
|
||||
@ -458,7 +463,7 @@
|
||||
#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
|
||||
#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
|
||||
#define WLAN_EID_EXT_KEY_DELIVERY 7
|
||||
#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
|
||||
#define WLAN_EID_EXT_WRAPPED_DATA 8
|
||||
#define WLAN_EID_EXT_FTM_SYNC_INFO 9
|
||||
#define WLAN_EID_EXT_EXTENDED_REQUEST 10
|
||||
#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
|
||||
@ -473,8 +478,11 @@
|
||||
#define WLAN_EID_EXT_SPATIAL_REUSE 39
|
||||
#define WLAN_EID_EXT_OCV_OCI 54
|
||||
#define WLAN_EID_EXT_SHORT_SSID_LIST 58
|
||||
#define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59
|
||||
#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
|
||||
#define WLAN_EID_EXT_EDMG_OPERATION 62
|
||||
#define WLAN_EID_EXT_MSCS_DESCRIPTOR 88
|
||||
#define WLAN_EID_EXT_TCLAS_MASK 89
|
||||
#define WLAN_EID_EXT_REJECTED_GROUPS 92
|
||||
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
|
||||
|
||||
@ -558,11 +566,15 @@
|
||||
#define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80
|
||||
#define WLAN_EXT_CAPAB_SAE_PW_ID 81
|
||||
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
|
||||
#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
|
||||
#define WLAN_EXT_CAPAB_MSCS 85
|
||||
#define WLAN_EXT_CAPAB_SAE_PK_EXCLUSIVELY 88
|
||||
|
||||
/* Extended RSN Capabilities */
|
||||
/* bits 0-3: Field length (n-1) */
|
||||
#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
|
||||
#define WLAN_RSNX_CAPAB_SAE_H2E 5
|
||||
#define WLAN_RSNX_CAPAB_SAE_PK 6
|
||||
|
||||
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
|
||||
#define WLAN_ACTION_SPECTRUM_MGMT 0
|
||||
@ -1315,6 +1327,10 @@ struct ieee80211_ampe_ie {
|
||||
#define OWE_IE_VENDOR_TYPE 0x506f9a1c
|
||||
#define OWE_OUI_TYPE 28
|
||||
#define MULTI_AP_OUI_TYPE 0x1B
|
||||
#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e
|
||||
#define DPP_CC_OUI_TYPE 0x1e
|
||||
#define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f
|
||||
#define SAE_PK_OUI_TYPE 0x1f
|
||||
|
||||
#define MULTI_AP_SUB_ELEM_TYPE 0x06
|
||||
#define MULTI_AP_TEAR_DOWN BIT(4)
|
||||
@ -1874,7 +1890,15 @@ enum wnm_sleep_mode_response_status {
|
||||
/* WNM-Sleep Mode subelement IDs */
|
||||
enum wnm_sleep_mode_subelement_id {
|
||||
WNM_SLEEP_SUBELEM_GTK = 0,
|
||||
WNM_SLEEP_SUBELEM_IGTK = 1
|
||||
WNM_SLEEP_SUBELEM_IGTK = 1,
|
||||
WNM_SLEEP_SUBELEM_BIGTK = 2,
|
||||
};
|
||||
|
||||
/* WNM notification type (IEEE P802.11-REVmd/D3.0, Table 9-430) */
|
||||
enum wnm_notification_Type {
|
||||
WNM_NOTIF_TYPE_FIRMWARE_UPDATE = 0,
|
||||
WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE = 2,
|
||||
WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221,
|
||||
};
|
||||
|
||||
/* Channel Switch modes (802.11h) */
|
||||
@ -2090,7 +2114,7 @@ enum phy_type {
|
||||
PHY_TYPE_VHT = 9,
|
||||
};
|
||||
|
||||
/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
|
||||
/* IEEE P802.11-REVmd/D3.0, 9.4.2.36 - Neighbor Report element */
|
||||
/* BSSID Information Field */
|
||||
#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
|
||||
#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
|
||||
@ -2107,6 +2131,7 @@ enum phy_type {
|
||||
#define NEI_REP_BSSID_INFO_HT BIT(11)
|
||||
#define NEI_REP_BSSID_INFO_VHT BIT(12)
|
||||
#define NEI_REP_BSSID_INFO_FTM BIT(13)
|
||||
#define NEI_REP_BSSID_INFO_HE BIT(14)
|
||||
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
|
||||
@ -2133,12 +2158,53 @@ struct ieee80211_he_operation {
|
||||
le32 he_oper_params; /* HE Operation Parameters[3] and
|
||||
* BSS Color Information[1] */
|
||||
le16 he_mcs_nss_set;
|
||||
u8 vht_op_info_chwidth;
|
||||
u8 vht_op_info_chan_center_freq_seg0_idx;
|
||||
u8 vht_op_info_chan_center_freq_seg1_idx;
|
||||
/* Followed by conditional MaxBSSID Indicator subfield (u8) */
|
||||
/* Followed by conditional VHT Operation Information (3 octets),
|
||||
* Max Co-Hosted BSSID Indicator subfield (1 octet), and/or 6 GHz
|
||||
* Operation Information subfield (5 octets). */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* IEEE P802.11ax/D6.0, Figure 9-787k - 6 GHz Operation Information field */
|
||||
struct ieee80211_he_6ghz_oper_info {
|
||||
u8 primary_chan;
|
||||
u8 control;
|
||||
u8 chan_center_freq_seg0;
|
||||
u8 chan_center_freq_seg1;
|
||||
u8 min_rate;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define HE_6GHZ_OPER_INFO_CTRL_CHAN_WIDTH_MASK (BIT(0) | BIT(1))
|
||||
#define HE_6GHZ_OPER_INFO_CTRL_DUP_BEACON BIT(2)
|
||||
|
||||
/* IEEE P802.11ax/D6.0, 9.4.2.261 HE 6 GHz Band Capabilities element */
|
||||
struct ieee80211_he_6ghz_band_cap {
|
||||
/* Minimum MPDU Start Spacing B0..B2
|
||||
* Maximum A-MPDU Length Exponent B3..B5
|
||||
* Maximum MPDU Length B6..B7 */
|
||||
le16 capab;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define HE_6GHZ_BAND_CAP_MIN_MPDU_START (BIT(0) | BIT(1) | BIT(2))
|
||||
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_16K BIT(3)
|
||||
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_32K BIT(4)
|
||||
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_64K (BIT(3) | BIT(4))
|
||||
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_128K BIT(5)
|
||||
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_256K (BIT(3) | BIT(5))
|
||||
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_512K (BIT(4) | BIT(5))
|
||||
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_1024K (BIT(3) | BIT(4) | BIT(5))
|
||||
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK (BIT(3) | BIT(4) | BIT(5))
|
||||
#define HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT 3
|
||||
#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_7991 BIT(6)
|
||||
#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_11454 BIT(7)
|
||||
#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK (BIT(6) | BIT(7))
|
||||
#define HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT 6
|
||||
#define HE_6GHZ_BAND_CAP_SMPS_MASK (BIT(9) | BIT(10))
|
||||
#define HE_6GHZ_BAND_CAP_SMPS_STATIC 0
|
||||
#define HE_6GHZ_BAND_CAP_SMPS_DYNAMIC BIT(9)
|
||||
#define HE_6GHZ_BAND_CAP_SMPS_DISABLED (BIT(9) | BIT(10))
|
||||
#define HE_6GHZ_BAND_CAP_RD_RESPONDER BIT(11)
|
||||
#define HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS BIT(12)
|
||||
#define HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS BIT(13)
|
||||
|
||||
/*
|
||||
* IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
|
||||
*/
|
||||
@ -2156,6 +2222,8 @@ struct ieee80211_spatial_reuse {
|
||||
|
||||
/* HE Capabilities Information defines */
|
||||
|
||||
#define HE_MACCAP_TWT_RESPONDER ((u8) BIT(2))
|
||||
|
||||
#define HE_PHYCAP_CHANNEL_WIDTH_SET_IDX 0
|
||||
#define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \
|
||||
BIT(3) | BIT(4)))
|
||||
@ -2198,7 +2266,7 @@ struct ieee80211_spatial_reuse {
|
||||
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
|
||||
BIT(26) | BIT(27) | \
|
||||
BIT(28) | BIT(29)))
|
||||
#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(30))
|
||||
#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30))
|
||||
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
|
||||
#define HE_OPERATION_BSS_COLOR_OFFSET 24
|
||||
|
||||
@ -2278,4 +2346,25 @@ enum edmg_bw_config {
|
||||
/* DPP Public Action frame identifiers - OUI_WFA */
|
||||
#define DPP_OUI_TYPE 0x1A
|
||||
|
||||
/* Robust AV streaming Action field values */
|
||||
enum robust_av_streaming_action {
|
||||
ROBUST_AV_SCS_REQ = 0,
|
||||
ROBUST_AV_SCS_RESP = 1,
|
||||
ROBUST_AV_GROUP_MEMBERSHIP_REQ = 2,
|
||||
ROBUST_AV_GROUP_MEMBERSHIP_RESP = 3,
|
||||
ROBUST_AV_MSCS_REQ = 4,
|
||||
ROBUST_AV_MSCS_RESP = 5,
|
||||
};
|
||||
|
||||
enum scs_request_type {
|
||||
SCS_REQ_ADD = 0,
|
||||
SCS_REQ_REMOVE = 1,
|
||||
SCS_REQ_CHANGE = 2,
|
||||
};
|
||||
|
||||
/* Optional subelement IDs for MSCS Descriptor element */
|
||||
enum mscs_description_subelem {
|
||||
MCSC_SUBELEM_STATUS = 1,
|
||||
};
|
||||
|
||||
#endif /* IEEE802_11_DEFS_H */
|
||||
|
@ -45,6 +45,8 @@ int ocv_derive_all_parameters(struct oci_info *oci)
|
||||
oci->sec_channel = 1;
|
||||
else if (op_class_map->bw == BW40MINUS)
|
||||
oci->sec_channel = -1;
|
||||
else if (op_class_map->bw == BW40)
|
||||
oci->sec_channel = (((oci->channel - 1) / 4) % 2) ? -1 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -95,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,
|
||||
struct wpa_channel_info *ci, int tx_chanwidth,
|
||||
int tx_seg1_idx)
|
||||
enum oci_verify_result
|
||||
ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
|
||||
struct wpa_channel_info *ci, int tx_chanwidth,
|
||||
int tx_seg1_idx)
|
||||
{
|
||||
struct oci_info oci;
|
||||
|
||||
if (!oci_ie) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: did not receive mandatory OCI");
|
||||
return -1;
|
||||
"did not receive mandatory OCI");
|
||||
return OCI_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (oci_ie_len != 3) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: received OCI of unexpected length (%d)",
|
||||
"received OCI of unexpected length (%d)",
|
||||
(int) oci_ie_len);
|
||||
return -1;
|
||||
return OCI_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
os_memset(&oci, 0, sizeof(oci));
|
||||
@ -120,25 +123,25 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
|
||||
oci.seg1_idx = oci_ie[2];
|
||||
if (ocv_derive_all_parameters(&oci) != 0) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: unable to interpret received OCI");
|
||||
return -1;
|
||||
"unable to interpret received OCI");
|
||||
return OCI_PARSE_ERROR;
|
||||
}
|
||||
|
||||
/* Primary frequency used to send frames to STA must match the STA's */
|
||||
if ((int) ci->frequency != oci.freq) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: primary channel mismatch in received OCI (we use %d but receiver is using %d)",
|
||||
"primary channel mismatch in received OCI (we use %d but receiver is using %d)",
|
||||
ci->frequency, oci.freq);
|
||||
return -1;
|
||||
return OCI_PRIMARY_FREQ_MISMATCH;
|
||||
}
|
||||
|
||||
/* We shouldn't transmit with a higher bandwidth than the STA supports
|
||||
*/
|
||||
if (tx_chanwidth > oci.chanwidth) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
|
||||
"channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
|
||||
tx_chanwidth, oci.chanwidth);
|
||||
return -1;
|
||||
return OCI_CHANNEL_WIDTH_MISMATCH;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -150,9 +153,9 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
|
||||
if (tx_chanwidth == 40 && ci->frequency < 2500 &&
|
||||
ci->sec_channel != oci.sec_channel) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
|
||||
"secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
|
||||
ci->sec_channel, oci.sec_channel);
|
||||
return -1;
|
||||
return OCI_SECONDARY_FREQ_MISMATCH;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -163,10 +166,10 @@ int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
|
||||
ci->chanwidth == CHAN_WIDTH_80P80) &&
|
||||
tx_seg1_idx != oci.seg1_idx) {
|
||||
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
|
||||
"OCV failed: frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
|
||||
"frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
|
||||
tx_seg1_idx, oci.seg1_idx);
|
||||
return -1;
|
||||
return OCI_SEG_1_INDEX_MISMATCH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return OCI_SUCCESS;
|
||||
}
|
||||
|
@ -27,14 +27,21 @@ struct oci_info {
|
||||
#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
|
||||
#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + OCV_OCI_LEN)
|
||||
|
||||
enum oci_verify_result {
|
||||
OCI_SUCCESS, OCI_NOT_FOUND, OCI_INVALID_LENGTH, OCI_PARSE_ERROR,
|
||||
OCI_PRIMARY_FREQ_MISMATCH, OCI_CHANNEL_WIDTH_MISMATCH,
|
||||
OCI_SECONDARY_FREQ_MISMATCH, OCI_SEG_1_INDEX_MISMATCH
|
||||
};
|
||||
|
||||
extern char ocv_errorstr[256];
|
||||
|
||||
int ocv_derive_all_parameters(struct oci_info *oci);
|
||||
int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos);
|
||||
int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
|
||||
int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos);
|
||||
int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
|
||||
struct wpa_channel_info *ci, int tx_chanwidth,
|
||||
int tx_seg1_idx);
|
||||
enum oci_verify_result
|
||||
ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
|
||||
struct wpa_channel_info *ci, int tx_chanwidth,
|
||||
int tx_seg1_idx);
|
||||
|
||||
#endif /* OCV_H */
|
||||
|
@ -82,6 +82,7 @@ struct privsep_cmd_set_key {
|
||||
size_t seq_len;
|
||||
u8 key[32];
|
||||
size_t key_len;
|
||||
enum key_flag key_flag;
|
||||
};
|
||||
|
||||
enum privsep_event {
|
||||
|
File diff suppressed because it is too large
Load Diff
133
src/common/sae.c
133
src/common/sae.c
@ -169,7 +169,7 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
* being smaller than prime. */
|
||||
in_range = const_time_fill_msb((unsigned int) cmp_prime);
|
||||
/* The algorithm description would skip the next steps if
|
||||
* cmp_prime >= 0 (reutnr 0 here), but go through them regardless to
|
||||
* cmp_prime >= 0 (return 0 here), but go through them regardless to
|
||||
* minimize externally observable differences in behavior. */
|
||||
|
||||
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
|
||||
@ -713,6 +713,8 @@ static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
|
||||
goto fail;
|
||||
const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
|
||||
x1 = crypto_bignum_init_set(bin, prime_len);
|
||||
if (!x1)
|
||||
goto fail;
|
||||
debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
|
||||
|
||||
/* gx1 = x1^3 + a * x1 + b */
|
||||
@ -753,6 +755,8 @@ static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
|
||||
goto fail;
|
||||
const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
|
||||
v = crypto_bignum_init_set(bin, prime_len);
|
||||
if (!v)
|
||||
goto fail;
|
||||
debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
|
||||
|
||||
/* x = CSEL(l, x1, x2) */
|
||||
@ -1052,10 +1056,17 @@ sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len,
|
||||
|
||||
wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
|
||||
|
||||
if (ssid_len > 32)
|
||||
return NULL;
|
||||
|
||||
pt = os_zalloc(sizeof(*pt));
|
||||
if (!pt)
|
||||
return NULL;
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
os_memcpy(pt->ssid, ssid, ssid_len);
|
||||
pt->ssid_len = ssid_len;
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
pt->group = group;
|
||||
pt->ec = crypto_ec_init(group);
|
||||
if (pt->ec) {
|
||||
@ -1354,14 +1365,15 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
|
||||
identifier) < 0))
|
||||
return -1;
|
||||
|
||||
sae->tmp->h2e = 0;
|
||||
sae->h2e = 0;
|
||||
sae->pk = 0;
|
||||
return sae_derive_commit(sae);
|
||||
}
|
||||
|
||||
|
||||
int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
|
||||
const u8 *addr1, const u8 *addr2,
|
||||
int *rejected_groups)
|
||||
int *rejected_groups, const struct sae_pk *pk)
|
||||
{
|
||||
if (!sae->tmp)
|
||||
return -1;
|
||||
@ -1377,6 +1389,11 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
os_memcpy(sae->tmp->ssid, pt->ssid, pt->ssid_len);
|
||||
sae->tmp->ssid_len = pt->ssid_len;
|
||||
sae->tmp->ap_pk = pk;
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
|
||||
wpabuf_free(sae->tmp->own_rejected_groups);
|
||||
sae->tmp->own_rejected_groups = NULL;
|
||||
@ -1409,7 +1426,7 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
|
||||
return -1;
|
||||
}
|
||||
|
||||
sae->tmp->h2e = 1;
|
||||
sae->h2e = 1;
|
||||
return sae_derive_commit(sae);
|
||||
}
|
||||
|
||||
@ -1515,7 +1532,7 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
|
||||
const u8 *salt;
|
||||
struct wpabuf *rejected_groups = NULL;
|
||||
u8 keyseed[SAE_MAX_HASH_LEN];
|
||||
u8 keys[SAE_MAX_HASH_LEN + SAE_PMK_LEN];
|
||||
u8 keys[2 * SAE_MAX_HASH_LEN + SAE_PMK_LEN];
|
||||
struct crypto_bignum *tmp;
|
||||
int ret = -1;
|
||||
size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
|
||||
@ -1530,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",
|
||||
* (commit-scalar + peer-commit-scalar) modulo r)
|
||||
* PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
|
||||
*
|
||||
* When SAE-PK is used,
|
||||
* KCK || PMK || KEK = KDF-Hash-Length(keyseed, "SAE-PK keys", context)
|
||||
*/
|
||||
if (!sae->tmp->h2e)
|
||||
if (!sae->h2e)
|
||||
hash_len = SHA256_MAC_LEN;
|
||||
else if (sae->tmp->dh)
|
||||
hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
|
||||
else
|
||||
hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
|
||||
if (sae->tmp->h2e && (sae->tmp->own_rejected_groups ||
|
||||
sae->tmp->peer_rejected_groups)) {
|
||||
if (sae->h2e && (sae->tmp->own_rejected_groups ||
|
||||
sae->tmp->peer_rejected_groups)) {
|
||||
struct wpabuf *own, *peer;
|
||||
|
||||
own = sae->tmp->own_rejected_groups;
|
||||
@ -1589,15 +1609,40 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
|
||||
* octets). */
|
||||
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (sae->pk) {
|
||||
if (sae_kdf_hash(hash_len, keyseed, "SAE-PK keys",
|
||||
val, sae->tmp->order_len,
|
||||
keys, 2 * hash_len + SAE_PMK_LEN) < 0)
|
||||
goto fail;
|
||||
} else {
|
||||
if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
|
||||
val, sae->tmp->order_len,
|
||||
keys, hash_len + SAE_PMK_LEN) < 0)
|
||||
goto fail;
|
||||
}
|
||||
#else /* CONFIG_SAE_PK */
|
||||
if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
|
||||
val, sae->tmp->order_len,
|
||||
keys, hash_len + SAE_PMK_LEN) < 0)
|
||||
goto fail;
|
||||
#endif /* !CONFIG_SAE_PK */
|
||||
|
||||
forced_memzero(keyseed, sizeof(keyseed));
|
||||
os_memcpy(sae->tmp->kck, keys, hash_len);
|
||||
sae->tmp->kck_len = hash_len;
|
||||
os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
|
||||
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (sae->pk) {
|
||||
os_memcpy(sae->tmp->kek, keys + hash_len + SAE_PMK_LEN,
|
||||
hash_len);
|
||||
sae->tmp->kek_len = hash_len;
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: KEK for SAE-PK",
|
||||
sae->tmp->kek, sae->tmp->kek_len);
|
||||
}
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
forced_memzero(keys, sizeof(keys));
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
|
||||
sae->tmp->kck, sae->tmp->kck_len);
|
||||
@ -1623,38 +1668,42 @@ int sae_process_commit(struct sae_data *sae)
|
||||
}
|
||||
|
||||
|
||||
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
|
||||
const struct wpabuf *token, const char *identifier)
|
||||
int sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
|
||||
const struct wpabuf *token, const char *identifier)
|
||||
{
|
||||
u8 *pos;
|
||||
|
||||
if (sae->tmp == NULL)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
|
||||
if (!sae->tmp->h2e && token) {
|
||||
if (!sae->h2e && token) {
|
||||
wpabuf_put_buf(buf, token);
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
|
||||
wpabuf_head(token), wpabuf_len(token));
|
||||
}
|
||||
pos = wpabuf_put(buf, sae->tmp->prime_len);
|
||||
crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
|
||||
sae->tmp->prime_len, sae->tmp->prime_len);
|
||||
if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
|
||||
sae->tmp->prime_len, sae->tmp->prime_len) < 0)
|
||||
return -1;
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
|
||||
pos, sae->tmp->prime_len);
|
||||
if (sae->tmp->ec) {
|
||||
pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
|
||||
crypto_ec_point_to_bin(sae->tmp->ec,
|
||||
sae->tmp->own_commit_element_ecc,
|
||||
pos, pos + sae->tmp->prime_len);
|
||||
if (crypto_ec_point_to_bin(sae->tmp->ec,
|
||||
sae->tmp->own_commit_element_ecc,
|
||||
pos, pos + sae->tmp->prime_len) < 0)
|
||||
return -1;
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
|
||||
pos, sae->tmp->prime_len);
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
|
||||
pos + sae->tmp->prime_len, sae->tmp->prime_len);
|
||||
} else {
|
||||
pos = wpabuf_put(buf, sae->tmp->prime_len);
|
||||
crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
|
||||
sae->tmp->prime_len, sae->tmp->prime_len);
|
||||
if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
|
||||
sae->tmp->prime_len,
|
||||
sae->tmp->prime_len) < 0)
|
||||
return -1;
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
|
||||
pos, sae->tmp->prime_len);
|
||||
}
|
||||
@ -1669,7 +1718,7 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
|
||||
identifier);
|
||||
}
|
||||
|
||||
if (sae->tmp->h2e && sae->tmp->own_rejected_groups) {
|
||||
if (sae->h2e && sae->tmp->own_rejected_groups) {
|
||||
wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
|
||||
sae->tmp->own_rejected_groups);
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
|
||||
@ -1679,7 +1728,7 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
|
||||
wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
|
||||
}
|
||||
|
||||
if (sae->tmp->h2e && token) {
|
||||
if (sae->h2e && token) {
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
|
||||
wpabuf_put_u8(buf, 1 + wpabuf_len(token));
|
||||
wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
|
||||
@ -1688,6 +1737,8 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
|
||||
"SAE: Anti-clogging token (in container)",
|
||||
token);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2183,13 +2234,14 @@ static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
|
||||
}
|
||||
|
||||
|
||||
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
|
||||
int sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
|
||||
{
|
||||
const u8 *sc;
|
||||
size_t hash_len;
|
||||
int res;
|
||||
|
||||
if (sae->tmp == NULL)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
hash_len = sae->tmp->kck_len;
|
||||
|
||||
@ -2200,17 +2252,26 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
|
||||
sae->send_confirm++;
|
||||
|
||||
if (sae->tmp->ec)
|
||||
sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
|
||||
sae->tmp->own_commit_element_ecc,
|
||||
sae->peer_commit_scalar,
|
||||
sae->tmp->peer_commit_element_ecc,
|
||||
wpabuf_put(buf, hash_len));
|
||||
res = sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
|
||||
sae->tmp->own_commit_element_ecc,
|
||||
sae->peer_commit_scalar,
|
||||
sae->tmp->peer_commit_element_ecc,
|
||||
wpabuf_put(buf, hash_len));
|
||||
else
|
||||
sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
|
||||
sae->tmp->own_commit_element_ffc,
|
||||
sae->peer_commit_scalar,
|
||||
sae->tmp->peer_commit_element_ffc,
|
||||
wpabuf_put(buf, hash_len));
|
||||
res = sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
|
||||
sae->tmp->own_commit_element_ffc,
|
||||
sae->peer_commit_scalar,
|
||||
sae->tmp->peer_commit_element_ffc,
|
||||
wpabuf_put(buf, hash_len));
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (sae_write_confirm_pk(sae, buf) < 0)
|
||||
return -1;
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2264,6 +2325,12 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAE_PK
|
||||
if (sae_check_confirm_pk(sae, data + 2 + hash_len,
|
||||
len - 2 - hash_len) < 0)
|
||||
return -1;
|
||||
#endif /* CONFIG_SAE_PK */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user