wpa: Import wpa_supplicant/hostapd commits up to b4f7506ff

Merge vendor commits 40c7ff83e7,
efec822389, and
2f6c3ea960.

Tested by:	philip
MFC after:	2 months
This commit is contained in:
Cy Schubert 2021-09-03 06:07:19 -07:00
commit c1d255d3ff
504 changed files with 91175 additions and 19082 deletions

View file

@ -56,6 +56,9 @@ In general, the best way of generating a suitable formatted patch file
is by committing the changes to a cloned git repository and using git
format-patch. The patch can then be sent, e.g., with git send-email.
A list of pending patches waiting for review is available in
Patchwork: https://patchwork.ozlabs.org/project/hostap/list/
History of license and contributions terms
------------------------------------------
@ -140,7 +143,7 @@ The license terms used for hostap.git files
Modified BSD license (no advertisement clause):
Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
Copyright (c) 2002-2021, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without

File diff suppressed because it is too large Load diff

View file

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

1375
contrib/wpa/hostapd/Makefile Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,214 @@
# Example hostapd build time configuration
#
# This file lists the configuration options that are used when building the
# hostapd binary. All lines starting with # are ignored. Configuration option
# lines must be commented out complete, if they are not to be included, i.e.,
# just setting VARIABLE=n is not disabling that variable.
#
# This file is included in Makefile, so variables like CFLAGS and LIBS can also
# be modified from here. In most cass, these lines should use += in order not
# to override previous values of the variables.
# Driver interface for Host AP driver
#CONFIG_DRIVER_HOSTAP=y
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
# Driver interface for drivers using the nl80211 kernel interface
#CONFIG_DRIVER_NL80211=y
# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
# shipped with your distribution yet. If that is the case, you need to build
# newer libnl version and point the hostapd build to use it.
#LIBNL=/usr/src/libnl
#CFLAGS += -I$(LIBNL)/include
#LIBS += -L$(LIBNL)/lib
CONFIG_LIBNL20=y
# QCA vendor extensions to nl80211
CONFIG_DRIVER_NL80211_QCA=y
# Broadcom vendor extensions to nl80211
#CONFIG_DRIVER_NL80211_BRCM=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
#LIBS += -L/usr/local/lib
#LIBS_p += -L/usr/local/lib
#LIBS_c += -L/usr/local/lib
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
# WPA2/IEEE 802.11i RSN pre-authentication
#CONFIG_RSN_PREAUTH=y
# Support Operating Channel Validation
#CONFIG_OCV=y
# Integrated EAP server
#CONFIG_EAP=y
# EAP-MD5 for the integrated EAP server
#CONFIG_EAP_MD5=y
# EAP-TLS for the integrated EAP server
#CONFIG_EAP_TLS=y
# EAP-MSCHAPv2 for the integrated EAP server
#CONFIG_EAP_MSCHAPV2=y
# EAP-PEAP for the integrated EAP server
#CONFIG_EAP_PEAP=y
# EAP-GTC for the integrated EAP server
#CONFIG_EAP_GTC=y
# EAP-TTLS for the integrated EAP server
#CONFIG_EAP_TTLS=y
# EAP-SIM for the integrated EAP server
#CONFIG_EAP_SIM=y
# EAP-AKA for the integrated EAP server
#CONFIG_EAP_AKA=y
# EAP-AKA' for the integrated EAP server
# This requires CONFIG_EAP_AKA to be enabled, too.
#CONFIG_EAP_AKA_PRIME=y
# EAP-PAX for the integrated EAP server
#CONFIG_EAP_PAX=y
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
# EAP-SAKE for the integrated EAP server
#CONFIG_EAP_SAKE=y
# EAP-GPSK for the integrated EAP server
#CONFIG_EAP_GPSK=y
# Include support for optional SHA256 cipher suite in EAP-GPSK
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
# Note: Default OpenSSL package does not include support for all the
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
# to add the needed functions.
#CONFIG_EAP_FAST=y
# Wi-Fi Protected Setup (WPS)
CONFIG_WPS=y
# Enable UPnP support for external WPS Registrars
#CONFIG_WPS_UPNP=y
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
# Trusted Network Connect (EAP-TNC)
#CONFIG_EAP_TNC=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
# RADIUS authentication server. This provides access to the integrated EAP
# server from external hosts using RADIUS.
#CONFIG_RADIUS_SERVER=y
# Build IPv6 support for RADIUS operations
CONFIG_IPV6=y
# IEEE Std 802.11r-2008 (Fast BSS Transition)
#CONFIG_IEEE80211R=y
# Use the hostapd's IEEE 802.11 authentication (ACL), but without
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=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.
#CONFIG_NO_STDOUT_DEBUG=y
# Add support for writing debug log to Android logcat instead of standard output
CONFIG_ANDROID_LOG=y
# Remove support for RADIUS accounting
#CONFIG_NO_ACCOUNTING=y
# Remove support for RADIUS
CONFIG_NO_RADIUS=y
# Remove support for VLANs
#CONFIG_NO_VLAN=y
# Remove support for dumping internal state through control interface commands
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
#CONFIG_NO_DUMP_STATE=y
# Select wrapper for operatins system and C library specific functions
# unix = UNIX/POSIX like systems (default)
# win32 = Windows systems
# none = Empty template
CONFIG_OS=unix
# Enable tracing code for developer debugging
# This tracks use of memory allocations and other registrations and reports
# incorrect use with a backtrace of call (or allocation) location.
#CONFIG_WPA_TRACE=y
# For BSD, comment out these.
#LIBS += -lexecinfo
#LIBS_p += -lexecinfo
#LIBS_c += -lexecinfo
# Use libbfd to get more details for developer debugging
# This enables use of libbfd to get more detailed symbols for the backtraces
# generated by CONFIG_WPA_TRACE=y.
#CONFIG_WPA_TRACE_BFD=y
# For BSD, comment out these.
#LIBS += -lbfd -liberty -lz
#LIBS_p += -lbfd -liberty -lz
#LIBS_c += -lbfd -liberty -lz
# Should we use poll instead of select? Select is used by default.
#CONFIG_ELOOP_POLL=y
# Should we use epoll instead of select? Select is used by default.
#CONFIG_ELOOP_EPOLL=y
# Enable AP
CONFIG_AP=y
# Enable Fast Session Transfer (FST)
#CONFIG_FST=y
# Multiband Operation support
# These extensions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
# Include internal line edit mode in hostapd_cli.
CONFIG_WPA_CLI_EDIT=y
# Opportunistic Wireless Encryption (OWE)
# Experimental implementation of draft-harkins-owe-07.txt
#CONFIG_OWE=y
# Wpa_supplicant's random pool is not necessary on Android. Randomness is
# already provided by the entropymixer service which ensures sufficient
# entropy is maintained across reboots. Commit b410eb1913 'Initialize
# /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before
# either wpa_supplicant or hostapd are run.
CONFIG_NO_RANDOM_POOL=y
# Wired equivalent privacy (WEP)
# WEP is an obsolete cryptographic data confidentiality algorithm that is not
# considered secure. It should not be used for anything anymore. The
# functionality needed to use WEP is available in the current hostapd
# release under this optional build parameter. This functionality is subject to
# be completely removed in a future release.
CONFIG_WEP=y

View file

@ -14,6 +14,7 @@
#include "utils/common.h"
#include "utils/uuid.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "crypto/sha256.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
@ -340,7 +341,7 @@ static int hostapd_config_read_eap_user(const char *fname,
struct hostapd_radius_attr *attr, *a;
attr = hostapd_parse_radius_attr(buf + 19);
if (attr == NULL) {
wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s",
wpa_printf(MSG_ERROR, "Invalid radius_accept_attr: %s",
buf + 19);
user = NULL; /* already in the BSS list */
goto failed;
@ -711,12 +712,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_SAE
else if (os_strcmp(start, "SAE") == 0)
val |= WPA_KEY_MGMT_SAE;
@ -755,6 +754,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
else if (os_strcmp(start, "OSEN") == 0)
val |= WPA_KEY_MGMT_OSEN;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_PASN
else if (os_strcmp(start, "PASN") == 0)
val |= WPA_KEY_MGMT_PASN;
#endif /* CONFIG_PASN */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@ -795,6 +798,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)
{
@ -845,6 +849,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)
@ -942,104 +947,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)
@ -1153,7 +1060,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)
{
@ -1173,14 +1079,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]"))
@ -1214,7 +1112,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf,
return 0;
}
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
@ -1323,6 +1220,32 @@ static u8 set_he_cap(int val, u8 mask)
return (u8) (mask & (val << find_bit_offset(mask)));
}
static int hostapd_parse_he_srg_bitmap(u8 *bitmap, char *val)
{
int bitpos;
char *pos, *end;
os_memset(bitmap, 0, 8);
pos = val;
while (*pos != '\0') {
end = os_strchr(pos, ' ');
if (end)
*end = '\0';
bitpos = atoi(pos);
if (bitpos < 0 || bitpos > 64)
return -1;
bitmap[bitpos / 8] |= BIT(bitpos % 8);
if (!end)
break;
pos = end + 1;
}
return 0;
}
#endif /* CONFIG_IEEE80211AX */
@ -2300,6 +2223,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)
@ -2322,6 +2274,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;
@ -2329,6 +2293,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;
}
@ -2365,6 +2332,22 @@ fail:
#endif /* CONFIG_DPP2 */
static int get_hex_config(u8 *buf, size_t max_len, int line,
const char *field, const char *val)
{
size_t hlen = os_strlen(val), len = hlen / 2;
u8 tmp[EXT_CAPA_MAX_LEN];
os_memset(tmp, 0, EXT_CAPA_MAX_LEN);
if (hlen & 1 || len > EXT_CAPA_MAX_LEN || hexstr2bin(val, tmp, len)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid %s", line, field);
return -1;
}
os_memcpy(buf, tmp, EXT_CAPA_MAX_LEN);
return 0;
}
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@ -2473,6 +2456,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);
@ -2484,12 +2474,13 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->ieee802_1x = atoi(pos);
} else if (os_strcmp(buf, "eapol_version") == 0) {
int eapol_version = atoi(pos);
#ifdef CONFIG_MACSEC
if (eapol_version < 1 || eapol_version > 3) {
int max_ver = 3;
#else /* CONFIG_MACSEC */
if (eapol_version < 1 || eapol_version > 2) {
int max_ver = 2;
#endif /* CONFIG_MACSEC */
if (eapol_version < 1 || eapol_version > max_ver) {
wpa_printf(MSG_ERROR,
"Line %d: invalid EAPOL version (%d): '%s'.",
line, eapol_version, pos);
@ -2547,6 +2538,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->tls_session_lifetime = atoi(pos);
} else if (os_strcmp(buf, "tls_flags") == 0) {
bss->tls_flags = parse_tls_flags(pos);
} else if (os_strcmp(buf, "max_auth_rounds") == 0) {
bss->max_auth_rounds = atoi(pos);
} else if (os_strcmp(buf, "max_auth_rounds_short") == 0) {
bss->max_auth_rounds_short = atoi(pos);
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
os_free(bss->ocsp_stapling_response);
bss->ocsp_stapling_response = os_strdup(pos);
@ -2611,7 +2606,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);
@ -2620,6 +2615,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->eap_teap_auth = val;
} else if (os_strcmp(buf, "eap_teap_pac_no_inner") == 0) {
bss->eap_teap_pac_no_inner = atoi(pos);
} else if (os_strcmp(buf, "eap_teap_separate_result") == 0) {
bss->eap_teap_separate_result = atoi(pos);
} else if (os_strcmp(buf, "eap_teap_id") == 0) {
bss->eap_teap_id = atoi(pos);
#endif /* EAP_SERVER_TEAP */
#ifdef EAP_SERVER_SIM
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
@ -2668,6 +2667,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);
@ -2695,6 +2695,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) {
@ -2706,8 +2707,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->eapol_key_index_workaround = atoi(pos);
#ifdef CONFIG_IAPP
} else if (os_strcmp(buf, "iapp_interface") == 0) {
bss->ieee802_11f = 1;
os_strlcpy(bss->iapp_iface, pos, sizeof(bss->iapp_iface));
wpa_printf(MSG_INFO, "DEPRECATED: iapp_interface not used");
#endif /* CONFIG_IAPP */
} else if (os_strcmp(buf, "own_ip_addr") == 0) {
if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
@ -2728,6 +2728,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return 1;
}
bss->radius->force_client_addr = 1;
} else if (os_strcmp(buf, "radius_client_dev") == 0) {
os_free(bss->radius->force_client_dev);
bss->radius->force_client_dev = os_strdup(pos);
} else if (os_strcmp(buf, "auth_server_addr") == 0) {
if (hostapd_config_read_radius_addr(
&bss->radius->auth_servers,
@ -2870,6 +2873,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;
@ -2879,6 +2892,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);
@ -3131,6 +3153,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "acs_exclude_dfs") == 0) {
conf->acs_exclude_dfs = atoi(pos);
} else if (os_strcmp(buf, "op_class") == 0) {
conf->op_class = atoi(pos);
} else if (os_strcmp(buf, "channel") == 0) {
if (os_strcmp(pos, "acs_survey") == 0) {
#ifndef CONFIG_ACS
@ -3145,12 +3169,25 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->channel = atoi(pos);
conf->acs = conf->channel == 0;
}
} else if (os_strcmp(buf, "edmg_channel") == 0) {
conf->edmg_channel = atoi(pos);
} else if (os_strcmp(buf, "enable_edmg") == 0) {
conf->enable_edmg = atoi(pos);
} else if (os_strcmp(buf, "chanlist") == 0) {
if (hostapd_parse_chanlist(conf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
line);
return 1;
}
} else if (os_strcmp(buf, "freqlist") == 0) {
if (freq_range_list_parse(&conf->acs_freq_list, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid frequency list",
line);
return 1;
}
conf->acs_freq_list_present = 1;
} else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) {
conf->acs_exclude_6ghz_non_psc = atoi(pos);
} else if (os_strcmp(buf, "beacon_int") == 0) {
int val = atoi(pos);
/* MIB defines range as 1..65535, but very small values
@ -3272,6 +3309,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
conf->rate_type = BEACON_RATE_VHT;
conf->beacon_rate = val;
} else if (os_strncmp(pos, "he:", 3) == 0) {
val = atoi(pos + 3);
if (val < 0 || val > 11) {
wpa_printf(MSG_ERROR,
"Line %d: invalid beacon_rate HE-MCS %d",
line, val);
return 1;
}
conf->rate_type = BEACON_RATE_HE;
conf->beacon_rate = val;
} else {
val = atoi(pos);
if (val < 10 || val > 10000) {
@ -3292,6 +3339,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) {
@ -3310,6 +3358,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);
@ -3341,7 +3390,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;
@ -3372,7 +3421,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
conf->use_driver_iface_addr = atoi(pos);
#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos);
} else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
@ -3389,6 +3437,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) {
@ -3403,14 +3453,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line);
return 1;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
} else if (os_strcmp(buf, "ocv") == 0) {
bss->ocv = atoi(pos);
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) {
@ -3423,7 +3471,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);
@ -3456,11 +3503,16 @@ 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) {
conf->he_op.he_twt_required = atoi(pos);
} else if (os_strcmp(buf, "he_twt_responder") == 0) {
conf->he_op.he_twt_responder = atoi(pos);
} else if (os_strcmp(buf, "he_rts_threshold") == 0) {
conf->he_op.he_rts_threshold = atoi(pos);
} else if (os_strcmp(buf, "he_basic_mcs_nss_set") == 0) {
@ -3550,19 +3602,53 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] =
atoi(pos) & 0xff;
} else if (os_strcmp(buf, "he_spr_sr_control") == 0) {
conf->spr.sr_control = atoi(pos) & 0xff;
conf->spr.sr_control = atoi(pos) & 0x1f;
} else if (os_strcmp(buf, "he_spr_non_srg_obss_pd_max_offset") == 0) {
conf->spr.non_srg_obss_pd_max_offset = atoi(pos);
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_min_offset") == 0) {
conf->spr.srg_obss_pd_min_offset = atoi(pos);
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_max_offset") == 0) {
conf->spr.srg_obss_pd_max_offset = atoi(pos);
} else if (os_strcmp(buf, "he_spr_srg_bss_colors") == 0) {
if (hostapd_parse_he_srg_bitmap(
conf->spr.srg_bss_color_bitmap, pos)) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid srg bss colors list '%s'",
line, pos);
return 1;
}
} else if (os_strcmp(buf, "he_spr_srg_partial_bssid") == 0) {
if (hostapd_parse_he_srg_bitmap(
conf->spr.srg_partial_bssid_bitmap, pos)) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid srg partial bssid list '%s'",
line, pos);
return 1;
}
} else if (os_strcmp(buf, "he_oper_chwidth") == 0) {
conf->he_oper_chwidth = atoi(pos);
} else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) {
conf->he_oper_centr_freq_seg0_idx = atoi(pos);
} else if (os_strcmp(buf, "he_oper_centr_freq_seg1_idx") == 0) {
conf->he_oper_centr_freq_seg1_idx = atoi(pos);
} else if (os_strcmp(buf, "he_6ghz_max_mpdu") == 0) {
conf->he_6ghz_max_mpdu = atoi(pos);
} else if (os_strcmp(buf, "he_6ghz_max_ampdu_len_exp") == 0) {
conf->he_6ghz_max_ampdu_len_exp = atoi(pos);
} else if (os_strcmp(buf, "he_6ghz_rx_ant_pat") == 0) {
conf->he_6ghz_rx_ant_pat = atoi(pos);
} else if (os_strcmp(buf, "he_6ghz_tx_ant_pat") == 0) {
conf->he_6ghz_tx_ant_pat = atoi(pos);
} else if (os_strcmp(buf, "unsol_bcast_probe_resp_interval") == 0) {
int val = atoi(pos);
if (val < 0 || val > 20) {
wpa_printf(MSG_ERROR,
"Line %d: invalid unsol_bcast_probe_resp_interval value",
line);
return 1;
}
bss->unsol_bcast_probe_resp_interval = val;
#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@ -3744,6 +3830,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "server_id") == 0) {
os_free(bss->server_id);
bss->server_id = os_strdup(pos);
} else if (os_strcmp(buf, "wps_application_ext") == 0) {
wpabuf_free(bss->wps_application_ext);
bss->wps_application_ext = wpabuf_parse_bin(pos);
#ifdef CONFIG_WPS_NFC
} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
bss->wps_nfc_dev_pw_id = atoi(pos);
@ -4144,9 +4233,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) {
@ -4162,8 +4295,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "assocresp_elements") == 0) {
if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos))
return 1;
} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
bss->sae_anti_clogging_threshold = atoi(pos);
} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0 ||
os_strcmp(buf, "anti_clogging_threshold") == 0) {
bss->anti_clogging_threshold = atoi(pos);
} else if (os_strcmp(buf, "sae_sync") == 0) {
bss->sae_sync = atoi(pos);
} else if (os_strcmp(buf, "sae_groups") == 0) {
@ -4175,6 +4309,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "sae_require_mfp") == 0) {
bss->sae_require_mfp = atoi(pos);
} else if (os_strcmp(buf, "sae_confirm_immediate") == 0) {
bss->sae_confirm_immediate = atoi(pos);
} else if (os_strcmp(buf, "sae_pwe") == 0) {
bss->sae_pwe = atoi(pos);
} else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
int val = atoi(pos);
if (val < 0 || val > 255) {
@ -4318,12 +4456,24 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->dhcp_server_port = atoi(pos);
} else if (os_strcmp(buf, "dhcp_relay_port") == 0) {
bss->dhcp_relay_port = atoi(pos);
} else if (os_strcmp(buf, "fils_discovery_min_interval") == 0) {
bss->fils_discovery_min_int = atoi(pos);
} else if (os_strcmp(buf, "fils_discovery_max_interval") == 0) {
bss->fils_discovery_max_int = atoi(pos);
#endif /* CONFIG_FILS */
} else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
bss->multicast_to_unicast = atoi(pos);
} else if (os_strcmp(buf, "broadcast_deauth") == 0) {
bss->broadcast_deauth = atoi(pos);
} else if (os_strcmp(buf, "notify_mgmt_frames") == 0) {
bss->notify_mgmt_frames = atoi(pos);
#ifdef CONFIG_DPP
} else if (os_strcmp(buf, "dpp_name") == 0) {
os_free(bss->dpp_name);
bss->dpp_name = os_strdup(pos);
} else if (os_strcmp(buf, "dpp_mud_url") == 0) {
os_free(bss->dpp_mud_url);
bss->dpp_mud_url = os_strdup(pos);
} else if (os_strcmp(buf, "dpp_connector") == 0) {
os_free(bss->dpp_connector);
bss->dpp_connector = os_strdup(pos);
@ -4339,6 +4489,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
@ -4372,9 +4534,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line, pos);
return 1;
}
} else if (os_strcmp(buf, "owe_ptk_workaround") == 0) {
bss->owe_ptk_workaround = atoi(pos);
#endif /* CONFIG_OWE */
} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
bss->coloc_intf_reporting = atoi(pos);
#endif /* CONFIG_OWE */
} else if (os_strcmp(buf, "multi_ap") == 0) {
int val = atoi(pos);
@ -4389,8 +4553,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);
@ -4506,6 +4674,37 @@ 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);
#ifdef CONFIG_PASN
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcmp(buf, "force_kdk_derivation") == 0) {
bss->force_kdk_derivation = atoi(pos);
} else if (os_strcmp(buf, "pasn_corrupt_mic") == 0) {
bss->pasn_corrupt_mic = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strcmp(buf, "pasn_groups") == 0) {
if (hostapd_parse_intlist(&bss->pasn_groups, pos)) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid pasn_groups value '%s'",
line, pos);
return 1;
}
} else if (os_strcmp(buf, "pasn_comeback_after") == 0) {
bss->pasn_comeback_after = atoi(pos);
#endif /* CONFIG_PASN */
} else if (os_strcmp(buf, "ext_capa_mask") == 0) {
if (get_hex_config(bss->ext_capa_mask, EXT_CAPA_MAX_LEN,
line, "ext_capa_mask", pos))
return 1;
} else if (os_strcmp(buf, "ext_capa") == 0) {
if (get_hex_config(bss->ext_capa, EXT_CAPA_MAX_LEN,
line, "ext_capa", pos))
return 1;
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",

File diff suppressed because it is too large Load diff

View file

@ -44,15 +44,9 @@ CONFIG_LIBNL32=y
# Driver interface for no driver (e.g., RADIUS server only)
#CONFIG_DRIVER_NONE=y
# IEEE 802.11F/IAPP
CONFIG_IAPP=y
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
# IEEE 802.11w (management frame protection)
CONFIG_IEEE80211W=y
# Support Operating Channel Validation
#CONFIG_OCV=y
@ -154,9 +148,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
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
#CONFIG_WNM=y
@ -355,12 +346,12 @@ CONFIG_IPV6=y
# * ath10k
#
# For more details refer to:
# http://wireless.kernel.org/en/users/Documentation/acs
# https://wireless.wiki.kernel.org/en/users/documentation/acs
#
#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
@ -389,3 +380,25 @@ CONFIG_IPV6=y
# Override default value for the wpa_disable_eapol_key_retries configuration
# parameter. See that parameter in hostapd.conf for more details.
#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
# 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
# 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
# Pre-Association Security Negotiation (PASN)
# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol
# design is still subject to change. As such, this should not yet be enabled in
# production use.
# This requires CONFIG_IEEE80211W=y to be enabled, too.
#CONFIG_PASN=y

View file

@ -0,0 +1,19 @@
#
# init.rc fragment for hostapd on Android
# Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
#
on post-fs-data
mkdir /data/misc/wifi/hostapd 0770 wifi wifi
service hostapd /vendor/bin/hostapd \
/data/misc/wifi/hostapd.conf
class main
user wifi
writepid /data/misc/wifi/hostapd.pid
group wifi
disabled
oneshot

View file

@ -41,7 +41,6 @@ interface=wlan0
# bit 2 (4) = RADIUS
# bit 3 (8) = WPA
# bit 4 (16) = driver interface
# bit 5 (32) = IAPP
# bit 6 (64) = MLME
#
# Levels (minimum value for logged events):
@ -73,7 +72,7 @@ ctrl_interface=/var/run/hostapd
# run as non-root users. However, since the control interface can be used to
# change the network configuration, this access needs to be protected in many
# cases. By default, hostapd is configured to use gid 0 (root). If you
# want to allow non-root users to use the contron interface, add a new group
# want to allow non-root users to use the control interface, add a new group
# and change this value to match with that group. Add users that should have
# control interface access to this group.
#
@ -147,7 +146,8 @@ ssid=test
# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
# needs to be set to hw_mode=a. When using ACS (see channel parameter), a
# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6 GHz this needs
# to be set to hw_mode=a. When using ACS (see channel parameter), a
# special value "any" can be used to indicate that any support band can be used.
# This special case is currently supported only with drivers with which
# offloaded ACS is used.
@ -164,8 +164,14 @@ hw_mode=g
# which will enable the ACS survey based algorithm.
channel=1
# Global operating class (IEEE 802.11, Annex E, Table E-4)
# This option allows hostapd to specify the operating class of the channel
# configured with the channel parameter. channel and op_class together can
# uniquely identify channels across different bands, including the 6 GHz band.
#op_class=131
# ACS tuning - Automatic Channel Selection
# See: http://wireless.kernel.org/en/users/Documentation/acs
# See: https://wireless.wiki.kernel.org/en/users/documentation/acs
#
# You can customize the ACS survey algorithm with following variables:
#
@ -199,11 +205,26 @@ channel=1
#chanlist=100 104 108 112 116
#chanlist=1 6 11-13
# Frequency list restriction. This option allows hostapd to select one of the
# provided frequencies when a frequency should be automatically selected.
# 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,5955,5975
#freqlist=2437,5985-6105
# Exclude DFS channels from ACS
# This option can be used to exclude all DFS channels from the ACS channel list
# in cases where the driver supports DFS channels.
#acs_exclude_dfs=1
# Include only preferred scan channels from 6 GHz band for ACS
# This option can be used to include only preferred scan channels in the 6 GHz
# band. This can be useful in particular for devices that operate only a 6 GHz
# BSS without a collocated 2.4/5 GHz BSS.
# Default behavior is to include all PSC and non-PSC channels.
#acs_exclude_6ghz_non_psc=1
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@ -258,6 +279,8 @@ fragm_threshold=-1
# beacon_rate=ht:<HT MCS>
# VHT:
# beacon_rate=vht:<VHT MCS>
# HE:
# beacon_rate=he:<HE MCS>
#
# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
#beacon_rate=10
@ -550,6 +573,10 @@ wmm_ac_vo_acm=0
# Default: 1 (enabled)
#broadcast_deauth=1
# Get notifications for received Management frames on control interface
# Default: 0 (disabled)
#notify_mgmt_frames=0
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
@ -559,6 +586,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
@ -577,8 +607,6 @@ wmm_ac_vo_acm=0
# 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)
@ -613,6 +641,9 @@ wmm_ac_vo_acm=0
# 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]
@ -767,6 +798,9 @@ wmm_ac_vo_acm=0
# 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
@ -785,6 +819,9 @@ wmm_ac_vo_acm=0
# 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
@ -794,12 +831,27 @@ wmm_ac_vo_acm=0
# 1 = required
#he_twt_required=0
#he_twt_responder: Whether TWT (HE) responder is enabled
# 0 = disabled
# 1 = enabled if supported by the driver (default)
#he_twt_responder=1
#he_rts_threshold: Duration of STA transmission
# 0 = not set (default)
# unsigned integer = duration in units of 16 us
#he_rts_threshold=0
# HE operating channel information; see matching vht_* parameters for details.
# he_oper_centr_freq_seg0_idx field is used to indicate center frequency of 80
# and 160 MHz bandwidth operation. In 80+80 MHz operation, it is the center
# frequency of the lower frequency segment. he_oper_centr_freq_seg1_idx field
# is used only with 80+80 MHz bandwidth operation and it is used to transmit
# the center frequency of the second segment.
# 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/D6.1 Annex E, Table E-4).
#he_oper_chwidth
#he_oper_centr_freq_seg0_idx
#he_oper_centr_freq_seg1_idx
@ -835,10 +887,82 @@ wmm_ac_vo_acm=0
#he_mu_edca_ac_vo_timer=255
# Spatial Reuse Parameter Set
#
# SR Control field value
# B0 = PSR Disallowed
# B1 = Non-SRG OBSS PD SR Disallowed
# B2 = Non-SRG Offset Present
# B3 = SRG Information Present
# B4 = HESIGA_Spatial_reuse_value15_allowed
#he_spr_sr_control
#
# Non-SRG OBSS PD Max Offset (included if he_spr_sr_control B2=1)
#he_spr_non_srg_obss_pd_max_offset
# SRG OBSS PD Min Offset (included if he_spr_sr_control B3=1)
#he_spr_srg_obss_pd_min_offset
#
# SRG OBSS PD Max Offset (included if he_spr_sr_control B3=1)
#he_spr_srg_obss_pd_max_offset
#
# SPR SRG BSS Color (included if he_spr_sr_control B3=1)
# This config represents SRG BSS Color Bitmap field of Spatial Reuse Parameter
# Set element that indicates the BSS color values used by members of the
# SRG of which the transmitting STA is a member. The value is in range of 0-63.
#he_spr_srg_bss_colors=1 2 10 63
#
# SPR SRG Partial BSSID (included if he_spr_sr_control B3=1)
# This config represents SRG Partial BSSID Bitmap field of Spatial Reuse
# Parameter Set element that indicates the Partial BSSID values used by members
# of the SRG of which the transmitting STA is a member. The value range
# corresponds to one of the 64 possible values of BSSID[39:44], where the lowest
# numbered bit corresponds to Partial BSSID value 0 and the highest numbered bit
# corresponds to Partial BSSID value 63.
#he_spr_srg_partial_bssid=0 1 3 63
#
#he_6ghz_max_mpdu: Maximum MPDU Length of HE 6 GHz band capabilities.
# Indicates maximum MPDU length
# 0 = 3895 octets
# 1 = 7991 octets
# 2 = 11454 octets (default)
#he_6ghz_max_mpdu=2
#
#he_6ghz_max_ampdu_len_exp: Maximum A-MPDU Length Exponent of HE 6 GHz band
# capabilities. Indicates the maximum length of A-MPDU pre-EOF padding that
# the STA can receive. This field is an integer in the range of 0 to 7.
# The length defined by this field is equal to
# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
# 0 = AMPDU length of 8k
# 1 = AMPDU length of 16k
# 2 = AMPDU length of 32k
# 3 = AMPDU length of 65k
# 4 = AMPDU length of 131k
# 5 = AMPDU length of 262k
# 6 = AMPDU length of 524k
# 7 = AMPDU length of 1048k (default)
#he_6ghz_max_ampdu_len_exp=7
#
#he_6ghz_rx_ant_pat: Rx Antenna Pattern Consistency of HE 6 GHz capability.
# Indicates the possibility of Rx antenna pattern change
# 0 = Rx antenna pattern might change during the lifetime of an association
# 1 = Rx antenna pattern does not change during the lifetime of an association
# (default)
#he_6ghz_rx_ant_pat=1
#
#he_6ghz_tx_ant_pat: Tx Antenna Pattern Consistency of HE 6 GHz capability.
# Indicates the possibility of Tx antenna pattern change
# 0 = Tx antenna pattern might change during the lifetime of an association
# 1 = Tx antenna pattern does not change during the lifetime of an association
# (default)
#he_6ghz_tx_ant_pat=1
# Unsolicited broadcast Probe Response transmission settings
# This is for the 6 GHz band only. If the interval is set to a non-zero value,
# the AP schedules unsolicited broadcast Probe Response frames to be
# transmitted for in-band discovery. Refer to
# IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning.
# Valid range: 0..20 TUs; default is 0 (disabled)
#unsol_bcast_probe_resp_interval=0
##### IEEE 802.1X-2004 related configuration ##################################
@ -877,6 +1001,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
@ -1012,7 +1138,7 @@ eap_server=0
#check_crl=1
# Specify whether to ignore certificate CRL validity time mismatches with
# errors X509_V_ERR_CERT_HAS_EXPIRED and X509_V_ERR_CERT_NOT_YET_VALID.
# errors X509_V_ERR_CRL_HAS_EXPIRED and X509_V_ERR_CRL_NOT_YET_VALID.
#
# 0 = ignore errors
# 1 = do not ignore errors (default)
@ -1081,6 +1207,12 @@ eap_server=0
# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
#tls_flags=[flag1][flag2]...
# Maximum number of EAP message rounds with data (default: 100)
#max_auth_rounds=100
# Maximum number of short EAP message rounds (default: 50)
#max_auth_rounds_short=50
# Cached OCSP stapling response (DER encoded)
# If set, this file is sent as a certificate status response by the EAP server
# if the EAP peer requests certificate status in the ClientHello message.
@ -1167,7 +1299,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
@ -1194,6 +1326,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
@ -1201,6 +1335,20 @@ eap_server=0
# 1 = skip inner authentication (inner EAP/Basic-Password-Auth)
#eap_teap_pac_no_inner=0
# EAP-TEAP behavior with Result TLV
# 0 = include with Intermediate-Result TLV (default)
# 1 = send in a separate message (for testing purposes)
#eap_teap_separate_result=0
# EAP-TEAP identities
# 0 = allow any identity type (default)
# 1 = require user identity
# 2 = require machine identity
# 3 = request user identity; accept either user or machine identity
# 4 = request machine identity; accept either user or machine identity
# 5 = require both user and machine identity
#eap_teap_id=0
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
# (default: 0 = disabled).
#eap_sim_aka_result_ind=1
@ -1223,11 +1371,6 @@ eap_server=0
# Whether to enable ERP on the EAP server.
#eap_server_erp=1
##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
# Interface to be used for IAPP broadcast packets
#iapp_interface=eth0
##### RADIUS client configuration #############################################
# for IEEE 802.1X with external Authentication Server, IEEE 802.11
@ -1261,6 +1404,12 @@ own_ip_addr=127.0.0.1
# used, e.g., when the device has multiple IP addresses.
#radius_client_addr=127.0.0.1
# RADIUS client forced local interface. Helps run properly with VRF
# Default is none set which allows the network stack to pick the appropriate
# interface automatically.
# Example below binds to eth0
#radius_client_dev=eth0
# RADIUS authentication server
#auth_server_addr=127.0.0.1
#auth_server_port=1812
@ -1466,6 +1615,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
@ -1566,8 +1726,26 @@ own_ip_addr=127.0.0.1
# 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)
@ -1618,6 +1796,12 @@ own_ip_addr=127.0.0.1
# 1 = optional
# 2 = required
#ieee80211w=0
# The most common configuration options for this based on the PMF (protected
# management frames) certification program are:
# PMF enabled: ieee80211w=1 and wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256
# PMF required: ieee80211w=2 and wpa_key_mgmt=WPA-EAP-SHA256
# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
# WPA3-Personal-only mode: ieee80211w=2 and wpa_key_mgmt=SAE
# Group management cipher suite
# Default: AES-128-CMAC (BIP)
@ -1630,6 +1814,13 @@ own_ip_addr=127.0.0.1
# 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)
# and beacon protection support indication from the driver.
# 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
@ -1642,9 +1833,25 @@ own_ip_addr=127.0.0.1
# ocv: Operating Channel Validation
# This is a countermeasure against multi-channel man-in-the-middle attacks.
# Enabling this depends on the driver's support for OCV when the driver SME is
# used. If hostapd SME is used, this will be enabled just based on this
# configuration.
# 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
@ -1676,7 +1883,7 @@ own_ip_addr=127.0.0.1
# 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
@ -1691,7 +1898,8 @@ own_ip_addr=127.0.0.1
# 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
@ -1701,10 +1909,11 @@ own_ip_addr=127.0.0.1
# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
# This parameter defines how many open SAE instances can be in progress at the
# same time before the anti-clogging mechanism is taken into use.
#sae_anti_clogging_threshold=5
#sae_anti_clogging_threshold=5 (deprecated)
#anti_clogging_threshold=5
# Maximum number of SAE synchronization errors (dot11RSNASAESync)
# The offending SAe peer will be disconnected if more than this many
# The offending SAE peer will be disconnected if more than this many
# synchronization errors happen.
#sae_sync=5
@ -1729,6 +1938,23 @@ own_ip_addr=127.0.0.1
# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
#sae_require_mfp=0
# SAE Confirm behavior
# By default, AP will send out only SAE Commit message in response to a received
# SAE Commit message. This parameter can be set to 1 to override that behavior
# to send both SAE Commit and SAE Confirm messages without waiting for the STA
# to send its SAE Confirm message first.
#sae_confirm_immediate=0
# SAE mechanism for PWE derivation
# 0 = hunting-and-pecking loop only (default without password identifier)
# 1 = hash-to-element only (default with password identifier)
# 2 = both hunting-and-pecking loop and hash-to-element enabled
# Note: The default value is likely to change from 0 to 2 once the new
# hash-to-element mechanism has received more interoperability testing.
# When using SAE password identifier, the hash-to-element mechanism is used
# regardless of the sae_pwe parameter value.
#sae_pwe=0
# FILS Cache Identifier (16-bit value in hexdump format)
#fils_cache_id=0011
@ -1753,6 +1979,19 @@ own_ip_addr=127.0.0.1
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
#owe_groups=19 20 21
# OWE PTK derivation workaround
# Initial OWE implementation used SHA256 when deriving the PTK for all OWE
# groups. This was supposed to change to SHA384 for group 20 and SHA512 for
# group 21. This parameter can be used to enable workaround for interoperability
# with stations that use SHA256 with groups 20 and 21. By default (0) only the
# appropriate hash function is accepted. When workaround is enabled (1), the
# appropriate hash function is tried first and if that fails, SHA256-based PTK
# derivation is attempted. This workaround can result in reduced security for
# groups 20 and 21, but is required for interoperability with older
# implementations. There is no impact to group 19 behavior. The workaround is
# disabled by default and can be enabled by uncommenting the following line.
#owe_ptk_workaround=1
# OWE transition mode configuration
# Pointer to the matching open/OWE BSS
#owe_transition_bssid=<bssid>
@ -1790,6 +2029,45 @@ own_ip_addr=127.0.0.1
# default: 30 TUs (= 30.72 milliseconds)
#fils_hlp_wait_time=30
# FILS Discovery frame transmission minimum and maximum interval settings.
# If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery
# frame transmission. These values use TUs as the unit and have allowed range
# of 0-10000. fils_discovery_min_interval defaults to 20.
#fils_discovery_min_interval=20
#fils_discovery_max_interval=0
# 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
# PASN ECDH groups
# PASN implementations are required to support group 19 (NIST P-256). If this
# parameter is not set, only group 19 is supported by default. This
# configuration parameter can be used to specify a limited set of allowed
# groups. The group values are listed in the IANA registry:
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
#pasn_groups=19 20 21
# PASN comeback after time in TUs
# In case the AP is temporarily unable to handle a PASN authentication exchange
# due to a too large number of parallel operations, this value indicates to the
# peer after how many TUs it can try the PASN exchange again.
# (default: 10 TUs)
#pasn_comeback_after=10
##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@ -1833,7 +2111,7 @@ own_ip_addr=127.0.0.1
# 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
@ -1889,7 +2167,7 @@ own_ip_addr=127.0.0.1
#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
@ -2143,6 +2421,13 @@ own_ip_addr=127.0.0.1
#wps_nfc_dh_privkey: Hexdump of DH Private Key
#wps_nfc_dev_pw: Hexdump of Device Password
# Application Extension attribute for Beacon and Probe Response frames
# This parameter can be used to add application extension into WPS IE. The
# contents of this parameter starts with 16-octet (32 hexdump characters) of
# UUID to identify the specific application and that is followed by the actual
# application specific data.
#wps_application_ext=<hexdump>
##### Wi-Fi Direct (P2P) ######################################################
# Enable P2P Device management
@ -2151,6 +2436,31 @@ own_ip_addr=127.0.0.1
# Allow cross connection
#allow_cross_connection=1
##### Device Provisioning Protocol (DPP) ######################################
# Name for Enrollee's DPP Configuration Request
#dpp_name=Test
# MUD URL for Enrollee's DPP Configuration Request (optional)
#dpp_mud_url=https://example.com/mud
#dpp_connector
#dpp_netaccesskey
#dpp_netaccesskey_expiry
#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
@ -2531,7 +2841,7 @@ own_ip_addr=127.0.0.1
# Default is 0 = OCE disabled
#oce=0
# RSSI-based assocition rejection
# RSSI-based association rejection
#
# Reject STA association if RSSI is below given threshold (in dBm)
# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
@ -2546,6 +2856,10 @@ own_ip_addr=127.0.0.1
# 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
@ -2638,6 +2952,19 @@ own_ip_addr=127.0.0.1
# airtime.
#airtime_bss_limit=1
##### EDMG support ############################################################
#
# Enable EDMG capability for AP mode in the 60 GHz band. Default value is false.
# To configure channel bonding for an EDMG AP use edmg_channel below.
# If enable_edmg is set and edmg_channel is not set, EDMG CB1 will be
# configured.
#enable_edmg=1
#
# Configure channel bonding for AP mode in the 60 GHz band.
# This parameter is relevant only if enable_edmg is set.
# Default value is 0 (no channel bonding).
#edmg_channel=9
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration

View file

@ -7,9 +7,15 @@
# keyid=<keyid_string>
# An optional VLAN ID can be specified by prefixing the line with
# vlanid=<VLAN ID>.
# An optional WPS tag can be added by prefixing the line with
# wps=<0/1> (default: 0). Any matching entry with that tag will be used when
# generating a PSK for a WPS Enrollee instead of generating a new random
# per-Enrollee PSK.
00:00:00:00:00:00 secret passphrase
00:11:22:33:44:55 another passphrase
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
keyid=example_id 00:11:22:33:44:77 passphrase with keyid
vlanid=3 00:00:00:00:00:00 passphrase with vlanid
wps=1 00:00:00:00:00:00 passphrase for WPS
wps=1 11:22:33:44:55:00 dev-specific passphrase for WPS
00:00:00:00:00:00 another passphrase for all STAs

View file

@ -54,7 +54,7 @@ static void usage(void)
fprintf(stderr, "%s\n", hostapd_cli_version);
fprintf(stderr,
"\n"
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvBr] "
"[-a<path>] \\\n"
" [-P<pid file>] [-G<ping interval>] [command..]\n"
"\n"
@ -68,6 +68,9 @@ static void usage(void)
" -a<file> run in daemon mode executing the action file "
"based on events\n"
" from hostapd\n"
" -r try to reconnect when client socket is "
"disconnected.\n"
" This is useful only when used with -a.\n"
" -B run a daemon in the background\n"
" -i<ifname> Interface to listen on (default: first "
"interface found in the\n"
@ -401,7 +404,6 @@ static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
#endif /* CONFIG_TAXONOMY */
#ifdef CONFIG_IEEE80211W
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@ -414,7 +416,6 @@ static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
return wpa_ctrl_command(ctrl, buf);
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
@ -974,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;
}
@ -1226,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;
@ -1311,24 +1313,17 @@ static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
}
static int hostapd_cli_cmd_show_neighbor(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "SHOW_NEIGHBOR");
}
static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[400];
int res;
if (argc != 2) {
printf("Invalid remove_neighbor command: needs 2 arguments\n");
return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
argv[0], argv[1]);
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long REMOVE_NEIGHBOR command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
return hostapd_cli_cmd(ctrl, "REMOVE_NEIGHBOR", 1, argc, argv);
}
@ -1408,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[])
{
@ -1470,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 */
@ -1508,6 +1541,14 @@ static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
}
#ifdef ANDROID
static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return hostapd_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
}
#endif /* ANDROID */
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@ -1542,10 +1583,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
"<addr> = get taxonomy signature for a station" },
#endif /* CONFIG_TAXONOMY */
#ifdef CONFIG_IEEE80211W
{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
"<addr> = send SA Query to a station" },
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
"<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
@ -1637,8 +1676,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
"<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
" = add AP to neighbor database" },
{ "show_neighbor", hostapd_cli_cmd_show_neighbor, NULL,
" = show neighbor database entries" },
{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
"<addr> <ssid=> = remove AP from neighbor database" },
"<addr> [ssid=<hex>] = remove AP from neighbor database" },
{ "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
"<addr> = send LCI request to a station"},
{ "req_range", hostapd_cli_cmd_req_range, NULL,
@ -1656,6 +1697,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,
@ -1676,6 +1719,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" },
@ -1687,6 +1740,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" },
{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
"= reload wpa_psk_file only" },
#ifdef ANDROID
{ "driver", hostapd_cli_cmd_driver, NULL,
"<driver sub command> [<hex formatted data>] = send driver command data" },
#endif /* ANDROID */
{ NULL, NULL, NULL, NULL }
};
@ -2011,12 +2068,13 @@ int main(int argc, char *argv[])
int warning_displayed = 0;
int c;
int daemonize = 0;
int reconnect = 0;
if (os_program_init())
return -1;
for (;;) {
c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
c = getopt(argc, argv, "a:BhG:i:p:P:rs:v");
if (c < 0)
break;
switch (c) {
@ -2045,6 +2103,9 @@ int main(int argc, char *argv[])
case 'P':
pid_file = optarg;
break;
case 'r':
reconnect = 1;
break;
case 's':
client_socket_dir = optarg;
break;
@ -2087,8 +2148,7 @@ int main(int argc, char *argv[])
printf("Connection established.\n");
break;
}
if (!interactive) {
if (!interactive && !reconnect) {
perror("Failed to connect to hostapd - "
"wpa_ctrl_open");
return -1;
@ -2106,8 +2166,14 @@ int main(int argc, char *argv[])
return -1;
if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
return -1;
if (interactive)
if (reconnect && action_file && ctrl_ifname) {
while (!hostapd_cli_quit) {
if (ctrl_conn)
hostapd_cli_action(ctrl_conn);
os_sleep(1, 0);
hostapd_cli_reconnect(ctrl_ifname);
}
} else if (interactive)
hostapd_cli_interactive();
else if (action_file)
hostapd_cli_action(ctrl_conn);

View file

@ -81,9 +81,6 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
case HOSTAPD_MODULE_DRIVER:
module_str = "DRIVER";
break;
case HOSTAPD_MODULE_IAPP:
module_str = "IAPP";
break;
case HOSTAPD_MODULE_MLME:
module_str = "MLME";
break;
@ -221,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
@ -263,7 +260,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
struct hostapd_iface *iface;
int k;
wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname);
iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
@ -454,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);
}
@ -676,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;
@ -771,7 +772,7 @@ int main(int argc, char *argv[])
if (log_file)
wpa_debug_open_file(log_file);
else
if (!log_file && !wpa_debug_syslog)
wpa_debug_setup_stdout();
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog)
@ -905,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);

