Merge ^/head r351317 through r351731.

This commit is contained in:
Dimitry Andric 2019-09-03 05:58:43 +00:00
commit c5c3ba6b43
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/clang900-import/; revision=351732
636 changed files with 38323 additions and 14150 deletions

View file

@ -49,6 +49,9 @@ OLD_FILES+=usr/include/c++/v1/experimental/system_error
OLD_FILES+=usr/include/c++/v1/experimental/tuple
OLD_FILES+=usr/lib/libc++fs.a
# 20190825: zlib 1.0.4 removed from kernel
OLD_FILES+=usr/include/sys/zlib.h
OLD_FILES+=usr/include/sys/zutil.h
# 20190817: pft_ping.py and sniffer.py moved to /usr/tests/sys/netpfil/common
OLD_FILES+=usr/tests/sys/netpfil/pf/sniffer.py
OLD_FILES+=usr/tests/sys/netpfil/pf/pft_ping.py
@ -65,8 +68,8 @@ OLD_FILES+=usr/share/man/man3/cap_random_buf.3.gz
OLD_FILES+=usr/share/man/man9/vm_page_hold.9.gz
# 20190618: sys/capability.h removed (sys/capsicum.h is the one to use)
OLD_FILES+=usr/include/sys/capability.h
# 20190615: sys/pwm.h renamed to dev/pwmc.h and pwm(9) removed
OLD_FILES+=usr/include/sys/pwm.h usr/share/man/man9/pwm.9.gz
# 20190615: sys/pwm.h renamed to dev/pwmc.h
OLD_FILES+=usr/include/sys/pwm.h
# 20190612: new clang import which bumps version from 8.0.0 to 8.0.1.
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/8.0.0/include/sanitizer/asan_interface.h

View file

@ -10,7 +10,25 @@ newline. Entries should be separated by a newline.
Changes to this file should not be MFCed.
r351201:
r351522:
Add kernel-side support for in-kernel Transport Layer Security
(KTLS). KTLS permits using sendfile(2) over sockets using
TLS.
r351361:
Add probes for lockmgr(9) to the lockstat DTrace provider, add
corresponding lockstat(1) events, and document the new probes in
dtrace_lockstat.4.
r351356:
Intel RST is a new 'feature' that remaps NVMe devices from
their normal location to part of the AHCI bar space. This
will eliminate the need to set the BIOS SATA setting from RST
to AHCI causing the nvme drive to be erased before FreeBSD
will see the nvme drive. FreeBSD will now be able to see the
nvme drive now in the default config.
r351201, r351372:
Add a vop_stdioctl() call, so that file systems that do not support
holes will have a trivial implementation of lseek(SEEK_DATA/SEEK_HOLE).
The algorithm appears to be compatible with the POSIX draft and
@ -18,6 +36,8 @@ r351201:
does not support holes. Prior to this patch, lseek(2) would reply
-1 with errno set to ENOTTY for SEEK_DATA/SEEK_HOLE on files in
file systems that do not support holes.
r351372 maps ENOTTY to EINVAL for lseek(SEEK_DATA/SEEK_HOLE) for
any other cases, such as a ENOTTY return from vn_bmap_seekhole().
r350665:
The fuse driver has been renamed to fusefs(5) and been substantially
@ -50,6 +70,9 @@ r350307:
libcap_random(3) has been removed. Applications can use native
APIs to get random data in capability mode.
r349529,r349530:
Add support for using unmapped mbufs with sendfile(2).
r349352:
nand(4) and related components have been removed.

View file

@ -26,6 +26,11 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
disable the most expensive debugging functionality run
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
20190823:
Several of ping6's options have been renamed for better consistency
with ping. If you use any of -ARWXaghmrtwx, you must update your
scripts. See ping6(8) for details.
20190727:
The vfs.fusefs.sync_unmount and vfs.fusefs.init_backgrounded sysctls
and the "-o sync_unmount" and "-o init_backgrounded" mount options have

View file

@ -43,7 +43,7 @@ reader()
while true
do
sleep 0.1
cat /etc/motd > /dev/null
cat /COPYRIGHT > /dev/null
done
}

View file

@ -44,7 +44,7 @@ reader()
while true
do
sleep 0.1
cat /etc/motd > /dev/null
cat /COPYRIGHT > /dev/null
done
}

View file

@ -55,7 +55,7 @@ else
removeinet6=0
fi
$dtrace -c "/sbin/ping6 -q -c 1 -X 3 $local" -qs /dev/stdin <<EOF | sort -n | \
$dtrace -c "/sbin/ping6 -q -c 1 -t 3 $local" -qs /dev/stdin <<EOF | sort -n | \
grep -v -e '^round-trip ' -e '^--- '
ip:::send
/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&

View file

@ -26,5 +26,5 @@
while true
do
sleep 0.1
cat /etc/motd > /dev/null
cat /COPYRIGHT > /dev/null
done

View file

@ -158,29 +158,33 @@ static ls_event_info_t g_event_info[LS_MAX_EVENTS] = {
{ 'C', "Lock", "R/W writer blocked by readers", "nsec",
"lockstat:::rw-block", "arg2 == 0 && arg3 == 0 && arg4" },
{ 'C', "Lock", "R/W reader blocked by writer", "nsec",
"lockstat:::rw-block", "arg2 != 0 && arg3 == 1" },
"lockstat:::rw-block", "arg2 == 1 && arg3 == 1" },
{ 'C', "Lock", "R/W reader blocked by write wanted", "nsec",
"lockstat:::rw-block", "arg2 != 0 && arg3 == 0 && arg4" },
"lockstat:::rw-block", "arg2 == 1 && arg3 == 0 && arg4" },
{ 'C', "Lock", "R/W writer spin on writer", "nsec",
"lockstat:::rw-spin", "arg2 == 0 && arg3 == 1" },
{ 'C', "Lock", "R/W writer spin on readers", "nsec",
"lockstat:::rw-spin", "arg2 == 0 && arg3 == 0 && arg4" },
{ 'C', "Lock", "R/W reader spin on writer", "nsec",
"lockstat:::rw-spin", "arg2 != 0 && arg3 == 1" },
"lockstat:::rw-spin", "arg2 == 1 && arg3 == 1" },
{ 'C', "Lock", "R/W reader spin on write wanted", "nsec",
"lockstat:::rw-spin", "arg2 != 0 && arg3 == 0 && arg4" },
"lockstat:::rw-spin", "arg2 == 1 && arg3 == 0 && arg4" },
{ 'C', "Lock", "SX exclusive block", "nsec",
"lockstat:::sx-block", "arg2 == 0" },
{ 'C', "Lock", "SX shared block", "nsec",
"lockstat:::sx-block", "arg2 != 0" },
"lockstat:::sx-block", "arg2 == 1" },
{ 'C', "Lock", "SX exclusive spin", "nsec",
"lockstat:::sx-spin", "arg2 == 0" },
{ 'C', "Lock", "SX shared spin", "nsec",
"lockstat:::sx-spin", "arg2 != 0" },
{ 'C', "Lock", "Unknown event (type 16)", "units" },
{ 'C', "Lock", "Unknown event (type 17)", "units" },
{ 'C', "Lock", "Unknown event (type 18)", "units" },
{ 'C', "Lock", "Unknown event (type 19)", "units" },
"lockstat:::sx-spin", "arg2 == 1" },
{ 'C', "Lock", "lockmgr writer blocked by writer", "nsec",
"lockstat:::lockmgr-block", "arg2 == 0 && arg3 == 1" },
{ 'C', "Lock", "lockmgr writer blocked by readers", "nsec",
"lockstat:::lockmgr-block", "arg2 == 0 && arg3 == 0 && arg4" },
{ 'C', "Lock", "lockmgr reader blocked by writer", "nsec",
"lockstat:::lockmgr-block", "arg2 == 1 && arg3 == 1" },
{ 'C', "Lock", "lockmgr reader blocked by write wanted", "nsec",
"lockstat:::lockmgr-block", "arg2 == 1 && arg3 == 0 && arg4" },
{ 'C', "Lock", "Unknown event (type 20)", "units" },
{ 'C', "Lock", "Unknown event (type 21)", "units" },
{ 'C', "Lock", "Unknown event (type 22)", "units" },
@ -206,13 +210,17 @@ static ls_event_info_t g_event_info[LS_MAX_EVENTS] = {
"lockstat:::rw-release", "arg1 == 1",
"lockstat:::rw-acquire" },
{ 'H', "Lock", "SX shared hold", "nsec",
"lockstat:::sx-release", "arg1 == 0",
"lockstat:::sx-acquire" },
{ 'H', "Lock", "SX exclusive hold", "nsec",
"lockstat:::sx-release", "arg1 == 1",
"lockstat:::sx-acquire" },
{ 'H', "Lock", "Unknown event (type 38)", "units" },
{ 'H', "Lock", "Unknown event (type 39)", "units" },
{ 'H', "Lock", "SX exclusive hold", "nsec",
"lockstat:::sx-release", "arg1 == 0",
"lockstat:::sx-acquire" },
{ 'H', "Lock", "lockmgr shared hold", "nsec",
"lockstat:::lockmgr-release", "arg1 == 1",
"lockstat:::lockmgr-acquire" },
{ 'H', "Lock", "lockmgr exclusive hold", "nsec",
"lockstat:::lockmgr-release,lockstat:::lockmgr-disown", "arg1 == 0",
"lockstat:::lockmgr-acquire" },
{ 'H', "Lock", "Unknown event (type 40)", "units" },
{ 'H', "Lock", "Unknown event (type 41)", "units" },
{ 'H', "Lock", "Unknown event (type 42)", "units" },

View file

@ -472,7 +472,7 @@ differ(void *arg)
if (err)
return ((void *)-1);
if (di->zerr) {
ASSERT(di->zerr == EINVAL);
ASSERT(di->zerr == EPIPE);
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"Internal error: bad data from diff IOCTL"));

View file

@ -73,7 +73,6 @@ int fputc(int c, FILE* stream);
int fputs(const char* restrict s, FILE* restrict stream);
int getc(FILE* stream);
int getchar(void);
char* gets(char* s); // removed in C++14
int putc(int c, FILE* stream);
int putchar(int c);
int puts(const char* s);
@ -152,9 +151,6 @@ using ::tmpnam;
#ifndef _LIBCPP_HAS_NO_STDIN
using ::getchar;
#if _LIBCPP_STD_VER <= 11 && !defined(_LIBCPP_MSVCRT)
using ::gets;
#endif
using ::scanf;
using ::vscanf;
#endif

View file

@ -74,7 +74,6 @@
#undef fwrite
#undef getc
#undef getchar
#undef gets
#undef perror
#undef printf
#undef putc
@ -121,7 +120,6 @@ _GLIBCXX_BEGIN_NAMESPACE(std)
using ::fwrite;
using ::getc;
using ::getchar;
using ::gets;
using ::perror;
using ::printf;
using ::putc;

View file

@ -787,7 +787,7 @@ ProcessMonitor::~ProcessMonitor() { StopMonitor(); }
// Thread setup and tear down.
void ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Status &error) {
static const char *g_thread_name = "lldb.process.freebsd.operation";
static const char *g_thread_name = "freebsd.op";
if (m_operation_thread->IsJoinable())
return;
@ -955,7 +955,7 @@ bool ProcessMonitor::Launch(LaunchArgs *args) {
void ProcessMonitor::StartAttachOpThread(AttachArgs *args,
lldb_private::Status &error) {
static const char *g_thread_name = "lldb.process.freebsd.operation";
static const char *g_thread_name = "freebsd.op";
if (m_operation_thread->IsJoinable())
return;

View file

@ -33,6 +33,24 @@ __RCSID("$NetBSD: h_gets.c,v 1.1 2010/12/27 02:04:19 pgoyette Exp $");
#include <stdio.h>
#ifdef __FreeBSD__
/*
* We want to test the gets() implementation, but cannot simply link against
* the gets symbol because it is not in the default version. (We've made it
* unavailable by default on FreeBSD because it should not be used.)
*
* The next two lines create an unsafe_gets() function that resolves to
* gets@FBSD_1.0, which we call from our local gets() implementation.
*/
__sym_compat(gets, unsafe_gets, FBSD_1.0);
char *unsafe_gets(char *);
char *gets(char *buf)
{
return unsafe_gets(buf);
}
#endif
int
main(int argc, char *argv[])
{

View file

@ -365,6 +365,20 @@ setdefaults(e)
TLS_Srv_Opts = TLS_I_SRV;
if (NULL == EVP_digest)
EVP_digest = EVP_md5();
Srv_SSL_Options = SSL_OP_ALL;
Clt_SSL_Options = SSL_OP_ALL
# ifdef SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv2
# endif
# ifdef SSL_OP_NO_TICKET
| SSL_OP_NO_TICKET
# endif
;
# ifdef SSL_OP_TLSEXT_PADDING
/* SSL_OP_TLSEXT_PADDING breaks compatibility with some sites */
Srv_SSL_Options &= ~SSL_OP_TLSEXT_PADDING;
Clt_SSL_Options &= ~SSL_OP_TLSEXT_PADDING;
# endif /* SSL_OP_TLSEXT_PADDING */
#endif /* STARTTLS */
#ifdef HESIOD_INIT
HesiodContext = NULL;

View file

@ -159,22 +159,6 @@ readcf(cfname, safe, e)
FileName = cfname;
LineNumber = 0;
#if STARTTLS
Srv_SSL_Options = SSL_OP_ALL;
Clt_SSL_Options = SSL_OP_ALL
# ifdef SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv2
# endif
# ifdef SSL_OP_NO_TICKET
| SSL_OP_NO_TICKET
# endif
;
# ifdef SSL_OP_TLSEXT_PADDING
/* SSL_OP_TLSEXT_PADDING breaks compatibility with some sites */
Srv_SSL_Options &= ~SSL_OP_TLSEXT_PADDING;
Clt_SSL_Options &= ~SSL_OP_TLSEXT_PADDING;
# endif /* SSL_OP_TLSEXT_PADDING */
#endif /* STARTTLS */
if (DontLockReadFiles)
sff |= SFF_NOLOCK;
cf = safefopen(cfname, O_RDONLY, 0444, sff);

View file

@ -1,5 +1,29 @@
ChangeLog for hostapd
2019-08-07 - v2.9
* SAE changes
- disable use of groups using Brainpool curves
- improved protection against side channel attacks
[https://w1.fi/security/2019-6/]
* EAP-pwd changes
- disable use of groups using Brainpool curves
- improved protection against side channel attacks
[https://w1.fi/security/2019-6/]
* fixed FT-EAP initial mobility domain association using PMKSA caching
* added configuration of airtime policy
* fixed FILS to and RSNE into (Re)Association Response frames
* fixed DPP bootstrapping URI parser of channel list
* added support for regulatory WMM limitation (for ETSI)
* added support for MACsec Key Agreement using IEEE 802.1X/PSK
* added experimental support for EAP-TEAP server (RFC 7170)
* added experimental support for EAP-TLS server with TLS v1.3
* added support for two server certificates/keys (RSA/ECC)
* added AKMSuiteSelector into "STA <addr>" control interface data to
determine with AKM was used for an association
* added eap_sim_id parameter to allow EAP-SIM/AKA server pseudonym and
fast reauthentication use to be disabled
* fixed an ECDH operation corner case with OpenSSL
2019-04-21 - v2.8
* SAE changes
- added support for SAE Password Identifier

View file

@ -24,14 +24,6 @@
#include "config_file.h"
#ifndef CONFIG_NO_RADIUS
#ifdef EAP_SERVER
static struct hostapd_radius_attr *
hostapd_parse_radius_attr(const char *value);
#endif /* EAP_SERVER */
#endif /* CONFIG_NO_RADIUS */
#ifndef CONFIG_NO_VLAN
static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
const char *fname)
@ -660,75 +652,6 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
}
static struct hostapd_radius_attr *
hostapd_parse_radius_attr(const char *value)
{
const char *pos;
char syntax;
struct hostapd_radius_attr *attr;
size_t len;
attr = os_zalloc(sizeof(*attr));
if (attr == NULL)
return NULL;
attr->type = atoi(value);
pos = os_strchr(value, ':');
if (pos == NULL) {
attr->val = wpabuf_alloc(1);
if (attr->val == NULL) {
os_free(attr);
return NULL;
}
wpabuf_put_u8(attr->val, 0);
return attr;
}
pos++;
if (pos[0] == '\0' || pos[1] != ':') {
os_free(attr);
return NULL;
}
syntax = *pos++;
pos++;
switch (syntax) {
case 's':
attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
break;
case 'x':
len = os_strlen(pos);
if (len & 1)
break;
len /= 2;
attr->val = wpabuf_alloc(len);
if (attr->val == NULL)
break;
if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
wpabuf_free(attr->val);
os_free(attr);
return NULL;
}
break;
case 'd':
attr->val = wpabuf_alloc(4);
if (attr->val)
wpabuf_put_be32(attr->val, atoi(pos));
break;
default:
os_free(attr);
return NULL;
}
if (attr->val == NULL) {
os_free(attr);
return NULL;
}
return attr;
}
static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
{
@ -2313,6 +2236,42 @@ static unsigned int parse_tls_flags(const char *val)
#endif /* EAP_SERVER */
#ifdef CONFIG_AIRTIME_POLICY
static int add_airtime_weight(struct hostapd_bss_config *bss, char *value)
{
struct airtime_sta_weight *wt;
char *pos, *next;
wt = os_zalloc(sizeof(*wt));
if (!wt)
return -1;
/* 02:01:02:03:04:05 10 */
pos = value;
next = os_strchr(pos, ' ');
if (next)
*next++ = '\0';
if (!next || hwaddr_aton(pos, wt->addr)) {
wpa_printf(MSG_ERROR, "Invalid station address: '%s'", pos);
os_free(wt);
return -1;
}
pos = next;
wt->weight = atoi(pos);
if (!wt->weight) {
wpa_printf(MSG_ERROR, "Invalid weight: '%s'", pos);
os_free(wt);
return -1;
}
wt->next = bss->airtime_weight_list;
bss->airtime_weight_list = wt;
return 0;
}
#endif /* CONFIG_AIRTIME_POLICY */
#ifdef CONFIG_SAE
static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
{
@ -2376,6 +2335,36 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val)
#endif /* CONFIG_SAE */
#ifdef CONFIG_DPP2
static int hostapd_dpp_controller_parse(struct hostapd_bss_config *bss,
const char *pos)
{
struct dpp_controller_conf *conf;
char *val;
conf = os_zalloc(sizeof(*conf));
if (!conf)
return -1;
val = get_param(pos, "ipaddr=");
if (!val || hostapd_parse_ip_addr(val, &conf->ipaddr))
goto fail;
os_free(val);
val = get_param(pos, "pkhash=");
if (!val || os_strlen(val) != 2 * SHA256_MAC_LEN ||
hexstr2bin(val, conf->pkhash, SHA256_MAC_LEN) < 0)
goto fail;
os_free(val);
conf->next = bss->dpp_controller;
bss->dpp_controller = conf;
return 0;
fail:
os_free(val);
os_free(conf);
return -1;
}
#endif /* CONFIG_DPP2 */
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@ -2496,7 +2485,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "eapol_version") == 0) {
int eapol_version = atoi(pos);
#ifdef CONFIG_MACSEC
if (eapol_version < 1 || eapol_version > 3) {
#else /* CONFIG_MACSEC */
if (eapol_version < 1 || eapol_version > 2) {
#endif /* CONFIG_MACSEC */
wpa_printf(MSG_ERROR,
"Line %d: invalid EAPOL version (%d): '%s'.",
line, eapol_version, pos);
@ -2519,12 +2512,21 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "server_cert") == 0) {
os_free(bss->server_cert);
bss->server_cert = os_strdup(pos);
} else if (os_strcmp(buf, "server_cert2") == 0) {
os_free(bss->server_cert2);
bss->server_cert2 = os_strdup(pos);
} else if (os_strcmp(buf, "private_key") == 0) {
os_free(bss->private_key);
bss->private_key = os_strdup(pos);
} else if (os_strcmp(buf, "private_key2") == 0) {
os_free(bss->private_key2);
bss->private_key2 = os_strdup(pos);
} else if (os_strcmp(buf, "private_key_passwd") == 0) {
os_free(bss->private_key_passwd);
bss->private_key_passwd = os_strdup(pos);
} else if (os_strcmp(buf, "private_key_passwd2") == 0) {
os_free(bss->private_key_passwd2);
bss->private_key_passwd2 = os_strdup(pos);
} else if (os_strcmp(buf, "check_cert_subject") == 0) {
if (!pos[0]) {
wpa_printf(MSG_ERROR, "Line %d: unknown check_cert_subject '%s'",
@ -2605,6 +2607,20 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
bss->pac_key_refresh_time = atoi(pos);
#endif /* EAP_SERVER_FAST */
#ifdef EAP_SERVER_TEAP
} else if (os_strcmp(buf, "eap_teap_auth") == 0) {
int val = atoi(pos);
if (val < 0 || val > 1) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid eap_teap_auth value",
line);
return 1;
}
bss->eap_teap_auth = val;
} else if (os_strcmp(buf, "eap_teap_pac_no_inner") == 0) {
bss->eap_teap_pac_no_inner = atoi(pos);
#endif /* EAP_SERVER_TEAP */
#ifdef EAP_SERVER_SIM
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
os_free(bss->eap_sim_db);
@ -2613,6 +2629,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->eap_sim_db_timeout = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
bss->eap_sim_aka_result_ind = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_id") == 0) {
bss->eap_sim_id = atoi(pos);
#endif /* EAP_SERVER_SIM */
#ifdef EAP_SERVER_TNC
} else if (os_strcmp(buf, "tnc") == 0) {
@ -2816,6 +2834,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
a = a->next;
a->next = attr;
}
} else if (os_strcmp(buf, "radius_req_attr_sqlite") == 0) {
os_free(bss->radius_req_attr_sqlite);
bss->radius_req_attr_sqlite = os_strdup(pos);
} else if (os_strcmp(buf, "radius_das_port") == 0) {
bss->radius_das_port = atoi(pos);
} else if (os_strcmp(buf, "radius_das_client") == 0) {
@ -3442,6 +3463,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->he_op.he_twt_required = 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) {
conf->he_op.he_basic_mcs_nss_set = atoi(pos);
} else if (os_strcmp(buf, "he_mu_edca_qos_info_param_count") == 0) {
conf->he_mu_edca.he_qos_info |=
set_he_cap(atoi(pos), HE_QOS_INFO_EDCA_PARAM_SET_COUNT);
@ -3526,6 +3549,20 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "he_mu_edca_ac_vo_timer") == 0) {
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;
} 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_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);
#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@ -4298,6 +4335,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "dpp_csign") == 0) {
if (parse_wpabuf_hex(line, buf, &bss->dpp_csign, pos))
return 1;
#ifdef CONFIG_DPP2
} else if (os_strcmp(buf, "dpp_controller") == 0) {
if (hostapd_dpp_controller_parse(bss, pos))
return 1;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_OWE
} else if (os_strcmp(buf, "owe_transition_bssid") == 0) {
@ -4349,6 +4391,121 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->rssi_reject_assoc_timeout = atoi(pos);
} else if (os_strcmp(buf, "pbss") == 0) {
bss->pbss = atoi(pos);
#ifdef CONFIG_AIRTIME_POLICY
} else if (os_strcmp(buf, "airtime_mode") == 0) {
int val = atoi(pos);
if (val < 0 || val > AIRTIME_MODE_MAX) {
wpa_printf(MSG_ERROR, "Line %d: Unknown airtime_mode",
line);
return 1;
}
conf->airtime_mode = val;
} else if (os_strcmp(buf, "airtime_update_interval") == 0) {
conf->airtime_update_interval = atoi(pos);
} else if (os_strcmp(buf, "airtime_bss_weight") == 0) {
bss->airtime_weight = atoi(pos);
} else if (os_strcmp(buf, "airtime_bss_limit") == 0) {
int val = atoi(pos);
if (val < 0 || val > 1) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid airtime_bss_limit (must be 0 or 1)",
line);
return 1;
}
bss->airtime_limit = val;
} else if (os_strcmp(buf, "airtime_sta_weight") == 0) {
if (add_airtime_weight(bss, pos) < 0) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid airtime weight '%s'",
line, pos);
return 1;
}
#endif /* CONFIG_AIRTIME_POLICY */
#ifdef CONFIG_MACSEC
} else if (os_strcmp(buf, "macsec_policy") == 0) {
int macsec_policy = atoi(pos);
if (macsec_policy < 0 || macsec_policy > 1) {
wpa_printf(MSG_ERROR,
"Line %d: invalid macsec_policy (%d): '%s'.",
line, macsec_policy, pos);
return 1;
}
bss->macsec_policy = macsec_policy;
} else if (os_strcmp(buf, "macsec_integ_only") == 0) {
int macsec_integ_only = atoi(pos);
if (macsec_integ_only < 0 || macsec_integ_only > 1) {
wpa_printf(MSG_ERROR,
"Line %d: invalid macsec_integ_only (%d): '%s'.",
line, macsec_integ_only, pos);
return 1;
}
bss->macsec_integ_only = macsec_integ_only;
} else if (os_strcmp(buf, "macsec_replay_protect") == 0) {
int macsec_replay_protect = atoi(pos);
if (macsec_replay_protect < 0 || macsec_replay_protect > 1) {
wpa_printf(MSG_ERROR,
"Line %d: invalid macsec_replay_protect (%d): '%s'.",
line, macsec_replay_protect, pos);
return 1;
}
bss->macsec_replay_protect = macsec_replay_protect;
} else if (os_strcmp(buf, "macsec_replay_window") == 0) {
bss->macsec_replay_window = atoi(pos);
} else if (os_strcmp(buf, "macsec_port") == 0) {
int macsec_port = atoi(pos);
if (macsec_port < 1 || macsec_port > 65534) {
wpa_printf(MSG_ERROR,
"Line %d: invalid macsec_port (%d): '%s'.",
line, macsec_port, pos);
return 1;
}
bss->macsec_port = macsec_port;
} else if (os_strcmp(buf, "mka_priority") == 0) {
int mka_priority = atoi(pos);
if (mka_priority < 0 || mka_priority > 255) {
wpa_printf(MSG_ERROR,
"Line %d: invalid mka_priority (%d): '%s'.",
line, mka_priority, pos);
return 1;
}
bss->mka_priority = mka_priority;
} else if (os_strcmp(buf, "mka_cak") == 0) {
size_t len = os_strlen(pos);
if (len > 2 * MACSEC_CAK_MAX_LEN ||
(len != 2 * 16 && len != 2 * 32) ||
hexstr2bin(pos, bss->mka_cak, len / 2)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
line, pos);
return 1;
}
bss->mka_cak_len = len / 2;
bss->mka_psk_set |= MKA_PSK_SET_CAK;
} else if (os_strcmp(buf, "mka_ckn") == 0) {
size_t len = os_strlen(pos);
if (len > 2 * MACSEC_CKN_MAX_LEN || /* too long */
len < 2 || /* too short */
len % 2 != 0 /* not an integral number of bytes */) {
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
line, pos);
return 1;
}
bss->mka_ckn_len = len / 2;
if (hexstr2bin(pos, bss->mka_ckn, bss->mka_ckn_len)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
line, pos);
return -1;
}
bss->mka_psk_set |= MKA_PSK_SET_CKN;
#endif /* CONFIG_MACSEC */
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",

View file

@ -1830,26 +1830,40 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
struct iphdr ip;
const u8 *pos;
unsigned int i;
char extra[30];
if (len != HWSIM_PACKETLEN)
if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore unexpected length %d",
(int) len);
return;
}
eth = (const struct ether_header *) buf;
os_memcpy(&ip, eth + 1, sizeof(ip));
pos = &buf[sizeof(*eth) + sizeof(ip)];
if (ip.ihl != 5 || ip.version != 4 ||
ntohs(ip.tot_len) != HWSIM_IP_LEN)
ntohs(ip.tot_len) > HWSIM_IP_LEN) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore unexpect IP header");
return;
}
for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
if (*pos != (u8) i)
for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
if (*pos != (u8) i) {
wpa_printf(MSG_DEBUG,
"test data: RX - ignore mismatching payload");
return;
}
pos++;
}
wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
extra[0] = '\0';
if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@ -1894,7 +1908,7 @@ static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
{
u8 dst[ETH_ALEN], src[ETH_ALEN];
char *pos;
char *pos, *pos2;
int used;
long int val;
u8 tos;
@ -1903,11 +1917,12 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
struct iphdr *ip;
u8 *dpos;
unsigned int i;
size_t send_len = HWSIM_IP_LEN;
if (hapd->l2_test == NULL)
return -1;
/* format: <dst> <src> <tos> */
/* format: <dst> <src> <tos> [len=<length>] */
pos = cmd;
used = hwaddr_aton2(pos, dst);
@ -1921,11 +1936,19 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
return -1;
pos += used;
val = strtol(pos, NULL, 0);
val = strtol(pos, &pos2, 0);
if (val < 0 || val > 0xff)
return -1;
tos = val;
pos = os_strstr(pos2, " len=");
if (pos) {
i = atoi(pos + 5);
if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
return -1;
send_len = i;
}
eth = (struct ether_header *) &buf[2];
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
@ -1936,17 +1959,17 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
ip->version = 4;
ip->ttl = 64;
ip->tos = tos;
ip->tot_len = htons(HWSIM_IP_LEN);
ip->tot_len = htons(send_len);
ip->protocol = 1;
ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
dpos = (u8 *) (ip + 1);
for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
for (i = 0; i < send_len - sizeof(*ip); i++)
*dpos++ = i;
if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
HWSIM_PACKETLEN) < 0)
sizeof(struct ether_header) + send_len) < 0)
return -1;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR

View file

@ -108,11 +108,18 @@ CONFIG_EAP_TTLS=y
#CONFIG_EAP_GPSK_SHA256=y
# EAP-FAST for the integrated EAP server
# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
#CONFIG_EAP_FAST=y
# EAP-TEAP for the integrated EAP server
# Note: The current EAP-TEAP implementation is experimental and should not be
# enabled for production use. The IETF RFC 7170 that defines EAP-TEAP has number
# of conflicting statements and missing details and the implementation has
# vendor specific workarounds for those and as such, may not interoperate with
# any other implementation. This should not be used for anything else than
# experimentation and interoperability testing until those issues has been
# resolved.
#CONFIG_EAP_TEAP=y
# Wi-Fi Protected Setup (WPS)
#CONFIG_WPS=y
# Enable UPnP support for external WPS Registrars
@ -376,6 +383,9 @@ CONFIG_IPV6=y
# Experimental implementation of draft-harkins-owe-07.txt
#CONFIG_OWE=y
# Airtime policy support
#CONFIG_AIRTIME_POLICY=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

View file

@ -121,6 +121,11 @@ int eap_server_register_methods(void)
ret = eap_server_fast_register();
#endif /* EAP_SERVER_FAST */
#ifdef EAP_SERVER_TEAP
if (ret == 0)
ret = eap_server_teap_register();
#endif /* EAP_SERVER_TEAP */
#ifdef EAP_SERVER_WSC
if (ret == 0)
ret = eap_server_wsc_register();

View file

@ -782,10 +782,8 @@ wmm_ac_vo_acm=0
# 1 = supported
#he_mu_beamformer=1
# he_bss_color: BSS color
# 0 = no BSS color (default)
# unsigned integer = BSS color
#he_bss_color=0
# he_bss_color: BSS color (1-63)
#he_bss_color=1
#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
@ -801,6 +799,17 @@ wmm_ac_vo_acm=0
# unsigned integer = duration in units of 16 us
#he_rts_threshold=0
# HE operating channel information; see matching vht_* parameters for details.
#he_oper_chwidth
#he_oper_centr_freq_seg0_idx
#he_oper_centr_freq_seg1_idx
#he_basic_mcs_nss_set: Basic NSS/MCS set
# 16-bit combination of 2-bit values of Max HE-MCS For 1..8 SS; each 2-bit
# value having following meaning:
# 0 = HE-MCS 0-7, 1 = HE-MCS 0-9, 2 = HE-MCS 0-11, 3 = not supported
#he_basic_mcs_nss_set
#he_mu_edca_qos_info_param_count
#he_mu_edca_qos_info_q_ack
#he_mu_edca_qos_info_queue_request=1
@ -825,6 +834,12 @@ wmm_ac_vo_acm=0
#he_mu_edca_ac_vo_ecwmax=15
#he_mu_edca_ac_vo_timer=255
# Spatial Reuse Parameter Set
#he_spr_sr_control
#he_spr_non_srg_obss_pd_max_offset
#he_spr_srg_obss_pd_min_offset
#he_spr_srg_obss_pd_max_offset
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@ -836,6 +851,8 @@ wmm_ac_vo_acm=0
# the new version number correctly (they seem to drop the frames completely).
# In order to make hostapd interoperate with these clients, the version number
# can be set to the older version (1) with this configuration value.
# Note: When using MACsec, eapol_version shall be set to 3, which is
# defined in IEEE Std 802.1X-2010.
#eapol_version=2
# Optional displayable message sent with EAP Request-Identity. The first \0
@ -879,6 +896,54 @@ eapol_key_index_workaround=0
# ERP is enabled (eap_server_erp=1).
#erp_domain=example.com
##### MACsec ##################################################################
# macsec_policy: IEEE 802.1X/MACsec options
# This determines how sessions are secured with MACsec (only for MACsec
# drivers).
# 0: MACsec not in use (default)
# 1: MACsec enabled - Should secure, accept key server's advice to
# determine whether to use a secure session or not.
#
# macsec_integ_only: IEEE 802.1X/MACsec transmit mode
# This setting applies only when MACsec is in use, i.e.,
# - macsec_policy is enabled
# - the key server has decided to enable MACsec
# 0: Encrypt traffic (default)
# 1: Integrity only
#
# macsec_replay_protect: IEEE 802.1X/MACsec replay protection
# This setting applies only when MACsec is in use, i.e.,
# - macsec_policy is enabled
# - the key server has decided to enable MACsec
# 0: Replay protection disabled (default)
# 1: Replay protection enabled
#
# macsec_replay_window: IEEE 802.1X/MACsec replay protection window
# This determines a window in which replay is tolerated, to allow receipt
# of frames that have been misordered by the network.
# This setting applies only when MACsec replay protection active, i.e.,
# - macsec_replay_protect is enabled
# - the key server has decided to enable MACsec
# 0: No replay window, strict check (default)
# 1..2^32-1: number of packets that could be misordered
#
# macsec_port: IEEE 802.1X/MACsec port
# Port component of the SCI
# Range: 1-65534 (default: 1)
#
# mka_priority (Priority of MKA Actor)
# Range: 0..255 (default: 255)
#
# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
# In this mode, instances of hostapd can act as MACsec peers. The peer
# with lower priority will become the key server and start distributing SAKs.
# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-byte (128-bit)
# hex-string (32 hex-digits) or a 32-byte (256-bit) hex-string (64 hex-digits)
# mka_ckn (CKN = CAK Name) takes a 1..32-bytes (8..256 bit) hex-string
# (2..64 hex-digits)
##### Integrated EAP server ###################################################
# Optionally, hostapd can be configured to use an integrated EAP server
@ -912,6 +977,23 @@ eap_server=0
# Passphrase for private key
#private_key_passwd=secret passphrase
# An alternative server certificate and private key can be configured with the
# following parameters (with values just like the parameters above without the
# '2' suffix). The ca_cert file (in PEM encoding) is used to add the trust roots
# for both server certificates and/or client certificates).
#
# The main use case for this alternative server certificate configuration is to
# enable both RSA and ECC public keys. The server will pick which one to use
# based on the client preferences for the cipher suite (in the TLS ClientHello
# message). It should be noted that number of deployed EAP peer implementations
# do not filter out the cipher suite list based on their local configuration and
# as such, configuration of alternative types of certificates on the server may
# result in interoperability issues.
#server_cert2=/etc/hostapd.server-ecc.pem
#private_key2=/etc/hostapd.server-ecc.prv
#private_key_passwd2=secret passphrase
# Server identity
# EAP methods that provide mechanism for authenticated server identity delivery
# use this value. If not set, "hostapd" is used as a default.
@ -1109,10 +1191,27 @@ eap_server=0
# (or fewer) of the lifetime remains.
#pac_key_refresh_time=86400
# EAP-TEAP authentication type
# 0 = inner EAP (default)
# 1 = Basic-Password-Auth
#eap_teap_auth=0
# EAP-TEAP authentication behavior when using PAC
# 0 = perform inner authentication (default)
# 1 = skip inner authentication (inner EAP/Basic-Password-Auth)
#eap_teap_pac_no_inner=0
# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
# (default: 0 = disabled).
#eap_sim_aka_result_ind=1
# EAP-SIM and EAP-AKA identity options
# 0 = do not use pseudonyms or fast reauthentication
# 1 = use pseudonyms, but not fast reauthentication
# 2 = do not use pseudonyms, but use fast reauthentication
# 3 = use pseudonyms and use fast reauthentication (default)
#eap_sim_id=3
# Trusted Network Connect (TNC)
# If enabled, TNC validation will be required before the peer is allowed to
# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
@ -1292,6 +1391,17 @@ own_ip_addr=127.0.0.1
# Operator-Name = "Operator"
#radius_acct_req_attr=126:s:Operator
# If SQLite support is included, path to a database from which additional
# RADIUS request attributes are extracted based on the station MAC address.
#
# The schema for the radius_attributes table is:
# id | sta | reqtype | attr : multi-key (sta, reqtype)
# id = autonumber
# sta = station MAC address in `11:22:33:44:55:66` format.
# type = `auth` | `acct` | NULL (match any)
# attr = existing config file format, e.g. `126:s:Test Operator`
#radius_req_attr_sqlite=radius_attr.sqlite
# Dynamic Authorization Extensions (RFC 5176)
# This mechanism can be used to allow dynamic changes to user session based on
# commands from a RADIUS server (or some other disconnect client that has the
@ -2492,6 +2602,42 @@ own_ip_addr=127.0.0.1
# that allows sending of such data. Default: 0.
#stationary_ap=0
##### Airtime policy configuration ###########################################
# Set the airtime policy operating mode:
# 0 = disabled (default)
# 1 = static config
# 2 = per-BSS dynamic config
# 3 = per-BSS limit mode
#airtime_mode=0
# Interval (in milliseconds) to poll the kernel for updated station activity in
# dynamic and limit modes
#airtime_update_interval=200
# Static configuration of station weights (when airtime_mode=1). Kernel default
# weight is 256; set higher for larger airtime share, lower for smaller share.
# Each entry is a MAC address followed by a weight.
#airtime_sta_weight=02:01:02:03:04:05 256
#airtime_sta_weight=02:01:02:03:04:06 512
# Per-BSS airtime weight. In multi-BSS mode, set for each BSS and hostapd will
# configure station weights to enforce the correct ratio between BSS weights
# depending on the number of active stations. The *ratios* between different
# BSSes is what's important, not the absolute numbers.
# Must be set for all BSSes if airtime_mode=2 or 3, has no effect otherwise.
#airtime_bss_weight=1
# Whether the current BSS should be limited (when airtime_mode=3).
#
# If set, the BSS weight ratio will be applied in the case where the current BSS
# would exceed the share defined by the BSS weight ratio. E.g., if two BSSes are
# set to the same weights, and one is set to limited, the limited BSS will get
# no more than half the available airtime, but if the non-limited BSS has more
# stations active, that *will* be allowed to exceed its half of the available
# airtime.
#airtime_bss_limit=1
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration

View file

@ -1214,6 +1214,13 @@ static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
}
static int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_ctrl_command(ctrl, "UPDATE_BEACON");
}
static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@ -1617,6 +1624,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"= reload configuration for current interface" },
{ "disable", hostapd_cli_cmd_disable, NULL,
"= disable hostapd on current interface" },
{ "update_beacon", hostapd_cli_cmd_update_beacon, NULL,
"= update Beacon frame contents\n"},
{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
"= drop all ERP keys"},
{ "log_level", hostapd_cli_cmd_log_level, NULL,

View file

@ -653,6 +653,9 @@ int main(int argc, char *argv[])
int start_ifaces_in_sync = 0;
char **if_names = NULL;
size_t if_names_size = 0;
#ifdef CONFIG_DPP
struct dpp_global_config dpp_conf;
#endif /* CONFIG_DPP */
if (os_program_init())
return -1;
@ -672,7 +675,9 @@ int main(int argc, char *argv[])
dl_list_init(&interfaces.eth_p_oui);
#endif /* CONFIG_ETH_P_OUI */
#ifdef CONFIG_DPP
interfaces.dpp = dpp_global_init();
os_memset(&dpp_conf, 0, sizeof(dpp_conf));
/* TODO: dpp_conf.msg_ctx? */
interfaces.dpp = dpp_global_init(&dpp_conf);
if (!interfaces.dpp)
return -1;
#endif /* CONFIG_DPP */

View file

@ -1588,6 +1588,7 @@ static void set_pps_cred_digital_cert(struct hs20_osu_client *ctx, int id,
xml_node_t *node, const char *fqdn)
{
char buf[200], dir[200];
int res;
wpa_printf(MSG_INFO, "- Credential/DigitalCertificate");
@ -1599,14 +1600,20 @@ static void set_pps_cred_digital_cert(struct hs20_osu_client *ctx, int id,
wpa_printf(MSG_INFO, "Failed to set username");
}
snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir, fqdn);
res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir,
fqdn);
if (os_snprintf_error(sizeof(buf), res))
return;
if (os_file_exists(buf)) {
if (set_cred_quoted(ctx->ifname, id, "client_cert", buf) < 0) {
wpa_printf(MSG_INFO, "Failed to set client_cert");
}
}
snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir, fqdn);
res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir,
fqdn);
if (os_snprintf_error(sizeof(buf), res))
return;
if (os_file_exists(buf)) {
if (set_cred_quoted(ctx->ifname, id, "private_key", buf) < 0) {
wpa_printf(MSG_INFO, "Failed to set private_key");
@ -1620,6 +1627,7 @@ static void set_pps_cred_realm(struct hs20_osu_client *ctx, int id,
{
char *str = xml_node_get_text(ctx->xml, node);
char buf[200], dir[200];
int res;
if (str == NULL)
return;
@ -1634,7 +1642,9 @@ static void set_pps_cred_realm(struct hs20_osu_client *ctx, int id,
if (getcwd(dir, sizeof(dir)) == NULL)
return;
snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn);
res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn);
if (os_snprintf_error(sizeof(buf), res))
return;
if (os_file_exists(buf)) {
if (set_cred_quoted(ctx->ifname, id, "ca_cert", buf) < 0) {
wpa_printf(MSG_INFO, "Failed to set CA cert");
@ -2717,6 +2727,8 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
if (!pps_fname) {
char buf[256];
int res;
wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
if (address && os_strncmp(address, "fqdn=", 5) == 0) {
wpa_printf(MSG_INFO, "Use requested FQDN from command line");
@ -2737,8 +2749,13 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
"SP/%s/pps.xml", ctx->fqdn);
pps_fname = pps_fname_buf;
os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem",
buf);
res = os_snprintf(ca_fname_buf, sizeof(ca_fname_buf),
"SP/%s/ca.pem", buf);
if (os_snprintf_error(sizeof(ca_fname_buf), res)) {
os_free(ctx->fqdn);
ctx->fqdn = NULL;
return -1;
}
ca_fname = ca_fname_buf;
}

View file

@ -97,6 +97,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
msg) < 0)
goto fail;
if (sta && add_sqlite_radius_attr(hapd, sta, msg, 1) < 0)
goto fail;
if (sta) {
for (i = 0; ; i++) {
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,

View file

@ -594,12 +594,12 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
iface->conf->secondary_channel)
n_chans = 2;
if (iface->conf->ieee80211ac) {
switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_80MHZ:
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_80MHZ:
n_chans = 4;
break;
case VHT_CHANWIDTH_160MHZ:
case CHANWIDTH_160MHZ:
n_chans = 8;
break;
}
@ -607,7 +607,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
bw = num_chan_to_bw(n_chans);
/* TODO: VHT80+80. Update acs_adjust_vht_center_freq() too. */
/* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */
wpa_printf(MSG_DEBUG,
"ACS: Survey analysis for selected bandwidth %d MHz", bw);
@ -647,9 +647,9 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
}
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
iface->conf->ieee80211ac) {
if (iface->conf->vht_oper_chwidth ==
VHT_CHANWIDTH_80MHZ &&
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_80MHZ &&
!acs_usable_vht80_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for VHT80",
@ -657,8 +657,8 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
continue;
}
if (iface->conf->vht_oper_chwidth ==
VHT_CHANWIDTH_160MHZ &&
if (hostapd_get_oper_chwidth(iface->conf) ==
CHANWIDTH_160MHZ &&
!acs_usable_vht160_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for VHT160",
@ -783,20 +783,20 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
}
static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
static void acs_adjust_center_freq(struct hostapd_iface *iface)
{
int offset;
wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_USE_HT:
offset = 2 * iface->conf->secondary_channel;
break;
case VHT_CHANWIDTH_80MHZ:
case CHANWIDTH_80MHZ:
offset = 6;
break;
case VHT_CHANWIDTH_160MHZ:
case CHANWIDTH_160MHZ:
offset = 14;
break;
default:
@ -807,8 +807,8 @@ static void acs_adjust_vht_center_freq(struct hostapd_iface *iface)
return;
}
iface->conf->vht_oper_centr_freq_seg0_idx =
iface->conf->channel + offset;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
iface->conf->channel + offset);
}
@ -863,8 +863,8 @@ static void acs_study(struct hostapd_iface *iface)
iface->conf->channel = ideal_chan->chan;
if (iface->conf->ieee80211ac)
acs_adjust_vht_center_freq(iface);
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
acs_adjust_center_freq(iface);
err = 0;
fail:

View file

@ -0,0 +1,269 @@
/*
* Airtime policy configuration
* Copyright (c) 2018-2019, Toke Høiland-Jørgensen <toke@toke.dk>
*
* 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/eloop.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "sta_info.h"
#include "airtime_policy.h"
/* Idea:
* Two modes of airtime enforcement:
* 1. Static weights: specify weights per MAC address with a per-BSS default
* 2. Per-BSS limits: Dynamically calculate weights of backlogged stations to
* enforce relative total shares between BSSes.
*
* - Periodic per-station callback to update queue status.
*
* Copy accounting_sta_update_stats() to get TXQ info and airtime weights and
* keep them updated in sta_info.
*
* - Separate periodic per-bss (or per-iface?) callback to update weights.
*
* Just need to loop through all interfaces, count sum the active stations (or
* should the per-STA callback just adjust that for the BSS?) and calculate new
* weights.
*/
static int get_airtime_policy_update_timeout(struct hostapd_iface *iface,
unsigned int *sec,
unsigned int *usec)
{
unsigned int update_int = iface->conf->airtime_update_interval;
if (!update_int) {
wpa_printf(MSG_ERROR,
"Airtime policy: Invalid airtime policy update interval %u",
update_int);
return -1;
}
*sec = update_int / 1000;
*usec = (update_int % 1000) * 1000;
return 0;
}
static void set_new_backlog_time(struct hostapd_data *hapd,
struct sta_info *sta,
struct os_reltime *now)
{
sta->backlogged_until = *now;
sta->backlogged_until.usec += hapd->iconf->airtime_update_interval *
AIRTIME_BACKLOG_EXPIRY_FACTOR;
while (sta->backlogged_until.usec >= 1000000) {
sta->backlogged_until.sec++;
sta->backlogged_until.usec -= 1000000;
}
}
static void count_backlogged_sta(struct hostapd_data *hapd)
{
struct sta_info *sta;
struct hostap_sta_driver_data data = {};
unsigned int num_backlogged = 0;
struct os_reltime now;
os_get_reltime(&now);
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (hostapd_drv_read_sta_data(hapd, &data, sta->addr))
continue;
if (data.backlog_bytes > 0)
set_new_backlog_time(hapd, sta, &now);
if (os_reltime_before(&now, &sta->backlogged_until))
num_backlogged++;
}
hapd->num_backlogged_sta = num_backlogged;
}
static int sta_set_airtime_weight(struct hostapd_data *hapd,
struct sta_info *sta,
unsigned int weight)
{
int ret = 0;
if (weight != sta->airtime_weight &&
(ret = hostapd_sta_set_airtime_weight(hapd, sta->addr, weight)))
return ret;
sta->airtime_weight = weight;
return ret;
}
static void set_sta_weights(struct hostapd_data *hapd, unsigned int weight)
{
struct sta_info *sta;
for (sta = hapd->sta_list; sta; sta = sta->next)
sta_set_airtime_weight(hapd, sta, weight);
}
static unsigned int get_airtime_quantum(unsigned int max_wt)
{
unsigned int quantum = AIRTIME_QUANTUM_TARGET / max_wt;
if (quantum < AIRTIME_QUANTUM_MIN)
quantum = AIRTIME_QUANTUM_MIN;
else if (quantum > AIRTIME_QUANTUM_MAX)
quantum = AIRTIME_QUANTUM_MAX;
return quantum;
}
static void update_airtime_weights(void *eloop_data, void *user_data)
{
struct hostapd_iface *iface = eloop_data;
struct hostapd_data *bss;
unsigned int sec, usec;
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;
int wt, num_bss = 0, max_wt = 0;
size_t i;
for (i = 0; i < iface->num_bss; i++) {
bss = iface->bss[i];
if (!bss->started || !bss->conf->airtime_weight)
continue;
count_backlogged_sta(bss);
if (!bss->num_backlogged_sta)
continue;
if (!num_sta_min || bss->num_backlogged_sta < num_sta_min)
num_sta_min = bss->num_backlogged_sta;
num_sta_prod *= bss->num_backlogged_sta;
num_sta_sum += bss->num_backlogged_sta;
wt_sum += bss->conf->airtime_weight;
num_bss++;
}
if (num_sta_min) {
for (i = 0; i < iface->num_bss; i++) {
bss = iface->bss[i];
if (!bss->started || !bss->conf->airtime_weight)
continue;
/* Check if we can divide all sta numbers by the
* smallest number to keep weights as small as possible.
* This is a lazy way to avoid having to factor
* integers. */
if (bss->num_backlogged_sta &&
bss->num_backlogged_sta % num_sta_min > 0)
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
* larger share than the relative BSS weights indicates
* it should. */
if (!apply_limit && bss->conf->airtime_limit) {
if (bss->num_backlogged_sta * wt_sum >
bss->conf->airtime_weight * num_sta_sum)
apply_limit = TRUE;
}
}
if (all_div_min)
num_sta_prod /= num_sta_min;
}
for (i = 0; i < iface->num_bss; i++) {
bss = iface->bss[i];
if (!bss->started || !bss->conf->airtime_weight)
continue;
/* We only set the calculated weight if the BSS has active
* stations and there are other active interfaces as well -
* otherwise we just set a unit weight. This ensures that
* the weights are set reasonably when stations transition from
* inactive to active. */
if (apply_limit && bss->num_backlogged_sta && num_bss > 1)
wt = bss->conf->airtime_weight * num_sta_prod /
bss->num_backlogged_sta;
else
wt = 1;
bss->airtime_weight = wt;
if (wt > max_wt)
max_wt = wt;
}
quantum = get_airtime_quantum(max_wt);
for (i = 0; i < iface->num_bss; i++) {
bss = iface->bss[i];
if (!bss->started || !bss->conf->airtime_weight)
continue;
set_sta_weights(bss, bss->airtime_weight * quantum);
}
if (get_airtime_policy_update_timeout(iface, &sec, &usec) < 0)
return;
eloop_register_timeout(sec, usec, update_airtime_weights, iface,
NULL);
}
static int get_weight_for_sta(struct hostapd_data *hapd, const u8 *sta)
{
struct airtime_sta_weight *wt;
wt = hapd->conf->airtime_weight_list;
while (wt && os_memcmp(wt->addr, sta, ETH_ALEN) != 0)
wt = wt->next;
return wt ? wt->weight : hapd->conf->airtime_weight;
}
int airtime_policy_new_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
unsigned int weight;
if (hapd->iconf->airtime_mode == AIRTIME_MODE_STATIC) {
weight = get_weight_for_sta(hapd, sta->addr);
if (weight)
return sta_set_airtime_weight(hapd, sta, weight);
}
return 0;
}
int airtime_policy_update_init(struct hostapd_iface *iface)
{
unsigned int sec, usec;
if (iface->conf->airtime_mode < AIRTIME_MODE_DYNAMIC)
return 0;
if (get_airtime_policy_update_timeout(iface, &sec, &usec) < 0)
return -1;
eloop_register_timeout(sec, usec, update_airtime_weights, iface, NULL);
return 0;
}
void airtime_policy_update_deinit(struct hostapd_iface *iface)
{
eloop_cancel_timeout(update_airtime_weights, iface, NULL);
}

View file

@ -0,0 +1,48 @@
/*
* Airtime policy configuration
* Copyright (c) 2018-2019, Toke Høiland-Jørgensen <toke@toke.dk>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef AIRTIME_POLICY_H
#define AIRTIME_POLICY_H
struct hostapd_iface;
#ifdef CONFIG_AIRTIME_POLICY
#define AIRTIME_DEFAULT_UPDATE_INTERVAL 200 /* ms */
#define AIRTIME_BACKLOG_EXPIRY_FACTOR 2500 /* 2.5 intervals + convert to usec */
/* scale quantum so this becomes the effective quantum after applying the max
* weight, but never go below min or above max */
#define AIRTIME_QUANTUM_MIN 8 /* usec */
#define AIRTIME_QUANTUM_MAX 256 /* usec */
#define AIRTIME_QUANTUM_TARGET 1024 /* usec */
int airtime_policy_new_sta(struct hostapd_data *hapd, struct sta_info *sta);
int airtime_policy_update_init(struct hostapd_iface *iface);
void airtime_policy_update_deinit(struct hostapd_iface *iface);
#else /* CONFIG_AIRTIME_POLICY */
static inline int airtime_policy_new_sta(struct hostapd_data *hapd,
struct sta_info *sta)
{
return -1;
}
static inline int airtime_policy_update_init(struct hostapd_iface *iface)
{
return -1;
}
static inline void airtime_policy_update_deinit(struct hostapd_iface *iface)
{
}
#endif /* CONFIG_AIRTIME_POLICY */
#endif /* AIRTIME_POLICY_H */

View file

@ -13,12 +13,14 @@
#include "crypto/tls.h"
#include "radius/radius_client.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_1x_defs.h"
#include "common/eapol_common.h"
#include "common/dhcp.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
#include "sta_info.h"
#include "airtime_policy.h"
#include "ap_config.h"
@ -76,6 +78,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->radius_server_auth_port = 1812;
bss->eap_sim_db_timeout = 1;
bss->eap_sim_id = 3;
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
bss->eapol_version = EAPOL_VERSION;
@ -138,6 +141,11 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->hs20_release = (HS20_VERSION >> 4) + 1;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MACSEC
bss->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
bss->macsec_port = 1;
#endif /* CONFIG_MACSEC */
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
}
@ -236,6 +244,13 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->acs_num_scans = 5;
#endif /* CONFIG_ACS */
#ifdef CONFIG_IEEE80211AX
conf->he_op.he_rts_threshold = HE_OPERATION_RTS_THRESHOLD_MASK >>
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;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
* by default to indicate that the regulations encompass all
* environments for the current frequency band in the country. */
@ -244,6 +259,10 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->rssi_reject_assoc_rssi = 0;
conf->rssi_reject_assoc_timeout = 30;
#ifdef CONFIG_AIRTIME_POLICY
conf->airtime_update_interval = AIRTIME_DEFAULT_UPDATE_INTERVAL;
#endif /* CONFIG_AIRTIME_POLICY */
return conf;
}
@ -458,7 +477,76 @@ hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
}
static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value)
{
const char *pos;
char syntax;
struct hostapd_radius_attr *attr;
size_t len;
attr = os_zalloc(sizeof(*attr));
if (!attr)
return NULL;
attr->type = atoi(value);
pos = os_strchr(value, ':');
if (!pos) {
attr->val = wpabuf_alloc(1);
if (!attr->val) {
os_free(attr);
return NULL;
}
wpabuf_put_u8(attr->val, 0);
return attr;
}
pos++;
if (pos[0] == '\0' || pos[1] != ':') {
os_free(attr);
return NULL;
}
syntax = *pos++;
pos++;
switch (syntax) {
case 's':
attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
break;
case 'x':
len = os_strlen(pos);
if (len & 1)
break;
len /= 2;
attr->val = wpabuf_alloc(len);
if (!attr->val)
break;
if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
wpabuf_free(attr->val);
os_free(attr);
return NULL;
}
break;
case 'd':
attr->val = wpabuf_alloc(4);
if (attr->val)
wpabuf_put_be32(attr->val, atoi(pos));
break;
default:
os_free(attr);
return NULL;
}
if (!attr->val) {
os_free(attr);
return NULL;
}
return attr;
}
void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
{
struct hostapd_radius_attr *prev;
@ -559,8 +647,26 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
}
#ifdef CONFIG_DPP2
static void hostapd_dpp_controller_conf_free(struct dpp_controller_conf *conf)
{
struct dpp_controller_conf *prev;
while (conf) {
prev = conf;
conf = conf->next;
os_free(prev);
}
}
#endif /* CONFIG_DPP2 */
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
#if defined(CONFIG_WPS) || defined(CONFIG_HS20)
size_t i;
#endif
if (conf == NULL)
return;
@ -589,12 +695,16 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
}
hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
os_free(conf->radius_req_attr_sqlite);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
os_free(conf->ca_cert);
os_free(conf->server_cert);
os_free(conf->server_cert2);
os_free(conf->private_key);
os_free(conf->private_key2);
os_free(conf->private_key_passwd);
os_free(conf->private_key_passwd2);
os_free(conf->check_cert_subject);
os_free(conf->ocsp_stapling_response);
os_free(conf->ocsp_stapling_response_multi);
@ -653,12 +763,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
{
unsigned int i;
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
wpabuf_free(conf->wps_vendor_ext[i]);
}
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
wpabuf_free(conf->wps_vendor_ext[i]);
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@ -684,7 +790,6 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->hs20_operating_class);
os_free(conf->hs20_icons);
if (conf->hs20_osu_providers) {
size_t i;
for (i = 0; i < conf->hs20_osu_providers_count; i++) {
struct hs20_osu_provider *p;
size_t j;
@ -702,8 +807,6 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->hs20_osu_providers);
}
if (conf->hs20_operator_icon) {
size_t i;
for (i = 0; i < conf->hs20_operator_icon_count; i++)
os_free(conf->hs20_operator_icon[i]);
os_free(conf->hs20_operator_icon);
@ -740,10 +843,27 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->dpp_connector);
wpabuf_free(conf->dpp_netaccesskey);
wpabuf_free(conf->dpp_csign);
#ifdef CONFIG_DPP2
hostapd_dpp_controller_conf_free(conf->dpp_controller);
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
hostapd_config_free_sae_passwords(conf);
#ifdef CONFIG_AIRTIME_POLICY
{
struct airtime_sta_weight *wt, *wt_prev;
wt = conf->airtime_weight_list;
conf->airtime_weight_list = NULL;
while (wt) {
wt_prev = wt;
wt = wt->next;
os_free(wt_prev);
}
}
#endif /* CONFIG_AIRTIME_POLICY */
os_free(conf);
}
@ -1140,6 +1260,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
return -1;
}
#ifdef CONFIG_AIRTIME_POLICY
if (full_config && conf->airtime_mode > AIRTIME_MODE_STATIC &&
!conf->airtime_update_interval) {
wpa_printf(MSG_ERROR, "Airtime update interval cannot be zero");
return -1;
}
#endif /* CONFIG_AIRTIME_POLICY */
for (i = 0; i < NUM_TX_QUEUES; i++) {
if (hostapd_config_check_cw(conf, i))
return -1;

View file

@ -15,6 +15,7 @@
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "crypto/sha256.h"
#include "wps/wps.h"
#include "fst/fst.h"
#include "vlan.h"
@ -252,6 +253,18 @@ struct sae_password_entry {
int vlan_id;
};
struct dpp_controller_conf {
struct dpp_controller_conf *next;
u8 pkhash[SHA256_MAC_LEN];
struct hostapd_ip_addr ipaddr;
};
struct airtime_sta_weight {
struct airtime_sta_weight *next;
unsigned int weight;
u8 addr[ETH_ALEN];
};
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@ -288,6 +301,7 @@ struct hostapd_bss_config {
int radius_request_cui;
struct hostapd_radius_attr *radius_auth_req_attr;
struct hostapd_radius_attr *radius_acct_req_attr;
char *radius_req_attr_sqlite;
int radius_das_port;
unsigned int radius_das_time_window;
int radius_das_require_event_timestamp;
@ -390,8 +404,11 @@ struct hostapd_bss_config {
char *ca_cert;
char *server_cert;
char *server_cert2;
char *private_key;
char *private_key2;
char *private_key_passwd;
char *private_key_passwd2;
char *check_cert_subject;
int check_crl;
int check_crl_strict;
@ -410,7 +427,10 @@ struct hostapd_bss_config {
int eap_fast_prov;
int pac_key_lifetime;
int pac_key_refresh_time;
int eap_teap_auth;
int eap_teap_pac_no_inner;
int eap_sim_aka_result_ind;
int eap_sim_id;
int tnc;
int fragment_size;
u16 pwd_group;
@ -570,6 +590,7 @@ struct hostapd_bss_config {
int osen;
int proxy_arp;
int na_mcast_to_ucast;
#ifdef CONFIG_HS20
int hs20;
int hs20_release;
@ -692,6 +713,9 @@ struct hostapd_bss_config {
struct wpabuf *dpp_netaccesskey;
unsigned int dpp_netaccesskey_expiry;
struct wpabuf *dpp_csign;
#ifdef CONFIG_DPP2
struct dpp_controller_conf *dpp_controller;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_OWE
@ -709,6 +733,100 @@ struct hostapd_bss_config {
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
int airtime_limit;
struct airtime_sta_weight *airtime_weight_list;
#endif /* CONFIG_AIRTIME_POLICY */
#ifdef CONFIG_MACSEC
/**
* macsec_policy - Determines the policy for MACsec secure session
*
* 0: MACsec not in use (default)
* 1: MACsec enabled - Should secure, accept key server's advice to
* determine whether to use a secure session or not.
*/
int macsec_policy;
/**
* macsec_integ_only - Determines how MACsec are transmitted
*
* This setting applies only when MACsec is in use, i.e.,
* - macsec_policy is enabled
* - the key server has decided to enable MACsec
*
* 0: Encrypt traffic (default)
* 1: Integrity only
*/
int macsec_integ_only;
/**
* macsec_replay_protect - Enable MACsec replay protection
*
* This setting applies only when MACsec is in use, i.e.,
* - macsec_policy is enabled
* - the key server has decided to enable MACsec
*
* 0: Replay protection disabled (default)
* 1: Replay protection enabled
*/
int macsec_replay_protect;
/**
* macsec_replay_window - MACsec replay protection window
*
* A window in which replay is tolerated, to allow receipt of frames
* that have been misordered by the network.
*
* This setting applies only when MACsec replay protection active, i.e.,
* - macsec_replay_protect is enabled
* - the key server has decided to enable MACsec
*
* 0: No replay window, strict check (default)
* 1..2^32-1: number of packets that could be misordered
*/
u32 macsec_replay_window;
/**
* macsec_port - MACsec port (in SCI)
*
* Port component of the SCI.
*
* Range: 1-65534 (default: 1)
*/
int macsec_port;
/**
* mka_priority - Priority of MKA Actor
*
* Range: 0-255 (default: 255)
*/
int mka_priority;
/**
* mka_ckn - MKA pre-shared CKN
*/
#define MACSEC_CKN_MAX_LEN 32
size_t mka_ckn_len;
u8 mka_ckn[MACSEC_CKN_MAX_LEN];
/**
* mka_cak - MKA pre-shared CAK
*/
#define MACSEC_CAK_MAX_LEN 32
size_t mka_cak_len;
u8 mka_cak[MACSEC_CAK_MAX_LEN];
#define MKA_PSK_SET_CKN BIT(0)
#define MKA_PSK_SET_CAK BIT(1)
#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK)
/**
* mka_psk_set - Whether mka_ckn and mka_cak are set
*/
u8 mka_psk_set;
#endif /* CONFIG_MACSEC */
};
/**
@ -727,7 +845,20 @@ struct he_operation {
u8 he_bss_color;
u8 he_default_pe_duration;
u8 he_twt_required;
u8 he_rts_threshold;
u16 he_rts_threshold;
u16 he_basic_mcs_nss_set;
};
/**
* struct spatial_reuse - Spatial reuse
*/
struct spatial_reuse {
u8 sr_control;
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;
};
/**
@ -852,6 +983,10 @@ struct hostapd_config {
struct he_phy_capabilities_info he_phy_capab;
struct he_operation he_op;
struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
struct spatial_reuse spr;
u8 he_oper_chwidth;
u8 he_oper_centr_freq_seg0_idx;
u8 he_oper_centr_freq_seg1_idx;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@ -861,12 +996,87 @@ struct hostapd_config {
int rssi_reject_assoc_rssi;
int rssi_reject_assoc_timeout;
#ifdef CONFIG_AIRTIME_POLICY
enum {
AIRTIME_MODE_OFF = 0,
AIRTIME_MODE_STATIC = 1,
AIRTIME_MODE_DYNAMIC = 2,
AIRTIME_MODE_LIMIT = 3,
__AIRTIME_MODE_MAX,
} airtime_mode;
unsigned int airtime_update_interval;
#define AIRTIME_MODE_MAX (__AIRTIME_MODE_MAX - 1)
#endif /* CONFIG_AIRTIME_POLICY */
};
static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
{
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
return conf->he_oper_chwidth;
#endif /* CONFIG_IEEE80211AX */
return conf->vht_oper_chwidth;
}
static inline void
hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
{
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
conf->he_oper_chwidth = oper_chwidth;
#endif /* CONFIG_IEEE80211AX */
conf->vht_oper_chwidth = oper_chwidth;
}
static inline u8
hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf)
{
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
return conf->he_oper_centr_freq_seg0_idx;
#endif /* CONFIG_IEEE80211AX */
return conf->vht_oper_centr_freq_seg0_idx;
}
static inline void
hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
u8 oper_centr_freq_seg0_idx)
{
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
#endif /* CONFIG_IEEE80211AX */
conf->vht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
}
static inline u8
hostapd_get_oper_centr_freq_seg1_idx(struct hostapd_config *conf)
{
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
return conf->he_oper_centr_freq_seg1_idx;
#endif /* CONFIG_IEEE80211AX */
return conf->vht_oper_centr_freq_seg1_idx;
}
static inline void
hostapd_set_oper_centr_freq_seg1_idx(struct hostapd_config *conf,
u8 oper_centr_freq_seg1_idx)
{
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
conf->he_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
#endif /* CONFIG_IEEE80211AX */
conf->vht_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
}
int hostapd_mac_comp(const void *a, const void *b);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr);
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
@ -885,6 +1095,7 @@ const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
struct hostapd_radius_attr * hostapd_parse_radius_attr(const char *value);
int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);

View file

@ -413,6 +413,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set)
{
@ -432,6 +434,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
params.vht_capabilities = vht_capab;
params.he_capab = he_capab;
params.he_capab_len = he_capab_len;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
@ -537,17 +541,20 @@ 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 sec_channel_offset, int vht_oper_chwidth,
int he_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
{
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,
vht_enabled, sec_channel_offset,
vht_oper_chwidth,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth,
center_segment0, center_segment1,
hapd->iface->current_mode ?
hapd->iface->current_mode->vht_capab : 0))
cmode ? cmode->vht_capab : 0,
cmode ?
&cmode->he_capab[IEEE80211_MODE_AP] : NULL))
return -1;
if (hapd->driver == NULL)
@ -583,6 +590,16 @@ int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
}
int hostapd_sta_set_airtime_weight(struct hostapd_data *hapd, const u8 *addr,
unsigned int weight)
{
if (!hapd->driver || !hapd->driver->sta_set_airtime_weight)
return 0;
return hapd->driver->sta_set_airtime_weight(hapd->drv_priv, addr,
weight);
}
int hostapd_set_country(struct hostapd_data *hapd, const char *country)
{
if (hapd->driver == NULL ||
@ -775,14 +792,16 @@ int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int he_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_freq_params data;
int res;
struct hostapd_hw_modes *cmode = iface->current_mode;
if (!hapd->driver || !hapd->driver->start_dfs_cac)
if (!hapd->driver || !hapd->driver->start_dfs_cac || !cmode)
return 0;
if (!iface->conf->ieee80211h) {
@ -792,10 +811,11 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
}
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
vht_enabled, sec_channel_offset,
vht_oper_chwidth, center_segment0,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth, center_segment0,
center_segment1,
iface->current_mode->vht_capab)) {
cmode->vht_capab,
&cmode->he_capab[IEEE80211_MODE_AP])) {
wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
}
@ -919,15 +939,17 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
params.ch_width = 40;
/* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
/* Note: VHT20 is defined by combination of ht_capab & oper_chwidth
*/
if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
if ((hapd->iface->conf->ieee80211ax ||
hapd->iface->conf->ieee80211ac) &&
params.ht40_enabled) {
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
if (oper_chwidth == CHANWIDTH_80MHZ)
params.ch_width = 80;
else if (hapd->iface->conf->vht_oper_chwidth ==
VHT_CHANWIDTH_160MHZ ||
hapd->iface->conf->vht_oper_chwidth ==
VHT_CHANWIDTH_80P80MHZ)
else if (oper_chwidth == CHANWIDTH_160MHZ ||
oper_chwidth == CHANWIDTH_80P80MHZ)
params.ch_width = 160;
}
@ -936,3 +958,13 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
return ret;
}
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen)
{
if (!hapd->driver || !hapd->driver->update_dh_ie || !hapd->drv_priv)
return 0;
return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
ie, ielen);
}