View file

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

View file

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

View file

@ -158,7 +158,7 @@ int est_load_cacerts(struct hs20_osu_client *ctx, const char *url)
return -1;
}
pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
if (pkcs7 && pkcs7_len < resp_len / 2) {
wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary",
(unsigned int) pkcs7_len, (unsigned int) resp_len);
@ -639,8 +639,7 @@ int est_build_csr(struct hs20_osu_client *ctx, const char *url)
return -1;
}
attrs = base64_decode((unsigned char *) resp, resp_len,
&attrs_len);
attrs = base64_decode(resp, resp_len, &attrs_len);
os_free(resp);
if (attrs == NULL) {
@ -734,7 +733,7 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
}
wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
if (pkcs7 == NULL) {
wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
pkcs7 = os_malloc(resp_len);

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,42 @@
ALL=hs20_spp_server
include ../../src/build.rules
CFLAGS += -I../../src
CFLAGS += -I../../src/utils
CFLAGS += -I../../src/crypto
LIBS += -lsqlite3
# Using glibc < 2.17 requires -lrt for clock_gettime()
LIBS += -lrt
ifndef CONFIG_NO_GITVER
# Add VERSION_STR postfix for builds from a git repository
ifeq ($(wildcard ../../.git),../../.git)
GITVER := $(shell git describe --dirty=+)
ifneq ($(GITVER),)
CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
endif
endif
endif
OBJS=spp_server.o
OBJS += hs20_spp_server.o
OBJS += ../../src/utils/xml-utils.o
OBJS += ../../src/utils/base64.o
OBJS += ../../src/utils/common.o
OBJS += ../../src/utils/os_unix.o
OBJS += ../../src/utils/wpa_debug.o
OBJS += ../../src/crypto/md5-internal.o
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: common-clean
rm -f core *~

View file

@ -0,0 +1,13 @@
#!/bin/sh
for i in server-client server server-revoked user ocsp; do
rm -f $i.csr $i.key $i.pem
done
rm -f openssl.cnf.tmp
if [ -d demoCA ]; then
rm -r demoCA
fi
rm -f ca.pem logo.asn1 logo.der server.der ocsp-server-cache.der
rm -f my-openssl.cnf my-openssl-root.cnf
#rm -r rootCA

View file

@ -0,0 +1,17 @@
asn1 = SEQUENCE:attrs
[attrs]
#oid1 = OID:challengePassword
attr1 = SEQUENCE:extreq
oid2 = OID:sha256WithRSAEncryption
[extreq]
oid = OID:extensionRequest
vals = SET:extreqvals
[extreqvals]
oid1 = OID:macAddress
#oid2 = OID:imei
#oid3 = OID:meid
#oid4 = OID:DevId

View file

@ -0,0 +1,4 @@
#!/bin/sh
openssl asn1parse -genconf est-csrattrs.cnf -out est-csrattrs.der -oid hs20.oid
base64 est-csrattrs.der > est-attrs.b64

View file

@ -0,0 +1,7 @@
1.3.6.1.1.1.1.22 macAddress
1.2.840.113549.1.9.14 extensionRequest
1.3.6.1.4.1.40808.1.1.1 id-wfa-hotspot-friendlyName
1.3.6.1.4.1.40808.1.1.2 id-kp-HS2.0Auth
1.3.6.1.4.1.40808.1.1.3 imei
1.3.6.1.4.1.40808.1.1.4 meid
1.3.6.1.4.1.40808.1.1.5 DevId

View file

@ -0,0 +1,11 @@
#!/bin/sh
for i in *.pem; do
echo "===[ $i ]==================="
openssl ocsp -text -CAfile ca.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
# openssl ocsp -text -CAfile rootCA/cacert.pem -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
# openssl ocsp -text -CAfile rootCA/cacert.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
# openssl ocsp -text -CAfile rootCA/cacert.pem -VAfile ca.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
done

View file

@ -0,0 +1,3 @@
#!/bin/sh
openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner demoCA/cacert.pem -rkey demoCA/private/cakey-plain.pem -CA demoCA/cacert.pem -resp_no_certs -text

View file

@ -0,0 +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 -ignore_err

View file

@ -0,0 +1,11 @@
#!/bin/sh
# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
openssl ocsp \
-no_nonce \
-CAfile ca.pem \
-verify_other demoCA/cacert.pem \
-issuer demoCA/cacert.pem \
-cert server.pem \
-url http://localhost:8888/ \
-respout ocsp-server-cache.der

View file

@ -0,0 +1,125 @@
# OpenSSL configuration file for Hotspot 2.0 PKI (Root CA)
HOME = .
RANDFILE = $ENV::HOME/.rnd
oid_section = new_oids
[ new_oids ]
#logotypeoid=1.3.6.1.5.5.7.1.12
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
dir = ./rootCA # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several certificates with same subject
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
RANDFILE = $dir/private/.rand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = default # use public key default MD
preserve = no # keep passed DN ordering
policy = policy_match
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
[ req ]
default_bits = 2048
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
input_password = @PASSWORD@
output_password = @PASSWORD@
string_mask = utf8only
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = US
countryName_min = 2
countryName_max = 2
localityName = Locality Name (eg, city)
localityName_default = Tuusula
0.organizationName = Organization Name (eg, company)
0.organizationName_default = WFA Hotspot 2.0
##organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
#@OU@
commonName = Common Name (e.g. server FQDN or YOUR name)
#@CN@
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ req_attributes ]
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName=DNS:example.com,DNS:another.example.com
[ v3_ca ]
# Hotspot 2.0 PKI requirements
subjectKeyIdentifier=hash
basicConstraints = critical,CA:true
keyUsage = critical, cRLSign, keyCertSign
[ crl_ext ]
# issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always
[ v3_OCSP ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = OCSPSigning

View file

@ -0,0 +1,200 @@
# OpenSSL configuration file for Hotspot 2.0 PKI (Intermediate CA)
HOME = .
RANDFILE = $ENV::HOME/.rnd
oid_section = new_oids
[ new_oids ]
#logotypeoid=1.3.6.1.5.5.7.1.12
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
dir = ./demoCA # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several certificates with same subject
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
RANDFILE = $dir/private/.rand # private random number file
x509_extensions = ext_client # The extentions to add to the cert
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
# Extension copying option: use with caution.
copy_extensions = copy
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = default # use public key default MD
preserve = no # keep passed DN ordering
policy = policy_match
# For the CA policy
[ policy_match ]
countryName = supplied
stateOrProvinceName = optional
organizationName = supplied
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_osu_server ]
countryName = match
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = supplied
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
[ req ]
default_bits = 2048
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
input_password = @PASSWORD@
output_password = @PASSWORD@
string_mask = utf8only
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = FI
countryName_min = 2
countryName_max = 2
localityName = Locality Name (eg, city)
localityName_default = Tuusula
0.organizationName = Organization Name (eg, company)
0.organizationName_default = @DOMAIN@
##organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
#@OU@
commonName = Common Name (e.g. server FQDN or YOUR name)
#@CN@
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ req_attributes ]
[ v3_ca ]
# Hotspot 2.0 PKI requirements
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, cRLSign, keyCertSign
authorityInfoAccess = OCSP;URI:@OCSP_URI@
# For SP intermediate CA
#subjectAltName=critical,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engExample OSU
#nameConstraints=permitted;DNS:.@DOMAIN@
#1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
[ v3_osu_server ]
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, keyEncipherment
#@ALTNAME@
#logotypeoid=ASN1:SEQUENCE:LogotypeExtn
1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
[LogotypeExtn]
communityLogos=EXP:0,SEQUENCE:LogotypeInfo
[LogotypeInfo]
# note: implicit tag converted to explicit for CHOICE
direct=EXP:0,SEQUENCE:LogotypeData
[LogotypeData]
image=SEQUENCE:LogotypeImage
[LogotypeImage]
imageDetails=SEQUENCE:LogotypeDetails
imageInfo=SEQUENCE:LogotypeImageInfo
[LogotypeDetails]
mediaType=IA5STRING:image/png
logotypeHash=SEQUENCE:HashAlgAndValues
logotypeURI=SEQUENCE:URI
[HashAlgAndValues]
value1=SEQUENCE:HashAlgAndValueSHA256
#value2=SEQUENCE:HashAlgAndValueSHA1
[HashAlgAndValueSHA256]
hashAlg=SEQUENCE:sha256_alg
hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH256@
[HashAlgAndValueSHA1]
hashAlg=SEQUENCE:sha1_alg
hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH1@
[sha256_alg]
algorithm=OID:sha256
[sha1_alg]
algorithm=OID:sha1
[URI]
uri=IA5STRING:@LOGO_URI@
[LogotypeImageInfo]
# default value color(1), component optional
#type=IMP:0,INTEGER:1
fileSize=INTEGER:7549
xSize=INTEGER:128
ySize=INTEGER:80
language=IMP:4,IA5STRING:zxx
[ crl_ext ]
# issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always
[ v3_OCSP ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = OCSPSigning
[ ext_client ]
basicConstraints=CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
authorityInfoAccess = OCSP;URI:@OCSP_URI@
#@ALTNAME@
extendedKeyUsage = clientAuth
[ ext_server ]
# Hotspot 2.0 PKI requirements
basicConstraints=critical, CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
authorityInfoAccess = OCSP;URI:@OCSP_URI@
#@ALTNAME@
extendedKeyUsage = critical, serverAuth
keyUsage = critical, keyEncipherment

View file

@ -0,0 +1,209 @@
#!/bin/sh
if [ -z "$OPENSSL" ]; then
OPENSSL=openssl
fi
export OPENSSL_CONF=$PWD/openssl.cnf
PASS=whatever
if [ -z "$DOMAIN" ]; then
DOMAIN=w1.fi
fi
COMPANY=w1.fi
OPER_ENG="engw1.fi TESTING USE"
OPER_FI="finw1.fi TESTIKÄYTTÖ"
CNR="Hotspot 2.0 Trust Root CA - 99"
CNO="ocsp.$DOMAIN"
CNV="osu-revoked.$DOMAIN"
CNOC="osu-client.$DOMAIN"
OSU_SERVER_HOSTNAME="osu.$DOMAIN"
DEBUG=0
OCSP_URI="http://$CNO:8888/"
LOGO_URI="http://osu.w1.fi/w1fi_logo.png"
LOGO_HASH256="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d"
LOGO_HASH1="5e1d5085676eede6b02da14d31c523ec20ffba0b"
# Command line overrides
USAGE=$( cat <<EOF
Usage:\n
# -c: Company name, used to generate Subject name CN for Intermediate CA\n
# -C: Subject name CN of the Root CA ($CNR)\n
# -D: Enable debugging (set -x, etc)\n
# -g: Logo sha1 hash ($LOGO_HASH1)\n
# -G: Logo sha256 hash ($LOGO_HASH256)\n
# -h: Show this help message\n
# -l: Logo URI ($LOGO_URI)\n
# -m: Domain ($DOMAIN)\n
# -o: Subject name CN for OSU-Client Server ($CNOC)\n
# -O: Subject name CN for OCSP Server ($CNO)\n
# -p: passphrase for private keys ($PASS)\n
# -r: Operator-english ($OPER_ENG)\n
# -R: Operator-finish ($OPER_FI)\n
# -S: OSU Server name ($OSU_SERVER_HOSTNAME)\n
# -u: OCSP-URI ($OCSP_URI)\n
# -V: Subject name CN for OSU-Revoked Server ($CNV)\n
EOF
)
while getopts "c:C:Dg:G:l:m:o:O:p:r:R:S:u:V:h" flag
do
case $flag in
c) COMPANY=$OPTARG;;
C) CNR=$OPTARG;;
D) DEBUG=1;;
g) LOGO_HASH1=$OPTARG;;
G) LOGO_HASH256=$OPTARG;;
h) echo -e $USAGE; exit 0;;
l) LOGO_URI=$OPTARG;;
m) DOMAIN=$OPTARG;;
o) CNOC=$OPTARG;;
O) CNO=$OPTARG;;
p) PASS=$OPTARG;;
r) OPER_ENG=$OPTARG;;
R) OPER_FI=$OPTARG;;
S) OSU_SERVER_HOSTNAME=$OPTARG;;
u) OCSP_URI=$OPTARG;;
V) CNV=$OPTARG;;
*) echo "Unknown flag: $flag"; echo -e $USAGE; exit 1;;
esac
done
fail()
{
echo "$*"
exit 1
}
echo
echo "---[ Root CA ]----------------------------------------------------------"
echo
if [ $DEBUG = 1 ]
then
set -x
fi
# Set the passphrase and some other common config accordingly.
cat openssl-root.cnf | sed "s/@PASSWORD@/$PASS/" \
> my-openssl-root.cnf
cat openssl.cnf | sed "s/@PASSWORD@/$PASS/" |
sed "s,@OCSP_URI@,$OCSP_URI," |
sed "s,@LOGO_URI@,$LOGO_URI," |
sed "s,@LOGO_HASH1@,$LOGO_HASH1," |
sed "s,@LOGO_HASH256@,$LOGO_HASH256," |
sed "s/@DOMAIN@/$DOMAIN/" \
> my-openssl.cnf
cat my-openssl-root.cnf | sed "s/#@CN@/commonName_default = $CNR/" > openssl.cnf.tmp
mkdir -p rootCA/certs rootCA/crl rootCA/newcerts rootCA/private
touch rootCA/index.txt
if [ -e rootCA/private/cakey.pem ]; then
echo " * Use existing Root CA"
else
echo " * Generate Root CA private key"
$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:4096 -keyout rootCA/private/cakey.pem -out rootCA/careq.pem || fail "Failed to generate Root CA private key"
echo " * Sign Root CA certificate"
$OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out rootCA/cacert.pem -days 10957 -batch -keyfile rootCA/private/cakey.pem -passin pass:$PASS -selfsign -extensions v3_ca -outdir rootCA/newcerts -infiles rootCA/careq.pem || fail "Failed to sign Root CA certificate"
$OPENSSL x509 -in rootCA/cacert.pem -out rootCA/cacert.der -outform DER || fail "Failed to create rootCA DER"
sha256sum rootCA/cacert.der > rootCA/cacert.fingerprint || fail "Failed to create rootCA fingerprint"
fi
if [ ! -e rootCA/crlnumber ]; then
echo 00 > rootCA/crlnumber
fi
echo
echo "---[ Intermediate CA ]--------------------------------------------------"
echo
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $COMPANY Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp
mkdir -p demoCA/certs demoCA/crl demoCA/newcerts demoCA/private
touch demoCA/index.txt
if [ -e demoCA/private/cakey.pem ]; then
echo " * Use existing Intermediate CA"
else
echo " * Generate Intermediate CA private key"
$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -keyout demoCA/private/cakey.pem -out demoCA/careq.pem || fail "Failed to generate Intermediate CA private key"
echo " * Sign Intermediate CA certificate"
$OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out demoCA/cacert.pem -days 3652 -batch -keyfile rootCA/private/cakey.pem -cert rootCA/cacert.pem -passin pass:$PASS -extensions v3_ca -infiles demoCA/careq.pem || fail "Failed to sign Intermediate CA certificate"
# horrible from security view point, but for testing purposes since OCSP responder does not seem to support -passin
openssl rsa -in demoCA/private/cakey.pem -out demoCA/private/cakey-plain.pem -passin pass:$PASS
$OPENSSL x509 -in demoCA/cacert.pem -out demoCA/cacert.der -outform DER || fail "Failed to create demoCA DER."
sha256sum demoCA/cacert.der > demoCA/cacert.fingerprint || fail "Failed to create demoCA fingerprint"
fi
if [ ! -e demoCA/crlnumber ]; then
echo 00 > demoCA/crlnumber
fi
echo
echo "OCSP responder"
echo
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNO/" > openssl.cnf.tmp
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out ocsp.csr -keyout ocsp.key -extensions v3_OCSP
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP || fail "Could not generate ocsp.pem"
echo
echo "---[ Server - to be revoked ] ------------------------------------------"
echo
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNV/" > openssl.cnf.tmp
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-revoked.csr -keyout server-revoked.key
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-revoked.csr -out server-revoked.pem -key $PASS -days 730 -extensions ext_server
$OPENSSL ca -revoke server-revoked.pem -key $PASS
echo
echo "---[ Server - with client ext key use ] ---------------------------------"
echo "---[ Only used for negative-testing for OSU-client implementation ] -----"
echo
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNOC/" > openssl.cnf.tmp
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key || fail "Could not create server-client.key"
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create server-client.pem"
echo
echo "---[ User ]-------------------------------------------------------------"
echo
cat my-openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key || fail "Could not create user.key"
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create user.pem"
echo
echo "---[ Server ]-----------------------------------------------------------"
echo
ALT="DNS:$OSU_SERVER_HOSTNAME"
ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_ENG"
ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_FI"
cat my-openssl.cnf |
sed "s/#@CN@/commonName_default = $OSU_SERVER_HOSTNAME/" |
sed "s/^##organizationalUnitName/organizationalUnitName/" |
sed "s/#@OU@/organizationalUnitName_default = Hotspot 2.0 Online Sign Up Server/" |
sed "s/#@ALTNAME@/subjectAltName=critical,$ALT/" \
> openssl.cnf.tmp
echo $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server || fail "Failed to generate server request"
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server.csr -out server.pem -key $PASS -days 730 -extensions ext_server -policy policy_osu_server || fail "Failed to sign server certificate"
#dump logotype details for debugging
$OPENSSL x509 -in server.pem -out server.der -outform DER
openssl asn1parse -in server.der -inform DER | grep HEX | tail -1 | sed 's/.*://' | xxd -r -p > logo.der
openssl asn1parse -in logo.der -inform DER > logo.asn1
echo
echo "---[ CRL ]---------------------------------------------------------------"
echo
$OPENSSL ca -config $PWD/my-openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS
echo
echo "---[ Verify ]------------------------------------------------------------"
echo
$OPENSSL verify -CAfile rootCA/cacert.pem demoCA/cacert.pem
$OPENSSL verify -CAfile rootCA/cacert.pem -untrusted demoCA/cacert.pem *.pem
cat rootCA/cacert.pem demoCA/cacert.pem > ca.pem

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View file

@ -0,0 +1,262 @@
Hotspot 2.0 OSU server
======================
The information in this document is based on the assumption that Ubuntu
16.04 server (64-bit) distribution is used and the web server is
Apache2. Neither of these are requirements for the installation, but if
other combinations are used, the package names and configuration
parameters may need to be adjusted.
NOTE: This implementation and the example configuration here is meant
only for testing purposes in a lab environment. This design is not
secure to be installed in a publicly available Internet server without
considerable amount of modification and review for security issues.
Build dependencies
------------------
Ubuntu 16.04 server
- default installation
- upgraded to latest package versions
sudo apt-get update
sudo apt-get upgrade
Packages needed for running the service:
sudo apt-get install sqlite3
sudo apt-get install apache2
sudo apt-get install php-sqlite3 php-xml libapache2-mod-php
Additional packages needed for building the components:
sudo apt-get install build-essential
sudo apt-get install libsqlite3-dev
sudo apt-get install libssl-dev
sudo apt-get install libxml2-dev
Installation location
---------------------
Select a location for the installation root directory. The example here
assumes /home/user/hs20-server to be used, but this can be changed by
editing couple of files as indicated below.
sudo mkdir -p /home/user/hs20-server
sudo chown $USER /home/user/hs20-server
mkdir -p /home/user/hs20-server/spp
mkdir -p /home/user/hs20-server/AS
Build
-----
# hostapd as RADIUS server
cd hostapd
#example build configuration
cat > .config <<EOF
CONFIG_DRIVER_NONE=y
CONFIG_PKCS12=y
CONFIG_RADIUS_SERVER=y
CONFIG_EAP=y
CONFIG_EAP_TLS=y
CONFIG_EAP_MSCHAPV2=y
CONFIG_EAP_PEAP=y
CONFIG_EAP_GTC=y
CONFIG_EAP_TTLS=y
CONFIG_EAP_SIM=y
CONFIG_EAP_AKA=y
CONFIG_EAP_AKA_PRIME=y
CONFIG_SQLITE=y
CONFIG_HS20=y
EOF
make hostapd hlr_auc_gw
cp hostapd hlr_auc_gw /home/user/hs20-server/AS
# build hs20_spp_server
cd ../hs20/server
make clean
make
cp hs20_spp_server /home/user/hs20-server/spp
# prepare database (web server user/group needs to have write access)
mkdir -p /home/user/hs20-server/AS/DB
sudo chgrp www-data /home/user/hs20-server/AS/DB
sudo chmod g+w /home/user/hs20-server/AS/DB
sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql.txt
sudo chgrp www-data /home/user/hs20-server/AS/DB/eap_user.db
sudo chmod g+w /home/user/hs20-server/AS/DB/eap_user.db
# add example configuration (note: need to update URLs to match the system)
sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql-example.txt
# copy PHP scripts
# Modify config.php if different installation directory is used.
# Modify PHP scripts to get the desired behavior for user interaction (or use
# the examples as-is for initial testing).
cp -r www /home/user/hs20-server
# Create /home/user/hs20-server/terms-and-conditions file (HTML segment to be
# inserted within the BODY section of the page).
cat > /home/user/hs20-server/terms-and-conditions <<EOF
<P>Terms and conditions..</P>
EOF
# Build local keys and certs
cd ca
# Display help options.
./setup.sh -h
# Remove old keys, fill in appropriate values, and generate your keys.
# For instance:
./clean.sh
rm -fr rootCA"
old_hostname=myserver.local
./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" \
-o $old_hostname-osu-client \
-O $old_hostname-oscp -p lanforge -S $old_hostname \
-V $old_hostname-osu-revoked \
-m local -u http://$old_hostname:8888/
# Configure subscription policies
mkdir -p /home/user/hs20-server/spp/policy
cat > /home/user/hs20-server/spp/policy/default.xml <<EOF
<Policy>
<PolicyUpdate>
<UpdateInterval>30</UpdateInterval>
<UpdateMethod>ClientInitiated</UpdateMethod>
<Restriction>Unrestricted</Restriction>
<URI>https://policy-server.osu.example.com/hs20/spp.php</URI>
</PolicyUpdate>
</Policy>
EOF
# Install Hotspot 2.0 SPP and OMA DM XML schema/DTD files
# XML schema for SPP
# Copy the latest XML schema into /home/user/hs20-server/spp/spp.xsd
# OMA DM Device Description Framework DTD
# Copy into /home/user/hs20-server/spp/dm_ddf-v1_2.dtd
# http://www.openmobilealliance.org/tech/DTD/dm_ddf-v1_2.dtd
# Configure RADIUS authentication service
# Note: Change the URL to match the setup
# Note: Install AAA server key/certificate and root CA in Key directory
cat > /home/user/hs20-server/AS/as-sql.conf <<EOF
driver=none
radius_server_clients=as.radius_clients
eap_server=1
eap_user_file=sqlite:DB/eap_user.db
ca_cert=Key/ca.pem
server_cert=Key/server.pem
private_key=Key/server.key
private_key_passwd=passphrase
eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=eap_sim.db
subscr_remediation_url=https://subscription-server.osu.example.com/hs20/spp.php
EOF
# Set RADIUS passphrase for the APs
# Note: Modify to match the setup
cat > /home/user/hs20-server/AS/as.radius_clients <<EOF
0.0.0.0/0 radius
EOF
Start RADIUS authentication server
----------------------------------
cd /home/user/hs20-server/AS
./hostapd -B as-sql.conf
OSEN RADIUS server configuration notes
The OSEN RADIUS server config file should have the 'ocsp_stapling_response'
configuration in it. For example:
# hostapd-radius config for the radius used by the OSEN AP
interface=eth0#0
driver=none
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
eap_server=1
eap_user_file=/home/user/hs20-server/AS/hostapd-osen.eap_user
server_id=ben-ota-2-osen
radius_server_auth_port=1811
radius_server_clients=/home/user/hs20-server/AS/hostap.radius_clients
ca_cert=/home/user/hs20-server/ca/ca.pem
server_cert=/home/user/hs20-server/ca/server.pem
private_key=/home/user/hs20-server/ca/server.key
private_key_passwd=whatever
ocsp_stapling_response=/home/user/hs20-server/ca/ocsp-server-cache.der
The /home/user/hs20-server/AS/hostapd-osen.eap_user file should look
similar to this, and should coorelate with the osu_nai entry in
the non-OSEN VAP config file. For instance:
# cat hostapd-osen.eap_user
# For OSEN authentication (Hotspot 2.0 Release 2)
"osen@w1.fi" WFA-UNAUTH-TLS
# Run OCSP server:
cd /home/user/hs20-server/ca
./ocsp-responder.sh&
# Update cache (This should be run periodically)
./ocsp-update-cache.sh
Configure web server
--------------------
Edit /etc/apache2/sites-available/default-ssl
Add following block just before "SSL Engine Switch" line":
Alias /hs20/ "/home/user/hs20-server/www/"
<Directory "/home/user/hs20-server/www/">
Options Indexes MultiViews FollowSymLinks
AllowOverride None
Require all granted
SSLOptions +StdEnvVars
</Directory>
Update SSL configuration to use the OSU server certificate/key.
They keys and certs are called 'server.key' and 'server.pem' from
ca/setup.sh.
To support subscription remediation using client certificates, set
"SSLVerifyClient optional" and configure the trust root CA(s) for the
client certificates with SSLCACertificateFile.
Enable default-ssl site and restart Apache2:
sudo a2ensite default-ssl
sudo a2enmod ssl
sudo service apache2 restart
Management UI
-------------
The sample PHP scripts include a management UI for testing
purposes. That is available at https://<server>/hs20/users.php
AP configuration
----------------
APs can now be configured to use the OSU server as the RADIUS
authentication server. In addition, the OSU Provider List ANQP element
should be configured to use the SPP (SOAP+XML) option and with the
following Server URL:
https://<server>/hs20/spp.php/signup?realm=example.com

View file

@ -0,0 +1,207 @@
/*
* Hotspot 2.0 SPP server - standalone version
* Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include <time.h>
#include <sqlite3.h>
#include "common.h"
#include "common/version.h"
#include "xml-utils.h"
#include "spp_server.h"
static void write_timestamp(FILE *f)
{
time_t t;
struct tm *tm;
time(&t);
tm = localtime(&t);
fprintf(f, "%04u-%02u-%02u %02u:%02u:%02u ",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
}
void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
{
va_list ap;
if (ctx->debug_log == NULL)
return;
write_timestamp(ctx->debug_log);
va_start(ap, fmt);
vfprintf(ctx->debug_log, fmt, ap);
va_end(ap);
fprintf(ctx->debug_log, "\n");
}
void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node)
{
char *str;
if (ctx->debug_log == NULL)
return;
str = xml_node_to_str(ctx->xml, node);
if (str == NULL)
return;
write_timestamp(ctx->debug_log);
fprintf(ctx->debug_log, "%s: '%s'\n", title, str);
os_free(str);
}
static int process(struct hs20_svc *ctx)
{
int dmacc = 0;
xml_node_t *soap, *spp, *resp;
char *user, *realm, *post, *str;
ctx->addr = getenv("HS20ADDR");
if (ctx->addr)
debug_print(ctx, 1, "Connection from %s", ctx->addr);
ctx->test = getenv("HS20TEST");
if (ctx->test)
debug_print(ctx, 1, "Requested test functionality: %s",
ctx->test);
user = getenv("HS20USER");
if (user && strlen(user) == 0)
user = NULL;
realm = getenv("HS20REALM");
if (realm == NULL) {
debug_print(ctx, 1, "HS20REALM not set");
return -1;
}
post = getenv("HS20POST");
if (post == NULL) {
debug_print(ctx, 1, "HS20POST not set");
return -1;
}
ctx->imsi = getenv("HS20IMSI");
if (ctx->imsi)
debug_print(ctx, 1, "IMSI %s", ctx->imsi);
ctx->eap_method = getenv("HS20EAPMETHOD");
if (ctx->eap_method)
debug_print(ctx, 1, "EAP method %s", ctx->eap_method);
ctx->id_hash = getenv("HS20IDHASH");
if (ctx->id_hash)
debug_print(ctx, 1, "ID-HASH %s", ctx->id_hash);
soap = xml_node_from_buf(ctx->xml, post);
if (soap == NULL) {
debug_print(ctx, 1, "Could not parse SOAP data");
return -1;
}
debug_dump_node(ctx, "Received SOAP message", soap);
spp = soap_get_body(ctx->xml, soap);
if (spp == NULL) {
debug_print(ctx, 1, "Could not get SPP message");
xml_node_free(ctx->xml, soap);
return -1;
}
debug_dump_node(ctx, "Received SPP message", spp);
resp = hs20_spp_server_process(ctx, spp, user, realm, dmacc);
xml_node_free(ctx->xml, soap);
if (resp == NULL && user == NULL) {
debug_print(ctx, 1, "Request HTTP authentication");
return 2; /* Request authentication */
}
if (resp == NULL) {
debug_print(ctx, 1, "No response");
return -1;
}
soap = soap_build_envelope(ctx->xml, resp);
if (soap == NULL) {
debug_print(ctx, 1, "SOAP envelope building failed");
return -1;
}
str = xml_node_to_str(ctx->xml, soap);
xml_node_free(ctx->xml, soap);
if (str == NULL) {
debug_print(ctx, 1, "Could not get node string");
return -1;
}
printf("%s", str);
free(str);
return 0;
}
static void usage(void)
{
printf("usage:\n"
"hs20_spp_server -r<root directory> [-f<debug log>]\n");
}
int main(int argc, char *argv[])
{
struct hs20_svc ctx;
int ret;
os_memset(&ctx, 0, sizeof(ctx));
for (;;) {
int c = getopt(argc, argv, "f:r:v");
if (c < 0)
break;
switch (c) {
case 'f':
if (ctx.debug_log)
break;
ctx.debug_log = fopen(optarg, "a");
if (ctx.debug_log == NULL) {
printf("Could not write to %s\n", optarg);
return -1;
}
break;
case 'r':
ctx.root_dir = optarg;
break;
case 'v':
printf("hs20_spp_server v%s\n", VERSION_STR);
return 0;
default:
usage();
return -1;
}
}
if (ctx.root_dir == NULL) {
usage();
return -1;
}
ctx.xml = xml_node_init_ctx(&ctx, NULL);
if (ctx.xml == NULL)
return -1;
if (hs20_spp_server_init(&ctx) < 0) {
xml_node_deinit_ctx(ctx.xml);
return -1;
}
ret = process(&ctx);
debug_print(&ctx, 1, "process() --> %d", ret);
xml_node_deinit_ctx(ctx.xml);
hs20_spp_server_deinit(&ctx);
if (ctx.debug_log)
fclose(ctx.debug_log);
return ret;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
/*
* Hotspot 2.0 SPP server
* Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef SPP_SERVER_H
#define SPP_SERVER_H
struct hs20_svc {
const void *ctx;
struct xml_node_ctx *xml;
char *root_dir;
FILE *debug_log;
sqlite3 *db;
const char *addr;
const char *test;
const char *imsi;
const char *eap_method;
const char *id_hash;
};
void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
__attribute__ ((format (printf, 3, 4)));
void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node);
xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
const char *auth_user,
const char *auth_realm, int dmacc);
int hs20_spp_server_init(struct hs20_svc *ctx);
void hs20_spp_server_deinit(struct hs20_svc *ctx);
#endif /* SPP_SERVER_H */

View file

@ -0,0 +1,17 @@
INSERT INTO osu_config(realm,field,value) VALUES('example.com','fqdn','example.com');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','friendly_name','Example Operator');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','spp_http_auth_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/spp-root-ca.der');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/aaa-root-ca.der');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_account','free');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','policy_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','remediation_url','https://subscription-server.osu.example.com/hs20/remediation.php?session_id=');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_remediation_url','https://subscription-server.osu.example.com/hs20/free-remediation.php?session_id=');
INSERT INTO osu_config(realm,field,value) VALUES('example.com','signup_url','https://subscription-server.osu.example.com/hs20/signup.php?session_id=');
INSERT INTO users(identity,realm,methods,password,phase2,shared) VALUES('free','example.com','TTLS-MSCHAPV2','free',1,1);
INSERT INTO wildcards(identity,methods) VALUES('','TTLS,TLS');

View file

@ -0,0 +1,108 @@
CREATE TABLE eventlog(
user TEXT,
realm TEXT,
sessionid TEXT COLLATE NOCASE,
timestamp TEXT,
notes TEXT,
dump TEXT,
addr TEXT
);
CREATE TABLE sessions(
timestamp TEXT,
id TEXT COLLATE NOCASE,
user TEXT,
realm TEXT,
password TEXT,
machine_managed BOOLEAN,
operation INTEGER,
type TEXT,
pps TEXT,
redirect_uri TEXT,
devinfo TEXT,
devdetail TEXT,
cert TEXT,
cert_pem TEXT,
mac_addr TEXT,
osu_user TEXT,
osu_password TEXT,
eap_method TEXT,
mobile_identifier_hash TEXT,
test TEXT
);
CREATE index sessions_id_index ON sessions(id);
CREATE TABLE osu_config(
realm TEXT,
field TEXT,
value TEXT
);
CREATE TABLE users(
identity TEXT PRIMARY KEY,
methods TEXT,
password TEXT,
machine_managed BOOLEAN,
remediation TEXT,
phase2 INTEGER,
realm TEXT,
policy TEXT,
devinfo TEXT,
devdetail TEXT,
pps TEXT,
fetch_pps INTEGER,
osu_user TEXT,
osu_password TEXT,
shared INTEGER,
cert TEXT,
cert_pem TEXT,
t_c_timestamp INTEGER,
mac_addr TEXT,
last_msk TEXT,
polupd_done TEXT,
subrem TEXT
);
CREATE TABLE wildcards(
identity TEXT PRIMARY KEY,
methods TEXT
);
CREATE TABLE authlog(
timestamp TEXT,
session TEXT,
nas_ip TEXT,
username TEXT,
note TEXT
);
CREATE TABLE pending_tc(
mac_addr TEXT PRIMARY KEY,
identity TEXT
);
CREATE TABLE current_sessions(
mac_addr TEXT PRIMARY KEY,
identity TEXT,
start_time TEXT,
nas TEXT,
hs20_t_c_filtering BOOLEAN,
waiting_coa_ack BOOLEAN,
coa_ack_received BOOLEAN
);
CREATE TABLE cert_enroll(
mac_addr TEXT PRIMARY KEY,
user TEXT,
realm TEXT,
serialnum TEXT
);
CREATE TABLE sim_provisioning(
mobile_identifier_hash TEXT PRIMARY KEY,
imsi TEXT,
mac_addr TEXT,
eap_method TEXT,
timestamp TEXT
);

View file

@ -0,0 +1,50 @@
<?php
require('config.php');
$db = new PDO($osu_db);
if (!$db) {
die($sqliteerror);
}
if (isset($_POST["id"]))
$id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
else
die("Missing session id");
if (strlen($id) < 32)
die("Invalid session id");
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
if ($row == false) {
die("Session not found");
}
$uri = $row['redirect_uri'];
$rowid = $row['rowid'];
$realm = $row['realm'];
$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
if (!$row || strlen($row['value']) == 0) {
die("Free account disabled");
}
$user = $row['value'];
$row = $db->query("SELECT password FROM users WHERE identity='$user' AND realm='$realm'")->fetch();
if (!$row)
die("Free account not found");
$pw = $row['password'];
if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', machine_managed='1' WHERE rowid=$rowid")) {
die("Failed to update session database");
}
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
"VALUES ('$user', '$realm', '$id', " .
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
"'completed user input response for a new PPS MO')");
header("Location: $uri", true, 302);
?>

View file

@ -0,0 +1,56 @@
<?php
require('config.php');
$db = new PDO($osu_db);
if (!$db) {
die($sqliteerror);
}
if (isset($_POST["id"]))
$id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
else
die("Missing session id");
$user = $_POST["user"];
$pw = $_POST["password"];
if (strlen($id) < 32 || !isset($user) || !isset($pw)) {
die("Invalid POST data");
}
if (strlen($user) < 1 || strncasecmp($user, "cert-", 5) == 0) {
echo "<html><body><p><red>Invalid username</red></p>\n";
echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
echo "</body></html>\n";
exit;
}
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
if ($row == false) {
die("Session not found");
}
$realm = $row['realm'];
$userrow = $db->query("SELECT identity FROM users WHERE identity='$user' AND realm='$realm'")->fetch();
if ($userrow) {
echo "<html><body><p><red>Selected username is not available</red></p>\n";
echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
echo "</body></html>\n";
exit;
}
$uri = $row['redirect_uri'];
$rowid = $row['rowid'];
if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', type='password' WHERE rowid=$rowid")) {
die("Failed to update session database");
}
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
"VALUES ('$user', '$realm', '$id', " .
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
"'completed user input response for a new PPS MO')");
header("Location: $uri", true, 302);
?>

View file

@ -0,0 +1,39 @@
<?php
require('config.php');
$db = new PDO($osu_db);
if (!$db) {
die($sqliteerror);
}
if (isset($_GET["id"]))
$id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
else
die("Missing session id");
if (strlen($id) < 32)
die("Invalid session id");
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
if ($row == false) {
die("Session not found");
}
$uri = $row['redirect_uri'];
$rowid = $row['rowid'];
$realm = $row['realm'];
$user = sha1(mt_rand());
if (!$db->exec("UPDATE sessions SET user='$user', type='cert' WHERE rowid=$rowid")) {
die("Failed to update session database");
}
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
"VALUES ('', '$realm', '$id', " .
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
"'completed user input response for client certificate enrollment')");
header("Location: $uri", true, 302);
?>

View file

@ -0,0 +1,7 @@
<?php
$osu_root = "/home/user/hs20-server";
$osu_db = "sqlite:$osu_root/AS/DB/eap_user.db";
$t_c_file = "$osu_root/terms-and-conditions";
$t_c_timestamp = 123456789;
$hostapd_ctrl = "udg:///home/user/hs20-server/AS/ctrl/as"
?>

View file

@ -0,0 +1,232 @@
<?php
require('config.php');
$params = explode("/", $_SERVER["PATH_INFO"], 3);
$realm = $params[1];
$cmd = $params[2];
$method = $_SERVER["REQUEST_METHOD"];
unset($user);
unset($rowid);
$db = new PDO($osu_db);
if (!$db) {
error_log("EST: Could not access database");
die("Could not access database");
}
if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
$needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
'uri'=>1, 'response'=>1);
$data = array();
$keys = implode('|', array_keys($needed));
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
$_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed[$m[1]]);
}
if ($needed) {
error_log("EST: Missing auth parameter");
die('Authentication failed');
}
$user = $data['username'];
if (strlen($user) < 1) {
error_log("EST: Empty username");
die('Authentication failed');
}
$sql = "SELECT rowid,password,operation FROM sessions " .
"WHERE user='$user' AND realm='$realm'";
$q = $db->query($sql);
if (!$q) {
error_log("EST: Session not found for user=$user realm=$realm");
die("Session not found");
}
$row = $q->fetch();
if (!$row) {
error_log("EST: Session fetch failed for user=$user realm=$realm");
die('Session not found');
}
$rowid = $row['rowid'];
$oper = $row['operation'];
if ($oper != '5') {
error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
die("Session not found");
}
$pw = $row['password'];
if (strlen($pw) < 1) {
error_log("EST: Empty password for user=$user realm=$realm");
die('Authentication failed');
}
$A1 = md5($user . ':' . $realm . ':' . $pw);
$A2 = md5($method . ':' . $data['uri']);
$resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
$data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
if ($data['response'] != $resp) {
error_log("EST: Incorrect authentication response for user=$user realm=$realm");
die('Authentication failed');
}
} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
$_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
$user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
$sql = "SELECT rowid,password,operation FROM sessions " .
"WHERE user='$user' AND realm='$realm'";
$q = $db->query($sql);
if (!$q) {
error_log("EST: Session not found for user=$user realm=$realm");
die("Session not found");
}
$row = $q->fetch();
if (!$row) {
error_log("EST: Session fetch failed for user=$user realm=$realm");
die('Session not found');
}
$rowid = $row['rowid'];
$oper = $row['operation'];
if ($oper != '10') {
error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
die("Session not found");
}
}
if ($method == "GET" && $cmd == "cacerts") {
$fname = "$osu_root/est/$realm-cacerts.pkcs7";
if (!file_exists($fname)) {
error_log("EST: cacerts - unknown realm $realm");
die("Unknown realm");
}
header("Content-Transfer-Encoding: base64");
header("Content-Type: application/pkcs7-mime");
$data = file_get_contents($fname);
echo wordwrap(base64_encode($data), 72, "\n", true);
echo "\n";
error_log("EST: cacerts");
} else if ($method == "GET" && $cmd == "csrattrs") {
header("Content-Transfer-Encoding: base64");
header("Content-Type: application/csrattrs");
readfile("$osu_root/est/est-attrs.b64");
error_log("EST: csrattrs");
} else if ($method == "POST" &&
($cmd == "simpleenroll" || $cmd == "simplereenroll")) {
$reenroll = $cmd == "simplereenroll";
if (!$reenroll && (!isset($user) || strlen($user) == 0)) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
error_log("EST: simpleenroll - require authentication");
die('Authentication required');
}
if ($reenroll &&
(!isset($user) ||
!isset($_SERVER["SSL_CLIENT_VERIFY"]) ||
$_SERVER["SSL_CLIENT_VERIFY"] != "SUCCESS")) {
header('HTTP/1.1 403 Forbidden');
error_log("EST: simplereenroll - require certificate authentication");
die('Authentication required');
}
if (!isset($_SERVER["CONTENT_TYPE"])) {
error_log("EST: simpleenroll without Content-Type");
die("Missing Content-Type");
}
if (!stristr($_SERVER["CONTENT_TYPE"], "application/pkcs10")) {
error_log("EST: simpleenroll - unexpected Content-Type: " .
$_SERVER["CONTENT_TYPE"]);
die("Unexpected Content-Type");
}
$data = file_get_contents("php://input");
error_log("EST: simpleenroll - POST data from php://input: " . $data);
$req = base64_decode($data);
if ($req == FALSE) {
error_log("EST: simpleenroll - Invalid base64-encoded PKCS#10 data");
die("Invalid base64-encoded PKCS#10 data");
}
$cadir = "$osu_root/est";
$reqfile = "$cadir/tmp/cert-req.pkcs10";
$f = fopen($reqfile, "wb");
fwrite($f, $req);
fclose($f);
$req_pem = "$reqfile.pem";
if (file_exists($req_pem))
unlink($req_pem);
exec("openssl req -in $reqfile -inform DER -out $req_pem -outform PEM");
if (!file_exists($req_pem)) {
error_log("EST: simpleenroll - Failed to parse certificate request");
die("Failed to parse certificate request");
}
/* FIX: validate request and add HS 2.0 extensions to cert */
$cert_pem = "$cadir/tmp/req-signed.pem";
if (file_exists($cert_pem))
unlink($cert_pem);
exec("openssl x509 -req -in $req_pem -CAkey $cadir/cakey.pem -out $cert_pem -CA $cadir/cacert.pem -CAserial $cadir/serial -days 365 -text");
if (!file_exists($cert_pem)) {
error_log("EST: simpleenroll - Failed to sign certificate");
die("Failed to sign certificate");
}
$cert = file_get_contents($cert_pem);
$handle = popen("openssl x509 -in $cert_pem -serial -noout", "r");
$serial = fread($handle, 200);
pclose($handle);
$pattern = "/serial=(?P<snhex>[0-9a-fA-F:]*)/m";
preg_match($pattern, $serial, $matches);
if (!isset($matches['snhex']) || strlen($matches['snhex']) < 1) {
error_log("EST: simpleenroll - Could not get serial number");
die("Could not get serial number");
}
$sn = str_replace(":", "", strtoupper($matches['snhex']));
$user = "cert-$sn";
error_log("EST: user = $user");
$cert_der = "$cadir/tmp/req-signed.der";
if (file_exists($cert_der))
unlink($cert_der);
exec("openssl x509 -in $cert_pem -inform PEM -out $cert_der -outform DER");
if (!file_exists($cert_der)) {
error_log("EST: simpleenroll - Failed to convert certificate");
die("Failed to convert certificate");
}
$der = file_get_contents($cert_der);
$fingerprint = hash("sha256", $der);
error_log("EST: sha256(DER cert): $fingerprint");
$pkcs7 = "$cadir/tmp/est-client.pkcs7";
if (file_exists($pkcs7))
unlink($pkcs7);
exec("openssl crl2pkcs7 -nocrl -certfile $cert_pem -out $pkcs7 -outform DER");
if (!file_exists($pkcs7)) {
error_log("EST: simpleenroll - Failed to prepare PKCS#7 file");
die("Failed to prepare PKCS#7 file");
}
if (!$db->exec("UPDATE sessions SET user='$user', cert='$fingerprint', cert_pem='$cert' WHERE rowid=$rowid")) {
error_log("EST: simpleenroll - Failed to update session database");
die("Failed to update session database");
}
header("Content-Transfer-Encoding: base64");
header("Content-Type: application/pkcs7-mime");
$data = file_get_contents($pkcs7);
$resp = wordwrap(base64_encode($data), 72, "\n", true);
echo $resp . "\n";
error_log("EST: simpleenroll - PKCS#7 response: " . $resp);
} else {
header("HTTP/1.0 404 Not Found");
error_log("EST: Unexpected method or path");
die("Unexpected method or path");
}
?>

View file

@ -0,0 +1,19 @@
<html>
<head>
<title>Hotspot 2.0 - public and free hotspot - remediation</title>
</head>
<body>
<h3>Hotspot 2.0 - public and free hotspot</h3>
<p>Terms and conditions have changed. You need to accept the new terms
to continue using this network.</p>
<p>Terms and conditions..</p>
<?php
echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Accept</a><br>\n";
?>
</body>
</html>

View file

@ -0,0 +1,23 @@
<html>
<head>
<title>Hotspot 2.0 - public and free hotspot</title>
</head>
<body>
<?php
$id = $_GET["session_id"];
echo "<h3>Hotspot 2.0 - public and free hotspot</h3>\n";
echo "<form action=\"add-free.php\" method=\"POST\">\n";
echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
?>
<p>Terms and conditions..</p>
<input type="submit" value="Accept">
</form>
</body>
</html>

View file

@ -0,0 +1,32 @@
<?php
require('config.php');
$db = new PDO($osu_db);
if (!$db) {
die($sqliteerror);
}
if (isset($_GET["id"]))
$id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
else
$id = 0;
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
if ($row == false) {
die("Session not found");
}
$uri = $row['redirect_uri'];
header("Location: $uri", true, 302);
$user = $row['user'];
$realm = $row['realm'];
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
"VALUES ('$user', '$realm', '$id', " .
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
"'redirected after user input')");
?>

View file

@ -0,0 +1,41 @@
<?php
require('config.php');
$db = new PDO($osu_db);
if (!$db) {
die($sqliteerror);
}
if (isset($_POST["id"]))
$id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
else
die("Missing session id");
$pw = $_POST["password"];
if (strlen($id) < 32 || !isset($pw)) {
die("Invalid POST data");
}
$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
if ($row == false) {
die("Session not found");
}
$user = $row['user'];
$realm = $row['realm'];
$uri = $row['redirect_uri'];
$rowid = $row['rowid'];
if (!$db->exec("UPDATE sessions SET password='$pw' WHERE rowid=$rowid")) {
die("Failed to update session database");
}
$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
"VALUES ('$user', '$realm', '$id', " .
"strftime('%Y-%m-%d %H:%M:%f','now'), " .
"'completed user input response for subscription remediation')");
header("Location: $uri", true, 302);
?>

View file

@ -0,0 +1,55 @@
<html>
<head>
<title>Hotspot 2.0 subscription remediation</title>
</head>
<body>
<?php
require('config.php');
$db = new PDO($osu_db);
if (!$db) {
die($sqliteerror);
}
if (isset($_GET["session_id"]))
$id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["session_id"]);
else
$id = 0;
echo "SessionID: " . $id . "<br>\n";
$row = $db->query("SELECT * FROM sessions WHERE id='$id'")->fetch();
if ($row == false) {
die("Session not found");
}
$username = $row['user'];
echo "User: " . $username . "@" . $row['realm'] . "<br>\n";
$user = $db->query("SELECT machine_managed,methods FROM users WHERE identity='$username'")->fetch();
if ($user == false) {
die("User not found");
}
echo "<hr><br>\n";
$cert = $user['methods'] == "TLS" || strncmp($username, "cert-", 5) == 0;
if ($cert) {
echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
} else if ($user['machine_managed'] == "1") {
echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
echo "This will provide a new machine-generated password.<br>\n";
} else {
echo "<form action=\"remediation-pw.php\" method=\"POST\">\n";
echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
echo "New password: <input type=\"password\" name=\"password\"><br>\n";
echo "<input type=\"submit\" value=\"Change password\">\n";
echo "</form>\n";
}
?>
</body>
</html>

View file