View file

@ -41,6 +41,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
@ -61,12 +63,14 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
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 sec_channel_offset, int vht_oper_chwidth,
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);
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);
int hostapd_sta_set_airtime_weight(struct hostapd_data *hapd, const u8 *addr,
unsigned int weight);
int hostapd_set_country(struct hostapd_data *hapd, const char *country);
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time);
@ -122,9 +126,12 @@ int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int he_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
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);
#include "drivers/driver.h"

View file

@ -120,7 +120,10 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
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;
@ -195,7 +198,8 @@ int authsrv_init(struct hostapd_data *hapd)
#ifdef EAP_TLS_FUNCS
if (hapd->conf->eap_server &&
(hapd->conf->ca_cert || hapd->conf->server_cert ||
hapd->conf->private_key || hapd->conf->dh_file)) {
hapd->conf->private_key || hapd->conf->dh_file ||
hapd->conf->server_cert2 || hapd->conf->private_key2)) {
struct tls_config conf;
struct tls_connection_params params;
@ -224,8 +228,11 @@ int authsrv_init(struct hostapd_data *hapd)
os_memset(&params, 0, sizeof(params));
params.ca_cert = hapd->conf->ca_cert;
params.client_cert = hapd->conf->server_cert;
params.client_cert2 = hapd->conf->server_cert2;
params.private_key = hapd->conf->private_key;
params.private_key2 = hapd->conf->private_key2;
params.private_key_passwd = hapd->conf->private_key_passwd;
params.private_key_passwd2 = hapd->conf->private_key_passwd2;
params.dh_file = hapd->conf->dh_file;
params.openssl_ciphers = hapd->conf->openssl_ciphers;
params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves;

View file

@ -347,7 +347,7 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
hapd->iconf->secondary_channel,
hapd->iconf->vht_oper_chwidth,
hostapd_get_oper_chwidth(hapd->iconf),
&op_class, &channel) ==
NUM_HOSTAPD_MODES)
return eid;
@ -398,7 +398,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
if (hapd->iconf->ieee80211ax) {
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_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
}
#endif /* CONFIG_IEEE80211AX */
@ -509,9 +510,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
pos = hostapd_eid_he_capab(hapd, pos);
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);
}
#endif /* CONFIG_IEEE80211AX */
@ -593,7 +595,7 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
pos = ssid_list;
end = ssid_list + ssid_list_len;
while (end - pos >= 1) {
while (end - pos >= 2) {
if (2 + pos[1] > end - pos)
break;
if (pos[1] == 0)
@ -1088,7 +1090,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
if (hapd->iconf->ieee80211ax) {
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_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
}
#endif /* CONFIG_IEEE80211AX */
@ -1223,9 +1226,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
tailpos = hostapd_eid_he_capab(hapd, tailpos);
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);
}
#endif /* CONFIG_IEEE80211AX */
@ -1394,6 +1399,7 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
struct hostapd_freq_params freq;
struct hostapd_iface *iface = hapd->iface;
struct hostapd_config *iconf = iface->conf;
struct hostapd_hw_modes *cmode = iface->current_mode;
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
@ -1417,15 +1423,16 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
params.reenable = hapd->reenable_beacon;
hapd->reenable_beacon = 0;
if (iface->current_mode &&
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
iconf->channel, iconf->ieee80211n,
iconf->ieee80211ac,
iconf->ieee80211ac, iconf->ieee80211ax,
iconf->secondary_channel,
iconf->vht_oper_chwidth,
iconf->vht_oper_centr_freq_seg0_idx,
iconf->vht_oper_centr_freq_seg1_idx,
iface->current_mode->vht_capab) == 0)
hostapd_get_oper_chwidth(iconf),
hostapd_get_oper_centr_freq_seg0_idx(iconf),
hostapd_get_oper_centr_freq_seg1_idx(iconf),
cmode->vht_capab,
&cmode->he_capab[IEEE80211_MODE_AP]) == 0)
params.freq = &freq;
res = hostapd_drv_set_ap(hapd, &params);

View file

@ -712,6 +712,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
"secondary_channel=%d\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
"ieee80211ax=%d\n"
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
@ -720,6 +721,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
iface->conf->ieee80211n && !hapd->conf->disable_11n,
iface->conf->ieee80211ac &&
!hapd->conf->disable_11ac,
iface->conf->ieee80211ax,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))

View file

@ -28,17 +28,17 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
if (iface->conf->ieee80211n && iface->conf->secondary_channel)
n_chans = 2;
if (iface->conf->ieee80211ac) {
switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_USE_HT:
break;
case VHT_CHANWIDTH_80MHZ:
case CHANWIDTH_80MHZ:
n_chans = 4;
break;
case VHT_CHANWIDTH_160MHZ:
case CHANWIDTH_160MHZ:
n_chans = 8;
break;
case VHT_CHANWIDTH_80P80MHZ:
case CHANWIDTH_80P80MHZ:
n_chans = 4;
*seg1 = 4;
break;
@ -188,8 +188,8 @@ static int is_in_chanlist(struct hostapd_iface *iface,
* The function assumes HT40+ operation.
* Make sure to adjust the following variables after calling this:
* - hapd->secondary_channel
* - hapd->vht_oper_centr_freq_seg0_idx
* - hapd->vht_oper_centr_freq_seg1_idx
* - hapd->vht/he_oper_centr_freq_seg0_idx
* - hapd->vht/he_oper_centr_freq_seg1_idx
*/
static int dfs_find_channel(struct hostapd_iface *iface,
struct hostapd_channel_data **ret_chan,
@ -232,44 +232,44 @@ static int dfs_find_channel(struct hostapd_iface *iface,
}
static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
struct hostapd_channel_data *chan,
int secondary_channel,
u8 *vht_oper_centr_freq_seg0_idx,
u8 *vht_oper_centr_freq_seg1_idx)
static void dfs_adjust_center_freq(struct hostapd_iface *iface,
struct hostapd_channel_data *chan,
int secondary_channel,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx)
{
if (!iface->conf->ieee80211ac)
if (!iface->conf->ieee80211ac && !iface->conf->ieee80211ax)
return;
if (!chan)
return;
*vht_oper_centr_freq_seg1_idx = 0;
*oper_centr_freq_seg1_idx = 0;
switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_USE_HT:
if (secondary_channel == 1)
*vht_oper_centr_freq_seg0_idx = chan->chan + 2;
*oper_centr_freq_seg0_idx = chan->chan + 2;
else if (secondary_channel == -1)
*vht_oper_centr_freq_seg0_idx = chan->chan - 2;
*oper_centr_freq_seg0_idx = chan->chan - 2;
else
*vht_oper_centr_freq_seg0_idx = chan->chan;
*oper_centr_freq_seg0_idx = chan->chan;
break;
case VHT_CHANWIDTH_80MHZ:
*vht_oper_centr_freq_seg0_idx = chan->chan + 6;
case CHANWIDTH_80MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 6;
break;
case VHT_CHANWIDTH_160MHZ:
*vht_oper_centr_freq_seg0_idx = chan->chan + 14;
case CHANWIDTH_160MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 14;
break;
default:
wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
*vht_oper_centr_freq_seg0_idx = 0;
*oper_centr_freq_seg0_idx = 0;
break;
}
wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
*vht_oper_centr_freq_seg0_idx,
*vht_oper_centr_freq_seg1_idx);
*oper_centr_freq_seg0_idx,
*oper_centr_freq_seg1_idx);
}
@ -288,24 +288,24 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
channel_no -= 4;
/* VHT */
if (iface->conf->ieee80211ac) {
switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
/* VHT/HE */
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
case CHANWIDTH_USE_HT:
break;
case VHT_CHANWIDTH_80MHZ:
channel_no =
iface->conf->vht_oper_centr_freq_seg0_idx - 6;
case CHANWIDTH_80MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 6;
break;
case VHT_CHANWIDTH_160MHZ:
channel_no =
iface->conf->vht_oper_centr_freq_seg0_idx - 14;
case CHANWIDTH_160MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 14;
break;
case VHT_CHANWIDTH_80P80MHZ:
channel_no =
iface->conf->vht_oper_centr_freq_seg0_idx - 6;
chan_seg1 =
iface->conf->vht_oper_centr_freq_seg1_idx - 6;
case CHANWIDTH_80P80MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 6;
chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
iface->conf) - 6;
break;
default:
wpa_printf(MSG_INFO,
@ -348,7 +348,7 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start)
mode->num_channels, channel_no, iface->conf->channel,
iface->conf->ieee80211n,
iface->conf->secondary_channel,
iface->conf->vht_oper_chwidth);
hostapd_get_oper_chwidth(iface->conf));
for (i = 0; i < mode->num_channels; i++) {
wpa_printf(MSG_DEBUG, "Available channel: %d",
@ -435,8 +435,8 @@ static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
static struct hostapd_channel_data *
dfs_get_valid_channel(struct hostapd_iface *iface,
int *secondary_channel,
u8 *vht_oper_centr_freq_seg0_idx,
u8 *vht_oper_centr_freq_seg1_idx,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx,
int skip_radar)
{
struct hostapd_hw_modes *mode;
@ -447,8 +447,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
*secondary_channel = 0;
*vht_oper_centr_freq_seg0_idx = 0;
*vht_oper_centr_freq_seg1_idx = 0;
*oper_centr_freq_seg0_idx = 0;
*oper_centr_freq_seg1_idx = 0;
if (iface->current_mode == NULL)
return NULL;
@ -473,10 +473,10 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
else
*secondary_channel = 0;
dfs_adjust_vht_center_freq(iface, chan,
*secondary_channel,
vht_oper_centr_freq_seg0_idx,
vht_oper_centr_freq_seg1_idx);
dfs_adjust_center_freq(iface, chan,
*secondary_channel,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx);
return chan;
}
@ -724,8 +724,8 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = sec;
iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
}
} while (res);
@ -736,20 +736,19 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
iface->freq,
iface->conf->channel, iface->conf->secondary_channel,
iface->conf->vht_oper_chwidth,
iface->conf->vht_oper_centr_freq_seg0_idx,
iface->conf->vht_oper_centr_freq_seg1_idx,
hostapd_get_oper_chwidth(iface->conf),
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
iface->dfs_cac_ms / 1000);
res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
iface->freq,
iface->conf->channel,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
iface->conf->secondary_channel,
iface->conf->vht_oper_chwidth,
iface->conf->vht_oper_centr_freq_seg0_idx,
iface->conf->vht_oper_centr_freq_seg1_idx);
res = hostapd_start_dfs_cac(
iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
iface->conf->ieee80211n, iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
iface->conf->secondary_channel,
hostapd_get_oper_chwidth(iface->conf),
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
if (res) {
wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
@ -842,16 +841,16 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
int secondary_channel;
u8 vht_oper_centr_freq_seg0_idx = 0;
u8 vht_oper_centr_freq_seg1_idx = 0;
u8 oper_centr_freq_seg0_idx = 0;
u8 oper_centr_freq_seg1_idx = 0;
int skip_radar = 0;
int err = 1;
/* Radar detected during active CAC */
iface->cac_started = 0;
channel = dfs_get_valid_channel(iface, &secondary_channel,
&vht_oper_centr_freq_seg0_idx,
&vht_oper_centr_freq_seg1_idx,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
@ -868,10 +867,10 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
iface->conf->vht_oper_centr_freq_seg0_idx =
vht_oper_centr_freq_seg0_idx;
iface->conf->vht_oper_centr_freq_seg1_idx =
vht_oper_centr_freq_seg1_idx;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
oper_centr_freq_seg1_idx);
err = 0;
hostapd_setup_interface_complete(iface, err);
@ -883,12 +882,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
int secondary_channel;
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
u8 oper_centr_freq_seg0_idx;
u8 oper_centr_freq_seg1_idx;
int skip_radar = 1;
struct csa_settings csa_settings;
unsigned int i;
int err = 1;
struct hostapd_hw_modes *cmode = iface->current_mode;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@ -911,8 +911,8 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
/* Perform channel switch/CSA */
channel = dfs_get_valid_channel(iface, &secondary_channel,
&vht_oper_centr_freq_seg0_idx,
&vht_oper_centr_freq_seg1_idx,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
@ -923,8 +923,8 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
*/
skip_radar = 0;
channel = dfs_get_valid_channel(iface, &secondary_channel,
&vht_oper_centr_freq_seg0_idx,
&vht_oper_centr_freq_seg1_idx,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
wpa_printf(MSG_INFO,
@ -936,10 +936,10 @@ 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;
iface->conf->vht_oper_centr_freq_seg0_idx =
vht_oper_centr_freq_seg0_idx;
iface->conf->vht_oper_centr_freq_seg1_idx =
vht_oper_centr_freq_seg1_idx;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
oper_centr_freq_seg1_idx);
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
@ -962,11 +962,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
channel->chan,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
secondary_channel,
iface->conf->vht_oper_chwidth,
vht_oper_centr_freq_seg0_idx,
vht_oper_centr_freq_seg1_idx,
iface->current_mode->vht_capab);
hostapd_get_oper_chwidth(iface->conf),
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
cmode->vht_capab,
&cmode->he_capab[IEEE80211_MODE_AP]);
if (err) {
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
@ -986,10 +988,10 @@ 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;
iface->conf->vht_oper_centr_freq_seg0_idx =
vht_oper_centr_freq_seg0_idx;
iface->conf->vht_oper_centr_freq_seg1_idx =
vht_oper_centr_freq_seg1_idx;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
oper_centr_freq_seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
oper_centr_freq_seg1_idx);
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);

View file

@ -16,6 +16,7 @@
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "gas_query_ap.h"
#include "gas_serv.h"
#include "wpa_auth.h"
#include "dpp_hostapd.h"
@ -557,6 +558,14 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
* received hash values */
dpp_bootstrap_find_pair(hapd->iface->interfaces->dpp, i_bootstrap,
r_bootstrap, &own_bi, &peer_bi);
#ifdef CONFIG_DPP2
if (!own_bi) {
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
src, hdr, buf, len, freq, i_bootstrap,
r_bootstrap) == 0)
return;
}
#endif /* CONFIG_DPP2 */
if (!own_bi) {
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"No matching own bootstrapping key found - ignore message");
@ -1357,6 +1366,12 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RX "src=" MACSTR
" freq=%u type=%d", MAC2STR(src), freq, type);
#ifdef CONFIG_DPP2
if (dpp_relay_rx_action(hapd->iface->interfaces->dpp,
src, hdr, buf, len, freq, NULL, NULL) == 0)
return;
#endif /* CONFIG_DPP2 */
switch (type) {
case DPP_PA_AUTHENTICATION_REQ:
hostapd_dpp_rx_auth_req(hapd, src, hdr, buf, len, freq);
@ -1410,7 +1425,8 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
struct wpabuf *
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
const u8 *query, size_t query_len)
const u8 *query, size_t query_len,
const u8 *data, size_t data_len)
{
struct dpp_authentication *auth = hapd->dpp_auth;
struct wpabuf *resp;
@ -1418,6 +1434,13 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
if (!auth || !auth->auth_success ||
os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
#ifdef CONFIG_DPP2
if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data,
data_len) == 0) {
/* Response will be forwarded once received over TCP */
return NULL;
}
#endif /* CONFIG_DPP2 */
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
}
@ -1609,11 +1632,67 @@ void hostapd_dpp_stop(struct hostapd_data *hapd)
}
#ifdef CONFIG_DPP2
static void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq,
const u8 *msg, size_t len)
{
struct hostapd_data *hapd = ctx;
u8 *buf;
wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u",
MAC2STR(addr), freq);
buf = os_malloc(2 + len);
if (!buf)
return;
buf[0] = WLAN_ACTION_PUBLIC;
buf[1] = WLAN_PA_VENDOR_SPECIFIC;
os_memcpy(buf + 2, msg, len);
hostapd_drv_send_action(hapd, freq, 0, addr, buf, 2 + len);
os_free(buf);
}
static void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr,
u8 dialog_token, int prot,
struct wpabuf *buf)
{
struct hostapd_data *hapd = ctx;
gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf);
}
#endif /* CONFIG_DPP2 */
static int hostapd_dpp_add_controllers(struct hostapd_data *hapd)
{
#ifdef CONFIG_DPP2
struct dpp_controller_conf *ctrl;
struct dpp_relay_config config;
os_memset(&config, 0, sizeof(config));
config.cb_ctx = hapd;
config.tx = hostapd_dpp_relay_tx;
config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx;
for (ctrl = hapd->conf->dpp_controller; ctrl; ctrl = ctrl->next) {
config.ipaddr = &ctrl->ipaddr;
config.pkhash = ctrl->pkhash;
if (dpp_relay_add_controller(hapd->iface->interfaces->dpp,
&config) < 0)
return -1;
}
#endif /* CONFIG_DPP2 */
return 0;
}
int hostapd_dpp_init(struct hostapd_data *hapd)
{
hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
hapd->dpp_init_done = 1;
return 0;
return hostapd_dpp_add_controllers(hapd);
}

View file

@ -19,7 +19,8 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
const u8 *data, size_t data_len, int ok);
struct wpabuf *
hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
const u8 *query, size_t query_len);
const u8 *query, size_t query_len,
const u8 *data, size_t data_len);
void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok);
int hostapd_dpp_configurator_add(struct hostapd_data *hapd, const char *cmd);
int hostapd_dpp_configurator_remove(struct hostapd_data *hapd, const char *id);

View file

@ -772,7 +772,8 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2)
int offset, int width, int cf1, int cf2,
int finished)
{
/* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
@ -783,10 +784,18 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"driver had 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, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
finished ? "had" : "starting",
freq, ht, hapd->iconf->ch_switch_vht_config, offset,
width, channel_width_to_string(width), cf1, cf2);
if (!hapd->iface->current_mode) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"ignore channel switch since the interface is not yet ready");
return;
}
hapd->iface->freq = freq;
channel = hostapd_hw_get_channel(hapd, freq);
@ -799,19 +808,19 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
switch (width) {
case CHAN_WIDTH_80:
chwidth = VHT_CHANWIDTH_80MHZ;
chwidth = CHANWIDTH_80MHZ;
break;
case CHAN_WIDTH_80P80:
chwidth = VHT_CHANWIDTH_80P80MHZ;
chwidth = CHANWIDTH_80P80MHZ;
break;
case CHAN_WIDTH_160:
chwidth = VHT_CHANWIDTH_160MHZ;
chwidth = CHANWIDTH_160MHZ;
break;
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
case CHAN_WIDTH_40:
default:
chwidth = VHT_CHANWIDTH_USE_HT;
chwidth = CHANWIDTH_USE_HT;
break;
}
@ -844,13 +853,22 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
hapd->iconf->ch_switch_vht_config = 0;
hapd->iconf->secondary_channel = offset;
hapd->iconf->vht_oper_chwidth = chwidth;
hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
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);
is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
hapd->iface->num_hw_features);
wpa_msg(hapd->msg_ctx, MSG_INFO,
"%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d",
finished ? WPA_EVENT_CHANNEL_SWITCH :
WPA_EVENT_CHANNEL_SWITCH_STARTED,
freq, ht, offset, channel_width_to_string(width),
cf1, cf2, is_dfs);
if (!finished)
return;
if (hapd->csa_in_progress &&
freq == hapd->cs_freq_params.freq) {
hostapd_cleanup_cs_params(hapd);
@ -942,28 +960,31 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
goto out;
}
if (hapd->iface->conf->ieee80211ac) {
if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
/* set defaults for backwards compatibility */
hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
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) {
hapd->iconf->vht_oper_centr_freq_seg0_idx =
acs_res->vht_seg0_center_ch;
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
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) {
hapd->iconf->vht_oper_centr_freq_seg0_idx =
acs_res->vht_seg0_center_ch;
hapd->iconf->vht_oper_chwidth =
VHT_CHANWIDTH_160MHZ;
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf,
acs_res->vht_seg0_center_ch);
hostapd_set_oper_chwidth(hapd->iconf,
CHANWIDTH_160MHZ);
} else {
hapd->iconf->vht_oper_centr_freq_seg0_idx =
acs_res->vht_seg0_center_ch;
hapd->iconf->vht_oper_centr_freq_seg1_idx =
acs_res->vht_seg1_center_ch;
hapd->iconf->vht_oper_chwidth =
VHT_CHANWIDTH_80P80MHZ;
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf,
acs_res->vht_seg0_center_ch);
hostapd_set_oper_centr_freq_seg1_idx(
hapd->iconf,
acs_res->vht_seg1_center_ch);
hostapd_set_oper_chwidth(hapd->iconf,
CHANWIDTH_80P80MHZ);
}
}
}
@ -1568,6 +1589,73 @@ static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
}
#ifdef CONFIG_OWE
static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd,
const u8 *peer, const u8 *ie,
size_t ie_len)
{
u16 status;
struct sta_info *sta;
struct ieee802_11_elems elems;
if (!hapd || !hapd->wpa_auth) {
wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context");
return -1;
}
if (!peer) {
wpa_printf(MSG_DEBUG, "OWE: Peer unknown");
return -1;
}
if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) {
wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured");
status = WLAN_STATUS_AKMP_NOT_VALID;
goto err;
}
if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) {
wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for "
MACSTR, MAC2STR(peer));
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto err;
}
status = owe_validate_request(hapd, peer, elems.rsn_ie,
elems.rsn_ie_len,
elems.owe_dh, elems.owe_dh_len);
if (status != WLAN_STATUS_SUCCESS)
goto err;
sta = ap_get_sta(hapd, peer);
if (sta) {
ap_sta_no_session_timeout(hapd, sta);
accounting_sta_stop(hapd, sta);
/*
* Make sure that the previously registered inactivity timer
* will not remove the STA immediately.
*/
sta->timeout_next = STA_NULLFUNC;
} else {
sta = ap_sta_add(hapd, peer);
if (!sta) {
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto err;
}
}
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie,
elems.rsn_ie_len, elems.owe_dh,
elems.owe_dh_len);
if (status != WLAN_STATUS_SUCCESS)
ap_free_sta(hapd, sta);
return 0;
err:
hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0);
return 0;
}
#endif /* CONFIG_OWE */
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@ -1673,6 +1761,15 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->assoc_info.req_ies_len,
data->assoc_info.reassoc);
break;
#ifdef CONFIG_OWE
case EVENT_UPDATE_DH:
if (!data)
return;
hostapd_notif_update_dh_ie(hapd, data->update_dh.peer,
data->update_dh.ie,
data->update_dh.ie_len);
break;
#endif /* CONFIG_OWE */
case EVENT_DISASSOC:
if (data)
hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
@ -1689,6 +1786,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
case EVENT_AUTH:
hostapd_notif_auth(hapd, &data->auth);
break;
case EVENT_CH_SWITCH_STARTED:
case EVENT_CH_SWITCH:
if (!data)
break;
@ -1697,7 +1795,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->ch_switch.ch_offset,
data->ch_switch.ch_width,
data->ch_switch.cf1,
data->ch_switch.cf2);
data->ch_switch.cf2,
event == EVENT_CH_SWITCH);
break;
case EVENT_CONNECT_FAILED_REASON:
if (!data)

View file

@ -1522,9 +1522,9 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
#ifdef CONFIG_DPP
static void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
int prot, struct wpabuf *buf)
void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
int prot, struct wpabuf *buf)
{
struct wpabuf *tx_buf;
@ -1681,7 +1681,8 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
if (dpp) {
struct wpabuf *msg;
msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen);
msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen,
data, len);
if (!msg)
return;
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);

View file

@ -88,4 +88,8 @@ void gas_serv_dialog_clear(struct gas_dialog_info *dialog);
int gas_serv_init(struct hostapd_data *hapd);
void gas_serv_deinit(struct hostapd_data *hapd);
void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
int prot, struct wpabuf *buf);
#endif /* GAS_SERV_H */

View file