@ -0,0 +1,59 @@
<html>
<head>
<title>Hotspot 2.0 signup</title>
</head>
<body>
<?php
$id = $_GET["session_id"];
require('config.php');
$db = new PDO($osu_db);
if (!$db) {
die($sqliteerror);
}
$row = $db->query("SELECT realm,test FROM sessions WHERE id='$id'")->fetch();
if ($row == false) {
die("Session not found for id: $id");
}
$realm = $row['realm'];
$test = $row['test'];
if (strlen($test) > 0) {
echo "<p style=\"color:#FF0000\">Special test functionality: $test</red></big></p>\n";
}
echo "<h3>Sign up for a subscription - $realm</h3>\n";
echo "<p>This page can be used to select between three different types of subscriptions for testing purposes.</p>\n";
echo "<h4>Option 1 - shared free access credential</h4>\n";
$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
if ($row && strlen($row['value']) > 0) {
echo "<p><a href=\"free.php?session_id=$id\">Sign up for free access</a></p>\n";
}
echo "<h4>Option 2 - username/password credential</h4>\n";
echo "<form action=\"add-mo.php\" method=\"POST\">\n";
echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
?>
Select a username and password. Leave password empty to get automatically
generated and machine managed password.<br>
Username: <input type="text" name="user"><br>
Password: <input type="password" name="password"><br>
<input type="submit" value="Complete subscription registration">
</form>
<?php
echo "<h4>Option 3 - client certificate credential</h4>\n";
echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client certificate</a></p>\n"
?>
</body>
</html>

View file

@ -0,0 +1,168 @@
<?php
require('config.php');
if (!stristr($_SERVER["CONTENT_TYPE"], "application/soap+xml")) {
error_log("spp.php - Unexpected Content-Type " . $_SERVER["CONTENT_TYPE"]);
die("Unexpected Content-Type");
}
if ($_SERVER["REQUEST_METHOD"] != "POST") {
error_log("spp.php - Unexpected method " . $_SERVER["REQUEST_METHOD"]);
die("Unexpected method");
}
if (isset($_GET["realm"])) {
$realm = $_GET["realm"];
$realm = PREG_REPLACE("/[^0-9a-zA-Z\.\-]/i", '', $realm);
} else {
error_log("spp.php - Realm not specified");
die("Realm not specified");
}
if (isset($_GET["test"]))
$test = PREG_REPLACE("/[^0-9a-zA-Z\_\-]/i", '', $_GET["test"]);
else
$test = "";
unset($user);
putenv("HS20CERT");
if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
$needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
'uri'=>1, 'response'=>1);
$data = array();
$keys = implode('|', array_keys($needed));
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
$_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed[$m[1]]);
}
if ($needed) {
error_log("spp.php - Authentication failed - missing: " . print_r($needed));
die('Authentication failed');
}
$user = $data['username'];
if (strlen($user) < 1) {
error_log("spp.php - Authentication failed - empty username");
die('Authentication failed');
}
$db = new PDO($osu_db);
if (!$db) {
error_log("spp.php - Could not access database");
die("Could not access database");
}
$row = $db->query("SELECT password FROM users " .
"WHERE identity='$user' AND realm='$realm'")->fetch();
if (!$row) {
$row = $db->query("SELECT osu_password FROM users " .
"WHERE osu_user='$user' AND realm='$realm'")->fetch();
$pw = $row['osu_password'];
} else
$pw = $row['password'];
if (!$row) {
error_log("spp.php - Authentication failed - user '$user' not found");
die('Authentication failed');
}
if (strlen($pw) < 1) {
error_log("spp.php - Authentication failed - empty password");
die('Authentication failed');
}
$A1 = md5($user . ':' . $realm . ':' . $pw);
$A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $data['uri']);
$resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
$data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
if ($data['response'] != $resp) {
error_log("Authentication failure - response mismatch");
die('Authentication failed');
}
} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
$_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
$user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
putenv("HS20CERT=yes");
} else if (isset($_GET["hotspot2dot0-mobile-identifier-hash"])) {
$id_hash = $_GET["hotspot2dot0-mobile-identifier-hash"];
$id_hash = PREG_REPLACE("/[^0-9a-h]/i", '', $id_hash);
$db = new PDO($osu_db);
if (!$db) {
error_log("spp.php - Could not access database");
die("Could not access database");
}
$row = $db->query("SELECT * FROM sim_provisioning " .
"WHERE mobile_identifier_hash='$id_hash'")->fetch();
if (!$row) {
error_log("spp.php - SIM provisioning failed - mobile_identifier_hash not found");
die('SIM provisioning failed - mobile_identifier_hash not found');
}
$imsi = $row['imsi'];
$mac_addr = $row['mac_addr'];
$eap_method = $row['eap_method'];
$row = $db->query("SELECT COUNT(*) FROM osu_config " .
"WHERE realm='$realm'")->fetch();
if (!$row || intval($row[0]) < 1) {
error_log("spp.php - SIM provisioning failed - realm $realm not found");
die('SIM provisioning failed');
}
error_log("spp.php - SIM provisioning for IMSI $imsi");
putenv("HS20SIMPROV=yes");
putenv("HS20IMSI=$imsi");
putenv("HS20MACADDR=$mac_addr");
putenv("HS20EAPMETHOD=$eap_method");
putenv("HS20IDHASH=$id_hash");
} else if (!isset($_SERVER["PATH_INFO"]) ||
$_SERVER["PATH_INFO"] != "/signup") {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
error_log("spp.php - Authentication required (not signup)");
die('Authentication required (not signup)');
}
if (isset($user) && strlen($user) > 0)
putenv("HS20USER=$user");
else
putenv("HS20USER");
putenv("HS20REALM=$realm");
$postdata = file_get_contents("php://input");
putenv("HS20POST=$postdata");
$addr = $_SERVER["REMOTE_ADDR"];
putenv("HS20ADDR=$addr");
putenv("HS20TEST=$test");
$last = exec("$osu_root/spp/hs20_spp_server -r$osu_root -f/tmp/hs20_spp_server.log", $output, $ret);
if ($ret == 2) {
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
error_log("spp.php - Authentication required (ret 2)");
die('Authentication required');
} else {
error_log("spp.php - Unexpected authentication error");
die("Unexpected authentication error");
}
}
if ($ret != 0) {
error_log("spp.php - Failed to process SPP request");
die("Failed to process SPP request");
}
//error_log("spp.php: Response: " . implode($output));
header("Content-Type: application/soap+xml");
echo implode($output);
?>

View file

@ -0,0 +1,87 @@
<?php
require('config.php');
function print_header()
{
echo "<html>\n";
echo "<head><title>HS 2.0 Terms and Conditions</title></head>\n";
echo "<body>\n";
}
$db = new PDO($osu_db);
if (!$db) {
die($sqliteerror);
}
if (!isset($_GET["addr"])) {
die("Missing addr parameter");
}
$addr = $_GET["addr"];
$accept = isset($_GET["accept"]) && $_GET["accept"] == "yes";
$res = $db->prepare("SELECT identity FROM pending_tc WHERE mac_addr=?");
$res->execute(array($addr));
$row = $res->fetch();
if (!$row) {
die("No pending session for the specified MAC address");
}
$identity = $row[0];
if (!$accept) {
print_header();
echo "<p>Accept the following terms and conditions by clicking here: <a href=\"terms.php?addr=$addr&accept=yes\">Accept</a></p>\n<hr>\n";
readfile($t_c_file);
} else {
$res = $db->prepare("UPDATE users SET t_c_timestamp=? WHERE identity=?");
if (!$res->execute(array($t_c_timestamp, $identity))) {
die("Failed to update user account.");
}
$res = $db->prepare("DELETE FROM pending_tc WHERE mac_addr=?");
$res->execute(array($addr));
$fp = fsockopen($hostapd_ctrl);
if (!$fp) {
die("Could not connect to hostapd(AS)");
}
fwrite($fp, "DAC_REQUEST coa $addr t_c_clear");
fclose($fp);
$waiting = true;
$ack = false;
for ($i = 1; $i <= 10; $i++) {
$res = $db->prepare("SELECT waiting_coa_ack,coa_ack_received FROM current_sessions WHERE mac_addr=?");
$res->execute(array($addr));
$row = $res->fetch();
if (!$row) {
die("No current session for the specified MAC address");
}
if (strlen($row[0]) > 0)
$waiting = $row[0] == 1;
if (strlen($row[1]) > 0)
$ack = $row[1] == 1;
$res->closeCursor();
if (!$waiting)
break;
sleep(1);
}
if ($ack) {
header('X-WFA-Hotspot20-Filtering: removed');
print_header();
echo "<p>Terms and conditions were accepted.</p>\n";
echo "<P>Filtering disabled.</P>\n";
} else {
print_header();
echo "<P>Failed to disable filtering.</P>\n";
}
}
?>
</body>
</html>

View file

@ -0,0 +1,377 @@
<?php
require('config.php');
$db = new PDO($osu_db);
if (!$db) {
die($sqliteerror);
}
if (isset($_GET["id"])) {
$id = $_GET["id"];
if (!is_numeric($id))
$id = 0;
} else
$id = 0;
if (isset($_GET["cmd"]))
$cmd = $_GET["cmd"];
else
$cmd = '';
if ($cmd == 'eventlog' && $id > 0) {
$row = $db->query("SELECT dump FROM eventlog WHERE rowid=$id")->fetch();
$dump = $row['dump'];
if ($dump[0] == '<') {
header("Content-type: text/xml");
echo "<?xml version=\"1.0\"?>\n";
echo $dump;
} else {
header("Content-type: text/plain");
echo $dump;
}
exit;
}
if ($cmd == 'mo' && $id > 0) {
$mo = $_GET["mo"];
if (!isset($mo))
exit;
if ($mo != "devinfo" && $mo != "devdetail" && $mo != "pps")
exit;
$row = $db->query("SELECT $mo FROM users WHERE rowid=$id")->fetch();
header("Content-type: text/xml");
echo "<?xml version=\"1.0\"?>\n";
echo $row[$mo];
exit;
}
if ($cmd == 'cert' && $id > 0) {
$row = $db->query("SELECT cert_pem FROM users WHERE rowid=$id")->fetch();
header("Content-type: text/plain");
echo $row['cert_pem'];
exit;
}
?>
<html>
<head><title>HS 2.0 users</title></head>
<body>
<?php
if ($cmd == 'subrem-clear' && $id > 0) {
$db->exec("UPDATE users SET remediation='' WHERE rowid=$id");
}
if ($cmd == 'subrem-add-user' && $id > 0) {
$db->exec("UPDATE users SET remediation='user' WHERE rowid=$id");
}
if ($cmd == 'subrem-add-machine' && $id > 0) {
$db->exec("UPDATE users SET remediation='machine' WHERE rowid=$id");
}
if ($cmd == 'subrem-add-reenroll' && $id > 0) {
$db->exec("UPDATE users SET remediation='reenroll' WHERE rowid=$id");
}
if ($cmd == 'subrem-add-policy' && $id > 0) {
$db->exec("UPDATE users SET remediation='policy' WHERE rowid=$id");
}
if ($cmd == 'subrem-add-free' && $id > 0) {
$db->exec("UPDATE users SET remediation='free' WHERE rowid=$id");
}
if ($cmd == 'fetch-pps-on' && $id > 0) {
$db->exec("UPDATE users SET fetch_pps=1 WHERE rowid=$id");
}
if ($cmd == 'fetch-pps-off' && $id > 0) {
$db->exec("UPDATE users SET fetch_pps=0 WHERE rowid=$id");
}
if ($cmd == 'reset-pw' && $id > 0) {
$db->exec("UPDATE users SET password='ChangeMe' WHERE rowid=$id");
}
if ($cmd == "policy" && $id > 0 && isset($_GET["policy"])) {
$policy = $_GET["policy"];
if ($policy == "no-policy" ||
is_readable("$osu_root/spp/policy/$policy.xml")) {
$db->exec("UPDATE users SET policy='$policy' WHERE rowid=$id");
}
}
if ($cmd == "account-type" && $id > 0 && isset($_GET["type"])) {
$type = $_GET["type"];
if ($type == "shared")
$db->exec("UPDATE users SET shared=1 WHERE rowid=$id");
if ($type == "default")
$db->exec("UPDATE users SET shared=0 WHERE rowid=$id");
}
if ($cmd == "set-osu-cred" && $id > 0) {
$osu_user = $_POST["osu_user"];
$osu_password = $_POST["osu_password"];
if (strlen($osu_user) == 0)
$osu_password = "";
$db->exec("UPDATE users SET osu_user='$osu_user', osu_password='$osu_password' WHERE rowid=$id");
}
if ($cmd == 'clear-t-c' && $id > 0) {
$db->exec("UPDATE users SET t_c_timestamp=NULL WHERE rowid=$id");
}
$dump = 0;
if ($id > 0) {
if (isset($_GET["dump"])) {
$dump = $_GET["dump"];
if (!is_numeric($dump))
$dump = 0;
} else
$dump = 0;
echo "[<a href=\"users.php\">All users</a>] ";
if ($dump == 0)
echo "[<a href=\"users.php?id=$id&dump=1\">Include debug dump</a>] ";
else
echo "[<a href=\"users.php?id=$id\">Without debug dump</a>] ";
echo "<br>\n";
$row = $db->query("SELECT rowid,* FROM users WHERE rowid=$id")->fetch();
echo "<H3>" . $row['identity'] . "@" . $row['realm'] . "</H3>\n";
echo "MO: ";
if (strlen($row['devinfo']) > 0) {
echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devinfo\">DevInfo</a>]\n";
}
if (strlen($row['devdetail']) > 0) {
echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devdetail\">DevDetail</a>]\n";
}
if (strlen($row['pps']) > 0) {
echo "[<a href=\"users.php?cmd=mo&id=$id&mo=pps\">PPS</a>]\n";
}
if (strlen($row['cert_pem']) > 0) {
echo "[<a href=\"users.php?cmd=cert&id=$id\">Certificate</a>]\n";
}
echo "<BR>\n";
echo "Fetch PPS MO: ";
if ($row['fetch_pps'] == "1") {
echo "On next connection " .
"[<a href=\"users.php?cmd=fetch-pps-off&id=$id\">" .
"do not fetch</a>]<br>\n";
} else {
echo "Do not fetch " .
"[<a href=\"users.php?cmd=fetch-pps-on&id=$id\">" .
"request fetch</a>]<br>\n";
}
$cert = $row['cert'];
if (strlen($cert) > 0) {
echo "Certificate fingerprint: $cert<br>\n";
}
echo "Remediation: ";
$rem = $row['remediation'];
if ($rem == "") {
echo "Not required";
echo " [<a href=\"users.php?cmd=subrem-add-user&id=" .
$row['rowid'] . "\">add:user</a>]";
echo " [<a href=\"users.php?cmd=subrem-add-machine&id=" .
$row['rowid'] . "\">add:machine</a>]";
if ($row['methods'] == 'TLS') {
echo " [<a href=\"users.php?cmd=subrem-add-reenroll&id=" .
$row['rowid'] . "\">add:reenroll</a>]";
}
echo " [<a href=\"users.php?cmd=subrem-add-policy&id=" .
$row['rowid'] . "\">add:policy</a>]";
echo " [<a href=\"users.php?cmd=subrem-add-free&id=" .
$row['rowid'] . "\">add:free</a>]";
} else if ($rem == "user") {
echo "User [<a href=\"users.php?cmd=subrem-clear&id=" .
$row['rowid'] . "\">clear</a>]";
} else if ($rem == "policy") {
echo "Policy [<a href=\"users.php?cmd=subrem-clear&id=" .
$row['rowid'] . "\">clear</a>]";
} else if ($rem == "free") {
echo "Free [<a href=\"users.php?cmd=subrem-clear&id=" .
$row['rowid'] . "\">clear</a>]";
} else if ($rem == "reenroll") {
echo "Reenroll [<a href=\"users.php?cmd=subrem-clear&id=" .
$row['rowid'] . "\">clear</a>]";
} else {
echo "Machine [<a href=\"users.php?cmd=subrem-clear&id=" .
$row['rowid'] . "\">clear</a>]";
}
echo "<br>\n";
if (strncmp($row['identity'], "cert-", 5) != 0)
echo "Machine managed: " . ($row['machine_managed'] == "1" ? "TRUE" : "FALSE") . "<br>\n";
echo "<form>Policy: <select name=\"policy\" " .
"onChange=\"window.location='users.php?cmd=policy&id=" .
$row['rowid'] . "&policy=' + this.value;\">\n";
echo "<option value=\"" . $row['policy'] . "\" selected>" . $row['policy'] .
"</option>\n";
$files = scandir("$osu_root/spp/policy");
foreach ($files as $file) {
if (!preg_match("/.xml$/", $file))
continue;
if ($file == $row['policy'] . ".xml")
continue;
$p = substr($file, 0, -4);
echo "<option value=\"$p\">$p</option>\n";
}
echo "<option value=\"no-policy\">no policy</option>\n";
echo "</select></form>\n";
echo "<form>Account type: <select name=\"type\" " .
"onChange=\"window.location='users.php?cmd=account-type&id=" .
$row['rowid'] . "&type=' + this.value;\">\n";
if ($row['shared'] > 0) {
$default_sel = "";
$shared_sel = " selected";
} else {
$default_sel = " selected";
$shared_sel = "";
}
echo "<option value=\"default\"$default_sel>default</option>\n";
echo "<option value=\"shared\"$shared_sel>shared</option>\n";
echo "</select></form>\n";
echo "Phase 2 method(s): " . $row['methods'] . "<br>\n";
echo "<br>\n";
echo "<a href=\"users.php?cmd=reset-pw&id=" .
$row['rowid'] . "\">Reset AAA password</a><br>\n";
echo "<br>\n";
echo "<form action=\"users.php?cmd=set-osu-cred&id=" . $row['rowid'] .
"\" method=\"POST\">\n";
echo "OSU credentials (if username empty, AAA credentials are used):<br>\n";
echo "username: <input type=\"text\" name=\"osu_user\" value=\"" .
$row['osu_user'] . "\">\n";
echo "password: <input type=\"password\" name=\"osu_password\">\n";
echo "<input type=\"submit\" value=\"Set OSU credentials\">\n";
echo "</form>\n";
if (strlen($row['t_c_timestamp']) > 0) {
echo "<br>\n";
echo "<a href=\"users.php?cmd=clear-t-c&id=" .
$row['rowid'] .
"\">Clear Terms and Conditions acceptance</a><br>\n";
}
echo "<hr>\n";
$user = $row['identity'];
$osu_user = $row['osu_user'];
$realm = $row['realm'];
}
if ($id > 0 || ($id == 0 && $cmd == 'eventlog')) {
if ($id == 0) {
echo "[<a href=\"users.php\">All users</a>] ";
echo "<br>\n";
}
echo "<table border=1>\n";
echo "<tr>";
if ($id == 0) {
echo "<th>user<th>realm";
}
echo "<th>time<th>address<th>sessionID<th>notes";
if ($dump > 0)
echo "<th>dump";
echo "\n";
if (isset($_GET["limit"])) {
$limit = $_GET["limit"];
if (!is_numeric($limit))
$limit = 20;
} else
$limit = 20;
if ($id == 0)
$res = $db->query("SELECT rowid,* FROM eventlog ORDER BY timestamp DESC LIMIT $limit");
else if (strlen($osu_user) > 0)
$res = $db->query("SELECT rowid,* FROM eventlog WHERE (user='$user' OR user='$osu_user') AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
else
$res = $db->query("SELECT rowid,* FROM eventlog WHERE user='$user' AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
foreach ($res as $row) {
echo "<tr>";
if ($id == 0) {
echo "<td>" . $row['user'] . "\n";
echo "<td>" . $row['realm'] . "\n";
}
echo "<td>" . $row['timestamp'] . "\n";
echo "<td>" . $row['addr'] . "\n";
echo "<td>" . $row['sessionid'] . "\n";
echo "<td>" . $row['notes'] . "\n";
$d = $row['dump'];
if (strlen($d) > 0) {
echo "[<a href=\"users.php?cmd=eventlog&id=" . $row['rowid'] .
"\">";
if ($d[0] == '<')
echo "XML";
else
echo "txt";
echo "</a>]\n";
if ($dump > 0)
echo "<td>" . htmlspecialchars($d) . "\n";
}
}
echo "</table>\n";
}
if ($id == 0 && $cmd != 'eventlog') {
echo "[<a href=\"users.php?cmd=eventlog&limit=50\">Eventlog</a>] ";
echo "<br>\n";
echo "<table border=1 cellspacing=0 cellpadding=0>\n";
echo "<tr><th>User<th>Realm<th><small>Remediation</small><th>Policy<th><small>Account type</small><th><small>Phase 2 method(s)</small><th>DevId<th>MAC Address<th>T&C\n";
$res = $db->query('SELECT rowid,* FROM users WHERE (phase2=1 OR methods=\'TLS\') ORDER BY identity');
foreach ($res as $row) {
echo "<tr><td><a href=\"users.php?id=" . $row['rowid'] . "\"> " .
$row['identity'] . " </a>";
echo "<td>" . $row['realm'];
$rem = $row['remediation'];
echo "<td>";
if ($rem == "") {
echo "-";
} else if ($rem == "user") {
echo "User";
} else if ($rem == "policy") {
echo "Policy";
} else if ($rem == "free") {
echo "Free";
} else if ($rem == "reenroll") {
echo "Reenroll";
} else {
echo "Machine";
}
echo "<td>" . $row['policy'];
if ($row['shared'] > 0)
echo "<td>shared";
else
echo "<td>default";
echo "<td><small>" . $row['methods'] . "</small>";
echo "<td>";
$xml = xml_parser_create();
xml_parse_into_struct($xml, $row['devinfo'], $devinfo);
foreach($devinfo as $k) {
if ($k['tag'] == 'DEVID') {
echo "<small>" . $k['value'] . "</small>";
break;
}
}
echo "<td><small>" . $row['mac_addr'] . "</small>";
echo "<td><small>" . $row['t_c_timestamp'] . "</small>";
echo "\n";
}
echo "</table>\n";
}
?>
</html>

12
contrib/wpa/src/Makefile Normal file
View file

@ -0,0 +1,12 @@
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae radius rsn_supp tls utils wps
SUBDIRS += fst
all:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
clean:
$(Q)for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
$(Q)rm -f *~
install:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done

View file

@ -0,0 +1,60 @@
CFLAGS += -DHOSTAPD
CFLAGS += -DNEED_AP_MLME
CFLAGS += -DCONFIG_ETH_P_OUI
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_INTERWORKING
CFLAGS += -DCONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R_AP
CFLAGS += -DCONFIG_WPS
CFLAGS += -DCONFIG_PROXYARP
CFLAGS += -DCONFIG_IPV6
CFLAGS += -DCONFIG_AIRTIME_POLICY
LIB_OBJS= \
accounting.o \
ap_config.o \
ap_drv_ops.o \
ap_list.o \
ap_mlme.o \
airtime_policy.o \
authsrv.o \
beacon.o \
bss_load.o \
ctrl_iface_ap.o \
dfs.o \
dhcp_snoop.o \
drv_callbacks.o \
eap_user_db.o \
eth_p_oui.o \
gas_serv.o \
hostapd.o \
hs20.o \
hw_features.o \
ieee802_11_auth.o \
ieee802_11.o \
ieee802_11_ht.o \
ieee802_11_shared.o \
ieee802_11_vht.o \
ieee802_1x.o \
neighbor_db.o \
ndisc_snoop.o \
p2p_hostapd.o \
pmksa_cache_auth.o \
preauth_auth.o \
rrm.o \
sta_info.o \
tkip_countermeasures.o \
utils.o \
vlan.o \
vlan_ifconfig.o \
vlan_init.o \
wmm.o \
wnm_ap.o \
wpa_auth.o \
wpa_auth_ft.o \
wpa_auth_glue.o \
wpa_auth_ie.o \
wps_hostapd.o \
x_snoop.o
include ../lib.rules

View file

@ -261,13 +261,13 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
}
void acs_cleanup(struct hostapd_iface *iface)
static void acs_cleanup_mode(struct hostapd_hw_modes *mode)
{
int i;
struct hostapd_channel_data *chan;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED)
acs_clean_chan_surveys(chan);
@ -276,6 +276,15 @@ void acs_cleanup(struct hostapd_iface *iface)
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
chan->min_nf = 0;
}
}
void acs_cleanup(struct hostapd_iface *iface)
{
int i;
for (i = 0; i < iface->num_hw_features; i++)
acs_cleanup_mode(&iface->hw_features[i]);
iface->chans_surveyed = 0;
iface->acs_num_completed_scans = 0;
@ -363,40 +372,47 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
}
static int acs_usable_ht40_chan(const struct hostapd_channel_data *chan)
static int acs_usable_bw40_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
157, 184, 192 };
const int allowed[] = { 5180, 5220, 5260, 5300, 5500, 5540, 5580, 5620,
5660, 5745, 5785, 4920, 4960, 5955, 5995, 6035,
6075, 6115, 6155, 6195, 6235, 6275, 6315, 6355,
6395, 6435, 6475, 6515, 6555, 6595, 6635, 6675,
6715, 6755, 6795, 6835, 6875, 6915, 6955, 6995,
7035, 7075 };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
if (chan->chan == allowed[i])
if (chan->freq == allowed[i])
return 1;
return 0;
}
static int acs_usable_vht80_chan(const struct hostapd_channel_data *chan)
static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 52, 100, 116, 132, 149 };
const int allowed[] = { 5180, 5260, 5550, 5580, 5660, 5745, 5955, 6035,
6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675,
6755, 6835, 6915, 6995 };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
if (chan->chan == allowed[i])
if (chan->freq == allowed[i])
return 1;
return 0;
}
static int acs_usable_vht160_chan(const struct hostapd_channel_data *chan)
static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 100 };
const int allowed[] = { 5180, 5500, 5955, 6115, 6275, 6435, 6595, 6755,
6915 };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(allowed); i++)
if (chan->chan == allowed[i])
if (chan->freq == allowed[i])
return 1;
return 0;
@ -453,21 +469,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 +519,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 +545,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 +559,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 +593,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 +643,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 +672,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,31 +684,33 @@ 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 &&
iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
!acs_usable_ht40_chan(chan)) {
wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for HT40",
if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
((iface->conf->ieee80211n &&
iface->conf->secondary_channel) ||
is_6ghz_freq(chan->freq)) &&
!acs_usable_bw40_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth",
chan->chan);
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 &&
!acs_usable_vht80_chan(chan)) {
!acs_usable_bw80_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for VHT80",
"ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth",
chan->chan);
continue;
}
if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_160MHZ &&
!acs_usable_vht160_chan(chan)) {
!acs_usable_bw160_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for VHT160",
"ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth",
chan->chan);
continue;
}
@ -698,7 +747,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 +793,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 +812,78 @@ 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;
if (is_6ghz_op_class(iface->conf->op_class)) {
bw = op_class_to_bandwidth(iface->conf->op_class);
n_chans = bw / 20;
goto bw_selected;
}
/* 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);
bw_selected:
/* 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 +939,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface)
return -1;
}
acs_survey_all_chans_intereference_factor(iface);
acs_survey_all_chans_interference_factor(iface);
return 0;
}
@ -862,6 +975,7 @@ static void acs_study(struct hostapd_iface *iface)
}
iface->conf->channel = ideal_chan->chan;
iface->freq = ideal_chan->freq;
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
acs_adjust_center_freq(iface);
@ -917,31 +1031,67 @@ fail:
}
static int acs_request_scan(struct hostapd_iface *iface)
static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode,
int *freq)
{
struct wpa_driver_scan_params params;
struct hostapd_channel_data *chan;
int i, *freq;
int i;
os_memset(&params, 0, sizeof(params));
params.freqs = os_calloc(iface->current_mode->num_channels + 1,
sizeof(params.freqs[0]));
if (params.freqs == NULL)
return -1;
freq = params.freqs;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
if (!is_in_chanlist(iface, chan))
continue;
if (!is_in_freqlist(iface, chan))
continue;
*freq++ = chan->freq;
}
return freq;
}
static int acs_request_scan(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
int i, *freq;
int num_channels;
struct hostapd_hw_modes *mode;
os_memset(&params, 0, sizeof(params));
num_channels = 0;
for (i = 0; i < iface->num_hw_features; i++) {
mode = &iface->hw_features[i];
if (!hostapd_hw_skip_mode(iface, mode))
num_channels += mode->num_channels;
}
params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0]));
if (params.freqs == NULL)
return -1;
freq = params.freqs;
for (i = 0; i < iface->num_hw_features; i++) {
mode = &iface->hw_features[i];
if (!hostapd_hw_skip_mode(iface, mode))
freq = acs_request_scan_add_freqs(iface, mode, freq);
}
*freq = 0;
if (params.freqs == freq) {
wpa_printf(MSG_ERROR, "ACS: No available channels found");
os_free(params.freqs);
return -1;
}
iface->scan_cb = acs_scan_complete;
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
@ -971,7 +1121,8 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
return HOSTAPD_CHAN_ACS;
}
if (!iface->current_mode)
if (!iface->current_mode &&
iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
return HOSTAPD_CHAN_INVALID;
acs_cleanup(iface);

View file

@ -79,6 +79,10 @@ static void count_backlogged_sta(struct hostapd_data *hapd)
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (hostapd_drv_read_sta_data(hapd, &data, sta->addr))
continue;
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->force_backlog_bytes)
data.backlog_bytes = 1;
#endif /* CONFIG_TESTING_OPTIONS */
if (data.backlog_bytes > 0)
set_new_backlog_time(hapd, sta, &now);
@ -134,8 +138,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 +173,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 +182,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data)
if (!apply_limit && bss->conf->airtime_limit) {
if (bss->num_backlogged_sta * wt_sum >
bss->conf->airtime_weight * num_sta_sum)
apply_limit = TRUE;
apply_limit = true;
}
}
if (all_div_min)

View file

@ -16,6 +16,7 @@
#include "common/ieee802_1x_defs.h"
#include "common/eapol_common.h"
#include "common/dhcp.h"
#include "common/sae.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
@ -53,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;
@ -86,11 +97,9 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->pwd_group = 19; /* ECC: GF(p=256) */
#ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201;
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
#endif /* CONFIG_IEEE80211W */
#ifdef EAP_SERVER_FAST
/* both anonymous and authenticated provisioning */
bss->eap_fast_prov = 3;
@ -112,7 +121,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->radius_das_time_window = 300;
bss->sae_anti_clogging_threshold = 5;
bss->anti_clogging_threshold = 5;
bss->sae_sync = 5;
bss->gas_frag_limit = 1400;
@ -122,6 +131,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->fils_hlp_wait_time = 30;
bss->dhcp_server_port = DHCP_SERVER_PORT;
bss->dhcp_relay_port = DHCP_SERVER_PORT;
bss->fils_discovery_min_int = 20;
#endif /* CONFIG_FILS */
bss->broadcast_deauth = 1;
@ -135,6 +145,9 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
* completed and tested with other implementations. */
bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
bss->max_auth_rounds = 100;
bss->max_auth_rounds_short = 50;
bss->send_probe_response = 1;
#ifdef CONFIG_HS20
@ -148,6 +161,15 @@ 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 */
#ifdef CONFIG_PASN
/* comeback after 10 TUs */
bss->pasn_comeback_after = 10;
#endif /* CONFIG_PASN */
}
@ -249,6 +271,14 @@ 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;
conf->he_op.he_twt_responder = 1;
conf->he_6ghz_max_mpdu = 2;
conf->he_6ghz_max_ampdu_len_exp = 7;
conf->he_6ghz_rx_ant_pat = 1;
conf->he_6ghz_tx_ant_pat = 1;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
@ -299,6 +329,7 @@ static int hostapd_config_read_wpa_psk(const char *fname,
while (fgets(buf, sizeof(buf), f)) {
int vlan_id = 0;
int wps = 0;
line++;
@ -329,6 +360,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
value = "";
if (!os_strcmp(name, "keyid")) {
keyid = value;
} else if (!os_strcmp(name, "wps")) {
wps = atoi(value);
} else if (!os_strcmp(name, "vlanid")) {
vlan_id = atoi(value);
} else {
@ -346,8 +379,9 @@ static int hostapd_config_read_wpa_psk(const char *fname,
if (!token)
token = "";
if (hwaddr_aton(token, addr)) {
wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
"line %d in '%s'", token, line, fname);
wpa_printf(MSG_ERROR,
"Invalid MAC address '%s' on line %d in '%s'",
token, line, fname);
ret = -1;
break;
}
@ -375,16 +409,17 @@ static int hostapd_config_read_wpa_psk(const char *fname,
ok = 0;
len = os_strlen(pos);
if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
if (len == 2 * PMK_LEN &&
hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
ok = 1;
else if (len >= 8 && len < 64) {
pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
4096, psk->psk, PMK_LEN);
else if (len >= 8 && len < 64 &&
pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
4096, psk->psk, PMK_LEN) == 0)
ok = 1;
}
if (!ok) {
wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
"'%s'", pos, line, fname);
wpa_printf(MSG_ERROR,
"Invalid PSK '%s' on line %d in '%s'",
pos, line, fname);
os_free(psk);
ret = -1;
break;
@ -402,6 +437,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
}
}
psk->wps = wps;
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
@ -433,10 +470,53 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid)
}
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
{
#ifdef CONFIG_SAE
struct hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw;
if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
!hostapd_sae_pk_in_use(conf)) ||
conf->sae_pwe == 3 ||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt))
return 0; /* PT not needed */
sae_deinit_pt(ssid->pt);
ssid->pt = NULL;
if (ssid->wpa_passphrase) {
ssid->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
ssid->ssid_len,
(const u8 *) ssid->wpa_passphrase,
os_strlen(ssid->wpa_passphrase),
NULL);
if (!ssid->pt)
return -1;
}
for (pw = conf->sae_passwords; pw; pw = pw->next) {
sae_deinit_pt(pw->pt);
pw->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
ssid->ssid_len,
(const u8 *) pw->password,
os_strlen(pw->password),
pw->identifier);
if (!pw->pt)
return -1;
}
#endif /* CONFIG_SAE */
return 0;
}
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
{
struct hostapd_ssid *ssid = &conf->ssid;
if (hostapd_setup_sae_pt(conf) < 0)
return -1;
if (ssid->wpa_passphrase != NULL) {
if (ssid->wpa_psk != NULL) {
wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
@ -581,6 +661,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;
@ -589,6 +670,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)
@ -642,6 +724,12 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
pw = pw->next;
str_clear_free(tmp->password);
os_free(tmp->identifier);
#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);
}
}
@ -674,10 +762,15 @@ 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 */
#ifdef CONFIG_SAE
sae_deinit_pt(conf->ssid.pt);
#endif /* CONFIG_SAE */
hostapd_config_free_eap_users(conf->eap_user);
os_free(conf->eap_user_sqlite);
@ -692,6 +785,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
conf->radius->num_auth_servers);
hostapd_config_free_radius(conf->radius->acct_servers,
conf->radius->num_acct_servers);
os_free(conf->radius->force_client_dev);
}
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
@ -765,6 +859,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->upc);
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
wpabuf_free(conf->wps_vendor_ext[i]);
wpabuf_free(conf->wps_application_ext);
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@ -832,6 +927,12 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override);
wpabuf_free(conf->sae_commit_override);
wpabuf_free(conf->rsne_override_eapol);
wpabuf_free(conf->rsnxe_override_eapol);
wpabuf_free(conf->rsne_override_ft);
wpabuf_free(conf->rsnxe_override_ft);
wpabuf_free(conf->gtk_rsc_override);
wpabuf_free(conf->igtk_rsc_override);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(conf->no_probe_resp_if_seen_on);
@ -840,6 +941,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
hostapd_config_free_fils_realms(conf);
#ifdef CONFIG_DPP
os_free(conf->dpp_name);
os_free(conf->dpp_mud_url);
os_free(conf->dpp_connector);
wpabuf_free(conf->dpp_netaccesskey);
wpabuf_free(conf->dpp_csign);
@ -864,6 +967,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
}
#endif /* CONFIG_AIRTIME_POLICY */
#ifdef CONFIG_PASN
os_free(conf->pasn_groups);
#endif /* CONFIG_PASN */
os_free(conf);
}
@ -885,6 +992,7 @@ void hostapd_config_free(struct hostapd_config *conf)
os_free(conf->supported_rates);
os_free(conf->basic_rates);
os_free(conf->acs_ch_list.range);
os_free(conf->acs_freq_list.range);
os_free(conf->driver_params);
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
@ -1027,10 +1135,85 @@ 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 bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss)
{
if (bss->wpa != WPA_PROTO_RSN) {
wpa_printf(MSG_ERROR,
"Pre-RSNA security methods are not allowed in 6 GHz");
return false;
}
if (bss->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_printf(MSG_ERROR,
"Management frame protection is required in 6 GHz");
return false;
}
if (bss->wpa_key_mgmt & (WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_PSK_SHA256)) {
wpa_printf(MSG_ERROR, "Invalid AKM suite for 6 GHz");
return false;
}
if (bss->rsn_pairwise & (WPA_CIPHER_WEP40 |
WPA_CIPHER_WEP104 |
WPA_CIPHER_TKIP)) {
wpa_printf(MSG_ERROR,
"Invalid pairwise cipher suite for 6 GHz");
return false;
}
if (bss->wpa_group & (WPA_CIPHER_WEP40 |
WPA_CIPHER_WEP104 |
WPA_CIPHER_TKIP)) {
wpa_printf(MSG_ERROR, "Invalid group cipher suite for 6 GHz");
return false;
}
return true;
}
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf,
int full_config)
{
if (full_config && is_6ghz_op_class(conf->op_class) &&
!hostapd_config_check_bss_6g(bss))
return -1;
if (full_config && bss->ieee802_1x && !bss->eap_server &&
!bss->radius->auth_servers) {
wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
@ -1038,6 +1221,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
return -1;
}
#ifdef CONFIG_WEP
if (bss->wpa) {
int wep, i;
@ -1055,6 +1239,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 &&
@ -1102,52 +1287,75 @@ 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");
}
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
#ifdef CONFIG_WEP
if (full_config && conf->ieee80211ax &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
bss->disable_11ax = true;
wpa_printf(MSG_ERROR,
"HE (IEEE 802.11ax) with WEP is not allowed, disabling HE capabilities");
}
#endif /* CONFIG_WEP */
if (full_config && conf->ieee80211ax && 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_11ax = true;
wpa_printf(MSG_ERROR,
"HE (IEEE 802.11ax) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling HE capabilities");
}
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_WPS
if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
@ -1155,12 +1363,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) ||
@ -1204,6 +1414,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;
}
@ -1284,11 +1503,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;
@ -1314,6 +1535,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 ?
@ -1324,11 +1546,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)
@ -1339,6 +1563,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;
@ -1377,3 +1602,38 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
return 2;
return with_id;
}
bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf)
{
#ifdef CONFIG_SAE_PK
struct sae_password_entry *pw;
for (pw = conf->sae_passwords; pw; pw = pw->next) {
if (pw->pk)
return true;
}
#endif /* CONFIG_SAE_PK */
return false;
}
#ifdef CONFIG_SAE_PK
bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf)
{
bool with_pk = false;
struct sae_password_entry *pw;
if (conf->ssid.wpa_passphrase)
return false;
for (pw = conf->sae_passwords; pw; pw = pw->next) {
if (!pw->pk)
return false;
with_pk = true;
}
return with_pk;
}
#endif /* CONFIG_SAE_PK */

View file

@ -67,6 +67,7 @@ struct hostapd_radius_servers;
struct ft_remote_r0kh;
struct ft_remote_r1kh;
#ifdef CONFIG_WEP
#define NUM_WEP_KEYS 4
struct hostapd_wep_keys {
u8 idx;
@ -75,10 +76,13 @@ struct hostapd_wep_keys {
int keys_set;
size_t default_len; /* key length used for dynamic key generation */
};
#endif /* CONFIG_WEP */
typedef enum hostap_security_policy {
SECURITY_PLAINTEXT = 0,
#ifdef CONFIG_WEP
SECURITY_STATIC_WEP = 1,
#endif /* CONFIG_WEP */
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4,
@ -88,6 +92,7 @@ typedef enum hostap_security_policy {
struct hostapd_ssid {
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
u32 short_ssid;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
unsigned int wpa_passphrase_set:1;
@ -99,8 +104,11 @@ struct hostapd_ssid {
struct hostapd_wpa_psk *wpa_psk;
char *wpa_passphrase;
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
@ -150,6 +158,7 @@ struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
char keyid[KEYID_LEN];
int wps;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
@ -188,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 {
@ -251,6 +251,8 @@ struct sae_password_entry {
char *identifier;
u8 peer_addr[ETH_ALEN];
int vlan_id;
struct sae_pt *pt;
struct sae_pk *pk;
};
struct dpp_controller_conf {
@ -265,6 +267,8 @@ struct airtime_sta_weight {
u8 addr[ETH_ALEN];
};
#define EXT_CAPA_MAX_LEN 15
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@ -317,18 +321,16 @@ 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;
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
* frames */
enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
@ -346,15 +348,15 @@ 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;
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
int group_mgmt_cipher;
int beacon_prot;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
@ -371,6 +373,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;
@ -415,6 +418,8 @@ struct hostapd_bss_config {
unsigned int crl_reload_interval;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
unsigned int max_auth_rounds;
unsigned int max_auth_rounds_short;
char *ocsp_stapling_response;
char *ocsp_stapling_response_multi;
char *dh_file;
@ -429,6 +434,8 @@ struct hostapd_bss_config {
int pac_key_refresh_time;
int eap_teap_auth;
int eap_teap_pac_no_inner;
int eap_teap_separate_result;
int eap_teap_id;
int eap_sim_aka_result_ind;
int eap_sim_id;
int tnc;
@ -497,6 +504,7 @@ struct hostapd_bss_config {
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
struct wpabuf *wps_application_ext;
int wps_nfc_pw_from_config;
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
@ -525,8 +533,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;
@ -648,9 +657,11 @@ struct hostapd_bss_config {
struct wpabuf *vendor_elements;
struct wpabuf *assocresp_elements;
unsigned int sae_anti_clogging_threshold;
unsigned int anti_clogging_threshold;
unsigned int sae_sync;
int sae_require_mfp;
int sae_confirm_immediate;
int sae_pwe;
int *sae_groups;
struct sae_password_entry *sae_passwords;
@ -661,7 +672,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)
@ -702,19 +732,27 @@ struct hostapd_bss_config {
unsigned int fils_hlp_wait_time;
u16 dhcp_server_port;
u16 dhcp_relay_port;
u32 fils_discovery_min_int;
u32 fils_discovery_max_int;
#endif /* CONFIG_FILS */
int multicast_to_unicast;
int broadcast_deauth;
int notify_mgmt_frames;
#ifdef CONFIG_DPP
char *dpp_name;
char *dpp_mud_url;
char *dpp_connector;
struct wpabuf *dpp_netaccesskey;
unsigned int dpp_netaccesskey_expiry;
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 */
@ -724,12 +762,15 @@ struct hostapd_bss_config {
size_t owe_transition_ssid_len;
char owe_transition_ifname[IFNAMSIZ + 1];
int *owe_groups;
int owe_ptk_workaround;
#endif /* CONFIG_OWE */
int coloc_intf_reporting;
u8 send_probe_response;
u8 transition_disable;
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
@ -827,15 +868,41 @@ struct hostapd_bss_config {
*/
u8 mka_psk_set;
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_PASN
#ifdef CONFIG_TESTING_OPTIONS
/*
* Normally, KDK should be derived if and only if both sides support
* secure LTF. Allow forcing KDK derivation for testing purposes.
*/
int force_kdk_derivation;
/* If set, corrupt the MIC in the 2nd Authentication frame of PASN */
int pasn_corrupt_mic;
#endif /* CONFIG_TESTING_OPTIONS */
int *pasn_groups;
/*
* The time in TUs after which the non-AP STA is requested to retry the
* PASN authentication in case there are too many parallel operations.
*/
u16 pasn_comeback_after;
#endif /* CONFIG_PASN */
unsigned int unsol_bcast_probe_resp_interval;
u8 ext_capa_mask[EXT_CAPA_MAX_LEN];
u8 ext_capa[EXT_CAPA_MAX_LEN];
};
/**
* 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;
};
/**
@ -843,8 +910,11 @@ 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;
u8 he_twt_responder;
u16 he_rts_threshold;
u16 he_basic_mcs_nss_set;
};
@ -857,8 +927,8 @@ struct spatial_reuse {
u8 non_srg_obss_pd_max_offset;
u8 srg_obss_pd_min_offset;
u8 srg_obss_pd_max_offset;
u8 srg_obss_color_bitmap;
u8 srg_obss_color_partial_bitmap;
u8 srg_bss_color_bitmap[8];
u8 srg_partial_bssid_bitmap[8];
};
/**
@ -871,11 +941,17 @@ struct hostapd_config {
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
u8 op_class;
u8 channel;
int enable_edmg;
u8 edmg_channel;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
struct wpa_freq_range_list acs_freq_list;
u8 acs_freq_list_present;
int acs_exclude_dfs;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
int acs_exclude_6ghz_non_psc;
enum {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
@ -987,6 +1063,10 @@ struct hostapd_config {
u8 he_oper_chwidth;
u8 he_oper_centr_freq_seg0_idx;
u8 he_oper_centr_freq_seg1_idx;
u8 he_6ghz_max_mpdu;
u8 he_6ghz_max_ampdu_len_exp;
u8 he_6ghz_rx_ant_pat;
u8 he_6ghz_tx_ant_pat;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@ -994,8 +1074,14 @@ struct hostapd_config {
#define CH_SWITCH_VHT_DISABLED BIT(1)
unsigned int ch_switch_vht_config;
/* HE enable/disable config from CHAN_SWITCH */
#define CH_SWITCH_HE_ENABLED BIT(0)
#define CH_SWITCH_HE_DISABLED BIT(1)
unsigned int ch_switch_he_config;
int rssi_reject_assoc_rssi;
int rssi_reject_assoc_timeout;
int rssi_ignore_probe_request;
#ifdef CONFIG_AIRTIME_POLICY
enum {
@ -1100,5 +1186,8 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */

View file

@ -10,6 +10,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/hw_features_common.h"
#include "wps/wps.h"
#include "p2p/p2p.h"
@ -107,6 +108,10 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
goto fail;
#endif /* CONFIG_FILS */
pos = hostapd_eid_rsnxe(hapd, buf, sizeof(buf));
if (add_buf_data(&assocresp, buf, pos - buf) < 0)
goto fail;
if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
goto fail;
@ -305,9 +310,7 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
params.wpa_pairwise = hapd->conf->wpa_pairwise;
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
params.rsn_preauth = hapd->conf->rsn_preauth;
#ifdef CONFIG_IEEE80211W
params.ieee80211w = hapd->conf->ieee80211w;
#endif /* CONFIG_IEEE80211W */
}
return hostapd_set_ieee8021x(hapd, &params);
}
@ -348,7 +351,7 @@ int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg)
{
if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
return 0;
return -EOPNOTSUPP;
return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
}
@ -415,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)
{
@ -436,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);
@ -540,7 +545,8 @@ int hostapd_flush(struct hostapd_data *hapd)
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int ht_enabled, int vht_enabled,
int freq, int channel, int edmg, u8 edmg_channel,
int ht_enabled, int vht_enabled,
int he_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
@ -548,7 +554,8 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
struct hostapd_freq_params data;
struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
edmg_channel, ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth,
center_segment0, center_segment1,
@ -583,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);
@ -645,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)
{
@ -675,36 +688,41 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len)
const u8 *key, size_t key_len, enum key_flag key_flag)
{
struct wpa_driver_set_key_params params;
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
return 0;
return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
key_idx, set_tx, seq, seq_len, key,
key_len);
os_memset(&params, 0, sizeof(params));
params.ifname = ifname;
params.alg = alg;
params.addr = addr;
params.key_idx = key_idx;
params.set_tx = set_tx;
params.seq = seq;
params.seq_len = seq_len;
params.key = key;
params.key_len = key_len;
params.vlan_id = vlan_id;
params.key_flag = key_flag;
return hapd->driver->set_key(hapd->drv_priv, &params);
}
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len, int noack)
const void *msg, size_t len, int noack,
const u16 *csa_offs, size_t csa_offs_len,
int no_encrypt)
{
if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
NULL, 0);
}
int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
const void *msg, size_t len, int noack,
const u16 *csa_offs, size_t csa_offs_len)
{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
csa_offs, csa_offs_len);
csa_offs, csa_offs_len, no_encrypt, 0);
}
@ -810,7 +828,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
return -1;
}
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth, center_segment0,
center_segment1,
@ -850,10 +869,24 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
if ((acs_ch_list_all ||
freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
chan->chan)) &&
!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
if (!acs_ch_list_all &&
(hapd->iface->conf->acs_freq_list.num &&
!freq_range_list_includes(
&hapd->iface->conf->acs_freq_list,
chan->freq)))
continue;
if (!acs_ch_list_all &&
(!hapd->iface->conf->acs_freq_list_present &&
hapd->iface->conf->acs_ch_list.num &&
!freq_range_list_includes(
&hapd->iface->conf->acs_ch_list,
chan->chan)))
continue;
if (is_6ghz_freq(chan->freq) &&
hapd->iface->conf->acs_exclude_6ghz_non_psc &&
!is_6ghz_psc_frequency(chan->freq))
continue;
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
!(hapd->iface->conf->acs_exclude_dfs &&
(chan->flag & HOSTAPD_CHAN_RADAR)))
int_array_add_unique(freq_list, chan->freq);
@ -879,10 +912,9 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
int ret, i, acs_ch_list_all = 0;
u8 *channels = NULL;
unsigned int num_channels = 0;
struct hostapd_hw_modes *mode;
int *freq_list = NULL;
enum hostapd_hw_mode selected_mode;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0;
@ -894,42 +926,27 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
* If no chanlist config parameter is provided, include all enabled
* channels of the selected hw_mode.
*/
if (!hapd->iface->conf->acs_ch_list.num)
acs_ch_list_all = 1;
if (hapd->iface->conf->acs_freq_list_present)
acs_ch_list_all = !hapd->iface->conf->acs_freq_list.num;
else
acs_ch_list_all = !hapd->iface->conf->acs_ch_list.num;
mode = hapd->iface->current_mode;
if (mode) {
channels = os_malloc(mode->num_channels);
if (channels == NULL)
return -1;
if (hapd->iface->current_mode)
selected_mode = hapd->iface->current_mode->mode;
else
selected_mode = HOSTAPD_MODE_IEEE80211ANY;
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
if (!acs_ch_list_all &&
!freq_range_list_includes(
&hapd->iface->conf->acs_ch_list,
chan->chan))
continue;
if (hapd->iface->conf->acs_exclude_dfs &&
(chan->flag & HOSTAPD_CHAN_RADAR))
continue;
if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
channels[num_channels++] = chan->chan;
int_array_add_unique(&freq_list, chan->freq);
}
}
} else {
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
hostapd_get_hw_mode_any_channels(hapd, mode,
acs_ch_list_all,
&freq_list);
}
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
if (selected_mode != HOSTAPD_MODE_IEEE80211ANY &&
selected_mode != mode->mode)
continue;
hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all,
&freq_list);
}
params.ch_list = channels;
params.ch_list_len = num_channels;
params.freq_list = freq_list;
params.edmg_enabled = hapd->iface->conf->enable_edmg;
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
@ -953,8 +970,11 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
params.ch_width = 160;
}
if (hapd->iface->conf->op_class)
params.ch_width = op_class_to_bandwidth(
hapd->iface->conf->op_class);
ret = hapd->driver->do_acs(hapd->drv_priv, &params);
os_free(channels);
os_free(freq_list);
return ret;
}
@ -968,3 +988,11 @@ int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
ie, ielen);
}
int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable)
{
if (!hapd->driver || !hapd->driver->dpp_listen || !hapd->drv_priv)
return 0;
return hapd->driver->dpp_listen(hapd->drv_priv, enable);
}

View file

@ -43,6 +43,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
@ -62,7 +63,8 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int ht_enabled, int vht_enabled,
int freq, int channel, int edmg, u8 edmg_channel,
int ht_enabled, int vht_enabled,
int he_enabled, int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
@ -79,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(
@ -88,14 +91,13 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int hostapd_drv_set_key(const char *ifname,
struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
int key_idx, int vlan_id, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len);
const u8 *key, size_t key_len, enum key_flag key_flag);
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len, int noack);
int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
const void *msg, size_t len, int noack,
const u16 *csa_offs, size_t csa_offs_len);
const void *msg, size_t len, int noack,
const u16 *csa_offs, size_t csa_offs_len,
int no_encrypt);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
@ -132,6 +134,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
int hostapd_drv_do_acs(struct hostapd_data *hapd);
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen);
int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable);
#include "drivers/driver.h"
@ -348,12 +351,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)
@ -381,4 +385,35 @@ hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
return hapd->driver->send_external_auth_status(hapd->drv_priv, params);
}
static inline int
hostapd_drv_set_band(struct hostapd_data *hapd, u32 band_mask)
{
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
return -1;
return hapd->driver->set_band(hapd->drv_priv, band_mask);
}
#ifdef ANDROID
static inline int hostapd_drv_driver_cmd(struct hostapd_data *hapd,
char *cmd, char *buf, size_t buf_len)
{
if (!hapd->driver->driver_cmd)
return -1;
return hapd->driver->driver_cmd(hapd->drv_priv, cmd, buf, buf_len);
}
#endif /* ANDROID */
#ifdef CONFIG_TESTING_OPTIONS
static inline int
hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type,
const u8 *match, size_t match_len,
bool multicast)
{
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->register_frame)
return -1;
return hapd->driver->register_frame(hapd->drv_priv, type, match,
match_len, multicast);
}
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* AP_DRV_OPS */

View file

@ -228,7 +228,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
if (!iface->olbc_ht && !ap->ht_support &&
(ap->channel == 0 ||
ap->channel == iface->conf->channel ||
@ -241,7 +240,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_update_beacons(iface);
@ -285,14 +283,12 @@ void ap_list_timer(struct hostapd_iface *iface)
iface->olbc = 0;
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
if (!olbc_ht && iface->olbc_ht) {
wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
iface->olbc_ht = 0;
hostapd_ht_operation_update(iface);
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
}
if (set_beacon)

View file

@ -110,28 +110,10 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
srv.auth_port = conf->radius_server_auth_port;
srv.acct_port = conf->radius_server_acct_port;
srv.conf_ctx = hapd;
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
srv.ssl_ctx = hapd->ssl_ctx;
srv.msg_ctx = hapd->msg_ctx;
srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
srv.eap_fast_a_id = conf->eap_fast_a_id;
srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
srv.eap_fast_prov = conf->eap_fast_prov;
srv.pac_key_lifetime = conf->pac_key_lifetime;
srv.pac_key_refresh_time = conf->pac_key_refresh_time;
srv.eap_teap_auth = conf->eap_teap_auth;
srv.eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
srv.eap_sim_id = conf->eap_sim_id;
srv.tnc = conf->tnc;
srv.wps = hapd->wps;
srv.ipv6 = conf->radius_server_ipv6;
srv.get_eap_user = hostapd_radius_get_eap_user;
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
srv.pwd_group = conf->pwd_group;
srv.server_id = conf->server_id ? conf->server_id : "hostapd";
srv.sqlite_file = conf->eap_user_sqlite;
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
@ -142,10 +124,8 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url;
srv.t_c_server_url = conf->t_c_server_url;
#endif /* CONFIG_HS20 */
srv.erp = conf->eap_server_erp;
srv.erp_domain = conf->erp_domain;
srv.tls_session_lifetime = conf->tls_session_lifetime;
srv.tls_flags = conf->tls_flags;
srv.eap_cfg = hapd->eap_cfg;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@ -193,6 +173,60 @@ static void authsrv_tls_event(void *ctx, enum tls_event ev,
#endif /* EAP_TLS_FUNCS */
static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd)
{
struct eap_config *cfg;
cfg = os_zalloc(sizeof(*cfg));
if (!cfg)
return NULL;
cfg->eap_server = hapd->conf->eap_server;
cfg->ssl_ctx = hapd->ssl_ctx;
cfg->msg_ctx = hapd->msg_ctx;
cfg->eap_sim_db_priv = hapd->eap_sim_db_priv;
cfg->tls_session_lifetime = hapd->conf->tls_session_lifetime;
cfg->tls_flags = hapd->conf->tls_flags;
cfg->max_auth_rounds = hapd->conf->max_auth_rounds;
cfg->max_auth_rounds_short = hapd->conf->max_auth_rounds_short;
if (hapd->conf->pac_opaque_encr_key)
cfg->pac_opaque_encr_key =
os_memdup(hapd->conf->pac_opaque_encr_key, 16);
if (hapd->conf->eap_fast_a_id) {
cfg->eap_fast_a_id = os_memdup(hapd->conf->eap_fast_a_id,
hapd->conf->eap_fast_a_id_len);
cfg->eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
}
if (hapd->conf->eap_fast_a_id_info)
cfg->eap_fast_a_id_info =
os_strdup(hapd->conf->eap_fast_a_id_info);
cfg->eap_fast_prov = hapd->conf->eap_fast_prov;
cfg->pac_key_lifetime = hapd->conf->pac_key_lifetime;
cfg->pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
cfg->eap_teap_auth = hapd->conf->eap_teap_auth;
cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result;
cfg->eap_teap_id = hapd->conf->eap_teap_id;
cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
cfg->eap_sim_id = hapd->conf->eap_sim_id;
cfg->tnc = hapd->conf->tnc;
cfg->wps = hapd->wps;
cfg->fragment_size = hapd->conf->fragment_size;
cfg->pwd_group = hapd->conf->pwd_group;
cfg->pbc_in_m1 = hapd->conf->pbc_in_m1;
if (hapd->conf->server_id) {
cfg->server_id = (u8 *) os_strdup(hapd->conf->server_id);
cfg->server_id_len = os_strlen(hapd->conf->server_id);
} else {
cfg->server_id = (u8 *) os_strdup("hostapd");
cfg->server_id_len = 7;
}
cfg->erp = hapd->conf->eap_server_erp;
return cfg;
}
int authsrv_init(struct hostapd_data *hapd)
{
#ifdef EAP_TLS_FUNCS
@ -273,6 +307,14 @@ int authsrv_init(struct hostapd_data *hapd)
}
#endif /* EAP_SIM_DB */
hapd->eap_cfg = authsrv_eap_config(hapd);
if (!hapd->eap_cfg) {
wpa_printf(MSG_ERROR,
"Failed to build EAP server configuration");
authsrv_deinit(hapd);
return -1;
}
#ifdef RADIUS_SERVER
if (hapd->conf->radius_server_clients &&
hostapd_setup_radius_srv(hapd))
@ -303,4 +345,7 @@ void authsrv_deinit(struct hostapd_data *hapd)
hapd->eap_sim_db_priv = NULL;
}
#endif /* EAP_SIM_DB */
eap_server_config_free(hapd->eap_cfg);
hapd->eap_cfg = NULL;
}

View file