@ -7,6 +7,9 @@
*/
#include "utils/includes.h"
#ifdef CONFIG_SQLITE
#include <sqlite3.h>
#endif /* CONFIG_SQLITE */
#include "utils/common.h"
#include "utils/eloop.h"
@ -50,6 +53,8 @@
#include "fils_hlp.h"
#include "acs.h"
#include "hs20.h"
#include "airtime_policy.h"
#include "wpa_auth_kay.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@ -260,11 +265,14 @@ int hostapd_reload_config(struct hostapd_iface *iface)
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
hapd->iconf->ht_capab = oldconf->ht_capab;
hapd->iconf->vht_capab = oldconf->vht_capab;
hapd->iconf->vht_oper_chwidth = oldconf->vht_oper_chwidth;
hapd->iconf->vht_oper_centr_freq_seg0_idx =
oldconf->vht_oper_centr_freq_seg0_idx;
hapd->iconf->vht_oper_centr_freq_seg1_idx =
oldconf->vht_oper_centr_freq_seg1_idx;
hostapd_set_oper_chwidth(hapd->iconf,
hostapd_get_oper_chwidth(oldconf));
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf,
hostapd_get_oper_centr_freq_seg0_idx(oldconf));
hostapd_set_oper_centr_freq_seg1_idx(
hapd->iconf,
hostapd_get_oper_centr_freq_seg1_idx(oldconf));
hapd->conf = newconf->bss[j];
hostapd_reload_bss(hapd);
}
@ -369,6 +377,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#endif /* CONFIG_NO_RADIUS */
hostapd_deinit_wps(hapd);
ieee802_1x_dealloc_kay_sm_hapd(hapd);
#ifdef CONFIG_DPP
hostapd_dpp_deinit(hapd);
gas_query_ap_deinit(hapd->gas);
@ -491,6 +500,7 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
iface->basic_rates = NULL;
ap_list_deinit(iface);
sta_track_deinit(iface);
airtime_policy_update_deinit(iface);
}
@ -1018,6 +1028,43 @@ hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
#define hostapd_das_coa NULL
#endif /* CONFIG_HS20 */
#ifdef CONFIG_SQLITE
static int db_table_exists(sqlite3 *db, const char *name)
{
char cmd[128];
os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
}
static int db_table_create_radius_attributes(sqlite3 *db)
{
char *err = NULL;
const char *sql =
"CREATE TABLE radius_attributes("
" id INTEGER PRIMARY KEY,"
" sta TEXT,"
" reqtype TEXT,"
" attr TEXT"
");"
"CREATE INDEX idx_sta_reqtype ON radius_attributes(sta,reqtype);";
wpa_printf(MSG_DEBUG,
"Adding database table for RADIUS attribute information");
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
wpa_printf(MSG_ERROR, "SQLite error: %s", err);
sqlite3_free(err);
return -1;
}
return 0;
}
#endif /* CONFIG_SQLITE */
#endif /* CONFIG_NO_RADIUS */
@ -1171,6 +1218,24 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (wpa_debug_level <= MSG_MSGDUMP)
conf->radius->msg_dumps = 1;
#ifndef CONFIG_NO_RADIUS
#ifdef CONFIG_SQLITE
if (conf->radius_req_attr_sqlite) {
if (sqlite3_open(conf->radius_req_attr_sqlite,
&hapd->rad_attr_db)) {
wpa_printf(MSG_ERROR, "Could not open SQLite file '%s'",
conf->radius_req_attr_sqlite);
return -1;
}
wpa_printf(MSG_DEBUG, "Opening RADIUS attribute database: %s",
conf->radius_req_attr_sqlite);
if (!db_table_exists(hapd->rad_attr_db, "radius_attributes") &&
db_table_create_radius_attributes(hapd->rad_attr_db) < 0)
return -1;
}
#endif /* CONFIG_SQLITE */
hapd->radius = radius_client_init(hapd, conf->radius);
if (hapd->radius == NULL) {
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
@ -1863,10 +1928,13 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
hapd->iconf->channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
hapd->iconf->ieee80211ax,
hapd->iconf->secondary_channel,
hapd->iconf->vht_oper_chwidth,
hapd->iconf->vht_oper_centr_freq_seg0_idx,
hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
hostapd_get_oper_chwidth(hapd->iconf),
hostapd_get_oper_centr_freq_seg0_idx(
hapd->iconf),
hostapd_get_oper_centr_freq_seg1_idx(
hapd->iconf))) {
wpa_printf(MSG_ERROR, "Could not set channel for "
"kernel driver");
goto fail;
@ -1976,6 +2044,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
hostapd_owe_update_trans(iface);
airtime_policy_update_init(iface);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
@ -2183,6 +2252,12 @@ static void hostapd_bss_deinit(struct hostapd_data *hapd)
hapd->conf ? hapd->conf->iface : "N/A");
hostapd_bss_deinit_no_free(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
#ifdef CONFIG_SQLITE
if (hapd->rad_attr_db) {
sqlite3_close(hapd->rad_attr_db);
hapd->rad_attr_db = NULL;
}
#endif /* CONFIG_SQLITE */
hostapd_cleanup(hapd);
}
@ -2486,8 +2561,12 @@ static void hostapd_deinit_driver(const struct wpa_driver_ops *driver,
wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
__func__, (int) j,
hapd_iface->bss[j]->drv_priv);
if (hapd_iface->bss[j]->drv_priv == drv_priv)
if (hapd_iface->bss[j]->drv_priv == drv_priv) {
hapd_iface->bss[j]->drv_priv = NULL;
hapd_iface->extended_capa = NULL;
hapd_iface->extended_capa_mask = NULL;
hapd_iface->extended_capa_len = 0;
}
}
}
}
@ -2992,6 +3071,8 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_P2P */
airtime_policy_new_sta(hapd, sta);
/* Start accounting here, if IEEE 802.1X and WPA are not used.
* IEEE 802.1X/WPA code will start accounting after the station has
* been authorized. */
@ -3032,6 +3113,14 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
}
#ifdef CONFIG_MACSEC
if (hapd->conf->wpa_key_mgmt == WPA_KEY_MGMT_NONE &&
hapd->conf->mka_psk_set)
ieee802_1x_create_preshared_mka_hapd(hapd, sta);
else
ieee802_1x_alloc_kay_sm_hapd(hapd, sta);
#endif /* CONFIG_MACSEC */
}
@ -3191,6 +3280,8 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
struct hostapd_freq_params *old_params)
{
int channel;
u8 seg0, seg1;
struct hostapd_hw_modes *mode;
if (!params->channel) {
/* check if the new channel is supported by hw */
@ -3201,33 +3292,37 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
if (!channel)
return -1;
mode = hapd->iface->current_mode;
/* if a pointer to old_params is provided we save previous state */
if (old_params &&
hostapd_set_freq_params(old_params, conf->hw_mode,
hostapd_hw_get_freq(hapd, conf->channel),
conf->channel, conf->ieee80211n,
conf->ieee80211ac,
conf->ieee80211ac, conf->ieee80211ax,
conf->secondary_channel,
conf->vht_oper_chwidth,
conf->vht_oper_centr_freq_seg0_idx,
conf->vht_oper_centr_freq_seg1_idx,
conf->vht_capab))
hostapd_get_oper_chwidth(conf),
hostapd_get_oper_centr_freq_seg0_idx(conf),
hostapd_get_oper_centr_freq_seg1_idx(conf),
conf->vht_capab,
mode ? &mode->he_capab[IEEE80211_MODE_AP] :
NULL))
return -1;
switch (params->bandwidth) {
case 0:
case 20:
case 40:
conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
break;
case 80:
if (params->center_freq2)
conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
hostapd_set_oper_chwidth(conf, CHANWIDTH_80P80MHZ);
else
conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
break;
case 160:
conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
break;
default:
return -1;
@ -3237,9 +3332,11 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
conf->ieee80211n = params->ht_enabled;
conf->secondary_channel = params->sec_channel_offset;
ieee80211_freq_to_chan(params->center_freq1,
&conf->vht_oper_centr_freq_seg0_idx);
&seg0);
ieee80211_freq_to_chan(params->center_freq2,
&conf->vht_oper_centr_freq_seg1_idx);
&seg1);
hostapd_set_oper_centr_freq_seg0_idx(conf, seg0);
hostapd_set_oper_centr_freq_seg1_idx(conf, seg1);
/* TODO: maybe call here hostapd_config_check here? */
@ -3253,7 +3350,7 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
u8 chan, vht_bandwidth;
u8 chan, bandwidth;
os_memset(&old_freq, 0, sizeof(old_freq));
if (!iface || !iface->freq || hapd->csa_in_progress)
@ -3262,29 +3359,30 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
switch (settings->freq_params.bandwidth) {
case 80:
if (settings->freq_params.center_freq2)
vht_bandwidth = VHT_CHANWIDTH_80P80MHZ;
bandwidth = CHANWIDTH_80P80MHZ;
else
vht_bandwidth = VHT_CHANWIDTH_80MHZ;
bandwidth = CHANWIDTH_80MHZ;
break;
case 160:
vht_bandwidth = VHT_CHANWIDTH_160MHZ;
bandwidth = CHANWIDTH_160MHZ;
break;
default:
vht_bandwidth = VHT_CHANWIDTH_USE_HT;
bandwidth = CHANWIDTH_USE_HT;
break;
}
if (ieee80211_freq_to_channel_ext(
settings->freq_params.freq,
settings->freq_params.sec_channel_offset,
vht_bandwidth,
bandwidth,
&hapd->iface->cs_oper_class,
&chan) == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_DEBUG,
"invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)",
"invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)",
settings->freq_params.freq,
settings->freq_params.sec_channel_offset,
settings->freq_params.vht_enabled);
settings->freq_params.vht_enabled,
settings->freq_params.he_enabled);
return -1;
}
@ -3384,29 +3482,29 @@ void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params)
{
int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
int seg0_idx = 0, seg1_idx = 0, bw = CHANWIDTH_USE_HT;
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
if (freq_params->center_freq1)
vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
if (freq_params->center_freq2)
vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
switch (freq_params->bandwidth) {
case 0:
case 20:
case 40:
vht_bw = VHT_CHANWIDTH_USE_HT;
bw = CHANWIDTH_USE_HT;
break;
case 80:
if (freq_params->center_freq2)
vht_bw = VHT_CHANWIDTH_80P80MHZ;
bw = CHANWIDTH_80P80MHZ;
else
vht_bw = VHT_CHANWIDTH_80MHZ;
bw = CHANWIDTH_80MHZ;
break;
case 160:
vht_bw = VHT_CHANWIDTH_160MHZ;
bw = CHANWIDTH_160MHZ;
break;
default:
wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
@ -3417,11 +3515,12 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
iface->freq = freq_params->freq;
iface->conf->channel = freq_params->channel;
iface->conf->secondary_channel = freq_params->sec_channel_offset;
iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
iface->conf->vht_oper_chwidth = vht_bw;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, seg1_idx);
hostapd_set_oper_chwidth(iface->conf, bw);
iface->conf->ieee80211n = freq_params->ht_enabled;
iface->conf->ieee80211ac = freq_params->vht_enabled;
iface->conf->ieee80211ax = freq_params->he_enabled;
/*
* cs_params must not be cleared earlier because the freq_params

View file

@ -9,6 +9,10 @@
#ifndef HOSTAPD_H
#define HOSTAPD_H
#ifdef CONFIG_SQLITE
#include <sqlite3.h>
#endif /* CONFIG_SQLITE */
#include "common/defs.h"
#include "utils/list.h"
#include "ap_config.h"
@ -232,6 +236,10 @@ struct hostapd_data {
struct wps_stat wps_stats;
#endif /* CONFIG_WPS */
#ifdef CONFIG_MACSEC
struct ieee802_1x_kay *kay;
#endif /* CONFIG_MACSEC */
struct hostapd_probereq_cb *probereq_cb;
size_t num_probereq_cb;
@ -379,6 +387,17 @@ struct hostapd_data {
unsigned int dpp_ignore_netaccesskey_mismatch:1;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
#ifdef CONFIG_AIRTIME_POLICY
unsigned int num_backlogged_sta;
unsigned int airtime_weight;
#endif /* CONFIG_AIRTIME_POLICY */
u8 last_1x_eapol_key_replay_counter[8];
#ifdef CONFIG_SQLITE
sqlite3 *rad_attr_db;
#endif /* CONFIG_SQLITE */
};
@ -541,6 +560,12 @@ struct hostapd_iface {
unsigned int num_sta_seen;
u8 dfs_domain;
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_quantum;
#endif /* CONFIG_AIRTIME_POLICY */
/* Previous WMM element information */
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
};
/* hostapd.c */
@ -607,7 +632,8 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2);
int offset, int width, int cf1, int cf2,
int finished);
struct survey_results;
void hostapd_event_get_survey(struct hostapd_iface *iface,
struct survey_results *survey_results);

View file

@ -329,9 +329,9 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
iface->conf->vht_oper_centr_freq_seg0_idx = 0;
iface->conf->vht_oper_centr_freq_seg1_idx = 0;
iface->conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 0);
hostapd_set_oper_chwidth(iface->conf, CHANWIDTH_USE_HT);
res = 1;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
@ -655,6 +655,14 @@ static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
}
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface)
{
return 1;
}
#endif /* CONFIG_IEEE80211AX */
#endif /* CONFIG_IEEE80211N */
@ -675,6 +683,11 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
if (!ieee80211n_supported_ht_capab(iface))
return -1;
#ifdef CONFIG_IEEE80211AX
if (iface->conf->ieee80211ax &&
!ieee80211ax_supported_he_capab(iface))
return -1;
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_IEEE80211AC
if (iface->conf->ieee80211ac &&
!ieee80211ac_supported_vht_capab(iface))
@ -863,12 +876,14 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
return -1;
if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
iface->conf->ieee80211n || iface->conf->ieee80211ac) &&
iface->conf->ieee80211n || iface->conf->ieee80211ac ||
iface->conf->ieee80211ax) &&
iface->conf->channel == 14) {
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT on channel 14");
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14");
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
iface->conf->ieee80211n = 0;
iface->conf->ieee80211ac = 0;
iface->conf->ieee80211ax = 0;
}
iface->current_mode = NULL;
@ -936,11 +951,16 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
int i, channel;
struct hostapd_hw_modes *mode;
channel = hw_get_chan(hapd->iface->current_mode, freq);
if (channel)
return channel;
if (hapd->iface->current_mode) {
channel = hw_get_chan(hapd->iface->current_mode, freq);
if (channel)
return channel;
}
/* Check other available modes since the channel list for the current
* mode did not include the specified frequency. */
if (!hapd->iface->hw_features)
return 0;
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
channel = hw_get_chan(mode, freq);

View file

@ -23,6 +23,7 @@
#include "common/sae.h"
#include "common/dpp.h"
#include "common/ocv.h"
#include "common/wpa_common.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@ -709,7 +710,8 @@ static void sae_sme_send_external_auth_status(struct hostapd_data *hapd,
os_memset(&params, 0, sizeof(params));
params.status = status;
params.bssid = sta->addr;
if (status == WLAN_STATUS_SUCCESS && sta->sae)
if (status == WLAN_STATUS_SUCCESS && sta->sae &&
!hapd->conf->disable_pmksa_caching)
params.pmkid = sta->sae->pmkid;
hostapd_drv_send_external_auth_status(hapd, &params);
@ -1038,8 +1040,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"start SAE authentication (RX commit, status=%u)",
status_code);
"start SAE authentication (RX commit, status=%u (%s))",
status_code, status2str(status_code));
if ((hapd->conf->mesh & MESH_ENABLED) &&
status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
@ -1182,8 +1184,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"SAE authentication (RX confirm, status=%u)",
status_code);
"SAE authentication (RX confirm, status=%u (%s))",
status_code, status2str(status_code));
if (status_code != WLAN_STATUS_SUCCESS)
goto remove_sta;
if (sta->sae->state >= SAE_CONFIRMED ||
@ -1224,8 +1226,9 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"unexpected SAE authentication transaction %u (status=%u)",
auth_transaction, status_code);
"unexpected SAE authentication transaction %u (status=%u (%s))",
auth_transaction, status_code,
status2str(status_code));
if (status_code != WLAN_STATUS_SUCCESS)
goto remove_sta;
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
@ -2323,8 +2326,11 @@ static void handle_auth(struct hostapd_data *hapd,
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
WLAN_STA_AUTHORIZED);
if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
NULL, NULL, sta->flags, 0, 0, 0, 0)) {
if (hostapd_sta_add(hapd, sta->addr, 0, 0,
sta->supported_rates,
sta->supported_rates_len,
0, NULL, NULL, NULL, 0,
sta->flags, 0, 0, 0, 0)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
@ -2790,6 +2796,123 @@ static u16 owe_process_assoc_req(struct hostapd_data *hapd,
return WLAN_STATUS_SUCCESS;
}
u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
const u8 *rsn_ie, size_t rsn_ie_len,
const u8 *owe_dh, size_t owe_dh_len)
{
struct wpa_ie_data data;
int res;
if (!rsn_ie || rsn_ie_len < 2) {
wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
MAC2STR(peer));
return WLAN_STATUS_INVALID_IE;
}
rsn_ie -= 2;
rsn_ie_len += 2;
res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
if (res) {
wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
" (res=%d)", MAC2STR(peer), res);
wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
return wpa_res_to_status_code(res);
}
if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
wpa_printf(MSG_DEBUG,
"OWE: Unexpected key mgmt 0x%x from " MACSTR,
(unsigned int) data.key_mgmt, MAC2STR(peer));
return WLAN_STATUS_AKMP_NOT_VALID;
}
if (!owe_dh) {
wpa_printf(MSG_DEBUG,
"OWE: No Diffie-Hellman Parameter element from "
MACSTR, MAC2STR(peer));
return WLAN_STATUS_AKMP_NOT_VALID;
}
return WLAN_STATUS_SUCCESS;
}
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)
{
u16 status;
u8 *owe_buf, ie[256 * 2];
size_t ie_len = 0;
int res;
if (!rsn_ie || rsn_ie_len < 2) {
wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
status = WLAN_STATUS_INVALID_IE;
goto end;
}
if (!sta->wpa_sm)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
NULL);
if (!sta->wpa_sm) {
wpa_printf(MSG_WARNING,
"OWE: Failed to initialize WPA state machine");
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto end;
}
rsn_ie -= 2;
rsn_ie_len += 2;
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq, rsn_ie, rsn_ie_len,
NULL, 0, owe_dh, owe_dh_len);
status = wpa_res_to_status_code(res);
if (status != WLAN_STATUS_SUCCESS)
goto end;
status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
if (status != WLAN_STATUS_SUCCESS)
goto end;
owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
NULL, 0);
if (!owe_buf) {
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto end;
}
if (sta->owe_ecdh) {
struct wpabuf *pub;
pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
if (!pub) {
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto end;
}
/* OWE Diffie-Hellman Parameter element */
*owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
*owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
*owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
*/
WPA_PUT_LE16(owe_buf, sta->owe_group);
owe_buf += 2;
os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
owe_buf += wpabuf_len(pub);
wpabuf_free(pub);
sta->external_dh_updated = 1;
}
ie_len = owe_buf - ie;
end:
wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
MACSTR, status, (unsigned int) ie_len,
MAC2STR(sta->addr));
hostapd_drv_update_dh_ie(hapd, sta->addr, status,
status == WLAN_STATUS_SUCCESS ? ie : NULL,
ie_len);
return status;
}
#endif /* CONFIG_OWE */
@ -2845,10 +2968,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
return resp;
resp = copy_sta_vht_oper(hapd, sta, elems.vht_operation);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@ -2869,6 +2988,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
return resp;
}
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
elems.he_capabilities,
elems.he_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
}
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_P2P
if (elems.p2p) {
@ -3231,6 +3359,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
{
struct ieee80211_ht_capabilities ht_cap;
struct ieee80211_vht_capabilities vht_cap;
struct ieee80211_he_capabilities he_cap;
int set = 1;
/*
@ -3283,6 +3412,12 @@ static int add_associated_sta(struct hostapd_data *hapd,
if (sta->flags & WLAN_STA_VHT)
hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
if (sta->flags & WLAN_STA_HE) {
hostapd_get_he_capab(hapd, sta->he_capab, &he_cap,
sta->he_capab_len);
}
#endif /* CONFIG_IEEE80211AX */
/*
* Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
@ -3294,6 +3429,8 @@ static int add_associated_sta(struct hostapd_data *hapd,
sta->listen_interval,
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
sta->flags & WLAN_STA_HE ? &he_cap : NULL,
sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
set)) {
@ -3331,6 +3468,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#ifdef CONFIG_FILS
if (sta && sta->fils_hlp_resp)
buflen += wpabuf_len(sta->fils_hlp_resp);
if (sta)
buflen += 150;
#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
@ -3392,6 +3531,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
}
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_FILS
if (sta && status_code == WLAN_STATUS_SUCCESS &&
(sta->auth_alg == WLAN_AUTH_FILS_SK ||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
sta->auth_alg == WLAN_AUTH_FILS_PK))
p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p,
buf + buflen - p,
ies, ies_len);
#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
if (sta && status_code == WLAN_STATUS_SUCCESS &&
@ -3434,6 +3582,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
p = hostapd_eid_he_operation(hapd, p);
p = hostapd_eid_spatial_reuse(hapd, p);
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
}
#endif /* CONFIG_IEEE80211AX */
p = hostapd_eid_ext_capab(hapd, p);
p = hostapd_eid_bss_max_idle_period(hapd, p);
if (sta && sta->qos_map_enabled)
@ -3610,6 +3767,12 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
return owe_buf;
}
if (sta->owe_pmk && sta->external_dh_updated) {
wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
*reason = WLAN_STATUS_SUCCESS;
return owe_buf;
}
*reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
if (*reason != WLAN_STATUS_SUCCESS)
return NULL;

View file

@ -18,6 +18,7 @@ struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
struct vlan_description;
struct hostapd_sta_wpa_psk_short;
enum ieee80211_op_mode;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
@ -57,9 +58,11 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
enum ieee80211_op_mode opmode);
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);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
@ -70,6 +73,10 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap);
void hostapd_get_he_capab(struct hostapd_data *hapd,
const struct ieee80211_he_capabilities *he_cap,
struct ieee80211_he_capabilities *neg_he_cap,
size_t he_capab_len);
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab);
@ -85,6 +92,9 @@ u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_oper);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_opmode);
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);
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,
@ -153,6 +163,12 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
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);
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);
u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
const u8 *rsn_ie, size_t rsn_ie_len,
const u8 *owe_dh, size_t owe_dh_len);
void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,

View file

@ -1,6 +1,7 @@
/*
* hostapd / IEEE 802.11ax HE
* Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
* Copyright (c) 2019 John Crispin <john@phrozen.org>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -13,37 +14,113 @@
#include "hostapd.h"
#include "ap_config.h"
#include "beacon.h"
#include "sta_info.h"
#include "ieee802_11.h"
#include "dfs.h"
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
{
u8 sz = 0, ru;
if ((phy_cap_info[HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] &
HE_PHYCAP_PPE_THRESHOLD_PRESENT) == 0)
return 0;
ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) &
HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
while (ru) {
if (ru & 0x1)
sz++;
ru >>= 1;
}
sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
sz = (sz * 6) + 7;
if (sz % 8)
sz += 8;
sz /= 8;
return sz;
}
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
enum ieee80211_op_mode opmode)
{
struct ieee80211_he_capabilities *cap;
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;
if (!hapd->iface->current_mode)
if (!mode)
return eid;
ie_size = sizeof(struct ieee80211_he_capabilities);
ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
mode->he_capab[opmode].phy_cap);
switch (hapd->iface->conf->he_oper_chwidth) {
case CHANWIDTH_80P80MHZ:
he_oper_chwidth |=
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
mcs_nss_size += 4;
/* fall through */
case CHANWIDTH_160MHZ:
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
mcs_nss_size += 4;
/* fall through */
case CHANWIDTH_80MHZ:
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;
}
ie_size += mcs_nss_size + ppet_size;
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + sizeof(struct ieee80211_he_capabilities);
*pos++ = 1 + ie_size;
*pos++ = WLAN_EID_EXT_HE_CAPABILITIES;
cap = (struct ieee80211_he_capabilities *) pos;
os_memset(cap, 0, sizeof(*cap));
os_memcpy(cap->he_mac_capab_info, mode->he_capab[opmode].mac_cap,
HE_MAX_MAC_CAPAB_SIZE);
os_memcpy(cap->he_phy_capab_info, mode->he_capab[opmode].phy_cap,
HE_MAX_PHY_CAPAB_SIZE);
os_memcpy(cap->optional, mode->he_capab[opmode].mcs, mcs_nss_size);
if (ppet_size)
os_memcpy(&cap->optional[mcs_nss_size],
mode->he_capab[opmode].ppet, ppet_size);
if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
HE_PHYCAP_SU_BEAMFORMER_CAPAB;
else
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] &=
~HE_PHYCAP_SU_BEAMFORMER_CAPAB;
if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
else
cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] &=
~HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
HE_PHYCAP_MU_BEAMFORMER_CAPAB;
else
cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] &=
~HE_PHYCAP_MU_BEAMFORMER_CAPAB;
pos += sizeof(*cap);
cap->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &=
he_oper_chwidth;
pos += ie_size;
return pos;
}
@ -53,36 +130,43 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_he_operation *oper;
u8 *pos = eid;
int oper_size = 6;
u32 params = 0;
if (!hapd->iface->current_mode)
return eid;
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + sizeof(struct ieee80211_he_operation);
*pos++ = 1 + oper_size;
*pos++ = WLAN_EID_EXT_HE_OPERATION;
oper = (struct ieee80211_he_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
if (hapd->iface->conf->he_op.he_bss_color)
oper->he_oper_params |= hapd->iface->conf->he_op.he_bss_color;
if (hapd->iface->conf->he_op.he_default_pe_duration)
oper->he_oper_params |=
(hapd->iface->conf->he_op.he_default_pe_duration <<
HE_OPERATION_DFLT_PE_DURATION_OFFSET);
params |= (hapd->iface->conf->he_op.he_default_pe_duration <<
HE_OPERATION_DFLT_PE_DURATION_OFFSET);
if (hapd->iface->conf->he_op.he_twt_required)
oper->he_oper_params |= HE_OPERATION_TWT_REQUIRED;
params |= HE_OPERATION_TWT_REQUIRED;
if (hapd->iface->conf->he_op.he_rts_threshold)
oper->he_oper_params |=
(hapd->iface->conf->he_op.he_rts_threshold <<
HE_OPERATION_RTS_THRESHOLD_OFFSET);
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);
/* HE minimum required basic MCS and NSS for STAs */
oper->he_mcs_nss_set =
host_to_le16(hapd->iface->conf->he_op.he_basic_mcs_nss_set);
/* TODO: conditional MaxBSSID Indicator subfield */
pos += sizeof(*oper);
oper->he_oper_params = host_to_le32(params);
pos += oper_size;
return pos;
}
@ -117,3 +201,148 @@ u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid)
return pos;
}
u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_spatial_reuse *spr;
u8 *pos = eid, *spr_param;
u8 sz = 1;
if (!hapd->iface->conf->spr.sr_control)
return eid;
if (hapd->iface->conf->spr.sr_control &
SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT)
sz++;
if (hapd->iface->conf->spr.sr_control &
SPATIAL_REUSE_SRG_INFORMATION_PRESENT)
sz += 18;
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + sz;
*pos++ = WLAN_EID_EXT_SPATIAL_REUSE;
spr = (struct ieee80211_spatial_reuse *) pos;
os_memset(spr, 0, sizeof(*spr));
spr->sr_ctrl = hapd->iface->conf->spr.sr_control;
pos++;
spr_param = spr->params;
if (spr->sr_ctrl & SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) {
*spr_param++ =
hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
pos++;
}
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;
pos += 18;
}
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,
size_t he_capab_len)
{
if (!he_cap)
return;
if (he_capab_len > sizeof(*neg_he_cap))
he_capab_len = sizeof(*neg_he_cap);
/* TODO: mask out unsupported features */
os_memcpy(neg_he_cap, he_cap, he_capab_len);
}
static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
enum ieee80211_op_mode opmode)
{
u16 sta_rx_mcs_set, ap_tx_mcs_set;
u8 mcs_count = 0;
const u16 *ap_mcs_set, *sta_mcs_set;
int i;
if (!hapd->iface->current_mode)
return 1;
ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs;
sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *)
sta_he_capab)->optional;
/*
* Disable HE capabilities for STAs for which there is not even a single
* allowed MCS in any supported number of streams, i.e., STA is
* advertising 3 (not supported) as HE MCS rates for all supported
* band/stream cases.
*/
switch (hapd->iface->conf->he_oper_chwidth) {
case CHANWIDTH_80P80MHZ:
mcs_count = 3;
break;
case CHANWIDTH_160MHZ:
mcs_count = 2;
break;
default:
mcs_count = 1;
break;
}
for (i = 0; i < mcs_count; i++) {
int j;
/* AP Tx MCS map vs. STA Rx MCS map */
sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]);
ap_tx_mcs_set = WPA_GET_LE16((const u8 *)
&ap_mcs_set[(i * 2) + 1]);
for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3)
continue;
if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3)
continue;
return 1;
}
}
wpa_printf(MSG_DEBUG,
"No matching HE MCS found between AP TX and STA RX");
return 0;
}
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 ||
!check_valid_he_mcs(hapd, he_capab, opmode) ||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
sta->flags &= ~WLAN_STA_HE;
os_free(sta->he_capab);
sta->he_capab = NULL;
return WLAN_STATUS_SUCCESS;
}
if (!sta->he_capab) {
sta->he_capab =
os_zalloc(sizeof(struct ieee80211_he_capabilities));
if (!sta->he_capab)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
sta->flags |= WLAN_STA_HE;
os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities));
os_memcpy(sta->he_capab, he_capab, he_capab_len);
sta->he_capab_len = he_capab_len;
return WLAN_STATUS_SUCCESS;
}

View file

@ -242,7 +242,7 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
return eid;
switch (iface->conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
case CHANWIDTH_USE_HT:
if (iconf->secondary_channel == 0) {
/* Max Transmit Power count = 0 (20 MHz) */
tx_pwr_count = 0;
@ -251,12 +251,12 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
tx_pwr_count = 1;
}
break;
case VHT_CHANWIDTH_80MHZ:
case CHANWIDTH_80MHZ:
/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
tx_pwr_count = 2;
break;
case VHT_CHANWIDTH_80P80MHZ:
case VHT_CHANWIDTH_160MHZ:
case CHANWIDTH_80P80MHZ:
case CHANWIDTH_160MHZ:
/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
tx_pwr_count = 3;
break;

View file

@ -7,6 +7,9 @@
*/
#include "utils/includes.h"
#ifdef CONFIG_SQLITE
#include <sqlite3.h>
#endif /* CONFIG_SQLITE */
#include "utils/common.h"
#include "utils/eloop.h"
@ -34,6 +37,7 @@
/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */
#include "ieee802_11.h"
#include "ieee802_1x.h"
#include "wpa_auth_kay.h"
#ifdef CONFIG_HS20
@ -63,6 +67,10 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
xhdr = (struct ieee802_1x_hdr *) buf;
xhdr->version = hapd->conf->eapol_version;
#ifdef CONFIG_MACSEC
if (xhdr->version > 2 && hapd->conf->macsec_policy == 0)
xhdr->version = 2;
#endif /* CONFIG_MACSEC */
xhdr->type = type;
xhdr->length = host_to_be16(datalen);
@ -157,6 +165,21 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
key->type = EAPOL_KEY_TYPE_RC4;
WPA_PUT_BE16(key->key_length, key_len);
wpa_get_ntp_timestamp(key->replay_counter);
if (os_memcmp(key->replay_counter,
hapd->last_1x_eapol_key_replay_counter,
IEEE8021X_REPLAY_COUNTER_LEN) <= 0) {
/* NTP timestamp did not increment from last EAPOL-Key frame;
* use previously used value + 1 instead. */
inc_byte_array(hapd->last_1x_eapol_key_replay_counter,
IEEE8021X_REPLAY_COUNTER_LEN);
os_memcpy(key->replay_counter,
hapd->last_1x_eapol_key_replay_counter,
IEEE8021X_REPLAY_COUNTER_LEN);
} else {
os_memcpy(hapd->last_1x_eapol_key_replay_counter,
key->replay_counter,
IEEE8021X_REPLAY_COUNTER_LEN);
}
if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
wpa_printf(MSG_ERROR, "Could not get random numbers");
@ -197,6 +220,10 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
/* This header is needed here for HMAC-MD5, but it will be regenerated
* in ieee802_1x_send() */
hdr->version = hapd->conf->eapol_version;
#ifdef CONFIG_MACSEC
if (hdr->version > 2)
hdr->version = 2;
#endif /* CONFIG_MACSEC */
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len);
hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
@ -591,6 +618,63 @@ int add_common_radius_attr(struct hostapd_data *hapd,
}
int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
struct radius_msg *msg, int acct)
{
#ifdef CONFIG_SQLITE
const char *attrtxt;
char addrtxt[3 * ETH_ALEN];
char *sql;
sqlite3_stmt *stmt = NULL;
if (!hapd->rad_attr_db)
return 0;
os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr));
sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);";
if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt,
NULL) != SQLITE_OK) {
wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s",
sqlite3_errmsg(hapd->rad_attr_db));
return -1;
}
sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC);
while (sqlite3_step(stmt) == SQLITE_ROW) {
struct hostapd_radius_attr *attr;
struct radius_attr_hdr *hdr;
attrtxt = (const char *) sqlite3_column_text(stmt, 0);
attr = hostapd_parse_radius_attr(attrtxt);
if (!attr) {
wpa_printf(MSG_ERROR,
"Skipping invalid attribute from SQL: %s",
attrtxt);
continue;
}
wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s",
attrtxt);
hdr = radius_msg_add_attr(msg, attr->type,
wpabuf_head(attr->val),
wpabuf_len(attr->val));
hostapd_config_free_radius_attr(attr);
if (!hdr) {
wpa_printf(MSG_ERROR,
"Could not add RADIUS attribute from SQL");
continue;
}
}
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
sqlite3_finalize(stmt);
#endif /* CONFIG_SQLITE */
return 0;
}
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len)
@ -630,6 +714,9 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
msg) < 0)
goto fail;
if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0)
goto fail;
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
@ -1104,6 +1191,13 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
/* TODO: implement support for this; show data */
break;
#ifdef CONFIG_MACSEC
case IEEE802_1X_TYPE_EAPOL_MKA:
wpa_printf(MSG_EXCESSIVE,
"EAPOL type %d will be handled by MKA", hdr->type);
break;
#endif /* CONFIG_MACSEC */
default:
wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type");
sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
@ -1385,6 +1479,8 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
size_t shared_secret_len)
{
struct radius_ms_mppe_keys *keys;
u8 *buf;
size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
if (sm == NULL)
return;
@ -1393,7 +1489,7 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
shared_secret_len);
if (keys && keys->send && keys->recv) {
size_t len = keys->send_len + keys->recv_len;
len = keys->send_len + keys->recv_len;
wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
keys->send, keys->send_len);
wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
@ -1421,6 +1517,20 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd,
os_free(keys->recv);
os_free(keys);
}
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len,
NULL) == 0) {
os_free(sm->eap_if->eapSessionId);
sm->eap_if->eapSessionId = os_memdup(buf, len);
if (sm->eap_if->eapSessionId) {
sm->eap_if->eapSessionIdLen = len;
wpa_hexdump(MSG_DEBUG, "EAP-Key Name",
sm->eap_if->eapSessionId,
sm->eap_if->eapSessionIdLen);
}
} else {
sm->eap_if->eapSessionIdLen = 0;
}
}
@ -2324,7 +2434,10 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.eap_fast_prov = hapd->conf->eap_fast_prov;
conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
conf.eap_teap_auth = hapd->conf->eap_teap_auth;
conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
conf.eap_sim_id = hapd->conf->eap_sim_id;
conf.tnc = hapd->conf->tnc;
conf.wps = hapd->wps;
conf.fragment_size = hapd->conf->fragment_size;
@ -2543,6 +2656,20 @@ const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
}
#ifdef CONFIG_MACSEC
const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm,
size_t *len)
{
*len = 0;
if (!sm || !sm->eap_if)
return NULL;
*len = sm->eap_if->eapSessionIdLen;
return sm->eap_if->eapSessionId;
}
#endif /* CONFIG_MACSEC */
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled)
{
@ -2833,6 +2960,10 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
}
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MACSEC
ieee802_1x_notify_create_actor_hapd(hapd, sta);
#endif /* CONFIG_MACSEC */
key = ieee802_1x_get_key(sta->eapol_sm, &len);
if (sta->session_timeout_set) {
os_get_reltime(&now);

View file

@ -39,6 +39,8 @@ u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx);
struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
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,
@ -57,6 +59,8 @@ int add_common_radius_attr(struct hostapd_data *hapd,
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
struct radius_msg *msg);
int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta,
struct radius_msg *msg, int acct);
void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len);