@ -36,27 +36,6 @@
#ifdef NEED_AP_MLME
static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
size_t len)
{
size_t i;
for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
if (hapd->conf->radio_measurements[i])
break;
}
if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
return eid;
*eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
*eid++ = RRM_CAPABILITIES_IE_LEN;
os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
return eid + RRM_CAPABILITIES_IE_LEN;
}
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
{
if (len < 2 + 5)
@ -287,17 +266,101 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
}
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
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];
}
@ -395,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)
@ -455,13 +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)
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);
@ -470,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);
@ -498,22 +555,34 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
!is_6ghz_op_class(hapd->iconf->op_class)) {
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 */
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
is_6ghz_op_class(hapd->iconf->op_class))
pos = hostapd_eid_txpower_envelope(hapd, pos);
#endif /* CONFIG_IEEE80211AX */
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 */
@ -522,9 +591,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)
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);
@ -553,11 +622,11 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_HS20
pos = hostapd_eid_hs20_indication(hapd, pos);
pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
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),
@ -579,7 +648,9 @@ enum ssid_match_result {
static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
const u8 *ssid, size_t ssid_len,
const u8 *ssid_list,
size_t ssid_list_len)
size_t ssid_list_len,
const u8 *short_ssid_list,
size_t short_ssid_list_len)
{
const u8 *pos, *end;
int wildcard = 0;
@ -590,20 +661,30 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
return EXACT_SSID_MATCH;
if (ssid_list == NULL)
return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
if (ssid_list) {
pos = ssid_list;
end = ssid_list + ssid_list_len;
while (end - pos >= 2) {
if (2 + pos[1] > end - pos)
break;
if (pos[1] == 0)
wildcard = 1;
if (pos[1] == hapd->conf->ssid.ssid_len &&
os_memcmp(pos + 2, hapd->conf->ssid.ssid,
pos[1]) == 0)
return EXACT_SSID_MATCH;
pos += 2 + pos[1];
}
}
pos = ssid_list;
end = ssid_list + ssid_list_len;
while (end - pos >= 2) {
if (2 + pos[1] > end - pos)
break;
if (pos[1] == 0)
wildcard = 1;
if (pos[1] == hapd->conf->ssid.ssid_len &&
os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
return EXACT_SSID_MATCH;
pos += 2 + pos[1];
if (short_ssid_list) {
pos = short_ssid_list;
end = short_ssid_list + short_ssid_list_len;
while (end - pos >= 4) {
if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos))
return EXACT_SSID_MATCH;
pos += 4;
}
}
return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
@ -741,11 +822,11 @@ void handle_probe_req(struct hostapd_data *hapd,
int ret;
u16 csa_offs[2];
size_t csa_offs_len;
u32 session_timeout, acct_interim_interval;
struct vlan_description vlan_id;
struct hostapd_sta_wpa_psk_short *psk = NULL;
char *identity = NULL;
char *radius_cui = NULL;
struct radius_sta rad_info;
if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
ssi_signal < hapd->iconf->rssi_ignore_probe_request)
return;
if (len < IEEE80211_HDRLEN)
return;
@ -754,10 +835,8 @@ void handle_probe_req(struct hostapd_data *hapd,
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
ie_len = len - IEEE80211_HDRLEN;
ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
&session_timeout,
&acct_interim_interval, &vlan_id,
&psk, &identity, &radius_cui, 1);
ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
&rad_info, 1);
if (ret == HOSTAPD_ACL_REJECT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Ignore Probe Request frame from " MACSTR
@ -836,7 +915,7 @@ void handle_probe_req(struct hostapd_data *hapd,
#endif /* CONFIG_P2P */
if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
elems.ssid_list_len == 0) {
elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
@ -868,7 +947,8 @@ void handle_probe_req(struct hostapd_data *hapd,
#endif /* CONFIG_TAXONOMY */
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
elems.ssid_list, elems.ssid_list_len);
elems.ssid_list, elems.ssid_list_len,
elems.short_ssid_list, elems.short_ssid_list_len);
if (res == NO_SSID_MATCH) {
if (!(mgmt->da[0] & 0x01)) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
@ -881,6 +961,12 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
}
#ifdef CONFIG_INTERWORKING
if (hapd->conf->interworking &&
elems.interworking && elems.interworking_len >= 1) {
@ -985,9 +1071,9 @@ void handle_probe_req(struct hostapd_data *hapd,
hapd->cs_c_off_ecsa_proberesp;
}
ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
csa_offs_len ? csa_offs : NULL,
csa_offs_len);
ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack,
csa_offs_len ? csa_offs : NULL,
csa_offs_len, 0);
if (ret < 0)
wpa_printf(MSG_INFO, "handle_probe_req: send failed");
@ -1038,6 +1124,23 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
#ifdef CONFIG_IEEE80211AX
/* Unsolicited broadcast Probe Response transmission, 6 GHz only */
static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
if (!is_6ghz_op_class(hapd->iconf->op_class))
return NULL;
params->unsol_bcast_probe_resp_interval =
hapd->conf->unsol_bcast_probe_resp_interval;
return hostapd_gen_probe_resp(hapd, NULL, 0,
&params->unsol_bcast_probe_resp_tmpl_len);
}
#endif /* CONFIG_IEEE80211AX */
void sta_track_del(struct hostapd_sta_info *info)
{
#ifdef CONFIG_TAXONOMY
@ -1048,6 +1151,243 @@ void sta_track_del(struct hostapd_sta_info *info)
}
#ifdef CONFIG_FILS
static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd)
{
u16 cap_info, phy_index = 0;
u8 chwidth = FD_CAP_BSS_CHWIDTH_20, mcs_nss_size = 4;
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
cap_info = FD_CAP_ESS;
if (hapd->conf->wpa)
cap_info |= FD_CAP_PRIVACY;
if (is_6ghz_op_class(hapd->iconf->op_class)) {
phy_index = FD_CAP_PHY_INDEX_HE;
switch (hapd->iconf->op_class) {
case 135:
mcs_nss_size += 4;
/* fallthrough */
case 134:
mcs_nss_size += 4;
chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
break;
case 133:
chwidth = FD_CAP_BSS_CHWIDTH_80;
break;
case 132:
chwidth = FD_CAP_BSS_CHWIDTH_40;
break;
}
} else {
switch (hostapd_get_oper_chwidth(hapd->iconf)) {
case CHANWIDTH_80P80MHZ:
mcs_nss_size += 4;
/* fallthrough */
case CHANWIDTH_160MHZ:
mcs_nss_size += 4;
chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
break;
case CHANWIDTH_80MHZ:
chwidth = FD_CAP_BSS_CHWIDTH_80;
break;
case CHANWIDTH_USE_HT:
if (hapd->iconf->secondary_channel)
chwidth = FD_CAP_BSS_CHWIDTH_40;
else
chwidth = FD_CAP_BSS_CHWIDTH_20;
break;
}
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)
phy_index = FD_CAP_PHY_INDEX_HE;
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_IEEE80211AC
if (!phy_index &&
hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)
phy_index = FD_CAP_PHY_INDEX_VHT;
#endif /* CONFIG_IEEE80211AC */
if (!phy_index &&
hapd->iconf->ieee80211n && !hapd->conf->disable_11n)
phy_index = FD_CAP_PHY_INDEX_HT;
}
cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT;
cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT;
if (mode) {
u16 *mcs = (u16 *) mode->he_capab[IEEE80211_MODE_AP].mcs;
int i;
u16 nss = 0;
for (i = 0; i < HE_NSS_MAX_STREAMS; i++) {
u16 nss_mask = 0x3 << (i * 2);
if (mcs_nss_size == 4 &&
(((mcs[0] & nss_mask) == nss_mask) ||
((mcs[1] & nss_mask) == nss_mask)))
continue;
if (mcs_nss_size == 8 &&
(((mcs[2] & nss_mask) == nss_mask) ||
((mcs[3] & nss_mask) == nss_mask)))
continue;
if (mcs_nss_size == 12 &&
(((mcs[4] & nss_mask) == nss_mask) ||
((mcs[5] & nss_mask) == nss_mask)))
continue;
nss++;
}
if (nss > 4)
cap_info |= FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT;
else if (nss)
cap_info |= (nss - 1) << FD_CAP_NSS_SHIFT;
}
return cap_info;
}
static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
{
struct ieee80211_mgmt *head;
const u8 *mobility_domain;
u8 *pos, *length_pos, buf[200];
u16 ctl = 0;
u8 fd_rsn_info[5];
size_t total_len, buf_len;
total_len = 24 + 2 + 12;
/* FILS Discovery Frame Control */
ctl = (sizeof(hapd->conf->ssid.short_ssid) - 1) |
FD_FRAME_CTL_SHORT_SSID_PRESENT |
FD_FRAME_CTL_LENGTH_PRESENT |
FD_FRAME_CTL_CAP_PRESENT;
total_len += 4 + 1 + 2;
/* Check for optional subfields and calculate length */
if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) {
ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT;
total_len += sizeof(fd_rsn_info);
}
mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
if (mobility_domain) {
ctl |= FD_FRAME_CTL_MD_PRESENT;
total_len += 3;
}
pos = hostapd_eid_fils_indic(hapd, buf, 0);
buf_len = pos - buf;
total_len += buf_len;
head = os_zalloc(total_len);
if (!head)
return NULL;
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memset(head->da, 0xff, ETH_ALEN);
os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
head->u.action.category = WLAN_ACTION_PUBLIC;
head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY;
pos = &head->u.action.u.public_action.variable[0];
/* FILS Discovery Information field */
/* FILS Discovery Frame Control */
WPA_PUT_LE16(pos, ctl);
pos += 2;
/* Hardware or low-level driver will fill in the Timestamp value */
pos += 8;
/* Beacon Interval */
WPA_PUT_LE16(pos, hapd->iconf->beacon_int);
pos += 2;
/* Short SSID */
WPA_PUT_LE32(pos, hapd->conf->ssid.short_ssid);
pos += sizeof(hapd->conf->ssid.short_ssid);
/* Store position of FILS discovery information element Length field */
length_pos = pos++;
/* FD Capability */
WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd));
pos += 2;
/* Operating Class - not present */
/* Primary Channel - not present */
/* AP Configuration Sequence Number - not present */
/* Access Network Options - not present */
/* FD RSN Information */
if (ctl & FD_FRAME_CTL_RSN_INFO_PRESENT) {
os_memcpy(pos, fd_rsn_info, sizeof(fd_rsn_info));
pos += sizeof(fd_rsn_info);
}
/* Channel Center Frequency Segment 1 - not present */
/* Mobility Domain */
if (ctl & FD_FRAME_CTL_MD_PRESENT) {
os_memcpy(pos, &mobility_domain[2], 3);
pos += 3;
}
/* Fill in the Length field value */
*length_pos = pos - (length_pos + 1);
/* FILS Indication element */
if (buf_len) {
os_memcpy(pos, buf, buf_len);
pos += buf_len;
}
*len = pos - (u8 *) head;
wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
head, pos - (u8 *) head);
return (u8 *) head;
}
/* Configure FILS Discovery frame transmission parameters */
static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
params->fd_max_int = hapd->conf->fils_discovery_max_int;
if (is_6ghz_op_class(hapd->iconf->op_class) &&
params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
params->fd_min_int = hapd->conf->fils_discovery_min_int;
if (params->fd_min_int > params->fd_max_int)
params->fd_min_int = params->fd_max_int;
if (params->fd_max_int)
return hostapd_gen_fils_discovery(hapd,
&params->fd_frame_tmpl_len);
return NULL;
}
#endif /* CONFIG_FILS */
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
@ -1058,7 +1398,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
@ -1087,16 +1427,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) {
@ -1105,6 +1449,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);
@ -1145,8 +1490,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);
@ -1163,18 +1507,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)
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);
@ -1183,15 +1520,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);
@ -1214,23 +1544,35 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
!is_6ghz_op_class(hapd->iconf->op_class)) {
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 */
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
is_6ghz_op_class(hapd->iconf->op_class))
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
#endif /* CONFIG_IEEE80211AX */
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 */
@ -1239,11 +1581,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)
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);
@ -1271,12 +1611,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#ifdef CONFIG_HS20
tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
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),
@ -1315,10 +1655,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;
@ -1331,7 +1674,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);
@ -1390,6 +1732,14 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
params->head = NULL;
os_free(params->proberesp);
params->proberesp = NULL;
#ifdef CONFIG_FILS
os_free(params->fd_frame_tmpl);
params->fd_frame_tmpl = NULL;
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211AX
os_free(params->unsol_bcast_probe_resp_tmpl);
params->unsol_bcast_probe_resp_tmpl = NULL;
#endif /* CONFIG_IEEE80211AX */
}
@ -1403,6 +1753,11 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
if (!hapd->drv_priv) {
wpa_printf(MSG_ERROR, "Interface is disabled");
return -1;
}
if (hapd->csa_in_progress) {
wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period");
return -1;
@ -1421,11 +1776,41 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
params.reenable = hapd->reenable_beacon;
#ifdef CONFIG_IEEE80211AX
params.he_spr_ctrl = hapd->iface->conf->spr.sr_control;
params.he_spr_non_srg_obss_pd_max_offset =
hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
params.he_spr_srg_obss_pd_min_offset =
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;
os_memcpy(params.he_spr_bss_color_bitmap,
hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
os_memcpy(params.he_spr_partial_bssid_bitmap,
hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
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);
params.unsol_bcast_probe_resp_tmpl =
hostapd_unsol_bcast_probe_resp(hapd, &params);
#endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0;
#ifdef CONFIG_SAE
params.sae_pwe = hapd->conf->sae_pwe;
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
params.fd_frame_tmpl = hostapd_fils_discovery(hapd, &params);
#endif /* CONFIG_FILS */
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
iconf->channel, iconf->ieee80211n,
iconf->channel, iconf->enable_edmg,
iconf->edmg_channel, iconf->ieee80211n,
iconf->ieee80211ac, iconf->ieee80211ax,
iconf->secondary_channel,
hostapd_get_oper_chwidth(iconf),

View file

@ -30,4 +30,6 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
struct wpabuf **probe_ie_taxonomy);
const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
#endif /* BEACON_H */

View file

@ -273,6 +273,36 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (!os_snprintf_error(buflen - len, res))
len += res;
}
if (sta->sae && sta->sae->tmp) {
const u8 *pos;
unsigned int j, count;
struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
res = os_snprintf(buf + len, buflen - len,
"sae_rejected_groups=");
if (!os_snprintf_error(buflen - len, res))
len += res;
if (groups) {
pos = wpabuf_head(groups);
count = wpabuf_len(groups) / 2;
} else {
pos = NULL;
count = 0;
}
for (j = 0; pos && j < count; j++) {
res = os_snprintf(buf + len, buflen - len, "%s%d",
j == 0 ? "" : " ", WPA_GET_LE16(pos));
if (!os_snprintf_error(buflen - len, res))
len += res;
pos += 2;
}
res = os_snprintf(buf + len, buflen - len, "\n");
if (!os_snprintf_error(buflen - len, res))
len += res;
}
#endif /* CONFIG_SAE */
if (sta->vlan_id > 0) {
@ -315,7 +345,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211N
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
res = os_snprintf(buf + len, buflen - len,
"ht_caps_info=0x%04x\n",
@ -324,7 +353,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (!os_snprintf_error(buflen - len, res))
len += res;
}
#endif /* CONFIG_IEEE80211N */
if (sta->ext_capability &&
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
@ -432,9 +460,6 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
int ret;
u8 *pos;
if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
mgmt = os_zalloc(sizeof(*mgmt) + 100);
if (mgmt == NULL)
return -1;
@ -468,8 +493,8 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
pos += 2;
*pos++ = minor_reason_code;
ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
pos - (u8 *) mgmt, 1);
ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
0);
os_free(mgmt);
return ret < 0 ? -1 : 0;
@ -499,8 +524,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@ -510,10 +534,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
encrypt) < 0)
if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
@ -562,8 +586,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
pos += 6;
encrypt = atoi(pos);
os_memset(&mgmt, 0, sizeof(mgmt));
@ -573,10 +596,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
encrypt) < 0)
if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
IEEE80211_HDRLEN +
sizeof(mgmt.u.deauth),
0, NULL, 0, !encrypt) < 0)
return -1;
return 0;
}
@ -709,6 +732,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
ret = os_snprintf(buf + len, buflen - len,
"channel=%u\n"
"edmg_enable=%d\n"
"edmg_channel=%d\n"
"secondary_channel=%d\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
@ -716,17 +741,36 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
iface->conf->enable_edmg,
iface->conf->edmg_channel,
iface->conf->ieee80211n && !hapd->conf->disable_11n ?
iface->conf->secondary_channel : 0,
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))
return len;
len += ret;
#ifdef CONFIG_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"
"he_oper_centr_freq_seg1_idx=%d\n",
iface->conf->he_oper_chwidth,
iface->conf->he_oper_centr_freq_seg0_idx,
iface->conf->he_oper_centr_freq_seg1_idx);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
#endif /* CONFIG_IEEE80211AX */
if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
ret = os_snprintf(buf + len, buflen - len,
"vht_oper_chwidth=%d\n"
@ -865,6 +909,7 @@ int hostapd_parse_csa_settings(const char *pos,
SET_CSA_SETTING(sec_channel_offset);
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
settings->freq_params.he_enabled = !!os_strstr(pos, " he");
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING

View file

@ -81,17 +81,17 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
* We will also choose this first channel as the control one.
*/
int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
184, 192 };
165, 173, 184, 192 };
/*
* VHT80, valid channels based on center frequency:
* 42, 58, 106, 122, 138, 155
* 42, 58, 106, 122, 138, 155, 171
*/
int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
int allowed_80[] = { 36, 52, 100, 116, 132, 149, 165 };
/*
* VHT160 valid channels based on center frequency:
* 50, 114
* 50, 114, 163
*/
int allowed_160[] = { 36, 100 };
int allowed_160[] = { 36, 100, 149 };
int *allowed = allowed_40;
unsigned int i, allowed_no = 0;
@ -144,30 +144,44 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int i;
u32 bw = num_chan_to_bw(num_chans);
if (first_chan_idx + num_chans > mode->num_channels)
if (first_chan_idx + num_chans > mode->num_channels) {
wpa_printf(MSG_DEBUG,
"DFS: some channels in range not defined");
return 0;
}
first_chan = &mode->channels[first_chan_idx];
/* hostapd DFS implementation assumes the first channel as primary.
* If it's not allowed to use the first channel as primary, decline the
* whole channel range. */
if (!chan_pri_allowed(first_chan))
if (!chan_pri_allowed(first_chan)) {
wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed");
return 0;
}
for (i = 0; i < num_chans; i++) {
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
first_chan_idx);
if (!chan)
if (!chan) {
wpa_printf(MSG_DEBUG, "DFS: no channel data for %d",
first_chan->freq + i * 20);
return 0;
}
/* HT 40 MHz secondary channel availability checked only for
* primary channel */
if (!chan_bw_allowed(chan, bw, 1, !i))
if (!chan_bw_allowed(chan, bw, 1, !i)) {
wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d",
first_chan->freq + i * 20);
return 0;
}
if (!dfs_channel_available(chan, skip_radar))
if (!dfs_channel_available(chan, skip_radar)) {
wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
first_chan->freq + i * 20);
return 0;
}
}
return 1;
@ -210,22 +224,36 @@ static int dfs_find_channel(struct hostapd_iface *iface,
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
(!dfs_is_chan_allowed(chan, n_chans) ||
!(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
!(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) {
wpa_printf(MSG_DEBUG,
"DFS: channel %d (%d) is incompatible",
chan->freq, chan->chan);
continue;
}
/* Skip incompatible chandefs */
if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
wpa_printf(MSG_DEBUG,
"DFS: range not available for %d (%d)",
chan->freq, chan->chan);
continue;
}
if (!is_in_chanlist(iface, chan))
if (!is_in_chanlist(iface, chan)) {
wpa_printf(MSG_DEBUG,
"DFS: channel %d (%d) not in chanlist",
chan->freq, chan->chan);
continue;
}
if (ret_chan && idx == channel_idx) {
wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
chan->freq, chan->chan);
*ret_chan = chan;
return idx;
}
wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
wpa_printf(MSG_DEBUG, "Adding channel %d (%d)",
chan->freq, chan->chan);
channel_idx++;
}
return channel_idx;
@ -235,6 +263,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
static void dfs_adjust_center_freq(struct hostapd_iface *iface,
struct hostapd_channel_data *chan,
int secondary_channel,
int sec_chan_idx_80p80,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx)
{
@ -261,8 +290,14 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface,
case CHANWIDTH_160MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 14;
break;
case CHANWIDTH_80P80MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 6;
*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
break;
default:
wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
wpa_printf(MSG_INFO,
"DFS: Unsupported channel width configuration");
*oper_centr_freq_seg0_idx = 0;
break;
}
@ -441,8 +476,11 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
struct hostapd_channel_data *chan2 = NULL;
int num_available_chandefs;
int chan_idx;
int chan_idx, chan_idx2;
int sec_chan_idx_80p80 = -1;
int i;
u32 _rand;
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
@ -459,6 +497,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
/* Get the count first */
num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
num_available_chandefs);
if (num_available_chandefs == 0)
return NULL;
@ -466,6 +506,12 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
return NULL;
chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
if (!chan) {
wpa_printf(MSG_DEBUG, "DFS: no random channel found");
return NULL;
}
wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)",
chan->freq, chan->chan);
/* dfs_find_channel() calculations assume HT40+ */
if (iface->conf->secondary_channel)
@ -473,8 +519,45 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
else
*secondary_channel = 0;
/* Get secondary channel for HT80P80 */
if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
if (num_available_chandefs <= 1) {
wpa_printf(MSG_ERROR,
"only 1 valid chan, can't support 80+80");
return NULL;
}
/*
* Loop all channels except channel1 to find a valid channel2
* that is not adjacent to channel1.
*/
for (i = 0; i < num_available_chandefs - 1; i++) {
/* start from chan_idx + 1, end when chan_idx - 1 */
chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
if (chan2 && abs(chan2->chan - chan->chan) > 12) {
/* two channels are not adjacent */
sec_chan_idx_80p80 = chan2->chan;
wpa_printf(MSG_DEBUG,
"DFS: got second chan: %d (%d)",
chan2->freq, chan2->chan);
break;
}
}
/* Check if we got a valid secondary channel which is not
* adjacent to the first channel.
*/
if (sec_chan_idx_80p80 == -1) {
wpa_printf(MSG_INFO,
"DFS: failed to get chan2 for 80+80");
return NULL;
}
}
dfs_adjust_center_freq(iface, chan,
*secondary_channel,
sec_chan_idx_80p80,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx);
@ -515,6 +598,7 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
int n_chans = 1, i;
struct hostapd_hw_modes *mode;
int frequency = freq;
int frequency2 = 0;
int ret = 0;
mode = iface->current_mode;
@ -542,6 +626,11 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
n_chans = 4;
frequency = cf1 - 30;
break;
case CHAN_WIDTH_80P80:
n_chans = 4;
frequency = cf1 - 30;
frequency2 = cf2 - 30;
break;
case CHAN_WIDTH_160:
n_chans = 8;
frequency = cf1 - 70;
@ -557,6 +646,11 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
for (i = 0; i < n_chans; i++) {
ret += set_dfs_state_freq(iface, frequency, state);
frequency = frequency + 20;
if (chan_width == CHAN_WIDTH_80P80) {
ret += set_dfs_state_freq(iface, frequency2, state);
frequency2 = frequency2 + 20;
}
}
return ret;
@ -662,6 +756,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
int skip_radar = 0;
if (is_6ghz_freq(iface->freq))
return 1;
if (!iface->current_mode) {
/*
* This can happen with drivers that do not provide mode
@ -759,7 +856,7 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
}
static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
{
int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
@ -807,7 +904,7 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
* another radio.
*/
if (iface->state != HAPD_IFACE_ENABLED &&
hostapd_config_dfs_chan_available(iface)) {
hostapd_is_dfs_chan_available(iface)) {
hostapd_setup_interface_complete(iface, 0);
iface->cac_started = 0;
}
@ -837,6 +934,44 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
}
static struct hostapd_channel_data *
dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx, int *skip_radar)
{
struct hostapd_channel_data *channel;
for (;;) {
channel = dfs_get_valid_channel(iface, secondary_channel,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
*skip_radar);
if (channel) {
wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
channel->chan);
return channel;
}
if (*skip_radar) {
*skip_radar = 0;
} else {
int oper_chwidth;
oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
if (oper_chwidth == CHANWIDTH_USE_HT)
break;
*skip_radar = 1;
hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
}
}
wpa_printf(MSG_INFO,
"%s: no DFS channels left, waiting for NOP to finish",
__func__);
return NULL;
}
static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
@ -854,8 +989,14 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
skip_radar);
if (!channel) {
wpa_printf(MSG_ERROR, "No valid channel available");
return err;
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
&skip_radar);
if (!channel) {
wpa_printf(MSG_ERROR, "No valid channel available");
return err;
}
}
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
@ -884,11 +1025,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",
@ -922,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",
@ -952,23 +1101,32 @@ 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,
channel->chan,
iface->conf->enable_edmg,
iface->conf->edmg_channel,
iface->conf->ieee80211n,
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");
@ -988,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,
@ -1024,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);
@ -1067,7 +1228,9 @@ int hostapd_is_dfs_required(struct hostapd_iface *iface)
{
int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res;
if (!iface->conf->ieee80211h || !iface->current_mode ||
if ((!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
!iface->conf->ieee80211h) ||
!iface->current_mode ||
iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
@ -1093,11 +1256,18 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
/* This is called when the driver indicates that an offloaded DFS has
* started CAC. */
hostapd_set_state(iface, HAPD_IFACE_DFS);
/* TODO: How to check CAC time for ETSI weather channels? */
iface->dfs_cac_ms = 60000;
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
"seg1=%d cac_time=%ds",
freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
iface->dfs_cac_ms / 1000);
iface->cac_started = 1;
os_get_reltime(&iface->dfs_cac_start);
return 0;
}
@ -1111,6 +1281,8 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
*/
int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
{
int dfs_res;
wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
__func__, iface->cac_started);
@ -1126,10 +1298,11 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
return 1;
}
if (ieee80211_is_dfs(iface->freq, iface->hw_features,
iface->num_hw_features)) {
wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
__func__, iface->freq);
dfs_res = hostapd_is_dfs_required(iface);
if (dfs_res > 0) {
wpa_printf(MSG_DEBUG,
"%s: freq %d MHz requires DFS for %d chans",
__func__, iface->freq, dfs_res);
return 0;
}
@ -1138,3 +1311,60 @@ 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 ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
HOSTAPD_CHAN_DFS_AVAILABLE)
continue;
if (center_freq - chan->freq < half_width &&
chan->freq - center_freq < half_width)
res++;
}
wpa_printf(MSG_DEBUG, "DFS CAC required: (%d, %d): in range: %s",
center_freq - half_width, center_freq + half_width,
res ? "yes" : "no");
return res;
}

View file

@ -25,9 +25,12 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
int ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2);
int hostapd_is_dfs_required(struct hostapd_iface *iface);
int hostapd_is_dfs_chan_available(struct hostapd_iface *iface);
int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2);
int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
int center_freq);
#endif /* DFS_H */

View file