View file

@ -139,19 +139,21 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd)
#ifdef NEED_AP_MLME
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
int ht, int vht)
int ht, int vht, int he)
{
if (!ht && !vht)
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
if (!ht && !vht && !he)
return NR_CHAN_WIDTH_20;
if (!hapd->iconf->secondary_channel)
return NR_CHAN_WIDTH_20;
if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT)
return NR_CHAN_WIDTH_40;
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
if (oper_chwidth == CHANWIDTH_80MHZ)
return NR_CHAN_WIDTH_80;
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
if (oper_chwidth == CHANWIDTH_160MHZ)
return NR_CHAN_WIDTH_160;
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
if (oper_chwidth == CHANWIDTH_80P80MHZ)
return NR_CHAN_WIDTH_80P80;
return NR_CHAN_WIDTH_20;
}
@ -164,6 +166,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;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
@ -205,16 +208,18 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
hapd->iconf->secondary_channel,
hapd->iconf->vht_oper_chwidth,
hostapd_get_oper_chwidth(hapd->iconf),
&op_class, &channel) ==
NUM_HOSTAPD_MODES)
return;
width = hostapd_get_nr_chan_width(hapd, ht, vht);
width = hostapd_get_nr_chan_width(hapd, ht, vht, he);
if (vht) {
center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
center_freq1_idx = hostapd_get_oper_centr_freq_seg0_idx(
hapd->iconf);
if (width == NR_CHAN_WIDTH_80P80)
center_freq2_idx =
hapd->iconf->vht_oper_centr_freq_seg1_idx;
hostapd_get_oper_centr_freq_seg1_idx(
hapd->iconf);
} else if (ht) {
ieee80211_freq_to_chan(hapd->iface->freq +
10 * hapd->iconf->secondary_channel,

View file

@ -330,6 +330,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->ht_capabilities);
os_free(sta->vht_capabilities);
os_free(sta->vht_operation);
os_free(sta->he_capab);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@ -670,6 +671,7 @@ void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
int i;
sta = ap_get_sta(hapd, addr);
if (sta)
@ -694,6 +696,15 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
return NULL;
}
for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
if (!hapd->iface->basic_rates)
break;
if (hapd->iface->basic_rates[i] < 0)
break;
sta->supported_rates[i] = hapd->iface->basic_rates[i] / 5;
}
sta->supported_rates_len = i;
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - ap_max_inactivity)",

View file

@ -37,6 +37,7 @@
#define WLAN_STA_VENDOR_VHT BIT(21)
#define WLAN_STA_PENDING_FILS_ERP BIT(22)
#define WLAN_STA_MULTI_AP BIT(23)
#define WLAN_STA_HE BIT(24)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@ -119,6 +120,7 @@ struct sta_info {
unsigned int agreed_to_steer:1;
unsigned int hs20_t_c_filtering:1;
unsigned int ft_over_ds:1;
unsigned int external_dh_updated:1;
u16 auth_alg;
@ -166,6 +168,8 @@ struct sta_info {
struct ieee80211_vht_capabilities *vht_capabilities;
struct ieee80211_vht_operation *vht_operation;
u8 vht_opmode;
struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
@ -275,6 +279,10 @@ struct sta_info {
u8 last_tk[WPA_TK_MAX_LEN];
size_t last_tk_len;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
};

View file

@ -20,6 +20,13 @@
#include "ap_drv_ops.h"
#include "wmm.h"
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
{
@ -39,6 +46,62 @@ static inline u8 wmm_ecw(int ecwmin, int ecwmax)
}
static void
wmm_set_regulatory_limit(const struct hostapd_wmm_ac_params *wmm_conf,
struct hostapd_wmm_ac_params *wmm,
const struct hostapd_wmm_rule *wmm_reg)
{
int ac;
for (ac = 0; ac < WMM_AC_NUM; ac++) {
wmm[ac].cwmin = MAX(wmm_conf[ac].cwmin, wmm_reg[ac].min_cwmin);
wmm[ac].cwmax = MAX(wmm_conf[ac].cwmax, wmm_reg[ac].min_cwmax);
wmm[ac].aifs = MAX(wmm_conf[ac].aifs, wmm_reg[ac].min_aifs);
wmm[ac].txop_limit =
MIN(wmm_conf[ac].txop_limit, wmm_reg[ac].max_txop);
wmm[ac].admission_control_mandatory =
wmm_conf[ac].admission_control_mandatory;
}
}
/*
* Calculate WMM regulatory limit if any.
*/
static void wmm_calc_regulatory_limit(struct hostapd_data *hapd,
struct hostapd_wmm_ac_params *acp)
{
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
int c;
os_memcpy(acp, hapd->iconf->wmm_ac_params,
sizeof(hapd->iconf->wmm_ac_params));
for (c = 0; mode && c < mode->num_channels; c++) {
struct hostapd_channel_data *chan = &mode->channels[c];
if (chan->freq != hapd->iface->freq)
continue;
if (chan->wmm_rules_valid)
wmm_set_regulatory_limit(hapd->iconf->wmm_ac_params,
acp, chan->wmm_rules);
break;
}
/*
* Check if we need to update set count. Since both were initialized to
* zero we can compare the whole array in one shot.
*/
if (os_memcmp(acp, hapd->iface->prev_wmm,
sizeof(hapd->iconf->wmm_ac_params)) != 0) {
os_memcpy(hapd->iface->prev_wmm, acp,
sizeof(hapd->iconf->wmm_ac_params));
hapd->parameter_set_count++;
}
}
/*
* Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
* Response frames.
@ -48,10 +111,12 @@ 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 };
int e;
if (!hapd->conf->wmm_enabled)
return eid;
wmm_calc_regulatory_limit(hapd, wmmp);
eid[0] = WLAN_EID_VENDOR_SPECIFIC;
wmm->oui[0] = 0x00;
wmm->oui[1] = 0x50;
@ -70,8 +135,7 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
/* fill in a parameter set record for each AC */
for (e = 0; e < 4; e++) {
struct wmm_ac_parameter *ac = &wmm->ac[e];
struct hostapd_wmm_ac_params *acp =
&hapd->iconf->wmm_ac_params[e];
struct hostapd_wmm_ac_params *acp = &wmmp[e];
ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
acp->admission_control_mandatory,

View file

@ -934,6 +934,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
forced_memzero(&PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
return 0;
@ -1407,6 +1408,8 @@ static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
#endif /* CONFIG_SHA256 */
#endif /* CONFIG_SHA384 */
forced_memzero(data, sizeof(data));
return ret;
}
@ -2046,7 +2049,7 @@ SM_STATE(WPA_PTK, INITPMK)
sm->Disconnect = TRUE;
return;
}
os_memset(msk, 0, sizeof(msk));
forced_memzero(msk, sizeof(msk));
sm->req_replay_counter_used = 0;
/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
@ -2285,12 +2288,12 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
os_memset(fils_ft, 0, sizeof(fils_ft));
forced_memzero(fils_ft, sizeof(fils_ft));
res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
sm->addr, sm->pmk_r1_name,
use_sha384);
os_memset(pmk_r0, 0, PMK_LEN_MAX);
forced_memzero(pmk_r0, PMK_LEN_MAX);
if (res < 0)
return -1;
wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
@ -2308,7 +2311,7 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
sm->wpa_key_mgmt, sm->fils_key_auth_sta,
sm->fils_key_auth_ap,
&sm->fils_key_auth_len);
os_memset(ick, 0, sizeof(ick));
forced_memzero(ick, sizeof(ick));
/* Store nonces for (Re)Association Request/Response frame processing */
os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
@ -2610,7 +2613,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
wpa_printf(MSG_DEBUG,
"FILS: Not enough room for FILS elements");
wpabuf_free(plain);
wpabuf_clear_free(plain);
return -1;
}
@ -2620,7 +2623,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
wpabuf_head(plain), wpabuf_len(plain),
5, aad, aad_len, pos) < 0) {
wpabuf_free(plain);
wpabuf_clear_free(plain);
return -1;
}
@ -2628,7 +2631,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
"FILS: Encrypted Association Response elements",
pos, AES_BLOCK_SIZE + wpabuf_len(plain));
current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
wpabuf_free(plain);
wpabuf_clear_free(plain);
sm->fils_completed = 1;
@ -2682,7 +2685,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
* of GTK in the BSS.
*/
if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
wpabuf_free(plain);
wpabuf_clear_free(plain);
return NULL;
}
gtk = dummy_gtk;
@ -2709,13 +2712,13 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
wpa_printf(MSG_WARNING,
"FILS: Failed to get channel info for OCI element");
wpabuf_free(plain);
wpabuf_clear_free(plain);
return NULL;
}
pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
if (ocv_insert_extended_oci(&ci, pos) < 0) {
wpabuf_free(plain);
wpabuf_clear_free(plain);
return NULL;
}
}
@ -2778,7 +2781,7 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
(unsigned int) wpabuf_len(plain));
wpabuf_free(plain);
wpabuf_clear_free(plain);
sm->fils_completed = 1;
return pos;
}
@ -3030,6 +3033,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
sm->MICVerified = TRUE;
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
forced_memzero(&PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
}
@ -4246,8 +4250,12 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
/* Private MIB */
ret = os_snprintf(buf + len, buflen - len,
"wpa=%d\n"
"AKMSuiteSelector=" RSN_SUITE "\n"
"hostapdWPAPTKState=%d\n"
"hostapdWPAPTKGroupState=%d\n",
sm->wpa,
RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)),
sm->wpa_ptk_state,
sm->wpa_ptk_group_state);
if (os_snprintf_error(buflen - len, ret))
@ -4359,6 +4367,15 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
sm->wpa_auth->conf.disable_pmksa_caching)
return -1;
#ifdef CONFIG_IEEE80211R_AP
if (pmk_len >= 2 * PMK_LEN && wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
!wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
/* Cache MPMK/XXKey instead of initial part from MSK */
pmk = pmk + PMK_LEN;
pmk_len = PMK_LEN;
} else
#endif /* CONFIG_IEEE80211R_AP */
if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
if (pmk_len > PMK_LEN_SUITE_B_192)
pmk_len = PMK_LEN_SUITE_B_192;
@ -4366,6 +4383,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
pmk_len = PMK_LEN;
}
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len);
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
sm->PTK.kck, sm->PTK.kck_len,
sm->wpa_auth->addr, sm->addr, session_timeout,
@ -4384,6 +4402,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
if (wpa_auth == NULL)
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
NULL, 0,
wpa_auth->addr,
@ -4401,6 +4420,7 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
if (wpa_auth->conf.disable_pmksa_caching)
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, PMK_LEN);
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
NULL, 0,
wpa_auth->addr, addr, 0, NULL,
@ -4425,6 +4445,7 @@ int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
if (wpa_auth->conf.disable_pmksa_caching)
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN);
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
NULL, 0, wpa_auth->addr, addr, session_timeout,
NULL, akmp))

View file

@ -475,6 +475,9 @@ void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len);
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);

View file

@ -25,6 +25,7 @@
#include "wmm.h"
#include "wpa_auth.h"
#include "wpa_auth_i.h"
#include "pmksa_cache_auth.h"
#ifdef CONFIG_IEEE80211R_AP
@ -2094,8 +2095,16 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
const u8 *identity, *radius_cui;
size_t identity_len, radius_cui_len;
int session_timeout;
const u8 *mpmk;
size_t mpmk_len;
if (sm->xxkey_len == 0) {
if (sm->xxkey_len > 0) {
mpmk = sm->xxkey;
mpmk_len = sm->xxkey_len;
} else if (sm->pmksa) {
mpmk = sm->pmksa->pmk;
mpmk_len = sm->pmksa->pmk_len;
} else {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
"derivation");
return -1;
@ -2112,7 +2121,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
&radius_cui);
session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
r0kh, r0kh_len, sm->addr,
pmk_r0, pmk_r0_name,
wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
@ -2217,6 +2226,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
return NULL;
}
forced_memzero(keybuf, sizeof(keybuf));
*len = subelem_len;
return subelem;
}
@ -3090,8 +3100,9 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
status = res;
wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
" auth_transaction=%d status=%d",
MAC2STR(sm->addr), auth_transaction + 1, status);
" auth_transaction=%d status=%u (%s)",
MAC2STR(sm->addr), auth_transaction + 1, status,
status2str(status));
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
resp_ies, resp_ies_len);
@ -3449,8 +3460,9 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
u8 *pos;
wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
" CurrentAP=" MACSTR " status=%d",
MAC2STR(sm->addr), MAC2STR(current_ap), status);
" CurrentAP=" MACSTR " status=%u (%s)",
MAC2STR(sm->addr), MAC2STR(current_ap), status,
status2str(status));
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
/* RRB - Forward action frame response to the Current AP */
@ -3556,7 +3568,7 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
pmk_r0->vlan, src_addr, type,
packet, packet_len);
os_memset(pmk_r1, 0, sizeof(pmk_r1));
forced_memzero(pmk_r1, sizeof(pmk_r1));
return ret;
}
@ -3882,10 +3894,7 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
ret = 0;
out:
if (plain) {
os_memset(plain, 0, plain_len);
os_free(plain);
}
bin_clear_free(plain, plain_len);
return ret;

View file

@ -53,6 +53,10 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->rsn_pairwise = conf->rsn_pairwise;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
#ifdef CONFIG_MACSEC
if (wconf->eapol_version > 2)
wconf->eapol_version = 2;
#endif /* CONFIG_MACSEC */
wconf->wmm_enabled = conf->wmm_enabled;
wconf->wmm_uapsd = conf->wmm_uapsd;
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;

View file

@ -1176,3 +1176,23 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
return pos + res;
}
#endif /* CONFIG_OWE */
#ifdef CONFIG_FILS
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len)
{
int res;
if (!sm ||
sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
WPA_KEY_MGMT_FT_FILS_SHA384))
return pos;
res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len, NULL);
if (res < 0)
return pos;
return pos + res;
}
#endif /* CONFIG_FILS */

View file

@ -0,0 +1,523 @@
/*
* IEEE 802.1X-2010 KaY Interface
* Copyright (c) 2019, 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 "pae/ieee802_1x_key.h"
#include "pae/ieee802_1x_kay.h"
#include "hostapd.h"
#include "sta_info.h"
#include "wpa_auth_kay.h"
#include "ieee802_1x.h"
#define DEFAULT_KEY_LEN 16
/* secure Connectivity Association Key Name (CKN) */
#define DEFAULT_CKN_LEN 16
static int hapd_macsec_init(void *priv, struct macsec_init_params *params)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->macsec_init)
return -1;
return hapd->driver->macsec_init(hapd->drv_priv, params);
}
static int hapd_macsec_deinit(void *priv)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->macsec_deinit)
return -1;
return hapd->driver->macsec_deinit(hapd->drv_priv);
}
static int hapd_macsec_get_capability(void *priv, enum macsec_cap *cap)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->macsec_get_capability)
return -1;
return hapd->driver->macsec_get_capability(hapd->drv_priv, cap);
}
static int hapd_enable_protect_frames(void *priv, Boolean enabled)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->enable_protect_frames)
return -1;
return hapd->driver->enable_protect_frames(hapd->drv_priv, enabled);
}
static int hapd_enable_encrypt(void *priv, Boolean enabled)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->enable_encrypt)
return -1;
return hapd->driver->enable_encrypt(hapd->drv_priv, enabled);
}
static int hapd_set_replay_protect(void *priv, Boolean enabled, u32 window)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->set_replay_protect)
return -1;
return hapd->driver->set_replay_protect(hapd->drv_priv, enabled,
window);
}
static int hapd_set_current_cipher_suite(void *priv, u64 cs)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->set_current_cipher_suite)
return -1;
return hapd->driver->set_current_cipher_suite(hapd->drv_priv, cs);
}
static int hapd_enable_controlled_port(void *priv, Boolean enabled)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->enable_controlled_port)
return -1;
return hapd->driver->enable_controlled_port(hapd->drv_priv, enabled);
}
static int hapd_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->get_receive_lowest_pn)
return -1;
return hapd->driver->get_receive_lowest_pn(hapd->drv_priv, sa);
}
static int hapd_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->get_transmit_next_pn)
return -1;
return hapd->driver->get_transmit_next_pn(hapd->drv_priv, sa);
}
static int hapd_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->set_transmit_next_pn)
return -1;
return hapd->driver->set_transmit_next_pn(hapd->drv_priv, sa);
}
static unsigned int conf_offset_val(enum confidentiality_offset co)
{
switch (co) {
case CONFIDENTIALITY_OFFSET_30:
return 30;
break;
case CONFIDENTIALITY_OFFSET_50:
return 50;
default:
return 0;
}
}
static int hapd_create_receive_sc(void *priv, struct receive_sc *sc,
enum validate_frames vf,
enum confidentiality_offset co)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->create_receive_sc)
return -1;
return hapd->driver->create_receive_sc(hapd->drv_priv, sc,
conf_offset_val(co), vf);
}
static int hapd_delete_receive_sc(void *priv, struct receive_sc *sc)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->delete_receive_sc)
return -1;
return hapd->driver->delete_receive_sc(hapd->drv_priv, sc);
}
static int hapd_create_receive_sa(void *priv, struct receive_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->create_receive_sa)
return -1;
return hapd->driver->create_receive_sa(hapd->drv_priv, sa);
}
static int hapd_delete_receive_sa(void *priv, struct receive_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->delete_receive_sa)
return -1;
return hapd->driver->delete_receive_sa(hapd->drv_priv, sa);
}
static int hapd_enable_receive_sa(void *priv, struct receive_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->enable_receive_sa)
return -1;
return hapd->driver->enable_receive_sa(hapd->drv_priv, sa);
}
static int hapd_disable_receive_sa(void *priv, struct receive_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->disable_receive_sa)
return -1;
return hapd->driver->disable_receive_sa(hapd->drv_priv, sa);
}
static int
hapd_create_transmit_sc(void *priv, struct transmit_sc *sc,
enum confidentiality_offset co)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->create_transmit_sc)
return -1;
return hapd->driver->create_transmit_sc(hapd->drv_priv, sc,
conf_offset_val(co));
}
static int hapd_delete_transmit_sc(void *priv, struct transmit_sc *sc)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->delete_transmit_sc)
return -1;
return hapd->driver->delete_transmit_sc(hapd->drv_priv, sc);
}
static int hapd_create_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->create_transmit_sa)
return -1;
return hapd->driver->create_transmit_sa(hapd->drv_priv, sa);
}
static int hapd_delete_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->delete_transmit_sa)
return -1;
return hapd->driver->delete_transmit_sa(hapd->drv_priv, sa);
}
static int hapd_enable_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->enable_transmit_sa)
return -1;
return hapd->driver->enable_transmit_sa(hapd->drv_priv, sa);
}
static int hapd_disable_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct hostapd_data *hapd = priv;
if (!hapd->driver->disable_transmit_sa)
return -1;
return hapd->driver->disable_transmit_sa(hapd->drv_priv, sa);
}
int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
struct sta_info *sta)
{
struct ieee802_1x_kay_ctx *kay_ctx;
struct ieee802_1x_kay *res = NULL;
enum macsec_policy policy;
ieee802_1x_dealloc_kay_sm_hapd(hapd);
if (!hapd->conf || hapd->conf->macsec_policy == 0)
return 0;
if (hapd->conf->macsec_policy == 1) {
if (hapd->conf->macsec_integ_only == 1)
policy = SHOULD_SECURE;
else
policy = SHOULD_ENCRYPT;
} else {
policy = DO_NOT_SECURE;
}
wpa_printf(MSG_DEBUG, "%s: if_name=%s", __func__, hapd->conf->iface);
kay_ctx = os_zalloc(sizeof(*kay_ctx));
if (!kay_ctx)
return -1;
kay_ctx->ctx = hapd;
kay_ctx->macsec_init = hapd_macsec_init;
kay_ctx->macsec_deinit = hapd_macsec_deinit;
kay_ctx->macsec_get_capability = hapd_macsec_get_capability;
kay_ctx->enable_protect_frames = hapd_enable_protect_frames;
kay_ctx->enable_encrypt = hapd_enable_encrypt;
kay_ctx->set_replay_protect = hapd_set_replay_protect;
kay_ctx->set_current_cipher_suite = hapd_set_current_cipher_suite;
kay_ctx->enable_controlled_port = hapd_enable_controlled_port;
kay_ctx->get_receive_lowest_pn = hapd_get_receive_lowest_pn;
kay_ctx->get_transmit_next_pn = hapd_get_transmit_next_pn;
kay_ctx->set_transmit_next_pn = hapd_set_transmit_next_pn;
kay_ctx->create_receive_sc = hapd_create_receive_sc;
kay_ctx->delete_receive_sc = hapd_delete_receive_sc;
kay_ctx->create_receive_sa = hapd_create_receive_sa;
kay_ctx->delete_receive_sa = hapd_delete_receive_sa;
kay_ctx->enable_receive_sa = hapd_enable_receive_sa;
kay_ctx->disable_receive_sa = hapd_disable_receive_sa;
kay_ctx->create_transmit_sc = hapd_create_transmit_sc;
kay_ctx->delete_transmit_sc = hapd_delete_transmit_sc;
kay_ctx->create_transmit_sa = hapd_create_transmit_sa;
kay_ctx->delete_transmit_sa = hapd_delete_transmit_sa;
kay_ctx->enable_transmit_sa = hapd_enable_transmit_sa;
kay_ctx->disable_transmit_sa = hapd_disable_transmit_sa;
res = ieee802_1x_kay_init(kay_ctx, policy,
hapd->conf->macsec_replay_protect,
hapd->conf->macsec_replay_window,
hapd->conf->macsec_port,
hapd->conf->mka_priority, hapd->conf->iface,
hapd->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
if (!res)
return -1;
hapd->kay = res;
return 0;
}
void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
{
if (!hapd->kay)
return;
ieee802_1x_kay_deinit(hapd->kay);
hapd->kay = NULL;
}
static int ieee802_1x_auth_get_session_id(struct hostapd_data *hapd,
struct sta_info *sta, u8 *sid,
size_t *len)
{
const u8 *session_id;
size_t id_len, need_len;
session_id = ieee802_1x_get_session_id(sta->eapol_sm, &id_len);
if (!session_id) {
wpa_printf(MSG_DEBUG,
"MACsec: Failed to get SessionID from EAPOL state machines");
return -1;
}
need_len = 1 + 2 * 32 /* random size */;
if (need_len > id_len) {
wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
return -1;
}
os_memcpy(sid, session_id, need_len);
*len = need_len;
return 0;
}
static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd,
struct sta_info *sta, u8 *msk, size_t *len)
{
const u8 *key;
size_t keylen;
if (!sta->eapol_sm)
return -1;
key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
if (key == NULL) {
wpa_printf(MSG_DEBUG,
"MACsec: Failed to get MSK from EAPOL state machines");
return -1;
}
wpa_printf(MSG_DEBUG, "MACsec: Successfully fetched key (len=%lu)",
(unsigned long) keylen);
wpa_hexdump_key(MSG_DEBUG, "MSK: ", key, keylen);
if (keylen > *len)
keylen = *len;
os_memcpy(msk, key, keylen);
*len = keylen;
return 0;
}
void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
struct sta_info *sta)
{
u8 *sid;
size_t sid_len = 128;
struct mka_key_name *ckn;
struct mka_key *cak;
struct mka_key *msk;
void *res = NULL;
if (!hapd->kay || hapd->kay->policy == DO_NOT_SECURE)
return NULL;
wpa_printf(MSG_DEBUG,
"IEEE 802.1X: External notification - Create MKA for "
MACSTR, MAC2STR(sta->addr));
msk = os_zalloc(sizeof(*msk));
sid = os_zalloc(sid_len);
ckn = os_zalloc(sizeof(*ckn));
cak = os_zalloc(sizeof(*cak));
if (!msk || !sid || !ckn || !cak)
goto fail;
msk->len = DEFAULT_KEY_LEN;
if (ieee802_1x_auth_get_msk(hapd, sta, msk->key, &msk->len)) {
wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get MSK");
goto fail;
}
if (ieee802_1x_auth_get_session_id(hapd, sta, sid, &sid_len))
{
wpa_printf(MSG_ERROR,
"IEEE 802.1X: Could not get EAP Session Id");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "own_addr", hapd->own_addr, ETH_ALEN);
wpa_hexdump(MSG_DEBUG, "sta_addr", sta->addr, ETH_ALEN);
/* Derive CAK from MSK */
cak->len = DEFAULT_KEY_LEN;
if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, hapd->own_addr,
sta->addr, cak->key, cak->len)) {
wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CAK failed");
goto fail;
}
wpa_hexdump_key(MSG_DEBUG, "Derived CAK", cak->key, cak->len);
/* Derive CKN from MSK */
ckn->len = DEFAULT_CKN_LEN;
if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, hapd->own_addr,
sta->addr, sid, sid_len, ckn->name)) {
wpa_printf(MSG_ERROR, "IEEE 802.1X: Deriving CKN failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "Derived CKN", ckn->name, ckn->len);
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, EAP_EXCHANGE,
TRUE);
fail:
bin_clear_free(msk, sizeof(*msk));
os_free(sid);
os_free(ckn);
bin_clear_free(cak, sizeof(*cak));
return res;
}
void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
struct sta_info *sta)
{
struct mka_key *cak;
struct mka_key_name *ckn;
void *res = NULL;
if ((hapd->conf->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
goto end;
ckn = os_zalloc(sizeof(*ckn));
if (!ckn)
goto end;
cak = os_zalloc(sizeof(*cak));
if (!cak)
goto free_ckn;
if (ieee802_1x_alloc_kay_sm_hapd(hapd, sta) < 0 || !hapd->kay)
goto free_cak;
if (hapd->kay->policy == DO_NOT_SECURE)
goto dealloc;
cak->len = hapd->conf->mka_cak_len;
os_memcpy(cak->key, hapd->conf->mka_cak, cak->len);
ckn->len = hapd->conf->mka_ckn_len;;
os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len);
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, TRUE);
if (res)
goto free_cak;
dealloc:
/* Failed to create MKA */
ieee802_1x_dealloc_kay_sm_hapd(hapd);
free_cak:
os_free(cak);
free_ckn:
os_free(ckn);
end:
return res;
}

View file

@ -0,0 +1,51 @@
/*
* IEEE 802.1X-2010 KaY Interface
* Copyright (c) 2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef WPA_AUTH_KAY_H
#define WPA_AUTH_KAY_H
#ifdef CONFIG_MACSEC
int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
struct sta_info *sta);
void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
struct sta_info *sta);
void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd);
void * ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
struct sta_info *sta);
#else /* CONFIG_MACSEC */
static inline int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
struct sta_info *sta)
{
return 0;
}
static inline void *
ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
struct sta_info *sta)
{
return NULL;
}
static inline void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd)
{
}
static inline void *
ieee802_1x_create_preshared_mka_hapd(struct hostapd_data *hapd,
struct sta_info *sta)
{
return NULL;
}
#endif /* CONFIG_MACSEC */
#endif /* WPA_AUTH_KAY_H */

File diff suppressed because it is too large Load diff

View file

@ -18,9 +18,11 @@
#include "crypto/sha256.h"
struct crypto_ecdh;
struct hostapd_ip_addr;
struct dpp_global;
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
#define DPP_TCP_PORT 7871
enum dpp_public_action_frame_type {
DPP_PA_AUTHENTICATION_REQ = 0,
@ -259,6 +261,22 @@ struct dpp_introduction {
size_t pmk_len;
};
struct dpp_relay_config {
const struct hostapd_ip_addr *ipaddr;
const u8 *pkhash;
void *cb_ctx;
void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
size_t len);
void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token, int prot,
struct wpabuf *buf);
};
struct dpp_controller_config {
const char *configurator_params;
int tcp_port;
};
#ifdef CONFIG_TESTING_OPTIONS
enum dpp_test_behavior {
DPP_TEST_DISABLED = 0,
@ -497,7 +515,26 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
char *buf, size_t buflen);
struct dpp_global * dpp_global_init(void);
int dpp_relay_add_controller(struct dpp_global *dpp,
struct dpp_relay_config *config);
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
const u8 *buf, size_t len, unsigned int freq,
const u8 *i_bootstrap, const u8 *r_bootstrap);
int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
size_t data_len);
int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config);
void dpp_controller_stop(struct dpp_global *dpp);
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
const struct hostapd_ip_addr *addr, int port);
struct dpp_global_config {
void *msg_ctx;
void *cb_ctx;
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
};
struct dpp_global * dpp_global_init(struct dpp_global_config *config);
void dpp_global_clear(struct dpp_global *dpp);
void dpp_global_deinit(struct dpp_global *dpp);

View file

@ -0,0 +1,215 @@
/*
* Shared Dragonfly functionality
* Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2019, 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/const_time.h"
#include "crypto/crypto.h"
#include "dragonfly.h"
int dragonfly_suitable_group(int group, int ecc_only)
{
/* Enforce REVmd rules on which SAE groups are suitable for production
* purposes: FFC groups whose prime is >= 3072 bits and ECC groups
* defined over a prime field whose prime is >= 256 bits. Furthermore,
* ECC groups defined over a characteristic 2 finite field and ECC
* groups with a co-factor greater than 1 are not suitable. Disable
* groups that use Brainpool curves as well for now since they leak more
* timing information due to the prime not being close to a power of
* two. */
return group == 19 || group == 20 || group == 21 ||
(!ecc_only &&
(group == 15 || group == 16 || group == 17 || group == 18));
}
unsigned int dragonfly_min_pwe_loop_iter(int group)
{
if (group == 22 || group == 23 || group == 24) {
/* FFC groups for which pwd-value is likely to be >= p
* frequently */
return 40;
}
if (group == 1 || group == 2 || group == 5 || group == 14 ||
group == 15 || group == 16 || group == 17 || group == 18) {
/* FFC groups that have prime that is close to a power of two */
return 1;
}
/* Default to 40 (this covers most ECC groups) */
return 40;
}
int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
struct crypto_bignum **qr,
struct crypto_bignum **qnr)
{
*qr = *qnr = NULL;
while (!(*qr) || !(*qnr)) {
struct crypto_bignum *tmp;
int res;
tmp = crypto_bignum_init();
if (!tmp || crypto_bignum_rand(tmp, prime) < 0) {
crypto_bignum_deinit(tmp, 0);
break;
}
res = crypto_bignum_legendre(tmp, prime);
if (res == 1 && !(*qr))
*qr = tmp;
else if (res == -1 && !(*qnr))
*qnr = tmp;
else
crypto_bignum_deinit(tmp, 0);
}
if (*qr && *qnr)
return 0;
crypto_bignum_deinit(*qr, 0);
crypto_bignum_deinit(*qnr, 0);
*qr = *qnr = NULL;
return -1;
}
static struct crypto_bignum *
dragonfly_get_rand_1_to_p_1(const struct crypto_bignum *prime)
{
struct crypto_bignum *tmp, *pm1, *one;
tmp = crypto_bignum_init();
pm1 = crypto_bignum_init();
one = crypto_bignum_init_set((const u8 *) "\x01", 1);
if (!tmp || !pm1 || !one ||
crypto_bignum_sub(prime, one, pm1) < 0 ||
crypto_bignum_rand(tmp, pm1) < 0 ||
crypto_bignum_add(tmp, one, tmp) < 0) {
crypto_bignum_deinit(tmp, 0);
tmp = NULL;
}
crypto_bignum_deinit(pm1, 0);
crypto_bignum_deinit(one, 0);
return tmp;
}
int dragonfly_is_quadratic_residue_blind(struct crypto_ec *ec,
const u8 *qr, const u8 *qnr,
const struct crypto_bignum *val)
{
struct crypto_bignum *r, *num, *qr_or_qnr = NULL;
int check, res = -1;
u8 qr_or_qnr_bin[DRAGONFLY_MAX_ECC_PRIME_LEN];
const struct crypto_bignum *prime;
size_t prime_len;
unsigned int mask;
prime = crypto_ec_get_prime(ec);
prime_len = crypto_ec_prime_len(ec);
/*
* Use a blinding technique to mask val while determining whether it is
* a quadratic residue modulo p to avoid leaking timing information
* while determining the Legendre symbol.
*
* v = val
* r = a random number between 1 and p-1, inclusive
* num = (v * r * r) modulo p
*/
r = dragonfly_get_rand_1_to_p_1(prime);
if (!r)
return -1;
num = crypto_bignum_init();
if (!num ||
crypto_bignum_mulmod(val, r, prime, num) < 0 ||
crypto_bignum_mulmod(num, r, prime, num) < 0)
goto fail;
/*
* Need to minimize differences in handling different cases, so try to
* avoid branches and timing differences.
*
* If r is odd:
* num = (num * qr) module p
* LGR(num, p) = 1 ==> quadratic residue
* else:
* num = (num * qnr) module p
* LGR(num, p) = -1 ==> quadratic residue
*
* mask is set to !odd(r)
*/
mask = const_time_is_zero(crypto_bignum_is_odd(r));
const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin);
qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len);
if (!qr_or_qnr ||
crypto_bignum_mulmod(num, qr_or_qnr, prime, num) < 0)
goto fail;
/* branchless version of check = odd(r) ? 1 : -1, */
check = const_time_select_int(mask, -1, 1);
/* Determine the Legendre symbol on the masked value */
res = crypto_bignum_legendre(num, prime);
if (res == -2) {
res = -1;
goto fail;
}
/* branchless version of res = res == check
* (res is -1, 0, or 1; check is -1 or 1) */
mask = const_time_eq(res, check);
res = const_time_select_int(mask, 1, 0);
fail:
crypto_bignum_deinit(num, 1);
crypto_bignum_deinit(r, 1);
crypto_bignum_deinit(qr_or_qnr, 1);
return res;
}
static int dragonfly_get_rand_2_to_r_1(struct crypto_bignum *val,
const struct crypto_bignum *order)
{
return crypto_bignum_rand(val, order) == 0 &&
!crypto_bignum_is_zero(val) &&
!crypto_bignum_is_one(val);
}
int dragonfly_generate_scalar(const struct crypto_bignum *order,
struct crypto_bignum *_rand,
struct crypto_bignum *_mask,
struct crypto_bignum *scalar)
{
int count;
/* Select two random values rand,mask such that 1 < rand,mask < r and
* rand + mask mod r > 1. */
for (count = 0; count < 100; count++) {
if (dragonfly_get_rand_2_to_r_1(_rand, order) &&
dragonfly_get_rand_2_to_r_1(_mask, order) &&
crypto_bignum_add(_rand, _mask, scalar) == 0 &&
crypto_bignum_mod(scalar, order, scalar) == 0 &&
!crypto_bignum_is_zero(scalar) &&
!crypto_bignum_is_one(scalar))
return 0;
}
/* This should not be reachable in practice if the random number
* generation is working. */
wpa_printf(MSG_INFO,
"dragonfly: Unable to get randomness for own scalar");
return -1;
}

View file

@ -0,0 +1,31 @@
/*
* Shared Dragonfly functionality
* Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
* Copyright (c) 2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef DRAGONFLY_H
#define DRAGONFLY_H
#define DRAGONFLY_MAX_ECC_PRIME_LEN 66
struct crypto_bignum;
struct crypto_ec;
int dragonfly_suitable_group(int group, int ecc_only);
unsigned int dragonfly_min_pwe_loop_iter(int group);
int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime,
struct crypto_bignum **qr,
struct crypto_bignum **qnr);
int dragonfly_is_quadratic_residue_blind(struct crypto_ec *ec,
const u8 *qr, const u8 *qnr,
const struct crypto_bignum *val);
int dragonfly_generate_scalar(const struct crypto_bignum *order,
struct crypto_bignum *_rand,
struct crypto_bignum *_mask,
struct crypto_bignum *scalar);
#endif /* DRAGONFLY_H */

View file