@ -39,22 +39,22 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
const u8 *end, *pos;
int res, msgtype = 0, prefixlen = 32;
u32 subnet_mask = 0;
u16 tot_len;
u16 ip_len;
exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
if (exten_len < 4)
return;
b = (const struct bootp_pkt *) &buf[ETH_HLEN];
tot_len = ntohs(b->iph.tot_len);
if (tot_len > (unsigned int) (len - ETH_HLEN))
ip_len = ntohs(b->iph.ip_len);
if (ip_len > (unsigned int) (len - ETH_HLEN))
return;
if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
return;
/* Parse DHCP options */
end = (const u8 *) b + tot_len;
end = (const u8 *) b + ip_len;
pos = &b->exten[4];
while (pos < end && *pos != DHCP_OPT_END) {
const u8 *opt = pos++;

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
/*
* hostapd / DPP integration
* Copyright (c) 2017, Qualcomm Atheros, Inc.
* Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -9,7 +10,12 @@
#ifndef DPP_HOSTAPD_H
#define DPP_HOSTAPD_H
struct dpp_bootstrap_info;
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
@ -35,4 +41,9 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd);
void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
#endif /* DPP_HOSTAPD_H */

View file

@ -16,6 +16,8 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/dpp.h"
#include "common/sae.h"
#include "common/hw_features_common.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@ -103,20 +105,45 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
#endif /* CONFIG_FILS */
static bool check_sa_query_need(struct hostapd_data *hapd, struct sta_info *sta)
{
if ((sta->flags &
(WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
(WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED))
return false;
if (!sta->sa_query_timed_out && sta->sa_query_count > 0)
ap_check_sa_query_timeout(hapd, sta);
if (!sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) {
/*
* STA has already been associated with MFP and SA Query timeout
* has not been reached. Reject the association attempt
* temporarily and start SA Query, if one is not pending.
*/
if (sta->sa_query_count == 0)
ap_sta_start_sa_query(hapd, sta);
return true;
}
return false;
}
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *req_ies, size_t req_ies_len, int reassoc)
{
struct sta_info *sta;
int new_assoc, res;
int new_assoc;
enum wpa_validate_result res;
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
int status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
if (addr == NULL) {
@ -131,6 +158,19 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
"hostapd_notif_assoc: Skip event with no address");
return -1;
}
if (is_multicast_ether_addr(addr) ||
is_zero_ether_addr(addr) ||
os_memcmp(addr, hapd->own_addr, ETH_ALEN) == 0) {
/* Do not process any frames with unexpected/invalid SA so that
* we do not add any state for unexpected STA addresses or end
* up sending out frames to unexpected destination. */
wpa_printf(MSG_DEBUG, "%s: Invalid SA=" MACSTR
" in received indication - ignore this indication silently",
__func__, MAC2STR(addr));
return 0;
}
random_add_randomness(addr, ETH_ALEN);
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
@ -207,7 +247,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
if (elems.ht_capabilities &&
(hapd->iface->conf->ht_capab &
@ -221,7 +260,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
ht40_intolerant_add(hapd->iface, sta);
}
#endif /* NEED_AP_MLME */
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_INTERWORKING
if (elems.ext_capab && elems.ext_capab_len > 4) {
@ -281,6 +319,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
struct wpabuf *wps;
if (check_sa_query_need(hapd, sta)) {
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
p = hostapd_eid_assoc_comeback_time(hapd, sta,
p);
hostapd_sta_assoc(hapd, addr, reassoc, status,
buf, p - buf);
return 0;
}
sta->flags |= WLAN_STA_WPS;
wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE);
@ -308,58 +357,75 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
ie, ielen,
elems.rsnxe ? elems.rsnxe - 2 : NULL,
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;
}
#ifdef CONFIG_IEEE80211W
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;
}
#endif /* CONFIG_IEEE80211W */
else {
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
}
goto fail;
}
#ifdef CONFIG_IEEE80211W
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);
@ -373,7 +439,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->flags |= WLAN_STA_MFP;
else
sta->flags &= ~WLAN_STA_MFP;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
@ -390,6 +455,20 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
}
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
if (hapd->conf->sae_pwe == 2 &&
sta->auth_alg == WLAN_AUTH_SAE &&
sta->sae && !sta->sae->h2e &&
ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
WLAN_RSNX_CAPAB_SAE_H2E)) {
wpa_printf(MSG_INFO, "SAE: " MACSTR
" indicates support for SAE H2E, but did not use it",
MAC2STR(sta->addr));
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
reason = WLAN_REASON_UNSPECIFIED;
goto fail;
}
#endif /* CONFIG_SAE */
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
@ -442,6 +521,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
}
#ifdef CONFIG_WPS
skip_wpa_check:
#endif /* CONFIG_WPS */
#ifdef CONFIG_MBO
if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
@ -453,13 +535,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#endif /* CONFIG_MBO */
#ifdef CONFIG_WPS
skip_wpa_check:
#endif /* CONFIG_WPS */
#ifdef CONFIG_IEEE80211R_AP
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
sta->auth_alg, req_ies, req_ies_len);
sta->auth_alg, req_ies, req_ies_len,
!elems.rsnxe);
if (!p) {
wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@ -546,22 +625,24 @@ skip_wpa_check:
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
elems.owe_dh) {
u8 *npos;
u16 ret_status;
npos = owe_assoc_req_process(hapd, sta,
elems.owe_dh, elems.owe_dh_len,
p, sizeof(buf) - (p - buf),
&reason);
&ret_status);
status = ret_status;
if (npos)
p = npos;
if (!npos &&
reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
hostapd_sta_assoc(hapd, addr, reassoc, ret_status, buf,
p - buf);
return 0;
}
if (!npos || reason != WLAN_STATUS_SUCCESS)
if (!npos || status != WLAN_STATUS_SUCCESS)
goto fail;
}
#endif /* CONFIG_OWE */
@ -598,6 +679,11 @@ skip_wpa_check:
pfs_fail:
#endif /* CONFIG_DPP2 */
if (elems.rrm_enabled &&
elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
sizeof(sta->rrm_enabled_capa));
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
@ -644,7 +730,8 @@ skip_wpa_check:
fail:
#ifdef CONFIG_IEEE80211R_AP
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
if (status >= 0)
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#endif /* CONFIG_IEEE80211R_AP */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta);
@ -682,6 +769,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
hostapd_set_sta_flags(hapd, sta);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@ -775,8 +863,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2,
int finished)
{
/* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
#ifdef NEED_AP_MLME
int channel, chwidth, is_dfs;
u8 seg0_idx = 0, seg1_idx = 0;
@ -784,9 +870,10 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
"driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
finished ? "had" : "starting",
freq, ht, hapd->iconf->ch_switch_vht_config, offset,
freq, ht, hapd->iconf->ch_switch_vht_config,
hapd->iconf->ch_switch_he_config, offset,
width, channel_width_to_string(width), cf1, cf2);
if (!hapd->iface->current_mode) {
@ -826,9 +913,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:
@ -849,13 +945,31 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
else if (hapd->iconf->ch_switch_vht_config &
CH_SWITCH_VHT_DISABLED)
hapd->iconf->ieee80211ac = 0;
} else if (hapd->iconf->ch_switch_he_config) {
/* CHAN_SWITCH HE config */
if (hapd->iconf->ch_switch_he_config &
CH_SWITCH_HE_ENABLED)
hapd->iconf->ieee80211ax = 1;
else if (hapd->iconf->ch_switch_he_config &
CH_SWITCH_HE_DISABLED)
hapd->iconf->ieee80211ax = 0;
}
hapd->iconf->ch_switch_vht_config = 0;
hapd->iconf->ch_switch_he_config = 0;
hapd->iconf->secondary_channel = offset;
hostapd_set_oper_chwidth(hapd->iconf, chwidth);
hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
if (hapd->iconf->ieee80211ac) {
hapd->iconf->vht_capab &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
if (chwidth == CHANWIDTH_160MHZ)
hapd->iconf->vht_capab |=
VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
else if (chwidth == CHANWIDTH_80P80MHZ)
hapd->iconf->vht_capab |=
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
}
is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
hapd->iface->num_hw_features);
@ -879,10 +993,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 */
}
@ -909,6 +1052,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
{
int ret, i;
int err = 0;
struct hostapd_channel_data *pri_chan;
if (hapd->iconf->channel) {
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@ -916,12 +1060,20 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
return;
}
hapd->iface->freq = acs_res->pri_freq;
if (!hapd->iface->current_mode) {
for (i = 0; i < hapd->iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode =
&hapd->iface->hw_features[i];
if (mode->mode == acs_res->hw_mode) {
if (hapd->iface->freq > 0 &&
!hw_get_chan(mode->mode,
hapd->iface->freq,
hapd->iface->hw_features,
hapd->iface->num_hw_features))
continue;
hapd->iface->current_mode = mode;
break;
}
@ -935,24 +1087,33 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
}
}
hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
if (!acs_res->pri_channel) {
if (!acs_res->pri_freq) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
err = 1;
goto out;
}
pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode,
acs_res->pri_freq, NULL,
hapd->iface->hw_features,
hapd->iface->num_hw_features);
if (!pri_chan) {
wpa_printf(MSG_ERROR,
"ACS: Could not determine primary channel number from pri_freq %u",
acs_res->pri_freq);
err = 1;
goto out;
}
hapd->iconf->channel = acs_res->pri_channel;
hapd->iconf->channel = pri_chan->chan;
hapd->iconf->acs = 1;
if (acs_res->sec_channel == 0)
if (acs_res->sec_freq == 0)
hapd->iconf->secondary_channel = 0;
else if (acs_res->sec_channel < acs_res->pri_channel)
else if (acs_res->sec_freq < acs_res->pri_freq)
hapd->iconf->secondary_channel = -1;
else if (acs_res->sec_channel > acs_res->pri_channel)
else if (acs_res->sec_freq > acs_res->pri_freq)
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
@ -960,32 +1121,35 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
goto out;
}
hapd->iconf->edmg_channel = acs_res->edmg_channel;
if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
/* set defaults for backwards compatibility */
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
if (acs_res->ch_width == 80) {
if (acs_res->ch_width == 40) {
if (is_6ghz_freq(acs_res->pri_freq))
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf,
acs_res->vht_seg0_center_ch);
} else if (acs_res->ch_width == 80) {
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf, acs_res->vht_seg0_center_ch);
hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ);
} else if (acs_res->ch_width == 160) {
if (acs_res->vht_seg1_center_ch == 0) {
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf,
acs_res->vht_seg0_center_ch);
hostapd_set_oper_chwidth(hapd->iconf,
CHANWIDTH_160MHZ);
CHANWIDTH_80MHZ);
} else {
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf,
acs_res->vht_seg0_center_ch);
hostapd_set_oper_chwidth(hapd->iconf,
CHANWIDTH_80P80MHZ);
hostapd_set_oper_centr_freq_seg1_idx(
hapd->iconf,
acs_res->vht_seg1_center_ch);
hostapd_set_oper_chwidth(hapd->iconf,
CHANWIDTH_80P80MHZ);
}
} else if (acs_res->ch_width == 160) {
hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ);
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf, acs_res->vht_seg1_center_ch);
}
}
@ -1164,12 +1328,10 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
return;
}
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
return;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
@ -1383,15 +1545,33 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
#endif /* HOSTAPD */
static struct hostapd_channel_data *
hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq)
{
int i;
struct hostapd_channel_data *chan;
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
if ((unsigned int) chan->freq == freq)
return chan;
}
return NULL;
}
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
{
int i;
struct hostapd_channel_data *chan;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if ((unsigned int) chan->freq == freq)
for (i = 0; i < iface->num_hw_features; i++) {
if (hostapd_hw_skip_mode(iface, &iface->hw_features[i]))
continue;
chan = hostapd_get_mode_chan(&iface->hw_features[i], freq);
if (chan)
return chan;
}

View file

@ -158,7 +158,7 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
ssize_t res;
u8 msgtype = 0;
int rapid_commit = 0;
struct iphdr *iph;
struct ip *iph;
struct udphdr *udph;
struct wpabuf *resp;
const u8 *rpos;
@ -259,14 +259,14 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
wpabuf_put_be16(resp, ETH_P_IP);
iph = wpabuf_put(resp, sizeof(*iph));
iph->version = 4;
iph->ihl = sizeof(*iph) / 4;
iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
iph->ttl = 1;
iph->protocol = 17; /* UDP */
iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
iph->daddr = dhcp->client_ip;
iph->check = ip_checksum(iph, sizeof(*iph));
iph->ip_v = 4;
iph->ip_hl = sizeof(*iph) / 4;
iph->ip_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
iph->ip_ttl = 1;
iph->ip_p = 17; /* UDP */
iph->ip_src.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
iph->ip_dst.s_addr = dhcp->client_ip;
iph->ip_sum = ip_checksum(iph, sizeof(*iph));
udph = wpabuf_put(resp, sizeof(*udph));
udph->uh_sport = htons(DHCP_SERVER_PORT);
udph->uh_dport = htons(DHCP_CLIENT_PORT);
@ -479,13 +479,13 @@ static int fils_process_hlp_udp(struct hostapd_data *hapd,
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
const struct iphdr *iph;
const struct ip *iph;
const struct udphdr *udph;
u16 sport, dport, ulen;
if (len < sizeof(*iph) + sizeof(*udph))
return 0;
iph = (const struct iphdr *) pos;
iph = (const struct ip *) pos;
udph = (const struct udphdr *) (iph + 1);
sport = ntohs(udph->uh_sport);
dport = ntohs(udph->uh_dport);
@ -510,24 +510,24 @@ static int fils_process_hlp_ip(struct hostapd_data *hapd,
struct sta_info *sta, const u8 *dst,
const u8 *pos, size_t len)
{
const struct iphdr *iph;
u16 tot_len;
const struct ip *iph;
uint16_t ip_len;
if (len < sizeof(*iph))
return 0;
iph = (const struct iphdr *) pos;
iph = (const struct ip *) pos;
if (ip_checksum(iph, sizeof(*iph)) != 0) {
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4 packet had invalid header checksum - dropped");
return 0;
}
tot_len = ntohs(iph->tot_len);
if (tot_len > len)
ip_len = ntohs(iph->ip_len);
if (ip_len > len)
return 0;
wpa_printf(MSG_DEBUG,
"FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
iph->saddr, iph->daddr, iph->protocol);
switch (iph->protocol) {
iph->ip_src.s_addr, iph->ip_dst.s_addr, iph->ip_p);
switch (iph->ip_p) {
case 17:
return fils_process_hlp_udp(hapd, sta, dst, pos, len);
}

View file

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

View file

@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
* Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2021, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/crc32.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "common/hw_features_common.h"
@ -28,7 +29,6 @@
#include "accounting.h"
#include "ap_list.h"
#include "beacon.h"
#include "iapp.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
#include "vlan_init.h"
@ -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 */
}
@ -101,7 +107,8 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
return;
if (hapd->conf->wmm_enabled < 0)
hapd->conf->wmm_enabled = hapd->iconf->ieee80211n;
hapd->conf->wmm_enabled = hapd->iconf->ieee80211n |
hapd->iconf->ieee80211ax;
#ifndef CONFIG_NO_RADIUS
radius_client_reconfig(hapd->radius, hapd->conf->radius);
@ -142,7 +149,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 +179,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 +295,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)
{
@ -292,26 +305,24 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
if (!ifname || !hapd->drv_priv)
return;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
0, NULL, 0, NULL, 0)) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0,
0, NULL, 0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear default "
"encryption keys (ifname=%s keyidx=%d)",
ifname, i);
}
}
#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w) {
for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
NULL, i, 0, NULL,
0, NULL, 0)) {
NULL, i, 0, 0, NULL,
0, NULL, 0, KEY_FLAG_GROUP)) {
wpa_printf(MSG_DEBUG, "Failed to clear "
"default mgmt encryption keys "
"(ifname=%s keyidx=%d)", ifname, i);
}
}
}
#endif /* CONFIG_IEEE80211W */
}
@ -328,11 +339,12 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
struct hostapd_ssid *ssid = &hapd->conf->ssid;
idx = ssid->wep.idx;
if (ssid->wep.default_len &&
if (ssid->wep.default_len && ssid->wep.key[idx] &&
hostapd_drv_set_key(hapd->conf->iface,
hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0,
1, NULL, 0, ssid->wep.key[idx],
ssid->wep.len[idx])) {
ssid->wep.len[idx],
KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
errors++;
}
@ -340,8 +352,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;
@ -363,8 +377,6 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
hapd->beacon_set_done = 0;
wpa_printf(MSG_DEBUG, "%s(%s)", __func__, hapd->conf->iface);
iapp_deinit(hapd->iapp);
hapd->iapp = NULL;
accounting_deinit(hapd);
hostapd_deinit_wpa(hapd);
vlan_deinit(hapd);
@ -381,6 +393,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_DPP
hostapd_dpp_deinit(hapd);
gas_query_ap_deinit(hapd->gas);
hapd->gas = NULL;
#endif /* CONFIG_DPP */
authsrv_deinit(hapd);
@ -403,6 +416,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
}
wpabuf_free(hapd->time_adv);
hapd->time_adv = NULL;
#ifdef CONFIG_INTERWORKING
gas_serv_deinit(hapd);
@ -418,16 +432,23 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
hapd->tmp_eap_user.identity_len);
bin_clear_free(hapd->tmp_eap_user.password,
hapd->tmp_eap_user.password_len);
os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
#endif /* CONFIG_SQLITE */
#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;
@ -481,14 +502,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);
@ -529,6 +548,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) {
@ -557,10 +578,13 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
for (i = 0; i < 4; i++) {
if (hapd->conf->ssid.wep.key[i] &&
hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 0,
i == hapd->conf->ssid.wep.idx, NULL, 0,
hapd->conf->ssid.wep.key[i],
hapd->conf->ssid.wep.len[i])) {
hapd->conf->ssid.wep.len[i],
i == hapd->conf->ssid.wep.idx ?
KEY_FLAG_GROUP_RX_TX_DEFAULT :
KEY_FLAG_GROUP_RX_TX)) {
wpa_printf(MSG_WARNING, "Could not set WEP "
"encryption.");
return -1;
@ -573,6 +597,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 +630,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 */
}
@ -1146,7 +1174,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
}
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;
conf->wmm_enabled = hapd->iconf->ieee80211n |
hapd->iconf->ieee80211ax;
#ifdef CONFIG_IEEE80211R_AP
if (is_zero_ether_addr(conf->r1_key_holder))
@ -1159,13 +1188,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,
@ -1195,8 +1226,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
}
/*
* Short SSID calculation is identical to FCS and it is defined in
* IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID).
*/
conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len);
if (!hostapd_drv_none(hapd)) {
wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR
" and ssid \"%s\"",
conf->iface, MAC2STR(hapd->own_addr),
wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len));
@ -1298,13 +1335,6 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
if (conf->ieee802_11f &&
(hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) {
wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
"failed.");
return -1;
}
#ifdef CONFIG_INTERWORKING
if (gas_serv_init(hapd)) {
wpa_printf(MSG_ERROR, "GAS server initialization failed");
@ -1352,6 +1382,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;
@ -1584,6 +1629,71 @@ static int setup_interface(struct hostapd_iface *iface)
}
static int configured_fixed_chan_to_freq(struct hostapd_iface *iface)
{
int freq, i, j;
if (!iface->conf->channel)
return 0;
if (iface->conf->op_class) {
freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
iface->conf->channel);
if (freq < 0) {
wpa_printf(MSG_INFO,
"Could not convert op_class %u channel %u to operating frequency",
iface->conf->op_class, iface->conf->channel);
return -1;
}
iface->freq = freq;
return 0;
}
/* Old configurations using only 2.4/5/60 GHz bands may not specify the
* op_class parameter. Select a matching channel from the configured
* mode using the channel parameter for these cases.
*/
for (j = 0; j < iface->num_hw_features; j++) {
struct hostapd_hw_modes *mode = &iface->hw_features[j];
if (iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
iface->conf->hw_mode != mode->mode)
continue;
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
if (chan->chan == iface->conf->channel &&
!is_6ghz_freq(chan->freq)) {
iface->freq = chan->freq;
return 0;
}
}
}
wpa_printf(MSG_INFO, "Could not determine operating frequency");
return -1;
}
static void hostapd_set_6ghz_sec_chan(struct hostapd_iface *iface)
{
int bw, seg0;
if (!is_6ghz_op_class(iface->conf->op_class))
return;
seg0 = hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
bw = center_idx_to_bw_6ghz(seg0);
/* Assign the secondary channel if absent in config for
* bandwidths > 20 MHz */
if (bw > 20 && !iface->conf->secondary_channel) {
if (((iface->conf->channel - 1) / 4) % 2)
iface->conf->secondary_channel = -1;
else
iface->conf->secondary_channel = 1;
}
}
static int setup_interface2(struct hostapd_iface *iface)
{
iface->wait_channel_update = 0;
@ -1592,7 +1702,21 @@ static int setup_interface2(struct hostapd_iface *iface)
/* Not all drivers support this yet, so continue without hw
* feature data. */
} else {
int ret = hostapd_select_hw_mode(iface);
int ret;
ret = configured_fixed_chan_to_freq(iface);
if (ret < 0)
goto fail;
if (iface->conf->op_class) {
int ch_width;
ch_width = op_class_to_ch_width(iface->conf->op_class);
hostapd_set_oper_chwidth(iface->conf, ch_width);
hostapd_set_6ghz_sec_chan(iface);
}
ret = hostapd_select_hw_mode(iface);
if (ret < 0) {
wpa_printf(MSG_ERROR, "Could not select hw_mode and "
"channel. (%d)", ret);
@ -1602,6 +1726,12 @@ static int setup_interface2(struct hostapd_iface *iface)
wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
return 0;
}
ret = hostapd_check_edmg_capab(iface);
if (ret < 0)
goto fail;
ret = hostapd_check_he_6ghz_capab(iface);
if (ret < 0)
goto fail;
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
goto fail;
@ -1694,7 +1824,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;
@ -1716,7 +1846,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;
@ -1728,7 +1858,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);
}
@ -1816,6 +1946,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;
@ -1873,12 +2010,11 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
goto fail;
wpa_printf(MSG_DEBUG, "Completing interface initialization");
if (iface->conf->channel) {
if (iface->freq) {
#ifdef NEED_AP_MLME
int res;
#endif /* NEED_AP_MLME */
iface->freq = hostapd_hw_get_freq(hapd, iface->conf->channel);
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
"Frequency: %d MHz",
hostapd_hw_mode_txt(iface->conf->hw_mode),
@ -1926,6 +2062,8 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
if (!delay_apply_cfg &&
hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
hapd->iconf->enable_edmg,
hapd->iconf->edmg_channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
hapd->iconf->ieee80211ax,
@ -2049,6 +2187,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)
@ -2189,10 +2334,12 @@ int hostapd_setup_interface(struct hostapd_iface *iface)
{
int ret;
if (!iface->conf)
return -1;
ret = setup_interface(iface);
if (ret) {
wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
iface->bss[0]->conf->iface);
iface->conf->bss[0]->iface);
return -1;
}
@ -2288,12 +2435,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 */
}
@ -2576,6 +2721,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);
@ -2637,6 +2788,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);
@ -3057,10 +3211,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);
/* IEEE 802.11F (IAPP) */
if (hapd->conf->ieee802_11f)
iapp_new_station(hapd->iapp, sta);
sta->post_csa_sa_query = 0;
#ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
@ -3298,7 +3449,8 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
if (old_params &&
hostapd_set_freq_params(old_params, conf->hw_mode,
hostapd_hw_get_freq(hapd, conf->channel),
conf->channel, conf->ieee80211n,
conf->channel, conf->enable_edmg,
conf->edmg_channel, conf->ieee80211n,
conf->ieee80211ac, conf->ieee80211ax,
conf->secondary_channel,
hostapd_get_oper_chwidth(conf),
@ -3436,15 +3588,23 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
}
void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
void hostapd_chan_switch_config(struct hostapd_data *hapd,
struct hostapd_freq_params *freq_params)
{
if (vht_enabled)
if (freq_params->he_enabled)
hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED;
else
hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_DISABLED;
if (freq_params->vht_enabled)
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
else
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
HOSTAPD_LEVEL_INFO,
"CHAN_SWITCH HE config 0x%x VHT config 0x%x",
hapd->iconf->ch_switch_he_config,
hapd->iconf->ch_switch_vht_config);
}
@ -3571,3 +3731,25 @@ void hostapd_periodic_iface(struct hostapd_iface *iface)
#endif /* CONFIG_NO_RADIUS */
}
}
#ifdef CONFIG_OCV
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta;
wpa_printf(MSG_DEBUG, "OCV: Post-CSA SA Query initiation check");
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (!sta->post_csa_sa_query)
continue;
wpa_printf(MSG_DEBUG, "OCV: OCVC STA " MACSTR
" did not start SA Query after CSA - disconnect",
MAC2STR(sta->addr));
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
}
}
#endif /* CONFIG_OCV */

View file

@ -38,6 +38,10 @@ union wps_event_data;
struct mesh_conf;
#endif /* CONFIG_MESH */
#ifdef CONFIG_CTRL_IFACE_UDP
#define CTRL_IFACE_COOKIE_LEN 8
#endif /* CONFIG_CTRL_IFACE_UDP */
struct hostapd_iface;
struct hapd_interfaces {
@ -72,6 +76,11 @@ struct hapd_interfaces {
#ifdef CONFIG_DPP
struct dpp_global *dpp;
#endif /* CONFIG_DPP */
#ifdef CONFIG_CTRL_IFACE_UDP
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
};
enum hostapd_chan_status {
@ -179,13 +188,12 @@ struct hostapd_data {
u64 acct_session_id;
struct radius_das_data *radius_das;
struct iapp_data *iapp;
struct hostapd_cached_radius_acl *acl_cache;
struct hostapd_acl_query_data *acl_queries;
struct wpa_authenticator *wpa_auth;
struct eapol_authenticator *eapol_auth;
struct eap_config *eap_cfg;
struct rsn_preauth_interface *preauth_iface;
struct os_reltime michael_mic_failure;
@ -318,10 +326,10 @@ struct hostapd_data {
#ifdef CONFIG_SAE
/** Key used for generating SAE anti-clogging tokens */
u8 sae_token_key[8];
struct os_reltime last_sae_token_key_update;
u16 sae_token_idx;
u16 sae_pending_token_idx[256];
u8 comeback_key[8];
struct os_reltime last_comeback_key_update;
u16 comeback_idx;
u16 comeback_pending_idx[256];
int dot11RSNASAERetransPeriod; /* msec */
struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
#endif /* CONFIG_SAE */
@ -337,12 +345,17 @@ struct hostapd_data {
u8 last_gtk[WPA_GTK_MAX_LEN];
size_t last_gtk_len;
#ifdef CONFIG_IEEE80211W
enum wpa_alg last_igtk_alg;
int last_igtk_key_idx;
u8 last_igtk[WPA_IGTK_MAX_LEN];
size_t last_igtk_len;
#endif /* CONFIG_IEEE80211W */
enum wpa_alg last_bigtk_alg;
int last_bigtk_key_idx;
u8 last_bigtk[WPA_BIGTK_MAX_LEN];
size_t last_bigtk_len;
bool force_backlog_bytes;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_MBO
@ -359,6 +372,8 @@ struct hostapd_data {
int dhcp_sock; /* UDP socket used with the DHCP server */
struct ptksa_cache *ptksa;
#ifdef CONFIG_DPP
int dpp_init_done;
struct dpp_authentication *dpp_auth;
@ -380,6 +395,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;
@ -398,6 +423,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 */
};
@ -465,9 +494,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
@ -566,6 +593,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 */
@ -594,13 +624,17 @@ 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);
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
int hostapd_csa_in_progress(struct hostapd_iface *iface);
void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
void hostapd_chan_switch_config(struct hostapd_data *hapd,
struct hostapd_freq_params *freq_params);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
void
@ -609,6 +643,7 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
void hostapd_periodic_iface(struct hostapd_iface *iface);
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,

View file

@ -80,15 +80,15 @@ u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_OCV
if (hapd->conf->ocv)
if (hapd->conf->ocv &&
(hapd->iface->drv_flags2 &
(WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
capab |= WPA_CAPABILITY_OCVC;
#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);

View file

@ -224,16 +224,27 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
}
#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
int pri_chan, sec_chan;
int pri_freq, sec_freq;
struct hostapd_channel_data *p_chan, *s_chan;
pri_chan = iface->conf->channel;
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
pri_freq = iface->freq;
sec_freq = pri_freq + iface->conf->secondary_channel * 20;
return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
sec_chan);
if (!iface->current_mode)
return 0;
p_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq, NULL,
iface->hw_features,
iface->num_hw_features);
s_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq, NULL,
iface->hw_features,
iface->num_hw_features);
return allowed_ht40_channel_pair(iface->current_mode->mode,
p_chan, s_chan);
}
@ -241,9 +252,11 @@ static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
{
if (iface->conf->secondary_channel > 0) {
iface->conf->channel += 4;
iface->freq += 20;
iface->conf->secondary_channel = -1;
} else {
iface->conf->channel -= 4;
iface->freq -= 20;
iface->conf->secondary_channel = 1;
}
}
@ -252,13 +265,23 @@ static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
int pri_chan, sec_chan;
unsigned int pri_freq, sec_freq;
int res;
struct hostapd_channel_data *pri_chan, *sec_chan;
pri_chan = iface->conf->channel;
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
pri_freq = iface->freq;
sec_freq = pri_freq + iface->conf->secondary_channel * 20;
res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
if (!iface->current_mode)
return 0;
pri_chan = hw_get_channel_freq(iface->current_mode->mode, pri_freq,
NULL, iface->hw_features,
iface->num_hw_features);
sec_chan = hw_get_channel_freq(iface->current_mode->mode, sec_freq,
NULL, iface->hw_features,
iface->num_hw_features);
res = check_40mhz_5g(scan_res, pri_chan, sec_chan);
if (res == 2) {
if (iface->conf->no_pri_sec_switch) {
@ -290,7 +313,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
{
struct wpa_scan_results *scan_res;
int oper40;
int res;
int res = 0;
/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
* allowed per IEEE Std 802.11-2012, 10.15.3.2 */
@ -326,7 +349,24 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
}
}
res = ieee80211n_allowed_ht40_channel_pair(iface);
#ifdef CONFIG_IEEE80211AX
if (iface->conf->secondary_channel &&
iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
iface->conf->ieee80211ax) {
struct he_capabilities *he_cap;
he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
wpa_printf(MSG_DEBUG,
"HE: 40 MHz channel width is not supported in 2.4 GHz; clear secondary channel configuration");
iface->conf->secondary_channel = 0;
}
}
#endif /* CONFIG_IEEE80211AX */
if (iface->conf->secondary_channel)
res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
@ -352,7 +392,7 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
if (iface->current_mode == NULL)
return;
pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
pri_freq = iface->freq;
if (iface->conf->secondary_channel > 0)
sec_freq = pri_freq + 20;
else
@ -397,7 +437,7 @@ static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
if (iface->current_mode == NULL)
return;
pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
pri_freq = iface->freq;
if (iface->conf->secondary_channel > 0) {
affected_start = pri_freq - 10;
affected_end = pri_freq + 30;
@ -537,26 +577,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
switch (conf & HT_CAP_INFO_SMPS_MASK) {
case HT_CAP_INFO_SMPS_STATIC:
if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
wpa_printf(MSG_ERROR,
"Driver does not support configured HT capability [SMPS-STATIC]");
return 0;
}
break;
case HT_CAP_INFO_SMPS_DYNAMIC:
if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
wpa_printf(MSG_ERROR,
"Driver does not support configured HT capability [SMPS-DYNAMIC]");
return 0;
}
break;
case HT_CAP_INFO_SMPS_DISABLED:
default:
break;
}
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
!(hw & HT_CAP_INFO_GREEN_FIELD)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
@ -663,13 +683,13 @@ static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface)
}
#endif /* CONFIG_IEEE80211AX */
#endif /* CONFIG_IEEE80211N */
int hostapd_check_ht_capab(struct hostapd_iface *iface)
{
#ifdef CONFIG_IEEE80211N
int ret;
if (is_6ghz_freq(iface->freq))
return 0;
if (!iface->conf->ieee80211n)
return 0;
@ -698,21 +718,92 @@ 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;
}
int hostapd_check_edmg_capab(struct hostapd_iface *iface)
{
struct hostapd_hw_modes *mode = iface->hw_features;
struct ieee80211_edmg_config edmg;
if (!iface->conf->enable_edmg)
return 0;
hostapd_encode_edmg_chan(iface->conf->enable_edmg,
iface->conf->edmg_channel,
iface->conf->channel,
&edmg);
if (mode->edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
return 0;
wpa_printf(MSG_WARNING, "Requested EDMG configuration is not valid");
wpa_printf(MSG_INFO, "EDMG capab: channels 0x%x, bw_config %d",
mode->edmg.channels, mode->edmg.bw_config);
wpa_printf(MSG_INFO,
"Requested EDMG configuration: channels 0x%x, bw_config %d",
edmg.channels, edmg.bw_config);
return -1;
}
int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
{
#ifdef CONFIG_IEEE80211AX
struct he_capabilities *he_cap;
u16 hw;
if (!iface->current_mode || !is_6ghz_freq(iface->freq))
return 0;
he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
hw = he_cap->he_6ghz_capa;
if (iface->conf->he_6ghz_max_mpdu >
((hw & HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK) >>
HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT)) {
wpa_printf(MSG_ERROR,
"The driver does not support the configured HE 6 GHz Max MPDU length");
return -1;
}
if (iface->conf->he_6ghz_max_ampdu_len_exp >
((hw & HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK) >>
HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT)) {
wpa_printf(MSG_ERROR,
"The driver does not support the configured HE 6 GHz Max AMPDU Length Exponent");
return -1;
}
if (iface->conf->he_6ghz_rx_ant_pat &&
!(hw & HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS)) {
wpa_printf(MSG_ERROR,
"The driver does not support the configured HE 6 GHz Rx Antenna Pattern");
return -1;
}
if (iface->conf->he_6ghz_tx_ant_pat &&
!(hw & HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS)) {
wpa_printf(MSG_ERROR,
"The driver does not support the configured HE 6 GHz Tx Antenna Pattern");
return -1;
}
#endif /* CONFIG_IEEE80211AX */
return 0;
}
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int channel, int primary)
int frequency, int primary)
{
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
chan = hw_get_channel_freq(iface->current_mode->mode, frequency, NULL,
iface->hw_features, iface->num_hw_features);
if (!chan)
return 0;
@ -721,8 +812,8 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
return 1;
wpa_printf(MSG_INFO,
"Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
channel, primary ? "primary" : "secondary",
"Frequency %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
frequency, primary ? "primary" : "secondary",
chan->flag,
chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
@ -730,37 +821,123 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
}
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
{
int secondary_chan;
int i, contiguous = 0;
int num_of_enabled = 0;
int max_contiguous = 0;
struct ieee80211_edmg_config edmg;
struct hostapd_channel_data *pri_chan;
pri_chan = hw_get_channel_chan(iface->current_mode,
iface->conf->channel, NULL);
if (!pri_chan)
if (!iface->conf->enable_edmg)
return 1;
if (!iface->current_mode)
return 0;
pri_chan = hw_get_channel_freq(iface->current_mode->mode,
iface->freq, NULL,
iface->hw_features,
iface->num_hw_features);
hostapd_encode_edmg_chan(iface->conf->enable_edmg,
iface->conf->edmg_channel,
pri_chan->chan,
&edmg);
if (!(edmg.channels & BIT(pri_chan->chan - 1)))
return 0;
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
/* 60 GHz channels 1..6 */
for (i = 0; i < 6; i++) {
int freq = 56160 + 2160 * (i + 1);
if (edmg.channels & BIT(i)) {
contiguous++;
num_of_enabled++;
} else {
contiguous = 0;
continue;
}
/* P802.11ay defines that the total number of subfields
* set to one does not exceed 4.
*/
if (num_of_enabled > 4)
return 0;
if (!hostapd_is_usable_chan(iface, freq, 1))
return 0;
if (contiguous > max_contiguous)
max_contiguous = contiguous;
}
/* Check if the EDMG configuration is valid under the limitations
* of P802.11ay.
*/
/* check bw_config against contiguous EDMG channels */
switch (edmg.bw_config) {
case EDMG_BW_CONFIG_4:
if (!max_contiguous)
return 0;
break;
case EDMG_BW_CONFIG_5:
if (max_contiguous < 2)
return 0;
break;
default:
return 0;
}
return 1;
}
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
int secondary_freq;
struct hostapd_channel_data *pri_chan;
if (!iface->current_mode)
return 0;
pri_chan = hw_get_channel_freq(iface->current_mode->mode,
iface->freq, NULL,
iface->hw_features,
iface->num_hw_features);
if (!pri_chan) {
wpa_printf(MSG_ERROR, "Primary frequency not present");
return 0;
}
if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) {
wpa_printf(MSG_ERROR, "Primary frequency not allowed");
return 0;
}
if (!hostapd_is_usable_edmg(iface))
return 0;
if (!iface->conf->secondary_channel)
return 1;
if (hostapd_is_usable_chan(iface, iface->freq +
iface->conf->secondary_channel * 20, 0)) {
if (iface->conf->secondary_channel == 1 &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))
return 1;
if (iface->conf->secondary_channel == -1 &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))
return 1;
}
if (!iface->conf->ht40_plus_minus_allowed)
return hostapd_is_usable_chan(
iface, iface->conf->channel +
iface->conf->secondary_channel * 4, 0);
return 0;
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
secondary_chan = iface->conf->channel + 4;
if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
secondary_freq = iface->freq + 20;
if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
iface->conf->secondary_channel = 1;
return 1;
}
secondary_chan = iface->conf->channel - 4;
if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
secondary_freq = iface->freq - 20;
if (hostapd_is_usable_chan(iface, secondary_freq, 0) &&
(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
iface->conf->secondary_channel = -1;
return 1;
@ -770,10 +947,43 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
}
static void hostapd_determine_mode(struct hostapd_iface *iface)
{
int i;
enum hostapd_hw_mode target_mode;
if (iface->current_mode ||
iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY)
return;
if (iface->freq < 4000)
target_mode = HOSTAPD_MODE_IEEE80211G;
else if (iface->freq > 50000)
target_mode = HOSTAPD_MODE_IEEE80211AD;
else
target_mode = HOSTAPD_MODE_IEEE80211A;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode;
mode = &iface->hw_features[i];
if (mode->mode == target_mode) {
iface->current_mode = mode;
iface->conf->hw_mode = mode->mode;
break;
}
}
if (!iface->current_mode)
wpa_printf(MSG_ERROR, "ACS: Cannot decide mode");
}
static enum hostapd_chan_status
hostapd_check_chans(struct hostapd_iface *iface)
{
if (iface->conf->channel) {
if (iface->freq) {
hostapd_determine_mode(iface);
if (hostapd_is_usable_chans(iface))
return HOSTAPD_CHAN_VALID;
else
@ -807,9 +1017,9 @@ static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Configured channel (%d) not found from the "
"channel list of current mode (%d) %s",
"Configured channel (%d) or frequency (%d) (secondary_channel=%d) not found from the channel list of the current mode (%d) %s",
iface->conf->channel,
iface->freq, iface->conf->secondary_channel,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
@ -829,9 +1039,7 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err)
case HOSTAPD_CHAN_VALID:
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO,
ACS_EVENT_COMPLETED "freq=%d channel=%d",
hostapd_hw_get_freq(iface->bss[0],
iface->conf->channel),
iface->conf->channel);
iface->freq, iface->conf->channel);
break;
case HOSTAPD_CHAN_ACS:
wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
@ -889,16 +1097,28 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
int chan;
if (mode->mode == iface->conf->hw_mode) {
if (iface->freq > 0 &&
!hw_mode_get_channel(mode, iface->freq, &chan))
continue;
iface->current_mode = mode;
break;
}
}
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,
@ -952,7 +1172,9 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
struct hostapd_hw_modes *mode;
if (hapd->iface->current_mode) {
channel = hw_get_chan(hapd->iface->current_mode, freq);
channel = hw_get_chan(hapd->iface->current_mode->mode, freq,
hapd->iface->hw_features,
hapd->iface->num_hw_features);
if (channel)
return channel;
}
@ -963,9 +1185,28 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
return 0;
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
channel = hw_get_chan(mode, freq);
channel = hw_get_chan(mode->mode, freq,
hapd->iface->hw_features,
hapd->iface->num_hw_features);
if (channel)
return channel;
}
return 0;
}
int hostapd_hw_skip_mode(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
int i;
if (iface->current_mode)
return mode != iface->current_mode;
if (mode->mode != HOSTAPD_MODE_IEEE80211B)
return 0;
for (i = 0; i < iface->num_hw_features; i++) {
if (iface->hw_features[i].mode == HOSTAPD_MODE_IEEE80211G)
return 1;
}
return 0;
}

View file

@ -21,9 +21,13 @@ const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_check_edmg_capab(struct hostapd_iface *iface);
int hostapd_check_he_6ghz_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,
@ -48,7 +52,7 @@ static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
static inline const char * hostapd_hw_mode_txt(int mode)
{
return NULL;
return "UNKNOWN";
}
static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
@ -61,6 +65,11 @@ static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0;
}
static inline int hostapd_check_edmg_capab(struct hostapd_iface *iface)
{
return 0;
}
static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
@ -71,6 +80,17 @@ 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;
}
static inline int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
{
return 0;
}
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */

File diff suppressed because it is too large Load diff

View file

@ -16,8 +16,7 @@ struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
struct vlan_description;
struct hostapd_sta_wpa_psk_short;
struct radius_sta;
enum ieee80211_op_mode;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
@ -50,9 +49,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
size_t len);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
@ -63,6 +63,7 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
@ -95,6 +96,10 @@ u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
enum ieee80211_op_mode opmode, const u8 *he_capab,
size_t he_capab_len);
u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *he_6ghz_capab);
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
enum ieee80211_op_mode mode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@ -162,7 +167,7 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
const u8 *msk, size_t msk_len);
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *owe_dh, u8 owe_dh_len,
u8 *owe_buf, size_t owe_buf_len, u16 *reason);
u8 *owe_buf, size_t owe_buf_len, u16 *status);
u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *rsn_ie, size_t rsn_ie_len,
const u8 *owe_dh, size_t owe_dh_len);
@ -180,17 +185,14 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval,
struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui,
int is_probe_req);
size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd);
u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len);
int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
#endif /* IEEE802_11_H */