@ -361,30 +361,35 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
int freq, int channel, int ht_enabled,
int vht_enabled, int sec_channel_offset,
int vht_oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps)
int vht_enabled, int he_enabled,
int sec_channel_offset,
int oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps,
struct he_capabilities *he_cap)
{
if (!he_cap)
he_enabled = 0;
os_memset(data, 0, sizeof(*data));
data->mode = mode;
data->freq = freq;
data->channel = channel;
data->ht_enabled = ht_enabled;
data->vht_enabled = vht_enabled;
data->he_enabled = he_enabled;
data->sec_channel_offset = sec_channel_offset;
data->center_freq1 = freq + sec_channel_offset * 10;
data->center_freq2 = 0;
data->bandwidth = sec_channel_offset ? 40 : 20;
if (data->vht_enabled) switch (vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
if (data->vht_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
if (center_segment1 ||
(center_segment0 != 0 &&
5000 + center_segment0 * 5 != data->center_freq1 &&
2407 + center_segment0 * 5 != data->center_freq1))
return -1;
break;
case VHT_CHANWIDTH_80P80MHZ:
case CHANWIDTH_80P80MHZ:
if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
wpa_printf(MSG_ERROR,
"80+80 channel width is not supported!");
@ -395,11 +400,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1;
data->center_freq2 = 5000 + center_segment1 * 5;
/* fall through */
case VHT_CHANWIDTH_80MHZ:
case CHANWIDTH_80MHZ:
data->bandwidth = 80;
if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ &&
if ((oper_chwidth == CHANWIDTH_80MHZ &&
center_segment1) ||
(vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ &&
(oper_chwidth == CHANWIDTH_80P80MHZ &&
!center_segment1) ||
!sec_channel_offset)
return -1;
@ -432,7 +437,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1;
}
break;
case VHT_CHANWIDTH_160MHZ:
case CHANWIDTH_160MHZ:
data->bandwidth = 160;
if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {

View file

@ -32,9 +32,11 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
int freq, int channel, int ht_enabled,
int vht_enabled, int sec_channel_offset,
int vht_oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps);
int vht_enabled, int he_enabled,
int sec_channel_offset,
int oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps,
struct he_capabilities *he_caps);
void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
int disabled);
int ieee80211ac_cap_check(u32 hw, u32 conf);

View file

@ -274,6 +274,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->he_capabilities = pos;
elems->he_capabilities_len = elen;
break;
case WLAN_EID_EXT_HE_OPERATION:
elems->he_operation = pos;
elems->he_operation_len = elen;
break;
case WLAN_EID_EXT_OCV_OCI:
elems->oci = pos;
elems->oci_len = elen;
@ -702,7 +706,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
{
u8 op_class;
return ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT,
&op_class, channel);
}
@ -712,7 +716,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
* for HT40 and VHT. DFS channels are not covered.
* @freq: Frequency (MHz) to convert
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
* @vht: VHT channel width (VHT_CHANWIDTH_*)
* @vht: VHT channel width (CHANWIDTH_*)
* @op_class: Buffer for returning operating class
* @channel: Buffer for returning channel number
* Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
@ -767,13 +771,13 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
}
switch (vht) {
case VHT_CHANWIDTH_80MHZ:
case CHANWIDTH_80MHZ:
vht_opclass = 128;
break;
case VHT_CHANWIDTH_160MHZ:
case CHANWIDTH_160MHZ:
vht_opclass = 129;
break;
case VHT_CHANWIDTH_80P80MHZ:
case CHANWIDTH_80P80MHZ:
vht_opclass = 130;
break;
default:
@ -892,16 +896,16 @@ int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
case CHAN_WIDTH_40:
vht = VHT_CHANWIDTH_USE_HT;
vht = CHANWIDTH_USE_HT;
break;
case CHAN_WIDTH_80:
vht = VHT_CHANWIDTH_80MHZ;
vht = CHANWIDTH_80MHZ;
break;
case CHAN_WIDTH_80P80:
vht = VHT_CHANWIDTH_80P80MHZ;
vht = CHANWIDTH_80P80MHZ;
break;
case CHAN_WIDTH_160:
vht = VHT_CHANWIDTH_160MHZ;
vht = CHANWIDTH_160MHZ;
break;
}
@ -1315,6 +1319,185 @@ const char * fc2str(u16 fc)
}
const char * reason2str(u16 reason)
{
#define R2S(r) case WLAN_REASON_ ## r: return #r;
switch (reason) {
R2S(UNSPECIFIED)
R2S(PREV_AUTH_NOT_VALID)
R2S(DEAUTH_LEAVING)
R2S(DISASSOC_DUE_TO_INACTIVITY)
R2S(DISASSOC_AP_BUSY)
R2S(CLASS2_FRAME_FROM_NONAUTH_STA)
R2S(CLASS3_FRAME_FROM_NONASSOC_STA)
R2S(DISASSOC_STA_HAS_LEFT)
R2S(STA_REQ_ASSOC_WITHOUT_AUTH)
R2S(PWR_CAPABILITY_NOT_VALID)
R2S(SUPPORTED_CHANNEL_NOT_VALID)
R2S(BSS_TRANSITION_DISASSOC)
R2S(INVALID_IE)
R2S(MICHAEL_MIC_FAILURE)
R2S(4WAY_HANDSHAKE_TIMEOUT)
R2S(GROUP_KEY_UPDATE_TIMEOUT)
R2S(IE_IN_4WAY_DIFFERS)
R2S(GROUP_CIPHER_NOT_VALID)
R2S(PAIRWISE_CIPHER_NOT_VALID)
R2S(AKMP_NOT_VALID)
R2S(UNSUPPORTED_RSN_IE_VERSION)
R2S(INVALID_RSN_IE_CAPAB)
R2S(IEEE_802_1X_AUTH_FAILED)
R2S(CIPHER_SUITE_REJECTED)
R2S(TDLS_TEARDOWN_UNREACHABLE)
R2S(TDLS_TEARDOWN_UNSPECIFIED)
R2S(SSP_REQUESTED_DISASSOC)
R2S(NO_SSP_ROAMING_AGREEMENT)
R2S(BAD_CIPHER_OR_AKM)
R2S(NOT_AUTHORIZED_THIS_LOCATION)
R2S(SERVICE_CHANGE_PRECLUDES_TS)
R2S(UNSPECIFIED_QOS_REASON)
R2S(NOT_ENOUGH_BANDWIDTH)
R2S(DISASSOC_LOW_ACK)
R2S(EXCEEDED_TXOP)
R2S(STA_LEAVING)
R2S(END_TS_BA_DLS)
R2S(UNKNOWN_TS_BA)
R2S(TIMEOUT)
R2S(PEERKEY_MISMATCH)
R2S(AUTHORIZED_ACCESS_LIMIT_REACHED)
R2S(EXTERNAL_SERVICE_REQUIREMENTS)
R2S(INVALID_FT_ACTION_FRAME_COUNT)
R2S(INVALID_PMKID)
R2S(INVALID_MDE)
R2S(INVALID_FTE)
R2S(MESH_PEERING_CANCELLED)
R2S(MESH_MAX_PEERS)
R2S(MESH_CONFIG_POLICY_VIOLATION)
R2S(MESH_CLOSE_RCVD)
R2S(MESH_MAX_RETRIES)
R2S(MESH_CONFIRM_TIMEOUT)
R2S(MESH_INVALID_GTK)
R2S(MESH_INCONSISTENT_PARAMS)
R2S(MESH_INVALID_SECURITY_CAP)
R2S(MESH_PATH_ERROR_NO_PROXY_INFO)
R2S(MESH_PATH_ERROR_NO_FORWARDING_INFO)
R2S(MESH_PATH_ERROR_DEST_UNREACHABLE)
R2S(MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS)
R2S(MESH_CHANNEL_SWITCH_REGULATORY_REQ)
R2S(MESH_CHANNEL_SWITCH_UNSPECIFIED)
}
return "UNKNOWN";
#undef R2S
}
const char * status2str(u16 status)
{
#define S2S(s) case WLAN_STATUS_ ## s: return #s;
switch (status) {
S2S(SUCCESS)
S2S(UNSPECIFIED_FAILURE)
S2S(TDLS_WAKEUP_ALTERNATE)
S2S(TDLS_WAKEUP_REJECT)
S2S(SECURITY_DISABLED)
S2S(UNACCEPTABLE_LIFETIME)
S2S(NOT_IN_SAME_BSS)
S2S(CAPS_UNSUPPORTED)
S2S(REASSOC_NO_ASSOC)
S2S(ASSOC_DENIED_UNSPEC)
S2S(NOT_SUPPORTED_AUTH_ALG)
S2S(UNKNOWN_AUTH_TRANSACTION)
S2S(CHALLENGE_FAIL)
S2S(AUTH_TIMEOUT)
S2S(AP_UNABLE_TO_HANDLE_NEW_STA)
S2S(ASSOC_DENIED_RATES)
S2S(ASSOC_DENIED_NOSHORT)
S2S(SPEC_MGMT_REQUIRED)
S2S(PWR_CAPABILITY_NOT_VALID)
S2S(SUPPORTED_CHANNEL_NOT_VALID)
S2S(ASSOC_DENIED_NO_SHORT_SLOT_TIME)
S2S(ASSOC_DENIED_NO_HT)
S2S(R0KH_UNREACHABLE)
S2S(ASSOC_DENIED_NO_PCO)
S2S(ASSOC_REJECTED_TEMPORARILY)
S2S(ROBUST_MGMT_FRAME_POLICY_VIOLATION)
S2S(UNSPECIFIED_QOS_FAILURE)
S2S(DENIED_INSUFFICIENT_BANDWIDTH)
S2S(DENIED_POOR_CHANNEL_CONDITIONS)
S2S(DENIED_QOS_NOT_SUPPORTED)
S2S(REQUEST_DECLINED)
S2S(INVALID_PARAMETERS)
S2S(REJECTED_WITH_SUGGESTED_CHANGES)
S2S(INVALID_IE)
S2S(GROUP_CIPHER_NOT_VALID)
S2S(PAIRWISE_CIPHER_NOT_VALID)
S2S(AKMP_NOT_VALID)
S2S(UNSUPPORTED_RSN_IE_VERSION)
S2S(INVALID_RSN_IE_CAPAB)
S2S(CIPHER_REJECTED_PER_POLICY)
S2S(TS_NOT_CREATED)
S2S(DIRECT_LINK_NOT_ALLOWED)
S2S(DEST_STA_NOT_PRESENT)
S2S(DEST_STA_NOT_QOS_STA)
S2S(ASSOC_DENIED_LISTEN_INT_TOO_LARGE)
S2S(INVALID_FT_ACTION_FRAME_COUNT)
S2S(INVALID_PMKID)
S2S(INVALID_MDIE)
S2S(INVALID_FTIE)
S2S(REQUESTED_TCLAS_NOT_SUPPORTED)
S2S(INSUFFICIENT_TCLAS_PROCESSING_RESOURCES)
S2S(TRY_ANOTHER_BSS)
S2S(GAS_ADV_PROTO_NOT_SUPPORTED)
S2S(NO_OUTSTANDING_GAS_REQ)
S2S(GAS_RESP_NOT_RECEIVED)
S2S(STA_TIMED_OUT_WAITING_FOR_GAS_RESP)
S2S(GAS_RESP_LARGER_THAN_LIMIT)
S2S(REQ_REFUSED_HOME)
S2S(ADV_SRV_UNREACHABLE)
S2S(REQ_REFUSED_SSPN)
S2S(REQ_REFUSED_UNAUTH_ACCESS)
S2S(INVALID_RSNIE)
S2S(U_APSD_COEX_NOT_SUPPORTED)
S2S(U_APSD_COEX_MODE_NOT_SUPPORTED)
S2S(BAD_INTERVAL_WITH_U_APSD_COEX)
S2S(ANTI_CLOGGING_TOKEN_REQ)
S2S(FINITE_CYCLIC_GROUP_NOT_SUPPORTED)
S2S(CANNOT_FIND_ALT_TBTT)
S2S(TRANSMISSION_FAILURE)
S2S(REQ_TCLAS_NOT_SUPPORTED)
S2S(TCLAS_RESOURCES_EXCHAUSTED)
S2S(REJECTED_WITH_SUGGESTED_BSS_TRANSITION)
S2S(REJECT_WITH_SCHEDULE)
S2S(REJECT_NO_WAKEUP_SPECIFIED)
S2S(SUCCESS_POWER_SAVE_MODE)
S2S(PENDING_ADMITTING_FST_SESSION)
S2S(PERFORMING_FST_NOW)
S2S(PENDING_GAP_IN_BA_WINDOW)
S2S(REJECT_U_PID_SETTING)
S2S(REFUSED_EXTERNAL_REASON)
S2S(REFUSED_AP_OUT_OF_MEMORY)
S2S(REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED)
S2S(QUERY_RESP_OUTSTANDING)
S2S(REJECT_DSE_BAND)
S2S(TCLAS_PROCESSING_TERMINATED)
S2S(TS_SCHEDULE_CONFLICT)
S2S(DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL)
S2S(MCCAOP_RESERVATION_CONFLICT)
S2S(MAF_LIMIT_EXCEEDED)
S2S(MCCA_TRACK_LIMIT_EXCEEDED)
S2S(DENIED_DUE_TO_SPECTRUM_MANAGEMENT)
S2S(ASSOC_DENIED_NO_VHT)
S2S(ENABLEMENT_DENIED)
S2S(RESTRICTION_FROM_AUTHORIZED_GDB)
S2S(AUTHORIZATION_DEENABLED)
S2S(FILS_AUTHENTICATION_FAILURE)
S2S(UNKNOWN_AUTHENTICATION_SERVER)
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
}
return "UNKNOWN";
#undef S2S
}
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
size_t ies_len)
{

View file

@ -94,6 +94,7 @@ struct ieee802_11_elems {
const u8 *oci;
const u8 *multi_ap;
const u8 *he_capabilities;
const u8 *he_operation;
u8 ssid_len;
u8 supp_rates_len;
@ -143,6 +144,7 @@ struct ieee802_11_elems {
u8 oci_len;
u8 multi_ap_len;
u8 he_capabilities_len;
u8 he_operation_len;
struct mb_ies_info mb_ies;
};
@ -185,6 +187,8 @@ int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info);
const char * fc2str(u16 fc);
const char * reason2str(u16 reason);
const char * status2str(u16 status);
struct oper_class_map {
enum hostapd_hw_mode mode;

View file

@ -468,6 +468,7 @@
#define WLAN_EID_EXT_HE_CAPABILITIES 35
#define WLAN_EID_EXT_HE_OPERATION 36
#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
#define WLAN_EID_EXT_SPATIAL_REUSE 39
#define WLAN_EID_EXT_OCV_OCI 54
/* Extended Capabilities field */
@ -1274,10 +1275,12 @@ struct ieee80211_ampe_ie {
#define VHT_RX_NSS_MAX_STREAMS 8
/* VHT channel widths */
#define VHT_CHANWIDTH_USE_HT 0
#define VHT_CHANWIDTH_80MHZ 1
#define VHT_CHANWIDTH_160MHZ 2
#define VHT_CHANWIDTH_80P80MHZ 3
#define CHANWIDTH_USE_HT 0
#define CHANWIDTH_80MHZ 1
#define CHANWIDTH_160MHZ 2
#define CHANWIDTH_80P80MHZ 3
#define HE_NSS_MAX_STREAMS 8
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
@ -2091,7 +2094,7 @@ enum phy_type {
/*
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
* subfields.
* Note: These definitions are not the same as other VHT_CHANWIDTH_*.
* Note: These definitions are not the same as other CHANWIDTH_*.
*/
enum nr_chan_width {
NR_CHAN_WIDTH_20 = 0,
@ -2104,21 +2107,46 @@ enum nr_chan_width {
struct ieee80211_he_capabilities {
u8 he_mac_capab_info[6];
u8 he_phy_capab_info[11];
u8 he_txrx_mcs_support[12]; /* TODO: 4, 8, or 12 octets */
/* PPE Thresholds (optional) */
/* Followed by 4, 8, or 12 octets of Supported HE-MCS And NSS Set field
* and optional variable length PPE Thresholds field. */
u8 optional[];
} STRUCT_PACKED;
struct ieee80211_he_operation {
u32 he_oper_params; /* HE Operation Parameters[3] and
* BSS Color Information[1] */
u8 he_mcs_nss_set[2];
le32 he_oper_params; /* HE Operation Parameters[3] and
* BSS Color Information[1] */
le16 he_mcs_nss_set;
u8 vht_op_info_chwidth;
u8 vht_op_info_chan_center_freq_seg0_idx;
u8 vht_op_info_chan_center_freq_seg1_idx;
/* Followed by conditional MaxBSSID Indicator subfield (u8) */
} STRUCT_PACKED;
/*
* IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
*/
struct ieee80211_spatial_reuse {
u8 sr_ctrl; /* SR Control */
/* Up to 19 octets of parameters:
* Non-SRG OBSS PD Max Offset[0 or 1]
* SRG OBSS PD Min Offset[0 or 1]
* SRG OBSS PD Max Offset[0 or 1]
* SRG BSS Color Bitmap[0 or 8]
* SRG Partial BSSID Bitmap[0 or 8]
*/
u8 params[19];
} STRUCT_PACKED;
/* HE Capabilities Information defines */
#define HE_PHYCAP_CHANNEL_WIDTH_SET_IDX 0
#define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \
BIT(3) | BIT(4)))
#define HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G ((u8) BIT(1))
#define HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G ((u8) BIT(2))
#define HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G ((u8) BIT(3))
#define HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G ((u8) BIT(4))
#define HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX 3
#define HE_PHYCAP_SU_BEAMFORMER_CAPAB ((u8) BIT(7))
#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX 4
@ -2126,23 +2154,39 @@ struct ieee80211_he_operation {
#define HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX 4
#define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1))
#define HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX 6
#define HE_PHYCAP_PPE_THRESHOLD_PRESENT ((u8) BIT(7))
/* HE PPE Threshold define */
#define HE_PPE_THRES_RU_INDEX_BITMASK_MASK 0xf
#define HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT 3
#define HE_PPE_THRES_NSS_MASK 0x7
/* HE Operation defines */
/* HE Operation Parameters and BSS Color Information fields */
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(0) | BIT(1) | \
BIT(2) | BIT(3) | \
BIT(4) | BIT(5)))
#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(6))
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(7))
#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(8) | BIT(9) | \
BIT(10)))
#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 8
#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(11))
#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(12) | BIT(13) | \
BIT(14) | BIT(15) | \
BIT(16) | BIT(17) | \
BIT(18) | BIT(19) | \
BIT(20) | BIT(21)))
#define HE_OPERATION_RTS_THRESHOLD_OFFSET 12
#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(0) | BIT(1) | \
BIT(2)))
#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 0
#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(3))
#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(4) | BIT(5) | \
BIT(6) | BIT(7) | \
BIT(8) | BIT(9) | \
BIT(10) | BIT(11) | \
BIT(12) | BIT(13)))
#define HE_OPERATION_RTS_THRESHOLD_OFFSET 4
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
BIT(26) | BIT(27) | \
BIT(28) | BIT(29)))
#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(30))
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
#define HE_OPERATION_BSS_COLOR_OFFSET 24
/* Spatial Reuse defines */
#define SPATIAL_REUSE_SRP_DISALLOWED BIT(0)
#define SPATIAL_REUSE_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1)
#define SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT BIT(2)
#define SPATIAL_REUSE_SRG_INFORMATION_PRESENT BIT(3)
#define SPATIAL_REUSE_HESIGA_SR_VAL15_ALLOWED BIT(4)
struct ieee80211_he_mu_edca_parameter_set {
u8 he_qos_info;

View file

@ -1,7 +1,7 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
* Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation
* Copyright (c) 2018-2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -98,6 +98,9 @@ enum qca_radiotap_vendor_ids {
* which supports DFS offloading, to indicate a radar pattern has been
* detected. The channel is now unusable.
*
* @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO: Get information from the driver.
* Attributes defined in enum qca_wlan_vendor_attr_get_wifi_info.
*
* @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: Get the feature bitmap
* based on enum wifi_logger_supported_features. Attributes defined in
* enum qca_wlan_vendor_attr_get_logger_features.
@ -373,7 +376,9 @@ enum qca_radiotap_vendor_ids {
* @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START: Start spectral scan. The scan
* parameters are specified by enum qca_wlan_vendor_attr_spectral_scan.
* This returns a cookie (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE)
* identifying the operation in success case.
* identifying the operation in success case. In failure cases an
* error code (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE)
* describing the reason for the failure is returned.
*
* @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_STOP: Stop spectral scan. This uses
* a cookie (%QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE) from
@ -524,6 +529,65 @@ enum qca_radiotap_vendor_ids {
* parameters including Zigbee state and specific WLAN periods to enhance
* PTA master. All these parameters are delivered by the attributes
* defined in enum qca_mpta_helper_vendor_attr.
* @QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING: This sub command is used to
* implement Beacon frame reporting feature.
*
* Userspace can request the driver/firmware to periodically report
* received Beacon frames whose BSSID is same as the current connected
* BSS's MAC address.
*
* In case the STA seamlessly (without sending disconnect indication to
* userspace) roams to a different BSS, Beacon frame reporting will be
* automatically enabled for the Beacon frames whose BSSID is same as the
* MAC address of the new BSS. Beacon reporting will be stopped when the
* STA is disconnected (when the disconnect indication is sent to
* userspace) and need to be explicitly enabled by userspace for next
* connection.
*
* When a Beacon frame matching configured conditions is received, and if
* userspace has requested to send asynchronous beacon reports, the
* driver/firmware will encapsulate the details of the Beacon frame in an
* event and send it to userspace along with updating the BSS information
* in cfg80211 scan cache, otherwise driver will only update the cfg80211
* scan cache with the information from the received Beacon frame but will
* not send any active report to userspace.
*
* The userspace can request the driver/firmware to stop reporting Beacon
* frames. If the driver/firmware is not able to receive Beacon frames due
* to other Wi-Fi operations such as off-channel activities, etc., the
* driver/firmware will send a pause event to userspace and stop reporting
* Beacon frames. Whether the beacon reporting will be automatically
* resumed or not by the driver/firmware later will be reported to
* userspace using the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES
* flag. The beacon reporting shall be resumed for all the cases except
* either when userspace sets
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME flag in the command
* which triggered the current beacon reporting or during any disconnection
* case as indicated by setting
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON to
* QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED by the
* driver.
*
* After QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_PAUSE event is received
* by userspace with QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES
* flag not set, the next first
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO event from the driver
* shall be considered as un-pause event.
*
* All the attributes used with this command are defined in
* enum qca_wlan_vendor_attr_beacon_reporting_params.
* @QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP: In practice, some APs have
* interop issues with the DUT. This sub command is used to transfer the
* AP info between the driver and user space. This works both as a command
* and an event. As a command, it configures the stored list of APs from
* user space to firmware; as an event, it indicates the AP info detected
* by the firmware to user space for persistent storage. The attributes
* defined in enum qca_vendor_attr_interop_issues_ap are used to deliver
* the parameters.
* @QCA_NL80211_VENDOR_SUBCMD_OEM_DATA: This command is used to send OEM data
* binary blobs from application/service to firmware. The attributes
* defined in enum qca_wlan_vendor_attr_oem_data_params are used to deliver
* the parameters.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@ -692,6 +756,9 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE = 177,
QCA_NL80211_VENDOR_SUBCMD_PEER_STATS_CACHE_FLUSH = 178,
QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG = 179,
QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING = 180,
QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP = 181,
QCA_NL80211_VENDOR_SUBCMD_OEM_DATA = 182,
};
enum qca_wlan_vendor_attr {
@ -1788,6 +1855,30 @@ enum qca_wlan_vendor_attr_config {
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_GTX = 57,
/* Attribute to configure disconnect IEs to the driver.
* This carries an array of unsigned 8-bit characters.
*
* If this is configured, driver shall fill the IEs in disassoc/deauth
* frame.
* These IEs are expected to be considered only for the next
* immediate disconnection (disassoc/deauth frame) originated by
* the DUT, irrespective of the entity (user space/driver/firmware)
* triggering the disconnection.
* The host drivers are not expected to use the IEs set through
* this interface for further disconnections after the first immediate
* disconnection initiated post the configuration.
* If the IEs are also updated through cfg80211 interface (after the
* enhancement to cfg80211_disconnect), host driver is expected to
* take the union of IEs from both of these interfaces and send in
* further disassoc/deauth frames.
*/
QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES = 58,
/* 8-bit unsigned value for ELNA bypass.
* 1-Enable, 0-Disable
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@ -3204,11 +3295,28 @@ enum qca_vendor_attr_sar_limits {
/**
* enum qca_wlan_vendor_attr_get_wifi_info: Attributes for data used by
* QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO sub command.
*
* @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION: In a request this attribute
* should be set to any U8 value to indicate that the driver version
* should be returned. When enabled in this manner, in a response this
* attribute will contain a string representation of the driver version.
*
* @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION: In a request this attribute
* should be set to any U8 value to indicate that the firmware version
* should be returned. When enabled in this manner, in a response this
* attribute will contain a string representation of the firmware version.
*
* @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX: In a request this attribute
* should be set to any U32 value to indicate that the current radio
* index should be returned. When enabled in this manner, in a response
* this attribute will contain a U32 radio index value.
*
*/
enum qca_wlan_vendor_attr_get_wifi_info {
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION = 1,
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION = 2,
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST,
@ -4481,6 +4589,44 @@ enum qca_wlan_vendor_attr_spectral_scan {
* qca_wlan_vendor_attr_spectral_scan_request_type.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE = 23,
/* This specifies the frequency span over which spectral
* scan would be carried out. Its value depends on the
* value of QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE and
* the relation is as follows.
* QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL
* Not applicable. Spectral scan would happen in the
* operating span.
* QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE
* Center frequency (in MHz) of the span of interest or
* for convenience, center frequency (in MHz) of any channel
* in the span of interest. If agile spectral scan is initiated
* without setting a valid frequency it returns the error code
* (QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED).
* u32 attribute.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY = 24,
/* Spectral scan mode. u32 attribute.
* It uses values defined in enum qca_wlan_vendor_spectral_scan_mode.
* If this attribute is not present, it is assumed to be
* normal mode (QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL).
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE = 25,
/* Spectral scan error code. u32 attribute.
* It uses values defined in enum
* qca_wlan_vendor_spectral_scan_error_code.
* This attribute is included only in failure scenarios.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE = 26,
/* 8-bit unsigned value to enable/disable debug of the
* Spectral DMA ring.
* 1-enable, 0-disable
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DMA_RING_DEBUG = 27,
/* 8-bit unsigned value to enable/disable debug of the
* Spectral DMA buffers.
* 1-enable, 0-disable
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DMA_BUFFER_DEBUG = 28,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
@ -4559,6 +4705,8 @@ enum qca_wlan_vendor_attr_spectral_cap {
* u8 attribute.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
/* Flag attribute to indicate agile spectral scan capability */
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL = 11,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
@ -4575,6 +4723,13 @@ enum qca_wlan_vendor_attr_spectral_scan_status {
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ENABLED = 1,
/* Flag attribute to indicate whether spectral scan is in progress*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ACTIVE = 2,
/* Spectral scan mode. u32 attribute.
* It uses values defined in enum qca_wlan_vendor_spectral_scan_mode.
* If this attribute is not present, normal mode
* (QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL is assumed to be
* requested.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MODE = 3,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MAX =
@ -4599,6 +4754,43 @@ enum qca_wlan_vendor_attr_spectral_scan_request_type {
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE_CONFIG,
};
/**
* qca_wlan_vendor_spectral_scan_mode: Attribute values for
* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE in the vendor subcmd
* QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START and
* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MODE in the vendor subcmd
* QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS. This represents the
* spectral scan modes.
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL: Normal spectral scan:
* spectral scan in the current operating span.
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE: Agile spectral scan:
* spectral scan in the configured agile span.
*/
enum qca_wlan_vendor_spectral_scan_mode {
QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL = 0,
QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE = 1,
};
/**
* qca_wlan_vendor_spectral_scan_error_code: Attribute values for
* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE in the vendor subcmd
* QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START.
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED: Changing the value
* of a parameter is not supported.
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED: Requested spectral scan
* mode is not supported.
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE: A parameter
* has invalid value.
* @QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED: A parameter
* is not initialized.
*/
enum qca_wlan_vendor_spectral_scan_error_code {
QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED = 0,
QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED = 1,
QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE = 2,
QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED = 3,
};
/**
* qca_wlan_vendor_spectral_scan_cap_hw_gen: Attribute values for
* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN to the vendor subcmd
@ -6709,4 +6901,251 @@ enum qca_mpta_helper_vendor_attr {
QCA_MPTA_HELPER_VENDOR_ATTR_AFTER_LAST - 1
};
/**
* enum qca_wlan_vendor_beacon_reporting_op_types - Defines different types of
* operations for which %QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING can be used.
* Will be used by %QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE.
*
* @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START: Sent by userspace to the driver
* to request the driver to start reporting Beacon frames.
* @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_STOP: Sent by userspace to the driver to
* request the driver to stop reporting Beacon frames.
* @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO: Sent by the driver to
* userspace to report received Beacon frames.
* @QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE: Sent by the driver to userspace
* to indicate that the driver is going to pause reporting Beacon frames.
*/
enum qca_wlan_vendor_beacon_reporting_op_types {
QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START = 0,
QCA_WLAN_VENDOR_BEACON_REPORTING_OP_STOP = 1,
QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO = 2,
QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE = 3,
};
/**
* enum qca_wlan_vendor_beacon_reporting_pause_reasons - Defines different types
* of reasons for which the driver is pausing reporting Beacon frames. Will be
* used by %QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON.
*
* @QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED: For unspecified
* reasons.
* @QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED: When the
* driver/firmware is starting a scan.
* @QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED: When the
* driver/firmware disconnects from the ESS and indicates the disconnection to
* userspace (non-seamless roaming case). This reason code will be used by the
* driver/firmware to indicate stopping of beacon report events. Userspace will
* need to start beacon reporting again (if desired) by sending vendor command
* QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING with
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START after the next connection is
* completed.
*/
enum qca_wlan_vendor_beacon_reporting_pause_reasons {
QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED = 0,
QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED = 1,
QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED = 2,
};
/*
* enum qca_wlan_vendor_attr_beacon_reporting_params - List of attributes used
* in vendor sub-command QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING.
*/
enum qca_wlan_vendor_attr_beacon_reporting_params {
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_INVALID = 0,
/* Specifies the type of operation that the vendor command/event is
* intended for. Possible values for this attribute are defined in
* enum qca_wlan_vendor_beacon_reporting_op_types. u32 attribute.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE = 1,
/* Optionally set by userspace to request the driver to report Beacon
* frames using asynchronous vendor events when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START. NLA_FLAG attribute.
* If this flag is not set, the driver will only update Beacon frames in
* cfg80211 scan cache but not send any vendor events.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING = 2,
/* Optionally used by userspace to request the driver/firmware to report
* Beacon frames periodically when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START.
* u32 attribute, indicates the period of Beacon frames to be reported
* and in the units of beacon interval.
* If this attribute is missing in the command, then the default value
* of 1 will be assumed by driver, i.e., to report every Beacon frame.
* Zero is an invalid value.
* If a valid value is received for this attribute, the driver will
* update the cfg80211 scan cache periodically as per the value received
* in this attribute in addition to updating the cfg80211 scan cache
* when there is significant change in Beacon frame IEs.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD = 3,
/* Used by the driver to encapsulate the SSID when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
* u8 array with a maximum size of 32.
*
* When generating beacon report from non-MBSSID Beacon frame, the SSID
* will be taken from the SSID element of the received Beacon frame.
*
* When generating beacon report from Multiple BSSID Beacon frame and if
* the BSSID of the current connected BSS matches the BSSID of the
* transmitting BSS, the SSID will be taken from the SSID element of the
* received Beacon frame.
*
* When generating beacon report from Multiple BSSID Beacon frame and if
* the BSSID of the current connected BSS matches the BSSID of one of
* the* nontransmitting BSSs, the SSID will be taken from the SSID field
* included in the nontransmitted BSS profile whose derived BSSID is
* same as the BSSID of the current connected BSS. When there is no
* nontransmitted BSS profile whose derived BSSID is same as the BSSID
* of current connected* BSS, this attribute will not be present.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID = 4,
/* Used by the driver to encapsulate the BSSID of the AP to which STA is
* currently connected to when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO. u8 array with a
* fixed size of 6 bytes.
*
* When generating beacon report from a Multiple BSSID beacon and the
* current connected BSSID matches one of the nontransmitted BSSIDs in a
* Multiple BSSID set, this BSSID will be that particular nontransmitted
* BSSID and not the transmitted BSSID (i.e., the transmitting address
* of the Beacon frame).
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID = 5,
/* Used by the driver to encapsulate the frequency in MHz on which
* the Beacon frame was received when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is
* set to QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
* u32 attribute.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ = 6,
/* Used by the driver to encapsulate the Beacon interval
* when the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
* u16 attribute. The value will be copied from the Beacon frame and the
* units are TUs.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI = 7,
/* Used by the driver to encapsulate the Timestamp field from the Beacon
* frame when the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set
* to QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO.
* u64 attribute.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF = 8,
/* Used by the driver to encapsulate the CLOCK_BOOTTIME when this
* Beacon frame is received in the driver when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO. u64 attribute, in
* the units of nanoseconds. This value is expected to have accuracy of
* about 10 ms.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED = 9,
/* Used by the driver to encapsulate the IEs of the Beacon frame from
* which this event is generated when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO. u8 array.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_IES = 10,
/* Used by the driver to specify the reason for the driver/firmware to
* pause sending beacons to userspace when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE. Possible values are
* defined in enum qca_wlan_vendor_beacon_reporting_pause_reasons, u32
* attribute.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON = 11,
/* Used by the driver to specify whether the driver will automatically
* resume reporting beacon events to userspace later (for example after
* the ongoing off-channel activity is completed etc.) when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE. NLA_FLAG attribute.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES = 12,
/* Optionally set by userspace to request the driver not to resume
* beacon reporting after a pause is completed, when the
* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE is set to
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START. NLA_FLAG attribute.
* If this flag is set, the driver will not resume beacon reporting
* after any pause in beacon reporting is completed. Userspace has to
* send QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command again in order
* to initiate beacon reporting again. If this flag is set in the recent
* QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command, then in the
* subsequent QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE event (if any)
* the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES shall not be
* set by the driver. Setting this flag until and unless there is a
* specific need is not recommended as there is a chance of some beacons
* received after pause command and next start command being not
* reported.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME = 13,
/* Keep last */
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_LAST,
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX =
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_LAST - 1
};
/**
* enum qca_vendor_interop_issues_ap_type - Interop issue types
* This enum defines the valid set of values of interop issue types. These
* values are used by attribute %QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE.
*
* @QCA_VENDOR_INTEROP_ISSUES_AP_ON_STA_PS: The AP has power save interop issue
* when the STA's Qpower feature is enabled.
*/
enum qca_vendor_interop_issues_ap_type {
QCA_VENDOR_INTEROP_ISSUES_AP_INVALID = 0,
QCA_VENDOR_INTEROP_ISSUES_AP_ON_STA_PS = 1,
};
/**
* enum qca_vendor_attr_interop_issues_ap - attribute for AP with interop issues
* Values are used by %QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP.
*
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_INVALID: Invalid value
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE: Interop issue type
* 32-bit unsigned value. The values defined in enum
* qca_vendor_interop_issues_ap_type are used.
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST: APs' BSSID container
* array of nested QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID attributes.
* It is present and mandatory for the command but is not used for the event
* since only a single BSSID is reported in an event.
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID: AP's BSSID 6-byte MAC address.
* It is used within the nested QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST
* attribute in command case and without such encapsulation in the event case.
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST: last value
* @QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX: max value
*/
enum qca_vendor_attr_interop_issues_ap {
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_INVALID,
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE,
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST,
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID,
/* keep last */
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX =
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST - 1
};
/*
* enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command
* QCA_NL80211_VENDOR_SUBCMD_OEM_DATA.
*
* @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: The binary blob for the vendor
* command QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this attribute.
* NLA_BINARY attribute, the max size is 1024 bytes.
*/
enum qca_wlan_vendor_attr_oem_data_params {
QCA_WLAN_VENDOR_ATTR_OEM_DATA_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA = 1,
/* keep last */
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX =
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST - 1
};
#endif /* QCA_VENDOR_H */

View file

@ -15,35 +15,22 @@
#include "crypto/random.h"
#include "crypto/dh_groups.h"
#include "ieee802_11_defs.h"
#include "dragonfly.h"
#include "sae.h"
static int sae_suitable_group(int group)
{
#ifdef CONFIG_TESTING_OPTIONS
/* Allow all groups for testing purposes in non-production builds. */
return 1;
#else /* CONFIG_TESTING_OPTIONS */
/* Enforce REVmd rules on which SAE groups are suitable for production
* purposes: FFC groups whose prime is >= 3072 bits and ECC groups
* defined over a prime field whose prime is >= 256 bits. Furthermore,
* ECC groups defined over a characteristic 2 finite field and ECC
* groups with a co-factor greater than 1 are not suitable. */
return group == 19 || group == 20 || group == 21 ||
group == 28 || group == 29 || group == 30 ||
group == 15 || group == 16 || group == 17 || group == 18;
#endif /* CONFIG_TESTING_OPTIONS */
}
int sae_set_group(struct sae_data *sae, int group)
{
struct sae_temporary_data *tmp;
if (!sae_suitable_group(group)) {
#ifdef CONFIG_TESTING_OPTIONS
/* Allow all groups for testing purposes in non-production builds. */
#else /* CONFIG_TESTING_OPTIONS */
if (!dragonfly_suitable_group(group, 0)) {
wpa_printf(MSG_DEBUG, "SAE: Reject unsuitable group %d", group);
return -1;
}
#endif /* CONFIG_TESTING_OPTIONS */
sae_clear_data(sae);
tmp = sae->tmp = os_zalloc(sizeof(*tmp));
@ -58,6 +45,7 @@ int sae_set_group(struct sae_data *sae, int group)
sae->group = group;
tmp->prime_len = crypto_ec_prime_len(tmp->ec);
tmp->prime = crypto_ec_get_prime(tmp->ec);
tmp->order_len = crypto_ec_order_len(tmp->ec);
tmp->order = crypto_ec_get_order(tmp->ec);
return 0;
}
@ -82,6 +70,7 @@ int sae_set_group(struct sae_data *sae, int group)
}
tmp->prime = tmp->prime_buf;
tmp->order_len = tmp->dh->order_len;
tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
tmp->dh->order_len);
if (tmp->order_buf == NULL) {
@ -134,58 +123,6 @@ void sae_clear_data(struct sae_data *sae)
}
static void buf_shift_right(u8 *buf, size_t len, size_t bits)
{
size_t i;
for (i = len - 1; i > 0; i--)
buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
buf[0] >>= bits;
}
static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
{
u8 val[SAE_MAX_PRIME_LEN];
int iter = 0;
struct crypto_bignum *bn = NULL;
int order_len_bits = crypto_bignum_bits(sae->tmp->order);
size_t order_len = (order_len_bits + 7) / 8;
if (order_len > sizeof(val))
return NULL;
for (;;) {
if (iter++ > 100 || random_get_bytes(val, order_len) < 0)
return NULL;
if (order_len_bits % 8)
buf_shift_right(val, order_len, 8 - order_len_bits % 8);
bn = crypto_bignum_init_set(val, order_len);
if (bn == NULL)
return NULL;
if (crypto_bignum_is_zero(bn) ||
crypto_bignum_is_one(bn) ||
crypto_bignum_cmp(bn, sae->tmp->order) >= 0) {
crypto_bignum_deinit(bn, 0);
continue;
}
break;
}
os_memset(val, 0, order_len);
return bn;
}
static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
{
crypto_bignum_deinit(sae->tmp->sae_rand, 1);
sae->tmp->sae_rand = sae_get_rand(sae);
if (sae->tmp->sae_rand == NULL)
return NULL;
return sae_get_rand(sae);
}
static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
{
wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
@ -200,103 +137,6 @@ static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
}
static struct crypto_bignum *
get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
int *r_odd)
{
for (;;) {
struct crypto_bignum *r;
u8 tmp[SAE_MAX_ECC_PRIME_LEN];
if (random_get_bytes(tmp, prime_len) < 0)
break;
if (prime_bits % 8)
buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
if (os_memcmp(tmp, prime, prime_len) >= 0)
continue;
r = crypto_bignum_init_set(tmp, prime_len);
if (!r)
break;
if (crypto_bignum_is_zero(r)) {
crypto_bignum_deinit(r, 0);
continue;
}
*r_odd = tmp[prime_len - 1] & 0x01;
return r;
}
return NULL;
}
static int is_quadratic_residue_blind(struct sae_data *sae,
const u8 *prime, size_t bits,
const u8 *qr, const u8 *qnr,
const struct crypto_bignum *y_sqr)
{
struct crypto_bignum *r, *num, *qr_or_qnr = NULL;
int r_odd, check, res = -1;
u8 qr_or_qnr_bin[SAE_MAX_ECC_PRIME_LEN];
size_t prime_len = sae->tmp->prime_len;
unsigned int mask;
/*
* Use the blinding technique to mask y_sqr while determining
* whether it is a quadratic residue modulo p to avoid leaking
* timing information while determining the Legendre symbol.
*
* v = y_sqr
* r = a random number between 1 and p-1, inclusive
* num = (v * r * r) modulo p
*/
r = get_rand_1_to_p_1(prime, prime_len, bits, &r_odd);
if (!r)
return -1;
num = crypto_bignum_init();
if (!num ||
crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 ||
crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
goto fail;
/*
* Need to minimize differences in handling different cases, so try to
* avoid branches and timing differences.
*
* If r_odd:
* num = (num * qr) module p
* LGR(num, p) = 1 ==> quadratic residue
* else:
* num = (num * qnr) module p
* LGR(num, p) = -1 ==> quadratic residue
*/
mask = const_time_is_zero(r_odd);
const_time_select_bin(mask, qnr, qr, prime_len, qr_or_qnr_bin);
qr_or_qnr = crypto_bignum_init_set(qr_or_qnr_bin, prime_len);
if (!qr_or_qnr ||
crypto_bignum_mulmod(num, qr_or_qnr, sae->tmp->prime, num) < 0)
goto fail;
/* r_odd is 0 or 1; branchless version of check = r_odd ? 1 : -1, */
check = const_time_select_int(mask, -1, 1);
res = crypto_bignum_legendre(num, sae->tmp->prime);
if (res == -2) {
res = -1;
goto fail;
}
/* branchless version of res = res == check
* (res is -1, 0, or 1; check is -1 or 1) */
mask = const_time_eq(res, check);
res = const_time_select_int(mask, 1, 0);
fail:
crypto_bignum_deinit(num, 1);
crypto_bignum_deinit(r, 1);
crypto_bignum_deinit(qr_or_qnr, 1);
return res;
}
static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
const u8 *prime, const u8 *qr, const u8 *qnr,
u8 *pwd_value)
@ -304,6 +144,8 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
struct crypto_bignum *y_sqr, *x_cand;
int res;
size_t bits;
int cmp_prime;
unsigned int in_range;
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
@ -317,8 +159,13 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
pwd_value, sae->tmp->prime_len);
if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
return 0;
cmp_prime = const_time_memcmp(pwd_value, prime, sae->tmp->prime_len);
/* Create a const_time mask for selection based on prf result
* being smaller than prime. */
in_range = const_time_fill_msb((unsigned int) cmp_prime);
/* The algorithm description would skip the next steps if
* cmp_prime >= 0 (reutnr 0 here), but go through them regardless to
* minimize externally observable differences in behavior. */
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
if (!x_cand)
@ -328,9 +175,12 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
if (!y_sqr)
return -1;
res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
res = dragonfly_is_quadratic_residue_blind(sae->tmp->ec, qr, qnr,
y_sqr);
crypto_bignum_deinit(y_sqr, 1);
return res;
if (res < 0)
return res;
return const_time_select_int(in_range, res, 0);
}
@ -423,47 +273,11 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
}
static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
const struct crypto_bignum *prime_bn,
size_t prime_bits, struct crypto_bignum **qr,
struct crypto_bignum **qnr)
{
*qr = NULL;
*qnr = NULL;
while (!(*qr) || !(*qnr)) {
u8 tmp[SAE_MAX_ECC_PRIME_LEN];
struct crypto_bignum *q;
int res;
if (random_get_bytes(tmp, prime_len) < 0)
break;
if (prime_bits % 8)
buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
if (os_memcmp(tmp, prime, prime_len) >= 0)
continue;
q = crypto_bignum_init_set(tmp, prime_len);
if (!q)
break;
res = crypto_bignum_legendre(q, prime_bn);
if (res == 1 && !(*qr))
*qr = q;
else if (res == -1 && !(*qnr))
*qnr = q;
else
crypto_bignum_deinit(q, 0);
}
return (*qr && *qnr) ? 0 : -1;
}
static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
size_t password_len, const char *identifier)
{
u8 counter, k = 40;
u8 counter, k;
u8 addrs[2 * ETH_ALEN];
const u8 *addr[3];
size_t len[3];
@ -477,7 +291,6 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
u8 x_cand_bin[SAE_MAX_ECC_PRIME_LEN];
u8 qr_bin[SAE_MAX_ECC_PRIME_LEN];
u8 qnr_bin[SAE_MAX_ECC_PRIME_LEN];
size_t bits;
int res = -1;
u8 found = 0; /* 0 (false) or 0xff (true) to be used as const_time_*
* mask */
@ -494,14 +307,12 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
prime_len) < 0)
goto fail;
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
/*
* Create a random quadratic residue (qr) and quadratic non-residue
* (qnr) modulo p for blinding purposes during the loop.
*/
if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
&qr, &qnr) < 0 ||
if (dragonfly_get_random_qr_qnr(sae->tmp->prime, &qr, &qnr) < 0 ||
crypto_bignum_to_bin(qr, qr_bin, sizeof(qr_bin), prime_len) < 0 ||
crypto_bignum_to_bin(qnr, qnr_bin, sizeof(qnr_bin), prime_len) < 0)
goto fail;
@ -537,6 +348,8 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
* attacks that attempt to determine the number of iterations required
* in the loop.
*/
k = dragonfly_min_pwe_loop_iter(sae->group);
for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
@ -618,13 +431,6 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
}
static int sae_modp_group_require_masking(int group)
{
/* Groups for which pwd-value is likely to be >= p frequently */
return group == 22 || group == 23 || group == 24;
}
static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
size_t password_len, const char *identifier)
@ -673,7 +479,7 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
len[num_elem] = sizeof(counter);
num_elem++;
k = sae_modp_group_require_masking(sae->group) ? 40 : 1;
k = dragonfly_min_pwe_loop_iter(sae->group);
for (counter = 1; counter <= k || !found; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
@ -768,48 +574,23 @@ static int sae_derive_commit_element_ffc(struct sae_data *sae,
static int sae_derive_commit(struct sae_data *sae)
{
struct crypto_bignum *mask;
int ret = -1;
unsigned int counter = 0;
int ret;
do {
counter++;
if (counter > 100) {
/*
* This cannot really happen in practice if the random
* number generator is working. Anyway, to avoid even a
* theoretical infinite loop, break out after 100
* attemps.
*/
return -1;
}
mask = sae_get_rand_and_mask(sae);
if (mask == NULL) {
wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
return -1;
}
/* commit-scalar = (rand + mask) modulo r */
if (!sae->tmp->own_commit_scalar) {
sae->tmp->own_commit_scalar = crypto_bignum_init();
if (!sae->tmp->own_commit_scalar)
goto fail;
}
crypto_bignum_add(sae->tmp->sae_rand, mask,
sae->tmp->own_commit_scalar);
crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
sae->tmp->own_commit_scalar);
} while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) ||
crypto_bignum_is_one(sae->tmp->own_commit_scalar));
if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) ||
(sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0))
goto fail;
ret = 0;
fail:
mask = crypto_bignum_init();
if (!sae->tmp->sae_rand)
sae->tmp->sae_rand = crypto_bignum_init();
if (!sae->tmp->own_commit_scalar)
sae->tmp->own_commit_scalar = crypto_bignum_init();
ret = !mask || !sae->tmp->sae_rand || !sae->tmp->own_commit_scalar ||
dragonfly_generate_scalar(sae->tmp->order, sae->tmp->sae_rand,
mask,
sae->tmp->own_commit_scalar) < 0 ||
(sae->tmp->ec &&
sae_derive_commit_element_ecc(sae, mask) < 0) ||
(sae->tmp->dh &&
sae_derive_commit_element_ffc(sae, mask) < 0);
crypto_bignum_deinit(mask, 1);
return ret;
return ret ? -1 : 0;
}
@ -930,10 +711,16 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
tmp);
crypto_bignum_mod(tmp, sae->tmp->order, tmp);
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
/* IEEE Std 802.11-2016 is not exactly clear on the encoding of the bit
* string that is needed for KCK, PMK, and PMKID derivation, but it
* seems to make most sense to encode the
* (commit-scalar + peer-commit-scalar) mod r part as a bit string by
* zero padding it from left to the length of the order (in full
* octets). */
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
val, sae->tmp->order_len, keys, sizeof(keys)) < 0)
goto fail;
os_memset(keyseed, 0, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);

View file

@ -33,6 +33,7 @@ struct sae_temporary_data {
struct crypto_bignum *sae_rand;
struct crypto_ec *ec;
int prime_len;
int order_len;
const struct dh_group *dh;
const struct crypto_bignum *prime;
const struct crypto_bignum *order;

View file

@ -9,6 +9,6 @@
#define GIT_VERSION_STR_POSTFIX ""
#endif /* GIT_VERSION_STR_POSTFIX */
#define VERSION_STR "2.8" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#define VERSION_STR "2.9" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#endif /* VERSION_H */

View file

@ -2075,6 +2075,16 @@ u32 wpa_akm_to_suite(int akm)
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
if (akm & WPA_KEY_MGMT_SAE)
return RSN_AUTH_KEY_MGMT_SAE;
if (akm & WPA_KEY_MGMT_FT_SAE)
return RSN_AUTH_KEY_MGMT_FT_SAE;
if (akm & WPA_KEY_MGMT_OWE)
return RSN_AUTH_KEY_MGMT_OWE;
if (akm & WPA_KEY_MGMT_DPP)
return RSN_AUTH_KEY_MGMT_DPP;
if (akm & WPA_KEY_MGMT_OSEN)
return RSN_AUTH_KEY_MGMT_OSEN;
return 0;
}

View file

@ -87,6 +87,9 @@ extern "C" {
#define WPA_EVENT_BEACON_LOSS "CTRL-EVENT-BEACON-LOSS "
/** Regulatory domain channel */
#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
/** Channel switch started (followed by freq=<MHz> and other channel parameters)
*/
#define WPA_EVENT_CHANNEL_SWITCH_STARTED "CTRL-EVENT-STARTED-CHANNEL-SWITCH "
/** Channel switch (followed by freq=<MHz> and other channel parameters) */
#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
/** SAE authentication failed due to unknown password identifier */

View file

@ -65,7 +65,7 @@ extern const u8 rcons[10];
#else /* AES_SMALL_TABLES */
#define RCON(i) (rcons[(i)] << 24)
#define RCON(i) ((u32) rcons[(i)] << 24)
static inline u32 rotr(u32 val, int bits)
{
@ -94,10 +94,10 @@ static inline u32 rotr(u32 val, int bits)
#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
#define TD3(i) rotr(Td0[(i) & 0xff], 24)
#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
#define TD44(i) (Td4s[(i) & 0xff])
#define TD41(i) ((u32) Td4s[((i) >> 24) & 0xff] << 24)
#define TD42(i) ((u32) Td4s[((i) >> 16) & 0xff] << 16)
#define TD43(i) ((u32) Td4s[((i) >> 8) & 0xff] << 8)
#define TD44(i) ((u32) Td4s[(i) & 0xff])
#define TD0_(i) Td0[(i) & 0xff]
#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
#define TD2_(i) rotr(Td0[(i) & 0xff], 16)

View file

@ -644,13 +644,6 @@ int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
int crypto_bignum_cmp(const struct crypto_bignum *a,
const struct crypto_bignum *b);
/**
* crypto_bignum_bits - Get size of a bignum in bits
* @a: Bignum
* Returns: Number of bits in the bignum
*/
int crypto_bignum_bits(const struct crypto_bignum *a);
/**
* crypto_bignum_is_zero - Is the given bignum zero
* @a: Bignum

View file

@ -570,8 +570,8 @@ int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
failed = !q || !ctx || !tmp ||
!BN_mod_exp(tmp, pub, q, p, ctx) ||
!BN_is_one(tmp);
BN_clear(q);
BN_clear(tmp);
BN_clear_free(q);
BN_clear_free(tmp);
BN_CTX_free(ctx);
if (failed)
goto fail;
@ -580,8 +580,8 @@ int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len,
res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len,
prime, prime_len, secret, len);
fail:
BN_clear(pub);
BN_clear(p);
BN_clear_free(pub);
BN_clear_free(p);
return res;
}
@ -1303,6 +1303,18 @@ int crypto_bignum_to_bin(const struct crypto_bignum *a,
if (padlen > buflen)
return -1;
if (padlen) {
#ifdef OPENSSL_IS_BORINGSSL
if (BN_bn2bin_padded(buf, padlen, (const BIGNUM *) a) == 0)
return -1;
return padlen;
#else /* OPENSSL_IS_BORINGSSL */
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
return BN_bn2binpad((const BIGNUM *) a, buf, padlen);
#endif
#endif
}
num_bytes = BN_num_bytes((const BIGNUM *) a);
if ((size_t) num_bytes > buflen)
return -1;
@ -1476,12 +1488,6 @@ int crypto_bignum_cmp(const struct crypto_bignum *a,
}
int crypto_bignum_bits(const struct crypto_bignum *a)
{
return BN_num_bits((const BIGNUM *) a);
}
int crypto_bignum_is_zero(const struct crypto_bignum *a)
{
return BN_is_zero((const BIGNUM *) a);
@ -1870,7 +1876,7 @@ struct crypto_ecdh * crypto_ecdh_init(int group)
{
struct crypto_ecdh *ecdh;
EVP_PKEY *params = NULL;
EC_KEY *ec_params;
EC_KEY *ec_params = NULL;
EVP_PKEY_CTX *kctx = NULL;
ecdh = os_zalloc(sizeof(*ecdh));
@ -1913,6 +1919,7 @@ struct crypto_ecdh * crypto_ecdh_init(int group)
}
done:
EC_KEY_free(ec_params);
EVP_PKEY_free(params);
EVP_PKEY_CTX_free(kctx);
@ -2052,13 +2059,17 @@ struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
secret = wpabuf_alloc(secret_len);
if (!secret)
goto fail;
if (EVP_PKEY_derive(ctx, wpabuf_put(secret, secret_len),
&secret_len) != 1) {
if (EVP_PKEY_derive(ctx, wpabuf_put(secret, 0), &secret_len) != 1) {
wpa_printf(MSG_ERROR,
"OpenSSL: EVP_PKEY_derive(2) failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
if (secret->size != secret_len)
wpa_printf(MSG_DEBUG,
"OpenSSL: EVP_PKEY_derive(2) changed secret_len %d -> %d",
(int) secret->size, (int) secret_len);
wpabuf_put(secret, secret_len);
done:
BN_free(x);

View file

@ -1198,12 +1198,6 @@ int crypto_bignum_cmp(const struct crypto_bignum *a,
}
int crypto_bignum_bits(const struct crypto_bignum *a)
{
return mp_count_bits((mp_int *) a);
}
int crypto_bignum_is_zero(const struct crypto_bignum *a)
{
return mp_iszero((mp_int *) a);

View file

@ -224,7 +224,7 @@ void SHA1Transform(u32 state[5], const unsigned char buffer[64])
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
os_memset(block, 0, 64);
forced_memzero(block, 64);
#endif
}
@ -300,7 +300,7 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
os_memset(context->buffer, 0, 64);
os_memset(context->state, 0, 20);
os_memset(context->count, 0, 8);
os_memset(finalcount, 0, 8);
forced_memzero(finalcount, sizeof(finalcount));
}
/* ===== end - public domain SHA1 implementation ===== */

View file

@ -61,7 +61,7 @@ int sha1_prf(const u8 *key, size_t key_len, const char *label,
}
counter++;
}
os_memset(hash, 0, sizeof(hash));
forced_memzero(hash, sizeof(hash));
return 0;
}

View file

@ -92,10 +92,10 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
SHA1_pos++;
}
os_memset(A_MD5, 0, MD5_MAC_LEN);
os_memset(P_MD5, 0, MD5_MAC_LEN);
os_memset(A_SHA1, 0, SHA1_MAC_LEN);
os_memset(P_SHA1, 0, SHA1_MAC_LEN);
forced_memzero(A_MD5, MD5_MAC_LEN);
forced_memzero(P_MD5, MD5_MAC_LEN);
forced_memzero(A_SHA1, SHA1_MAC_LEN);
forced_memzero(P_SHA1, SHA1_MAC_LEN);
return 0;
}

View file

@ -66,7 +66,7 @@ int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
len[0] = SHA1_MAC_LEN;
}
os_memset(hash, 0, SHA1_MAC_LEN);
forced_memzero(hash, SHA1_MAC_LEN);
return 0;
}

View file

@ -86,7 +86,8 @@ int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
_addr[1] = mac;
_len[1] = SHA1_MAC_LEN;
ret = sha1_vector(2, _addr, _len, mac);
os_memset(k_pad, 0, sizeof(k_pad));
forced_memzero(k_pad, sizeof(k_pad));
forced_memzero(tk, sizeof(tk));
return ret;
}

View file

@ -69,7 +69,7 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
if (iter == 255) {
os_memset(out, 0, outlen);
os_memset(T, 0, SHA256_MAC_LEN);
forced_memzero(T, SHA256_MAC_LEN);
return -1;
}
iter++;
@ -77,11 +77,11 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
{
os_memset(out, 0, outlen);
os_memset(T, 0, SHA256_MAC_LEN);
forced_memzero(T, SHA256_MAC_LEN);
return -1;
}
}
os_memset(T, 0, SHA256_MAC_LEN);
forced_memzero(T, SHA256_MAC_LEN);
return 0;
}

View file

@ -102,7 +102,7 @@ int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
buf[pos - 1] &= mask;
}
os_memset(hash, 0, sizeof(hash));
forced_memzero(hash, sizeof(hash));
return 0;
}

View file

@ -26,8 +26,8 @@
* This function is used to derive new, cryptographically separate keys from a
* given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
*/
void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
int tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
{
size_t clen;
u8 A[SHA256_MAC_LEN];
@ -50,12 +50,15 @@ void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
* PRF(secret, label, seed) = P_SHA256(secret, label + seed)
*/
hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
if (hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A) < 0)
return -1;
pos = 0;
while (pos < outlen) {
hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
if (hmac_sha256_vector(secret, secret_len, 3, addr, len, P) <
0 ||
hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A) < 0)
return -1;
clen = outlen - pos;
if (clen > SHA256_MAC_LEN)
@ -63,4 +66,6 @@ void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
os_memcpy(out + pos, P, clen);
pos += clen;
}
return 0;
}

View file

@ -20,9 +20,9 @@ int sha256_prf(const u8 *key, size_t key_len, const char *label,
int sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf,
size_t buf_len_bits);
void tls_prf_sha256(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
int tls_prf_sha256(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);

View file

@ -69,7 +69,7 @@ int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
if (iter == 255) {
os_memset(out, 0, outlen);
os_memset(T, 0, SHA384_MAC_LEN);
forced_memzero(T, SHA384_MAC_LEN);
return -1;
}
iter++;
@ -77,11 +77,11 @@ int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
if (hmac_sha384_vector(secret, secret_len, 4, addr, len, T) < 0)
{
os_memset(out, 0, outlen);
os_memset(T, 0, SHA384_MAC_LEN);
forced_memzero(T, SHA384_MAC_LEN);
return -1;
}
}
os_memset(T, 0, SHA384_MAC_LEN);
forced_memzero(T, SHA384_MAC_LEN);
return 0;
}

View file

@ -102,7 +102,7 @@ int sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
buf[pos - 1] &= mask;
}
os_memset(hash, 0, sizeof(hash));
forced_memzero(hash, sizeof(hash));
return 0;
}

View file

@ -69,7 +69,7 @@ int hmac_sha512_kdf(const u8 *secret, size_t secret_len,
if (iter == 255) {
os_memset(out, 0, outlen);
os_memset(T, 0, SHA512_MAC_LEN);
forced_memzero(T, SHA512_MAC_LEN);
return -1;
}
iter++;
@ -77,11 +77,11 @@ int hmac_sha512_kdf(const u8 *secret, size_t secret_len,
if (hmac_sha512_vector(secret, secret_len, 4, addr, len, T) < 0)
{
os_memset(out, 0, outlen);
os_memset(T, 0, SHA512_MAC_LEN);
forced_memzero(T, SHA512_MAC_LEN);
return -1;
}
}
os_memset(T, 0, SHA512_MAC_LEN);
forced_memzero(T, SHA512_MAC_LEN);
return 0;
}

View file

@ -102,7 +102,7 @@ int sha512_prf_bits(const u8 *key, size_t key_len, const char *label,
buf[pos - 1] &= mask;
}
os_memset(hash, 0, sizeof(hash));
forced_memzero(hash, sizeof(hash));
return 0;
}

View file

@ -48,6 +48,18 @@ enum tls_fail_reason {
#define TLS_MAX_ALT_SUBJECT 10
struct tls_cert_data {
int depth;
const char *subject;
const struct wpabuf *cert;
const u8 *hash;
size_t hash_len;
const char *altsubject[TLS_MAX_ALT_SUBJECT];
int num_altsubject;
const char *serial_num;
int tod;
};
union tls_event_data {
struct {
int depth;
@ -57,16 +69,7 @@ union tls_event_data {
const struct wpabuf *cert;
} cert_fail;
struct {
int depth;
const char *subject;
const struct wpabuf *cert;
const u8 *hash;
size_t hash_len;
const char *altsubject[TLS_MAX_ALT_SUBJECT];
int num_altsubject;
const char *serial_num;
} peer_cert;
struct tls_cert_data peer_cert;
struct {
int is_local;
@ -108,6 +111,7 @@ struct tls_config {
#define TLS_CONN_ENABLE_TLSv1_0 BIT(14)
#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
#define TLS_CONN_TEAP_ANON_DH BIT(17)
/**
* struct tls_connection_params - Parameters for TLS connection
@ -184,12 +188,15 @@ struct tls_connection_params {
const char *suffix_match;
const char *domain_match;
const char *client_cert;
const char *client_cert2;
const u8 *client_cert_blob;
size_t client_cert_blob_len;
const char *private_key;
const char *private_key2;
const u8 *private_key_blob;
size_t private_key_blob_len;
const char *private_key_passwd;
const char *private_key_passwd2;
const char *dh_file;
const u8 *dh_blob;
size_t dh_blob_len;
@ -643,4 +650,24 @@ tls_connection_get_success_data(struct tls_connection *conn);
void tls_connection_remove_session(struct tls_connection *conn);
/**
* tls_get_tls_unique - Fetch "tls-unique" for channel binding
* @conn: Connection context data from tls_connection_init()
* @buf: Buffer for returning the value
* @max_len: Maximum length of the buffer in bytes
* Returns: Number of bytes written to buf or -1 on error
*
* This function can be used to fetch "tls-unique" (RFC 5929, Section 3) which
* is the first TLS Finished message sent in the most recent TLS handshake of
* the TLS connection.
*/
int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len);
/**
* tls_connection_get_cipher_suite - Get current TLS cipher suite
* @conn: Connection context data from tls_connection_init()
* Returns: TLS cipher suite of the current connection or 0 on error
*/
u16 tls_connection_get_cipher_suite(struct tls_connection *conn);
#endif /* TLS_H */

View file

@ -44,6 +44,13 @@
#define OPENSSL_NEED_EAP_FAST_PRF
#endif
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
defined(EAP_SERVER_FAST) || defined(EAP_TEAP) || \
defined(EAP_SERVER_TEAP)
#define EAP_FAST_OR_TEAP
#endif
#if defined(OPENSSL_IS_BORINGSSL)
/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
typedef size_t stack_index_t;
@ -1071,11 +1078,8 @@ void * tls_init(const struct tls_config *conf)
}
#ifndef OPENSSL_NO_ENGINE
wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_load_ENGINE_strings();
ENGINE_load_dynamic();
#endif /* OPENSSL_VERSION_NUMBER */
wpa_printf(MSG_DEBUG, "ENGINE: Loading builtin engines");
ENGINE_load_builtin_engines();
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
@ -1331,6 +1335,8 @@ static const char * openssl_content_type(int content_type)
return "heartbeat";
case 256:
return "TLS header info"; /* pseudo content type */
case 257:
return "inner content type"; /* pseudo content type */
default:
return "?";
}
@ -1340,6 +1346,8 @@ static const char * openssl_content_type(int content_type)
static const char * openssl_handshake_type(int content_type, const u8 *buf,
size_t len)
{
if (content_type == 257 && buf && len == 1)
return openssl_content_type(buf[0]);
if (content_type != 22 || !buf || len == 0)
return "";
switch (buf[0]) {
@ -1570,6 +1578,11 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
options |= SSL_OP_NO_COMPRESSION;
#endif /* SSL_OP_NO_COMPRESSION */
SSL_set_options(conn->ssl, options);
#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
/* Hopefully there is no need for middlebox compatibility mechanisms
* when going through EAP authentication. */
SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
#endif
conn->ssl_in = BIO_new(BIO_s_mem());
if (!conn->ssl_in) {
@ -2152,6 +2165,34 @@ static void openssl_tls_fail_event(struct tls_connection *conn,
}
static int openssl_cert_tod(X509 *cert)
{
CERTIFICATEPOLICIES *ext;
stack_index_t i;
char buf[100];
int res;
int tod = 0;
ext = X509_get_ext_d2i(cert, NID_certificate_policies, NULL, NULL);
if (!ext)
return 0;
for (i = 0; i < sk_POLICYINFO_num(ext); i++) {
POLICYINFO *policy;
policy = sk_POLICYINFO_value(ext, i);
res = OBJ_obj2txt(buf, sizeof(buf), policy->policyid, 0);
if (res < 0 || (size_t) res >= sizeof(buf))
continue;
wpa_printf(MSG_DEBUG, "OpenSSL: Certificate Policy %s", buf);
if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
tod = 1;
}
return tod;
}
static void openssl_tls_cert_event(struct tls_connection *conn,
X509 *err_cert, int depth,
const char *subject)
@ -2244,6 +2285,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
ev.peer_cert.altsubject[alt] = altsubject[alt];
ev.peer_cert.num_altsubject = num_altsubject;
ev.peer_cert.tod = openssl_cert_tod(err_cert);
context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert);
for (alt = 0; alt < num_altsubject; alt++)
@ -2348,7 +2391,30 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
}
#endif /* CONFIG_SHA256 */
openssl_tls_cert_event(conn, err_cert, depth, buf);
if (!preverify_ok) {
if (depth > 0) {
/* Send cert event for the peer certificate so that
* the upper layers get information about it even if
* validation of a CA certificate fails. */
STACK_OF(X509) *chain;
chain = X509_STORE_CTX_get1_chain(x509_ctx);
if (chain && sk_X509_num(chain) > 0) {
char buf2[256];
X509 *cert;
cert = sk_X509_value(chain, 0);
X509_NAME_oneline(X509_get_subject_name(cert),
buf2, sizeof(buf2));
openssl_tls_cert_event(conn, cert, 0, buf2);
}
if (chain)
sk_X509_pop_free(chain, X509_free);
}
wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
" error %d (%s) depth %d for '%s'", err, err_str,
depth, buf);
@ -2404,8 +2470,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"Domain mismatch",
TLS_FAIL_DOMAIN_MISMATCH);
} else
openssl_tls_cert_event(conn, err_cert, depth, buf);
}
if (conn->cert_probe && preverify_ok && depth == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
@ -2580,9 +2645,23 @@ static int tls_connection_ca_cert(struct tls_data *data,
(const unsigned char **) &ca_cert_blob,
ca_cert_blob_len);
if (cert == NULL) {
tls_show_errors(MSG_WARNING, __func__,
"Failed to parse ca_cert_blob");
return -1;
BIO *bio = BIO_new_mem_buf(ca_cert_blob,
ca_cert_blob_len);
if (bio) {
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
BIO_free(bio);
}
if (!cert) {
tls_show_errors(MSG_WARNING, __func__,
"Failed to parse ca_cert_blob");
return -1;
}
while (ERR_get_error()) {
/* Ignore errors from DER conversion. */
}
}
if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
@ -3016,6 +3095,40 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags,
}
#endif /* CONFIG_SUITEB */
if (flags & TLS_CONN_TEAP_ANON_DH) {
#ifndef TEAP_DH_ANON_CS
#define TEAP_DH_ANON_CS \
"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:" \
"ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:" \
"ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:" \
"DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:" \
"DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:" \
"DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:" \
"ADH-AES256-GCM-SHA384:ADH-AES128-GCM-SHA256:" \
"ADH-AES256-SHA256:ADH-AES128-SHA256:ADH-AES256-SHA:ADH-AES128-SHA"
#endif
static const char *cs = TEAP_DH_ANON_CS;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
!defined(LIBRESSL_VERSION_NUMBER) && \
!defined(OPENSSL_IS_BORINGSSL)
/*
* Need to drop to security level 0 to allow anonymous
* cipher suites for EAP-TEAP.
*/
SSL_set_security_level(conn->ssl, 0);
#endif
wpa_printf(MSG_DEBUG,
"OpenSSL: Enable cipher suites for anonymous EAP-TEAP provisioning: %s",
cs);
if (SSL_set_cipher_list(conn->ssl, cs) != 1) {
tls_show_errors(MSG_INFO, __func__,
"Cipher suite configuration failed");
return -1;
}
}
return 0;
}
@ -4002,7 +4115,7 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
_out, skip + out_len) == 0) {
ret = 0;
}
os_memset(master_key, 0, sizeof(master_key));
forced_memzero(master_key, sizeof(master_key));
os_free(rnd);
if (ret == 0)
os_memcpy(out, _out + skip, out_len);
@ -4192,6 +4305,22 @@ openssl_connection_handshake(struct tls_connection *conn,
wpa_printf(MSG_DEBUG,
"OpenSSL: Handshake finished - resumed=%d",
tls_connection_resumed(conn->ssl_ctx, conn));
if (conn->server) {
char *buf;
size_t buflen = 2000;
buf = os_malloc(buflen);
if (buf) {
if (SSL_get_shared_ciphers(conn->ssl, buf,
buflen)) {
buf[buflen - 1] = '\0';
wpa_printf(MSG_DEBUG,
"OpenSSL: Shared ciphers: %s",
buf);
}
os_free(buf);
}
}
if (appl_data && in_data)
*appl_data = openssl_get_appl_data(conn,
wpabuf_len(in_data));
@ -4374,11 +4503,15 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
c++;
}
if (!buf[0]) {
wpa_printf(MSG_DEBUG, "OpenSSL: No ciphers listed");
return -1;
}
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#ifdef EAP_FAST_OR_TEAP
if (os_strstr(buf, ":ADH-")) {
/*
* Need to drop to security level 0 to allow anonymous
@ -4389,7 +4522,7 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
/* Force at least security level 1 */
SSL_set_security_level(conn->ssl, 1);
}
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
#endif /* EAP_FAST_OR_TEAP */
#endif
if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
@ -4443,7 +4576,7 @@ int tls_connection_enable_workaround(void *ssl_ctx,
}
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#ifdef EAP_FAST_OR_TEAP
/* ClientHello TLS extensions require a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
@ -4460,7 +4593,7 @@ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
return 0;
}
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
#endif /* EAP_FAST_OR_TEAP */
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
@ -4669,6 +4802,7 @@ static int ocsp_resp_cb(SSL *s, void *arg)
res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
&this_update, &next_update);
if (!res) {
OCSP_CERTID_free(id);
id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
if (!id) {
wpa_printf(MSG_DEBUG,
@ -4979,6 +5113,114 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
static void openssl_debug_dump_cipher_list(SSL_CTX *ssl_ctx)
{
SSL *ssl;
int i;
ssl = SSL_new(ssl_ctx);
if (!ssl)
return;
wpa_printf(MSG_DEBUG,
"OpenSSL: Enabled cipher suites in priority order");
for (i = 0; ; i++) {
const char *cipher;
cipher = SSL_get_cipher_list(ssl, i);
if (!cipher)
break;
wpa_printf(MSG_DEBUG, "Cipher %d: %s", i, cipher);
}
SSL_free(ssl);
}
#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
static const char * openssl_pkey_type_str(const EVP_PKEY *pkey)
{
if (!pkey)
return "NULL";
switch (EVP_PKEY_type(EVP_PKEY_id(pkey))) {
case EVP_PKEY_RSA:
return "RSA";
case EVP_PKEY_DSA:
return "DSA";
case EVP_PKEY_DH:
return "DH";
case EVP_PKEY_EC:
return "EC";
}
return "?";
}
static void openssl_debug_dump_certificate(int i, X509 *cert)
{
char buf[256];
EVP_PKEY *pkey;
ASN1_INTEGER *ser;
char serial_num[128];
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
ser = X509_get_serialNumber(cert);
if (ser)
wpa_snprintf_hex_uppercase(serial_num, sizeof(serial_num),
ASN1_STRING_get0_data(ser),
ASN1_STRING_length(ser));
else
serial_num[0] = '\0';
pkey = X509_get_pubkey(cert);
wpa_printf(MSG_DEBUG, "%d: %s (%s) %s", i, buf,
openssl_pkey_type_str(pkey), serial_num);
EVP_PKEY_free(pkey);
}
static void openssl_debug_dump_certificates(SSL_CTX *ssl_ctx)
{
STACK_OF(X509) *certs;
wpa_printf(MSG_DEBUG, "OpenSSL: Configured certificate chain");
if (SSL_CTX_get0_chain_certs(ssl_ctx, &certs) == 1) {
int i;
for (i = sk_X509_num(certs); i > 0; i--)
openssl_debug_dump_certificate(i, sk_X509_value(certs,
i - 1));
}
openssl_debug_dump_certificate(0, SSL_CTX_get0_certificate(ssl_ctx));
}
#endif
static void openssl_debug_dump_certificate_chains(SSL_CTX *ssl_ctx)
{
#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(BORINGSSL_API_VERSION)
int res;
for (res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
res == 1;
res = SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_NEXT))
openssl_debug_dump_certificates(ssl_ctx);
SSL_CTX_set_current_cert(ssl_ctx, SSL_CERT_SET_FIRST);
#endif
}
static void openssl_debug_dump_ctx(SSL_CTX *ssl_ctx)
{
openssl_debug_dump_cipher_list(ssl_ctx);
openssl_debug_dump_certificate_chains(ssl_ctx);
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
@ -5004,6 +5246,9 @@ int tls_global_set_params(void *tls_ctx,
tls_global_client_cert(data, params->client_cert) ||
tls_global_private_key(data, params->private_key,
params->private_key_passwd) ||
tls_global_client_cert(data, params->client_cert2) ||
tls_global_private_key(data, params->private_key2,
params->private_key_passwd2) ||
tls_global_dh(data, params->dh_file)) {
wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
return -1;
@ -5073,11 +5318,13 @@ int tls_global_set_params(void *tls_ctx,
tls_global->ocsp_stapling_response = NULL;
#endif /* HAVE_OCSP */
openssl_debug_dump_ctx(ssl_ctx);
return 0;
}
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#ifdef EAP_FAST_OR_TEAP
/* Pre-shared secred requires a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
* build this file with unmodified openssl. */
@ -5158,7 +5405,7 @@ static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
return 1;
}
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
#endif /* EAP_FAST_OR_TEAP */
int tls_connection_set_session_ticket_cb(void *tls_ctx,
@ -5166,7 +5413,7 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
tls_session_ticket_cb cb,
void *ctx)
{
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
#ifdef EAP_FAST_OR_TEAP
conn->session_ticket_cb = cb;
conn->session_ticket_cb_ctx = ctx;
@ -5183,9 +5430,9 @@ int tls_connection_set_session_ticket_cb(void *tls_ctx,
}
return 0;
#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
#else /* EAP_FAST_OR_TEAP */
return -1;
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
#endif /* EAP_FAST_OR_TEAP */
}
@ -5268,3 +5515,36 @@ void tls_connection_remove_session(struct tls_connection *conn)
wpa_printf(MSG_DEBUG,
"OpenSSL: Removed cached session to disable session resumption");
}
int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
{
size_t len;
int reused;
reused = SSL_session_reused(conn->ssl);
if ((conn->server && !reused) || (!conn->server && reused))
len = SSL_get_peer_finished(conn->ssl, buf, max_len);
else
len = SSL_get_finished(conn->ssl, buf, max_len);
if (len == 0 || len > max_len)
return -1;
return len;
}
u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
{
const SSL_CIPHER *cipher;
cipher = SSL_get_current_cipher(conn->ssl);
if (!cipher)
return 0;
#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
return SSL_CIPHER_get_protocol_id(cipher);
#else
return SSL_CIPHER_get_id(cipher) & 0xFFFF;
#endif
}

View file

@ -141,7 +141,7 @@ static int wolfssl_receive_cb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
if (get > (wpabuf_len(data->in_data) - data->consumed))
get = wpabuf_len(data->in_data) - data->consumed;
os_memcpy(buf, wpabuf_head(data->in_data) + data->consumed, get);
os_memcpy(buf, wpabuf_head_u8(data->in_data) + data->consumed, get);
data->consumed += get;
if (get == 0)
@ -2044,7 +2044,7 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
_out, skip + out_len);
}
os_memset(master_key, 0, master_key_len);
forced_memzero(master_key, master_key_len);
if (ret == 0)
os_memcpy(out, _out + skip, out_len);
bin_clear_free(tmp_out, skip + out_len);

View file

@ -101,6 +101,20 @@ enum reg_type {
REGDOM_TYPE_INTERSECTION,
};
/**
* struct hostapd_wmm_rule - WMM regulatory rule
* @min_cwmin: Lower bound of CW_min value
* @min_cwmax: Lower bound of CW_max value
* @min_aifs: Lower bound of AIFS value
* @max_txop: Upper bound of TXOP, value in units of 32 usec
*/
struct hostapd_wmm_rule {
int min_cwmin;
int min_cwmax;
int min_aifs;
int max_txop;
};
/**
* struct hostapd_channel_data - Channel information
*/
@ -156,34 +170,48 @@ struct hostapd_channel_data {
* dfs_cac_ms - DFS CAC time in milliseconds
*/
unsigned int dfs_cac_ms;
/**
* wmm_rules_valid - Indicates wmm_rules state
*/
int wmm_rules_valid;
/**
* wmm_rules - WMM regulatory rules
*/
struct hostapd_wmm_rule wmm_rules[WMM_AC_NUM];
};
#define HE_MAX_NUM_SS 8
#define HE_MAX_PHY_CAPAB_SIZE 3
/**
* struct he_ppe_threshold - IEEE 802.11ax HE PPE Threshold
*/
struct he_ppe_threshold {
u32 numss_m1;
u32 ru_count;
u32 ppet16_ppet8_ru3_ru0[HE_MAX_NUM_SS];
};
#define HE_MAX_MAC_CAPAB_SIZE 6
#define HE_MAX_PHY_CAPAB_SIZE 11
#define HE_MAX_MCS_CAPAB_SIZE 12
#define HE_MAX_PPET_CAPAB_SIZE 25
/**
* struct he_capabilities - IEEE 802.11ax HE capabilities
*/
struct he_capabilities {
u8 he_supported;
u32 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
u32 mac_cap;
u32 mcs;
struct he_ppe_threshold ppet;
u8 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
u8 mac_cap[HE_MAX_MAC_CAPAB_SIZE];
u8 mcs[HE_MAX_MCS_CAPAB_SIZE];
u8 ppet[HE_MAX_PPET_CAPAB_SIZE];
};
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
enum ieee80211_op_mode {
IEEE80211_MODE_INFRA = 0,
IEEE80211_MODE_IBSS = 1,
IEEE80211_MODE_AP = 2,
IEEE80211_MODE_MESH = 5,
/* only add new entries before IEEE80211_MODE_NUM */
IEEE80211_MODE_NUM
};
/**
* struct hostapd_hw_modes - Supported hardware mode information
*/
@ -243,15 +271,10 @@ struct hostapd_hw_modes {
/**
* he_capab - HE (IEEE 802.11ax) capabilities
*/
struct he_capabilities he_capab;
struct he_capabilities he_capab[IEEE80211_MODE_NUM];
};
#define IEEE80211_MODE_INFRA 0
#define IEEE80211_MODE_IBSS 1
#define IEEE80211_MODE_AP 2
#define IEEE80211_MODE_MESH 5
#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
@ -698,6 +721,11 @@ struct hostapd_freq_params {
*/
int vht_enabled;
/**
* he_enabled - Whether HE is enabled
*/
int he_enabled;
/**
* center_freq1 - Segment 0 center frequency in MHz
*
@ -1045,6 +1073,14 @@ struct wpa_driver_associate_params {
*/
int req_key_mgmt_offload;
/**
* req_handshake_offload - Request EAPOL handshake offload
*
* Request EAPOL handshake offload for this connection if the device
* supports it.
*/
int req_handshake_offload;
/**
* Flag for indicating whether this association includes support for
* RRM (Radio Resource Measurements)
@ -1122,6 +1158,11 @@ enum hide_ssid {
HIDDEN_SSID_ZERO_CONTENTS
};
enum ch_switch_state {
CH_SW_STARTED,
CH_SW_FINISHED
};
struct wowlan_triggers {
u8 any;
u8 disconnect;
@ -1752,6 +1793,7 @@ struct hostapd_data;
struct hostap_sta_driver_data {
unsigned long rx_packets, tx_packets;
unsigned long long rx_bytes, tx_bytes;
unsigned long long rx_airtime, tx_airtime;
int bytes_64bit; /* whether 64-bit byte counters are supported */
unsigned long current_tx_rate;
unsigned long current_rx_rate;
@ -1761,6 +1803,8 @@ struct hostap_sta_driver_data {
unsigned long tx_retry_failed;
unsigned long tx_retry_count;
s8 last_ack_rssi;
unsigned long backlog_packets;
unsigned long backlog_bytes;
s8 signal;
u8 rx_vhtmcs;
u8 tx_vhtmcs;
@ -1781,6 +1825,8 @@ struct hostapd_sta_add_params {
const struct ieee80211_vht_capabilities *vht_capabilities;
int vht_opmode_enabled;
u8 vht_opmode;
const struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
u32 flags; /* bitmask of WPA_STA_* flags */
u32 flags_mask; /* unset bits in flags */
#ifdef CONFIG_MESH
@ -2337,7 +2383,7 @@ struct wpa_driver_ops {
*
* Returns: 0 on success, -1 on failure
*/
int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
int (*deauthenticate)(void *priv, const u8 *addr, u16 reason_code);
/**
* associate - Request driver to associate
@ -2806,7 +2852,7 @@ struct wpa_driver_ops {
* a Deauthentication frame to be sent to it.
*/
int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr,
int reason);
u16 reason);
/**
* sta_disassoc - Disassociate a station (AP only)
@ -2820,7 +2866,7 @@ struct wpa_driver_ops {
* a Disassociation frame to be sent to it.
*/
int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr,
int reason);
u16 reason);
/**
* sta_remove - Remove a station entry (AP only)
@ -2937,6 +2983,16 @@ struct wpa_driver_ops {
unsigned int total_flags, unsigned int flags_or,
unsigned int flags_and);
/**
* sta_set_airtime_weight - Set station airtime weight (AP only)
* @priv: Private driver interface data
* @addr: Station address
* @weight: New weight for station airtime assignment
* Returns: 0 on success, -1 on failure
*/
int (*sta_set_airtime_weight)(void *priv, const u8 *addr,
unsigned int weight);
/**
* set_tx_queue_params - Set TX queue parameters
* @priv: Private driver interface data
@ -3974,6 +4030,18 @@ struct wpa_driver_ops {
*/
int (*leave_mesh)(void *priv);
/**
* probe_mesh_link - Inject a frame over direct mesh link to a given
* peer skipping the next_hop lookup from mpath table.
* @priv: Private driver interface data
* @addr: Peer MAC address
* @eth: Ethernet frame to be sent
* @len: Ethernet frame lengtn in bytes
* Returns 0 on success, -1 on failure
*/
int (*probe_mesh_link)(void *priv, const u8 *addr, const u8 *eth,
size_t len);
/**
* do_acs - Automatically select channel
* @priv: Private driver interface data
@ -4167,6 +4235,21 @@ struct wpa_driver_ops {
* Returns: 0 on success, < 0 on failure
*/
int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val);
/**
* update_dh_ie - Update DH IE
* @priv: Private driver interface data
* @peer_mac: Peer MAC address
* @reason_code: Reacon code
* @ie: DH IE
* @ie_len: DH IE length in bytes
* Returns: 0 on success, -1 on failure
*
* This callback is used to let the driver know the DH processing result
* and DH IE for a pending association.
*/
int (*update_dh_ie)(void *priv, const u8 *peer_mac, u16 reason_code,
const u8 *ie, size_t ie_len);
};
/**
@ -4540,6 +4623,15 @@ enum wpa_event_type {
* */
EVENT_CH_SWITCH,
/**
* EVENT_CH_SWITCH_STARTED - AP or GO started to switch channels
*
* This is a pre-switch event indicating the shortly following switch
* of operating channels.
*
* Described in wpa_event_data.ch_switch
*/
EVENT_CH_SWITCH_STARTED,
/**
* EVENT_WNM - Request WNM operation
*
@ -4703,6 +4795,11 @@ enum wpa_event_type {
* This event is emitted when an interface is added/removed for WDS STA.
*/
EVENT_WDS_STA_INTERFACE_STATUS,
/**
* EVENT_UPDATE_DH - Notification of updated DH information
*/
EVENT_UPDATE_DH,
};
@ -5536,6 +5633,15 @@ union wpa_event_data {
INTERFACE_REMOVED
} istatus;
} wds_sta_interface;
/**
* struct update_dh - Data for EVENT_UPDATE_DH
*/
struct update_dh {
const u8 *peer;
const u8 *ie;
size_t ie_len;
} update_dh;
};
/**

File diff suppressed because it is too large Load diff

View file

@ -662,7 +662,7 @@ rtbuf_len(void)
#undef WPA_OUI_TYPE
static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
int reason_code);
u16 reason_code);
static const char *
ether_sprintf(const u8 *addr)
@ -754,7 +754,7 @@ bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
}
static int
bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code)
bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, u16 reason_code)
{
return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
addr);
@ -762,7 +762,7 @@ bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code)
static int
bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
int reason_code)
u16 reason_code)
{
return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
addr);
@ -1025,7 +1025,7 @@ wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
}
static int
wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, u16 reason_code)
{
return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code,
addr);

View file

@ -67,6 +67,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(DRIVER_CLIENT_POLL_OK);
E2S(EAPOL_TX_STATUS);
E2S(CH_SWITCH);
E2S(CH_SWITCH_STARTED);
E2S(WNM);
E2S(CONNECT_FAILED_REASON);
E2S(DFS_RADAR_DETECTED);
@ -87,6 +88,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(STATION_OPMODE_CHANGED);
E2S(INTERFACE_MAC_CHANGED);
E2S(WDS_STA_INTERFACE_STATUS);
E2S(UPDATE_DH);
}
return "UNKNOWN";

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