View file

@ -32,12 +32,7 @@ struct hostapd_cached_radius_acl {
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
u32 session_timeout;
u32 acct_interim_interval;
struct vlan_description vlan_id;
struct hostapd_sta_wpa_psk_short *psk;
char *identity;
char *radius_cui;
struct radius_sta info;
};
@ -54,9 +49,9 @@ struct hostapd_acl_query_data {
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
{
os_free(e->identity);
os_free(e->radius_cui);
hostapd_free_psk_list(e->psk);
os_free(e->info.identity);
os_free(e->info.radius_cui);
hostapd_free_psk_list(e->info.psk);
os_free(e);
}
@ -73,25 +68,8 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
}
static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
struct hostapd_sta_wpa_psk_short *src)
{
if (!psk)
return;
if (src)
src->ref++;
*psk = src;
}
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
u32 *acct_interim_interval,
struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui)
struct radius_sta *out)
{
struct hostapd_cached_radius_acl *entry;
struct os_reltime now;
@ -105,27 +83,8 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
if (os_reltime_expired(&now, &entry->timestamp,
RADIUS_ACL_TIMEOUT))
return -1; /* entry has expired */
if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
if (session_timeout)
*session_timeout = entry->session_timeout;
if (acct_interim_interval)
*acct_interim_interval =
entry->acct_interim_interval;
if (vlan_id)
*vlan_id = entry->vlan_id;
copy_psk_list(psk, entry->psk);
if (identity) {
if (entry->identity)
*identity = os_strdup(entry->identity);
else
*identity = NULL;
}
if (radius_cui) {
if (entry->radius_cui)
*radius_cui = os_strdup(entry->radius_cui);
else
*radius_cui = NULL;
}
*out = entry->info;
return entry->accepted;
}
@ -238,42 +197,28 @@ int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
* @addr: MAC address of the STA
* @msg: Authentication message
* @len: Length of msg in octets
* @session_timeout: Buffer for returning session timeout (from RADIUS)
* @acct_interim_interval: Buffer for returning account interval (from RADIUS)
* @vlan_id: Buffer for returning VLAN ID
* @psk: Linked list buffer for returning WPA PSK
* @identity: Buffer for returning identity (from RADIUS)
* @radius_cui: Buffer for returning CUI (from RADIUS)
* @out.session_timeout: Buffer for returning session timeout (from RADIUS)
* @out.acct_interim_interval: Buffer for returning account interval (from
* RADIUS)
* @out.vlan_id: Buffer for returning VLAN ID
* @out.psk: Linked list buffer for returning WPA PSK
* @out.identity: Buffer for returning identity (from RADIUS)
* @out.radius_cui: Buffer for returning CUI (from RADIUS)
* @is_probe_req: Whether this query for a Probe Request frame
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*
* The caller is responsible for freeing the returned *identity and *radius_cui
* values with os_free().
* The caller is responsible for properly cloning the returned out->identity and
* out->radius_cui and out->psk values.
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval,
struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui,
const u8 *msg, size_t len, struct radius_sta *out,
int is_probe_req)
{
int res;
if (session_timeout)
*session_timeout = 0;
if (acct_interim_interval)
*acct_interim_interval = 0;
if (vlan_id)
os_memset(vlan_id, 0, sizeof(*vlan_id));
if (psk)
*psk = NULL;
if (identity)
*identity = NULL;
if (radius_cui)
*radius_cui = NULL;
os_memset(out, 0, sizeof(*out));
res = hostapd_check_acl(hapd, addr, vlan_id);
res = hostapd_check_acl(hapd, addr, &out->vlan_id);
if (res != HOSTAPD_ACL_PENDING)
return res;
@ -290,12 +235,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
};
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
vlan_id = NULL;
os_memset(&out->vlan_id, 0, sizeof(out->vlan_id));
/* Check whether ACL cache has an entry for this station */
res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval, vlan_id, psk,
identity, radius_cui);
res = hostapd_acl_cache_get(hapd, addr, out);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@ -307,14 +250,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
if (identity) {
os_free(*identity);
*identity = NULL;
}
if (radius_cui) {
os_free(*radius_cui);
*radius_cui = NULL;
}
return HOSTAPD_ACL_PENDING;
}
query = query->next;
@ -488,8 +423,8 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
passphraselen);
psk->is_passphrase = 1;
}
psk->next = cache->psk;
cache->psk = psk;
psk->next = cache->info.psk;
cache->info.psk = psk;
psk = NULL;
}
skip:
@ -518,6 +453,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_data *hapd = data;
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_sta *info;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
query = hapd->acl_queries;
@ -555,65 +491,66 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
}
os_get_reltime(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
info = &cache->info;
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
u8 *buf;
size_t len;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
&cache->session_timeout) == 0)
&info->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
else
cache->accepted = HOSTAPD_ACL_ACCEPT;
if (radius_msg_get_attr_int32(
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
&cache->acct_interim_interval) == 0 &&
cache->acct_interim_interval < 60) {
&info->acct_interim_interval) == 0 &&
info->acct_interim_interval < 60) {
wpa_printf(MSG_DEBUG, "Ignored too small "
"Acct-Interim-Interval %d for STA " MACSTR,
cache->acct_interim_interval,
info->acct_interim_interval,
MAC2STR(query->addr));
cache->acct_interim_interval = 0;
info->acct_interim_interval = 0;
}
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
cache->vlan_id.notempty = !!radius_msg_get_vlanid(
msg, &cache->vlan_id.untagged,
MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
info->vlan_id.notempty = !!radius_msg_get_vlanid(
msg, &info->vlan_id.untagged,
MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
&buf, &len, NULL) == 0) {
cache->identity = os_zalloc(len + 1);
if (cache->identity)
os_memcpy(cache->identity, buf, len);
info->identity = os_zalloc(len + 1);
if (info->identity)
os_memcpy(info->identity, buf, len);
}
if (radius_msg_get_attr_ptr(
msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
cache->radius_cui = os_zalloc(len + 1);
if (cache->radius_cui)
os_memcpy(cache->radius_cui, buf, len);
info->radius_cui = os_zalloc(len + 1);
if (info->radius_cui)
os_memcpy(info->radius_cui, buf, len);
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
!cache->psk)
!info->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
if (cache->vlan_id.notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
if (info->vlan_id.notempty &&
!hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) {
hostapd_logger(hapd, query->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN %d%s received from RADIUS server",
cache->vlan_id.untagged,
cache->vlan_id.tagged[0] ? "+" : "");
os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
info->vlan_id.untagged,
info->vlan_id.tagged[0] ? "+" : "");
os_memset(&info->vlan_id, 0, sizeof(info->vlan_id));
}
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
!cache->vlan_id.notempty)
!info->vlan_id.notempty)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
@ -622,7 +559,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
#ifdef CONFIG_DRIVER_RADIUS_ACL
hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
cache->session_timeout);
info->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
/* Re-send original authentication frame for 802.11 processing */
@ -685,6 +622,19 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
}
void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
struct hostapd_sta_wpa_psk_short *src)
{
if (!psk)
return;
if (src)
src->ref++;
*psk = src;
}
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
{
if (psk && psk->ref) {

View file

@ -16,18 +16,25 @@ enum {
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
struct radius_sta {
u32 session_timeout;
u32 acct_interim_interval;
struct vlan_description vlan_id;
struct hostapd_sta_wpa_psk_short *psk;
char *identity;
char *radius_cui;
};
int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
struct vlan_description *vlan_id);
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval,
struct vlan_description *vlan_id,
struct hostapd_sta_wpa_psk_short **psk,
char **identity, char **radius_cui,
const u8 *msg, size_t len, struct radius_sta *out,
int is_probe_req);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
void hostapd_acl_expire(struct hostapd_data *hapd);
void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
struct hostapd_sta_wpa_psk_short *src);
#endif /* IEEE802_11_AUTH_H */

View file

@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "beacon.h"
@ -44,6 +45,41 @@ static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
}
static u8 ieee80211_he_mcs_set_size(const u8 *phy_cap_info)
{
u8 sz = 4;
if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
sz += 4;
if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
sz += 4;
return sz;
}
static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
{
struct ieee80211_he_capabilities *cap;
size_t cap_len;
cap = (struct ieee80211_he_capabilities *) buf;
cap_len = sizeof(*cap) - sizeof(cap->optional);
if (len < cap_len)
return 1;
cap_len += ieee80211_he_mcs_set_size(cap->he_phy_capab_info);
if (len < cap_len)
return 1;
cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
return len != cap_len;
}
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
enum ieee80211_op_mode opmode)
{
@ -51,12 +87,12 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
u8 *pos = eid;
u8 ie_size = 0, mcs_nss_size = 0, ppet_size = 0;
u8 ie_size = 0, mcs_nss_size = 4, ppet_size = 0;
if (!mode)
return eid;
ie_size = sizeof(struct ieee80211_he_capabilities);
ie_size = sizeof(*cap) - sizeof(cap->optional);
ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
mode->he_capab[opmode].phy_cap);
@ -74,7 +110,6 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
case CHANWIDTH_USE_HT:
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
mcs_nss_size += 4;
break;
}
@ -136,6 +171,9 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
if (!hapd->iface->current_mode)
return eid;
if (is_6ghz_op_class(hapd->iconf->op_class))
oper_size += 5;
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + oper_size;
*pos++ = WLAN_EID_EXT_HE_OPERATION;
@ -154,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 =
@ -164,9 +205,49 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
/* TODO: conditional MaxBSSID Indicator subfield */
oper->he_oper_params = host_to_le32(params);
pos += 6; /* skip the fixed part */
pos += oper_size;
if (is_6ghz_op_class(hapd->iconf->op_class)) {
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
if (!seg0)
seg0 = hapd->iconf->channel;
params |= HE_OPERATION_6GHZ_OPER_INFO;
/* 6 GHz Operation Information field
* IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element,
* Figure 9-788k
*/
*pos++ = hapd->iconf->channel; /* Primary Channel */
/* Control: Channel Width */
if (seg1)
*pos++ = 3;
else
*pos++ = center_idx_to_bw_6ghz(seg0);
/* Channel Center Freq Seg0/Seg1 */
if (hapd->iconf->he_oper_chwidth == 2) {
/*
* Seg 0 indicates the channel center frequency index of
* the 160 MHz channel.
*/
seg1 = seg0;
if (hapd->iconf->channel < seg0)
seg0 -= 8;
else
seg0 += 8;
}
*pos++ = seg0;
*pos++ = seg1;
/* Minimum Rate */
*pos++ = 6; /* TODO: what should be set here? */
}
oper->he_oper_params = host_to_le32(params);
return pos;
}
@ -238,6 +319,11 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
os_memcpy(spr_param,
hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
spr_param += 8;
os_memcpy(spr_param,
hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
pos += 18;
}
@ -245,6 +331,46 @@ 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_config *conf = hapd->iface->conf;
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 & HE_6GHZ_BAND_CAP_MIN_MPDU_START;
capab |= (conf->he_6ghz_max_ampdu_len_exp <<
HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT) &
HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK;
capab |= (conf->he_6ghz_max_mpdu <<
HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT) &
HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK;
capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
if (conf->he_6ghz_rx_ant_pat)
capab |= HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS;
if (conf->he_6ghz_tx_ant_pat)
capab |= HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS;
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,
@ -323,8 +449,10 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
enum ieee80211_op_mode opmode, const u8 *he_capab,
size_t he_capab_len)
{
if (!he_capab || !hapd->iconf->ieee80211ax ||
if (!he_capab || !(sta->flags & WLAN_STA_WMM) ||
!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)) {
sta->flags &= ~WLAN_STA_HE;
os_free(sta->he_capab);
@ -346,3 +474,46 @@ 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) &&
hapd->iface->conf->he_op.he_twt_responder;
}

View file

@ -27,7 +27,7 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
u8 *pos = eid;
if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
hapd->conf->disable_11n)
hapd->conf->disable_11n || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_CAP;
@ -84,7 +84,8 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_ht_operation *oper;
u8 *pos = eid;
if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n ||
is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_OPERATION;
@ -108,32 +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)
return eid;
if (hapd->cs_freq_params.sec_channel_offset == -1)
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
else if (hapd->cs_freq_params.sec_channel_offset == 1)
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
else
return eid;
*eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
*eid++ = 1;
*eid++ = sec_ch;
return eid;
}
/*
op_mode
Set to 0 (HT pure) under the followign conditions
Set to 0 (HT pure) under the following conditions
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
Set to 1 (HT non-member protection) if there may be non-HT STAs

View file

@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ocv.h"
#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_config.h"
@ -19,8 +20,6 @@
#include "ieee802_11.h"
#ifdef CONFIG_IEEE80211W
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid)
{
@ -74,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);
@ -114,7 +123,8 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0, NULL, 0, 0)
< 0)
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
os_free(mgmt);
@ -152,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);
@ -195,7 +215,8 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
end += oci_ie_len;
}
#endif /* CONFIG_OCV */
if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0, NULL, 0, 0)
< 0)
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
os_free(resp);
@ -220,6 +241,12 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
(unsigned long) len);
return;
}
if (is_multicast_ether_addr(mgmt->da)) {
wpa_printf(MSG_DEBUG,
"IEEE 802.11: Ignore group-addressed SA Query frame (A1=" MACSTR " A2=" MACSTR ")",
MAC2STR(mgmt->da), MAC2STR(mgmt->sa));
return;
}
sta = ap_get_sta(hapd, sa);
@ -254,14 +281,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;
}
@ -304,8 +338,6 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
ap_sta_stop_sa_query(hapd, sta);
}
#endif /* CONFIG_IEEE80211W */
static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
{
@ -379,6 +411,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
@ -394,6 +431,18 @@ 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 &&
(hapd->iface->drv_flags &
WPA_DRIVER_FLAGS_BEACON_PROTECTION))
*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;
}
}
@ -402,48 +451,10 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
u8 len = 0, i;
u8 len = EXT_CAPA_MAX_LEN, i;
if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
len = 5;
if (len < 4 && hapd->conf->interworking)
len = 4;
if (len < 3 && hapd->conf->wnm_sleep_mode)
len = 3;
if (len < 1 && hapd->iconf->obss_interval)
len = 1;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
if (len < 9 &&
(hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
len = 9;
#ifdef CONFIG_WNM_AP
if (len < 4)
len = 4;
#endif /* CONFIG_WNM_AP */
#ifdef CONFIG_HS20
if (hapd->conf->hs20 && len < 6)
len = 6;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
if (hapd->conf->mbo_enabled && len < 6)
len = 6;
#endif /* CONFIG_MBO */
#ifdef CONFIG_FILS
if ((!(hapd->conf->wpa & WPA_PROTO_RSN) ||
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
len = 10;
#endif /* CONFIG_FILS */
#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 < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
return eid;
*pos++ = WLAN_EID_EXT_CAPAB;
*pos++ = len;
@ -454,6 +465,11 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
*pos &= ~hapd->iface->extended_capa_mask[i];
*pos |= hapd->iface->extended_capa[i];
}
if (i < EXT_CAPA_MAX_LEN) {
*pos &= ~hapd->conf->ext_capa_mask[i];
*pos |= hapd->conf->ext_capa[i];
}
}
while (len > 0 && eid[1 + len] == 0) {
@ -854,6 +870,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)
@ -1000,3 +1045,51 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
return 0;
}
#endif /* CONFIG_OCV */
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
{
u8 *pos = eid;
bool sae_pk = false;
u16 capab = 0;
size_t flen;
if (!(hapd->conf->wpa & WPA_PROTO_RSN))
return eid;
#ifdef CONFIG_SAE_PK
sae_pk = hostapd_sae_pk_in_use(hapd->conf);
#endif /* CONFIG_SAE_PK */
if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
(hapd->conf->sae_pwe == 1 || hapd->conf->sae_pwe == 2 ||
hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk) &&
hapd->conf->sae_pwe != 3) {
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
#ifdef CONFIG_SAE_PK
if (sae_pk)
capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
#endif /* CONFIG_SAE_PK */
}
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
flen = (capab & 0xff00) ? 2 : 1;
if (len < 2 + flen || !capab)
return eid; /* no supported extended RSN capabilities */
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
*pos++ = WLAN_EID_RSNX;
*pos++ = flen;
*pos++ = capab & 0x00ff;
capab >>= 8;
if (capab)
*pos++ = capab;
return pos;
}

View file

@ -26,7 +26,7 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 *pos = eid;
if (!mode)
if (!mode || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
@ -76,6 +76,9 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
if (is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
@ -164,176 +167,11 @@ 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;
struct hostapd_config *iconf = iface->conf;
struct hostapd_hw_modes *mode = iface->current_mode;
struct hostapd_channel_data *chan;
int dfs, i;
u8 channel, tx_pwr_count, local_pwr_constraint;
int max_tx_power;
u8 tx_pwr;
if (!mode)
return eid;
if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
return eid;
for (i = 0; i < mode->num_channels; i++) {
if (mode->channels[i].freq == iface->freq)
break;
}
if (i == mode->num_channels)
return eid;
switch (iface->conf->vht_oper_chwidth) {
case CHANWIDTH_USE_HT:
if (iconf->secondary_channel == 0) {
/* Max Transmit Power count = 0 (20 MHz) */
tx_pwr_count = 0;
} else {
/* Max Transmit Power count = 1 (20, 40 MHz) */
tx_pwr_count = 1;
}
break;
case CHANWIDTH_80MHZ:
/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
tx_pwr_count = 2;
break;
case CHANWIDTH_80P80MHZ:
case CHANWIDTH_160MHZ:
/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
tx_pwr_count = 3;
break;
default:
return eid;
}
/*
* Below local_pwr_constraint logic is referred from
* hostapd_eid_pwr_constraint.
*
* Check if DFS is required by regulatory.
*/
dfs = hostapd_is_dfs_required(hapd->iface);
if (dfs < 0)
dfs = 0;
/*
* In order to meet regulations when TPC is not implemented using
* a transmit power that is below the legal maximum (including any
* mitigation factor) should help. In this case, indicate 3 dB below
* maximum allowed transmit power.
*/
if (hapd->iconf->local_pwr_constraint == -1)
local_pwr_constraint = (dfs == 0) ? 0 : 3;
else
local_pwr_constraint = hapd->iconf->local_pwr_constraint;
/*
* A STA that is not an AP shall use a transmit power less than or
* equal to the local maximum transmit power level for the channel.
* The local maximum transmit power can be calculated from the formula:
* local max TX pwr = max TX pwr - local pwr constraint
* Where max TX pwr is maximum transmit power level specified for
* channel in Country element and local pwr constraint is specified
* for channel in this Power Constraint element.
*/
chan = &mode->channels[i];
max_tx_power = chan->max_tx_power - local_pwr_constraint;
/*
* Local Maximum Transmit power is encoded as two's complement
* with a 0.5 dB step.
*/
max_tx_power *= 2; /* in 0.5 dB steps */
if (max_tx_power > 127) {
/* 63.5 has special meaning of 63.5 dBm or higher */
max_tx_power = 127;
}
if (max_tx_power < -128)
max_tx_power = -128;
if (max_tx_power < 0)
tx_pwr = 0x80 + max_tx_power + 128;
else
tx_pwr = max_tx_power;
*eid++ = WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE;
*eid++ = 2 + tx_pwr_count;
/*
* Max Transmit Power count and
* Max Transmit Power units = 0 (EIRP)
*/
*eid++ = tx_pwr_count;
for (i = 0; i <= tx_pwr_count; i++)
*eid++ = tx_pwr;
return eid;
}
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab)
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
if (!vht_capab ||
if (!vht_capab || !(sta->flags & WLAN_STA_WMM) ||
!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac ||
!check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;
@ -422,7 +260,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;

File diff suppressed because it is too large Load diff

View file

@ -42,10 +42,9 @@ const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
size_t *len);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled);
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
int valid);
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
bool enabled);
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid);
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth);
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);

View file

@ -34,6 +34,60 @@ hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
}
int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
{
struct hostapd_neighbor_entry *nr;
char *pos, *end;
pos = buf;
end = buf + buflen;
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
list) {
int ret;
char nrie[2 * 255 + 1];
char lci[2 * 255 + 1];
char civic[2 * 255 + 1];
char ssid[SSID_MAX_LEN * 2 + 1];
ssid[0] = '\0';
wpa_snprintf_hex(ssid, sizeof(ssid), nr->ssid.ssid,
nr->ssid.ssid_len);
nrie[0] = '\0';
if (nr->nr)
wpa_snprintf_hex(nrie, sizeof(nrie),
wpabuf_head(nr->nr),
wpabuf_len(nr->nr));
lci[0] = '\0';
if (nr->lci)
wpa_snprintf_hex(lci, sizeof(lci),
wpabuf_head(nr->lci),
wpabuf_len(nr->lci));
civic[0] = '\0';
if (nr->civic)
wpa_snprintf_hex(civic, sizeof(civic),
wpabuf_head(nr->civic),
wpabuf_len(nr->civic));
ret = os_snprintf(pos, end - pos, MACSTR
" ssid=%s%s%s%s%s%s%s%s\n",
MAC2STR(nr->bssid), ssid,
nr->nr ? " nr=" : "", nrie,
nr->lci ? " lci=" : "", lci,
nr->civic ? " civic=" : "", civic,
nr->stationary ? " stat" : "");
if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
}
return pos - buf;
}
static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
{
wpabuf_free(nr->nr);
@ -166,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;
@ -202,6 +256,8 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
if (vht)
bssid_info |= NEI_REP_BSSID_INFO_VHT;
if (he)
bssid_info |= NEI_REP_BSSID_INFO_HE;
}
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */

View file

@ -13,6 +13,7 @@
struct hostapd_neighbor_entry *
hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid);
int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen);
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid,
const struct wpabuf *nr, const struct wpabuf *lci,

View file

@ -516,6 +516,12 @@ 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) ||
wpa_key_mgmt_fils(entry->akmp)) {
if (os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)
return entry;
continue;
}
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
entry->akmp);
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)

View file

@ -82,7 +82,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
sta = NULL;
} else {
sta->eapol_sm->radius_identifier = -1;
sta->eapol_sm->portValid = TRUE;
sta->eapol_sm->portValid = true;
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
}
}

View file

@ -46,9 +46,7 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
#ifdef CONFIG_IEEE80211W
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
#endif /* CONFIG_IEEE80211W */
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
@ -158,6 +156,37 @@ void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
}
#ifdef CONFIG_PASN
void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta)
{
if (sta->pasn) {
wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR,
MAC2STR(sta->addr));
if (sta->pasn->ecdh)
crypto_ecdh_deinit(sta->pasn->ecdh);
wpabuf_free(sta->pasn->secret);
sta->pasn->secret = NULL;
#ifdef CONFIG_SAE
sae_clear_data(&sta->pasn->sae);
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
/* In practice this pointer should be NULL */
wpabuf_free(sta->pasn->fils.erp_resp);
sta->pasn->fils.erp_resp = NULL;
#endif /* CONFIG_FILS */
bin_clear_free(sta->pasn, sizeof(*sta->pasn));
sta->pasn = NULL;
}
}
#endif /* CONFIG_PASN */
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@ -166,6 +195,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);
@ -235,9 +265,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) {
@ -248,10 +276,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)
@ -301,10 +329,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->challenge);
#ifdef CONFIG_IEEE80211W
os_free(sta->sa_query_trans_id);
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
@ -331,6 +357,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);
@ -375,8 +402,16 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
#endif /* CONFIG_WNM_AP */
#ifdef CONFIG_PASN
ap_free_sta_pasn(hapd, sta);
#endif /* CONFIG_PASN */
os_free(sta->ifname_wds);
#ifdef CONFIG_TESTING_OPTIONS
os_free(sta->sae_postponed_commit);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(sta);
}
@ -546,6 +581,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 =
@ -590,7 +626,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
if (!(sta->flags & WLAN_STA_AUTH)) {
if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_AUTHORIZED))) {
if (sta->flags & WLAN_STA_GAS) {
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
"entry " MACSTR, MAC2STR(sta->addr));
@ -813,6 +850,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)",
@ -863,6 +901,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 - "
@ -1028,6 +1067,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;
@ -1049,7 +1095,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->vlan_id == old_vlanid)
goto skip_counting;
if (sta->vlan_id > 0 && vlan == NULL) {
if (sta->vlan_id > 0 && !vlan &&
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
"binding station to (vlan_id=%d)",
@ -1095,8 +1142,6 @@ done:
}
#ifdef CONFIG_IEEE80211W
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
@ -1135,6 +1180,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,
@ -1186,8 +1233,6 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
sta->sa_query_count = 0;
}
#endif /* CONFIG_IEEE80211W */
const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
struct sta_info *sta)
@ -1324,9 +1369,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)",
@ -1414,7 +1460,8 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
int res;
buf[0] = '\0';
res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
res = os_snprintf(buf, buflen,
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@ -1433,6 +1480,8 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
(flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
(flags & WLAN_STA_HE ? "[HE]" : ""),
(flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
@ -1486,3 +1535,33 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
hapd, sta);
}
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
{
/*
* If a station that is already associated to the AP, is trying to
* authenticate again, remove the STA entry, in order to make sure the
* STA PS state gets cleared and configuration gets updated. To handle
* this, station's added_unassoc flag is cleared once the station has
* completed association.
*/
ap_sta_set_authorized(hapd, sta, 0);
hostapd_drv_sta_remove(hapd, sta->addr);
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED);
if (hostapd_sta_add(hapd, sta->addr, 0, 0,
sta->supported_rates,
sta->supported_rates_len,
0, NULL, NULL, NULL, 0, NULL,
sta->flags, 0, 0, 0, 0)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
"Could not add STA to kernel driver");
return -1;
}
sta->added_unassoc = 1;
return 0;
}

View file

@ -14,6 +14,8 @@
#include "vlan.h"
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "crypto/sha384.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@ -38,6 +40,8 @@
#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_PASN_FILS_ERP BIT(26)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@ -62,6 +66,43 @@ struct pending_eapol_rx {
struct os_reltime rx_time;
};
enum pasn_fils_state {
PASN_FILS_STATE_NONE = 0,
PASN_FILS_STATE_PENDING_AS,
PASN_FILS_STATE_COMPLETE
};
struct pasn_fils_data {
u8 state;
u8 nonce[FILS_NONCE_LEN];
u8 anonce[FILS_NONCE_LEN];
u8 session[FILS_SESSION_LEN];
u8 erp_pmkid[PMKID_LEN];
struct wpabuf *erp_resp;
};
struct pasn_data {
int akmp;
int cipher;
u16 group;
u8 trans_seq;
u8 wrapped_data_format;
size_t kdk_len;
u8 hash[SHA384_MAC_LEN];
struct wpa_ptk ptk;
struct crypto_ecdh *ecdh;
struct wpabuf *secret;
#ifdef CONFIG_SAE
struct sae_data sae;
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
struct pasn_fils_data fils;
#endif /* CONFIG_FILS */
};
struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
@ -121,6 +162,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,8 +212,8 @@ 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;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
int sa_query_timed_out;
@ -179,7 +221,6 @@ struct sta_info {
* sa_query_count octets of pending SA Query
* transaction identifiers */
struct os_reltime sa_query_start;
#endif /* CONFIG_IEEE80211W */
#if defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP)
#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
@ -278,11 +319,17 @@ struct sta_info {
int last_tk_key_idx;
u8 last_tk[WPA_TK_MAX_LEN];
size_t last_tk_len;
u8 *sae_postponed_commit;
size_t sae_postponed_commit_len;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
#ifdef CONFIG_PASN
struct pasn_data *pasn;
#endif /* CONFIG_PASN */
};
@ -358,5 +405,8 @@ 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);
void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* STA_INFO_H */

View file

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

View file

@ -22,7 +22,9 @@
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
{
int ret, i;
int ret;
#ifdef CONFIG_WEP
int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (!hapd->conf->ssid.wep.key[i])
@ -32,6 +34,7 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
vlan->ifname);
return -1;
}
#endif /* CONFIG_WEP */
if (!iface_exists(vlan->ifname))
ret = hostapd_vlan_if_add(hapd, vlan->ifname);

View file

@ -111,9 +111,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
u8 *pos = eid;
struct wmm_parameter_element *wmm =
(struct wmm_parameter_element *) (pos + 2);
struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM] = { 0 };
struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM];
int e;
os_memset(wmmp, 0, sizeof(wmmp));
if (!hapd->conf->wmm_enabled)
return eid;
wmm_calc_regulatory_limit(hapd, wmmp);
@ -209,7 +211,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
len = ((u8 *) (t + 1)) - buf;
if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
if (hostapd_drv_send_mlme(hapd, m, len, 0, NULL, 0, 0) < 0)
wpa_printf(MSG_INFO, "wmm_send_action: send failed");
}
@ -291,10 +293,11 @@ int wmm_process_tspec(struct wmm_tspec_element *tspec)
static void wmm_addts_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
struct wmm_tspec_element *tspec, size_t len)
const struct wmm_tspec_element *tspec, size_t len)
{
const u8 *end = ((const u8 *) mgmt) + len;
int res;
struct wmm_tspec_element tspec_resp;
if ((const u8 *) (tspec + 1) > end) {
wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
@ -306,10 +309,11 @@ static void wmm_addts_req(struct hostapd_data *hapd,
mgmt->u.action.u.wmm_action.dialog_token,
MAC2STR(mgmt->sa));
res = wmm_process_tspec(tspec);
os_memcpy(&tspec_resp, tspec, sizeof(struct wmm_tspec_element));
res = wmm_process_tspec(&tspec_resp);
wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
wmm_send_action(hapd, mgmt->sa, &tspec_resp, WMM_ACTION_CODE_ADDTS_RESP,
mgmt->u.action.u.wmm_action.dialog_token, res);
}

View file

@ -54,6 +54,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
size_t len;
size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0;
size_t bigtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie;
u8 *wnmtfs_ie, *oci_ie;
u8 wnmsleep_ie_len, oci_ie_len;
@ -102,6 +103,15 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
os_free(wnmtfs_ie);
return -1;
}
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->oci_freq_override_wnm_sleep) {
wpa_printf(MSG_INFO,
"TEST: Override OCI frequency %d -> %u MHz",
ci.frequency,
hapd->conf->oci_freq_override_wnm_sleep);
ci.frequency = hapd->conf->oci_freq_override_wnm_sleep;
}
#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
@ -122,8 +132,10 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
#define MAX_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26
#define MAX_BIGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
MAX_BIGTK_SUBELEM_LEN +
oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
@ -150,7 +162,6 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
pos += gtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
(int) gtk_elem_len);
#ifdef CONFIG_IEEE80211W
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
if (res < 0)
goto fail;
@ -158,11 +169,21 @@ 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);
#endif /* CONFIG_IEEE80211W */
if (hapd->conf->beacon_prot &&
(hapd->iface->drv_flags &
WPA_DRIVER_FLAGS_BEACON_PROTECTION)) {
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 */
@ -178,7 +199,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 */
@ -191,8 +213,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) {
@ -203,7 +225,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 ||
@ -223,6 +245,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);
@ -305,8 +328,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;
}
}
@ -510,6 +534,31 @@ 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 ||
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
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)
@ -528,8 +577,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;
}
}
@ -643,7 +698,7 @@ int wnm_send_disassoc_imminent(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to "
MACSTR, disassoc_timer, MAC2STR(sta->addr));
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@ -716,7 +771,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
os_memcpy(pos, url, url_len);
pos += url_len;
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
"Management Request frame");
return -1;
@ -792,7 +847,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
mbo_len);
}
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"Failed to send BSS Transition Management Request frame");
os_free(buf);
@ -836,7 +891,7 @@ int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to "
MACSTR " (dialog_token=%u auto_report=%u timeout=%u)",
MAC2STR(sta->addr), dialog_token, auto_report, timeout);
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) {
wpa_printf(MSG_DEBUG,
"WNM: Failed to send Collocated Interference Request frame");
return -1;

File diff suppressed because it is too large Load diff

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